Index: frog/leg/emitter.dart |
=================================================================== |
--- frog/leg/emitter.dart (revision 5925) |
+++ frog/leg/emitter.dart (working copy) |
@@ -1,728 +0,0 @@ |
-// Copyright (c) 2012, 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. |
- |
-/** |
- * A function element that represents a closure call. The signature is copied |
- * from the given element. |
- */ |
-class ClosureInvocationElement extends FunctionElement { |
- ClosureInvocationElement(SourceString name, |
- FunctionElement other) |
- : super.from(name, other, other.enclosingElement); |
- |
- isInstanceMember() => true; |
-} |
- |
-/** |
- * Generates the code for all used classes in the program. Static fields (even |
- * in classes) are ignored, since they can be treated as non-class elements. |
- * |
- * The code for the containing (used) methods must exist in the [:universe:]. |
- */ |
-class CodeEmitterTask extends CompilerTask { |
- static final String INHERIT_FUNCTION = ''' |
-function(child, parent) { |
- if (child.prototype.__proto__) { |
- child.prototype.__proto__ = parent.prototype; |
- } else { |
- function tmp() {}; |
- tmp.prototype = parent.prototype; |
- child.prototype = new tmp(); |
- child.prototype.constructor = child; |
- } |
-}'''; |
- |
- bool addedInheritFunction = false; |
- final Namer namer; |
- final NativeEmitter nativeEmitter; |
- Set<ClassElement> generatedClasses; |
- StringBuffer mainBuffer; |
- |
- CodeEmitterTask(Compiler compiler) |
- : namer = compiler.namer, |
- nativeEmitter = new NativeEmitter(compiler), |
- generatedClasses = new Set<ClassElement>(), |
- mainBuffer = new StringBuffer(), |
- super(compiler); |
- |
- String get name() => 'CodeEmitter'; |
- |
- String get inheritsName() => '${namer.ISOLATE}.\$inherits'; |
- |
- String get objectClassName() { |
- ClassElement objectClass = |
- compiler.coreLibrary.find(const SourceString('Object')); |
- return namer.isolatePropertyAccess(objectClass); |
- } |
- |
- void addInheritFunctionIfNecessary() { |
- if (addedInheritFunction) return; |
- addedInheritFunction = true; |
- mainBuffer.add('$inheritsName = '); |
- mainBuffer.add(INHERIT_FUNCTION); |
- mainBuffer.add(';\n'); |
- } |
- |
- void addParameterStub(FunctionElement member, |
- String attachTo(String invocationName), |
- StringBuffer buffer, |
- Selector selector, |
- bool isNative) { |
- FunctionParameters parameters = member.computeParameters(compiler); |
- int positionalArgumentCount = selector.positionalArgumentCount; |
- if (positionalArgumentCount == parameters.parameterCount) { |
- assert(selector.namedArgumentCount == 0); |
- return; |
- } |
- ConstantHandler handler = compiler.constantHandler; |
- List<SourceString> names = selector.getOrderedNamedArguments(); |
- |
- String invocationName = |
- namer.instanceMethodInvocationName(member.getLibrary(), member.name, |
- selector); |
- buffer.add('${attachTo(invocationName)} = function('); |
- |
- // The parameters that this stub takes. |
- List<String> parametersBuffer = new List<String>(selector.argumentCount); |
- // The arguments that will be passed to the real method. |
- List<String> argumentsBuffer = new List<String>(parameters.parameterCount); |
- |
- // We fill the lists depending on the selector. For example, |
- // take method foo: |
- // foo(a, b, [c, d]); |
- // |
- // We may have multiple ways of calling foo: |
- // (1) foo(1, 2, 3, 4) |
- // (2) foo(1, 2); |
- // (3) foo(1, 2, 3); |
- // (4) foo(1, 2, c: 3); |
- // (5) foo(1, 2, d: 4); |
- // (6) foo(1, 2, c: 3, d: 4); |
- // (7) foo(1, 2, d: 4, c: 3); |
- // |
- // What we generate at the call sites are: |
- // (1) foo$4(1, 2, 3, 4) |
- // (2) foo$2(1, 2); |
- // (3) foo$3(1, 2, 3); |
- // (4) foo$3$c(1, 2, 3); |
- // (5) foo$3$d(1, 2, 4); |
- // (6) foo$4$c$d(1, 2, 3, 4); |
- // (7) foo$4$c$d(1, 2, 3, 4); |
- // |
- // The stubs we generate are (expressed in Dart): |
- // (1) No stub generated, call is direct. |
- // (2) foo$2(a, b) => foo$4(a, b, null, null) |
- // (3) foo$3(a, b, c) => foo$4(a, b, c, null) |
- // (4) foo$3$c(a, b, c) => foo$4(a, b, c, null); |
- // (5) foo$3$d(a, b, d) => foo$4(a, b, null, d); |
- // (6) foo$4$c$d(a, b, c, d) => foo$4(a, b, c, d); |
- // (7) Same as (5). |
- // |
- // We need to generate a stub for (5) because the order of the |
- // stub arguments and the real method may be different. |
- |
- int count = 0; |
- int indexOfLastOptionalArgumentInParameters = positionalArgumentCount - 1; |
- parameters.forEachParameter((Element element) { |
- String jsName = JsNames.getValid(element.name.slowToString()); |
- if (count < positionalArgumentCount) { |
- parametersBuffer[count] = jsName; |
- argumentsBuffer[count] = jsName; |
- } else { |
- int index = names.indexOf(element.name); |
- if (index != -1) { |
- indexOfLastOptionalArgumentInParameters = count; |
- // The order of the named arguments is not the same as the |
- // one in the real method (which is in Dart source order). |
- argumentsBuffer[count] = jsName; |
- parametersBuffer[selector.positionalArgumentCount + index] = jsName; |
- } else { |
- Constant value = handler.initialVariableValues[element]; |
- if (value == null) { |
- argumentsBuffer[count] = '(void 0)'; |
- } else { |
- if (!value.isNull()) { |
- // If the value is the null constant, we should not pass it |
- // down to the native method. |
- indexOfLastOptionalArgumentInParameters = count; |
- } |
- argumentsBuffer[count] = |
- handler.writeJsCode(new StringBuffer(), value).toString(); |
- } |
- } |
- } |
- count++; |
- }); |
- String parametersString = Strings.join(parametersBuffer, ","); |
- buffer.add('$parametersString) {\n'); |
- |
- if (isNative) { |
- nativeEmitter.emitParameterStub( |
- member, invocationName, parametersString, argumentsBuffer, |
- indexOfLastOptionalArgumentInParameters); |
- } else { |
- String arguments = Strings.join(argumentsBuffer, ","); |
- buffer.add(' return this.${namer.getName(member)}($arguments)'); |
- } |
- buffer.add('\n};\n'); |
- } |
- |
- void addParameterStubs(FunctionElement member, |
- String attachTo(String invocationName), |
- StringBuffer buffer, |
- [bool isNative = false]) { |
- Set<Selector> selectors = compiler.universe.invokedNames[member.name]; |
- if (selectors == null) return; |
- FunctionParameters parameters = member.computeParameters(compiler); |
- for (Selector selector in selectors) { |
- if (!selector.applies(parameters)) continue; |
- addParameterStub(member, attachTo, buffer, selector, isNative); |
- } |
- } |
- |
- void addInstanceMember(Element member, |
- String attachTo(String name), |
- StringBuffer buffer, |
- [bool isNative = false]) { |
- // TODO(floitsch): we don't need to deal with members of |
- // uninstantiated classes, that have been overwritten by subclasses. |
- |
- if (member.kind === ElementKind.FUNCTION |
- || member.kind === ElementKind.GENERATIVE_CONSTRUCTOR_BODY |
- || member.kind === ElementKind.GETTER |
- || member.kind === ElementKind.SETTER) { |
- if (member.modifiers !== null && member.modifiers.isAbstract()) return; |
- String codeBlock = compiler.universe.generatedCode[member]; |
- if (codeBlock == null) return; |
- buffer.add('${attachTo(namer.getName(member))} = $codeBlock;\n'); |
- codeBlock = compiler.universe.generatedBailoutCode[member]; |
- if (codeBlock !== null) { |
- String name = compiler.namer.getBailoutName(member); |
- buffer.add('${attachTo(name)} = $codeBlock;\n'); |
- } |
- FunctionElement function = member; |
- FunctionParameters parameters = function.computeParameters(compiler); |
- if (!parameters.optionalParameters.isEmpty()) { |
- addParameterStubs(member, attachTo, buffer, isNative: isNative); |
- } |
- } else if (member.kind === ElementKind.FIELD) { |
- // TODO(ngeoffray): Have another class generate the code for the |
- // fields. |
- if ((member.modifiers === null || !member.modifiers.isFinal()) && |
- compiler.universe.invokedSetters.contains(member.name)) { |
- String setterName = namer.setterName(member.getLibrary(), member.name); |
- String name = |
- isNative ? member.name.slowToString() : namer.getName(member); |
- buffer.add('${attachTo(setterName)} = function(v){\n'); |
- buffer.add(' this.$name = v;\n};\n'); |
- } |
- if (compiler.universe.invokedGetters.contains(member.name)) { |
- String getterName = namer.getterName(member.getLibrary(), member.name); |
- String name = |
- isNative ? member.name.slowToString() : namer.getName(member); |
- buffer.add('${attachTo(getterName)} = function(){\n'); |
- buffer.add(' return this.$name;\n};\n'); |
- } |
- } else { |
- compiler.internalError('unexpected kind: "${member.kind}"', |
- element: member); |
- } |
- emitExtraAccessors(member, attachTo, buffer); |
- } |
- |
- bool generateFieldInits(ClassElement classElement, |
- StringBuffer argumentsBuffer, |
- StringBuffer bodyBuffer) { |
- bool isFirst = true; |
- do { |
- // TODO(floitsch): make sure there are no name clashes. |
- String className = namer.getName(classElement); |
- |
- void generateFieldInit(Element member) { |
- if (member.isInstanceMember() && member.kind == ElementKind.FIELD) { |
- if (!isFirst) argumentsBuffer.add(', '); |
- isFirst = false; |
- String memberName = namer.instanceFieldName(member.getLibrary(), |
- member.name); |
- argumentsBuffer.add('${className}_$memberName'); |
- bodyBuffer.add(' this.$memberName = ${className}_$memberName;\n'); |
- } |
- } |
- |
- for (Element element in classElement.members) { |
- generateFieldInit(element); |
- } |
- for (Element element in classElement.backendMembers) { |
- generateFieldInit(element); |
- } |
- |
- classElement = classElement.superclass; |
- } while(classElement !== null); |
- } |
- |
- void emitInherits(ClassElement cls, StringBuffer buffer) { |
- ClassElement superclass = cls.superclass; |
- if (superclass !== null) { |
- addInheritFunctionIfNecessary(); |
- String className = namer.isolatePropertyAccess(cls); |
- String superName = namer.isolatePropertyAccess(superclass); |
- buffer.add('${inheritsName}($className, $superName);\n'); |
- } |
- } |
- |
- void ensureGenerated(ClassElement classElement, StringBuffer buffer) { |
- if (classElement == null) return; |
- if (generatedClasses.contains(classElement)) return; |
- generatedClasses.add(classElement); |
- generateClass(classElement, buffer); |
- } |
- |
- void generateClass(ClassElement classElement, StringBuffer buffer) { |
- ensureGenerated(classElement.superclass, buffer); |
- |
- if (classElement.isNative()) { |
- nativeEmitter.generateNativeClass(classElement); |
- return; |
- } else { |
- // TODO(ngeoffray): Instead of switching between buffer, we |
- // should create code sections, and decide where to emit them at |
- // the end. |
- buffer = mainBuffer; |
- } |
- |
- String className = namer.isolatePropertyAccess(classElement); |
- String constructorName = namer.safeName(classElement.name.slowToString()); |
- buffer.add('$className = function $constructorName('); |
- StringBuffer bodyBuffer = new StringBuffer(); |
- // If the class is never instantiated we still need to set it up for |
- // inheritance purposes, but we can leave its JavaScript constructor empty. |
- if (compiler.universe.instantiatedClasses.contains(classElement)) { |
- generateFieldInits(classElement, buffer, bodyBuffer); |
- } |
- buffer.add(') {\n'); |
- buffer.add(bodyBuffer); |
- buffer.add('};\n'); |
- |
- emitInherits(classElement, buffer); |
- |
- String attachTo(String name) => '$className.prototype.$name'; |
- for (Element member in classElement.members) { |
- if (member.isInstanceMember()) { |
- addInstanceMember(member, attachTo, buffer); |
- } |
- } |
- for (Element member in classElement.backendMembers) { |
- if (member.isInstanceMember()) { |
- addInstanceMember(member, attachTo, buffer); |
- } |
- } |
- generateTypeTests(classElement, (Element other) { |
- buffer.add('${attachTo(namer.operatorIs(other))} = '); |
- if (nativeEmitter.requiresNativeIsCheck(other)) { |
- buffer.add('function() { return true; }'); |
- } else { |
- buffer.add('true'); |
- } |
- buffer.add(';\n'); |
- }); |
- |
- if (classElement === compiler.objectClass && compiler.enabledNoSuchMethod) { |
- // Emit the noSuchMethods on the Object prototype now, so that |
- // the code in the dynamicMethod can find them. Note that the |
- // code in dynamicMethod is invoked before analyzing the full JS |
- // script. |
- emitNoSuchMethodCalls(buffer); |
- } |
- } |
- |
- void generateTypeTests(ClassElement cls, |
- void generateTypeTest(ClassElement element)) { |
- if (compiler.universe.isChecks.contains(cls)) { |
- generateTypeTest(cls); |
- } |
- generateInterfacesIsTests(cls, generateTypeTest, new Set<Element>()); |
- } |
- |
- void generateInterfacesIsTests(ClassElement cls, |
- void generateTypeTest(ClassElement element), |
- Set<Element> alreadyGenerated) { |
- for (Type interfaceType in cls.interfaces) { |
- Element element = interfaceType.element; |
- if (!alreadyGenerated.contains(element) && |
- compiler.universe.isChecks.contains(element)) { |
- alreadyGenerated.add(element); |
- generateTypeTest(element); |
- } |
- generateInterfacesIsTests(element, generateTypeTest, alreadyGenerated); |
- } |
- } |
- |
- void emitClasses(StringBuffer buffer) { |
- for (ClassElement element in compiler.universe.instantiatedClasses) { |
- ensureGenerated(element, buffer); |
- } |
- } |
- |
- void emitStaticFunctionsWithNamer(StringBuffer buffer, |
- Map<Element, String> generatedCode, |
- String functionNamer(Element element)) { |
- generatedCode.forEach((Element element, String codeBlock) { |
- if (!element.isInstanceMember()) { |
- buffer.add('${functionNamer(element)} = '); |
- buffer.add(codeBlock); |
- buffer.add(';\n\n'); |
- } |
- }); |
- } |
- |
- void emitStaticFunctions(StringBuffer buffer) { |
- emitStaticFunctionsWithNamer(buffer, |
- compiler.universe.generatedCode, |
- namer.isolatePropertyAccess); |
- emitStaticFunctionsWithNamer(buffer, |
- compiler.universe.generatedBailoutCode, |
- namer.isolateBailoutPropertyAccess); |
- } |
- |
- void emitStaticFunctionGetters(StringBuffer buffer) { |
- Set<FunctionElement> functionsNeedingGetter = |
- compiler.universe.staticFunctionsNeedingGetter; |
- for (FunctionElement element in functionsNeedingGetter) { |
- // The static function does not have the correct name. Since |
- // [addParameterStubs] use the name to create its stubs we simply |
- // create a fake element with the correct name. |
- // Note: the callElement will not have any enclosingElement. |
- FunctionElement callElement = |
- new ClosureInvocationElement(Namer.CLOSURE_INVOCATION_NAME, element); |
- String staticName = namer.isolatePropertyAccess(element); |
- int parameterCount = element.parameterCount(compiler); |
- String invocationName = |
- namer.instanceMethodName(element.getLibrary(), callElement.name, |
- parameterCount); |
- buffer.add("$staticName.$invocationName = $staticName;\n"); |
- addParameterStubs(callElement, (name) => '$staticName.$name', buffer); |
- } |
- } |
- |
- void emitDynamicFunctionGetter(StringBuffer buffer, |
- String attachTo(String invocationName), |
- FunctionElement member) { |
- // For every method that has the same name as a property-get we create a |
- // getter that returns a bound closure. Say we have a class 'A' with method |
- // 'foo' and somewhere in the code there is a dynamic property get of |
- // 'foo'. Then we generate the following code (in pseudo Dart): |
- // |
- // class A { |
- // foo(x, y, z) { ... } // Original function. |
- // get foo() { return new BoundClosure499(this); } |
- // } |
- // class BoundClosure499 extends Closure { |
- // var self; |
- // BoundClosure499(this.self); |
- // $call3(x, y, z) { return self.foo(x, y, z); } |
- // } |
- |
- // TODO(floitsch): share the closure classes with other classes |
- // if they share methods with the same signature. |
- |
- // The closure class. |
- SourceString name = const SourceString("BoundClosure"); |
- ClassElement closureClassElement = |
- new ClosureClassElement(compiler, member.getCompilationUnit()); |
- String isolateAccess = namer.isolatePropertyAccess(closureClassElement); |
- ensureGenerated(closureClassElement.superclass, buffer); |
- |
- // Define the constructor with a name so that Object.toString can |
- // find the class name of the closure class. |
- buffer.add("$isolateAccess = function $name(self) "); |
- buffer.add("{ this.self = self; };\n"); |
- emitInherits(closureClassElement, buffer); |
- |
- String prototype = "$isolateAccess.prototype"; |
- |
- // Now add the methods on the closure class. The instance method does not |
- // have the correct name. Since [addParameterStubs] use the name to create |
- // its stubs we simply create a fake element with the correct name. |
- // Note: the callElement will not have any enclosingElement. |
- FunctionElement callElement = |
- new ClosureInvocationElement(Namer.CLOSURE_INVOCATION_NAME, member); |
- |
- int parameterCount = member.parameterCount(compiler); |
- String invocationName = |
- namer.instanceMethodName(member.getLibrary(), |
- callElement.name, parameterCount); |
- String targetName = namer.instanceMethodName(member.getLibrary(), |
- member.name, parameterCount); |
- List<String> arguments = new List<String>(parameterCount); |
- for (int i = 0; i < parameterCount; i++) { |
- arguments[i] = "arg$i"; |
- } |
- String joinedArgs = Strings.join(arguments, ", "); |
- buffer.add("$prototype.$invocationName = function($joinedArgs) {\n"); |
- buffer.add(" return this.self.$targetName($joinedArgs);\n"); |
- buffer.add("};\n"); |
- addParameterStubs(callElement, |
- (invocationName) => '$prototype.$invocationName', |
- buffer); |
- |
- // And finally the getter. |
- String getterName = namer.getterName(member.getLibrary(), member.name); |
- String closureClass = namer.isolateAccess(closureClassElement); |
- buffer.add("${attachTo(getterName)} = function() {\n"); |
- buffer.add(" return new $closureClass(this);\n"); |
- buffer.add("};\n"); |
- } |
- |
- void emitCallStubForGetter(StringBuffer buffer, |
- String attachTo(String name), |
- Element member, |
- Set<Selector> selectors) { |
- String getter; |
- if (member.kind == ElementKind.GETTER) { |
- getter = "this.${namer.getterName(member.getLibrary(), member.name)}()"; |
- } else { |
- getter = |
- "this.${namer.instanceFieldName(member.getLibrary(), member.name)}"; |
- } |
- for (Selector selector in selectors) { |
- String invocationName = |
- namer.instanceMethodInvocationName(member.getLibrary(), member.name, |
- selector); |
- SourceString callName = Namer.CLOSURE_INVOCATION_NAME; |
- String closureCallName = |
- namer.instanceMethodInvocationName(member.getLibrary(), callName, |
- selector); |
- List<String> arguments = <String>[]; |
- for (int i = 0; i < selector.argumentCount; i++) { |
- arguments.add("arg$i"); |
- } |
- String joined = Strings.join(arguments, ", "); |
- buffer.add("${attachTo(invocationName)} = function($joined) {\n"); |
- buffer.add(" return $getter.$closureCallName($joined);\n"); |
- buffer.add("};\n"); |
- } |
- } |
- |
- void emitStaticNonFinalFieldInitializations(StringBuffer buffer) { |
- // Adds initializations inside the Isolate constructor. |
- // Example: |
- // function Isolate() { |
- // this.staticNonFinal = Isolate.prototype.someVal; |
- // ... |
- // } |
- ConstantHandler handler = compiler.constantHandler; |
- List<VariableElement> staticNonFinalFields = |
- handler.getStaticNonFinalFieldsForEmission(); |
- if (!staticNonFinalFields.isEmpty()) buffer.add('\n'); |
- for (Element element in staticNonFinalFields) { |
- buffer.add(' this.${namer.getName(element)} = '); |
- compiler.withCurrentElement(element, () { |
- handler.writeJsCodeForVariable(buffer, element); |
- }); |
- buffer.add(';\n'); |
- } |
- } |
- |
- void emitCompileTimeConstants(StringBuffer buffer) { |
- ConstantHandler handler = compiler.constantHandler; |
- List<Constant> constants = handler.getConstantsForEmission(); |
- String prototype = "${namer.ISOLATE}.prototype"; |
- bool addedMakeConstantList = false; |
- for (Constant constant in constants) { |
- if (!addedMakeConstantList && constant.isList()) { |
- addedMakeConstantList = true; |
- emitMakeConstantList(prototype, buffer); |
- } |
- String name = handler.getNameForConstant(constant); |
- buffer.add('$prototype.$name = '); |
- handler.writeJsCode(buffer, constant); |
- buffer.add(';\n'); |
- } |
- } |
- |
- void emitMakeConstantList(String prototype, StringBuffer buffer) { |
- buffer.add(prototype); |
- buffer.add(@'''.makeConstantList = function(list) { |
- list.immutable$list = true; |
- list.fixed$length = true; |
- return list; |
-}; |
-'''); |
- } |
- |
- void emitStaticFinalFieldInitializations(StringBuffer buffer) { |
- ConstantHandler handler = compiler.constantHandler; |
- List<VariableElement> staticFinalFields = |
- handler.getStaticFinalFieldsForEmission(); |
- for (VariableElement element in staticFinalFields) { |
- buffer.add('${namer.isolatePropertyAccess(element)} = '); |
- compiler.withCurrentElement(element, () { |
- handler.writeJsCodeForVariable(buffer, element); |
- }); |
- buffer.add(';\n'); |
- } |
- } |
- |
- void emitExtraAccessors(Element member, |
- String attachTo(String name), |
- StringBuffer buffer) { |
- if (member.kind == ElementKind.GETTER || member.kind == ElementKind.FIELD) { |
- Set<Selector> selectors = compiler.universe.invokedNames[member.name]; |
- if (selectors !== null && !selectors.isEmpty()) { |
- compiler.emitter.emitCallStubForGetter( |
- buffer, attachTo, member, selectors); |
- } |
- } else if (member.kind == ElementKind.FUNCTION) { |
- if (compiler.universe.invokedGetters.contains(member.name)) { |
- compiler.emitter.emitDynamicFunctionGetter( |
- buffer, attachTo, member); |
- } |
- } |
- } |
- |
- void emitNoSuchMethodCalls(StringBuffer buffer) { |
- // Do not generate no such method calls if there is no class. |
- if (compiler.universe.instantiatedClasses.isEmpty()) return; |
- |
- ClassElement objectClass = |
- compiler.coreLibrary.find(const SourceString('Object')); |
- String className = namer.isolatePropertyAccess(objectClass); |
- String prototype = '$className.prototype'; |
- String noSuchMethodName = |
- namer.instanceMethodName(null, Compiler.NO_SUCH_METHOD, 2); |
- Collection<LibraryElement> libraries = |
- compiler.universe.libraries.getValues(); |
- |
- void generateMethod(String methodName, String jsName, Selector selector) { |
- buffer.add('$prototype.$jsName = function'); |
- StringBuffer args = new StringBuffer(); |
- for (int i = 0; i < selector.argumentCount; i++) { |
- if (i != 0) args.add(', '); |
- args.add('arg$i'); |
- } |
- // We need to check if the object has a noSuchMethod. If not, it |
- // means the object is a native object, and we can just call our |
- // generic noSuchMethod. Note that when calling this method, the |
- // 'this' object is not a Dart object. |
- buffer.add(' ($args) {\n'); |
- buffer.add(' return this.$noSuchMethodName\n'); |
- buffer.add(" ? this.$noSuchMethodName('$methodName', [$args])\n"); |
- buffer.add(" : $objectClassName.prototype.$noSuchMethodName.call("); |
- buffer.add("this, '$methodName', [$args])\n"); |
- buffer.add('}\n'); |
- } |
- |
- compiler.universe.invokedNames.forEach((SourceString methodName, |
- Set<Selector> selectors) { |
- if (objectClass.lookupLocalMember(methodName) === null |
- && methodName != Namer.OPERATOR_EQUALS) { |
- for (Selector selector in selectors) { |
- if (methodName.isPrivate()) { |
- for (LibraryElement lib in libraries) { |
- String jsName = |
- namer.instanceMethodInvocationName(lib, methodName, selector); |
- generateMethod(methodName.slowToString(), jsName, selector); |
- } |
- } else { |
- String jsName = |
- namer.instanceMethodInvocationName(null, methodName, selector); |
- generateMethod(methodName.slowToString(), jsName, selector); |
- } |
- } |
- } |
- }); |
- |
- compiler.universe.invokedGetters.forEach((SourceString getterName) { |
- if (getterName.isPrivate()) { |
- for (LibraryElement lib in libraries) { |
- String jsName = namer.getterName(lib, getterName); |
- generateMethod('get ${getterName.slowToString()}', jsName, |
- Selector.GETTER); |
- } |
- } else { |
- String jsName = namer.getterName(null, getterName); |
- generateMethod('get ${getterName.slowToString()}', jsName, |
- Selector.GETTER); |
- } |
- }); |
- |
- compiler.universe.invokedSetters.forEach((SourceString setterName) { |
- if (setterName.isPrivate()) { |
- for (LibraryElement lib in libraries) { |
- String jsName = namer.setterName(lib, setterName); |
- generateMethod('set ${setterName.slowToString()}', jsName, |
- Selector.SETTER); |
- } |
- } else { |
- String jsName = namer.setterName(null, setterName); |
- generateMethod('set ${setterName.slowToString()}', jsName, |
- Selector.SETTER); |
- } |
- }); |
- } |
- |
- String buildIsolateSetup(Element appMain, Element isolateMain) { |
- String mainAccess = "${namer.isolateAccess(appMain)}"; |
- String currentIsolate = "${namer.CURRENT_ISOLATE}"; |
- String mainEnsureGetter = ''; |
- // Since we pass the closurized version of the main method to |
- // the isolate method, we must make sure that it exists. |
- if (!compiler.universe.staticFunctionsNeedingGetter.contains(appMain)) { |
- String invocationName = |
- "${namer.closureInvocationName(Selector.INVOCATION_0)}"; |
- mainEnsureGetter = "$mainAccess.$invocationName = $mainAccess"; |
- } |
- |
- // TODO(ngeoffray): These globals are currently required by the isolate |
- // library, but since leg already generates code on an Isolate object, they |
- // are not really needed. We should remove them once Leg replaces Frog. |
- return """ |
-var \$globalThis = $currentIsolate; |
-var \$globalState; |
-var \$globals; |
-function \$static_init(){}; |
- |
-function \$initGlobals(context) { |
- context.isolateStatics = new ${namer.ISOLATE}(); |
-} |
-function \$setGlobals(context) { |
- $currentIsolate = context.isolateStatics; |
- \$globalThis = $currentIsolate; |
-} |
-$mainEnsureGetter |
-${namer.isolateAccess(isolateMain)}($mainAccess);"""; |
- } |
- |
- emitMain(StringBuffer buffer) { |
- if (compiler.isMockCompilation) return; |
- Element main = compiler.mainApp.find(Compiler.MAIN); |
- if (compiler.isolateLibrary != null) { |
- Element isolateMain = |
- compiler.isolateLibrary.find(Compiler.START_ROOT_ISOLATE); |
- buffer.add(buildIsolateSetup(main, isolateMain)); |
- } else { |
- buffer.add('${namer.isolateAccess(main)}();\n'); |
- } |
- } |
- |
- String assembleProgram() { |
- measure(() { |
- mainBuffer.add('function ${namer.ISOLATE}() {'); |
- emitStaticNonFinalFieldInitializations(mainBuffer); |
- mainBuffer.add('}\n\n'); |
- emitClasses(mainBuffer); |
- emitStaticFunctions(mainBuffer); |
- emitStaticFunctionGetters(mainBuffer); |
- emitCompileTimeConstants(mainBuffer); |
- emitStaticFinalFieldInitializations(mainBuffer); |
- nativeEmitter.emitDynamicDispatchMetadata(); |
- mainBuffer.add( |
- 'var ${namer.CURRENT_ISOLATE} = new ${namer.ISOLATE}();\n'); |
- nativeEmitter.assembleCode(mainBuffer); |
- emitMain(mainBuffer); |
- compiler.assembledCode = mainBuffer.toString(); |
- }); |
- return compiler.assembledCode; |
- } |
-} |