Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(75)

Unified Diff: compiler/java/com/google/dart/compiler/backend/js/GenerateJavascriptAST.java

Issue 8566022: Function type checking (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Getting to work in optimized Created 9 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: compiler/java/com/google/dart/compiler/backend/js/GenerateJavascriptAST.java
diff --git a/compiler/java/com/google/dart/compiler/backend/js/GenerateJavascriptAST.java b/compiler/java/com/google/dart/compiler/backend/js/GenerateJavascriptAST.java
index b9971760c053b235d6fc61454a0f135618170fe6..093cbec0f9cb16d0dd380fefa43629044d1f2f1a 100644
--- a/compiler/java/com/google/dart/compiler/backend/js/GenerateJavascriptAST.java
+++ b/compiler/java/com/google/dart/compiler/backend/js/GenerateJavascriptAST.java
@@ -1,4 +1,4 @@
-// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// Copyright (c) 2011, 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.
@@ -278,7 +278,7 @@ public class GenerateJavascriptAST {
jsNewDeclarationsStack.push(new HashSet<JsName>());
currentHolder = unit.getLibrary().getElement();
rtt = new RuntimeTypeInjector(this, typeProvider, translationContext,
- context.getCompilerConfiguration().developerModeChecks());
+ context.getCompilerConfiguration().developerModeChecks(), mangler, unitLibrary);
}
/**
@@ -593,38 +593,68 @@ public class GenerateJavascriptAST {
* Creates a $getter for a method of a class, returning $method as a closure
* bound to the current instance if it is an instance method.
*/
- private void generateMethodGetter(MethodElement methodElement) {
+ private void generateMethodGetter(MethodElement methodElement, boolean setSourceRefernce) {
// Generate a getter for method binding to a variable
- JsNameRef classJsNameRef = getJsName(methodElement.getEnclosingElement()).makeRef();
+ boolean isTopLevel = Elements.isTopLevel(methodElement);
+ if (methodElement.getModifiers().isGetter() || methodElement.getModifiers().isSetter()) {
+ return;
+ }
+ JsNameRef classJsNameRef = isTopLevel ? null :
+ getJsName(methodElement.getEnclosingElement()).makeRef();
String getterName = mangler.createGetterSyntax(methodElement, unitLibrary);
String methodName = methodElement.getName();
JsName getterJsName = globalScope.declareName(getterName, getterName, methodName);
getterJsName.setObfuscatable(false);
String mangledMethodName = mangler.mangleNamedMethod(methodElement, unitLibrary);
+ String mangledRttMethodName = mangledMethodName + "_$lookupRTT";
JsFunction func = new JsFunction(globalScope);
JsNameRef getterJsNameRef;
JsExpression methodToCall;
- if (methodElement.getModifiers().isStatic()) {
+ JsExpression rttMethodToCall;
+ if (isTopLevel || methodElement.getModifiers().isStatic()) {
// function() { return <class><member>$member; }
+ JsBlock body = new JsBlock();
+ func.setBody(body);
+ List<JsStatement> stmts = body.getStatements();
+ JsName returnVar = func.getScope().declareFreshName("ret");
+
getterJsNameRef = AstUtil.newNameRef(classJsNameRef, getterJsName);
methodToCall = AstUtil.newNameRef(classJsNameRef, mangledMethodName);
- func.setBody(AstUtil.newBlock(new JsReturn(methodToCall)));
+ stmts.add(AstUtil.newVar(null, returnVar, methodToCall));
+
+ rttMethodToCall = AstUtil.newNameRef(classJsNameRef, mangledRttMethodName);
+ JsBinaryOperation varLookup = AstUtil.newAssignment(
+ AstUtil.newNameRef(returnVar.makeRef(), "$lookupRTT"), rttMethodToCall);
+ stmts.add(varLookup.makeStmt());
+ stmts.add(new JsReturn(returnVar.makeRef()));
} else {
// function() { return $bind(<class>.prototype.<member>$member, this); }
JsNameRef prototypeRef = AstUtil.newPrototypeNameRef(classJsNameRef);
getterJsNameRef = AstUtil.newNameRef(prototypeRef, getterJsName);
methodToCall = AstUtil.newNameRef(prototypeRef, mangledMethodName);
+ rttMethodToCall = AstUtil.newNameRef(prototypeRef, mangledRttMethodName);
JsExpression bindMethodCall = AstUtil.newInvocation(
- new JsNameRef("$bind"), methodToCall, new JsThisRef());
+ new JsNameRef("$bind"), methodToCall, rttMethodToCall, new JsThisRef());
func.setBody(AstUtil.newBlock(new JsReturn(bindMethodCall)));
}
- func.setName(getterJsNameRef.getName());
- func.setSourceRef(methodElement.getNode());
- JsBinaryOperation asg = AstUtil.newAssignment(getterJsNameRef, func);
- asg.setSourceRef(methodElement.getNode());
+
+ JsExpression asg;
+ if (setSourceRefernce) {
+ func.setSourceRef(methodElement.getNode());
+ func.setName(null);
+ asg = AstUtil.newAssignment(getterJsNameRef, func);
+ asg.setSourceRef(methodElement.getNode());
+ } else {
+ func.setName(globalScope.declareName(getterJsNameRef.toString()));
+ asg = func;
+ }
globalBlock.getStatements().add(asg.makeStmt());
}
+ private void generateMethodGetter(MethodElement methodElement) {
+ generateMethodGetter(methodElement, true);
+ }
+
private boolean hasConstConstructor(ClassElement element) {
for (ConstructorElement ctr : element.getConstructors()) {
if (ctr.getModifiers().isConstant()) {
@@ -1095,8 +1125,7 @@ public class GenerateJavascriptAST {
}
assert currentScopeInfo == null : "Nested methods should be impossible";
- inFactoryOrStaticContext = x.getModifiers().isFactory()
- || x.getModifiers().isStatic();
+ inFactoryOrStaticContext = isFactoryOrStaticContext(x.getModifiers());
currentScopeInfo = ScopeRootInfo.makeScopeInfo(x, !shouldGenerateDeveloperModeChecks());
JsFunction func = (JsFunction) generate(x.getFunction());
@@ -1113,6 +1142,10 @@ public class GenerateJavascriptAST {
globalBlock.getStatements().add(func.makeStmt());
globalBlock.getStatements().add(tramp.makeStmt());
+
+ // special case for top level methods
+ rtt.generateRuntimeTypeInfo(x);
+ generateMethodGetter(x.getSymbol(), false);
}
return func;
@@ -1318,9 +1351,13 @@ public class GenerateJavascriptAST {
return prop;
}
+ private boolean isFactoryOrStaticContext(Modifiers modifiers) {
+ return modifiers.isFactory() || modifiers.isStatic();
+ }
+
/**
- * Turns a method into a prototype assignment on the JS class. Clears the
- * name from the given function.
+ * Turns a method into a prototype assignment on the JS class. Clears the name from the given
+ * function.
*/
private void makeMethod(Element element, JsFunction func) {
if (element.getEnclosingElement().getKind().equals(ElementKind.CLASS)) {
@@ -1333,10 +1370,8 @@ public class GenerateJavascriptAST {
globalBlock.getStatements().add(asg.makeStmt());
// If it's a (non-operator, non-property) method, generate its named trampoline.
- if (element.getKind().equals(ElementKind.METHOD) &&
- !element.getModifiers().isOperator() &&
- !element.getModifiers().isGetter() &&
- !element.getModifiers().isSetter()) {
+ if (element.getKind().equals(ElementKind.METHOD) && !element.getModifiers().isOperator()
+ && !element.getModifiers().isGetter() && !element.getModifiers().isSetter()) {
// Declare the mangled trampoline's name in the same scope as its target.
String mangled = mangler.mangleNamedMethod((MethodElement) element, unitLibrary);
JsName namedName = prop.getName().getEnclosing().declareName(mangled);
@@ -1347,6 +1382,18 @@ public class GenerateJavascriptAST {
asg = assign(namedProp, tramp);
globalBlock.getStatements().add(asg.makeStmt());
+
+ // Generate a lookup method after finally writing function / named tramp
+ assert currentScopeInfo == null : "Nested methods should be impossible";
+ inFactoryOrStaticContext = isFactoryOrStaticContext(element.getModifiers());
+ DartMethodDefinition x = (DartMethodDefinition) element.getNode();
+ currentScopeInfo = ScopeRootInfo.makeScopeInfo(x, !shouldGenerateDeveloperModeChecks());
+ rtt.generateRuntimeTypeInfo(x);
+
+ assert currentScopeInfo != null;
+ inFactoryOrStaticContext = false;
+ currentScopeInfo = null;
+
}
} else {
globalBlock.getStatements().add(func.makeStmt());
@@ -2925,6 +2972,7 @@ public class GenerateJavascriptAST {
JsName fnDeclaredName;
JsName hoistedName;
+ String hoistedRttName = null;
// TODO(johnlenz): values used in super class init methods are currently
// evaluated twice (once for the init and once for the constructor), but
@@ -2934,6 +2982,7 @@ public class GenerateJavascriptAST {
if (fnWasPreviouslyHoisted) {
fnDeclaredName = fn.getName();
hoistedName = fn.getName();
+ hoistedRttName = hoistedName.toString() + "_$lookupRTT";
} else {
// 0) Save off the original name
@@ -2971,16 +3020,28 @@ public class GenerateJavascriptAST {
hoistedName = globalScope.declareName(mangled);
tramp.setName(hoistedName);
globalBlock.getStatements().add(tramp.makeStmt());
+
+ if (x.getParent() != null && !(x.getParent() instanceof DartFunctionObjectInvocation)) {
+ hoistedRttName = hoistedName + "_$lookupRTT";
+ rtt.generateRuntimeTypeInfo(x, hoistedRttName);
+ }
+ } else {
+ String mangled = mangler.mangleNamedMethod(hoistedName.getIdent(), unitLibrary);
+ hoistedName = globalScope.declareName(mangled);
+ hoistedRttName = hoistedName + "_$lookupRTT";
+ }
+
+ if (x.getParent() == null || (x.getParent() instanceof DartFunctionObjectInvocation)) {
+ hoistedRttName = null;
}
// 5) Bind the necessary scope references and possibly "this".
JsExpression replacement;
if (list.isEmpty() && inFactoryOrStaticContext) {
-
// Simply replace the function
- replacement = new JsNameRef(hoistedName);
-
+ replacement = AstUtil.newInvocation(new JsNameRef("$bind"), new JsNameRef(hoistedName),
+ hoistedRttName != null ? new JsNameRef(hoistedRttName) : nulle(), undefined());
} else {
// Replace "function (){}" with "bind(hoistedName, this, scope1, scope2, ...)"
// so that references to class fields can be resolved.
@@ -3004,8 +3065,8 @@ public class GenerateJavascriptAST {
}
}
- JsInvocation invoke =
- AstUtil.newInvocation(new JsNameRef(jsBindName), new JsNameRef(hoistedName), thisRef);
+ JsInvocation invoke = AstUtil.newInvocation(new JsNameRef(jsBindName), new JsNameRef(
+ hoistedName), hoistedRttName != null ? new JsNameRef(hoistedRttName) : nulle(), thisRef);
// Add the scope alias to the bind call and function parameter list
int parameterIndex = 0;
@@ -3532,6 +3593,15 @@ public class GenerateJavascriptAST {
@Override
public JsNode visitFunctionTypeAlias(DartFunctionTypeAlias node) {
+ // TODO(codefu): Optimize away if we're never the rhs of a "is" check.
+ ClassElement classElement = node.getSymbol();
+ JsName classJsName = getJsName(classElement);
+ JsFunction jsClass = new JsFunction(globalScope, classJsName).setSourceRef(node);
+ jsClass.setIsConstructor(false);
+ jsClass.setBody(new JsBlock());
+ globalBlock.getStatements().add(jsClass.makeStmt());
+
+ rtt.generateRuntimeTypeInfo(node);
return null;
}
@@ -3617,21 +3687,23 @@ public class GenerateJavascriptAST {
MethodElement methodElement, DartNode qualifier) {
JsExpression boundMethod;
String mangledName = mangler.mangleNamedMethod(methodElement, unitLibrary);
+ String mangledGetter = mangler.createGetterSyntax(methodElement, unitLibrary);
boolean isSuperCall = (qualifier != null) && isSuperCall(qualifier.getSymbol());
if (isSuperCall) {
boundMethod = generateSuperFieldAccess(qualifier,
- mangler.createGetterSyntax(methodElement.getName(), unitLibrary));
+ mangler.createGetterSyntax(methodElement.getName(), unitLibrary));
} else if (Elements.isTopLevel(methodElement)) {
- boundMethod = AstUtil.newNameRef(null, mangledName);
+ boundMethod = AstUtil.newInvocation(AstUtil.newNameRef(null, mangledGetter));
} else if (methodElement.isStatic()) {
if (qualifier == null) {
qualifier = methodElement.getEnclosingElement().getNode();
assert (qualifier instanceof DartClass);
- boundMethod = AstUtil.newNameRef(getJsName(qualifier.getSymbol()).makeRef(), mangledName);
+ boundMethod = AstUtil.newNameRef(getJsName(qualifier.getSymbol()).makeRef(),
+ mangledGetter);
} else {
- assert (qualifier instanceof DartIdentifier);
- boundMethod = AstUtil.newNameRef((JsExpression) generate(qualifier), mangledName);
+ boundMethod = AstUtil.newNameRef((JsExpression) generate(qualifier), mangledGetter);
}
+ boundMethod = AstUtil.newInvocation(boundMethod);
} else {
// Should be an invocation on an instance
if (qualifier == null) {
@@ -3642,7 +3714,8 @@ public class GenerateJavascriptAST {
String className = mangler.mangleClassName(classElement);
JsNameRef prototypeRef = AstUtil.newPrototypeNameRef(new JsNameRef(className));
JsExpression methodToCall = AstUtil.newNameRef(prototypeRef, mangledName);
- boundMethod = AstUtil.newInvocation(new JsNameRef("$bind"), methodToCall, methodQualifier);
+ JsExpression methodRtt = AstUtil.newNameRef(prototypeRef, mangledName + "_$lookupRTT");
+ boundMethod = AstUtil.newInvocation(new JsNameRef("$bind"), methodToCall, methodRtt, methodQualifier);
}
boundMethod.setSourceRef(methodNode);
return boundMethod;

Powered by Google App Engine
This is Rietveld 408576698