From 598f1b5362eb799e40836ceeb5452c9ba937fd6c Mon Sep 17 00:00:00 2001 From: "Kartik K. Agaram" Date: Tue, 7 Feb 2017 00:22:08 -0800 Subject: 3746 --- html/043space.cc.html | 365 ++++++++++++++++++++++++++------------------------ 1 file changed, 187 insertions(+), 178 deletions(-) (limited to 'html/043space.cc.html') diff --git a/html/043space.cc.html b/html/043space.cc.html index efc582f4..60bc5518 100644 --- a/html/043space.cc.html +++ b/html/043space.cc.html @@ -127,7 +127,7 @@ if ('onhashchange' in window) { 63 if (x.name == "default-space") return; 64 if (!x.initialized) 65 raise << to_original_string(current_instruction()) << ": reagent not initialized: '" << x.original_string << "'\n" << end(); - 66 x.set_value(address(x.value, space_base(x))); + 66 x.set_value(address(x.value, space_base(x))); 67 x.properties.push_back(pair<string, string_tree*>("raw", NULL)); 68 assert(is_raw(x)); 69 } @@ -241,7 +241,7 @@ if ('onhashchange' in window) { 177 // `default-space:space <- new location:type, number-of-locals:literal` 178 // where N is Name[recipe][""] 179 if (curr.name == "new-default-space") { -180 rewrite_default_space_instruction(curr); +180 rewrite_default_space_instruction(curr); 181 } 182 :(after "Begin Preprocess read_memory(x)") 183 if (x.name == "number-of-locals") { @@ -283,7 +283,7 @@ if ('onhashchange' in window) { 219 220 :(before "End Rewrite Instruction(curr, recipe result)") 221 if (curr.name == "local-scope") { -222 rewrite_default_space_instruction(curr); +222 rewrite_default_space_instruction(curr); 223 } 224 225 //: todo: do this in a transform, rather than magically in the 'return' instruction @@ -309,7 +309,7 @@ if ('onhashchange' in window) { 245 // local variables only 246 if (has_property(product, "lookup")) continue; 247 if (has_property(product, "raw")) continue; // tests often want to check such locations after they run -248 if (escaping(product)) continue; +248 if (escaping(product)) continue; 249 // End Checks For Reclaiming Locals 250 trace(9999, "mem") << "clearing " << product.original_string << end(); 251 zeros.resize(size_of(product)); @@ -322,180 +322,189 @@ if ('onhashchange' in window) { 258 /*refcount*/1 + /*array length*/1 + /*number-of-locals*/Name[r][""]); 259 } 260 -261 :(code) -262 // is this reagent one of the values returned by the current (return) instruction? -263 // is the corresponding ingredient saved in the caller? -264 bool escaping(const reagent& r) { -265 assert(Current_routine); // run-time only -266 // nothing escapes when you fall through past end of recipe -267 if (current_step_index() >= SIZE(Current_routine->steps())) return false; -268 for (long long i = 0; i < SIZE(current_instruction().ingredients); ++i) { -269 if (r == current_instruction().ingredients.at(i)) { -270 if (caller_uses_product(i)) -271 return true; -272 } -273 } -274 return false; -275 } -276 -277 //: since we don't decrement refcounts for escaping values above, make sure we -278 //: don't increment them when the caller saves them either -279 -280 :(after "Write Products of Instruction") -281 Update_refcounts_in_write_memory = should_update_refcounts_in_write_memory(); -282 :(before "End Write Products of Instruction") -283 Update_refcounts_in_write_memory = true; -284 :(code) -285 bool should_update_refcounts_in_write_memory() { -286 const instruction& inst = current_instruction(); -287 // End should_update_refcounts_in_write_memory Special-cases For Primitives -288 if (inst.operation < MAX_PRIMITIVE_RECIPES) return true; -289 if (!contains_key(Recipe, inst.operation)) return true; -290 const recipe& callee = get(Recipe, inst.operation); -291 if (callee.steps.empty()) return true; -292 return callee.steps.at(0).old_name != "local-scope"; // callees that call local-scope are already dealt with before return -293 } -294 -295 bool caller_uses_product(int product_index) { -296 assert(Current_routine); // run-time only -297 assert(!Current_routine->calls.empty()); -298 if (Current_routine->calls.size() == 1) return false; -299 const call& caller = *++Current_routine->calls.begin(); -300 const instruction& caller_inst = to_instruction(caller); -301 if (product_index >= SIZE(caller_inst.products)) return false; -302 return !is_dummy(caller_inst.products.at(product_index)); -303 } -304 -305 void rewrite_default_space_instruction(instruction& curr) { -306 if (!curr.ingredients.empty()) -307 raise << to_original_string(curr) << " can't take any ingredients\n" << end(); -308 curr.name = "new"; -309 curr.ingredients.push_back(reagent("location:type")); -310 curr.ingredients.push_back(reagent("number-of-locals:literal")); -311 if (!curr.products.empty()) -312 raise << "new-default-space can't take any results\n" << end(); -313 curr.products.push_back(reagent("default-space:space")); -314 } -315 -316 :(scenario local_scope_frees_up_addresses_inside_containers) -317 container foo [ -318 x:num -319 y:&:num -320 ] -321 def main [ -322 local-scope -323 x:&:num <- new number:type -324 y:foo <- merge 34, x:&:num -325 # x and y are both cleared when main returns -326 ] -327 +mem: clearing x:&:num -328 +mem: decrementing refcount of 1006: 2 -> 1 -329 +mem: clearing y:foo -330 +mem: decrementing refcount of 1006: 1 -> 0 -331 +mem: automatically abandoning 1006 -332 -333 :(scenario local_scope_returns_addresses_inside_containers) -334 container foo [ -335 x:num -336 y:&:num -337 ] -338 def f [ -339 local-scope -340 x:&:num <- new number:type -341 *x:&:num <- copy 12 -342 y:foo <- merge 34, x:&:num -343 # since y is 'escaping' f, it should not be cleared -344 return y:foo -345 ] -346 def main [ -347 1:foo <- f -348 3:num <- get 1:foo, x:offset -349 4:&:num <- get 1:foo, y:offset -350 5:num <- copy *4:&:num -351 1:foo <- put 1:foo, y:offset, 0 -352 4:&:num <- copy 0 -353 ] -354 +mem: storing 34 in location 1 -355 +mem: storing 1006 in location 2 -356 +mem: storing 34 in location 3 -357 # refcount of 1:foo shouldn't include any stray ones from f -358 +run: {4: ("address" "number")} <- get {1: "foo"}, {y: "offset"} -359 +mem: incrementing refcount of 1006: 1 -> 2 -360 # 1:foo wasn't abandoned/cleared -361 +run: {5: "number"} <- copy {4: ("address" "number"), "lookup": ()} -362 +mem: storing 12 in location 5 -363 +run: {1: "foo"} <- put {1: "foo"}, {y: "offset"}, {0: "literal"} -364 +mem: decrementing refcount of 1006: 2 -> 1 -365 +run: {4: ("address" "number")} <- copy {0: "literal"} -366 +mem: decrementing refcount of 1006: 1 -> 0 -367 +mem: automatically abandoning 1006 -368 -369 :(scenario local_scope_claims_return_values_when_not_saved) -370 def f [ -371 local-scope -372 x:&:num <- new number:type -373 return x:&:num -374 ] -375 def main [ -376 f # doesn't save result -377 ] -378 # x reclaimed -379 +mem: automatically abandoning 1004 -380 # f's local scope reclaimed -381 +mem: automatically abandoning 1000 -382 -383 //:: all recipes must set default-space one way or another -384 -385 :(before "End Globals") -386 bool Hide_missing_default_space_errors = true; -387 :(before "End Checks") -388 Transform.push_back(check_default_space); // idempotent -389 :(code) -390 void check_default_space(const recipe_ordinal r) { -391 if (Hide_missing_default_space_errors) return; // skip previous core tests; this is only for Mu code -392 const recipe& caller = get(Recipe, r); -393 // End check_default_space Special-cases -394 // assume recipes with only numeric addresses know what they're doing (usually tests) -395 if (!contains_non_special_name(r)) return; -396 trace(9991, "transform") << "--- check that recipe " << caller.name << " sets default-space" << end(); -397 if (caller.steps.empty()) return; -398 if (caller.steps.at(0).products.empty() -399 || caller.steps.at(0).products.at(0).name != "default-space") { -400 raise << caller.name << " does not seem to start with default-space or local-scope\n" << end(); -401 } -402 } -403 :(after "Load Mu Prelude") -404 Hide_missing_default_space_errors = false; -405 :(after "Test Runs") -406 Hide_missing_default_space_errors = true; -407 :(after "Running Main") -408 Hide_missing_default_space_errors = false; -409 -410 :(code) -411 bool contains_non_special_name(const recipe_ordinal r) { -412 for (map<string, int>::iterator p = Name[r].begin(); p != Name[r].end(); ++p) { -413 if (p->first.empty()) continue; -414 if (p->first.find("stash_") == 0) continue; // generated by rewrite_stashes_to_text (cross-layer) -415 if (!is_special_name(p->first)) -416 return true; -417 } -418 return false; -419 } -420 -421 // reagent comparison -- only between reagents in a single recipe -422 bool operator==(const reagent& a, const reagent& b) { -423 if (a.name != b.name) return false; -424 if (property(a, "space") != property(b, "space")) return false; -425 return true; -426 } -427 -428 bool operator<(const reagent& a, const reagent& b) { -429 int aspace = 0, bspace = 0; -430 if (has_property(a, "space")) aspace = to_integer(property(a, "space")->value); -431 if (has_property(b, "space")) bspace = to_integer(property(b, "space")->value); -432 if (aspace != bspace) return aspace < bspace; -433 return a.name < b.name; -434 } +261 //: Reclaiming local variables above requires remembering what name an +262 //: instruction had before any rewrites or transforms. +263 :(before "End instruction Fields") +264 string old_name; +265 :(before "End instruction Clear") +266 old_name.clear(); +267 :(before "End next_instruction(curr)") +268 curr->old_name = curr->name; // before rewrite rules modify it +269 +270 :(code) +271 // is this reagent one of the values returned by the current (return) instruction? +272 // is the corresponding ingredient saved in the caller? +273 bool escaping(const reagent& r) { +274 assert(Current_routine); // run-time only +275 // nothing escapes when you fall through past end of recipe +276 if (current_step_index() >= SIZE(Current_routine->steps())) return false; +277 for (long long i = 0; i < SIZE(current_instruction().ingredients); ++i) { +278 if (r == current_instruction().ingredients.at(i)) { +279 if (caller_uses_product(i)) +280 return true; +281 } +282 } +283 return false; +284 } +285 +286 //: since we don't decrement refcounts for escaping values above, make sure we +287 //: don't increment them when the caller saves them either +288 +289 :(after "Write Products of Instruction") +290 Update_refcounts_in_write_memory = should_update_refcounts_in_write_memory(); +291 :(before "End Write Products of Instruction") +292 Update_refcounts_in_write_memory = true; +293 :(code) +294 bool should_update_refcounts_in_write_memory() { +295 const instruction& inst = current_instruction(); +296 // End should_update_refcounts_in_write_memory Special-cases For Primitives +297 if (inst.operation < MAX_PRIMITIVE_RECIPES) return true; +298 if (!contains_key(Recipe, inst.operation)) return true; +299 const recipe& callee = get(Recipe, inst.operation); +300 if (callee.steps.empty()) return true; +301 return callee.steps.at(0).old_name != "local-scope"; // callees that call local-scope are already dealt with before return +302 } +303 +304 bool caller_uses_product(int product_index) { +305 assert(Current_routine); // run-time only +306 assert(!Current_routine->calls.empty()); +307 if (Current_routine->calls.size() == 1) return false; +308 const call& caller = *++Current_routine->calls.begin(); +309 const instruction& caller_inst = to_instruction(caller); +310 if (product_index >= SIZE(caller_inst.products)) return false; +311 return !is_dummy(caller_inst.products.at(product_index)); +312 } +313 +314 void rewrite_default_space_instruction(instruction& curr) { +315 if (!curr.ingredients.empty()) +316 raise << to_original_string(curr) << " can't take any ingredients\n" << end(); +317 curr.name = "new"; +318 curr.ingredients.push_back(reagent("location:type")); +319 curr.ingredients.push_back(reagent("number-of-locals:literal")); +320 if (!curr.products.empty()) +321 raise << "new-default-space can't take any results\n" << end(); +322 curr.products.push_back(reagent("default-space:space")); +323 } +324 +325 :(scenario local_scope_frees_up_addresses_inside_containers) +326 container foo [ +327 x:num +328 y:&:num +329 ] +330 def main [ +331 local-scope +332 x:&:num <- new number:type +333 y:foo <- merge 34, x:&:num +334 # x and y are both cleared when main returns +335 ] +336 +mem: clearing x:&:num +337 +mem: decrementing refcount of 1006: 2 -> 1 +338 +mem: clearing y:foo +339 +mem: decrementing refcount of 1006: 1 -> 0 +340 +mem: automatically abandoning 1006 +341 +342 :(scenario local_scope_returns_addresses_inside_containers) +343 container foo [ +344 x:num +345 y:&:num +346 ] +347 def f [ +348 local-scope +349 x:&:num <- new number:type +350 *x:&:num <- copy 12 +351 y:foo <- merge 34, x:&:num +352 # since y is 'escaping' f, it should not be cleared +353 return y:foo +354 ] +355 def main [ +356 1:foo <- f +357 3:num <- get 1:foo, x:offset +358 4:&:num <- get 1:foo, y:offset +359 5:num <- copy *4:&:num +360 1:foo <- put 1:foo, y:offset, 0 +361 4:&:num <- copy 0 +362 ] +363 +mem: storing 34 in location 1 +364 +mem: storing 1006 in location 2 +365 +mem: storing 34 in location 3 +366 # refcount of 1:foo shouldn't include any stray ones from f +367 +run: {4: ("address" "number")} <- get {1: "foo"}, {y: "offset"} +368 +mem: incrementing refcount of 1006: 1 -> 2 +369 # 1:foo wasn't abandoned/cleared +370 +run: {5: "number"} <- copy {4: ("address" "number"), "lookup": ()} +371 +mem: storing 12 in location 5 +372 +run: {1: "foo"} <- put {1: "foo"}, {y: "offset"}, {0: "literal"} +373 +mem: decrementing refcount of 1006: 2 -> 1 +374 +run: {4: ("address" "number")} <- copy {0: "literal"} +375 +mem: decrementing refcount of 1006: 1 -> 0 +376 +mem: automatically abandoning 1006 +377 +378 :(scenario local_scope_claims_return_values_when_not_saved) +379 def f [ +380 local-scope +381 x:&:num <- new number:type +382 return x:&:num +383 ] +384 def main [ +385 f # doesn't save result +386 ] +387 # x reclaimed +388 +mem: automatically abandoning 1004 +389 # f's local scope reclaimed +390 +mem: automatically abandoning 1000 +391 +392 //:: all recipes must set default-space one way or another +393 +394 :(before "End Globals") +395 bool Hide_missing_default_space_errors = true; +396 :(before "End Checks") +397 Transform.push_back(check_default_space); // idempotent +398 :(code) +399 void check_default_space(const recipe_ordinal r) { +400 if (Hide_missing_default_space_errors) return; // skip previous core tests; this is only for Mu code +401 const recipe& caller = get(Recipe, r); +402 // End check_default_space Special-cases +403 // assume recipes with only numeric addresses know what they're doing (usually tests) +404 if (!contains_non_special_name(r)) return; +405 trace(9991, "transform") << "--- check that recipe " << caller.name << " sets default-space" << end(); +406 if (caller.steps.empty()) return; +407 if (caller.steps.at(0).products.empty() +408 || caller.steps.at(0).products.at(0).name != "default-space") { +409 raise << caller.name << " does not seem to start with default-space or local-scope\n" << end(); +410 } +411 } +412 :(after "Load Mu Prelude") +413 Hide_missing_default_space_errors = false; +414 :(after "Test Runs") +415 Hide_missing_default_space_errors = true; +416 :(after "Running Main") +417 Hide_missing_default_space_errors = false; +418 +419 :(code) +420 bool contains_non_special_name(const recipe_ordinal r) { +421 for (map<string, int>::iterator p = Name[r].begin(); p != Name[r].end(); ++p) { +422 if (p->first.empty()) continue; +423 if (p->first.find("stash_") == 0) continue; // generated by rewrite_stashes_to_text (cross-layer) +424 if (!is_special_name(p->first)) +425 return true; +426 } +427 return false; +428 } +429 +430 // reagent comparison -- only between reagents in a single recipe +431 bool operator==(const reagent& a, const reagent& b) { +432 if (a.name != b.name) return false; +433 if (property(a, "space") != property(b, "space")) return false; +434 return true; +435 } +436 +437 bool operator<(const reagent& a, const reagent& b) { +438 int aspace = 0, bspace = 0; +439 if (has_property(a, "space")) aspace = to_integer(property(a, "space")->value); +440 if (has_property(b, "space")) bspace = to_integer(property(b, "space")->value); +441 if (aspace != bspace) return aspace < bspace; +442 return a.name < b.name; +443 } -- cgit 1.4.1-2-gfad0