Chromium Code Reviews| 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 550cd71181c6891a643d0e850a9c80feb81332cc..e0adfcce906c00504370a5b4985ad2d97d30574a 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; |
| @@ -51,6 +50,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 |
| @@ -61,8 +62,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; |
| @@ -75,7 +157,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; |
| @@ -89,51 +171,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.hasClasses}); |
| /** |
| @@ -227,18 +280,27 @@ 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 = []; |
| + processedClasses.combinedConstructorFunction = |
|
floitsch
2014/12/29 18:00:22
Add comment, that the variable will be changed for
zarah
2014/12/30 14:02:44
Done.
|
| + "function \$reflectable(fn){fn.$reflectableField=1;return fn};\\n"+ |
| + "var \$desc;\\n"; |
| + } |
| for (var i = 0; i < length; i++) { |
| var data = reflectionData[i]; |
| @@ -263,20 +325,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 (#hasClasses) finishClasses(processedClasses); |
|
floitsch
2014/12/29 18:00:22
Indentation seems off.
zarah
2014/12/30 14:02:44
Done.
|
| +}''',{'libraries': librariesAccess, |
| + 'mangledNames': mangledNamesAccess, |
| + 'mangledGlobalNames': mangledGlobalNamesAccess, |
| + 'statics': staticsAccess, |
| + 'typeInformation': typeInformationAccess, |
| + 'globalFunctions': globalFunctionsAccess, |
| + 'interceptedNames': interceptedNamesAccess, |
| + 'notInCspMode': !compiler.useContentSecurityPolicy, |
| + 'hasClasses': oldEmitter.hasClasses}); |
| + |
| + 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 = |
|
floitsch
2014/12/29 18:00:22
Please avoid big code moves with code changes.
It'
zarah
2014/12/30 14:02:44
Acknowledged.
|
| + 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] || isolateProperties; |
| + 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) { |
| @@ -289,6 +421,12 @@ jsAst.Expression getReflectionDataParser(String classesCollector, |
| (function (reflectionData) { |
| "use strict"; |
| #header; |
|
floitsch
2014/12/29 18:00:22
Different CL:
I wonder if we shouldn't just inline
zarah
2014/12/30 14:02:44
Acknowledged.
|
| + if (#hasClasses) { |
| + #defineClass; |
| + #inheritFrom; |
| + #finishClasses; |
| + #processClassData; |
| + } |
| #processStatics; |
| #addStubs; |
| #tearOffCode; |
| @@ -296,11 +434,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, |
| + 'hasClasses': oldEmitter.hasClasses}); |
| } |