Move super resolution from kernel transformation to VM flow graph construction.

Super resolution kernel transformation updates kernel graph with
resolved static calls in place, which breaks incremental modular nature
of transformations.

Bug: dartbug.com/31043
Change-Id: I7ec52d29ea03652cae1403dd89552b30686a5749
Reviewed-on: https://dart-review.googlesource.com/18320
Commit-Queue: Alexander Aprelev <aam@google.com>
Reviewed-by: Samir Jindel <sjindel@google.com>
This commit is contained in:
Alexander Aprelev 2017-11-08 20:17:51 +00:00 committed by commit-bot@chromium.org
parent d8c174cf09
commit 1a45ad96ca
10 changed files with 648 additions and 16 deletions

View file

@ -18,12 +18,10 @@ class C2 extends core::Object implements sou::A2 {
: super core::Object::•();
}
abstract class _Object&A3 extends core::Object implements sou::A3 {
constructor •() → void
: super core::Object::•();
}
class C3 extends self::_Object&A3 {
default constructor •() → void
: super self::_Object&A3::•();
: super core::Object::•();
}
@self::Meta::•(sou::A14)
class X extends core::Object {

View file

@ -62,7 +62,8 @@ class VmTarget extends Target {
void performModularTransformationsOnLibraries(
CoreTypes coreTypes, ClassHierarchy hierarchy, List<Library> libraries,
{void logger(String msg)}) {
transformMixins.transformLibraries(this, coreTypes, hierarchy, libraries);
transformMixins.transformLibraries(this, coreTypes, hierarchy, libraries,
doSuperResolution: false /* resolution is done in Dart VM */);
logger?.call("Transformed mixin applications");
// TODO(kmillikin): Make this run on a per-method basis.

View file

@ -11,8 +11,10 @@ import '../target/targets.dart' show Target;
import '../type_algebra.dart';
void transformLibraries(Target targetInfo, CoreTypes coreTypes,
ClassHierarchy hierarchy, List<Library> libraries) {
new MixinFullResolution(targetInfo, coreTypes, hierarchy)
ClassHierarchy hierarchy, List<Library> libraries,
{bool doSuperResolution: true}) {
new MixinFullResolution(targetInfo, coreTypes, hierarchy,
doSuperResolution: doSuperResolution)
.transform(libraries);
}
@ -20,8 +22,9 @@ void transformLibraries(Target targetInfo, CoreTypes coreTypes,
/// and procedures from the mixed-in class, cloning all constructors from the
/// base class.
///
/// Super calls (as well as super initializer invocations) are also resolved
/// to their targets in this pass.
/// When [doSuperResolution] constructor parameter is [true], super calls
/// (as well as super initializer invocations) are also resolved to their
/// targets in this pass.
class MixinFullResolution {
final Target targetInfo;
final CoreTypes coreTypes;
@ -33,7 +36,13 @@ class MixinFullResolution {
/// valid anymore.
ClassHierarchy hierarchy;
MixinFullResolution(this.targetInfo, this.coreTypes, this.hierarchy);
// This enables `super` resolution transformation, which is not compatible
// with Dart VM's requirements around incremental compilation and has been
// moved to Dart VM itself.
final bool doSuperResolution;
MixinFullResolution(this.targetInfo, this.coreTypes, this.hierarchy,
{this.doSuperResolution: true});
/// Transform the given new [libraries]. It is expected that all other
/// libraries have already been transformed.
@ -56,6 +65,9 @@ class MixinFullResolution {
// We might need to update the class hierarchy.
hierarchy = hierarchy.applyChanges(transformedClasses);
if (!doSuperResolution) {
return;
}
// Resolve all super call expressions and super initializers.
for (var library in libraries) {
if (library.isExternal) continue;

View file

@ -239,6 +239,8 @@ dart/spawn_shutdown_test: SkipSlow
cc/IsolateReload_KernelIncrementalCompile: Skip
cc/IsolateReload_KernelIncrementalCompileAppAndLib: Skip
cc/IsolateReload_KernelIncrementalCompileGenerics: Skip
cc/Mixin_PrivateSuperResolution: Skip
cc/Mixin_PrivateSuperResolutionCrossLibraryShouldFail: Skip
[ ($compiler == dartk) && ($runtime == vm) ]
cc/CanonicalizationInScriptSnapshots: Fail

View file

@ -1220,6 +1220,19 @@ void StreamingScopeBuilder::VisitExpression() {
builder_->SkipCanonicalNameReference(); // read target_reference.
VisitExpression(); // read value·
return;
case kSuperPropertyGet:
HandleSpecialLoad(&result_->this_variable, Symbols::This());
builder_->ReadPosition(); // read position.
builder_->SkipName(); // read name.
builder_->SkipCanonicalNameReference(); // read target_reference.
return;
case kSuperPropertySet:
HandleSpecialLoad(&result_->this_variable, Symbols::This());
builder_->ReadPosition(); // read position.
builder_->SkipName(); // read name.
VisitExpression(); // read value.
builder_->SkipCanonicalNameReference(); // read target_reference.
return;
case kStaticGet:
builder_->ReadPosition(); // read position.
builder_->SkipCanonicalNameReference(); // read target_reference.
@ -1245,6 +1258,14 @@ void StreamingScopeBuilder::VisitExpression() {
builder_->SkipCanonicalNameReference(); // read target_reference.
VisitArguments(); // read arguments.
return;
case kSuperMethodInvocation:
HandleSpecialLoad(&result_->this_variable, Symbols::This());
builder_->ReadPosition(); // read position.
builder_->SkipName(); // read name.
VisitArguments(); // read arguments.
// read interface_target_reference.
builder_->SkipCanonicalNameReference();
return;
case kStaticInvocation:
case kConstStaticInvocation:
builder_->ReadPosition(); // read position.
@ -2532,6 +2553,9 @@ Instance& StreamingConstantEvaluator::EvaluateExpression(intptr_t offset,
case kDirectMethodInvocation:
EvaluateDirectMethodInvocation();
break;
case kSuperMethodInvocation:
EvaluateSuperMethodInvocation();
break;
case kStaticInvocation:
case kConstStaticInvocation:
EvaluateStaticInvocation();
@ -2807,13 +2831,9 @@ void StreamingConstantEvaluator::EvaluateMethodInvocation() {
ASSERT(!klass.IsNull());
// Search the superclass chain for the selector.
Function& function = Function::Handle(Z);
const String& method_name = builder_->ReadNameAsMethodName(); // read name.
while (!klass.IsNull()) {
function = klass.LookupDynamicFunctionAllowPrivate(method_name);
if (!function.IsNull()) break;
klass = klass.SuperClass();
}
Function& function =
builder_->FindMatchingFunctionAnyArgs(klass, method_name);
// The frontend should guarantee that [MethodInvocation]s inside constant
// expressions are always valid.
@ -2847,6 +2867,41 @@ void StreamingConstantEvaluator::EvaluateDirectMethodInvocation() {
result_ = H.Canonicalize(result_);
}
Class& StreamingFlowGraphBuilder::GetSuperOrDie() {
Class& klass = Class::Handle(Z, parsed_function()->function().Owner());
ASSERT(!klass.IsNull());
klass = klass.SuperClass();
ASSERT(!klass.IsNull());
return klass;
}
void StreamingConstantEvaluator::EvaluateSuperMethodInvocation() {
builder_->ReadPosition(); // read position.
const LocalVariable* this_variable = builder_->scopes()->this_variable;
ASSERT(this_variable->IsConst());
const Instance& receiver =
Instance::Handle(Z, this_variable->ConstValue()->raw());
ASSERT(!receiver.IsNull());
Class& klass = builder_->GetSuperOrDie();
const String& method_name = builder_->ReadNameAsMethodName(); // read name.
Function& function =
builder_->FindMatchingFunctionAnyArgs(klass, method_name);
// The frontend should guarantee that [MethodInvocation]s inside constant
// expressions are always valid.
ASSERT(!function.IsNull());
// Read arguments, run the method and canonicalize the result.
const Object& result = RunMethodCall(function, &receiver);
result_ ^= result.raw();
result_ = H.Canonicalize(result_);
builder_->SkipCanonicalNameReference(); // read interface_target_reference.
}
void StreamingConstantEvaluator::EvaluateStaticInvocation() {
builder_->ReadPosition(); // read position.
NameIndex procedure_reference =
@ -3660,8 +3715,11 @@ Fragment StreamingFlowGraphBuilder::BuildInitializers(
&argument_count); // read arguments.
argument_count += 1;
Class& parent_klass = GetSuperOrDie();
const Function& target = Function::ZoneHandle(
Z, H.LookupConstructorByKernelConstructor(canonical_target));
Z, H.LookupConstructorByKernelConstructor(
parent_klass, H.CanonicalNameString(canonical_target)));
instructions +=
StaticCall(TokenPosition::kNoSource, target, argument_count,
argument_names, ICData::kStatic);
@ -4249,12 +4307,18 @@ Fragment StreamingFlowGraphBuilder::BuildExpression(TokenPosition* position) {
return BuildDirectPropertyGet(position);
case kDirectPropertySet:
return BuildDirectPropertySet(position);
case kSuperPropertyGet:
return BuildSuperPropertyGet(position);
case kSuperPropertySet:
return BuildSuperPropertySet(position);
case kStaticGet:
return BuildStaticGet(position);
case kStaticSet:
return BuildStaticSet(position);
case kMethodInvocation:
return BuildMethodInvocation(position);
case kSuperMethodInvocation:
return BuildSuperMethodInvocation(position);
case kDirectMethodInvocation:
return BuildDirectMethodInvocation(position);
case kStaticInvocation:
@ -4680,6 +4744,17 @@ void StreamingFlowGraphBuilder::SkipExpression() {
SkipExpression(); // read value.
SkipCanonicalNameReference(); // read interface_target_reference.
return;
case kSuperPropertyGet:
ReadPosition(); // read position.
SkipName(); // read name.
SkipCanonicalNameReference(); // read interface_target_reference.
return;
case kSuperPropertySet:
ReadPosition(); // read position.
SkipName(); // read name.
SkipExpression(); // read value.
SkipCanonicalNameReference(); // read interface_target_reference.
return;
case kDirectPropertyGet:
ReadPosition(); // read position.
SkipFlags(); // read flags.
@ -4709,6 +4784,12 @@ void StreamingFlowGraphBuilder::SkipExpression() {
SkipArguments(); // read arguments.
SkipCanonicalNameReference(); // read interface_target_reference.
return;
case kSuperMethodInvocation:
ReadPosition(); // read position.
SkipName(); // read name.
SkipArguments(); // read arguments.
SkipCanonicalNameReference(); // read interface_target_reference.
return;
case kDirectMethodInvocation:
ReadPosition(); // read position.
SkipFlags(); // read flags.
@ -5227,6 +5308,43 @@ RawFunction* StreamingFlowGraphBuilder::LookupMethodByMember(
return flow_graph_builder_->LookupMethodByMember(target, method_name);
}
Function& StreamingFlowGraphBuilder::FindMatchingFunctionAnyArgs(
const Class& klass,
const String& name) {
// Search the superclass chain for the selector.
Function& function = Function::Handle(Z);
Class& iterate_klass = Class::Handle(Z, klass.raw());
while (!iterate_klass.IsNull()) {
function = iterate_klass.LookupDynamicFunctionAllowPrivate(name);
if (!function.IsNull()) break;
iterate_klass = iterate_klass.SuperClass();
}
return function;
}
Function& StreamingFlowGraphBuilder::FindMatchingFunction(
const Class& klass,
const String& name,
int type_args_len,
int argument_count,
const Array& argument_names) {
// Search the superclass chain for the selector.
Function& function = Function::Handle(Z);
Class& iterate_klass = Class::Handle(Z, klass.raw());
while (!iterate_klass.IsNull()) {
function = iterate_klass.LookupDynamicFunctionAllowPrivate(name);
if (!function.IsNull()) {
if (function.AreValidArguments(type_args_len, argument_count,
argument_names,
/* error_message = */ NULL)) {
return function;
}
}
iterate_klass = iterate_klass.SuperClass();
}
return Function::Handle();
}
bool StreamingFlowGraphBuilder::NeedsDebugStepCheck(const Function& function,
TokenPosition position) {
return flow_graph_builder_->NeedsDebugStepCheck(function, position);
@ -5783,6 +5901,213 @@ Fragment StreamingFlowGraphBuilder::BuildPropertySet(TokenPosition* p) {
return instructions;
}
static Function& GetNoSuchMethodOrDie(Zone* zone, const Class& klass) {
Function& nsm_function = Function::Handle(zone);
Class& iterate_klass = Class::Handle(zone, klass.raw());
while (!iterate_klass.IsNull()) {
nsm_function = iterate_klass.LookupDynamicFunction(Symbols::NoSuchMethod());
if (!nsm_function.IsNull() && nsm_function.NumParameters() == 2 &&
nsm_function.NumTypeParameters() == 0) {
break;
}
iterate_klass = iterate_klass.SuperClass();
}
// We are guaranteed to find noSuchMethod of class Object.
ASSERT(!nsm_function.IsNull());
return nsm_function;
}
// Note, that this will always mark `super` flag to true.
Fragment StreamingFlowGraphBuilder::BuildAllocateInvocationMirrorCall(
TokenPosition position,
const String& name,
intptr_t num_type_arguments,
intptr_t num_arguments,
const Array& argument_names,
LocalVariable* actuals_array,
Fragment build_rest_of_actuals) {
Fragment instructions;
// Populate array containing the actual arguments. Just add [this] here.
instructions += LoadLocal(actuals_array); // array
instructions += IntConstant(num_type_arguments == 0 ? 0 : 1); // index
instructions += LoadLocal(scopes()->this_variable); // receiver
instructions += StoreIndexed(kArrayCid);
instructions += Drop(); // dispose of stored value
instructions += build_rest_of_actuals;
// First argument is receiver.
instructions += LoadLocal(scopes()->this_variable);
instructions += PushArgument();
// Push the arguments for allocating the invocation mirror:
// - the name.
instructions += Constant(String::ZoneHandle(Z, name.raw()));
instructions += PushArgument();
// - the arguments descriptor.
const Array& args_descriptor =
Array::Handle(Z, ArgumentsDescriptor::New(num_type_arguments,
num_arguments, argument_names));
instructions += Constant(Array::ZoneHandle(Z, args_descriptor.raw()));
instructions += PushArgument();
// - an array containing the actual arguments.
instructions += LoadLocal(actuals_array);
instructions += PushArgument();
// - [true] indicating this is a `super` NoSuchMethod.
instructions += Constant(Bool::True());
instructions += PushArgument();
const Class& mirror_class =
Class::Handle(Z, Library::LookupCoreClass(Symbols::InvocationMirror()));
ASSERT(!mirror_class.IsNull());
const Function& allocation_function = Function::ZoneHandle(
Z, mirror_class.LookupStaticFunction(
Library::PrivateCoreLibName(Symbols::AllocateInvocationMirror())));
ASSERT(!allocation_function.IsNull());
instructions += StaticCall(position, allocation_function,
/* argument_count = */ 4, ICData::kStatic);
return instructions;
}
Fragment StreamingFlowGraphBuilder::BuildSuperPropertyGet(TokenPosition* p) {
const TokenPosition position = ReadPosition(); // read position.
if (p != NULL) *p = position;
Class& klass = GetSuperOrDie();
StringIndex name_index = ReadStringReference(); // read name index.
NameIndex library_reference =
((H.StringSize(name_index) >= 1) && H.CharacterAt(name_index, 0) == '_')
? ReadCanonicalNameReference() // read library index.
: NameIndex();
const String& getter_name = H.DartGetterName(library_reference, name_index);
const String& method_name = H.DartMethodName(library_reference, name_index);
SkipCanonicalNameReference(); // skip target_reference.
// Search the superclass chain for the selector looking for either getter or
// method.
Function& function = Function::Handle(Z);
while (!klass.IsNull()) {
function = klass.LookupDynamicFunction(method_name);
if (!function.IsNull()) {
Function& target =
Function::ZoneHandle(Z, function.ImplicitClosureFunction());
ASSERT(!target.IsNull());
// Generate inline code for allocation closure object with context
// which captures `this`.
return BuildImplicitClosureCreation(target);
}
function = klass.LookupDynamicFunction(getter_name);
if (!function.IsNull()) break;
klass = klass.SuperClass();
}
Fragment instructions;
if (klass.IsNull()) {
instructions +=
Constant(TypeArguments::ZoneHandle(Z, TypeArguments::null()));
instructions += IntConstant(1); // array size
instructions += CreateArray();
LocalVariable* actuals_array = MakeTemporary();
Class& parent_klass = GetSuperOrDie();
instructions += BuildAllocateInvocationMirrorCall(
position, getter_name,
/* num_type_arguments = */ 0,
/* num_arguments = */ 1,
/* argument_names = */ Object::empty_array(), actuals_array,
/* build_rest_of_actuals = */ Fragment());
instructions += PushArgument(); // second argument is invocation mirror
Function& nsm_function = GetNoSuchMethodOrDie(Z, parent_klass);
instructions +=
StaticCall(position, Function::ZoneHandle(Z, nsm_function.raw()),
/* argument_count = */ 2, ICData::kNSMDispatch);
instructions += DropTempsPreserveTop(1); // Drop array
} else {
ASSERT(!klass.IsNull());
ASSERT(!function.IsNull());
instructions += LoadLocal(scopes()->this_variable);
instructions += PushArgument();
instructions +=
StaticCall(position, Function::ZoneHandle(Z, function.raw()),
/* argument_count = */ 1, ICData::kSuper);
}
return instructions;
}
Fragment StreamingFlowGraphBuilder::BuildSuperPropertySet(TokenPosition* p) {
const TokenPosition position = ReadPosition(); // read position.
if (p != NULL) *p = position;
Class& klass = GetSuperOrDie();
const String& setter_name = ReadNameAsSetterName(); // read name.
Function& function = FindMatchingFunctionAnyArgs(klass, setter_name);
Fragment instructions(NullConstant());
LocalVariable* value = MakeTemporary(); // this holds RHS value
if (function.IsNull()) {
instructions +=
Constant(TypeArguments::ZoneHandle(Z, TypeArguments::null()));
instructions += IntConstant(2); // array size
instructions += CreateArray();
LocalVariable* actuals_array = MakeTemporary();
Fragment build_rest_of_actuals;
build_rest_of_actuals += LoadLocal(actuals_array); // array
build_rest_of_actuals += IntConstant(1); // index
build_rest_of_actuals += BuildExpression(); // value.
build_rest_of_actuals += StoreLocal(position, value);
build_rest_of_actuals += StoreIndexed(kArrayCid);
build_rest_of_actuals += Drop(); // dispose of stored value
instructions += BuildAllocateInvocationMirrorCall(
position, setter_name, /* num_type_arguments = */ 0,
/* num_arguments = */ 2,
/* argument_names = */ Object::empty_array(), actuals_array,
build_rest_of_actuals);
instructions += PushArgument(); // second argument - invocation mirror
SkipCanonicalNameReference(); // skip target_reference.
Function& nsm_function = GetNoSuchMethodOrDie(Z, klass);
instructions +=
StaticCall(position, Function::ZoneHandle(Z, nsm_function.raw()),
/* argument_count = */ 2, ICData::kNSMDispatch);
instructions += Drop(); // Drop result of NoSuchMethod invocation
instructions += Drop(); // Drop array
} else {
// receiver
instructions += LoadLocal(scopes()->this_variable);
instructions += PushArgument();
instructions += BuildExpression(); // read value.
instructions += StoreLocal(position, value);
instructions += PushArgument();
SkipCanonicalNameReference(); // skip target_reference.
instructions +=
StaticCall(position, Function::ZoneHandle(Z, function.raw()),
/* argument_count = */ 2, ICData::kSuper);
instructions += Drop(); // Drop result of the setter invocation.
}
return instructions;
}
Fragment StreamingFlowGraphBuilder::BuildDirectPropertyGet(TokenPosition* p) {
const TokenPosition position = ReadPosition(); // read position.
if (p != NULL) *p = position;
@ -6162,6 +6487,146 @@ Fragment StreamingFlowGraphBuilder::BuildDirectMethodInvocation(
type_args_len);
}
Fragment StreamingFlowGraphBuilder::BuildSuperMethodInvocation(
TokenPosition* p) {
const TokenPosition position = ReadPosition(); // read position.
if (p != NULL) *p = position;
intptr_t type_args_len = 0;
if (I->reify_generic_functions()) {
AlternativeReadingScope alt(reader_);
SkipName(); // skip method name
ReadUInt(); // read argument count.
type_args_len = ReadListLength(); // read types list length.
}
Class& klass = GetSuperOrDie();
// Search the superclass chain for the selector.
const String& method_name = ReadNameAsMethodName(); // read name.
// Figure out selector signature.
intptr_t argument_count;
Array& argument_names = Array::Handle(Z);
{
AlternativeReadingScope alt(reader_);
argument_count = ReadUInt();
SkipListOfDartTypes();
SkipListOfExpressions();
intptr_t named_list_length = ReadListLength();
argument_names ^= Array::New(named_list_length);
for (intptr_t i = 0; i < named_list_length; i++) {
const String& arg_name = H.DartSymbol(ReadStringReference());
argument_names.SetAt(i, arg_name);
SkipExpression();
}
}
Function& function = FindMatchingFunction(
klass, method_name, type_args_len,
argument_count + 1 /* account for 'this' */, argument_names);
if (function.IsNull()) {
ReadUInt(); // argument count
intptr_t type_list_length = ReadListLength();
Fragment instructions;
instructions +=
Constant(TypeArguments::ZoneHandle(Z, TypeArguments::null()));
instructions += IntConstant(argument_count + 1 /* this */ +
(type_list_length == 0 ? 0 : 1)); // array size
instructions += CreateArray();
LocalVariable* actuals_array = MakeTemporary();
// Call allocationInvocationMirror to get instance of Invocation.
Fragment build_rest_of_actuals;
intptr_t actuals_array_index = 0;
if (type_list_length > 0) {
const TypeArguments& type_arguments =
T.BuildTypeArguments(type_list_length);
build_rest_of_actuals += LoadLocal(actuals_array);
build_rest_of_actuals += IntConstant(actuals_array_index);
build_rest_of_actuals +=
TranslateInstantiatedTypeArguments(type_arguments);
build_rest_of_actuals += StoreIndexed(kArrayCid);
build_rest_of_actuals += Drop(); // dispose of stored value
++actuals_array_index;
}
++actuals_array_index; // account for 'this'.
// Read arguments
intptr_t list_length = ReadListLength();
intptr_t i = 0;
while (i < list_length) {
build_rest_of_actuals += LoadLocal(actuals_array); // array
build_rest_of_actuals += IntConstant(actuals_array_index + i); // index
build_rest_of_actuals += BuildExpression(); // value.
build_rest_of_actuals += StoreIndexed(kArrayCid);
build_rest_of_actuals += Drop(); // dispose of stored value
++i;
}
// Read named arguments
intptr_t named_list_length = ReadListLength();
if (named_list_length > 0) {
ASSERT(argument_count == list_length + named_list_length);
while ((i - list_length) < named_list_length) {
SkipStringReference();
build_rest_of_actuals += LoadLocal(actuals_array); // array
build_rest_of_actuals += IntConstant(i + actuals_array_index); // index
build_rest_of_actuals += BuildExpression(); // value.
build_rest_of_actuals += StoreIndexed(kArrayCid);
build_rest_of_actuals += Drop(); // dispose of stored value
++i;
}
}
instructions += BuildAllocateInvocationMirrorCall(
position, method_name, type_list_length,
/* num_arguments = */ argument_count + 1, argument_names, actuals_array,
build_rest_of_actuals);
instructions += PushArgument(); // second argument - invocation mirror
SkipCanonicalNameReference(); // skip target_reference.
Function& nsm_function = GetNoSuchMethodOrDie(Z, klass);
instructions += StaticCall(TokenPosition::kNoSource,
Function::ZoneHandle(Z, nsm_function.raw()),
/* argument_count = */ 2, ICData::kNSMDispatch);
instructions += DropTempsPreserveTop(1); // Drop actuals_array temp.
return instructions;
} else {
Fragment instructions;
if (I->reify_generic_functions()) {
AlternativeReadingScope alt(reader_);
ReadUInt(); // read argument count.
intptr_t list_length = ReadListLength(); // read types list length.
if (list_length > 0) {
const TypeArguments& type_arguments =
T.BuildTypeArguments(list_length); // read types.
instructions += TranslateInstantiatedTypeArguments(type_arguments);
instructions += PushArgument();
}
}
// receiver
instructions += LoadLocal(scopes()->this_variable);
instructions += PushArgument();
Array& argument_names = Array::ZoneHandle(Z);
intptr_t argument_count;
instructions +=
BuildArguments(&argument_names, &argument_count); // read arguments.
++argument_count; // include receiver
if (type_args_len > 0) ++argument_count;
SkipCanonicalNameReference(); // interfaceTargetReference
return instructions + StaticCall(position,
Function::ZoneHandle(Z, function.raw()),
argument_count, argument_names,
ICData::kSuper, type_args_len);
}
}
Fragment StreamingFlowGraphBuilder::BuildStaticInvocation(bool is_const,
TokenPosition* p) {
TokenPosition position = ReadPosition(); // read position.

View file

@ -758,6 +758,7 @@ class StreamingConstantEvaluator {
void EvaluateStaticGet();
void EvaluateMethodInvocation();
void EvaluateDirectMethodInvocation();
void EvaluateSuperMethodInvocation();
void EvaluateStaticInvocation();
void EvaluateConstructorInvocationInternal();
void EvaluateNot();
@ -1000,6 +1001,7 @@ class StreamingFlowGraphBuilder {
Value* stack();
void Push(Definition* definition);
Value* Pop();
Class& GetSuperOrDie();
Tag PeekArgumentsFirstPositionalTag();
const TypeArguments& PeekArgumentsInstantiatedType(const Class& klass);
@ -1011,6 +1013,12 @@ class StreamingFlowGraphBuilder {
LocalVariable* MakeTemporary();
RawFunction* LookupMethodByMember(NameIndex target,
const String& method_name);
Function& FindMatchingFunctionAnyArgs(const Class& klass, const String& name);
Function& FindMatchingFunction(const Class& klass,
const String& name,
int type_args_len,
int argument_count,
const Array& argument_names);
bool NeedsDebugStepCheck(const Function& function, TokenPosition position);
bool NeedsDebugStepCheck(Value* value, TokenPosition position);
@ -1126,12 +1134,22 @@ class StreamingFlowGraphBuilder {
Fragment BuildVariableSet(uint8_t payload, TokenPosition* position);
Fragment BuildPropertyGet(TokenPosition* position);
Fragment BuildPropertySet(TokenPosition* position);
Fragment BuildAllocateInvocationMirrorCall(TokenPosition position,
const String& name,
intptr_t num_type_arguments,
intptr_t num_arguments,
const Array& argument_names,
LocalVariable* actuals_array,
Fragment build_rest_of_actuals);
Fragment BuildSuperPropertyGet(TokenPosition* position);
Fragment BuildSuperPropertySet(TokenPosition* position);
Fragment BuildDirectPropertyGet(TokenPosition* position);
Fragment BuildDirectPropertySet(TokenPosition* position);
Fragment BuildStaticGet(TokenPosition* position);
Fragment BuildStaticSet(TokenPosition* position);
Fragment BuildMethodInvocation(TokenPosition* position);
Fragment BuildDirectMethodInvocation(TokenPosition* position);
Fragment BuildSuperMethodInvocation(TokenPosition* position);
Fragment BuildStaticInvocation(bool is_const, TokenPosition* position);
Fragment BuildConstructorInvocation(bool is_const, TokenPosition* position);
Fragment BuildNot(TokenPosition* position);

View file

@ -624,6 +624,22 @@ RawFunction* TranslationHelper::LookupConstructorByKernelConstructor(
return function;
}
RawFunction* TranslationHelper::LookupConstructorByKernelConstructor(
const Class& owner,
StringIndex constructor_name) {
GrowableHandlePtrArray<const String> pieces(Z, 3);
pieces.Add(DartString(String::Handle(owner.Name()).ToCString(), Heap::kOld));
pieces.Add(Symbols::Dot());
String& name = DartString(constructor_name);
pieces.Add(ManglePrivateName(Library::Handle(owner.library()), &name));
String& new_name =
String::ZoneHandle(Z, Symbols::FromConcatAll(thread_, pieces));
RawFunction* function = owner.LookupConstructorAllowPrivate(new_name);
ASSERT(function != Object::null());
return function;
}
Type& TranslationHelper::GetCanonicalType(const Class& klass) {
ASSERT(!klass.IsNull());
// Note that if cls is _Closure, the returned type will be _Closure,
@ -691,6 +707,16 @@ String& TranslationHelper::ManglePrivateName(NameIndex parent,
return *name_to_modify;
}
String& TranslationHelper::ManglePrivateName(const Library& library,
String* name_to_modify,
bool symbolize) {
if (name_to_modify->Length() >= 1 && name_to_modify->CharAt(0) == '_') {
*name_to_modify = library.PrivateName(*name_to_modify);
} else if (symbolize) {
*name_to_modify = Symbols::New(thread_, *name_to_modify);
}
return *name_to_modify;
}
FlowGraphBuilder::FlowGraphBuilder(
intptr_t kernel_offset,
ParsedFunction* parsed_function,

View file

@ -403,6 +403,9 @@ class TranslationHelper {
RawFunction* LookupConstructorByKernelConstructor(NameIndex constructor);
RawFunction* LookupConstructorByKernelConstructor(const Class& owner,
NameIndex constructor);
RawFunction* LookupConstructorByKernelConstructor(
const Class& owner,
StringIndex constructor_name);
Type& GetCanonicalType(const Class& klass);
@ -421,6 +424,9 @@ class TranslationHelper {
String& ManglePrivateName(NameIndex parent,
String* name_to_modify,
bool symbolize = true);
String& ManglePrivateName(const Library& library,
String* name_to_modify,
bool symbolize = true);
Thread* thread_;
Zone* zone_;

103
runtime/vm/mixin_test.cc Normal file
View file

@ -0,0 +1,103 @@
// 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.
#include "include/dart_api.h"
#include "vm/unit_test.h"
namespace dart {
#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
TEST_CASE(Mixin_PrivateSuperResolution) {
// clang-format off
Dart_SourceFile sourcefiles[] = {
{
"file:///test-app.dart",
"class A {\n"
" _bar() => 42;\n"
"}\n"
"class M extends A {\n"
" bar() => -1;\n"
"}\n"
"class B extends A {\n"
" foo() => 6;\n"
"}\n"
"class C extends B with M {\n"
" bar() => super._bar();\n"
"}\n"
"main() {\n"
" return new C().bar();\n"
"}\n",
},
{
"file:///.packages", "untitled:/"
}};
// clang-format on
Dart_Handle lib = TestCase::LoadTestScriptWithDFE(
sizeof(sourcefiles) / sizeof(Dart_SourceFile), sourcefiles,
/* resolver= */ NULL, /* finalize= */ true, /* incrementally= */ true);
EXPECT_VALID(lib);
Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL);
int64_t value = 0;
result = Dart_IntegerToInt64(result, &value);
EXPECT_VALID(result);
EXPECT_EQ(42, value);
}
TEST_CASE(Mixin_PrivateSuperResolutionCrossLibraryShouldFail) {
// clang-format off
Dart_SourceFile sourcefiles[] = {
{
"file:///test-app.dart",
"import 'test-lib.dart';\n"
"class D extends B with M {\n"
" bar() => super._bar();\n"
"}\n"
"main() {\n"
" try {\n"
" return new D().bar();\n"
" } catch (e) {\n"
" return e.toString().split('\\n').first;\n"
" }\n"
"}"
"}\n",
},
{
"file:///test-lib.dart",
"class A {\n"
" foo() => 4;\n"
" _bar() => 42;\n"
"}\n"
"class M extends A {\n"
" bar() => -1;\n"
"}\n"
"class B extends A {\n"
" foo() => 6;\n"
"}\n"
"class C extends B with M {\n"
" bar() => super._bar();\n"
"}\n"
},
{
"file:///.packages", "untitled:/"
}};
// clang-format on
Dart_Handle lib = TestCase::LoadTestScriptWithDFE(
sizeof(sourcefiles) / sizeof(Dart_SourceFile), sourcefiles,
/* resolver= */ NULL, /* finalize= */ true, /* incrementally= */ true);
EXPECT_VALID(lib);
Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL);
const char* result_str = NULL;
EXPECT(Dart_IsString(result));
EXPECT_VALID(Dart_StringToCString(result, &result_str));
EXPECT_STREQ(
"NoSuchMethodError: Super class of class 'D' has no instance method "
"'_bar'.",
result_str);
}
#endif // !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
} // namespace dart

View file

@ -428,6 +428,7 @@ vm_sources_tests = [
"message_handler_test.cc",
"message_test.cc",
"metrics_test.cc",
"mixin_test.cc",
"native_entry_test.cc",
"native_entry_test.h",
"object_arm64_test.cc",