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 5981370a47a9b5d75f139a2c9ae161a17a261d22..ceddd0a8e1b26ca2b30fa0e53b807338ee548240 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 |
| @@ -17,9 +17,9 @@ const bool VALIDATE_DATA = false; |
| // TODO(zarah): Rename this when renaming this file. |
| String get parseReflectionDataName => 'parseReflectionData'; |
| -jsAst.Expression getReflectionDataParser(OldEmitter oldEmitter, |
| - JavaScriptBackend backend, |
| - bool needsNativeSupport) { |
| +jsAst.Statement getReflectionDataParser(OldEmitter oldEmitter, |
| + JavaScriptBackend backend, |
| + bool needsNativeSupport) { |
| Namer namer = backend.namer; |
| Compiler compiler = backend.compiler; |
| CodeEmitterTask emitter = backend.emitter; |
| @@ -53,27 +53,62 @@ jsAst.Expression getReflectionDataParser(OldEmitter oldEmitter, |
| jsAst.Expression typesAccess = |
| emitter.generateEmbeddedGlobalAccess(embeddedNames.TYPES); |
| + |
| jsAst.Statement processClassData = js.statement('''{ |
| + function finishAddStubsHelper(prototype) { |
| + var prototype = prototype || this; |
|
floitsch
2015/03/11 13:59:33
document this.
herhut
2015/03/13 12:28:52
Done.
|
| + var object; |
| + while (prototype.#deferredAction != #markerFun) { |
| + if (prototype.hasOwnProperty(#deferredActionString)) { |
| + delete prototype.#deferredAction; // Intended to make it slow, too. |
| + var properties = Object.keys(prototype); |
| + for (var index = 0; index < properties.length; index++) { |
| + var property = properties[index]; |
| + var firstChar = property.charCodeAt(0); |
| + var elem; |
| + // We have to filter out some special properties that are used for |
| + // metadata in descriptors. Currently, we filter everything that |
| + // starts with + or *. This has to stay in sync with the special |
| + // properties that are used by processClassData below. |
| + if (property !== "${namer.classDescriptorProperty}" && |
| + property !== "$reflectableField" && |
| + firstChar !== 43 && // 43 is aka "+". |
| + firstChar !== 42 && // 42 is aka "*" |
| + (elem = prototype[property]) != null && |
| + elem.constructor === Array && |
| + property !== "<>") { |
| + addStubs(prototype, elem, property, false, null); |
| + } |
| + } |
| + convertToFastObject(prototype); |
| + } |
| + prototype = prototype.__proto__; |
| + } |
| + } |
| + |
| function processClassData(cls, descriptor, processedClasses) { |
| - var newDesc = map(); // Use a slow object. |
| + descriptor = convertToSlowObject(descriptor); // Use a slow object. |
| var previousProperty; |
| var properties = Object.keys(descriptor); |
| + var hasDeferredWork = false; |
| + var deferWork = supportsDirectProtoAccess && cls != #objectClassName; |
|
floitsch
2015/03/11 13:59:33
shouldDeferWork ?
shouldAddStubsEagerly = !...
sho
herhut
2015/03/13 12:28:52
Done.
|
| for (var i = 0; i < properties.length; i++) { |
| var property = properties[i]; |
| - var firstChar = property.substring(0, 1); |
| + var firstChar = property.charCodeAt(0); |
| if (property === "static") { |
| - processStatics(#embeddedStatics[cls] = descriptor[property], |
| + processStatics(#embeddedStatics[cls] = descriptor.static, |
| processedClasses); |
| - } else if (firstChar === "+") { |
| + delete descriptor.static; |
| + } else if (firstChar === 43) { // 43 is aka "+". |
|
floitsch
2015/03/11 13:59:33
is aka -> "is" or "aka".
herhut
2015/03/13 12:28:52
Argh, missed that one. Thanks, done.
|
| mangledNames[previousProperty] = property.substring(1); |
| var flag = descriptor[property]; |
| if (flag > 0) |
| descriptor[previousProperty].$reflectableField = flag; |
| - } else if (firstChar === "*") { |
| - newDesc[previousProperty].$defaultValuesField = descriptor[property]; |
| - var optionalMethods = newDesc.$methodsWithOptionalArgumentsField; |
| + } else if (firstChar === 42) { // 42 is "*" |
| + descriptor[previousProperty].$defaultValuesField = descriptor[property]; |
| + var optionalMethods = descriptor.$methodsWithOptionalArgumentsField; |
| if (!optionalMethods) { |
| - newDesc.$methodsWithOptionalArgumentsField = optionalMethods={} |
| + descriptor.$methodsWithOptionalArgumentsField = optionalMethods={} |
| } |
| optionalMethods[property] = previousProperty; |
| } else { |
| @@ -82,12 +117,19 @@ jsAst.Expression getReflectionDataParser(OldEmitter oldEmitter, |
| elem != null && |
| elem.constructor === Array && |
| property !== "<>") { |
| - addStubs(newDesc, elem, property, false, []); |
| + if (deferWork) { |
| + hasDeferredWork = true; |
| + } else { |
| + addStubs(descriptor, elem, property, false, null); |
| + } |
| } else { |
| - newDesc[previousProperty = property] = elem; |
| + previousProperty = property; |
| } |
| } |
| } |
| + |
| + if (hasDeferredWork) |
| + descriptor.#deferredAction = finishAddStubsHelper; |
| /* The 'fields' are either a constructor function or a |
| * string encoding fields, constructor and superclass. Gets the |
| @@ -95,7 +137,7 @@ jsAst.Expression getReflectionDataParser(OldEmitter oldEmitter, |
| * 'Super;field1,field2' |
| * from the CLASS_DESCRIPTOR_PROPERTY property on the descriptor. |
| */ |
| - var classData = newDesc["${namer.classDescriptorProperty}"], |
| + var classData = descriptor["${namer.classDescriptorProperty}"], |
| split, supr, fields = classData; |
| if (#hasRetainedMetadata) |
| @@ -113,7 +155,7 @@ jsAst.Expression getReflectionDataParser(OldEmitter oldEmitter, |
| supr = split[0]; |
| var functionSignature = split[1]; |
| if (functionSignature) |
| - newDesc.${namer.operatorSignature} = function(s) { |
| + descriptor.${namer.operatorSignature} = function(s) { |
| return function() { |
| return #types[s]; |
| }; |
| @@ -125,13 +167,18 @@ jsAst.Expression getReflectionDataParser(OldEmitter oldEmitter, |
| processedClasses.combinedConstructorFunction += defineClass(cls, fields); |
| processedClasses.constructorsList.push(cls); |
| } |
| - processedClasses.collected[cls] = [globalObject, newDesc]; |
| + processedClasses.collected[cls] = [globalObject, descriptor]; |
| classes.push(cls); |
| } |
| -}''', {'embeddedStatics': staticsAccess, |
| +}''', {'deferredAction': namer.deferredAction, |
| + 'deferredActionString': js.string(namer.deferredAction), |
| + 'embeddedStatics': staticsAccess, |
| 'hasRetainedMetadata': backend.hasRetainedMetadata, |
| + 'markerFun': oldEmitter.markerFun, |
| 'types': typesAccess, |
| - 'notInCspMode': !compiler.useContentSecurityPolicy}); |
| + 'notInCspMode': !compiler.useContentSecurityPolicy, |
| + 'objectClassName': |
| + js.string(namer.runtimeTypeName(compiler.objectClass))}); |
| // TODO(zarah): Remove empty else branches in output when if(#hole) is false. |
| jsAst.Statement processStatics = js.statement(''' |
| @@ -141,16 +188,16 @@ jsAst.Expression getReflectionDataParser(OldEmitter oldEmitter, |
| var property = properties[i]; |
| if (property === "${namer.classDescriptorProperty}") continue; |
| var element = descriptor[property]; |
| - var firstChar = property.substring(0, 1); |
| + var firstChar = property.charCodeAt(0); |
| var previousProperty; |
| - if (firstChar === "+") { |
| + if (firstChar === 43) { // 43 is "+". |
| mangledGlobalNames[previousProperty] = property.substring(1); |
| var flag = descriptor[property]; |
| if (flag > 0) |
| descriptor[previousProperty].$reflectableField = flag; |
| if (element && element.length) |
| #typeInformation[previousProperty] = element; |
| - } else if (firstChar === "*") { |
| + } else if (firstChar === 42) { // 42 is "*" |
| globalObject[previousProperty].$defaultValuesField = element; |
| var optionalMethods = descriptor.$methodsWithOptionalArgumentsField; |
| if (!optionalMethods) { |
| @@ -195,7 +242,7 @@ jsAst.Expression getReflectionDataParser(OldEmitter oldEmitter, |
| } |
| var funcs = [descriptor[name] = descriptor[alias] = f]; |
| f.\$stubName = name; |
| - functions.push(name); |
| + if (isStatic) functions.push(name); |
|
floitsch
2015/03/11 13:59:33
Is this necessary in this CL?
herhut
2015/03/13 12:28:52
Great catch. That was a left-over from an experime
|
| for (; index < array.length; index += 2) { |
| f = array[index + 1]; |
| if (typeof f != "function") break; |
| @@ -203,7 +250,7 @@ jsAst.Expression getReflectionDataParser(OldEmitter oldEmitter, |
| funcs.push(f); |
| if (f.\$stubName) { |
| descriptor[f.\$stubName] = f; |
| - functions.push(f.\$stubName); |
| + if (isStatic) functions.push(f.\$stubName); |
| } |
| } |
| index++; |
| @@ -230,10 +277,12 @@ jsAst.Expression getReflectionDataParser(OldEmitter oldEmitter, |
| descriptor[name].\$getter = f; |
| f.\$getterStub = true; |
| // Used to create an isolate using spawnFunction. |
| - if (isStatic) #globalFunctions[name] = f; |
| + if (isStatic) { |
| + #globalFunctions[name] = f; |
| + functions.push(getterStubName); |
| + } |
| descriptor[getterStubName] = f; |
| funcs.push(f); |
| - if (getterStubName) functions.push(getterStubName); |
| f.\$stubName = getterStubName; |
| f.\$callName = null; |
| // Update the interceptedNames map (which only exists if `invokeOn` was |
| @@ -427,7 +476,7 @@ jsAst.Expression getReflectionDataParser(OldEmitter oldEmitter, |
| '#.addStubs = addStubs;', [namer.accessIncrementalHelper])); |
| } |
| - return js(''' |
| + return js.statement(''' |
| function $parseReflectionDataName(reflectionData) { |
| "use strict"; |
| if (#needsClassSupport) { |