| 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;
|
| - }
|
| -}
|
|
|