Index: runtime/vm/simulator_dbc.cc |
diff --git a/runtime/vm/simulator_dbc.cc b/runtime/vm/simulator_dbc.cc |
index e732409bc749e76ffacdcc5c2ef6d5f3a8a0613f..ffe4e9285c7f38ef50cbac33b65e2daccf027b2b 100644 |
--- a/runtime/vm/simulator_dbc.cc |
+++ b/runtime/vm/simulator_dbc.cc |
@@ -87,24 +87,26 @@ DART_FORCE_INLINE static RawObject** SavedCallerFP(RawObject** FP) { |
} |
-DART_FORCE_INLINE static RawCode* FrameCode(RawObject** FP) { |
- return static_cast<RawCode*>(FP[kPcMarkerSlotFromFp]); |
-} |
- |
- |
-DART_FORCE_INLINE static void SetFrameCode(RawObject** FP, RawCode* code) { |
- FP[kPcMarkerSlotFromFp] = code; |
-} |
- |
- |
DART_FORCE_INLINE static RawObject** FrameArguments(RawObject** FP, |
intptr_t argc) { |
return FP - (kDartFrameFixedSize + argc); |
} |
+#define RAW_CAST(Type, val) (SimulatorHelpers::CastTo##Type(val)) |
+ |
+ |
class SimulatorHelpers { |
public: |
+#define DEFINE_CASTS(Type) \ |
+ DART_FORCE_INLINE static Raw##Type* CastTo##Type(RawObject* obj) { \ |
+ ASSERT((k##Type##Cid == kSmiCid) ? !obj->IsHeapObject() \ |
+ : obj->Is##Type()); \ |
+ return reinterpret_cast<Raw##Type*>(obj); \ |
+ } |
+ CLASS_LIST(DEFINE_CASTS) |
+#undef DEFINE_CASTS |
+ |
DART_FORCE_INLINE static RawSmi* GetClassIdAsSmi(RawObject* obj) { |
return Smi::New(obj->IsHeapObject() ? obj->GetClassId() |
: static_cast<intptr_t>(kSmiCid)); |
@@ -115,10 +117,8 @@ class SimulatorHelpers { |
: static_cast<intptr_t>(kSmiCid); |
} |
- DART_FORCE_INLINE static void IncrementUsageCounter(RawICData* icdata) { |
- reinterpret_cast<RawFunction*>(icdata->ptr()->owner_) |
- ->ptr() |
- ->usage_counter_++; |
+ DART_FORCE_INLINE static void IncrementUsageCounter(RawFunction* f) { |
+ f->ptr()->usage_counter_++; |
} |
DART_FORCE_INLINE static bool IsStrictEqualWithNumberCheck(RawObject* lhs, |
@@ -226,6 +226,17 @@ class SimulatorHelpers { |
} |
return false; |
} |
+ |
+ DART_FORCE_INLINE static RawCode* FrameCode(RawObject** FP) { |
+ ASSERT(GetClassId(FP[kPcMarkerSlotFromFp]) == kCodeCid); |
+ return static_cast<RawCode*>(FP[kPcMarkerSlotFromFp]); |
+ } |
+ |
+ |
+ DART_FORCE_INLINE static void SetFrameCode(RawObject** FP, RawCode* code) { |
+ ASSERT(GetClassId(code) == kCodeCid); |
+ FP[kPcMarkerSlotFromFp] = code; |
+ } |
}; |
@@ -482,6 +493,26 @@ void Simulator::CallRuntime(Thread* thread, |
} |
+DART_FORCE_INLINE static void EnterSyntheticFrame(RawObject*** FP, |
+ RawObject*** SP, |
+ uint32_t* pc) { |
+ RawObject** fp = *SP + kDartFrameFixedSize; |
+ fp[kPcMarkerSlotFromFp] = 0; |
+ fp[kSavedCallerPcSlotFromFp] = reinterpret_cast<RawObject*>(pc); |
+ fp[kSavedCallerFpSlotFromFp] = reinterpret_cast<RawObject*>(*FP); |
+ *FP = fp; |
+ *SP = fp - 1; |
+} |
+ |
+ |
+DART_FORCE_INLINE static void LeaveSyntheticFrame(RawObject*** FP, |
+ RawObject*** SP) { |
+ RawObject** fp = *FP; |
+ *FP = reinterpret_cast<RawObject**>(fp[kSavedCallerFpSlotFromFp]); |
+ *SP = fp - kDartFrameFixedSize; |
+} |
+ |
+ |
DART_FORCE_INLINE void Simulator::Invoke(Thread* thread, |
RawObject** call_base, |
RawObject** call_top, |
@@ -557,7 +588,6 @@ DART_FORCE_INLINE void Simulator::InstanceCall1(Thread* thread, |
RawObject*** FP, |
RawObject*** SP) { |
ASSERT(icdata->GetClassId() == kICDataCid); |
- SimulatorHelpers::IncrementUsageCounter(icdata); |
const intptr_t kCheckedArgs = 1; |
RawObject** args = call_base; |
@@ -596,7 +626,6 @@ DART_FORCE_INLINE void Simulator::InstanceCall2(Thread* thread, |
RawObject*** FP, |
RawObject*** SP) { |
ASSERT(icdata->GetClassId() == kICDataCid); |
- SimulatorHelpers::IncrementUsageCounter(icdata); |
const intptr_t kCheckedArgs = 2; |
RawObject** args = call_base; |
@@ -627,49 +656,6 @@ DART_FORCE_INLINE void Simulator::InstanceCall2(Thread* thread, |
} |
-DART_FORCE_INLINE void Simulator::InstanceCall3(Thread* thread, |
- RawICData* icdata, |
- RawObject** call_base, |
- RawObject** top, |
- RawArray** argdesc, |
- RawObjectPool** pp, |
- uint32_t** pc, |
- RawObject*** FP, |
- RawObject*** SP) { |
- ASSERT(icdata->GetClassId() == kICDataCid); |
- SimulatorHelpers::IncrementUsageCounter(icdata); |
- |
- const intptr_t kCheckedArgs = 3; |
- RawObject** args = call_base; |
- RawArray* cache = icdata->ptr()->ic_data_->ptr(); |
- |
- RawSmi* receiver_cid = SimulatorHelpers::GetClassIdAsSmi(args[0]); |
- RawSmi* arg0_cid = SimulatorHelpers::GetClassIdAsSmi(args[1]); |
- RawSmi* arg1_cid = SimulatorHelpers::GetClassIdAsSmi(args[2]); |
- |
- bool found = false; |
- const intptr_t length = Smi::Value(cache->length_); |
- for (intptr_t i = 0; |
- i < (length - (kCheckedArgs + 2)); i += (kCheckedArgs + 2)) { |
- if ((cache->data()[i + 0] == receiver_cid) && |
- (cache->data()[i + 1] == arg0_cid) && |
- (cache->data()[i + 2] == arg1_cid)) { |
- top[0] = cache->data()[i + kCheckedArgs]; |
- found = true; |
- break; |
- } |
- } |
- |
- if (!found) { |
- InlineCacheMiss( |
- kCheckedArgs, thread, icdata, call_base, top, *pc, *FP, *SP); |
- } |
- |
- *argdesc = icdata->ptr()->args_descriptor_; |
- Invoke(thread, call_base, top, pp, pc, FP, SP); |
-} |
- |
- |
// Note: functions below are marked DART_NOINLINE to recover performance on |
// ARM where inlining these functions into the interpreter loop seemed to cause |
// some code quality issues. |
@@ -801,7 +787,7 @@ static DART_NOINLINE bool InvokeNativeWrapper( |
thread->set_vm_tag(vm_tag); \ |
return special_[kExceptionSpecialIndex]; \ |
} \ |
- pp = FrameCode(FP)->ptr()->object_pool_->ptr(); \ |
+ pp = SimulatorHelpers::FrameCode(FP)->ptr()->object_pool_->ptr(); \ |
goto DispatchAfterException; \ |
} while (0) \ |
@@ -950,7 +936,29 @@ RawObject* Simulator::Call(const Code& code, |
} |
{ |
- BYTECODE(EntryOpt, A_B_C); |
+ BYTECODE(EntryOptimized, A_D); |
+ const uint8_t num_fixed_params = rA; |
+ const uint16_t num_registers = rD; |
+ |
+ // Decode arguments descriptor. |
+ const intptr_t pos_count = Smi::Value(*reinterpret_cast<RawSmi**>( |
+ reinterpret_cast<uword>(argdesc->ptr()) + |
+ Array::element_offset(ArgumentsDescriptor::kPositionalCountIndex))); |
+ |
+ // Check that we got the right number of positional parameters. |
+ if (pos_count != num_fixed_params) { |
+ // Mismatch can only occur if current function is a closure. |
+ goto ClosureNoSuchMethod; |
+ } |
+ |
+ // Reserve space for registers used by the optimized code. |
+ SP = FP + num_registers - 1; |
+ |
+ DISPATCH(); |
+ } |
+ |
+ { |
+ BYTECODE(EntryOptional, A_B_C); |
const uint16_t num_fixed_params = rA; |
const uint16_t num_opt_pos_params = rB; |
const uint16_t num_opt_named_params = rC; |
@@ -1098,7 +1106,7 @@ RawObject* Simulator::Call(const Code& code, |
{ |
// Function should be compiled now, dispatch to its entry point. |
RawCode* code = FrameFunction(FP)->ptr()->code_; |
- SetFrameCode(FP, code); |
+ SimulatorHelpers::SetFrameCode(FP, code); |
pp = code->ptr()->object_pool_->ptr(); |
pc = reinterpret_cast<uint32_t*>(code->ptr()->entry_point_); |
} |
@@ -1106,6 +1114,36 @@ RawObject* Simulator::Call(const Code& code, |
} |
{ |
+ BYTECODE(HotCheck, A_D); |
+ const uint8_t increment = rA; |
+ const uint16_t threshold = rD; |
+ RawFunction* f = FrameFunction(FP); |
+ int32_t counter = f->ptr()->usage_counter_; |
+ // Note: we don't increment usage counter in the prologue of optimized |
+ // functions. |
+ if (increment) { |
+ counter += increment; |
+ f->ptr()->usage_counter_ = counter; |
+ } |
+ if (counter >= threshold) { |
+ FP[0] = f; |
+ FP[1] = 0; |
+ Exit(thread, FP, FP + 2, pc); |
+ NativeArguments args(thread, 1, FP, FP + 1); |
+ INVOKE_RUNTIME(DRT_OptimizeInvokedFunction, args); |
+ { |
+ // DRT_OptimizeInvokedFunction returns the code object to execute. |
+ ASSERT(FP[1]->GetClassId() == kCodeCid); |
+ RawCode* code = static_cast<RawCode*>(FP[1]); |
+ SimulatorHelpers::SetFrameCode(FP, code); |
+ pp = code->ptr()->object_pool_->ptr(); |
+ pc = reinterpret_cast<uint32_t*>(code->ptr()->entry_point_); |
+ } |
+ } |
+ DISPATCH(); |
+ } |
+ |
+ { |
BYTECODE(CheckStack, A); |
{ |
if (reinterpret_cast<uword>(SP) >= thread->stack_limit()) { |
@@ -1259,6 +1297,14 @@ RawObject* Simulator::Call(const Code& code, |
} |
{ |
+ BYTECODE(Swap, A_X); |
+ RawObject* tmp = FP[rD]; |
+ FP[rD] = FP[rA]; |
+ FP[rA] = tmp; |
+ DISPATCH(); |
+ } |
+ |
+ { |
BYTECODE(StoreLocal, A_X); |
FP[rD] = *SP; |
DISPATCH(); |
@@ -1283,6 +1329,12 @@ RawObject* Simulator::Call(const Code& code, |
} |
{ |
+ BYTECODE(BooleanNegate, A_D); |
+ FP[rA] = (FP[rD] == true_value) ? false_value : true_value; |
+ DISPATCH(); |
+ } |
+ |
+ { |
BYTECODE(StaticCall, A_D); |
// Check if single stepping. |
@@ -1305,7 +1357,7 @@ RawObject* Simulator::Call(const Code& code, |
} |
{ |
- BYTECODE(InstanceCall, A_D); |
+ BYTECODE(InstanceCall1, A_D); |
// Check if single stepping. |
if (thread->isolate()->single_step()) { |
@@ -1320,9 +1372,12 @@ RawObject* Simulator::Call(const Code& code, |
RawObject** call_base = SP - argc + 1; |
RawObject** call_top = SP + 1; |
- InstanceCall1(thread, |
- static_cast<RawICData*>(LOAD_CONSTANT(kidx)), |
- call_base, call_top, &argdesc, &pp, &pc, &FP, &SP); |
+ |
+ RawICData* icdata = RAW_CAST(ICData, LOAD_CONSTANT(kidx)); |
+ SimulatorHelpers::IncrementUsageCounter( |
+ RAW_CAST(Function, icdata->ptr()->owner_)); |
+ InstanceCall1( |
+ thread, icdata, call_base, call_top, &argdesc, &pp, &pc, &FP, &SP); |
} |
DISPATCH(); |
@@ -1342,31 +1397,50 @@ RawObject* Simulator::Call(const Code& code, |
RawObject** call_base = SP - argc + 1; |
RawObject** call_top = SP + 1; |
- InstanceCall2(thread, |
- static_cast<RawICData*>(LOAD_CONSTANT(kidx)), |
- call_base, call_top, &argdesc, &pp, &pc, &FP, &SP); |
+ |
+ RawICData* icdata = RAW_CAST(ICData, LOAD_CONSTANT(kidx)); |
+ SimulatorHelpers::IncrementUsageCounter( |
+ RAW_CAST(Function, icdata->ptr()->owner_)); |
+ InstanceCall2( |
+ thread, icdata, call_base, call_top, &argdesc, &pp, &pc, &FP, &SP); |
} |
DISPATCH(); |
} |
{ |
- BYTECODE(InstanceCall3, A_D); |
- if (thread->isolate()->single_step()) { |
- Exit(thread, FP, SP + 1, pc); |
- NativeArguments args(thread, 0, NULL, NULL); |
- INVOKE_RUNTIME(DRT_SingleStepHandler, args); |
+ BYTECODE(InstanceCall1Opt, A_D); |
+ |
+ { |
+ const uint16_t argc = rA; |
+ const uint16_t kidx = rD; |
+ |
+ RawObject** call_base = SP - argc + 1; |
+ RawObject** call_top = SP + 1; |
+ |
+ RawICData* icdata = RAW_CAST(ICData, LOAD_CONSTANT(kidx)); |
+ SimulatorHelpers::IncrementUsageCounter(FrameFunction(FP)); |
+ InstanceCall1( |
+ thread, icdata, call_base, call_top, &argdesc, &pp, &pc, &FP, &SP); |
} |
+ DISPATCH(); |
+ } |
+ |
+ { |
+ BYTECODE(InstanceCall2Opt, A_D); |
+ |
{ |
const uint16_t argc = rA; |
const uint16_t kidx = rD; |
RawObject** call_base = SP - argc + 1; |
RawObject** call_top = SP + 1; |
- InstanceCall3(thread, |
- static_cast<RawICData*>(LOAD_CONSTANT(kidx)), |
- call_base, call_top, &argdesc, &pp, &pc, &FP, &SP); |
+ |
+ RawICData* icdata = RAW_CAST(ICData, LOAD_CONSTANT(kidx)); |
+ SimulatorHelpers::IncrementUsageCounter(FrameFunction(FP)); |
+ InstanceCall2( |
+ thread, icdata, call_base, call_top, &argdesc, &pp, &pc, &FP, &SP); |
} |
DISPATCH(); |
@@ -1495,7 +1569,7 @@ RawObject* Simulator::Call(const Code& code, |
// Restore SP, FP and PP. Push result and dispatch. |
SP = FrameArguments(FP, argc); |
FP = SavedCallerFP(FP); |
- pp = FrameCode(FP)->ptr()->object_pool_->ptr(); |
+ pp = SimulatorHelpers::FrameCode(FP)->ptr()->object_pool_->ptr(); |
*SP = result; |
DISPATCH(); |
} |
@@ -1740,7 +1814,7 @@ RawObject* Simulator::Call(const Code& code, |
} |
{ |
- BYTECODE(IfEqStrictTOS, A_D); |
+ BYTECODE(IfEqStrictTOS, 0); |
SP -= 2; |
if (SP[1] != SP[2]) { |
pc++; |
@@ -1749,7 +1823,7 @@ RawObject* Simulator::Call(const Code& code, |
} |
{ |
- BYTECODE(IfNeStrictTOS, A_D); |
+ BYTECODE(IfNeStrictTOS, 0); |
SP -= 2; |
if (SP[1] == SP[2]) { |
pc++; |
@@ -1758,7 +1832,7 @@ RawObject* Simulator::Call(const Code& code, |
} |
{ |
- BYTECODE(IfEqStrictNumTOS, A_D); |
+ BYTECODE(IfEqStrictNumTOS, 0); |
if (thread->isolate()->single_step()) { |
Exit(thread, FP, SP + 1, pc); |
NativeArguments args(thread, 0, NULL, NULL); |
@@ -1773,7 +1847,7 @@ RawObject* Simulator::Call(const Code& code, |
} |
{ |
- BYTECODE(IfNeStrictNumTOS, A_D); |
+ BYTECODE(IfNeStrictNumTOS, 0); |
if (thread->isolate()->single_step()) { |
Exit(thread, FP, SP + 1, pc); |
NativeArguments args(thread, 0, NULL, NULL); |
@@ -1788,6 +1862,46 @@ RawObject* Simulator::Call(const Code& code, |
} |
{ |
+ BYTECODE(IfEqStrict, A_D); |
+ RawObject* lhs = FP[rA]; |
+ RawObject* rhs = FP[rD]; |
+ if (lhs != rhs) { |
+ pc++; |
+ } |
+ DISPATCH(); |
+ } |
+ |
+ { |
+ BYTECODE(IfNeStrict, A_D); |
+ RawObject* lhs = FP[rA]; |
+ RawObject* rhs = FP[rD]; |
+ if (lhs == rhs) { |
+ pc++; |
+ } |
+ DISPATCH(); |
+ } |
+ |
+ { |
+ BYTECODE(IfEqStrictNum, A_D); |
+ RawObject* lhs = FP[rA]; |
+ RawObject* rhs = FP[rD]; |
+ if (!SimulatorHelpers::IsStrictEqualWithNumberCheck(lhs, rhs)) { |
+ pc++; |
+ } |
+ DISPATCH(); |
+ } |
+ |
+ { |
+ BYTECODE(IfNeStrictNum, A_D); |
+ RawObject* lhs = FP[rA]; |
+ RawObject* rhs = FP[rD]; |
+ if (SimulatorHelpers::IsStrictEqualWithNumberCheck(lhs, rhs)) { |
+ pc++; |
+ } |
+ DISPATCH(); |
+ } |
+ |
+ { |
BYTECODE(Jump, 0); |
const int32_t target = static_cast<int32_t>(op) >> 8; |
pc += (target - 1); |
@@ -1817,11 +1931,79 @@ RawObject* Simulator::Call(const Code& code, |
RawObject* value = SP[3]; |
ASSERT(array->GetClassId() == kArrayCid); |
ASSERT(!index->IsHeapObject()); |
+ ASSERT(SimulatorHelpers::CheckIndex(index, array->ptr()->length_)); |
+ array->StorePointer(array->ptr()->data() + Smi::Value(index), value); |
+ DISPATCH(); |
+ } |
+ |
+ { |
+ BYTECODE(StoreIndexed, A_B_C); |
+ RawArray* array = static_cast<RawArray*>(FP[rA]); |
+ RawSmi* index = static_cast<RawSmi*>(FP[rB]); |
+ RawObject* value = FP[rC]; |
+ ASSERT(array->GetClassId() == kArrayCid); |
+ ASSERT(!index->IsHeapObject()); |
+ ASSERT(SimulatorHelpers::CheckIndex(index, array->ptr()->length_)); |
array->StorePointer(array->ptr()->data() + Smi::Value(index), value); |
DISPATCH(); |
} |
{ |
+ BYTECODE(Deopt, A_D); |
+ const uint16_t deopt_id = rD; |
+ if (deopt_id == 0) { // Lazy deoptimization. |
+ // Preserve result of the previous call. |
+ // TODO(vegorov) we could have actually included result into the |
+ // deoptimization environment because it is passed through the stack. |
+ // If we do then we could remove special result handling from this code. |
+ RawObject* result = SP[0]; |
+ |
+ // Leaf runtime function DeoptimizeCopyFrame expects a Dart frame. |
+ // The code in this frame may not cause GC. |
+ // DeoptimizeCopyFrame and DeoptimizeFillFrame are leaf runtime calls. |
+ EnterSyntheticFrame(&FP, &SP, pc - 1); |
+ const intptr_t frame_size_in_bytes = |
+ DLRT_DeoptimizeCopyFrame(reinterpret_cast<uword>(FP), |
+ /*is_lazy_deopt=*/1); |
+ LeaveSyntheticFrame(&FP, &SP); |
+ |
+ SP = FP + (frame_size_in_bytes / kWordSize); |
+ EnterSyntheticFrame(&FP, &SP, pc - 1); |
+ DLRT_DeoptimizeFillFrame(reinterpret_cast<uword>(FP)); |
+ |
+ // We are now inside a valid frame. |
+ { |
+ *++SP = result; // Preserve result (call below can cause GC). |
+ *++SP = 0; // Space for the result: number of materialization args. |
+ Exit(thread, FP, SP + 1, /*pc=*/0); |
+ NativeArguments native_args(thread, 0, SP, SP); |
+ INVOKE_RUNTIME(DRT_DeoptimizeMaterialize, native_args); |
+ } |
+ const intptr_t materialization_arg_count = |
+ Smi::Value(RAW_CAST(Smi, *SP--)); |
+ result = *SP--; // Reload the result. It might have been relocated by GC. |
+ |
+ // Restore caller PC. |
+ pc = SavedCallerPC(FP); |
+ |
+ // Check if it is a fake PC marking the entry frame. |
+ ASSERT((reinterpret_cast<uword>(pc) & 2) == 0); |
+ |
+ // Restore SP, FP and PP. Push result and dispatch. |
+ // Note: unlike in a normal return sequence we don't need to drop |
+ // arguments - those are not part of the innermost deoptimization |
+ // environment they were dropped by FlowGraphCompiler::RecordAfterCall. |
+ SP = FrameArguments(FP, materialization_arg_count); |
+ FP = SavedCallerFP(FP); |
+ pp = SimulatorHelpers::FrameCode(FP)->ptr()->object_pool_->ptr(); |
+ *SP = result; |
+ } else { |
+ UNIMPLEMENTED(); |
+ } |
+ DISPATCH(); |
+ } |
+ |
+ { |
BYTECODE(Trap, 0); |
UNIMPLEMENTED(); |
DISPATCH(); |
@@ -1847,7 +2029,7 @@ RawObject* Simulator::Call(const Code& code, |
RawObject** args = SP - argc; |
FP = SavedCallerFP(FP); |
if (has_dart_caller) { |
- pp = FrameCode(FP)->ptr()->object_pool_->ptr(); |
+ pp = SimulatorHelpers::FrameCode(FP)->ptr()->object_pool_->ptr(); |
} |
*++SP = null_value; |