//: Update refcounts when copying addresses. //: The top of the address layer has more on refcounts. :(scenario refcounts) def main [ 1:address:number <- copy 1000/unsafe 2:address:number <- copy 1:address:number 1:address:number <- copy 0 2:address:number <- copy 0 ] +run: {1: ("address" "number")} <- copy {1000: "literal", "unsafe": ()} +mem: incrementing refcount of 1000: 0 -> 1 +run: {2: ("address" "number")} <- copy {1: ("address" "number")} +mem: incrementing refcount of 1000: 1 -> 2 +run: {1: ("address" "number")} <- copy {0: "literal"} +mem: decrementing refcount of 1000: 2 -> 1 +run: {2: ("address" "number")} <- copy {0: "literal"} +mem: decrementing refcount of 1000: 1 -> 0 :(before "End Globals") //: escape hatch for a later layer bool Update_refcounts_in_write_memory = true; :(before "End write_memory(x) Special-cases") if (Update_refcounts_in_write_memory) update_any_refcounts(x, data); :(code) void update_any_refcounts(const reagent& canonized_x, const vector& data) { increment_any_refcounts(canonized_x, data); // increment first so we don't reclaim on x <- copy x decrement_any_refcounts(canonized_x); } void increment_any_refcounts(const reagent& canonized_x, const vector& data) { if (is_mu_address(canonized_x)) { assert(scalar(data)); assert(!canonized_x.metadata.size); increment_refcount(data.at(0)); } // End Increment Refcounts(canonized_x) } void increment_refcount(int new_address) { assert(new_address >= 0); if (new_address == 0) return; int new_refcount = get_or_insert(Memory, new_address); trace(9999, "mem") << "incrementing refcount of " << new_address << ": " << new_refcount << " -> " << new_refcount+1 << end(); put(Memory, new_address, new_refcount+1); } void decrement_any_refcounts(const reagent& canonized_x) { if (is_mu_address(canonized_x)) { assert(canonized_x.value); assert(!canonized_x.metadata.size); decrement_refcount(get_or_insert(Memory, canonized_x.value), canonized_x.type->right, payload_size(canonized_x)); } // End Decrement Refcounts(canonized_x) } void decrement_refcount(int old_address, const type_tree* payload_type, int payload_size) { assert(old_address >= 0); if (old_address) { int old_refcount = get_or_insert(Memory, old_address); trace(9999, "mem") << "decrementing refcount of " << old_address << ": " << old_refcount << " -> " << old_refcount-1 << end(); --old_refcount; put(Memory, old_address, old_refcount); if (old_refcount < 0) { tb_shutdown(); cerr << "Negative refcount!!! " << old_address << ' ' << old_refcount << '\n'; if (Trace_stream) { cerr << "Saving trace to last_trace.\n"; ofstream fout("last_trace"); fout << Trace_stream->readable_contents(""); fout.close(); } exit(0); } // End Decrement Refcount(old_address, payload_type, payload_size) } } int payload_size(reagent/*copy*/ x) { x.properties.push_back(pair("lookup", NULL)); lookup_memory_core(x); return size_of(x) + /*refcount*/1; } :(scenario refcounts_reflexive) def main [ 1:address:number <- new number:type # idempotent copies leave refcount unchanged 1:address:number <- copy 1:address:number ] +run: {1: ("address" "number")} <- new {number: "type"} +mem: incrementing refcount of 1000: 0 -> 1 +run: {1: ("address" "number")} <- copy {1: ("address" "number")} +mem: incrementing refcount of 1000: 1 -> 2 +mem: decrementing refcount of 1000: 2 -> 1 :(scenario refcounts_call) def main [ 1:address:number <- new number:type # passing in addresses to recipes increments refcount foo 1:address:number # return does NOT yet decrement refcount; memory must be explicitly managed 1:address:number <- new number:type ] def foo [ 2:address:number <- next-ingredient ] +run: {1: ("address" "number")} <- new {number: "type"} +mem: incrementing refcount of 1000: 0 -> 1 +run: foo {1: ("address" "number")} # leave ambiguous precisely when the next increment happens; a later layer # will mess with that +mem: incrementing refcount of 1000: 1 -> 2 +run: {1: ("address" "number")} <- new {number: "type"} +mem: decrementing refcount of 1000: 2 -> 1 //: fix up any instructions that don't follow the usual flow of read_memory //: before the RUN switch, and write_memory after :(scenario refcounts_put) container foo [ x:address:number ] def main [ 1:address:number <- new number:type 2:address:foo <- new foo:type *2:address:foo <- put *2:address:foo, x:offset, 1:address:number ] +run: {1: ("address" "number")} <- new {number: "type"} +mem: incrementing refcount of 1000: 0 -> 1 +run: {2: ("address" "foo")} <- new {foo: "type"} +mem: incrementing refcount of 1002: 0 -> 1 +run: {2: ("address" "foo"), "lookup": ()} <- put {2: ("address" "foo"), "lookup": ()}, {x: "offset"}, {1: ("address" "number")} # put increments refcount +mem: incrementing refcount of 1000: 1 -> 2 :(after "Write Memory in PUT in Run") reagent/*copy*/ element = element_type(base.type, offset); assert(!has_property(element, "lookup")); element.set_value(address); update_any_refcounts(element, ingredients.at(2)); :(scenario refcounts_put_index) def main [ 1:address:number <- new number:type 2:address:array:address:number <- new {(address number): type}, 3 *2:address:array:address:number <- put-index *2:address:array:address:number, 0, 1:address:number ] +run: {1: ("address" "number")} <- new {number: "type"} +mem: incrementing refcount of 1000: 0 -> 1 +run: {2: ("address" "array" "address" "number")} <- new {(address number): "type"}, {3: "literal"} +mem: incrementing refcount of 1002: 0 -> 1 +run: {2: ("address" "array" "address" "number"), "lookup": ()} <- put-index {2: ("address" "array" "address" "number"), "lookup": ()}, {0: "literal"}, {1: ("address" "number")} # put-index increments refcount +mem: incrementing refcount of 1000: 1 -> 2 :(after "Write Memory in PUT_INDEX in Run") update_any_refcounts(element, value); :(scenario refcounts_maybe_convert) exclusive-container foo [ x:number p:address:number ] def main [ 1:address:number <- new number:type 2:foo <- merge 1/p, 1:address:number 4:address:number, 5:boolean <- maybe-convert 2:foo, 1:variant/p ] +run: {1: ("address" "number")} <- new {number: "type"} +mem: incrementing refcount of 1000: 0 -> 1 # merging in an address increments refcount +run: {2: "foo"} <- merge {1: "literal", "p": ()}, {1: ("address" "number")} +mem: incrementing refcount of 1000: 1 -> 2 +run: {4: ("address" "number")}, {5: "boolean"} <- maybe-convert {2: "foo"}, {1: "variant", "p": ()} # maybe-convert increments refcount on success +mem: incrementing refcount of 1000: 2 -> 3 :(after "Write Memory in Successful MAYBE_CONVERT") // TODO: double-check data here as well vector data; for (int i = 0; i < size_of(product); ++i) data.push_back(get_or_insert(Memory, base_address+/*skip tag*/1+i)); update_any_refcounts(product, data); //:: manage refcounts in instructions that copy multiple locations at a time :(scenario refcounts_copy_nested) container foo [ x:address:number # address inside container ] def main [ 1:address:number <- new number:type
#ifndef COMMON_H
#define COMMON_H

#define enableInterrupts() asm volatile("sti")
#define disableInterrupts() asm volatile("cli")
#define halt() asm volatile("hlt")


typedef unsigned  long long uint64;
typedef signed    long long int64;
typedef unsigned  int       uint32;
typedef           int       int32;
typedef unsigned  short     uint16;
typedef           short     int16;
typedef unsigned  char      uint8;
typedef           char      int8;
typedef unsigned  int       size_t;

#define BOOL uint8
#define TRUE 1
#define FALSE 0
#define NULL 0

#define KERN_PAGE_DIRECTORY     0x00001000

#define KERN_BASE               0x00100000

//16M is identity mapped as below.
//First 8M we don't touch. Kernel code is there.
//4M is reserved for 4K page directories.
//4M is not used for now. kernel mini heap was here in old times.
#define RESERVED_AREA           0x01000000 //16 mb
#define KERN_PD_AREA_BEGIN      0x00800000 // 8 mb
#define KERN_PD_AREA_END        0x00C00000 //12 mb
#define KERN_NOTUSED_BEGIN      0x00C00000 //12 mb
#define KERN_NOTUSED_END        0x01000000 //16 mb

#define GFX_MEMORY              0x01000000 //16 mb

#define KERN_HEAP_BEGIN         0x02000000 //32 mb
#define KERN_HEAP_END           0x40000000 // 1 gb


#define PAGE_INDEX_4K(addr)     ((addr) >> 12)
#define PAGE_INDEX_4M(addr)     ((addr) >> 22)
#define PAGING_FLAG             0x80000000  // CR0 - bit 31
#define PSE_FLAG                0x00000010  // CR4 - bit 4
#define PG_PRESENT              0x00000001  // page directory / table
#define PG_WRITE                0x00000002
#define PG_USER                 0x00000004
#define PG_4MB                  0x00000080
#define PAGESIZE_4K             0x00001000
#define PAGESIZE_4M             0x00400000
#define RAM_AS_4K_PAGES         0x100000
#define RAM_AS_4M_PAGES         1024

#define KERNELMEMORY_PAGE_COUNT 256 //(KERN_HEAP_END / PAGESIZE_4M)

#define KERN_STACK_SIZE         PAGESIZE_4K

//KERN_HEAP_END ends and this one starts
#define USER_OFFSET             0x40000000
#define USER_OFFSET_END         0xF0000000
#define USER_OFFSET_MMAP        0xF0000000
#define USER_OFFSET_MMAP_END    0xFFFFFFFF

#define USER_EXE_IMAGE          0x200000 //2MB
#define USER_ARGV_ENV_SIZE      0x10000  //65KB
#define USER_ARGV_ENV_LOC       (USER_OFFSET + (USER_EXE_IMAGE - USER_ARGV_ENV_SIZE))
//This means we support executable images up to 2MB
//And user malloc functions will start from USER_OFFSET + USER_EXE_IMAGE
//We will 65KB (0x10000) for argv and environ just before user malloc start
//So USER_EXE_IMAGE - USER_ARGV_ENV_SIZE = 0x1F0000
//That means argv and env data will start from USER_OFFSET + 0x1F0000
//Of course libc should know this numbers :)

#define USER_STACK          0xF0000000

void outb(uint16 port, uint8 value);
void outw(uint16 port, uint16 value);
uint8 inb(uint16 port);
uint16 inw(uint16 port);

#define PANIC(msg) panic(msg, __FILE__, __LINE__);
#define WARNING(msg) warning(msg, __FILE__, __LINE__);
#define ASSERT(b) ((b) ? (void)0 : panic_assert(__FILE__, __LINE__, #b))

#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))

void warning(const char *message, const char *file, uint32 line);
void panic(const char *message, const char *file, uint32 line);
void panic_assert(const char *file, uint32 line, const char *desc);

void* memset(uint8 *dest, uint8 val, uint32 len);
void* memcpy(uint8 *dest, const uint8 *src, uint32 len);
void* memmove(void* dest, const void* src, uint32 n);
int memcmp(const void* p1, const void* p2, uint32 c);

int strcmp(const char *str1, const char *str2);
int strncmp(const char *str1, const char *str2, int length);
char *strcpy(char *dest, const char *src);
char *strcpyNonNull(char *dest, const char *src);
char *strncpy(char *dest, const char *src, uint32 num);
char* strcat(char *dest, const char *src);
int strlen(const char *src);
int strFirstIndexOf(const char *src, char c);
int sprintf(char* buffer, const char *format, ...);

void printkf(const char *format, ...);

int atoi(char *str);
void itoa(char *buf, int base, int d);

uint32 rand();

uint32 readEip();
uint32 readEsp();
uint32 getCpuFlags();
BOOL isInterruptsEnabled();

void beginCriticalSection();
void endCriticalSection();

#endif // COMMON_H

// vim:expandtab:ts=2
metadata, canonized_x.type); for (map, set >::const_iterator p = metadata.address.begin(); p != metadata.address.end(); ++p) { if (!all_match(data, p->first)) continue; for (set::const_iterator info = p->second.begin(); info != p->second.end(); ++info) decrement_refcount(get_or_insert(Memory, canonized_x.value + info->offset), info->payload_type, size_of(info->payload_type)+/*refcount*/1); } } :(code) bool all_match(const vector& data, const set& conditions) { for (set::const_iterator p = conditions.begin(); p != conditions.end(); ++p) { if (data.at(p->offset) != p->tag) return false; } return true; } :(scenario refcounts_put_container) container foo [ a:bar # contains an address ] container bar [ x:address:number ] def main [ 1:address:number <- new number:type 2:bar <- merge 1:address:number 3:address:foo <- new foo:type *3:address:foo <- put *3:address:foo, a:offset, 2:bar ] +run: {1: ("address" "number")} <- new {number: "type"} +mem: incrementing refcount of 1000: 0 -> 1 +run: {2: "bar"} <- merge {1: ("address" "number")} +mem: incrementing refcount of 1000: 1 -> 2 +run: {3: ("address" "foo"), "lookup": ()} <- put {3: ("address" "foo"), "lookup": ()}, {a: "offset"}, {2: "bar"} # put increments refcount inside container +mem: incrementing refcount of 1000: 2 -> 3 :(scenario refcounts_put_index_array) container bar [ x:address:number ] def main [ 1:address:number <- new number:type 2:bar <- merge 1:address:number 3:address:array:bar <- new bar:type, 3 *3:address:array:bar <- put-index *3:address:array:bar, 0, 2:bar ] +run: {1: ("address" "number")} <- new {number: "type"} +mem: incrementing refcount of 1000: 0 -> 1 +run: {2: "bar"} <- merge {1: ("address" "number")} +mem: incrementing refcount of 1000: 1 -> 2 +run: {3: ("address" "array" "bar"), "lookup": ()} <- put-index {3: ("address" "array" "bar"), "lookup": ()}, {0: "literal"}, {2: "bar"} # put-index increments refcount inside container +mem: incrementing refcount of 1000: 2 -> 3 :(scenario refcounts_maybe_convert_container) exclusive-container foo [ a:number b:bar # contains an address ] container bar [ x:address:number ] def main [ 1:address:number <- new number:type 2:bar <- merge 1:address:number 3:foo <- merge 1/b, 2:bar 5:bar, 6:boolean <- maybe-convert 3:foo, 1:variant/b ] +run: {1: ("address" "number")} <- new {number: "type"} +mem: incrementing refcount of 1000: 0 -> 1 +run: {2: "bar"} <- merge {1: ("address" "number")} +mem: incrementing refcount of 1000: 1 -> 2 +run: {3: "foo"} <- merge {1: "literal", "b": ()}, {2: "bar"} +mem: incrementing refcount of 1000: 2 -> 3 +run: {5: "bar"}, {6: "boolean"} <- maybe-convert {3: "foo"}, {1: "variant", "b": ()} +mem: incrementing refcount of 1000: 3 -> 4 :(scenario refcounts_copy_doubly_nested) container foo [ a:bar # no addresses b:curr # contains addresses ] container bar [ x:number y:number ] container curr [ x:number y:address:number # address inside container inside container ] def main [ 1:address:number <- new number:type 2:address:curr <- new curr:type *2:address:curr <- put *2:address:curr, 1:offset/y, 1:address:number 3:address:foo <- new foo:type *3:address:foo <- put *3:address:foo, 1:offset/b, *2:address:curr 4:foo <- copy *3:address:foo ] +transform: compute address offsets for container foo +transform: checking container foo, element 1 +transform: address at offset 3 +run: {1: ("address" "number")} <- new {number: "type"} +mem: incrementing refcount of 1000: 0 -> 1 # storing an address in a container updates its refcount +run: {2: ("address" "curr"), "lookup": ()} <- put {2: ("address" "curr"), "lookup": ()}, {1: "offset", "y": ()}, {1: ("address" "number")} +mem: incrementing refcount of 1000: 1 -> 2 # storing a container in a container updates refcounts of any contained addresses +run: {3: ("address" "foo"), "lookup": ()} <- put {3: ("address" "foo"), "lookup": ()}, {1: "offset", "b": ()}, {2: ("address" "curr"), "lookup": ()} +mem: incrementing refcount of 1000: 2 -> 3 # copying a container containing a container containing an address updates refcount +run: {4: "foo"} <- copy {3: ("address" "foo"), "lookup": ()} +mem: incrementing refcount of 1000: 3 -> 4 :(scenario refcounts_copy_exclusive_container_within_container) container foo [ a:number b:bar ] exclusive-container bar [ x:number y:number z:address:number ] def main [ 1:address:number <- new number:type 2:bar <- merge 0/x, 34 3:foo <- merge 12, 2:bar 5:bar <- merge 1/y, 35 6:foo <- merge 13, 5:bar 8:bar <- merge 2/z, 1:address:number 9:foo <- merge 14, 8:bar 11:foo <- copy 9:foo ] +run: {1: ("address" "number")} <- new {number: "type"} +mem: incrementing refcount of 1000: 0 -> 1 # no change while merging items of other types +run: {8: "bar"} <- merge {2: "literal", "z": ()}, {1: ("address" "number")} +mem: incrementing refcount of 1000: 1 -> 2 +run: {9: "foo"} <- merge {14: "literal"}, {8: "bar"} +mem: incrementing refcount of 1000: 2 -> 3 +run: {11: "foo"} <- copy {9: "foo"} +mem: incrementing refcount of 1000: 3 -> 4 :(scenario refcounts_copy_container_within_exclusive_container) exclusive-container foo [ a:number b:bar ] container bar [ x:number y:number z:address:number ] def main [ 1:address:number <- new number:type 2:foo <- merge 0/a, 34 6:foo <- merge 0/a, 35 10:bar <- merge 2/x, 15/y, 1:address:number 13:foo <- merge 1/b, 10:bar 17:foo <- copy 13:foo ] +run: {1: ("address" "number")} <- new {number: "type"} +mem: incrementing refcount of 1000: 0 -> 1 # no change while merging items of other types +run: {10: "bar"} <- merge {2: "literal", "x": ()}, {15: "literal", "y": ()}, {1: ("address" "number")} +mem: incrementing refcount of 1000: 1 -> 2 +run: {13: "foo"} <- merge {1: "literal", "b": ()}, {10: "bar"} +mem: incrementing refcount of 1000: 2 -> 3 +run: {17: "foo"} <- copy {13: "foo"} +mem: incrementing refcount of 1000: 3 -> 4 :(scenario refcounts_copy_exclusive_container_within_exclusive_container) exclusive-container foo [ a:number b:bar ] exclusive-container bar [ x:number y:address:number ] def main [ 1:address:number <- new number:type 10:foo <- merge 1/b, 1/y, 1:address:number 20:foo <- copy 10:foo ] +run: {1: ("address" "number")} <- new {number: "type"} +mem: incrementing refcount of 1000: 0 -> 1 # no change while merging items of other types +run: {10: "foo"} <- merge {1: "literal", "b": ()}, {1: "literal", "y": ()}, {1: ("address" "number")} +mem: incrementing refcount of 1000: 1 -> 2 +run: {20: "foo"} <- copy {10: "foo"} +mem: incrementing refcount of 1000: 2 -> 3 :(scenario refcounts_copy_array_within_container) container foo [ x:address:array:number ] def main [ 1:address:array:number <- new number:type, 3 2:foo <- merge 1:address:array:number 3:address:array:number <- new number:type, 5 2:foo <- merge 3:address:array:number ] +run: {1: ("address" "array" "number")} <- new {number: "type"}, {3: "literal"} +mem: incrementing refcount of 1000: 0 -> 1 +run: {2: "foo"} <- merge {1: ("address" "array" "number")} +mem: incrementing refcount of 1000: 1 -> 2 +run: {2: "foo"} <- merge {3: ("address" "array" "number")} +mem: decrementing refcount of 1000: 2 -> 1 :(scenario refcounts_handle_exclusive_containers_with_different_tags) container foo1 [ x:address:number y:number ] container foo2 [ x:number y:address:number ] exclusive-container bar [ a:foo1 b:foo2 ] def main [ 1:address:number <- copy 12000/unsafe # pretend allocation *1:address:number <- copy 34 2:bar <- merge 0/foo1, 1:address:number, 97 5:address:number <- copy 13000/unsafe # pretend allocation *5:address:number <- copy 35 6:bar <- merge 1/foo2, 98, 5:address:number 2:bar <- copy 6:bar ] +run: {2: "bar"} <- merge {0: "literal", "foo1": ()}, {1: ("address" "number")}, {97: "literal"} +mem: incrementing refcount of 12000: 1 -> 2 +run: {6: "bar"} <- merge {1: "literal", "foo2": ()}, {98: "literal"}, {5: ("address" "number")} +mem: incrementing refcount of 13000: 1 -> 2 +run: {2: "bar"} <- copy {6: "bar"} +mem: incrementing refcount of 13000: 2 -> 3 +mem: decrementing refcount of 12000: 2 -> 1 :(code) bool is_mu_container(const reagent& r) { return is_mu_container(r.type); } bool is_mu_container(const type_tree* type) { if (!type) return false; // End is_mu_container(type) Special-cases if (type->value == 0) return false; type_info& info = get(Type, type->value); return info.kind == CONTAINER; } bool is_mu_exclusive_container(const reagent& r) { return is_mu_exclusive_container(r.type); } bool is_mu_exclusive_container(const type_tree* type) { if (!type) return false; // End is_mu_exclusive_container(type) Special-cases if (type->value == 0) return false; type_info& info = get(Type, type->value); return info.kind == EXCLUSIVE_CONTAINER; }