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

Unified Diff: pkg/compiler/lib/src/js_emitter/new_emitter/model_emitter.dart

Issue 1220333003: dart2js: Rename emitters. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 5 years, 5 months 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: pkg/compiler/lib/src/js_emitter/new_emitter/model_emitter.dart
diff --git a/pkg/compiler/lib/src/js_emitter/new_emitter/model_emitter.dart b/pkg/compiler/lib/src/js_emitter/new_emitter/model_emitter.dart
deleted file mode 100644
index 6a05e29f6d1782f59d45aeaa62af46b71baf7e92..0000000000000000000000000000000000000000
--- a/pkg/compiler/lib/src/js_emitter/new_emitter/model_emitter.dart
+++ /dev/null
@@ -1,1247 +0,0 @@
-// Copyright (c) 2014, 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.
-
-library dart2js.new_js_emitter.model_emitter;
-
-import '../../constants/values.dart' show ConstantValue, FunctionConstantValue;
-import '../../dart2jslib.dart' show Compiler;
-import '../../elements/elements.dart' show ClassElement, FunctionElement;
-import '../../js/js.dart' as js;
-import '../../js_backend/js_backend.dart' show
- JavaScriptBackend,
- Namer,
- ConstantEmitter;
-
-import '../js_emitter.dart' show AstContainer, NativeEmitter;
-
-import 'package:js_runtime/shared/embedded_names.dart' show
- CREATE_NEW_ISOLATE,
- DEFERRED_LIBRARY_URIS,
- DEFERRED_LIBRARY_HASHES,
- GET_TYPE_FROM_NAME,
- INITIALIZE_LOADED_HUNK,
- INTERCEPTORS_BY_TAG,
- IS_HUNK_INITIALIZED,
- IS_HUNK_LOADED,
- LEAF_TAGS,
- MANGLED_GLOBAL_NAMES,
- METADATA,
- TYPE_TO_INTERCEPTOR_MAP,
- TYPES;
-
-import '../js_emitter.dart' show NativeGenerator, buildTearOffCode;
-import '../model.dart';
-
-class ModelEmitter {
- final Compiler compiler;
- final Namer namer;
- ConstantEmitter constantEmitter;
- final NativeEmitter nativeEmitter;
-
- JavaScriptBackend get backend => compiler.backend;
-
- /// For deferred loading we communicate the initializers via this global var.
- static const String deferredInitializersGlobal =
- r"$__dart_deferred_initializers__";
-
- static const String deferredExtension = "part.js";
-
- static const String typeNameProperty = r"builtin$cls";
-
- ModelEmitter(Compiler compiler, Namer namer, this.nativeEmitter)
- : this.compiler = compiler,
- this.namer = namer {
-
- this.constantEmitter = new ConstantEmitter(
- compiler, namer, this.generateConstantReference,
- constantListGenerator);
- }
-
- js.Expression constantListGenerator(js.Expression array) {
- // TODO(floitsch): remove hard-coded name.
- return js.js('makeConstList(#)', [array]);
- }
-
- js.Expression generateEmbeddedGlobalAccess(String global) {
- return js.js(generateEmbeddedGlobalAccessString(global));
- }
-
- String generateEmbeddedGlobalAccessString(String global) {
- // TODO(floitsch): don't use 'init' as global embedder storage.
- return 'init.$global';
- }
-
- bool isConstantInlinedOrAlreadyEmitted(ConstantValue constant) {
- if (constant.isFunction) return true; // Already emitted.
- if (constant.isPrimitive) return true; // Inlined.
- if (constant.isDummy) return true; // Inlined.
- // The name is null when the constant is already a JS constant.
- // TODO(floitsch): every constant should be registered, so that we can
- // share the ones that take up too much space (like some strings).
- if (namer.constantName(constant) == null) return true;
- return false;
- }
-
- // TODO(floitsch): copied from OldEmitter. Adjust or share.
- int compareConstants(ConstantValue a, ConstantValue b) {
- // Inlined constants don't affect the order and sometimes don't even have
- // names.
- int cmp1 = isConstantInlinedOrAlreadyEmitted(a) ? 0 : 1;
- int cmp2 = isConstantInlinedOrAlreadyEmitted(b) ? 0 : 1;
- if (cmp1 + cmp2 < 2) return cmp1 - cmp2;
-
- // Emit constant interceptors first. Constant interceptors for primitives
- // might be used by code that builds other constants. See Issue 18173.
- if (a.isInterceptor != b.isInterceptor) {
- return a.isInterceptor ? -1 : 1;
- }
-
- // Sorting by the long name clusters constants with the same constructor
- // which compresses a tiny bit better.
- int r = namer.constantLongName(a).compareTo(namer.constantLongName(b));
- if (r != 0) return r;
- // Resolve collisions in the long name by using the constant name (i.e. JS
- // name) which is unique.
- return namer.constantName(a).compareTo(namer.constantName(b));
- }
-
- js.Expression generateStaticClosureAccess(FunctionElement element) {
- return js.js('#.#()',
- [namer.globalObjectFor(element), namer.staticClosureName(element)]);
- }
-
- js.Expression generateConstantReference(ConstantValue value) {
- if (value.isFunction) {
- FunctionConstantValue functionConstant = value;
- return generateStaticClosureAccess(functionConstant.element);
- }
-
- // We are only interested in the "isInlined" part, but it does not hurt to
- // test for the other predicates.
- if (isConstantInlinedOrAlreadyEmitted(value)) {
- return constantEmitter.generate(value);
- }
- return js.js('#.#()', [namer.globalObjectForConstant(value),
- namer.constantName(value)]);
- }
-
- int emitProgram(Program program) {
- List<Fragment> fragments = program.fragments;
- MainFragment mainFragment = fragments.first;
-
- int totalSize = 0;
-
- // We have to emit the deferred fragments first, since we need their
- // deferred hash (which depends on the output) when emitting the main
- // fragment.
- List<js.Expression> fragmentsCode = fragments.skip(1).map(
- (DeferredFragment deferredUnit) {
- js.Expression types =
- program.metadataTypesForOutputUnit(deferredUnit.outputUnit);
- return emitDeferredFragment(types, deferredUnit, program.holders);
- }).toList();
-
- js.Statement mainAst = emitMainFragment(program);
-
- js.TokenCounter counter = new js.TokenCounter();
- fragmentsCode.forEach(counter.countTokens);
- counter.countTokens(mainAst);
-
- program.finalizers.forEach((js.TokenFinalizer f) => f.finalizeTokens());
-
- for (int i = 0; i < fragmentsCode.length; ++i) {
- String code = js.prettyPrint(fragmentsCode[i], compiler).getText();
- totalSize += code.length;
- compiler.outputProvider(fragments[i+1].outputFileName, deferredExtension)
- ..add(code)
- ..close();
- }
-
- String mainCode = js.prettyPrint(mainAst, compiler).getText();
- compiler.outputProvider(mainFragment.outputFileName, 'js')
- ..add(buildGeneratedBy(compiler))
- ..add(mainCode)
- ..close();
- totalSize += mainCode.length;
-
- return totalSize;
- }
-
- /// Returns a [js.Literal] that represents the string result of unparsing
- /// [value].
- ///
- /// The returned node will, when its string value is requested, pretty-print
- /// the given [value] and, if [protectForEval] is true, wrap the resulting
- /// string in parenthesis. The result is also escaped.
- ///
- /// See [_UnparsedNode] for details.
- js.Literal unparse(Compiler compiler, js.Node value,
- {bool protectForEval: true}) {
- return new js.UnparsedNode(value, compiler, protectForEval);
- }
-
- String buildGeneratedBy(compiler) {
- var suffix = '';
- if (compiler.hasBuildId) suffix = ' version: ${compiler.buildId}';
- return '// Generated by dart2js, the Dart to JavaScript compiler$suffix.\n';
- }
-
- js.Statement emitMainFragment(Program program) {
- MainFragment fragment = program.fragments.first;
- List<js.Expression> elements = fragment.libraries.map(emitLibrary).toList();
- elements.add(
- emitLazilyInitializedStatics(fragment.staticLazilyInitializedFields));
- elements.add(emitConstants(fragment.constants));
-
- js.Expression code = new js.ArrayInitializer(elements);
-
- Map<String, dynamic> holes =
- {'deferredInitializer': emitDeferredInitializerGlobal(program.loadMap),
- 'holders': emitHolders(program.holders),
- 'tearOff': buildTearOffCode(backend),
- 'parseFunctionDescriptor':
- js.js.statement(parseFunctionDescriptorBoilerplate,
- {'argumentCount': js.string(namer.requiredParameterField),
- 'defaultArgumentValues': js.string(namer.defaultValuesField),
- 'callName': js.string(namer.callNameField)}),
-
- 'cyclicThrow':
- backend.emitter.staticFunctionAccess(backend.getCyclicThrowHelper()),
- 'outputContainsConstantList': program.outputContainsConstantList,
- 'embeddedGlobals': emitEmbeddedGlobals(program),
- 'readMetadataTypeFunction': readMetadataTypeFunction,
- 'staticNonFinals':
- emitStaticNonFinalFields(fragment.staticNonFinalFields),
- 'operatorIsPrefix': js.string(namer.operatorIsPrefix),
- 'callName': js.string(namer.callNameField),
- 'argumentCount': js.string(namer.requiredParameterField),
- 'defaultArgumentValues': js.string(namer.defaultValuesField),
- 'eagerClasses': emitEagerClassInitializations(fragment.libraries),
- 'invokeMain': fragment.invokeMain,
- 'code': code};
-
- holes.addAll(nativeHoles(program));
-
- return js.js.statement(boilerplate, holes);
- }
-
- Map<String, dynamic> nativeHoles(Program program) {
- Map<String, dynamic> nativeHoles = <String, dynamic>{};
-
- js.Statement nativeIsolateAffinityTagInitialization;
- if (NativeGenerator.needsIsolateAffinityTagInitialization(backend)) {
- nativeIsolateAffinityTagInitialization =
- NativeGenerator.generateIsolateAffinityTagInitialization(
- backend,
- generateEmbeddedGlobalAccess,
- // TODO(floitsch): convertToFastObject.
- js.js("(function(x) { return x; })", []));
- } else {
- nativeIsolateAffinityTagInitialization = js.js.statement(";");
- }
- nativeHoles['nativeIsolateAffinityTagInitialization'] =
- nativeIsolateAffinityTagInitialization;
-
-
- js.Expression nativeInfoAccess = js.js('nativeInfo', []);
- js.Expression constructorAccess = js.js('constructor', []);
- Function subclassReadGenerator = (js.Expression subclass) {
- return js.js('holdersMap[#][#].ensureResolved()', [subclass, subclass]);
- };
- js.Expression interceptorsByTagAccess =
- generateEmbeddedGlobalAccess(INTERCEPTORS_BY_TAG);
- js.Expression leafTagsAccess =
- generateEmbeddedGlobalAccess(LEAF_TAGS);
- js.Statement nativeInfoHandler = NativeGenerator.buildNativeInfoHandler(
- nativeInfoAccess,
- constructorAccess,
- subclassReadGenerator,
- interceptorsByTagAccess,
- leafTagsAccess);
-
- nativeHoles['needsNativeSupport'] = program.needsNativeSupport;
- nativeHoles['needsNoNativeSupport'] = !program.needsNativeSupport;
- nativeHoles['nativeInfoHandler'] = nativeInfoHandler;
-
- return nativeHoles;
- }
-
- js.Block emitHolders(List<Holder> holders) {
- // The top-level variables for holders must *not* be renamed by the
- // JavaScript pretty printer because a lot of code already uses the
- // non-renamed names. The generated code looks like this:
- //
- // var H = {}, ..., G = {};
- // var holders = [ H, ..., G ];
- //
- // and it is inserted at the top of the top-level function expression
- // that covers the entire program.
-
- List<js.Statement> statements = [
- new js.ExpressionStatement(
- new js.VariableDeclarationList(holders.map((e) =>
- new js.VariableInitialization(
- new js.VariableDeclaration(e.name, allowRename: false),
- new js.ObjectInitializer(const []))).toList())),
- js.js.statement('var holders = #', new js.ArrayInitializer(
- holders.map((e) => new js.VariableUse(e.name))
- .toList(growable: false))),
- js.js.statement('var holdersMap = Object.create(null)')
- ];
- return new js.Block(statements);
- }
-
- js.Block emitEmbeddedGlobals(Program program) {
- List<js.Property> globals = <js.Property>[];
-
- if (program.loadMap.isNotEmpty) {
- globals.addAll(emitEmbeddedGlobalsForDeferredLoading(program.loadMap));
- }
-
- if (program.typeToInterceptorMap != null) {
- globals.add(new js.Property(js.string(TYPE_TO_INTERCEPTOR_MAP),
- program.typeToInterceptorMap));
- }
-
- if (program.hasIsolateSupport) {
- String isolateName = namer.currentIsolate;
- globals.add(
- new js.Property(js.string(CREATE_NEW_ISOLATE),
- js.js('function () { return $isolateName; }')));
- // TODO(floitsch): add remaining isolate functions.
- }
-
- globals.add(emitMangledGlobalNames());
-
- globals.add(emitGetTypeFromName());
-
- globals.addAll(emitMetadata(program));
-
- if (program.needsNativeSupport) {
- globals.add(new js.Property(js.string(INTERCEPTORS_BY_TAG),
- js.js('Object.create(null)', [])));
- globals.add(new js.Property(js.string(LEAF_TAGS),
- js.js('Object.create(null)', [])));
- }
-
- js.ObjectInitializer globalsObject = new js.ObjectInitializer(globals);
-
- List<js.Statement> statements =
- [new js.ExpressionStatement(
- new js.VariableDeclarationList(
- [new js.VariableInitialization(
- new js.VariableDeclaration("init", allowRename: false),
- globalsObject)]))];
- return new js.Block(statements);
- }
-
- js.Property emitMangledGlobalNames() {
- List<js.Property> names = <js.Property>[];
-
- // We want to keep the original names for the most common core classes when
- // calling toString on them.
- List<ClassElement> nativeClassesNeedingUnmangledName =
- [compiler.intClass, compiler.doubleClass, compiler.numClass,
- compiler.stringClass, compiler.boolClass, compiler.nullClass,
- compiler.listClass];
- nativeClassesNeedingUnmangledName.forEach((element) {
- names.add(new js.Property(js.quoteName(namer.className(element)),
- js.string(element.name)));
- });
-
- return new js.Property(js.string(MANGLED_GLOBAL_NAMES),
- new js.ObjectInitializer(names));
- }
-
- js.Statement emitDeferredInitializerGlobal(Map loadMap) {
- if (loadMap.isEmpty) return new js.Block.empty();
-
- return js.js.statement("""
- if (typeof($deferredInitializersGlobal) === 'undefined')
- var $deferredInitializersGlobal = Object.create(null);""");
- }
-
- Iterable<js.Property> emitEmbeddedGlobalsForDeferredLoading(
- Map<String, List<Fragment>> loadMap) {
-
- List<js.Property> globals = <js.Property>[];
-
- js.ArrayInitializer fragmentUris(List<Fragment> fragments) {
- return js.stringArray(fragments.map((DeferredFragment fragment) =>
- "${fragment.outputFileName}.$deferredExtension"));
- }
- js.ArrayInitializer fragmentHashes(List<Fragment> fragments) {
- // TODO(floitsch): the hash must depend on the generated code.
- return js.numArray(
- fragments.map((DeferredFragment fragment) => fragment.hashCode));
- }
-
- List<js.Property> uris = new List<js.Property>(loadMap.length);
- List<js.Property> hashes = new List<js.Property>(loadMap.length);
- int count = 0;
- loadMap.forEach((String loadId, List<Fragment> fragmentList) {
- uris[count] =
- new js.Property(js.string(loadId), fragmentUris(fragmentList));
- hashes[count] =
- new js.Property(js.string(loadId), fragmentHashes(fragmentList));
- count++;
- });
-
- globals.add(new js.Property(js.string(DEFERRED_LIBRARY_URIS),
- new js.ObjectInitializer(uris)));
- globals.add(new js.Property(js.string(DEFERRED_LIBRARY_HASHES),
- new js.ObjectInitializer(hashes)));
-
- js.Expression isHunkLoadedFunction =
- js.js("function(hash) { return !!$deferredInitializersGlobal[hash]; }");
- globals.add(new js.Property(js.string(IS_HUNK_LOADED),
- isHunkLoadedFunction));
-
- js.Expression isHunkInitializedFunction =
- js.js("function(hash) { return false; }");
- globals.add(new js.Property(js.string(IS_HUNK_INITIALIZED),
- isHunkInitializedFunction));
-
- js.Expression typesAccess = generateEmbeddedGlobalAccess(TYPES);
-
- /// See [emitEmbeddedGlobalsForDeferredLoading] for the format of the
- /// deferred hunk.
- js.Expression initializeLoadedHunkFunction =
- js.js("""
- function(hash) {
- var hunk = $deferredInitializersGlobal[hash];
- $setupProgramName(hunk[0], #typesAccess.length);
- eval(hunk[1]);
- var deferredTypes = eval(hunk[2]);
- #typesAccess.push.apply(#typesAccess, deferredTypes);
- }""", {'typesAccess': typesAccess});
-
- globals.add(new js.Property(js.string(INITIALIZE_LOADED_HUNK),
- initializeLoadedHunkFunction));
-
- return globals;
- }
-
- js.Property emitGetTypeFromName() {
- js.Expression function =
- js.js( """function(name) {
- return holdersMap[name][name].ensureResolved();
- }""");
- return new js.Property(js.string(GET_TYPE_FROM_NAME), function);
- }
-
- static final String readMetadataTypeName = "readMetadataType";
-
- js.Statement get readMetadataTypeFunction {
- // Types are non-evaluated and must be compiled at first use.
- // Compiled strings are guaranteed not to be strings, and it's thus safe
- // to use a type-test to determine if a type has already been compiled.
- return js.js.statement('''function $readMetadataTypeName(index) {
- var type = #typesAccess[index];
- if (typeof type == 'string') {
- type = expressionCompile(type);
- #typesAccess[index] = type;
- }
- return type;
- }''', {"typesAccess": generateEmbeddedGlobalAccess(TYPES)});
- }
-
- js.Template get templateForReadType {
- // TODO(floitsch): make sure that no local variable shadows the access to
- // the readMetadataType function.
- return js.js.expressionTemplateFor('$readMetadataTypeName(#)');
- }
-
- static final String readMetadataName = "readLazyMetadata";
- static final String lazyMetadataName = "lazy_$METADATA";
-
- js.Statement get readMetadataFunction {
- // Types are non-evaluated and must be compiled at first use.
- // Compiled strings are guaranteed not to be strings, and it's thus safe
- // to use a type-test to determine if a type has already been compiled.
- return js.js.statement('''function $readMetadataName(index) {
- var lazyMetadata = #lazyMetadataAccess[index];
- if (typeof lazyMetadata == 'string') {
- #metadataAccess[index] = expressionCompile(lazyMetadata);
- #lazyMetadataAccess[index] = null;
- }
- return #metadataAccess[index];
- }''', {
- "lazyMetadataAccess": generateEmbeddedGlobalAccess(lazyMetadataName),
- "metadataAccess": generateEmbeddedGlobalAccess(METADATA)
- });
- }
-
- js.Template get templateForReadMetadata {
- // TODO(floitsch): make sure that no local variable shadows the access to
- // the readMetadata function.
- return js.js.expressionTemplateFor('$readMetadataName(#)');
- }
-
- List<js.Property> emitMetadata(Program program) {
- List<js.Property> metadataGlobals = <js.Property>[];
-
- js.Property createGlobal(js.Expression metadata, String global) {
- return new js.Property(js.string(global), metadata);
- }
-
- metadataGlobals.add(createGlobal(program.metadata, METADATA));
- js.Expression types =
- program.metadataTypesForOutputUnit(program.mainFragment.outputUnit);
- metadataGlobals.add(createGlobal(types, TYPES));
-
- return metadataGlobals;
- }
-
- js.Expression emitDeferredFragment(js.Expression deferredTypes,
- DeferredFragment fragment,
- List<Holder> holders) {
- // TODO(floitsch): initialize eager classes.
- // TODO(floitsch): the hash must depend on the output.
- int hash = fragment.hashCode;
-
- List<js.Expression> deferredCode =
- fragment.libraries.map(emitLibrary).toList();
-
- deferredCode.add(
- emitLazilyInitializedStatics(fragment.staticLazilyInitializedFields));
- deferredCode.add(emitConstants(fragment.constants));
-
- js.ArrayInitializer deferredArray = new js.ArrayInitializer(deferredCode);
-
- // This is the code that must be evaluated after all deferred classes have
- // been setup.
- js.Statement immediateCode = new js.Block([
- emitStaticNonFinalFields(fragment.staticNonFinalFields),
- emitEagerClassInitializations(fragment.libraries)]);
-
-
- js.Literal immediateString = unparse(compiler, immediateCode);
-
- js.ArrayInitializer hunk =
- new js.ArrayInitializer([deferredArray, immediateString,
- deferredTypes]);
-
- return js.js("$deferredInitializersGlobal[$hash] = #", hunk);
- }
-
- // This string should be referenced wherever JavaScript code makes assumptions
- // on the constants format.
- static final String constantsDescription =
- "The constants are encoded as a follows:"
- " [constantsHolderIndex, name, code, name2, code2, ...]."
- "The array is completely empty if there is no constant at all.";
-
- js.ArrayInitializer emitConstants(List<Constant> constants) {
- List<js.Expression> data = <js.Expression>[];
- if (constants.isNotEmpty) {
- int holderIndex = constants.first.holder.index;
- data.add(js.number(holderIndex));
- data.addAll(constants.expand((Constant constant) {
- assert(constant.holder.index == holderIndex);
- js.Expression code = constantEmitter.generate(constant.value);
- return [js.quoteName(constant.name), unparse(compiler, code)];
- }));
- }
- return new js.ArrayInitializer(data);
- }
-
- js.Block emitStaticNonFinalFields(List<StaticField> fields) {
- Iterable<js.Statement> statements = fields.map((StaticField field) {
- return js.js.statement("#.# = #;",
- [field.holder.name, field.name, field.code]);
- });
- return new js.Block(statements.toList());
- }
-
- js.Expression emitLazilyInitializedStatics(List<StaticField> fields) {
- Iterable fieldDescriptors = fields.expand((field) =>
- [ js.quoteName(field.name),
- js.quoteName(namer.deriveLazyInitializerName(field.name)),
- js.number(field.holder.index),
- emitLazyInitializer(field) ]);
- return new js.ArrayInitializer(fieldDescriptors.toList(growable: false));
- }
-
- js.Block emitEagerClassInitializations(List<Library> libraries) {
- js.Statement createInstantiation(Class cls) {
- return js.js.statement('new #.#()', [cls.holder.name, cls.name]);
- }
-
- List<js.Statement> instantiations =
- libraries.expand((Library library) => library.classes)
- .where((Class cls) => cls.isEager)
- .map(createInstantiation)
- .toList(growable: false);
- return new js.Block(instantiations);
- }
-
- // This string should be referenced wherever JavaScript code makes assumptions
- // on the mixin format.
- static final String nativeInfoDescription =
- "A class is encoded as follows:"
- " [name, class-code, holder-index], or "
- " [name, class-code, native-info, holder-index].";
-
- js.Expression emitLibrary(Library library) {
- Iterable staticDescriptors = library.statics.expand(emitStaticMethod);
-
- Iterable classDescriptors = library.classes.expand((Class cls) {
- js.Literal name = js.quoteName(cls.name);
- js.LiteralNumber holderIndex = js.number(cls.holder.index);
- js.Expression emittedClass = emitClass(cls);
- js.Expression nativeInfo = NativeGenerator.encodeNativeInfo(cls);
- if (nativeInfo == null) {
- return [name, emittedClass, holderIndex];
- } else {
- return [name, emittedClass, nativeInfo, holderIndex];
- }
- });
-
- js.Expression staticArray =
- new js.ArrayInitializer(staticDescriptors.toList(growable: false));
- js.Expression classArray =
- new js.ArrayInitializer(classDescriptors.toList(growable: false));
-
- return new js.ArrayInitializer([staticArray, classArray]);
- }
-
- js.Expression _generateConstructor(Class cls) {
- List<js.Name> fieldNames = const <js.Name>[];
-
- // If the class is not directly instantiated we only need it for inheritance
- // or RTI. In either case we don't need its fields.
- if (cls.isDirectlyInstantiated && !cls.isNative) {
- fieldNames = cls.fields.map((Field field) => field.name).toList();
- }
- js.Name name = cls.name;
-
- Iterable<js.Name> assignments = fieldNames.map((js.Name field) {
- return js.js("this.#field = #field", {"field": field});
- });
-
- return js.js('function #(#) { # }', [name, fieldNames, assignments]);
- }
-
- Method _generateGetter(Field field) {
- String getterTemplateFor(int flags) {
- switch (flags) {
- case 1: return "function() { return this[#]; }";
- case 2: return "function(receiver) { return receiver[#]; }";
- case 3: return "function(receiver) { return this[#]; }";
- }
- return null;
- }
-
- js.Expression fieldName = js.quoteName(field.name);
- js.Expression code = js.js(getterTemplateFor(field.getterFlags), fieldName);
- js.Name getterName = namer.deriveGetterName(field.accessorName);
- return new StubMethod(getterName, code);
- }
-
- Method _generateSetter(Field field) {
- String setterTemplateFor(int flags) {
- switch (flags) {
- case 1: return "function(val) { return this[#] = val; }";
- case 2: return "function(receiver, val) { return receiver[#] = val; }";
- case 3: return "function(receiver, val) { return this[#] = val; }";
- }
- return null;
- }
- js.Expression fieldName = js.quoteName(field.name);
- js.Expression code = js.js(setterTemplateFor(field.setterFlags), fieldName);
- js.Name setterName = namer.deriveSetterName(field.accessorName);
- return new StubMethod(setterName, code);
- }
-
- Iterable<Method> _generateGettersSetters(Class cls) {
- Iterable<Method> getters = cls.fields
- .where((Field field) => field.needsGetter)
- .map(_generateGetter);
-
- Iterable<Method> setters = cls.fields
- .where((Field field) => field.needsUncheckedSetter)
- .map(_generateSetter);
-
- return [getters, setters].expand((x) => x);
- }
-
- // This string should be referenced wherever JavaScript code makes assumptions
- // on the mixin format.
- static final String mixinFormatDescription =
- "Mixins have a reference to their mixin class at the place of the usual"
- "constructor. If they are instantiated the constructor follows the"
- "reference.";
-
- js.Expression emitClass(Class cls) {
- List elements = [js.quoteName(cls.superclassName, allowNull: true),
- js.number(cls.superclassHolderIndex)];
-
- if (cls.isMixinApplication) {
- MixinApplication mixin = cls;
- elements.add(js.quoteName(mixin.mixinClass.name));
- elements.add(js.number(mixin.mixinClass.holder.index));
- if (cls.isDirectlyInstantiated) {
- elements.add(_generateConstructor(cls));
- }
- } else {
- elements.add(_generateConstructor(cls));
- }
- Iterable<Method> methods = cls.methods;
- Iterable<Method> isChecks = cls.isChecks;
- Iterable<Method> callStubs = cls.callStubs;
- Iterable<Method> typeVariableReaderStubs = cls.typeVariableReaderStubs;
- Iterable<Method> noSuchMethodStubs = cls.noSuchMethodStubs;
- Iterable<Method> gettersSetters = _generateGettersSetters(cls);
- Iterable<Method> allMethods =
- [methods, isChecks, callStubs, typeVariableReaderStubs,
- noSuchMethodStubs, gettersSetters].expand((x) => x);
- elements.addAll(allMethods.expand(emitInstanceMethod));
-
- return unparse(compiler, new js.ArrayInitializer(elements));
- }
-
- js.Expression emitLazyInitializer(StaticField field) {
- assert(field.isLazy);
- return unparse(compiler, field.code);
- }
-
- /// JavaScript code template that implements parsing of a function descriptor.
- /// Descriptors are used in place of the actual JavaScript function
- /// definition in the output if additional information needs to be passed to
- /// facilitate the generation of tearOffs at runtime. The format is an array
- /// with the following fields:
- ///
- /// * [InstanceMethod.aliasName] (optional).
- /// * [Method.code]
- /// * [DartMethod.callName]
- /// * isInterceptedMethod (optional, present if [DartMethod.needsTearOff]).
- /// * [DartMethod.tearOffName] (optional, present if
- /// [DartMethod.needsTearOff]).
- /// * functionType (optional, present if [DartMethod.needsTearOff]).
- ///
- /// followed by
- ///
- /// * [ParameterStubMethod.name]
- /// * [ParameterStubMethod.callName]
- /// * [ParameterStubMethod.code]
- ///
- /// for each stub in [DartMethod.parameterStubs].
- ///
- /// If the closure could be used in `Function.apply` (i.e.
- /// [DartMethod.canBeApplied] is true) then the following fields are appended:
- ///
- /// * [DartMethod.requiredParameterCount]
- /// * [DartMethod.optionalParameterDefaultValues]
-
- static final String parseFunctionDescriptorBoilerplate = r"""
-function parseFunctionDescriptor(proto, name, descriptor, typesOffset) {
- if (descriptor instanceof Array) {
- // 'pos' points to the last read entry.
- var f, pos = -1;
- var aliasOrFunction = descriptor[++pos];
- if (typeof aliasOrFunction == "string") {
- // Install the alias for super calls on the prototype chain.
- proto[aliasOrFunction] = f = descriptor[++pos];
- } else {
- f = aliasOrFunction;
- }
-
- proto[name] = f;
- var funs = [f];
- f[#callName] = descriptor[++pos];
-
- var isInterceptedOrParameterStubName = descriptor[pos + 1];
- var isIntercepted, tearOffName, reflectionInfo;
- if (typeof isInterceptedOrParameterStubName == "boolean") {
- isIntercepted = descriptor[++pos];
- tearOffName = descriptor[++pos];
- reflectionInfo = descriptor[++pos];
- if (typeof reflectionInfo == "number") {
- reflectionInfo = reflectionInfo + typesOffset;
- }
- }
-
- // We iterate in blocks of 3 but have to stop before we reach the (optional)
- // two trailing items. To accomplish this, we only iterate until we reach
- // length - 2.
- for (++pos; pos < descriptor.length - 2; pos += 3) {
- var stub = descriptor[pos + 2];
- stub[#callName] = descriptor[pos + 1];
- proto[descriptor[pos]] = stub;
- funs.push(stub);
- }
-
- if (tearOffName) {
- proto[tearOffName] =
- tearOff(funs, reflectionInfo, false, name, isIntercepted);
- }
- if (pos < descriptor.length) {
- f[#argumentCount] = descriptor[pos];
- f[#defaultArgumentValues] = descriptor[pos + 1];
- }
- } else {
- proto[name] = descriptor;
- }
-}
-""";
-
- js.Expression _encodeOptionalParameterDefaultValues(DartMethod method) {
- // TODO(herhut): Replace [js.LiteralNull] with [js.ArrayHole].
- if (method.optionalParameterDefaultValues is List) {
- List<ConstantValue> defaultValues = method.optionalParameterDefaultValues;
- Iterable<js.Expression> elements =
- defaultValues.map(generateConstantReference);
- return new js.ArrayInitializer(elements.toList());
- } else {
- Map<String, ConstantValue> defaultValues =
- method.optionalParameterDefaultValues;
- List<js.Property> properties = <js.Property>[];
- defaultValues.forEach((String name, ConstantValue value) {
- properties.add(new js.Property(js.string(name),
- generateConstantReference(value)));
- });
- return new js.ObjectInitializer(properties);
- }
- }
-
- Iterable<js.Expression> emitInstanceMethod(Method method) {
-
- List<js.Expression> makeNameCodePair(Method method) {
- return [js.quoteName(method.name), method.code];
- }
-
- List<js.Expression> makeNameCallNameCodeTriplet(ParameterStubMethod stub) {
- js.Expression callName = stub.callName == null
- ? new js.LiteralNull()
- : js.quoteName(stub.callName);
- return [js.quoteName(stub.name), callName, stub.code];
- }
-
- if (method is InstanceMethod) {
- if (method.needsTearOff || method.aliasName != null) {
- /// See [parseFunctionDescriptorBoilerplate] for a full description of
- /// the format.
- // [name, [aliasName, function, callName, isIntercepted, tearOffName,
- // functionType, stub1_name, stub1_callName, stub1_code, ...]
- var data = [];
- if (method.aliasName != null) {
- data.add(js.quoteName(method.aliasName));
- }
- data.add(method.code);
- data.add(js.quoteName(method.callName, allowNull: true));
-
- if (method.needsTearOff) {
- bool isIntercepted = backend.isInterceptedMethod(method.element);
- data.add(new js.LiteralBool(isIntercepted));
- data.add(js.quoteName(method.tearOffName));
- data.add((method.functionType));
- }
-
- data.addAll(method.parameterStubs.expand(makeNameCallNameCodeTriplet));
- if (method.canBeApplied) {
- data.add(js.number(method.requiredParameterCount));
- data.add(_encodeOptionalParameterDefaultValues(method));
- }
- return [js.quoteName(method.name), new js.ArrayInitializer(data)];
- } else {
- // TODO(floitsch): not the most efficient way...
- return ([method]..addAll(method.parameterStubs))
- .expand(makeNameCodePair);
- }
- } else {
- return makeNameCodePair(method);
- }
- }
-
- Iterable<js.Expression> emitStaticMethod(StaticMethod method) {
- js.Expression holderIndex = js.number(method.holder.index);
- List<js.Expression> output = <js.Expression>[];
-
- void _addMethod(Method method) {
- js.Expression unparsed = unparse(compiler, method.code);
- output.add(js.quoteName(method.name));
- output.add(holderIndex);
- output.add(unparsed);
- }
-
- List<js.Expression> makeNameCallNameCodeTriplet(ParameterStubMethod stub) {
- js.Expression callName = stub.callName == null
- ? new js.LiteralNull()
- : js.quoteName(stub.callName);
- return [js.quoteName(stub.name), callName, unparse(compiler, stub.code)];
- }
-
- _addMethod(method);
- // TODO(floitsch): can there be anything else than a StaticDartMethod?
- if (method is StaticDartMethod) {
- if (method.needsTearOff) {
- /// The format emitted is the same as for the parser specified at
- /// [parseFunctionDescriptorBoilerplate] except for the missing
- /// field whether the method is intercepted.
- // [name, [function, callName, tearOffName, functionType,
- // stub1_name, stub1_callName, stub1_code, ...]
- var data = [unparse(compiler, method.code)];
- data.add(js.quoteName(method.callName));
- data.add(js.quoteName(method.tearOffName));
- data.add(method.functionType);
- data.addAll(method.parameterStubs.expand(makeNameCallNameCodeTriplet));
- if (method.canBeApplied) {
- data.add(js.number(method.requiredParameterCount));
- data.add(_encodeOptionalParameterDefaultValues(method));
- }
- return [js.quoteName(method.name), holderIndex,
- new js.ArrayInitializer(data)];
- } else {
- method.parameterStubs.forEach(_addMethod);
- }
- }
- return output;
- }
-
- static final String setupProgramName = "setupProgram";
-
- static final String boilerplate = """
-{
-// Declare deferred-initializer global.
-#deferredInitializer;
-
-(function(start, program) {
- // Initialize holder objects.
- #holders;
- var nativeInfos = Object.create(null);
-
- // Counter to generate unique names for tear offs.
- var functionCounter = 0;
-
- function $setupProgramName(program, typesOffset) {
- for (var i = 0; i < program.length - 2; i++) {
- setupLibrary(program[i], typesOffset);
- }
- setupLazyStatics(program[i]);
- setupConstants(program[i + 1]);
- }
-
- function setupLibrary(library, typesOffset) {
- var statics = library[0];
- for (var i = 0; i < statics.length; i += 3) {
- var holderIndex = statics[i + 1];
- setupStatic(statics[i], holders[holderIndex], statics[i + 2],
- typesOffset);
- }
-
- var classes = library[1];
- for (var i = 0; i < classes.length; i += 3) {
- var name = classes[i];
- var cls = classes[i + 1];
-
- if (#needsNativeSupport) {
- // $nativeInfoDescription.
- var indexOrNativeInfo = classes[i + 2];
- if (typeof indexOrNativeInfo == "number") {
- var holderIndex = classes[i + 2];
- } else {
- nativeInfos[name] = indexOrNativeInfo;
- holderIndex = classes[i + 3];
- i++;
- }
- }
-
- if (#needsNoNativeSupport) {
- var holderIndex = classes[i + 2];
- }
-
- holdersMap[name] = holders[holderIndex];
- setupClass(name, holders[holderIndex], cls, typesOffset);
- }
- }
-
- function setupLazyStatics(statics) {
- for (var i = 0; i < statics.length; i += 4) {
- var name = statics[i];
- var getterName = statics[i + 1];
- var holderIndex = statics[i + 2];
- var initializer = statics[i + 3];
- setupLazyStatic(name, getterName, holders[holderIndex], initializer);
- }
- }
-
- function setupConstants(constants) {
- // $constantsDescription.
- if (constants.length == 0) return;
- // We assume that all constants are in the same holder.
- var holder = holders[constants[0]];
- for (var i = 1; i < constants.length; i += 2) {
- var name = constants[i];
- var initializer = constants[i + 1];
- setupConstant(name, holder, initializer);
- }
- }
-
- function setupStatic(name, holder, descriptor, typesOffset) {
- if (typeof descriptor == 'string') {
- holder[name] = function() {
- if (descriptor == null) {
- // Already compiled. This happens when we have calls to the static as
- // arguments to the static: `foo(foo(499))`;
- return holder[name].apply(this, arguments);
- }
- var method = compile(name, descriptor);
- holder[name] = method;
- descriptor = null; // GC the descriptor.
- return method.apply(this, arguments);
- };
- } else {
- // Parse the tear off information and generate compile handlers.
- // TODO(herhut): Share parser with instance methods.
- function compileAllStubs(typesOffset) {
- var funs;
- var fun = compile(name, descriptor[0]);
- fun[#callName] = descriptor[1];
- holder[name] = fun;
- funs = [fun];
- // We iterate in blocks of 3 but have to stop before we reach the
- // (optional) two trailing items. To accomplish this, we only iterate
- // until we reach length - 2.
- for (var pos = 4; pos < descriptor.length - 2; pos += 3) {
- var stubName = descriptor[pos];
- fun = compile(stubName, descriptor[pos + 2]);
- fun[#callName] = descriptor[pos + 1];
- holder[stubName] = fun;
- funs.push(fun);
- }
- if (descriptor[2] != null) { // tear-off name.
- // functions, reflectionInfo, isStatic, name, isIntercepted.
- var reflectionInfo = descriptor[3];
- if (typeof reflectionInfo == "number") {
- reflectionInfo = reflectionInfo + typesOffset;
- }
- holder[descriptor[2]] =
- tearOff(funs, reflectionInfo, true, name, false);
- }
- if (pos < descriptor.length) {
- fun[#argumentCount] = descriptor[pos];
- fun[#defaultArgumentValues] = descriptor[pos + 1];
- }
- }
-
- function setupCompileAllAndDelegateStub(name, typesOffset) {
- holder[name] = function() {
- // The descriptor is null if we already compiled this function. This
- // happens when we have calls to the static as arguments to the
- // static: `foo(foo(499))`;
- if (descriptor != null) {
- compileAllStubs(typesOffset);
- descriptor = null; // GC the descriptor.
- }
- return holder[name].apply(this, arguments);
- };
- }
-
- setupCompileAllAndDelegateStub(name, typesOffset);
- for (var pos = 4; pos < descriptor.length; pos += 3) {
- setupCompileAllAndDelegateStub(descriptor[pos], typesOffset);
- }
- if (descriptor[2] != null) { // tear-off name.
- setupCompileAllAndDelegateStub(descriptor[2], typesOffset)
- }
- }
- }
-
- function setupLazyStatic(name, getterName, holder, descriptor) {
- holder[name] = null;
- holder[getterName] = function() {
- var initializer = compile(name, descriptor);
- holder[getterName] = function() { #cyclicThrow(name) };
- var result;
- var sentinelInProgress = descriptor;
- try {
- result = holder[name] = sentinelInProgress;
- result = holder[name] = initializer();
- } finally {
- // Use try-finally, not try-catch/throw as it destroys the stack trace.
- if (result === sentinelInProgress) {
- // The lazy static (holder[name]) might have been set to a different
- // value. According to spec we still have to reset it to null, if the
- // initialization failed.
- holder[name] = null;
- }
- // TODO(floitsch): the function should probably be unique for each
- // static.
- holder[getterName] = function() { return this[name]; };
- }
- return result;
- };
- }
-
- function setupConstant(name, holder, descriptor) {
- var c;
- holder[name] = function() {
- if (descriptor !== null) {
- c = compile(name, descriptor);
- name = null;
- descriptor = null;
- }
- return c;
- };
- }
-
- function setupClass(name, holder, descriptor, typesOffset) {
- var patch = function() {
- if (patch.ensureResolved == patch) {
- // We have not yet been compiled.
- var constructor = compileConstructor(name, descriptor, typesOffset);
- holder[name] = constructor;
- name = holder = descriptor = null; // GC the captured arguments.
- // Make sure we can invoke 'ensureResolved' multiple times on the patch
- // function.
- patch.ensureResolved = function() { return constructor; };
- constructor.ensureResolved = function() { return this; };
- } else {
- // This can happen when arguments to the constructor are of the same
- // class, like in `new A(new A(null))`.
- constructor = patch.ensureResolved();
- }
- // If the patch has been called as "ensureResolved" return.
- if (this === patch) return constructor;
- var object = new constructor();
- constructor.apply(object, arguments);
- return object;
- };
-
- // We store the patch function on itself to make it
- // possible to resolve superclass references without constructing instances.
- patch.ensureResolved = patch;
- holder[name] = patch;
- }
-
- #tearOff;
-
- #parseFunctionDescriptor;
-
- function compileConstructor(name, descriptor, typesOffset) {
- descriptor = compile(name, descriptor);
- var prototype = determinePrototype(descriptor);
- var constructor;
- var functionsIndex;
- // $mixinFormatDescription.
- if (typeof descriptor[2] !== 'function') {
- fillPrototypeWithMixedIn(descriptor[2], descriptor[3], prototype);
- // descriptor[4] contains the constructor if the mixin application is
- // directly instantiated.
- if (typeof descriptor[4] === 'function') {
- constructor = descriptor[4];
- functionsIndex = 5;
- } else {
- constructor = function() {};
- functionsIndex = 4;
- }
- } else {
- constructor = descriptor[2];
- functionsIndex = 3;
- }
-
- for (var i = functionsIndex; i < descriptor.length; i += 2) {
- parseFunctionDescriptor(prototype, descriptor[i], descriptor[i + 1],
- typesOffset);
- }
-
- constructor.$typeNameProperty = name; // Needed for RTI.
- constructor.prototype = prototype;
- prototype[#operatorIsPrefix + name] = constructor;
- prototype.constructor = constructor;
- return constructor;
- }
-
- function fillPrototypeWithMixedIn(mixinName, mixinHolderIndex, prototype) {
- var mixin = holders[mixinHolderIndex][mixinName].ensureResolved();
- var mixinPrototype = mixin.prototype;
-
- // Fill the prototype with the mixin's properties.
- var mixinProperties = Object.keys(mixinPrototype);
- for (var i = 0; i < mixinProperties.length; i++) {
- var p = mixinProperties[i];
- prototype[p] = mixinPrototype[p];
- }
- }
-
- function determinePrototype(descriptor) {
- var superclassName = descriptor[0];
- if (!superclassName) return { };
-
- // Look up the superclass constructor function in the right holder.
- var holderIndex = descriptor[1];
- var superclass = holders[holderIndex][superclassName].ensureResolved();
-
- // Create a new prototype object chained to the superclass prototype.
- var intermediate = function() { };
- intermediate.prototype = superclass.prototype;
- return new intermediate();
- }
-
- function compile(__name__, __s__) {
- 'use strict';
- // TODO(floitsch): evaluate the performance impact of the string
- // concatenations.
- return eval(__s__ + "\\n//# sourceURL=" + __name__ + ".js");
- }
-
- if (#outputContainsConstantList) {
- function makeConstList(list) {
- // By assigning a function to the properties they become part of the
- // hidden class. The actual values of the fields don't matter, since we
- // only check if they exist.
- list.immutable\$list = Array;
- list.fixed\$length = Array;
- return list;
- }
- }
-
- if (#needsNativeSupport) {
- function handleNativeClassInfos() {
- for (var nativeClass in nativeInfos) {
- var constructor = holdersMap[nativeClass][nativeClass].ensureResolved();
- var nativeInfo = nativeInfos[nativeClass];
- #nativeInfoHandler;
- }
- }
- }
-
- $setupProgramName(program, 0);
-
- // Initialize globals.
- #embeddedGlobals;
-
- function expressionCompile(__s__) {
- 'use strict';
- return eval('(' + __s__ + ')');
- }
-
- #readMetadataTypeFunction;
-
- // TODO(floitsch): this order means that native classes may not be
- // referenced from constants. I'm mostly afraid of things like using them as
- // generic arguments (which should be fine, but maybe there are other
- // similar things).
- // Initialize natives.
- if (#needsNativeSupport) handleNativeClassInfos();
-
- // Initialize static non-final fields.
- #staticNonFinals;
-
- // Add native boilerplate code.
- #nativeIsolateAffinityTagInitialization;
-
- // Initialize eager classes.
- #eagerClasses;
-
- var end = Date.now();
- // print('Setup: ' + (end - start) + ' ms.');
-
- #invokeMain; // Start main.
-
-})(Date.now(), #code)
-}""";
-
-}

Powered by Google App Engine
This is Rietveld 408576698