Chromium Code Reviews| Index: runtime/vm/code_generator.cc |
| diff --git a/runtime/vm/code_generator.cc b/runtime/vm/code_generator.cc |
| index bc9689c2fe3bb0ad5daa9d5785f86ac52aa31c43..6c3ffa746ea3aee0cc3cbb0c4a87f7b0ba8a792b 100644 |
| --- a/runtime/vm/code_generator.cc |
| +++ b/runtime/vm/code_generator.cc |
| @@ -671,7 +671,7 @@ DEFINE_RUNTIME_ENTRY(PatchStaticCall, 0) { |
| " to '%s' new entry point %#" Px " (%s)\n", |
| caller_frame->pc(), |
| target_function.ToFullyQualifiedCString(), |
| - target_code.EntryPoint(), |
| + target_code.UncheckedEntryPoint(), |
| target_code.is_optimized() ? "optimized" : "unoptimized"); |
| } |
| arguments.SetReturn(target_code); |
| @@ -1028,12 +1028,92 @@ DEFINE_RUNTIME_ENTRY(StaticCallMissHandlerTwoArgs, 3) { |
| // Handle a miss of a megamorphic cache. |
| // Arg0: Receiver. |
| +// Returns: the ICData used to continue with a polymorphic call. |
| +DEFINE_RUNTIME_ENTRY(MonomorphicMiss, 1) { |
| +#if defined(TARGET_ARCH_DBC) |
| + // DBC does not use switchable calls. |
| + UNREACHABLE(); |
| +#else |
| + const Instance& receiver = Instance::CheckedHandle(zone, arguments.ArgAt(0)); |
| + |
| + DartFrameIterator iterator; |
| + StackFrame* caller_frame = iterator.NextFrame(); |
| + ASSERT(caller_frame->IsDartFrame()); |
| + const Code& caller_code = Code::Handle(zone, caller_frame->LookupDartCode()); |
| + const Function& caller_function = |
| + Function::Handle(zone, caller_frame->LookupDartFunction()); |
| + |
| + Smi& old_guarded_cid = Smi::Handle(zone); |
|
Florian Schneider
2016/08/10 02:32:14
To avoid overlapping terminology, maybe rename gua
rmacnak
2016/08/11 00:17:49
=> expected_cid
|
| + old_guarded_cid ^= CodePatcher::GetSwitchableCallDataAt(caller_frame->pc(), |
| + caller_code); |
| + const Code& old_target_code = |
| + Code::Handle(CodePatcher::GetSwitchableCallTargetAt(caller_frame->pc(), |
| + caller_code)); |
| + Function& old_target = Function::Handle(zone); |
| + old_target ^= old_target_code.owner(); |
| + |
| + // We lost the original ICData when we patched to the monomorphic case. |
| + const String& name = String::Handle(zone, old_target.name()); |
| + ASSERT(!old_target.HasOptionalParameters()); |
| + const Array& descriptor = Array::Handle(zone, |
| + ArgumentsDescriptor::New(old_target.num_fixed_parameters())); |
| + const ICData& ic_data = |
| + ICData::Handle(zone, ICData::New(caller_function, |
| + name, |
| + descriptor, |
| + Thread::kNoDeoptId, |
| + 1, /* args_tested */ |
| + false /* static_call */)); |
| + |
| + // Add the first target. |
| + ic_data.AddReceiverCheck(old_guarded_cid.Value(), old_target); |
| + |
| + // Patch to call through stub. |
| + Code& stub = Code::Handle(zone); |
| + if (Isolate::Current()->compilation_allowed()) { |
| + stub = StubCode::ICLookupThroughFunction_entry()->code(); |
| + } else { |
| + stub = StubCode::ICLookupThroughCode_entry()->code(); |
| + } |
| + CodePatcher::PatchSwitchableCallAt(caller_frame->pc(), |
| + caller_code, |
| + ic_data, |
| + stub); |
| + |
| + // Maybe add the new target. |
| + Class& cls = Class::Handle(zone, receiver.clazz()); |
| + ArgumentsDescriptor args_desc(descriptor); |
| + Function& target_function = Function::Handle(zone, |
| + Resolver::ResolveDynamicForReceiverClass(cls, |
| + name, |
| + args_desc)); |
| + if (target_function.IsNull()) { |
| + target_function = InlineCacheMissHelper(receiver, descriptor, name); |
| + } |
| + if (target_function.IsNull()) { |
| + ASSERT(!FLAG_lazy_dispatchers); |
| + } else { |
| + ic_data.AddReceiverCheck(receiver.GetClassId(), target_function); |
| + } |
| + |
| + // Return the ICData. The miss stub will jump to continue in the IC lookup |
| + // stub. |
| + arguments.SetArgAt(0, stub); |
| + arguments.SetReturn(ic_data); |
| +#endif // !defined(TARGET_ARCH_DBC) |
| +} |
| + |
| + |
| +// Handle a miss of a megamorphic cache. |
| +// Arg0: Receiver. |
| // Arg1: ICData or MegamorphicCache. |
| // Arg2: Arguments descriptor array. |
| // Returns: target function to call. |
| DEFINE_RUNTIME_ENTRY(MegamorphicCacheMissHandler, 3) { |
| -// DBC does not use megamorphic calls right now. |
| -#if !defined(TARGET_ARCH_DBC) |
| +#if defined(TARGET_ARCH_DBC) |
| + // DBC does not use megamorphic calls right now. |
| + UNREACHABLE(); |
| +#else |
| const Instance& receiver = Instance::CheckedHandle(zone, arguments.ArgAt(0)); |
| const Object& ic_data_or_cache = Object::Handle(zone, arguments.ArgAt(1)); |
| const Array& descriptor = Array::CheckedHandle(zone, arguments.ArgAt(2)); |
| @@ -1067,21 +1147,54 @@ DEFINE_RUNTIME_ENTRY(MegamorphicCacheMissHandler, 3) { |
| if (ic_data_or_cache.IsICData()) { |
| const ICData& ic_data = ICData::Cast(ic_data_or_cache); |
| - ic_data.AddReceiverCheck(receiver.GetClassId(), target_function); |
| - if (ic_data.NumberOfChecks() > FLAG_max_polymorphic_checks) { |
| - // Switch to megamorphic call. |
| - const MegamorphicCache& cache = MegamorphicCache::Handle(zone, |
| - MegamorphicCacheTable::Lookup(isolate, name, descriptor)); |
| + |
| + if ((ic_data.NumberOfChecks() == 0) && |
| + !target_function.HasOptionalParameters()) { |
| + // This call site is unlinked: transition to a monomorphic direct call. |
| + // Note we cannot do this if the target has optional parameters because |
| + // the monomorphic direct call does not load the arguments descriptor. |
| + |
| + if (!target_function.HasCode()) { |
| + const Error& error = |
| + Error::Handle(Compiler::CompileFunction(thread, target_function)); |
| + if (!error.IsNull()) { |
| + Exceptions::PropagateError(error); |
| + } |
| + } |
| + |
| DartFrameIterator iterator; |
| StackFrame* miss_function_frame = iterator.NextFrame(); |
| ASSERT(miss_function_frame->IsDartFrame()); |
| StackFrame* caller_frame = iterator.NextFrame(); |
| ASSERT(caller_frame->IsDartFrame()); |
| - const Code& code = Code::Handle(zone, caller_frame->LookupDartCode()); |
| - const Code& stub = |
| - Code::Handle(zone, StubCode::MegamorphicLookup_entry()->code()); |
| - CodePatcher::PatchSwitchableCallAt(caller_frame->pc(), |
| - code, ic_data, cache, stub); |
| + const Code& caller_code = |
| + Code::Handle(zone, caller_frame->LookupDartCode()); |
| + const Code& target_code = |
| + Code::Handle(zone, target_function.CurrentCode()); |
| + const Smi& expected_cid = |
| + Smi::Handle(zone, Smi::New(receiver.GetClassId())); |
| + |
| + CodePatcher::PatchSwitchableCallAt(caller_frame->pc(), caller_code, |
| + expected_cid, target_code); |
| + } else { |
| + ic_data.AddReceiverCheck(receiver.GetClassId(), target_function); |
| + if (ic_data.NumberOfChecks() > FLAG_max_polymorphic_checks) { |
| + // Switch to megamorphic call. |
| + const MegamorphicCache& cache = MegamorphicCache::Handle(zone, |
| + MegamorphicCacheTable::Lookup(isolate, name, descriptor)); |
| + DartFrameIterator iterator; |
| + StackFrame* miss_function_frame = iterator.NextFrame(); |
| + ASSERT(miss_function_frame->IsDartFrame()); |
| + StackFrame* caller_frame = iterator.NextFrame(); |
| + ASSERT(caller_frame->IsDartFrame()); |
| + const Code& caller_code = |
| + Code::Handle(zone, caller_frame->LookupDartCode()); |
| + const Code& stub = |
| + Code::Handle(zone, StubCode::MegamorphicLookup_entry()->code()); |
| + |
| + CodePatcher::PatchSwitchableCallAt(caller_frame->pc(), caller_code, |
| + cache, stub); |
| + } |
| } |
| } else { |
| const MegamorphicCache& cache = MegamorphicCache::Cast(ic_data_or_cache); |
| @@ -1091,8 +1204,6 @@ DEFINE_RUNTIME_ENTRY(MegamorphicCacheMissHandler, 3) { |
| cache.Insert(class_id, target_function); |
| } |
| arguments.SetReturn(target_function); |
| -#else |
| - UNREACHABLE(); |
| #endif // !defined(TARGET_ARCH_DBC) |
| } |
| @@ -1461,7 +1572,7 @@ DEFINE_RUNTIME_ENTRY(StackOverflow, 0) { |
| // unoptimized code. Patch the stack frame to return into the OSR |
| // code. |
| uword optimized_entry = |
| - Instructions::Handle(optimized_code.instructions()).EntryPoint(); |
| + Instructions::UncheckedEntryPoint(optimized_code.instructions()); |
| function.AttachCode(original_code); |
| frame->set_pc(optimized_entry); |
| frame->set_pc_marker(optimized_code.raw()); |
| @@ -1596,7 +1707,7 @@ DEFINE_RUNTIME_ENTRY(FixCallersTarget, 0) { |
| "target '%s' -> %#" Px "\n", |
| frame->pc(), |
| target_function.ToFullyQualifiedCString(), |
| - current_target_code.EntryPoint()); |
| + current_target_code.UncheckedEntryPoint()); |
| } |
| arguments.SetReturn(current_target_code); |
| } |
| @@ -1638,7 +1749,7 @@ DEFINE_RUNTIME_ENTRY(FixAllocationStubTarget, 0) { |
| " -> %#" Px "\n", |
| frame->pc(), |
| alloc_class.ToCString(), |
| - alloc_stub.EntryPoint()); |
| + alloc_stub.UncheckedEntryPoint()); |
| } |
| arguments.SetReturn(alloc_stub); |
| #else |
| @@ -1690,7 +1801,7 @@ void DeoptimizeAt(const Code& optimized_code, uword pc) { |
| const Instructions& instrs = |
| Instructions::Handle(zone, optimized_code.instructions()); |
| { |
| - WritableInstructionsScope writable(instrs.EntryPoint(), instrs.size()); |
| + WritableInstructionsScope writable(instrs.PayloadStart(), instrs.size()); |
| CodePatcher::InsertDeoptimizationCallAt(pc, lazy_deopt_jump); |
| } |
| if (FLAG_trace_patching) { |