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

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

Issue 8845002: Function type checking: Part Deux (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: 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 a3c030fac11aff91bbb3889144f4d164386bb247..0e157a2dee6f9d6813b1a17350c5d3f931ba5de4 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);
}
/**
@@ -595,33 +595,57 @@ public class GenerateJavascriptAST {
*/
private void generateMethodGetter(MethodElement methodElement) {
// 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";
mmendez 2011/12/07 20:03:00 Nit: you could add this logic to the mangler insta
codefu 2011/12/07 21:44:54 Done.
JsFunction func = new JsFunction(globalScope);
JsNameRef getterJsNameRef;
- JsExpression methodToCall;
- if (methodElement.getModifiers().isStatic()) {
- // function() { return <class><member>$member; }
+ if (isTopLevel || methodElement.getModifiers().isStatic()) {
+ // function() {
+ // var ret = <class><member>$named;
+ // ret.$lookupRTT = <class><member>$named_$lookupRTT;
+ // return ret;
+ // }
+ func.setBody(new JsBlock());
+ List<JsStatement> stmts = func.getBody().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,
+ AstUtil.newNameRef(classJsNameRef, mangledMethodName)));
+ JsBinaryOperation varLookup = AstUtil.newAssignment(
+ AstUtil.newNameRef(returnVar.makeRef(), "$lookupRTT"),
+ AstUtil.newNameRef(classJsNameRef, mangledRttMethodName));
+ stmts.add(varLookup.makeStmt());
+ stmts.add(new JsReturn(returnVar.makeRef()));
} else {
- // function() { return $bind(<class>.prototype.<member>$member, this); }
+ // function() { return $bind(<class>.prototype.<member>$named,
+ // $bind(<class>.prototype.<member>$named_$lookupRTT, this); }
JsNameRef prototypeRef = AstUtil.newPrototypeNameRef(classJsNameRef);
getterJsNameRef = AstUtil.newNameRef(prototypeRef, getterJsName);
- methodToCall = AstUtil.newNameRef(prototypeRef, mangledMethodName);
- JsExpression bindMethodCall = AstUtil.newInvocation(
- new JsNameRef("$bind"), methodToCall, new JsThisRef());
+ JsExpression bindMethodCall = AstUtil.newInvocation(new JsNameRef("$bind"),
+ AstUtil.newNameRef(prototypeRef, mangledMethodName),
+ AstUtil.newNameRef(prototypeRef, mangledRttMethodName), 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 (isTopLevel) {
+ func.setName(globalScope.declareName(getterJsNameRef.toString()));
codefu 2011/12/07 21:44:54 Could this just be func.setName(getterJsNameRef.ge
+ asg = func;
mmendez 2011/12/07 20:03:00 Missing call to setSourceRef?
codefu 2011/12/07 21:44:54 Top levels didn't have a $getter before this chang
+ } else {
+ func.setSourceRef(methodElement.getNode());
+ asg = AstUtil.newAssignment(getterJsNameRef, func);
+ asg.setSourceRef(methodElement.getNode());
+ }
globalBlock.getStatements().add(asg.makeStmt());
}
@@ -1095,12 +1119,10 @@ 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());
-
assert currentScopeInfo != null;
inFactoryOrStaticContext = false;
currentScopeInfo = null;
@@ -1113,6 +1135,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());
}
return func;
@@ -1335,9 +1361,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)) {
@@ -1350,10 +1380,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);
@@ -1364,6 +1392,17 @@ 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());
@@ -2942,6 +2981,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
@@ -2951,6 +2991,7 @@ public class GenerateJavascriptAST {
if (fnWasPreviouslyHoisted) {
fnDeclaredName = fn.getName();
hoistedName = fn.getName();
+ hoistedRttName = hoistedName.toString() + "_$lookupRTT";
mmendez 2011/12/07 20:03:00 Nit: See comment above about name mangling.
codefu 2011/12/07 21:44:54 Done and updated in all the other locations.
} else {
// 0) Save off the original name
@@ -2988,16 +3029,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.
@@ -3021,8 +3074,9 @@ 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;
@@ -3549,6 +3603,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;
}
@@ -3634,21 +3697,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) {
@@ -3659,7 +3724,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