Chromium Code Reviews| Index: sdk/lib/_internal/compiler/implementation/js_emitter/code_emitter_task.dart |
| diff --git a/sdk/lib/_internal/compiler/implementation/js_emitter/code_emitter_task.dart b/sdk/lib/_internal/compiler/implementation/js_emitter/code_emitter_task.dart |
| index c5dd94aaae0da35570c35080e1f94d7b88a4d23b..5bb280f3989a24a4ce7dbb7657925a0525b2bd86 100644 |
| --- a/sdk/lib/_internal/compiler/implementation/js_emitter/code_emitter_task.dart |
| +++ b/sdk/lib/_internal/compiler/implementation/js_emitter/code_emitter_task.dart |
| @@ -148,74 +148,65 @@ class CodeEmitterTask extends CompilerTask { |
| String valueParamName = compiler.enableMinification ? "v" : "value"; |
| String reflectableField = namer.reflectableField; |
| - // function generateAccessor(field, prototype, cls) { |
| - jsAst.Fun fun = js.fun(['fieldDescriptor', 'accessors', 'cls'], [ |
| - js('var fieldInformation = fieldDescriptor.split("-")'), |
| - js('var field = fieldInformation[0]'), |
| - js('var len = field.length'), |
| - js('var code = field.charCodeAt(len - 1)'), |
| - js('var reflectable'), |
| - js.if_('fieldInformation.length > 1', js('reflectable = true'), |
| - js('reflectable = false')), |
| - js('code = ((code >= $RANGE1_FIRST) && (code <= $RANGE1_LAST))' |
| - ' ? code - $RANGE1_ADJUST' |
| - ' : ((code >= $RANGE2_FIRST) && (code <= $RANGE2_LAST))' |
| - ' ? code - $RANGE2_ADJUST' |
| - ' : ((code >= $RANGE3_FIRST) && (code <= $RANGE3_LAST))' |
| - ' ? code - $RANGE3_ADJUST' |
| - ' : $NO_FIELD_CODE'), |
| - |
| - // if (needsAccessor) { |
| - js.if_('code', [ |
| - js('var getterCode = code & 3'), |
| - js('var setterCode = code >> 2'), |
| - js('var accessorName = field = field.substring(0, len - 1)'), |
| - |
| - js('var divider = field.indexOf(":")'), |
| - js.if_('divider > 0', [ // Colon never in first position. |
| - js('accessorName = field.substring(0, divider)'), |
| - js('field = field.substring(divider + 1)') |
| - ]), |
| - |
| - // if (needsGetter) { |
| - js.if_('getterCode', [ |
| - js('var args = (getterCode & 2) ? "$receiverParamName" : ""'), |
| - js('var receiver = (getterCode & 1) ? "this" : "$receiverParamName"'), |
| - js('var body = "return " + receiver + "." + field'), |
| - js('var property =' |
| - ' cls + ".prototype.${namer.getterPrefix}" + accessorName + "="'), |
| - js('var fn = "function(" + args + "){" + body + "}"'), |
| - js.if_( |
| - 'reflectable', |
| - js('accessors.push(property + "\$reflectable(" + fn + ");\\n")'), |
| - js('accessors.push(property + fn + ";\\n")')), |
| - ]), |
| - |
| - // if (needsSetter) { |
| - js.if_('setterCode', [ |
| - js('var args = (setterCode & 2)' |
| - ' ? "$receiverParamName,${_}$valueParamName"' |
| - ' : "$valueParamName"'), |
| - js('var receiver = (setterCode & 1) ? "this" : "$receiverParamName"'), |
| - js('var body = receiver + "." + field + "$_=$_$valueParamName"'), |
| - js('var property =' |
| - ' cls + ".prototype.${namer.setterPrefix}" + accessorName + "="'), |
| - js('var fn = "function(" + args + "){" + body + "}"'), |
| - js.if_( |
| - 'reflectable', |
| - js('accessors.push(property + "\$reflectable(" + fn + ");\\n")'), |
| - js('accessors.push(property + fn + ";\\n")')), |
| - ]), |
| - |
| - ]), |
| - |
| - // return field; |
| - js.return_('field') |
| - ]); |
| + return js.statement(''' |
| + function generateAccessor(fieldDescriptor, accessors, cls) { |
| + var fieldInformation = fieldDescriptor.split("-"); |
| + var field = fieldInformation[0]; |
| + var len = field.length; |
| + var code = field.charCodeAt(len - 1); |
| + var reflectable; |
| + if (fieldInformation.length > 1) reflectable = true; |
|
floitsch
2014/04/22 16:11:18
var reflectable = fieldInformation.length > 1;
sra1
2014/04/23 02:33:50
I agree, but the process for this change it to cha
|
| + else reflectable = false; |
| + code = ((code >= $RANGE1_FIRST) && (code <= $RANGE1_LAST)) |
| + ? code - $RANGE1_ADJUST |
| + : ((code >= $RANGE2_FIRST) && (code <= $RANGE2_LAST)) |
| + ? code - $RANGE2_ADJUST |
| + : ((code >= $RANGE3_FIRST) && (code <= $RANGE3_LAST)) |
| + ? code - $RANGE3_ADJUST |
| + : $NO_FIELD_CODE; |
| + |
| + if (code) { // needsAccessor |
| + var getterCode = code & 3; |
| + var setterCode = code >> 2; |
| + var accessorName = field = field.substring(0, len - 1); |
| + |
| + var divider = field.indexOf(":"); |
| + if (divider > 0) { // Colon never in first position. |
| + accessorName = field.substring(0, divider); |
| + field = field.substring(divider + 1); |
| + } |
| + |
| + if (getterCode) { // needsGetter |
| + var args = (getterCode & 2) ? "$receiverParamName" : ""; |
| + var receiver = (getterCode & 1) ? "this" : "$receiverParamName"; |
| + var body = "return " + receiver + "." + field; |
| + var property = |
| + cls + ".prototype.${namer.getterPrefix}" + accessorName + "="; |
| + var fn = "function(" + args + "){" + body + "}"; |
| + if (reflectable) |
| + accessors.push(property + "\$reflectable(" + fn + ");\\n"); |
| + else |
| + accessors.push(property + fn + ";\\n"); |
| + } |
| + |
| + if (setterCode) { // needsSetter |
| + var args = (setterCode & 2) |
| + ? "$receiverParamName,${_}$valueParamName" |
| + : "$valueParamName"; |
| + var receiver = (setterCode & 1) ? "this" : "$receiverParamName"; |
| + var body = receiver + "." + field + "$_=$_$valueParamName"; |
| + var property = |
| + cls + ".prototype.${namer.setterPrefix}" + accessorName + "="; |
| + var fn = "function(" + args + "){" + body + "}"; |
| + if (reflectable) |
| + accessors.push(property + "\$reflectable(" + fn + ");\\n"); |
| + else |
| + accessors.push(property + fn + ";\\n"); |
| + } |
| + } |
| - return new jsAst.FunctionDeclaration( |
| - new jsAst.VariableDeclaration('generateAccessor'), |
| - fun); |
| + return field; |
| + }'''); |
| } |
| List get defineClassFunction { |
| @@ -304,130 +295,134 @@ class CodeEmitterTask extends CompilerTask { |
| // object and copy over the members. |
| String reflectableField = namer.reflectableField; |
| - List<jsAst.Node> statements = [ |
| - js('var pendingClasses = {}'), |
| - js.if_('!init.allClasses', js('init.allClasses = {}')), |
| - js('var allClasses = init.allClasses'), |
| - |
| - optional( |
| - DEBUG_FAST_OBJECTS, |
| - js('print("Number of classes: "' |
| - r' + Object.getOwnPropertyNames($$).length)')), |
| - |
| - js('var hasOwnProperty = Object.prototype.hasOwnProperty'), |
| - |
| - js.if_('typeof dart_precompiled == "function"', |
| - [js('var constructors = dart_precompiled(collectedClasses)')], |
| - |
| - [js('var combinedConstructorFunction = "function \$reflectable(fn){' |
| - 'fn.$reflectableField=1;return fn};\\n"+ "var \$desc;\\n"'), |
| - js('var constructorsList = []')]), |
| - js.forIn('cls', 'collectedClasses', [ |
| - js.if_('hasOwnProperty.call(collectedClasses, cls)', [ |
| - js('var desc = collectedClasses[cls]'), |
| - js.if_('desc instanceof Array', js('desc = desc[1]')), |
| - |
| - /* The 'fields' are either a constructor function or a |
| - * string encoding fields, constructor and superclass. Get |
| - * the superclass and the fields in the format |
| - * '[name/]Super;field1,field2' |
| - * from the CLASS_DESCRIPTOR_PROPERTY property on the descriptor. |
| - * The 'name/' is optional and contains the name that should be used |
| - * when printing the runtime type string. It is used, for example, to |
| - * print the runtime type JSInt as 'int'. |
| - */ |
| - js('var classData = desc["${namer.classDescriptorProperty}"], ' |
| - 'supr, name = cls, fields = classData'), |
| - optional( |
| - backend.hasRetainedMetadata, |
| - js.if_('typeof classData == "object" && ' |
| - 'classData instanceof Array', |
| - [js('classData = fields = classData[0]')])), |
| - |
| - js.if_('typeof classData == "string"', [ |
| - js('var split = classData.split("/")'), |
| - js.if_('split.length == 2', [ |
| - js('name = split[0]'), |
| - js('fields = split[1]') |
| - ]) |
| - ]), |
| - |
| - js('var s = fields.split(";")'), |
| - js('fields = s[1] == "" ? [] : s[1].split(",")'), |
| - js('supr = s[0]'), |
| - js('split = supr.split(":")'), |
| - js.if_('split.length == 2', [ |
| - js('supr = split[0]'), |
| - js('var functionSignature = split[1]'), |
| - js.if_('functionSignature', |
| - js('desc.\$signature = #', |
| - js.fun('s', |
| - js.return_(js.fun([], js.return_('init.metadata[s]'))))( |
| - js('functionSignature')))) |
| - ]), |
| - |
| - optional(needsMixinSupport, js.if_('supr && supr.indexOf("+") > 0', [ |
| - js('s = supr.split("+")'), |
| - js('supr = s[0]'), |
| - js('var mixin = collectedClasses[s[1]]'), |
| - js.if_('mixin instanceof Array', js('mixin = mixin[1]')), |
| - js.forIn('d', 'mixin', [ |
| - js.if_('hasOwnProperty.call(mixin, d)' |
| - '&& !hasOwnProperty.call(desc, d)', |
| - js('desc[d] = mixin[d]')) |
| - ]), |
| - ])), |
| - |
| - js.if_('typeof dart_precompiled != "function"', |
| - [js('combinedConstructorFunction +=' |
| - ' defineClass(name, cls, fields)'), |
| - js('constructorsList.push(cls)')]), |
| - js.if_('supr', js('pendingClasses[cls] = supr')) |
| - ]) |
| - ]), |
| - js.statement(''' |
| - if (typeof dart_precompiled != "function") { |
| - combinedConstructorFunction += |
| - "return [\\n " + constructorsList.join(",\\n ") + "\\n]"; |
| - var constructors = |
| - new Function("\$collectedClasses", combinedConstructorFunction) |
| - (collectedClasses); |
| - combinedConstructorFunction = null; |
| - }'''), |
| - js.for_('var i = 0', 'i < constructors.length', 'i++', [ |
| - js('var constructor = constructors[i]'), |
| - js('var cls = constructor.name'), |
| - js('var desc = collectedClasses[cls]'), |
| - js('var globalObject = isolateProperties'), |
| - js.if_('desc instanceof Array', [ |
| - js('globalObject = desc[0] || isolateProperties'), |
| - js('desc = desc[1]') |
| - ]), |
| - optional(backend.isTreeShakingDisabled, |
| - js('constructor["${namer.metadataField}"] = desc')), |
| - js('allClasses[cls] = constructor'), |
| - js('globalObject[cls] = constructor'), |
| - ]), |
| - js('constructors = null'), |
| - |
| - js('var finishedClasses = {}'), |
| - js('init.interceptorsByTag = Object.create(null)'), |
| - js('init.leafTags = {}'), |
| - |
| - buildFinishClass(), |
| - ]; |
| - nsmEmitter.addTrivialNsmHandlers(statements); |
| + return js(''' |
| + function(collectedClasses, isolateProperties, existingIsolateProperties) { |
| + var pendingClasses = {}; |
| + if (!init.allClasses) init.allClasses = {}; |
| + var allClasses = init.allClasses; |
| + |
| + if (#) // DEBUG_FAST_OBJECTS |
| + print("Number of classes: " + |
| + Object.getOwnPropertyNames(\$\$).length); |
| - statements.add( |
| - js.statement('for (var cls in pendingClasses) finishClass(cls);') |
| - ); |
| + var hasOwnProperty = Object.prototype.hasOwnProperty; |
| + |
| + if (typeof dart_precompiled == "function") { |
|
floitsch
2014/04/22 16:11:18
Not this CL, but I think this is a compile-time co
sra1
2014/04/23 02:33:50
I'm not sure because the csp stuff is appended.
It
|
| + var constructors = dart_precompiled(collectedClasses); |
| + } else { |
| + var combinedConstructorFunction = |
| + "function \$reflectable(fn){fn.$reflectableField=1;return fn};\\n"+ |
| + "var \$desc;\\n"; |
| + var constructorsList = []; |
| + } |
| + |
| + for (var cls in collectedClasses) { |
| + if (hasOwnProperty.call(collectedClasses, cls)) { |
| + var desc = collectedClasses[cls]; |
| + if (desc instanceof Array) desc = desc[1]; |
| + |
| + /* The 'fields' are either a constructor function or a |
| + * string encoding fields, constructor and superclass. Get |
| + * the superclass and the fields in the format |
| + * '[name/]Super;field1,field2' |
| + * from the CLASS_DESCRIPTOR_PROPERTY property on the descriptor. |
| + * The 'name/' is optional and contains the name that should be used |
| + * when printing the runtime type string. It is used, for example, |
| + * to print the runtime type JSInt as 'int'. |
| + */ |
| + var classData = desc["${namer.classDescriptorProperty}"], |
| + supr, name = cls, fields = classData; |
| + if (#) // backend.hasRetainedMetadata |
| + if (typeof classData == "object" && |
| + classData instanceof Array) { |
| + classData = fields = classData[0]; |
| + } |
| + if (typeof classData == "string") { |
| + var split = classData.split("/"); |
| + if (split.length == 2) { |
| + name = split[0]; |
| + fields = split[1]; |
| + } |
| + } |
| + |
| + var s = fields.split(";"); |
| + fields = s[1] == "" ? [] : s[1].split(","); |
| + supr = s[0]; |
| + split = supr.split(":"); |
| + if (split.length == 2) { |
| + supr = split[0]; |
| + var functionSignature = split[1]; |
| + if (functionSignature) |
| + desc.\$signature = (function(s) { |
| + return function(){ return init.metadata[s]; }; |
| + })(functionSignature); |
| + } |
| + |
| + if (#) // needsMixinSupport |
| + if (supr && supr.indexOf("+") > 0) { |
| + s = supr.split("+"); |
| + supr = s[0]; |
| + var mixin = collectedClasses[s[1]]; |
| + if (mixin instanceof Array) mixin = mixin[1]; |
| + for(var d in mixin) { |
| + if (hasOwnProperty.call(mixin, d) && |
| + !hasOwnProperty.call(desc, d)) |
| + desc[d] = mixin[d]; |
| + } |
| + } |
| + |
| + if (typeof dart_precompiled != "function") { |
| + combinedConstructorFunction += defineClass(name, cls, fields); |
| + constructorsList.push(cls); |
| + } |
| + if (supr) pendingClasses[cls] = supr; |
| + } |
| + } |
| + |
| + if (typeof dart_precompiled != "function") { |
| + combinedConstructorFunction += |
| + "return [\\n " + constructorsList.join(",\\n ") + "\\n]"; |
| + var constructors = |
| + new Function("\$collectedClasses", combinedConstructorFunction) |
| + (collectedClasses); |
| + combinedConstructorFunction = null; |
| + } |
| + |
| + for (var i = 0; i < constructors.length; i++) { |
| + var constructor = constructors[i]; |
| + var cls = constructor.name; |
| + var desc = collectedClasses[cls]; |
| + var globalObject = isolateProperties; |
| + if (desc instanceof Array) { |
| + globalObject = desc[0] || isolateProperties; |
| + desc = desc[1]; |
| + } |
| + if (#) //backend.isTreeShakingDisabled, |
| + constructor["${namer.metadataField}"] = desc; |
| + allClasses[cls] = constructor; |
| + globalObject[cls] = constructor; |
| + } |
| - // function(collectedClasses, |
| - // isolateProperties, |
| - // existingIsolateProperties) |
| - return js.fun(['collectedClasses', 'isolateProperties', |
| - 'existingIsolateProperties'], statements); |
| + constructors = null; |
| + |
| + var finishedClasses = {}; |
| + init.interceptorsByTag = Object.create(null); |
| + init.leafTags = {}; |
| + |
| + #; // buildFinishClass(), |
| + |
| + #; // buildTrivialNsmHandlers() |
| + |
| + for (var cls in pendingClasses) finishClass(cls); |
| + }''', [ |
| + DEBUG_FAST_OBJECTS, |
| + backend.hasRetainedMetadata, |
| + needsMixinSupport, |
| + backend.isTreeShakingDisabled, |
| + buildFinishClass(), |
| + nsmEmitter.buildTrivialNsmHandlers()]); |
| + |
| } |
| jsAst.Node optional(bool condition, jsAst.Node node) { |
| @@ -437,38 +432,35 @@ class CodeEmitterTask extends CompilerTask { |
| jsAst.FunctionDeclaration buildFinishClass() { |
| String specProperty = '"${namer.nativeSpecProperty}"'; // "%" |
| - // function finishClass(cls) { |
| - jsAst.Fun fun = js.fun(['cls'], [ |
| + return js.statement(''' |
| + function finishClass(cls) { |
| - // TODO(8540): Remove this work around. |
| - /* Opera does not support 'getOwnPropertyNames'. Therefore we use |
| - hasOwnProperty instead. */ |
| - js('var hasOwnProperty = Object.prototype.hasOwnProperty'), |
| + // TODO(8540): Remove this work around. |
| + // Opera does not support 'getOwnPropertyNames'. Therefore we use |
| + // hasOwnProperty instead. |
| + var hasOwnProperty = Object.prototype.hasOwnProperty; |
| - // if (hasOwnProperty.call(finishedClasses, cls)) return; |
| - js.if_('hasOwnProperty.call(finishedClasses, cls)', |
| - js.return_()), |
| + if (hasOwnProperty.call(finishedClasses, cls)) return; |
| - js('finishedClasses[cls] = true'), |
| + finishedClasses[cls] = true; |
| - js('var superclass = pendingClasses[cls]'), |
| + var superclass = pendingClasses[cls]; |
| - // The superclass is only false (empty string) for Dart's Object class. |
| - // The minifier together with noSuchMethod can put methods on the |
| - // Object.prototype object, and they show through here, so we check that |
| - // we have a string. |
| - js.if_('!superclass || typeof superclass != "string"', js.return_()), |
| - js('finishClass(superclass)'), |
| - js('var constructor = allClasses[cls]'), |
| - js('var superConstructor = allClasses[superclass]'), |
| + // The superclass is only false (empty string) for the Dart Object |
| + // class. The minifier together with noSuchMethod can put methods on |
| + // the Object.prototype object, and they show through here, so we check |
| + // that we have a string. |
| + if (!superclass || typeof superclass != "string") return; |
| + finishClass(superclass); |
| + var constructor = allClasses[cls]; |
| + var superConstructor = allClasses[superclass]; |
| - js.if_(js('!superConstructor'), |
| - js('superConstructor =' |
| - 'existingIsolateProperties[superclass]')), |
| + if (!superConstructor) |
| + superConstructor = existingIsolateProperties[superclass]; |
| - js('var prototype = inheritFrom(constructor, superConstructor)'), |
| + var prototype = inheritFrom(constructor, superConstructor); |
| - optional(!nativeClasses.isEmpty, |
| + if (#) { // !nativeClasses.isEmpty, |
| // The property looks like this: |
| // |
| // HtmlElement: { |
| @@ -490,30 +482,34 @@ class CodeEmitterTask extends CompilerTask { |
| // |
| // The information is used to build tables referenced by |
| // getNativeInterceptor and custom element support. |
| - js.if_('hasOwnProperty.call(prototype, $specProperty)', [ |
| - js('var nativeSpec = prototype[$specProperty].split(";")'), |
| - js.if_('nativeSpec[0]', [ |
| - js('var tags = nativeSpec[0].split("|")'), |
| - js.for_('var i = 0', 'i < tags.length', 'i++', [ |
| - js('init.interceptorsByTag[tags[i]] = constructor'), |
| - js('init.leafTags[tags[i]] = true')])]), |
| - js.if_('nativeSpec[1]', [ |
| - js('tags = nativeSpec[1].split("|")'), |
| - optional(true, // User subclassing of native classes? |
| - js.if_('nativeSpec[2]', [ |
| - js('var subclasses = nativeSpec[2].split("|")'), |
| - js.for_('var i = 0', 'i < subclasses.length', 'i++', [ |
| - js('var subclass = allClasses[subclasses[i]]'), |
| - js('subclass.\$nativeSuperclassTag = ' |
| - 'tags[0]')])])), |
| - js.for_('i = 0', 'i < tags.length', 'i++', [ |
| - js('init.interceptorsByTag[tags[i]] = constructor'), |
| - js('init.leafTags[tags[i]] = false')])])])) |
| - ]); |
| - |
| - return new jsAst.FunctionDeclaration( |
| - new jsAst.VariableDeclaration('finishClass'), |
| - fun); |
| + if (hasOwnProperty.call(prototype, $specProperty)) { |
| + var nativeSpec = prototype[$specProperty].split(";"); |
| + if (nativeSpec[0]) { |
| + var tags = nativeSpec[0].split("|"); |
| + for (var i = 0; i < tags.length; i++) { |
| + init.interceptorsByTag[tags[i]] = constructor; |
| + init.leafTags[tags[i]] = true; |
| + } |
| + } |
| + if (nativeSpec[1]) { |
| + tags = nativeSpec[1].split("|"); |
| + if (#) { // User subclassing of native classes? |
| + if (nativeSpec[2]) { |
| + var subclasses = nativeSpec[2].split("|"); |
| + for (var i = 0; i < subclasses.length; i++) { |
| + var subclass = allClasses[subclasses[i]]; |
| + subclass.\$nativeSuperclassTag = tags[0]; |
| + } |
| + } |
| + for (i = 0; i < tags.length; i++) { |
| + init.interceptorsByTag[tags[i]] = constructor; |
| + init.leafTags[tags[i]] = false; |
| + } |
| + } |
| + } |
| + } |
| + } |
| + }''', [!nativeClasses.isEmpty, true]); |
| } |
| jsAst.Fun get finishIsolateConstructorFunction { |
| @@ -540,80 +536,57 @@ class CodeEmitterTask extends CompilerTask { |
| Isolate.prototype = oldIsolate.prototype; |
| Isolate.prototype.constructor = Isolate; |
| Isolate.${namer.isolatePropertiesName} = isolateProperties; |
| - # |
| - # |
| + if (#) |
| + Isolate.$finishClassesProperty = oldIsolate.$finishClassesProperty; |
| + if (#) |
| + Isolate.makeConstantList = oldIsolate.makeConstantList; |
| return Isolate; |
| }''', |
| - [ optional(needsDefineClass, |
| - js('Isolate.$finishClassesProperty =' |
| - ' oldIsolate.$finishClassesProperty')), |
| - optional(hasMakeConstantList, |
| - js('Isolate.makeConstantList = oldIsolate.makeConstantList')) |
| - ]); |
| + [ needsDefineClass, hasMakeConstantList ]); |
| } |
| jsAst.Fun get lazyInitializerFunction { |
| - // function(prototype, staticName, fieldName, getterName, lazyValue) { |
| - var parameters = <String>['prototype', 'staticName', 'fieldName', |
| - 'getterName', 'lazyValue']; |
| - return js.fun(parameters, addLazyInitializerLogic()); |
| - } |
| - |
| - List addLazyInitializerLogic() { |
| String isolate = namer.currentIsolate; |
| String cyclicThrow = namer.isolateAccess(backend.getCyclicThrowHelper()); |
| - var lazies = []; |
| - if (backend.rememberLazies) { |
| - lazies = [ |
| - js.if_('!init.lazies', js('init.lazies = {}')), |
| - js('init.lazies[fieldName] = getterName')]; |
| - } |
| - return lazies..addAll([ |
| - js('var sentinelUndefined = {}'), |
| - js('var sentinelInProgress = {}'), |
| - js('prototype[fieldName] = sentinelUndefined'), |
| - |
| - // prototype[getterName] = function() |
| - js('prototype[getterName] = #', js.fun([], [ |
| - js('var result = $isolate[fieldName]'), |
| - |
| - // try |
| - js.try_([ |
| - js.if_('result === sentinelUndefined', [ |
| - js('$isolate[fieldName] = sentinelInProgress'), |
| - |
| - // try |
| - js.try_([ |
| - js('result = $isolate[fieldName] = lazyValue()'), |
| - |
| - ], finallyPart: [ |
| - // Use try-finally, not try-catch/throw as it destroys the |
| - // stack trace. |
| - |
| - // if (result === sentinelUndefined) |
| - js.if_('result === sentinelUndefined', [ |
| - // if ($isolate[fieldName] === sentinelInProgress) |
| - js.if_('$isolate[fieldName] === sentinelInProgress', [ |
| - js('$isolate[fieldName] = null'), |
| - ]) |
| - ]) |
| - ]) |
| - ], /* else */ [ |
| - js.if_('result === sentinelInProgress', |
| - js('$cyclicThrow(staticName)') |
| - ) |
| - ]), |
| - |
| - // return result; |
| - js.return_('result') |
| - |
| - ], finallyPart: [ |
| - js('$isolate[getterName] = #', |
| - js.fun([], [js.return_('this[fieldName]')])) |
| - ]) |
| - ])) |
| - ]); |
| + return js(''' |
| + function (prototype, staticName, fieldName, getterName, lazyValue) { |
| + if (#) { |
| + if (!init.lazies) init.lazies = {}; |
| + init.lazies[fieldName] = getterName; |
| + } |
| + |
| + var sentinelUndefined = {}; |
| + var sentinelInProgress = {}; |
| + prototype[fieldName] = sentinelUndefined; |
| + |
| + prototype[getterName] = function () { |
| + var result = $isolate[fieldName]; |
| + try { |
| + if (result === sentinelUndefined) { |
| + $isolate[fieldName] = sentinelInProgress; |
| + |
| + try { |
| + result = $isolate[fieldName] = lazyValue(); |
| + } finally { |
| + // Use try-finally, not try-catch/throw as it destroys the |
| + // stack trace. |
| + if (result === sentinelUndefined) |
| + if ($isolate[fieldName] === sentinelInProgress) |
| + $isolate[fieldName] = null; |
| + } |
| + } else { |
| + if (result === sentinelInProgress) |
| + $cyclicThrow(staticName); |
| + } |
| + |
| + return result; |
| + } finally { |
| + $isolate[getterName] = function() { return this[fieldName]; }; |
| + } |
| + } |
| + } |
| + ''', [backend.rememberLazies]); |
| } |
| List buildDefineClassAndFinishClassFunctionsIfNecessary() { |
| @@ -628,7 +601,7 @@ class CodeEmitterTask extends CompilerTask { |
| List buildLazyInitializerFunctionIfNecessary() { |
| if (!needsLazyInitializer) return []; |
| - return [js('$lazyInitializerName = #', lazyInitializerFunction)]; |
| + return [js('# = #', [js(lazyInitializerName), lazyInitializerFunction])]; |
|
floitsch
2014/04/22 16:11:18
lazyInitializerName is a string. Do you have to ru
sra1
2014/04/23 02:33:50
It is a String, but it is not an identifier: "Isol
|
| } |
| List buildFinishIsolateConstructor() { |
| @@ -760,14 +733,14 @@ class CodeEmitterTask extends CompilerTask { |
| jsAst.FunctionDeclaration buildPrecompiledFunction() { |
| // TODO(ahe): Compute a hash code. |
| String name = 'dart_precompiled'; |
| - |
| - precompiledFunction.add( |
| - js.return_( |
| - new jsAst.ArrayInitializer.from(precompiledConstructorNames))); |
| - precompiledFunction.insert(0, js(r'var $desc')); |
| - return new jsAst.FunctionDeclaration( |
| - new jsAst.VariableDeclaration(name), |
| - js.fun([r'$collectedClasses'], precompiledFunction)); |
| + return js.statement(''' |
|
floitsch
2014/04/22 16:11:18
This should not be cached.
Write TODO, that this s
sra1
2014/04/23 02:33:50
The name is dart_precompiled, from the previous li
|
| + function $name(\$collectedClasses) { |
| + var \$desc; |
| + #; |
| + return #; |
| + }''', [ |
| + precompiledFunction, |
| + new jsAst.ArrayInitializer.from(precompiledConstructorNames)]); |
| } |
| void generateClass(ClassElement classElement, ClassBuilder properties) { |
| @@ -858,8 +831,9 @@ class CodeEmitterTask extends CompilerTask { |
| compiler.withCurrentElement(element, () { |
| Constant initialValue = handler.getInitialValueFor(element); |
| jsAst.Expression init = |
| - js('$isolateProperties.${namer.getNameOfGlobalField(element)} = #', |
| - constantEmitter.referenceInInitializationContext(initialValue)); |
| + js('$isolateProperties.# = #', |
| + [namer.getNameOfGlobalField(element), |
| + constantEmitter.referenceInInitializationContext(initialValue)]); |
| buffer.write(jsAst.prettyPrint(init, compiler)); |
| buffer.write('$N'); |
| }); |
| @@ -883,17 +857,15 @@ class CodeEmitterTask extends CompilerTask { |
| // lazyInitializer(prototype, 'name', fieldName, getterName, initial); |
| // The name is used for error reporting. The 'initial' must be a |
| // closure that constructs the initial value. |
| - List<jsAst.Expression> arguments = <jsAst.Expression>[]; |
| - arguments.add(js(isolateProperties)); |
| - arguments.add(js.string(element.name)); |
| - arguments.add(js.string(namer.getNameX(element))); |
| - arguments.add(js.string(namer.getLazyInitializerName(element))); |
| - arguments.add(code); |
| jsAst.Expression getter = buildLazyInitializedGetter(element); |
| - if (getter != null) { |
| - arguments.add(getter); |
| - } |
| - jsAst.Expression init = js(lazyInitializerName)(arguments); |
| + jsAst.Expression init = js('#(#,#,#,#,#,#)', |
| + [js(lazyInitializerName), |
|
floitsch
2014/04/22 16:11:18
lazyInitializerName is a String. Why do we need to
sra1
2014/04/23 02:33:50
It is "Isolate.$lazy"
Only strings in the form of
|
| + js(isolateProperties), |
| + js.string(element.name), |
| + js.string(namer.getNameX(element)), |
| + js.string(namer.getLazyInitializerName(element)), |
| + code, |
| + getter == null ? [] : [getter]]); |
| buffer.write(jsAst.prettyPrint(init, compiler)); |
| buffer.write("$N"); |
| } |
| @@ -928,9 +900,9 @@ class CodeEmitterTask extends CompilerTask { |
| String name = namer.constantName(constant); |
| if (constant.isList) emitMakeConstantListIfNotEmitted(buffer); |
| - jsAst.Expression init = js( |
| - '${namer.globalObjectForConstant(constant)}.$name = #', |
| - constantInitializerExpression(constant)); |
| + jsAst.Expression init = js('#.# = #', |
| + [namer.globalObjectForConstant(constant), name, |
| + constantInitializerExpression(constant)]); |
| buffer.write(jsAst.prettyPrint(init, compiler)); |
| buffer.write('$N'); |
| } |
| @@ -1194,15 +1166,15 @@ class CodeEmitterTask extends CompilerTask { |
| } |
| void emitInitFunction(CodeBuffer buffer) { |
| - jsAst.Fun fun = js.fun([], [ |
| - js('$isolateProperties = {}'), |
| - ] |
| - ..addAll(buildDefineClassAndFinishClassFunctionsIfNecessary()) |
| - ..addAll(buildLazyInitializerFunctionIfNecessary()) |
| - ..addAll(buildFinishIsolateConstructor()) |
| - ); |
| - jsAst.FunctionDeclaration decl = new jsAst.FunctionDeclaration( |
| - new jsAst.VariableDeclaration('init'), fun); |
| + jsAst.FunctionDeclaration decl = js.statement(''' |
| + function init() { |
| + $isolateProperties = {}; |
| + #; #; #; |
| + }''', [ |
| + buildDefineClassAndFinishClassFunctionsIfNecessary(), |
| + buildLazyInitializerFunctionIfNecessary(), |
| + buildFinishIsolateConstructor()]); |
| + |
| buffer.write(jsAst.prettyPrint(decl, compiler).getText()); |
| if (compiler.enableMinification) buffer.write('\n'); |
| } |
| @@ -1389,7 +1361,7 @@ mainBuffer.add(r''' |
| var map = new jsAst.ObjectInitializer(properties); |
| mainBuffer.write( |
| jsAst.prettyPrint( |
| - js('init.mangledNames = #', map).toStatement(), compiler)); |
| + js.statement('init.mangledNames = #', map), compiler)); |
| if (compiler.enableMinification) { |
| mainBuffer.write(';'); |
| } |
| @@ -1405,7 +1377,7 @@ mainBuffer.add(r''' |
| var map = new jsAst.ObjectInitializer(properties); |
| mainBuffer.write( |
| jsAst.prettyPrint( |
| - js('init.mangledGlobalNames = #', map).toStatement(), |
| + js.statement('init.mangledGlobalNames = #', map), |
| compiler)); |
| if (compiler.enableMinification) { |
| mainBuffer.write(';'); |