Index: runtime/vm/code_generator.cc |
diff --git a/runtime/vm/code_generator.cc b/runtime/vm/code_generator.cc |
index fb9e84635d038f7adc2ab0c2a6b9642b4080dfc4..5ddbf867b71e256814356e4320006bfc362781f3 100644 |
--- a/runtime/vm/code_generator.cc |
+++ b/runtime/vm/code_generator.cc |
@@ -1545,7 +1545,7 @@ DEFINE_LEAF_RUNTIME_ENTRY(intptr_t, DeoptimizeCopyFrame, |
const intptr_t num_args = |
function.HasOptionalParameters() ? 0 : function.num_fixed_parameters(); |
intptr_t unoptimized_stack_size = |
- + deopt_info.TranslationLength() - num_args |
+ + deopt_info.FrameSize() - num_args |
- kLastParamSlotIndex; // Subtract caller FP and PC (possibly pc marker). |
return unoptimized_stack_size * kWordSize; |
} |
@@ -1577,16 +1577,44 @@ static intptr_t DeoptimizeWithDeoptInfo(const Code& code, |
Array::Handle(code.object_table()), |
num_args, |
static_cast<DeoptReasonId>(deopt_reason)); |
- for (intptr_t to_index = len - 1; to_index >= 0; to_index--) { |
- deopt_instructions[to_index]->Execute(&deopt_context, to_index); |
+ const intptr_t frame_size = deopt_info.FrameSize(); |
+ |
+ // All kMaterializeObject instructions are emitted before the instructions |
+ // that describe stack frames. Skip them and defer materialization of |
+ // objects until the frame is fully reconstructed and it is safe to perform |
+ // GC. |
+ // Arguments (class of the instance to allocate and field-value pairs) are |
+ // described as part of the expression stack for the bottom-most deoptimized |
+ // frame. They will be used during materialization and removed from the stack |
+ // right before control switches to the unoptimized code. |
+ const intptr_t num_materializations = len - frame_size; |
+ Isolate::Current()->PrepareForDeferredMaterialization(num_materializations); |
+ for (intptr_t from_index = 0, to_index = 1; |
+ from_index < num_materializations; |
+ from_index++) { |
+ const intptr_t field_count = |
+ DeoptInstr::GetFieldCount(deopt_instructions[from_index]); |
+ intptr_t* args = deopt_context.GetToFrameAddressAt(to_index); |
+ DeferredObject* obj = new DeferredObject(field_count, args); |
+ Isolate::Current()->SetDeferredObjectAt(from_index, obj); |
+ to_index += obj->ArgumentCount(); |
} |
+ |
+ // Populate stack frames. |
+ for (intptr_t to_index = frame_size - 1, from_index = len - 1; |
+ to_index >= 0; |
+ to_index--, from_index--) { |
+ intptr_t* to_addr = deopt_context.GetToFrameAddressAt(to_index); |
+ deopt_instructions[from_index]->Execute(&deopt_context, to_addr); |
+ } |
+ |
if (FLAG_trace_deoptimization_verbose) { |
- for (intptr_t i = 0; i < len; i++) { |
- OS::PrintErr("*%"Pd". [%p] %#014"Px" [%s]\n", |
- i, |
- &start[i], |
- start[i], |
- deopt_instructions[i]->ToCString()); |
+ for (intptr_t i = 0; i < frame_size; i++) { |
+ OS::PrintErr("*%"Pd". [%"Px"] %#014"Px" [%s]\n", |
+ i, |
+ reinterpret_cast<uword>(&start[i]), |
+ start[i], |
+ deopt_instructions[i + (len - frame_size)]->ToCString()); |
} |
} |
return deopt_context.GetCallerFp(); |
@@ -1637,17 +1665,30 @@ END_LEAF_RUNTIME_ENTRY |
// This is the last step in the deoptimization, GC can occur. |
-DEFINE_RUNTIME_ENTRY(DeoptimizeMaterializeDoubles, 0) { |
- DeferredObject* deferred_object = Isolate::Current()->DetachDeferredObjects(); |
- |
- while (deferred_object != NULL) { |
- DeferredObject* current = deferred_object; |
- deferred_object = deferred_object->next(); |
- |
- current->Materialize(); |
- |
- delete current; |
+// Returns number of bytes to remove from the expression stack of the |
+// bottom-most deoptimized frame. Those arguments were artificially injected |
+// under return address to keep them discoverable by GC that can occur during |
+// materialization phase. |
+DEFINE_RUNTIME_ENTRY(DeoptimizeMaterialize, 0) { |
+ // First materialize all unboxed "primitive" values (doubles, mints, simd) |
+ // then materialize objects. The order is important: objects might be |
+ // referencing boxes allocated on the first step. At the same time |
+ // objects can't be referencing other deferred objects because storing |
+ // an object into a field is always conservatively treated as escaping by |
+ // allocation sinking and load forwarding. |
+ isolate->MaterializeDeferredBoxes(); |
+ isolate->MaterializeDeferredObjects(); |
+ |
+ // Compute total number of artificial arguments used during deoptimization. |
+ intptr_t deopt_arguments = 0; |
+ for (intptr_t i = 0; i < isolate->DeferredObjectsCount(); i++) { |
+ deopt_arguments += isolate->GetDeferredObject(i)->ArgumentCount(); |
} |
+ Isolate::Current()->DeleteDeferredObjects(); |
+ |
+ // Return value tells deoptimization stub to remove the given number of bytes |
+ // from the stack. |
+ arguments.SetReturn(Smi::Handle(Smi::New(deopt_arguments * kWordSize))); |
// Since this is the only step where GC can occur during deoptimization, |
// use it to report the source line where deoptimization occured. |