From 78a12c9d706f6197d3710ece04e9bd8d4eebe713 Mon Sep 17 00:00:00 2001 From: "Kartik K. Agaram" Date: Tue, 16 Aug 2016 17:03:27 -0700 Subject: 3202 - bugfix: 'start-running' and refcounts When you pass an ingredient to a recipe using 'start-running' it mostly behaves identically to performing a regular function call. However, if the calling function completed before the new routine had a chance to run, the ingredients passed in ran the risk of being reclaimed. In response, let's always increment refcounts at the time of a function call rather than when the ingredients are read inside the callee. Now the summary of commit 3197 is modified to this: Update refcounts of products after every instruction, EXCEPT: a) when instruction is a non-primitive and the callee starts with 'local-scope' (because it's already not decremented in 'return') OR: b) when instruction is primitive 'next-ingredient' or 'next-ingredient-without-typechecking' --- 072scheduler.cc | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) (limited to '072scheduler.cc') diff --git a/072scheduler.cc b/072scheduler.cc index 61d759ea..068e1617 100644 --- a/072scheduler.cc +++ b/072scheduler.cc @@ -171,6 +171,7 @@ case START_RUNNING: { reagent/*copy*/ ingredient = current_instruction().ingredients.at(i); canonize_type(ingredient); new_routine->calls.front().ingredients.push_back(ingredient); + // End Populate start-running Ingredient } Routines.push_back(new_routine); products.resize(1); @@ -225,6 +226,64 @@ def f2 [ ] +mem: storing 4 in location 2 +//: more complex: refcounting management when starting up new routines + +:(scenario start_running_immediately_updates_refcounts_of_ingredients) +def main [ + local-scope + create-new-routine + switch # make sure we run new routine before returning +] +def create-new-routine [ + local-scope + n:address:number <- new number:type + *n <- copy 34 + start-running new-routine, n + # refcount of n decremented +] +def new-routine n:address:number [ + local-scope + load-ingredients + 1:number/raw <- copy *n +] +# check that n wasn't reclaimed when create-new-routine returned ++mem: storing 34 in location 1 + +//: to support the previous scenario we'll increment refcounts for all call +//: ingredients right at call time, and stop incrementing refcounts inside +//: next-ingredient +:(before "End Populate Call Ingredient") +increment_any_refcounts(ingredient, ingredients.at(i)); +:(before "End Populate start-running Ingredient") +increment_any_refcounts(ingredient, ingredients.at(i)); +:(before "End should_update_refcounts_in_write_memory Special-cases For Primitives") +if (inst.operation == NEXT_INGREDIENT || inst.operation == NEXT_INGREDIENT_WITHOUT_TYPECHECKING) + return false; +:(code) +void increment_any_refcounts(const reagent& x, const vector& data) { + if (is_mu_address(x)) { + assert(scalar(data)); + assert(x.value); + assert(!x.metadata.size); + increment_refcount(data.at(0)); + } + if (is_mu_container(x) || is_mu_exclusive_container(x)) { + const container_metadata& metadata = get(Container_metadata, 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) + increment_refcount(data.at(info->offset)); + } + } +} + +void increment_refcount(int address) { + if (address == 0) return; + int refcount = get_or_insert(Memory, address); + trace(9999, "mem") << "incrementing refcount of " << address << ": " << refcount << " -> " << refcount+1 << end(); + put(Memory, address, refcount+1); +} + :(scenario start_running_returns_routine_id) def f1 [ 1:number <- start-running f2 -- cgit 1.4.1-2-gfad0