mirror of
https://github.com/dart-lang/sdk
synced 2024-10-06 14:39:38 +00:00
Refactor SsaBuilder.visitStaticSend and visitGetterSend.
BUG= R=karlklose@google.com Review URL: https://codereview.chromium.org//1112563002 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@45449 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
parent
f59e077911
commit
d9b0cc7da2
|
@ -794,6 +794,14 @@ abstract class IrBuilderVisitor extends ast.Visitor<ir.Primitive>
|
|||
return irBuilder.buildSuperMethodGet(method);
|
||||
}
|
||||
|
||||
@override
|
||||
ir.Primitive visitUnresolvedGet(
|
||||
ast.Send node,
|
||||
Element element,
|
||||
_) {
|
||||
return giveup(node, 'visitUnresolvedGet');
|
||||
}
|
||||
|
||||
@override
|
||||
ir.Primitive visitUnresolvedSuperGet(
|
||||
ast.Send node,
|
||||
|
@ -1127,6 +1135,16 @@ abstract class IrBuilderVisitor extends ast.Visitor<ir.Primitive>
|
|||
sourceInformation: sourceInformationBuilder.buildCall(node));
|
||||
}
|
||||
|
||||
@override
|
||||
ir.Primitive handleStaticFunctionIncompatibleInvoke(
|
||||
ast.Send node,
|
||||
MethodElement function,
|
||||
ast.NodeList arguments,
|
||||
CallStructure callStructure,
|
||||
_) {
|
||||
return giveup(node, 'handleStaticFunctionIncompatibleInvoke');
|
||||
}
|
||||
|
||||
@override
|
||||
ir.Primitive handleStaticGetterInvoke(
|
||||
ast.Send node,
|
||||
|
@ -1190,10 +1208,20 @@ abstract class IrBuilderVisitor extends ast.Visitor<ir.Primitive>
|
|||
return giveup(node, 'visitSuperMethodIncompatibleInvoke');
|
||||
}
|
||||
|
||||
@override
|
||||
ir.Primitive visitUnresolvedInvoke(
|
||||
ast.Send node,
|
||||
Element element,
|
||||
ast.NodeList arguments,
|
||||
Selector selector,
|
||||
_) {
|
||||
return giveup(node, 'visitUnresolvedInvoke');
|
||||
}
|
||||
|
||||
@override
|
||||
ir.Primitive visitUnresolvedSuperInvoke(
|
||||
ast.Send node,
|
||||
MethodElement method,
|
||||
Element element,
|
||||
ast.NodeList arguments,
|
||||
Selector selector,
|
||||
_) {
|
||||
|
|
|
@ -737,6 +737,21 @@ abstract class SemanticSendVisitor<R, A> {
|
|||
CallStructure callStructure,
|
||||
A arg);
|
||||
|
||||
/// Invocation of the static [function] with incompatible [arguments].
|
||||
///
|
||||
/// For instance
|
||||
/// class C {
|
||||
/// static foo(a, b) {}
|
||||
/// }
|
||||
/// m() { C.foo(null); }
|
||||
///
|
||||
R visitStaticFunctionIncompatibleInvoke(
|
||||
Send node,
|
||||
MethodElement function,
|
||||
NodeList arguments,
|
||||
CallStructure callStructure,
|
||||
A arg);
|
||||
|
||||
/// Assignment of [rhs] to the static [function].
|
||||
///
|
||||
/// For instance
|
||||
|
@ -907,6 +922,21 @@ abstract class SemanticSendVisitor<R, A> {
|
|||
CallStructure callStructure,
|
||||
A arg);
|
||||
|
||||
/// Invocation of the top level [function] with incompatible [arguments].
|
||||
///
|
||||
/// For instance
|
||||
/// class C {
|
||||
/// static foo(a, b) {}
|
||||
/// }
|
||||
/// m() { C.foo(null); }
|
||||
///
|
||||
R visitTopLevelFunctionIncompatibleInvoke(
|
||||
Send node,
|
||||
MethodElement function,
|
||||
NodeList arguments,
|
||||
CallStructure callStructure,
|
||||
A arg);
|
||||
|
||||
/// Assignment of [rhs] to the top level [function].
|
||||
///
|
||||
/// For instance
|
||||
|
@ -2682,7 +2712,7 @@ abstract class SemanticSendVisitor<R, A> {
|
|||
/// m7() => prefix.C.unresolved;
|
||||
///
|
||||
// TODO(johnniwinther): Split the cases in which a prefix is resolved.
|
||||
R errorUnresolvedGet(
|
||||
R visitUnresolvedGet(
|
||||
Send node,
|
||||
Element element,
|
||||
A arg);
|
||||
|
@ -2732,7 +2762,7 @@ abstract class SemanticSendVisitor<R, A> {
|
|||
/// m7() => prefix.C.unresolved(null, 42);
|
||||
///
|
||||
// TODO(johnniwinther): Split the cases in which a prefix is resolved.
|
||||
R errorUnresolvedInvoke(
|
||||
R visitUnresolvedInvoke(
|
||||
Send node,
|
||||
Element element,
|
||||
NodeList arguments,
|
||||
|
|
|
@ -464,24 +464,6 @@ abstract class ErrorBulkMixin<R, A>
|
|||
return bulkHandleError(node, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
R errorUnresolvedGet(
|
||||
Send node,
|
||||
Element element,
|
||||
A arg) {
|
||||
return bulkHandleError(node, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
R errorUnresolvedInvoke(
|
||||
Send node,
|
||||
Element element,
|
||||
NodeList arguments,
|
||||
Selector selector,
|
||||
A arg) {
|
||||
return bulkHandleError(node, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
R errorUnresolvedPostfix(
|
||||
Send node,
|
||||
|
@ -1237,6 +1219,16 @@ abstract class InvokeBulkMixin<R, A>
|
|||
return bulkHandleInvoke(node, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
R visitStaticFunctionIncompatibleInvoke(
|
||||
Send node,
|
||||
MethodElement function,
|
||||
NodeList arguments,
|
||||
CallStructure callStructure,
|
||||
A arg) {
|
||||
return bulkHandleInvoke(node, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
R visitStaticGetterInvoke(
|
||||
Send node,
|
||||
|
@ -1325,6 +1317,16 @@ abstract class InvokeBulkMixin<R, A>
|
|||
return bulkHandleInvoke(node, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
R visitTopLevelFunctionIncompatibleInvoke(
|
||||
Send node,
|
||||
MethodElement function,
|
||||
NodeList arguments,
|
||||
CallStructure callStructure,
|
||||
A arg) {
|
||||
return bulkHandleInvoke(node, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
R visitTopLevelGetterInvoke(
|
||||
Send node,
|
||||
|
@ -1365,6 +1367,16 @@ abstract class InvokeBulkMixin<R, A>
|
|||
return bulkHandleInvoke(node, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
R visitUnresolvedInvoke(
|
||||
Send node,
|
||||
Element element,
|
||||
NodeList arguments,
|
||||
Selector selector,
|
||||
A arg) {
|
||||
return bulkHandleInvoke(node, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
R visitUnresolvedSuperInvoke(
|
||||
Send node,
|
||||
|
@ -1546,6 +1558,14 @@ abstract class GetBulkMixin<R, A>
|
|||
return bulkHandleGet(node, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
R visitUnresolvedGet(
|
||||
Send node,
|
||||
Element element,
|
||||
A arg) {
|
||||
return bulkHandleGet(node, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
R visitUnresolvedSuperGet(
|
||||
Send node,
|
||||
|
@ -3769,6 +3789,17 @@ class TraversalSendMixin<R, A> implements SemanticSendVisitor<R, A> {
|
|||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
R visitStaticFunctionIncompatibleInvoke(
|
||||
Send node,
|
||||
MethodElement function,
|
||||
NodeList arguments,
|
||||
CallStructure callStructure,
|
||||
A arg) {
|
||||
apply(arguments, arg);
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
R visitStaticGetterGet(
|
||||
Send node,
|
||||
|
@ -4354,6 +4385,17 @@ class TraversalSendMixin<R, A> implements SemanticSendVisitor<R, A> {
|
|||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
R visitTopLevelFunctionIncompatibleInvoke(
|
||||
Send node,
|
||||
MethodElement function,
|
||||
NodeList arguments,
|
||||
CallStructure callStructure,
|
||||
A arg) {
|
||||
apply(arguments, arg);
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
R visitTopLevelGetterGet(
|
||||
Send node,
|
||||
|
@ -4565,7 +4607,7 @@ class TraversalSendMixin<R, A> implements SemanticSendVisitor<R, A> {
|
|||
}
|
||||
|
||||
@override
|
||||
R errorUnresolvedGet(
|
||||
R visitUnresolvedGet(
|
||||
Send node,
|
||||
Element element,
|
||||
A arg) {
|
||||
|
@ -4573,7 +4615,7 @@ class TraversalSendMixin<R, A> implements SemanticSendVisitor<R, A> {
|
|||
}
|
||||
|
||||
@override
|
||||
R errorUnresolvedInvoke(
|
||||
R visitUnresolvedInvoke(
|
||||
Send node,
|
||||
Element element,
|
||||
NodeList arguments,
|
||||
|
@ -5377,6 +5419,13 @@ abstract class BaseImplementationOfStaticsMixin<R, A>
|
|||
CallStructure callStructure,
|
||||
A arg);
|
||||
|
||||
R handleStaticFunctionIncompatibleInvoke(
|
||||
Send node,
|
||||
MethodElement function,
|
||||
NodeList arguments,
|
||||
CallStructure callStructure,
|
||||
A arg);
|
||||
|
||||
R handleStaticGetterGet(
|
||||
Send node,
|
||||
FunctionElement getter,
|
||||
|
@ -5503,6 +5552,17 @@ abstract class BaseImplementationOfStaticsMixin<R, A>
|
|||
node, function, arguments, callStructure, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
R visitStaticFunctionIncompatibleInvoke(
|
||||
Send node,
|
||||
MethodElement function,
|
||||
NodeList arguments,
|
||||
CallStructure callStructure,
|
||||
A arg) {
|
||||
return handleStaticFunctionIncompatibleInvoke(
|
||||
node, function, arguments, callStructure, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
R visitStaticGetterGet(
|
||||
Send node,
|
||||
|
@ -5675,6 +5735,17 @@ abstract class BaseImplementationOfStaticsMixin<R, A>
|
|||
node, function, arguments, callStructure, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
R visitTopLevelFunctionIncompatibleInvoke(
|
||||
Send node,
|
||||
MethodElement function,
|
||||
NodeList arguments,
|
||||
CallStructure callStructure,
|
||||
A arg) {
|
||||
return handleStaticFunctionIncompatibleInvoke(
|
||||
node, function, arguments, callStructure, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
R visitTopLevelGetterGet(
|
||||
Send node,
|
||||
|
|
|
@ -234,12 +234,17 @@ abstract class SendResolverMixin {
|
|||
case SendStructureKind.SET:
|
||||
return new SetStructure(semantics, selector);
|
||||
case SendStructureKind.INVOKE:
|
||||
if (semantics.kind == AccessKind.SUPER_METHOD) {
|
||||
// TODO(johnniwinther): Find all statically resolved case that should
|
||||
// go here (top level, static, local, ...).
|
||||
if (!selector.callStructure.signatureApplies(semantics.element)) {
|
||||
return new IncompatibleInvokeStructure(semantics, selector);
|
||||
}
|
||||
switch (semantics.kind) {
|
||||
case AccessKind.STATIC_METHOD:
|
||||
case AccessKind.SUPER_METHOD:
|
||||
case AccessKind.TOPLEVEL_METHOD:
|
||||
// TODO(johnniwinther): Should local function also be handled here?
|
||||
if (!selector.callStructure.signatureApplies(semantics.element)) {
|
||||
return new IncompatibleInvokeStructure(semantics, selector);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return new InvokeStructure(semantics, selector);
|
||||
case SendStructureKind.UNARY:
|
||||
|
|
|
@ -333,7 +333,7 @@ class InvokeStructure<R, A> implements SendStructure<R, A> {
|
|||
callStructure,
|
||||
arg);
|
||||
case AccessKind.UNRESOLVED:
|
||||
return visitor.errorUnresolvedInvoke(
|
||||
return visitor.visitUnresolvedInvoke(
|
||||
node,
|
||||
semantics.element,
|
||||
node.argumentsNode,
|
||||
|
@ -374,6 +374,13 @@ class IncompatibleInvokeStructure<R, A> implements SendStructure<R, A> {
|
|||
|
||||
R dispatch(SemanticSendVisitor<R, A> visitor, Send node, A arg) {
|
||||
switch (semantics.kind) {
|
||||
case AccessKind.STATIC_METHOD:
|
||||
return visitor.visitStaticFunctionIncompatibleInvoke(
|
||||
node,
|
||||
semantics.element,
|
||||
node.argumentsNode,
|
||||
callStructure,
|
||||
arg);
|
||||
case AccessKind.SUPER_METHOD:
|
||||
return visitor.visitSuperMethodIncompatibleInvoke(
|
||||
node,
|
||||
|
@ -381,7 +388,14 @@ class IncompatibleInvokeStructure<R, A> implements SendStructure<R, A> {
|
|||
node.argumentsNode,
|
||||
callStructure,
|
||||
arg);
|
||||
default:
|
||||
case AccessKind.TOPLEVEL_METHOD:
|
||||
return visitor.visitTopLevelFunctionIncompatibleInvoke(
|
||||
node,
|
||||
semantics.element,
|
||||
node.argumentsNode,
|
||||
callStructure,
|
||||
arg);
|
||||
default:
|
||||
// TODO(johnniwinther): Support more variants of this invoke structure.
|
||||
break;
|
||||
}
|
||||
|
@ -522,7 +536,7 @@ class GetStructure<R, A> implements SendStructure<R, A> {
|
|||
semantics.constant,
|
||||
arg);
|
||||
case AccessKind.UNRESOLVED:
|
||||
return visitor.errorUnresolvedGet(
|
||||
return visitor.visitUnresolvedGet(
|
||||
node,
|
||||
semantics.element,
|
||||
arg);
|
||||
|
|
|
@ -481,7 +481,7 @@ class ResolvedSemanticDispatcher<R> extends Object
|
|||
}
|
||||
|
||||
@override
|
||||
R errorUnresolvedGet(
|
||||
R visitUnresolvedGet(
|
||||
Send node,
|
||||
Element element,
|
||||
ResolvedKindVisitor<R> visitor) {
|
||||
|
@ -489,7 +489,7 @@ class ResolvedSemanticDispatcher<R> extends Object
|
|||
}
|
||||
|
||||
@override
|
||||
R errorUnresolvedInvoke(
|
||||
R visitUnresolvedInvoke(
|
||||
Send node,
|
||||
Element element,
|
||||
NodeList arguments,
|
||||
|
|
|
@ -1518,12 +1518,6 @@ class SsaBuilder extends NewResolvedVisitor {
|
|||
return graph.addConstant(getConstantForNode(node), compiler);
|
||||
}
|
||||
|
||||
bool isLazilyInitialized(VariableElement element) {
|
||||
ConstantExpression initialValue =
|
||||
backend.constants.getConstantForVariable(element);
|
||||
return initialValue == null;
|
||||
}
|
||||
|
||||
TypeMask cachedTypeOfThis;
|
||||
|
||||
TypeMask getTypeOfThis() {
|
||||
|
@ -3245,94 +3239,121 @@ class SsaBuilder extends NewResolvedVisitor {
|
|||
}
|
||||
}
|
||||
|
||||
void generateGetter(ast.Send send, Element element) {
|
||||
if (element != null && element.isForeign(backend)) {
|
||||
visitForeignGetter(send);
|
||||
} else if (Elements.isStaticOrTopLevelField(element)) {
|
||||
ConstantExpression constant;
|
||||
if (element.isField && !element.isAssignable) {
|
||||
/// Generate read access of an unresolved static or top level entity.
|
||||
void generateStaticUnresolvedGet(ast.Send node, Element element) {
|
||||
if (element is ErroneousElement) {
|
||||
// An erroneous element indicates an unresolved static getter.
|
||||
generateThrowNoSuchMethod(
|
||||
node,
|
||||
noSuchMethodTargetSymbolString(element, 'get'),
|
||||
argumentNodes: const Link<ast.Node>());
|
||||
} else {
|
||||
// This happens when [element] has parse errors.
|
||||
assert(invariant(node, element.isErroneous));
|
||||
// TODO(ahe): Do something like the above, that is, emit a runtime
|
||||
// error.
|
||||
stack.add(graph.addConstantNull(compiler));
|
||||
}
|
||||
}
|
||||
|
||||
/// Read a static or top level [field] of constant value.
|
||||
void generateStaticConstGet(
|
||||
ast.Send node,
|
||||
FieldElement field,
|
||||
ConstantExpression constant) {
|
||||
ConstantValue value = constant.value;
|
||||
HConstant instruction;
|
||||
// Constants that are referred via a deferred prefix should be referred
|
||||
// by reference.
|
||||
PrefixElement prefix = compiler.deferredLoadTask
|
||||
.deferredPrefixElement(node, elements);
|
||||
if (prefix != null) {
|
||||
instruction = graph.addDeferredConstant(value, prefix, compiler);
|
||||
} else {
|
||||
instruction = graph.addConstant(value, compiler);
|
||||
}
|
||||
stack.add(instruction);
|
||||
// The inferrer may have found a better type than the constant
|
||||
// handler in the case of lists, because the constant handler
|
||||
// does not look at elements in the list.
|
||||
TypeMask type =
|
||||
TypeMaskFactory.inferredTypeForElement(field, compiler);
|
||||
if (!type.containsAll(compiler.world) &&
|
||||
!instruction.isConstantNull()) {
|
||||
// TODO(13429): The inferrer should know that an element
|
||||
// cannot be null.
|
||||
instruction.instructionType = type.nonNullable();
|
||||
}
|
||||
}
|
||||
|
||||
/// Read a static or top level [field].
|
||||
void generateStaticFieldGet(ast.Send node, FieldElement field) {
|
||||
generateIsDeferredLoadedCheckIfNeeded(node);
|
||||
|
||||
ConstantExpression constant =
|
||||
backend.constants.getConstantForVariable(field);
|
||||
if (constant != null) {
|
||||
if (!field.isAssignable) {
|
||||
// A static final or const. Get its constant value and inline it if
|
||||
// the value can be compiled eagerly.
|
||||
constant = backend.constants.getConstantForVariable(element);
|
||||
}
|
||||
if (constant != null) {
|
||||
ConstantValue value = constant.value;
|
||||
HConstant instruction;
|
||||
// Constants that are referred via a deferred prefix should be referred
|
||||
// by reference.
|
||||
PrefixElement prefix = compiler.deferredLoadTask
|
||||
.deferredPrefixElement(send, elements);
|
||||
if (prefix != null) {
|
||||
instruction = graph.addDeferredConstant(value, prefix, compiler);
|
||||
} else {
|
||||
instruction = graph.addConstant(value, compiler);
|
||||
}
|
||||
stack.add(instruction);
|
||||
// The inferrer may have found a better type than the constant
|
||||
// handler in the case of lists, because the constant handler
|
||||
// does not look at elements in the list.
|
||||
TypeMask type =
|
||||
TypeMaskFactory.inferredTypeForElement(element, compiler);
|
||||
if (!type.containsAll(compiler.world) &&
|
||||
!instruction.isConstantNull()) {
|
||||
// TODO(13429): The inferrer should know that an element
|
||||
// cannot be null.
|
||||
instruction.instructionType = type.nonNullable();
|
||||
}
|
||||
} else if (element.isField && isLazilyInitialized(element)) {
|
||||
HInstruction instruction = new HLazyStatic(
|
||||
element,
|
||||
TypeMaskFactory.inferredTypeForElement(element, compiler));
|
||||
generateStaticConstGet(node, field, constant);
|
||||
} else {
|
||||
// TODO(5346): Try to avoid the need for calling [declaration] before
|
||||
// creating an [HStatic].
|
||||
HInstruction instruction = new HStatic(
|
||||
field.declaration,
|
||||
TypeMaskFactory.inferredTypeForElement(field, compiler));
|
||||
push(instruction);
|
||||
} else {
|
||||
if (element.isGetter) {
|
||||
pushInvokeStatic(send, element, <HInstruction>[]);
|
||||
} else {
|
||||
// TODO(5346): Try to avoid the need for calling [declaration] before
|
||||
// creating an [HStatic].
|
||||
HInstruction instruction = new HStatic(
|
||||
element.declaration,
|
||||
TypeMaskFactory.inferredTypeForElement(element, compiler));
|
||||
push(instruction);
|
||||
}
|
||||
}
|
||||
} else if (Elements.isInstanceSend(send, elements)) {
|
||||
HInstruction receiver = generateInstanceSendReceiver(send);
|
||||
generateInstanceGetterWithCompiledReceiver(
|
||||
send, elements.getSelector(send), receiver);
|
||||
} else if (Elements.isStaticOrTopLevelFunction(element)) {
|
||||
// TODO(5346): Try to avoid the need for calling [declaration] before
|
||||
// creating an [HStatic].
|
||||
push(new HStatic(element.declaration, backend.nonNullType));
|
||||
// TODO(ahe): This should be registered in codegen.
|
||||
registry.registerGetOfStaticFunction(element.declaration);
|
||||
} else if (Elements.isErroneous(element)) {
|
||||
if (element is ErroneousElement) {
|
||||
// An erroneous element indicates an unresolved static getter.
|
||||
generateThrowNoSuchMethod(
|
||||
send,
|
||||
noSuchMethodTargetSymbolString(element, 'get'),
|
||||
argumentNodes: const Link<ast.Node>());
|
||||
} else {
|
||||
// TODO(ahe): Do something like the above, that is, emit a runtime
|
||||
// error.
|
||||
stack.add(graph.addConstantNull(compiler));
|
||||
}
|
||||
} else {
|
||||
if (send.asSendSet() == null) {
|
||||
internalError(send, "Unhandled local: $element");
|
||||
}
|
||||
// TODO(johnniwinther): Remove this when [generateGetter] is no longer
|
||||
// called from [visitSendSet] (for compound assignments).
|
||||
handleLocalGet(element);
|
||||
HInstruction instruction = new HLazyStatic(
|
||||
field,
|
||||
TypeMaskFactory.inferredTypeForElement(field, compiler));
|
||||
push(instruction);
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate a getter invocation of the static or top level [getter].
|
||||
void generateStaticGetterGet(ast.Send node, MethodElement getter) {
|
||||
if (getter.isDeferredLoaderGetter) {
|
||||
generateDeferredLoaderGet(node, getter);
|
||||
} else {
|
||||
generateIsDeferredLoadedCheckIfNeeded(node);
|
||||
pushInvokeStatic(node, getter, <HInstruction>[]);
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate a dynamic getter invocation.
|
||||
void generateDynamicGet(ast.Send node) {
|
||||
HInstruction receiver = generateInstanceSendReceiver(node);
|
||||
generateInstanceGetterWithCompiledReceiver(
|
||||
node, elements.getSelector(node), receiver);
|
||||
}
|
||||
|
||||
/// Generate a closurization of the static or top level [function].
|
||||
void generateStaticFunctionGet(ast.Send node, MethodElement function) {
|
||||
generateIsDeferredLoadedCheckIfNeeded(node);
|
||||
// TODO(5346): Try to avoid the need for calling [declaration] before
|
||||
// creating an [HStatic].
|
||||
push(new HStatic(function.declaration, backend.nonNullType));
|
||||
// TODO(ahe): This should be registered in codegen.
|
||||
registry.registerGetOfStaticFunction(function.declaration);
|
||||
}
|
||||
|
||||
/// Read a local variable, function or parameter.
|
||||
void handleLocalGet(LocalElement local) {
|
||||
stack.add(localsHandler.readLocal(local));
|
||||
}
|
||||
|
||||
@override
|
||||
void visitDynamicPropertyGet(
|
||||
ast.Send node,
|
||||
ast.Node receiver,
|
||||
Selector selector,
|
||||
_) {
|
||||
generateDynamicGet(node);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitLocalVariableGet(ast.Send node, LocalVariableElement variable, _) {
|
||||
handleLocalGet(variable);
|
||||
|
@ -3348,6 +3369,62 @@ class SsaBuilder extends NewResolvedVisitor {
|
|||
handleLocalGet(function);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitStaticFieldGet(
|
||||
ast.Send node,
|
||||
FieldElement field,
|
||||
_) {
|
||||
generateStaticFieldGet(node, field);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitStaticFunctionGet(
|
||||
ast.Send node,
|
||||
MethodElement function,
|
||||
_) {
|
||||
generateStaticFunctionGet(node, function);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitStaticGetterGet(
|
||||
ast.Send node,
|
||||
FunctionElement getter,
|
||||
_) {
|
||||
generateStaticGetterGet(node, getter);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitThisPropertyGet(
|
||||
ast.Send node,
|
||||
Selector selector,
|
||||
_) {
|
||||
generateDynamicGet(node);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitTopLevelFieldGet(
|
||||
ast.Send node,
|
||||
FieldElement field,
|
||||
_) {
|
||||
generateStaticFieldGet(node, field);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitTopLevelFunctionGet(
|
||||
ast.Send node,
|
||||
MethodElement function,
|
||||
_) {
|
||||
generateStaticFunctionGet(node, function);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitTopLevelGetterGet(
|
||||
ast.Send node,
|
||||
FunctionElement getter,
|
||||
_) {
|
||||
generateStaticGetterGet(node, getter);
|
||||
}
|
||||
|
||||
void generateInstanceSetterWithCompiledReceiver(ast.Send send,
|
||||
HInstruction receiver,
|
||||
HInstruction value,
|
||||
|
@ -4014,9 +4091,8 @@ class SsaBuilder extends NewResolvedVisitor {
|
|||
<HInstruction>[]));
|
||||
}
|
||||
|
||||
visitForeignSend(ast.Send node) {
|
||||
Selector selector = elements.getSelector(node);
|
||||
String name = selector.name;
|
||||
void handleForeignSend(ast.Send node, FunctionElement element) {
|
||||
String name = element.name;
|
||||
if (name == 'JS') {
|
||||
handleForeignJs(node);
|
||||
} else if (name == 'JS_CURRENT_ISOLATE_CONTEXT') {
|
||||
|
@ -4091,15 +4167,13 @@ class SsaBuilder extends NewResolvedVisitor {
|
|||
} else if (name == 'JS_STRING_CONCAT') {
|
||||
handleJsStringConcat(node);
|
||||
} else {
|
||||
throw "Unknown foreign: ${selector}";
|
||||
throw "Unknown foreign: ${element}";
|
||||
}
|
||||
}
|
||||
|
||||
visitForeignGetter(ast.Send node) {
|
||||
Element element = elements[node];
|
||||
generateDeferredLoaderGet(ast.Send node, FunctionElement deferredLoader) {
|
||||
// Until now we only handle these as getters.
|
||||
invariant(node, element.isDeferredLoaderGetter);
|
||||
FunctionElement deferredLoader = element;
|
||||
invariant(node, deferredLoader.isDeferredLoaderGetter);
|
||||
Element loadFunction = compiler.loadLibraryFunction;
|
||||
PrefixElement prefixElement = deferredLoader.enclosingElement;
|
||||
String loadId = compiler.deferredLoadTask
|
||||
|
@ -4798,72 +4872,156 @@ class SsaBuilder extends NewResolvedVisitor {
|
|||
}
|
||||
assert(invariant(node, node.arguments.tail.isEmpty,
|
||||
message: "Invalid assertion: $node"));
|
||||
buildStaticFunctionInvoke(
|
||||
generateStaticFunctionInvoke(
|
||||
node, backend.assertMethod, CallStructure.ONE_ARG);
|
||||
}
|
||||
|
||||
visitStaticSend(ast.Send node) {
|
||||
CallStructure callStructure = elements.getSelector(node).callStructure;
|
||||
Element element = elements[node];
|
||||
if (elements.isAssert(node)) {
|
||||
element = backend.assertMethod;
|
||||
}
|
||||
if (element.isForeign(backend) && element.isFunction) {
|
||||
visitForeignSend(node);
|
||||
return;
|
||||
}
|
||||
if (element.isErroneous) {
|
||||
if (element is ErroneousElement) {
|
||||
// An erroneous element indicates that the funciton could not be
|
||||
// resolved (a warning has been issued).
|
||||
generateThrowNoSuchMethod(node,
|
||||
noSuchMethodTargetSymbolString(element),
|
||||
argumentNodes: node.arguments);
|
||||
} else {
|
||||
// TODO(ahe): Do something like [generateWrongArgumentCountError].
|
||||
stack.add(graph.addConstantNull(compiler));
|
||||
}
|
||||
return;
|
||||
}
|
||||
invariant(element, !element.isGenerativeConstructor);
|
||||
generateIsDeferredLoadedCheckIfNeeded(node);
|
||||
if (element.isFunction) {
|
||||
// TODO(5347): Try to avoid the need for calling [implementation] before
|
||||
// calling [makeStaticArgumentList].
|
||||
if (!callStructure.signatureApplies(element.implementation)) {
|
||||
generateWrongArgumentCountError(node, element, node.arguments);
|
||||
return;
|
||||
}
|
||||
buildStaticFunctionInvoke(node, element, callStructure);
|
||||
} else {
|
||||
generateGetter(node, element);
|
||||
List<HInstruction> inputs = <HInstruction>[pop()];
|
||||
addDynamicSendArgumentsToList(node, inputs);
|
||||
Selector closureSelector = callStructure.callSelector;
|
||||
pushWithPosition(
|
||||
new HInvokeClosure(closureSelector, inputs, backend.dynamicType),
|
||||
node);
|
||||
}
|
||||
internalError(node, "Unexpected visitStaticSend");
|
||||
}
|
||||
|
||||
void buildStaticFunctionInvoke(
|
||||
/// Generate an invocation to the static or top level [function].
|
||||
void generateStaticFunctionInvoke(
|
||||
ast.Send node,
|
||||
FunctionElement element,
|
||||
FunctionElement function,
|
||||
CallStructure callStructure) {
|
||||
List<HInstruction> inputs = makeStaticArgumentList(
|
||||
callStructure,
|
||||
node.arguments,
|
||||
element.implementation);
|
||||
function.implementation);
|
||||
|
||||
if (element == compiler.identicalFunction) {
|
||||
if (function == compiler.identicalFunction) {
|
||||
pushWithPosition(
|
||||
new HIdentity(inputs[0], inputs[1], null, backend.boolType), node);
|
||||
return;
|
||||
} else {
|
||||
pushInvokeStatic(node, element, inputs);
|
||||
pushInvokeStatic(node, function, inputs);
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate an invocation to a static or top level function with the wrong
|
||||
/// number of arguments.
|
||||
void generateStaticFunctionIncompatibleInvoke(ast.Send node,
|
||||
Element element) {
|
||||
generateWrongArgumentCountError(node, element, node.arguments);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitStaticFieldInvoke(
|
||||
ast.Send node,
|
||||
FieldElement field,
|
||||
ast.NodeList arguments,
|
||||
CallStructure callStructure,
|
||||
_) {
|
||||
generateStaticFieldGet(node, field);
|
||||
generateCallInvoke(node, pop());
|
||||
}
|
||||
|
||||
@override
|
||||
void visitStaticFunctionInvoke(
|
||||
ast.Send node,
|
||||
MethodElement function,
|
||||
ast.NodeList arguments,
|
||||
CallStructure callStructure,
|
||||
_) {
|
||||
generateStaticFunctionInvoke(node, function, callStructure);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitStaticFunctionIncompatibleInvoke(
|
||||
ast.Send node,
|
||||
MethodElement function,
|
||||
ast.NodeList arguments,
|
||||
CallStructure callStructure,
|
||||
_) {
|
||||
generateStaticFunctionIncompatibleInvoke(node, function);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitStaticGetterInvoke(
|
||||
ast.Send node,
|
||||
FunctionElement getter,
|
||||
ast.NodeList arguments,
|
||||
CallStructure callStructure,
|
||||
_) {
|
||||
generateStaticGetterGet(node, getter);
|
||||
generateCallInvoke(node, pop());
|
||||
}
|
||||
|
||||
@override
|
||||
void visitTopLevelFieldInvoke(
|
||||
ast.Send node,
|
||||
FieldElement field,
|
||||
ast.NodeList arguments,
|
||||
CallStructure callStructure,
|
||||
_) {
|
||||
generateStaticFieldGet(node, field);
|
||||
generateCallInvoke(node, pop());
|
||||
}
|
||||
|
||||
@override
|
||||
void visitTopLevelFunctionInvoke(
|
||||
ast.Send node,
|
||||
MethodElement function,
|
||||
ast.NodeList arguments,
|
||||
CallStructure callStructure,
|
||||
_) {
|
||||
if (function.isForeign(backend)) {
|
||||
handleForeignSend(node, function);
|
||||
} else {
|
||||
generateStaticFunctionInvoke(node, function, callStructure);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void visitTopLevelFunctionIncompatibleInvoke(
|
||||
ast.Send node,
|
||||
MethodElement function,
|
||||
ast.NodeList arguments,
|
||||
CallStructure callStructure,
|
||||
_) {
|
||||
generateStaticFunctionIncompatibleInvoke(node, function);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitTopLevelGetterInvoke(
|
||||
ast.Send node,
|
||||
FunctionElement getter,
|
||||
ast.NodeList arguments,
|
||||
CallStructure callStructure,
|
||||
_) {
|
||||
generateStaticGetterGet(node, getter);
|
||||
generateCallInvoke(node, pop());
|
||||
}
|
||||
|
||||
@override
|
||||
void visitUnresolvedGet(
|
||||
ast.Send node,
|
||||
Element element,
|
||||
_) {
|
||||
generateStaticUnresolvedGet(node, element);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitUnresolvedInvoke(
|
||||
ast.Send node,
|
||||
Element element,
|
||||
ast.NodeList arguments,
|
||||
Selector selector,
|
||||
_) {
|
||||
if (element is ErroneousElement) {
|
||||
// An erroneous element indicates that the funciton could not be
|
||||
// resolved (a warning has been issued).
|
||||
generateThrowNoSuchMethod(node,
|
||||
noSuchMethodTargetSymbolString(element),
|
||||
argumentNodes: node.arguments);
|
||||
} else {
|
||||
// TODO(ahe): Do something like [generateWrongArgumentCountError].
|
||||
stack.add(graph.addConstantNull(compiler));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
HConstant addConstantString(String string) {
|
||||
ast.DartString dartString = new ast.DartString.literal(string);
|
||||
ConstantValue constant = constantSystem.createString(dartString);
|
||||
|
@ -4985,8 +5143,7 @@ class SsaBuilder extends NewResolvedVisitor {
|
|||
}
|
||||
|
||||
visitGetterSend(ast.Send node) {
|
||||
generateIsDeferredLoadedCheckIfNeeded(node);
|
||||
generateGetter(node, elements[node]);
|
||||
internalError(node, "Unexpected visitGetterSend");
|
||||
}
|
||||
|
||||
// TODO(antonm): migrate rest of SsaFromAstMixin to internalError.
|
||||
|
@ -5390,8 +5547,18 @@ class SsaBuilder extends NewResolvedVisitor {
|
|||
receiver = generateInstanceSendReceiver(node);
|
||||
generateInstanceGetterWithCompiledReceiver(
|
||||
node, elements.getGetterSelectorInComplexSendSet(node), receiver);
|
||||
} else if (getter.isErroneous) {
|
||||
generateStaticUnresolvedGet(node, getter);
|
||||
} else if (getter.isField) {
|
||||
generateStaticFieldGet(node, getter);
|
||||
} else if (getter.isGetter) {
|
||||
generateStaticGetterGet(node, getter);
|
||||
} else if (getter.isFunction) {
|
||||
generateStaticFunctionGet(node, getter);
|
||||
} else if (getter.isLocal) {
|
||||
handleLocalGet(getter);
|
||||
} else {
|
||||
generateGetter(node, getter);
|
||||
internalError(node, "Unexpected getter: $getter");
|
||||
}
|
||||
HInstruction getterInstruction = pop();
|
||||
handleComplexOperatorSend(node, getterInstruction, node.arguments);
|
||||
|
|
|
@ -127,6 +127,7 @@ Future<String> compileAll(String code,
|
|||
trustTypeAnnotations: trustTypeAnnotations,
|
||||
expectedWarnings: expectedWarnings,
|
||||
outputProvider: outputCollector);
|
||||
compiler.diagnosticHandler = createHandler(compiler, code);
|
||||
return compiler.runCompiler(uri).then((_) {
|
||||
Expect.isFalse(compiler.compilationFailed,
|
||||
'Unexpected compilation error(s): ${compiler.errors}');
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// 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 'dart:async';
|
||||
import "package:expect/expect.dart";
|
||||
import "package:async_helper/async_helper.dart";
|
||||
import 'compiler_helper.dart';
|
||||
|
@ -235,27 +236,31 @@ void main() {
|
|||
|
||||
|
||||
main() {
|
||||
test(String code, Function f) {
|
||||
asyncTest(() => compileAll(code, disableInlining: false).then((generated) {
|
||||
Expect.isTrue(f(generated));
|
||||
}));
|
||||
test(String code, String expected) {
|
||||
return () => compileAll(code, disableInlining: false).then((generated) {
|
||||
Expect.isTrue(generated.contains(expected),
|
||||
"Generated code didn't contain '$expected'.\n"
|
||||
"Test:\n$code, Generated:\n$generated");
|
||||
});
|
||||
}
|
||||
test(TEST_1, (generated) => generated.contains('return 42'));
|
||||
test(TEST_2, (generated) => generated.contains('return 42'));
|
||||
test(TEST_3, (generated) => generated.contains('return 84'));
|
||||
test(TEST_4, (generated) => generated.contains('return t1 + t1'));
|
||||
test(TEST_5, (generated) => generated.contains('return 84'));
|
||||
test(TEST_6, (generated) => generated.contains('return 84'));
|
||||
test(TEST_7, (generated) => generated.contains('return 32'));
|
||||
test(TEST_8, (generated) => generated.contains('return a.a'));
|
||||
test(TEST_9, (generated) => generated.contains('return a.a'));
|
||||
test(TEST_10, (generated) => generated.contains('return 2'));
|
||||
test(TEST_11, (generated) => generated.contains('return a.a'));
|
||||
test(TEST_12, (generated) => generated.contains('return 6'));
|
||||
test(TEST_13, (generated) => generated.contains('return 6'));
|
||||
test(TEST_14, (generated) => generated.contains('return t1[0]'));
|
||||
test(TEST_15, (generated) => generated.contains('return 42'));
|
||||
test(TEST_16, (generated) => generated.contains('return \$.a'));
|
||||
test(TEST_17, (generated) => generated.contains('return t1'));
|
||||
test(TEST_18, (generated) => generated.contains('return t1'));
|
||||
asyncTest(() => Future.forEach([
|
||||
test(TEST_1, 'return 42'),
|
||||
test(TEST_2, 'return 42'),
|
||||
test(TEST_3, 'return 84'),
|
||||
test(TEST_4, 'return t1 + t1'),
|
||||
test(TEST_5, 'return 84'),
|
||||
test(TEST_6, 'return 84'),
|
||||
test(TEST_7, 'return 32'),
|
||||
test(TEST_8, 'return a.a'),
|
||||
test(TEST_9, 'return a.a'),
|
||||
test(TEST_10, 'return 2'),
|
||||
test(TEST_11, 'return a.a'),
|
||||
test(TEST_12, 'return 6'),
|
||||
test(TEST_13, 'return 6'),
|
||||
test(TEST_14, 'return t1[0]'),
|
||||
test(TEST_15, 'return 42'),
|
||||
test(TEST_16, 'return \$.a'),
|
||||
test(TEST_17, 'return t1'),
|
||||
test(TEST_18, 'return t1'),
|
||||
], (f) => f()));
|
||||
}
|
||||
|
|
|
@ -505,6 +505,14 @@ const Map<String, List<Test>> SEND_TESTS = const {
|
|||
const Visit(VisitKind.VISIT_STATIC_FUNCTION_INVOKE,
|
||||
element: 'function(C#o)',
|
||||
arguments: '(null,42)')),
|
||||
const Test(
|
||||
'''
|
||||
class C { static o(a, b) {} }
|
||||
m() => C.o(null);
|
||||
''',
|
||||
const Visit(VisitKind.VISIT_STATIC_FUNCTION_INCOMPATIBLE_INVOKE,
|
||||
element: 'function(C#o)',
|
||||
arguments: '(null)')),
|
||||
],
|
||||
'Top level fields': const [
|
||||
// Top level fields
|
||||
|
@ -554,6 +562,12 @@ const Map<String, List<Test>> SEND_TESTS = const {
|
|||
const Visit(VisitKind.VISIT_TOP_LEVEL_FIELD_INVOKE,
|
||||
element: 'field(o)',
|
||||
arguments: '(null,42)')),
|
||||
const Test(
|
||||
'''
|
||||
m() => o;
|
||||
''',
|
||||
const Visit(VisitKind.VISIT_UNRESOLVED_GET,
|
||||
name: 'o')),
|
||||
],
|
||||
'Top level properties': const [
|
||||
// Top level properties
|
||||
|
@ -623,6 +637,14 @@ const Map<String, List<Test>> SEND_TESTS = const {
|
|||
const Visit(VisitKind.VISIT_TOP_LEVEL_FUNCTION_INVOKE,
|
||||
element: 'function(o)',
|
||||
arguments: '(null,42)')),
|
||||
const Test(
|
||||
'''
|
||||
o(a, b) {}
|
||||
m() => o(null);
|
||||
''',
|
||||
const Visit(VisitKind.VISIT_TOP_LEVEL_FUNCTION_INCOMPATIBLE_INVOKE,
|
||||
element: 'function(o)',
|
||||
arguments: '(null)')),
|
||||
const Test.prefix(
|
||||
'''
|
||||
o(a, b) {}
|
||||
|
@ -631,6 +653,13 @@ const Map<String, List<Test>> SEND_TESTS = const {
|
|||
const Visit(VisitKind.VISIT_TOP_LEVEL_FUNCTION_INVOKE,
|
||||
element: 'function(o)',
|
||||
arguments: '(null,42)')),
|
||||
const Test(
|
||||
'''
|
||||
m() => o(null, 42);
|
||||
''',
|
||||
const Visit(VisitKind.VISIT_UNRESOLVED_INVOKE,
|
||||
name: 'o',
|
||||
arguments: '(null,42)')),
|
||||
],
|
||||
'Dynamic properties': const [
|
||||
// Dynamic properties
|
||||
|
@ -3640,6 +3669,18 @@ class SemanticSendTestVisitor extends SemanticTestVisitor {
|
|||
apply(arguments, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
visitStaticFunctionIncompatibleInvoke(
|
||||
Send node,
|
||||
MethodElement function,
|
||||
NodeList arguments,
|
||||
CallStructure callStructure,
|
||||
arg) {
|
||||
visits.add(new Visit(VisitKind.VISIT_STATIC_FUNCTION_INCOMPATIBLE_INVOKE,
|
||||
element: function, arguments: arguments));
|
||||
apply(arguments, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
visitStaticGetterGet(
|
||||
Send node,
|
||||
|
@ -3828,6 +3869,18 @@ class SemanticSendTestVisitor extends SemanticTestVisitor {
|
|||
apply(arguments, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
visitTopLevelFunctionIncompatibleInvoke(
|
||||
Send node,
|
||||
MethodElement function,
|
||||
NodeList arguments,
|
||||
CallStructure callStructure,
|
||||
arg) {
|
||||
visits.add(new Visit(VisitKind.VISIT_TOP_LEVEL_FUNCTION_INCOMPATIBLE_INVOKE,
|
||||
element: function, arguments: arguments));
|
||||
apply(arguments, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
visitTopLevelGetterGet(
|
||||
Send node,
|
||||
|
@ -5065,21 +5118,22 @@ class SemanticSendTestVisitor extends SemanticTestVisitor {
|
|||
}
|
||||
|
||||
@override
|
||||
errorUnresolvedGet(
|
||||
visitUnresolvedGet(
|
||||
Send node,
|
||||
ErroneousElement element,
|
||||
Element element,
|
||||
arg) {
|
||||
// TODO: implement errorUnresolvedGet
|
||||
visits.add(new Visit(VisitKind.VISIT_UNRESOLVED_GET, name: element.name));
|
||||
}
|
||||
|
||||
@override
|
||||
errorUnresolvedInvoke(
|
||||
visitUnresolvedInvoke(
|
||||
Send node,
|
||||
ErroneousElement element,
|
||||
Element element,
|
||||
NodeList arguments,
|
||||
Selector selector,
|
||||
arg) {
|
||||
// TODO: implement errorUnresolvedInvoke
|
||||
visits.add(new Visit(VisitKind.VISIT_UNRESOLVED_INVOKE,
|
||||
name: element.name, arguments: arguments));
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -6036,6 +6090,7 @@ enum VisitKind {
|
|||
|
||||
VISIT_STATIC_FUNCTION_GET,
|
||||
VISIT_STATIC_FUNCTION_INVOKE,
|
||||
VISIT_STATIC_FUNCTION_INCOMPATIBLE_INVOKE,
|
||||
VISIT_STATIC_FUNCTION_DECL,
|
||||
|
||||
VISIT_TOP_LEVEL_FIELD_GET,
|
||||
|
@ -6058,6 +6113,7 @@ enum VisitKind {
|
|||
|
||||
VISIT_TOP_LEVEL_FUNCTION_GET,
|
||||
VISIT_TOP_LEVEL_FUNCTION_INVOKE,
|
||||
VISIT_TOP_LEVEL_FUNCTION_INCOMPATIBLE_INVOKE,
|
||||
VISIT_TOP_LEVEL_FUNCTION_DECL,
|
||||
|
||||
VISIT_DYNAMIC_PROPERTY_GET,
|
||||
|
@ -6101,6 +6157,8 @@ enum VisitKind {
|
|||
VISIT_SUPER_METHOD_INVOKE,
|
||||
VISIT_SUPER_METHOD_INCOMPATIBLE_INVOKE,
|
||||
|
||||
VISIT_UNRESOLVED_GET,
|
||||
VISIT_UNRESOLVED_INVOKE,
|
||||
VISIT_UNRESOLVED_SUPER_GET,
|
||||
VISIT_UNRESOLVED_SUPER_INVOKE,
|
||||
|
||||
|
|
Loading…
Reference in a new issue