//: A simple memory allocator to create space for new variables at runtime. :(scenarios run) :(scenario new) # call new two times with identical arguments; you should get back different results recipe main [ 1:address:number/raw <- new number:type 2:address:number/raw <- new number:type 3:boolean/raw <- equal 1:address:number/raw, 2:address:number/raw ] +mem: storing 0 in location 3 :(before "End Globals") long long int Reserved_for_tests = 1000; long long int Memory_allocated_until = Reserved_for_tests; long long int Initial_memory_per_routine = 100000; :(before "End Setup") Memory_allocated_until = Reserved_for_tests; Initial_memory_per_routine = 100000; :(before "End routine Fields") long long int alloc, alloc_max; :(before "End routine Constructor") alloc = Memory_allocated_until; Memory_allocated_until += Initial_memory_per_routine; alloc_max = Memory_allocated_until; trace(Primitive_recipe_depth, "new") << "routine allocated memory from " << alloc << " to " << alloc_max << end(); //:: First handle 'type' operands. :(before "End Mu Types Initialization") Type_ordinal["type"] = 0; :(after "Per-recipe Transforms") // replace type names with type_ordinals if (inst.operation == Recipe_ordinal["new"]) { // End NEW Transform Special-cases // first arg must be of type 'type' if (inst.ingredients.empty()) raise << Recipe[r].name << ": 'new' expects one or two ingredients\n" << end(); if (inst.ingredients.at(0).properties.empty() || inst.ingredients.at(0).properties.at(0).second.empty() || inst.ingredients.at(0).properties.at(0).second.at(0) != "type") raise << Recipe[r].name << ": first ingredient of 'new' should be a type, but got " << inst.ingredients.at(0).original_string << '\n' << end(); if (Type_ordinal.find(inst.ingredients.at(0).name) == Type_ordinal.end()) raise << Recipe[r].name << ": unknown type " << inst.ingredients.at(0).name << '\n' << end(); inst.ingredients.at(0).set_value(Type_ordinal[inst.ingredients.at(0).name]); trace(Primitive_recipe_depth, "new") << inst.ingredients.at(0).name << " -> " << inst.ingredients.at(0).name << end(); end_new_transform:; } //:: Now implement the primitive recipe. //: todo: build 'new' in mu itself :(before "End Primitive Recipe Declarations") NEW, :(before "End Primitive Recipe Numbers") Recipe_ordinal["new"] = NEW; :(before "End Primitive Recipe Implementations") case NEW: { if (ingredients.empty() || SIZE(ingredients) > 2) { raise << current_recipe_name() << ": 'new' requires one or two ingredients, but got " << current_instruction().to_string() << '\n' << end(); break; } if (!scalar(ingredients.at(0))) { raise << current_recipe_name() << ": first ingredient of 'new' should be a type, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end(); break; } // compute the space we need long long int size = 0; long long int array_length = 0; { vector type; type.push_back(current_instruction().ingredients.at(0).value); if (SIZE(current_instruction().ingredients) > 1) { // array array_length = ingredients.at(1).at(0); trace(Primitive_recipe_depth, "mem") << "array size is " << array_length << end(); size = array_length*size_of(type) + /*space for length*/1; } else { // scalar size = size_of(type); } } //? Total_alloc += size; //? 1 //? Num_alloc++; //? 1 // compute the region of memory to return // really crappy at the moment ensure_space(size); const long long int result = Current_routine->alloc; trace(Primitive_recipe_depth, "mem") << "new alloc: " << result << end(); // save result products.resize(1); products.at(0).push_back(result); // initialize allocated space for (long long int address = result; address < result+size; ++address) { Memory[address] = 0; } if (SIZE(current_instruction().ingredients) > 1) { Memory[result] = array_length; } // bump Current_routine->alloc += size; // no support for reclaiming memory assert(Current_routine->alloc <= Current_routine->alloc_max); break; } //? :(before "End Globals") //? 1 //? long long int Total_alloc = 0; //? 1 //? long long int Num_alloc = 0; //? 1 //? long long int Total_free = 0; //? 1 //? long long int Num_free = 0; //? 1 //? :(before "End Setup") //? 1 //? Total_alloc = Num_alloc = Total_free = Num_free = 0; //? 1 //? :(before "End Teardown") //? 1 //? cerr << Total_alloc << "/" << Num_alloc //? 1 //? << " vs " << Total_free << "/" << Num_free << '\n'; //? 1 //? cerr << SIZE(Memory) << '\n'; //? 1 :(code) void ensure_space(long long int size) { assert(size <= Initial_memory_per_routine); if (Current_routine->alloc + size > Current_routine->alloc_max) { // waste the remaining space and create a new chunk Current_routine->alloc = Memory_allocated_until; Memory_allocated_until += Initial_memory_per_routine; Current_routine->alloc_max = Memory_allocated_until; trace(Primitive_recipe_depth, "new") << "routine allocated memory from " << Current_routine->alloc << " to " << Current_ro
// C++ style:
//  no pointers except cell*
//  use long as the default integer type; it's always large enough to hold pointers

#define unused __attribute__((unused))

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<errno.h>
#include<time.h>
#include<math.h>
#include<vector>
using std::vector;
#include<list>
using std::list;
#include<stack>
using std::stack;
#include<utility>
using std::pair;

#include<tr1/unordered_map>
using std::tr1::unordered_map;
#include<tr1/unordered_set>
using std::tr1::unordered_set;
#include<algorithm>

#include<string>
using std::string;
const size_t NOT_FOUND