| Index: pkg/compiler/lib/src/js_emitter/old_emitter/reflection_data_parser.dart
|
| diff --git a/pkg/compiler/lib/src/js_emitter/old_emitter/reflection_data_parser.dart b/pkg/compiler/lib/src/js_emitter/old_emitter/reflection_data_parser.dart
|
| index c9d20172b85a655466848c40fac4efa65b3edab2..89404d6882f75d2b816108ca675212a1fa3ef1c0 100644
|
| --- a/pkg/compiler/lib/src/js_emitter/old_emitter/reflection_data_parser.dart
|
| +++ b/pkg/compiler/lib/src/js_emitter/old_emitter/reflection_data_parser.dart
|
| @@ -14,9 +14,8 @@ const DEFAULT_ARGUMENTS_INDEX = 5;
|
|
|
| const bool VALIDATE_DATA = false;
|
|
|
| -// TODO(ahe): This code should be integrated in CodeEmitterTask.finishClasses.
|
| -jsAst.Expression getReflectionDataParser(String classesCollector,
|
| - JavaScriptBackend backend) {
|
| +jsAst.Expression getReflectionDataParser(OldEmitter oldEmitter,
|
| + JavaScriptBackend backend) {
|
| Namer namer = backend.namer;
|
| Compiler compiler = backend.compiler;
|
| CodeEmitterTask emitter = backend.emitter;
|
| @@ -48,6 +47,8 @@ jsAst.Expression getReflectionDataParser(String classesCollector,
|
| emitter.generateEmbeddedGlobalAccess(embeddedNames.MANGLED_NAMES);
|
| jsAst.Expression librariesAccess =
|
| emitter.generateEmbeddedGlobalAccess(embeddedNames.LIBRARIES);
|
| + jsAst.Expression metadataAccess =
|
| + emitter.generateEmbeddedGlobalAccess(embeddedNames.METADATA);
|
|
|
| jsAst.Statement header = js.statement('''
|
| // [map] returns an object literal that V8 shouldn not try to optimize with a
|
| @@ -58,8 +59,89 @@ jsAst.Expression getReflectionDataParser(String classesCollector,
|
| function map(x){x=Object.create(null);x.x=0;delete x.x;return x}
|
| ''');
|
|
|
| + jsAst.Statement processClassData = js.statement('''{
|
| + function processClassData(cls, descriptor, processedClasses) {
|
| + var newDesc = {};
|
| + var previousProperty;
|
| + for (var property in descriptor) {
|
| + if (!hasOwnProperty.call(descriptor, property)) continue;
|
| + var firstChar = property.substring(0, 1);
|
| + if (property === "static") {
|
| + processStatics(#embeddedStatics[cls] = descriptor[property],
|
| + processedClasses);
|
| + } else if (firstChar === "+") {
|
| + mangledNames[previousProperty] = property.substring(1);
|
| + var flag = descriptor[property];
|
| + if (flag > 0)
|
| + descriptor[previousProperty].$reflectableField = flag;
|
| + } else if (firstChar === "@" && property !== "@") {
|
| + newDesc[property.substring(1)][$metadataField] = descriptor[property];
|
| + } else if (firstChar === "*") {
|
| + newDesc[previousProperty].$defaultValuesField = descriptor[property];
|
| + var optionalMethods = newDesc.$methodsWithOptionalArgumentsField;
|
| + if (!optionalMethods) {
|
| + newDesc.$methodsWithOptionalArgumentsField = optionalMethods={}
|
| + }
|
| + optionalMethods[property] = previousProperty;
|
| + } else {
|
| + var elem = descriptor[property];
|
| + if (property !== "${namer.classDescriptorProperty}" &&
|
| + elem != null &&
|
| + elem.constructor === Array &&
|
| + property !== "<>") {
|
| + addStubs(newDesc, elem, property, false, descriptor, []);
|
| + } else {
|
| + newDesc[previousProperty = property] = elem;
|
| + }
|
| + }
|
| + }
|
| +
|
| + /* The 'fields' are either a constructor function or a
|
| + * string encoding fields, constructor and superclass. Gets the
|
| + * superclass and fields in the format
|
| + * 'Super;field1,field2'
|
| + * from the CLASS_DESCRIPTOR_PROPERTY property on the descriptor.
|
| + */
|
| + var classData = newDesc["${namer.classDescriptorProperty}"],
|
| + split, supr, fields = classData;
|
| +
|
| + if (#hasRetainedMetadata)
|
| + if (typeof classData == "object" &&
|
| + classData instanceof Array) {
|
| + classData = fields = classData[0];
|
| + }
|
| + // ${ClassBuilder.fieldEncodingDescription}.
|
| + var s = fields.split(";");
|
| + fields = s[1] == "" ? [] : s[1].split(",");
|
| + supr = s[0];
|
| + // ${ClassBuilder.functionTypeEncodingDescription}.
|
| + split = supr.split(":");
|
| + if (split.length == 2) {
|
| + supr = split[0];
|
| + var functionSignature = split[1];
|
| + if (functionSignature)
|
| + newDesc.${namer.operatorSignature} = function(s) {
|
| + return function() {
|
| + return #metadata[s];
|
| + };
|
| + }(functionSignature);
|
| + }
|
| +
|
| + if (supr) processedClasses.pending[cls] = supr;
|
| + if (#notInCspMode) {
|
| + processedClasses.combinedConstructorFunction += defineClass(cls, fields);
|
| + processedClasses.constructorsList.push(cls);
|
| + }
|
| + processedClasses.collected[cls] = [globalObject, newDesc];
|
| + classes.push(cls);
|
| + }
|
| +}''', {'embeddedStatics': staticsAccess,
|
| + 'hasRetainedMetadata': backend.hasRetainedMetadata,
|
| + 'metadata': metadataAccess,
|
| + 'notInCspMode': !compiler.useContentSecurityPolicy});
|
| +
|
| jsAst.Statement processStatics = js.statement('''
|
| - function processStatics(descriptor) {
|
| + function processStatics(descriptor, processedClasses) {
|
| for (var property in descriptor) {
|
| if (!hasOwnProperty.call(descriptor, property)) continue;
|
| if (property === "${namer.classDescriptorProperty}") continue;
|
| @@ -72,7 +154,7 @@ jsAst.Expression getReflectionDataParser(String classesCollector,
|
| if (flag > 0)
|
| descriptor[previousProperty].$reflectableField = flag;
|
| if (element && element.length)
|
| - #[previousProperty] = element; // embedded typeInformation.
|
| + #typeInformation[previousProperty] = element;
|
| } else if (firstChar === "@") {
|
| property = property.substring(1);
|
| ${namer.currentIsolate}[property][$metadataField] = element;
|
| @@ -86,51 +168,22 @@ jsAst.Expression getReflectionDataParser(String classesCollector,
|
| } else if (typeof element === "function") {
|
| globalObject[previousProperty = property] = element;
|
| functions.push(property);
|
| - #[property] = element; // embedded globalFunctions.
|
| + #globalFunctions[property] = element;
|
| } else if (element.constructor === Array) {
|
| addStubs(globalObject, element, property,
|
| true, descriptor, functions);
|
| } else {
|
| - previousProperty = property;
|
| - var newDesc = {};
|
| - var previousProp;
|
| - for (var prop in element) {
|
| - if (!hasOwnProperty.call(element, prop)) continue;
|
| - firstChar = prop.substring(0, 1);
|
| - if (prop === "static") {
|
| - processStatics(#[property] = element[prop]); // embedded statics.
|
| - } else if (firstChar === "+") {
|
| - mangledNames[previousProp] = prop.substring(1);
|
| - var flag = element[prop];
|
| - if (flag > 0)
|
| - element[previousProp].$reflectableField = flag;
|
| - } else if (firstChar === "@" && prop !== "@") {
|
| - newDesc[prop.substring(1)][$metadataField] = element[prop];
|
| - } else if (firstChar === "*") {
|
| - newDesc[previousProp].$defaultValuesField = element[prop];
|
| - var optionalMethods = newDesc.$methodsWithOptionalArgumentsField;
|
| - if (!optionalMethods) {
|
| - newDesc.$methodsWithOptionalArgumentsField = optionalMethods={}
|
| - }
|
| - optionalMethods[prop] = previousProp;
|
| - } else {
|
| - var elem = element[prop];
|
| - if (prop !== "${namer.classDescriptorProperty}" &&
|
| - elem != null &&
|
| - elem.constructor === Array &&
|
| - prop !== "<>") {
|
| - addStubs(newDesc, elem, prop, false, element, []);
|
| - } else {
|
| - newDesc[previousProp = prop] = elem;
|
| - }
|
| - }
|
| + // We will not enter this case if no classes are defined.
|
| + if (#hasClasses) {
|
| + previousProperty = property;
|
| + processClassData(property, element, processedClasses);
|
| }
|
| - $classesCollector[property] = [globalObject, newDesc];
|
| - classes.push(property);
|
| }
|
| }
|
| }
|
| -''', [typeInformationAccess, globalFunctionsAccess, staticsAccess]);
|
| +''', {'typeInformation': typeInformationAccess,
|
| + 'globalFunctions': globalFunctionsAccess,
|
| + 'hasClasses': oldEmitter.needsClassSupport});
|
|
|
|
|
| /**
|
| @@ -226,18 +279,29 @@ jsAst.Expression getReflectionDataParser(String classesCollector,
|
|
|
| jsAst.Statement init = js.statement('''{
|
| var functionCounter = 0;
|
| - if (!#) # = []; // embedded libraries.
|
| - if (!#) # = map(); // embedded mangledNames.
|
| - if (!#) # = map(); // embedded mangledGlobalNames.
|
| - if (!#) # = map(); // embedded statics.
|
| - if (!#) # = map(); // embedded typeInformation.
|
| - if (!#) # = map(); // embedded globalFunctions.
|
| - if (!#) # = map(); // embedded interceptedNames.
|
| - var libraries = #; // embeded libraries.
|
| - var mangledNames = #; // embedded mangledNames.
|
| - var mangledGlobalNames = #; // embedded mangledGlobalNames.
|
| + if (!#libraries) #libraries = [];
|
| + if (!#mangledNames) #mangledNames = map();
|
| + if (!#mangledGlobalNames) #mangledGlobalNames = map();
|
| + if (!#statics) #statics = map();
|
| + if (!#typeInformation) #typeInformation = map();
|
| + if (!#globalFunctions) #globalFunctions = map();
|
| + if (!#interceptedNames) #interceptedNames = map();
|
| + var libraries = #libraries;
|
| + var mangledNames = #mangledNames;
|
| + var mangledGlobalNames = #mangledGlobalNames;
|
| var hasOwnProperty = Object.prototype.hasOwnProperty;
|
| var length = reflectionData.length;
|
| + var processedClasses = Object.create(null);
|
| + processedClasses.collected = Object.create(null);
|
| + processedClasses.pending = Object.create(null);
|
| + if (#notInCspMode) {
|
| + processedClasses.constructorsList = [];
|
| + // For every class processed [processedClasses.combinedConstructorFunction]
|
| + // will be updated with the corresponding constructor function.
|
| + processedClasses.combinedConstructorFunction =
|
| + "function \$reflectable(fn){fn.$reflectableField=1;return fn};\\n"+
|
| + "var \$desc;\\n";
|
| + }
|
| for (var i = 0; i < length; i++) {
|
| var data = reflectionData[i];
|
|
|
| @@ -262,20 +326,90 @@ jsAst.Expression getReflectionDataParser(String classesCollector,
|
| if (fields instanceof Array) fields = fields[0];
|
| var classes = [];
|
| var functions = [];
|
| - processStatics(descriptor);
|
| + processStatics(descriptor, processedClasses);
|
| libraries.push([name, uri, classes, functions, metadata, fields, isRoot,
|
| globalObject]);
|
| }
|
| -}''', [librariesAccess, librariesAccess,
|
| - mangledNamesAccess, mangledNamesAccess,
|
| - mangledGlobalNamesAccess, mangledGlobalNamesAccess,
|
| - staticsAccess, staticsAccess,
|
| - typeInformationAccess, typeInformationAccess,
|
| - globalFunctionsAccess, globalFunctionsAccess,
|
| - interceptedNamesAccess, interceptedNamesAccess,
|
| - librariesAccess,
|
| - mangledNamesAccess,
|
| - mangledGlobalNamesAccess]);
|
| + if (#needsClassSupport) finishClasses(processedClasses);
|
| +}''', {'libraries': librariesAccess,
|
| + 'mangledNames': mangledNamesAccess,
|
| + 'mangledGlobalNames': mangledGlobalNamesAccess,
|
| + 'statics': staticsAccess,
|
| + 'typeInformation': typeInformationAccess,
|
| + 'globalFunctions': globalFunctionsAccess,
|
| + 'interceptedNames': interceptedNamesAccess,
|
| + 'notInCspMode': !compiler.useContentSecurityPolicy,
|
| + 'needsClassSupport': oldEmitter.needsClassSupport});
|
| +
|
| + jsAst.Expression allClassesAccess =
|
| + emitter.generateEmbeddedGlobalAccess(embeddedNames.ALL_CLASSES);
|
| +
|
| + String specProperty = '"${namer.nativeSpecProperty}"'; // "%"
|
| +
|
| + // Class descriptions are collected in a JS object.
|
| + // 'finishClasses' takes all collected descriptions and sets up
|
| + // the prototype.
|
| + // Once set up, the constructors prototype field satisfy:
|
| + // - it contains all (local) members.
|
| + // - its internal prototype (__proto__) points to the superclass'
|
| + // prototype field.
|
| + // - the prototype's constructor field points to the JavaScript
|
| + // constructor.
|
| + // For engines where we have access to the '__proto__' we can manipulate
|
| + // the object literal directly. For other engines we have to create a new
|
| + // object and copy over the members.
|
| + jsAst.Statement finishClasses = js.statement('''{
|
| + function finishClasses(processedClasses) {
|
| + if (#debugFastObjects)
|
| + print("Number of classes: " +
|
| + Object.getOwnPropertyNames(processedClasses.collected).length);
|
| +
|
| + var allClasses = #allClasses;
|
| +
|
| + if (#inCspMode) {
|
| + constructors = dart_precompiled(processedClasses.collected);
|
| + }
|
| +
|
| + if (#notInCspMode) {
|
| + processedClasses.combinedConstructorFunction +=
|
| + "return [\\n" + processedClasses.constructorsList.join(",\\n ") +
|
| + "\\n]";
|
| + var constructors =
|
| + new Function("\$collectedClasses",
|
| + processedClasses.combinedConstructorFunction)
|
| + (processedClasses.collected);
|
| + processedClasses.combinedConstructorFunction = null;
|
| + }
|
| +
|
| + for (var i = 0; i < constructors.length; i++) {
|
| + var constructor = constructors[i];
|
| + var cls = constructor.name;
|
| + var desc = processedClasses.collected[cls];
|
| + var globalObject = \$;
|
| + if (desc instanceof Array) {
|
| + globalObject = desc[0] || \$;
|
| + desc = desc[1];
|
| + }
|
| + if (#isTreeShakingDisabled)
|
| + constructor["${namer.metadataField}"] = desc;
|
| + allClasses[cls] = constructor;
|
| + globalObject[cls] = constructor;
|
| + }
|
| + constructors = null;
|
| +
|
| + #finishClassFunction;
|
| +
|
| + #trivialNsmHandlers;
|
| +
|
| + for (var cls in processedClasses.pending) finishClass(cls);
|
| + }
|
| +}''', {'allClasses': allClassesAccess,
|
| + 'debugFastObjects': DEBUG_FAST_OBJECTS,
|
| + 'isTreeShakingDisabled': backend.isTreeShakingDisabled,
|
| + 'finishClassFunction': oldEmitter.buildFinishClass(),
|
| + 'trivialNsmHandlers': oldEmitter.buildTrivialNsmHandlers(),
|
| + 'inCspMode': compiler.useContentSecurityPolicy,
|
| + 'notInCspMode': !compiler.useContentSecurityPolicy});
|
|
|
| List<jsAst.Statement> incrementalSupport = <jsAst.Statement>[];
|
| if (compiler.hasIncrementalSupport) {
|
| @@ -288,6 +422,12 @@ jsAst.Expression getReflectionDataParser(String classesCollector,
|
| (function (reflectionData) {
|
| "use strict";
|
| #header;
|
| + if (#needsClassSupport) {
|
| + #defineClass;
|
| + #inheritFrom;
|
| + #finishClasses;
|
| + #processClassData;
|
| + }
|
| #processStatics;
|
| #addStubs;
|
| #tearOffCode;
|
| @@ -295,11 +435,16 @@ jsAst.Expression getReflectionDataParser(String classesCollector,
|
| #init;
|
| })''', {
|
| 'header': header,
|
| + 'defineClass': oldEmitter.defineClassFunction,
|
| + 'inheritFrom': oldEmitter.buildInheritFrom(),
|
| + 'processClassData': processClassData,
|
| 'processStatics': processStatics,
|
| 'incrementalSupport': incrementalSupport,
|
| 'addStubs': addStubs,
|
| 'tearOffCode': tearOffCode,
|
| - 'init': init});
|
| + 'init': init,
|
| + 'finishClasses': finishClasses,
|
| + 'needsClassSupport': oldEmitter.needsClassSupport});
|
| }
|
|
|
|
|
|
|