mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 11:03:19 +00:00
[vm/aot] Ignore artificial methods when computing single target.
When AOT call specializer computes single target for a method invocation it needs to ignore artificial methods like field dispatchers and method extractors that are lazily injected by the precompiler as compilation of the whole application progresses. Lazy injections means that we don't have complete knowledge when we compile a single method. Bug: Change-Id: I249ca397bb3da89f512a1ace49b198a0ffc9bf97 Reviewed-on: https://dart-review.googlesource.com/30520 Commit-Queue: Vyacheslav Egorov <vegorov@google.com> Reviewed-by: Alexander Markov <alexmarkov@google.com>
This commit is contained in:
parent
f150c47ac1
commit
c41e92de84
|
@ -0,0 +1,49 @@
|
||||||
|
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
|
||||||
|
// for details. All rights reserved. Use of this source code is governed by a
|
||||||
|
// BSD-style license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
import "package:expect/expect.dart";
|
||||||
|
|
||||||
|
// Note: below we are using tear-offs instead of calling methods directly
|
||||||
|
// to guarantee very specific compilation order:
|
||||||
|
//
|
||||||
|
// - compile main, add get:methodM and get:callMethodM to selector set.
|
||||||
|
// - compile A.callMethodM and add get:createB to selector set.
|
||||||
|
// - compile A.createB and mark B as allocated.
|
||||||
|
//
|
||||||
|
// Class B is not marked as allocated until A.createB is compiled, which means
|
||||||
|
// that when A.callMethodM is compiled only class A has get:methodM method
|
||||||
|
// extractor injected.
|
||||||
|
//
|
||||||
|
// This test is verifying that optimizing compiler does not treat this method
|
||||||
|
// extractor as a single target for this.get:methodM call.
|
||||||
|
main() {
|
||||||
|
// This adds selector 'get:methodM' into the sent selector set and
|
||||||
|
// marks class A as allocated.
|
||||||
|
new A().methodM;
|
||||||
|
|
||||||
|
// This adds get:callMethodM to the sent selector set.
|
||||||
|
final callMethodMOnA = new A().callMethodM;
|
||||||
|
final b = callMethodMOnA("A");
|
||||||
|
final callMethodMOnB = b.callMethodM;
|
||||||
|
callMethodMOnB("B");
|
||||||
|
}
|
||||||
|
|
||||||
|
class A {
|
||||||
|
B callMethodM(String expected) {
|
||||||
|
final f = methodM;
|
||||||
|
Expect.equals(expected, f());
|
||||||
|
|
||||||
|
final newB = createB;
|
||||||
|
return newB();
|
||||||
|
}
|
||||||
|
|
||||||
|
B createB() => new B();
|
||||||
|
|
||||||
|
String methodM() => 'A';
|
||||||
|
}
|
||||||
|
|
||||||
|
class B extends A {
|
||||||
|
@override
|
||||||
|
String methodM() => 'B';
|
||||||
|
}
|
|
@ -719,10 +719,18 @@ void AotCallSpecializer::VisitInstanceCall(InstanceCallInstr* instr) {
|
||||||
for (intptr_t i = 0; i < class_ids.length(); i++) {
|
for (intptr_t i = 0; i < class_ids.length(); i++) {
|
||||||
const intptr_t cid = class_ids[i];
|
const intptr_t cid = class_ids[i];
|
||||||
cls = isolate()->class_table()->At(cid);
|
cls = isolate()->class_table()->At(cid);
|
||||||
|
// Even if we are resolving get:M on a class that has method M
|
||||||
|
// ResolveForReceiverClass would not inject a method extractor into
|
||||||
|
// a class becuase FLAG_lazy_dispatchers is set to false during AOT
|
||||||
|
// compilation. Precompiler however does inject method extractors
|
||||||
|
// (see Precompiler::CheckForNewDynamicFunctions). This means that that
|
||||||
|
// lookup for get:m might overlook a method M in subclass and return
|
||||||
|
// get:m (method extractor for M) from a superclass.
|
||||||
|
// For this reason we abort optimization if lookup returns any
|
||||||
|
// artificial functions that can be inserted lazily.
|
||||||
target = instr->ResolveForReceiverClass(cls);
|
target = instr->ResolveForReceiverClass(cls);
|
||||||
if (target.IsNull()) {
|
if (target.IsNull() || target.IsMethodExtractor() ||
|
||||||
// Can't resolve the target. It might be a noSuchMethod,
|
target.IsInvokeFieldDispatcher()) {
|
||||||
// call through getter or closurization.
|
|
||||||
single_target = Function::null();
|
single_target = Function::null();
|
||||||
ic_data = ICData::null();
|
ic_data = ICData::null();
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in a new issue