| Index: runtime/vm/code_generator.cc
|
| diff --git a/runtime/vm/code_generator.cc b/runtime/vm/code_generator.cc
|
| index bc9689c2fe3bb0ad5daa9d5785f86ac52aa31c43..ca1ba0bd52d019871ef330fb12e04197e41ccf63 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,88 @@ 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_expected_cid = Smi::Handle(zone);
|
| + old_expected_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_expected_cid.Value(), old_target);
|
| +
|
| + // 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);
|
| + }
|
| +
|
| + // Patch to call through stub.
|
| + const Code& stub =
|
| + Code::Handle(zone, StubCode::ICLookupThroughCode_entry()->code());
|
| + ASSERT(!Isolate::Current()->compilation_allowed());
|
| + CodePatcher::PatchSwitchableCallAt(caller_frame->pc(),
|
| + caller_code,
|
| + ic_data,
|
| + stub);
|
| +
|
| + // Return the ICData. The miss stub will jump to continue in the IC lookup
|
| + // 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 +1143,58 @@ 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() &&
|
| + !Isolate::Current()->compilation_allowed()) {
|
| + // 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.
|
| + // We cannot do this if we are still in the middle of precompiling because
|
| + // the monomorphic case hides an live instance selector from the
|
| + // treeshaker.
|
| +
|
| + 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) {
|
|
|