Chromium Code Reviews| Index: runtime/vm/simulator_dbc.cc |
| diff --git a/runtime/vm/simulator_dbc.cc b/runtime/vm/simulator_dbc.cc |
| index e732409bc749e76ffacdcc5c2ef6d5f3a8a0613f..04984c72cc9937e2e07deb6692fc7597376d53d6 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 MAP_CLASS_ID |
|
zra
2016/05/19 16:24:28
#undef DEFINE_CASTS ?
Vyacheslav Egorov (Google)
2016/05/20 12:11:47
Done.
|
| + |
| 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,16 +1397,21 @@ 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); |
| + BYTECODE(InstanceCall1Opt, A_D); |
| + |
| + // Check if single stepping. |
|
Florian Schneider
2016/05/19 13:21:40
Optimized code can't be single stepped.
Vyacheslav Egorov (Google)
2016/05/19 15:19:40
Done.
|
| if (thread->isolate()->single_step()) { |
| Exit(thread, FP, SP + 1, pc); |
| NativeArguments args(thread, 0, NULL, NULL); |
| @@ -1364,9 +1424,35 @@ RawObject* Simulator::Call(const Code& code, |
| 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)); |
| + InstanceCall1( |
| + thread, icdata, call_base, call_top, &argdesc, &pp, &pc, &FP, &SP); |
| + } |
| + |
| + DISPATCH(); |
| + } |
| + |
| + { |
| + BYTECODE(InstanceCall2Opt, A_D); |
| + if (thread->isolate()->single_step()) { |
|
Florian Schneider
2016/05/19 13:21:40
Optimized code can't be single-stepped.
Vyacheslav Egorov (Google)
2016/05/19 15:19:40
Done.
|
| + Exit(thread, FP, SP + 1, pc); |
| + NativeArguments args(thread, 0, NULL, NULL); |
| + INVOKE_RUNTIME(DRT_SingleStepHandler, args); |
| + } |
| + |
| + { |
| + 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)); |
| + InstanceCall2( |
| + thread, icdata, call_base, call_top, &argdesc, &pp, &pc, &FP, &SP); |
| } |
| DISPATCH(); |
| @@ -1495,7 +1581,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 +1826,7 @@ RawObject* Simulator::Call(const Code& code, |
| } |
| { |
| - BYTECODE(IfEqStrictTOS, A_D); |
| + BYTECODE(IfEqStrictTOS, 0); |
| SP -= 2; |
| if (SP[1] != SP[2]) { |
| pc++; |
| @@ -1749,7 +1835,7 @@ RawObject* Simulator::Call(const Code& code, |
| } |
| { |
| - BYTECODE(IfNeStrictTOS, A_D); |
| + BYTECODE(IfNeStrictTOS, 0); |
| SP -= 2; |
| if (SP[1] == SP[2]) { |
| pc++; |
| @@ -1758,7 +1844,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 +1859,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 +1874,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 +1943,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 +2041,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; |