Chromium Code Reviews| Index: sdk/lib/_internal/compiler/implementation/js_emitter/nsm_emitter.dart |
| diff --git a/sdk/lib/_internal/compiler/implementation/js_emitter/nsm_emitter.dart b/sdk/lib/_internal/compiler/implementation/js_emitter/nsm_emitter.dart |
| index c298c5709861b6693c6e4c76b2c19688b2435630..0173cd9e4b7410884a397ec876e83fec9093f660 100644 |
| --- a/sdk/lib/_internal/compiler/implementation/js_emitter/nsm_emitter.dart |
| +++ b/sdk/lib/_internal/compiler/implementation/js_emitter/nsm_emitter.dart |
| @@ -63,10 +63,8 @@ class NsmEmitter extends CodeEmitterHelper { |
| jsAst.Expression generateMethod(String jsName, Selector selector) { |
| // Values match JSInvocationMirror in js-helper library. |
| int type = selector.invocationMirrorKind; |
| - List<jsAst.Parameter> parameters = <jsAst.Parameter>[]; |
| - for (int i = 0; i < selector.argumentCount; i++) { |
| - parameters.add(new jsAst.Parameter('\$$i')); |
| - } |
| + List<String> parameterNames = |
| + new List.generate(selector.argumentCount, (i) => '\$$i'); |
| List<jsAst.Expression> argNames = |
| selector.getOrderedNamedArguments().map((String name) => |
| @@ -83,20 +81,21 @@ class NsmEmitter extends CodeEmitterHelper { |
| } |
| assert(backend.isInterceptedName(Compiler.NO_SUCH_METHOD)); |
| - jsAst.Expression expression = js('this.$noSuchMethodName')( |
| - [js('this'), |
| - namer.elementAccess(backend.getCreateInvocationMirror())([ |
| - js.string(compiler.enableMinification ? |
| - internalName : methodName), |
| - js.string(internalName), |
| - type, |
| - new jsAst.ArrayInitializer.from( |
| - parameters.map((param) => js(param.name)).toList()), |
| - new jsAst.ArrayInitializer.from(argNames)])]); |
| - parameters = backend.isInterceptedName(selector.name) |
| - ? ([new jsAst.Parameter('\$receiver')]..addAll(parameters)) |
| - : parameters; |
| - return js.fun(parameters, js.return_(expression)); |
| + jsAst.Expression expression = js('this.#(this, #(#, #, #, #, #))', [ |
| + noSuchMethodName, |
| + namer.elementAccess(backend.getCreateInvocationMirror()), |
| + js.string(compiler.enableMinification ? |
| + internalName : methodName), |
| + js.string(internalName), |
| + js.number(type), |
| + new jsAst.ArrayInitializer.from(parameterNames.map(js)), |
| + new jsAst.ArrayInitializer.from(argNames)]); |
| + |
| + if (backend.isInterceptedName(selector.name)) { |
| + return js(r'function($receiver, #) { return # }', [parameterNames, expression]); |
|
floitsch
2014/04/22 16:11:18
long line.
sra1
2014/04/23 02:33:50
Done.
|
| + } else { |
| + return js(r'function(#) { return # }', [parameterNames, expression]); |
| + } |
| } |
| for (String jsName in addedJsNames.keys.toList()..sort()) { |
| @@ -176,8 +175,9 @@ class NsmEmitter extends CodeEmitterHelper { |
| * they are called with the receiver as the first argument). They need a |
| * slightly different noSuchMethod handler, so we handle these first. |
| */ |
| - void addTrivialNsmHandlers(List<jsAst.Node> statements) { |
| - if (trivialNsmHandlers.length == 0) return; |
| + List<jsAst.Statement> buildTrivialNsmHandlers() { |
| + List<jsAst.Statement> statements = <jsAst.Statement>[]; |
| + if (trivialNsmHandlers.length == 0) return statements; |
| // Sort by calling convention, JS name length and by JS name. |
| trivialNsmHandlers.sort((a, b) { |
| bool aIsIntercepted = backend.isInterceptedName(a.name); |
| @@ -268,106 +268,120 @@ class NsmEmitter extends CodeEmitterHelper { |
| // Startup code that loops over the method names and puts handlers on the |
| // Object class to catch noSuchMethod invocations. |
| ClassElement objectClass = compiler.objectClass; |
| - String createInvocationMirror = namer.isolateAccess( |
| + jsAst.Expression createInvocationMirror = namer.elementAccess( |
| backend.getCreateInvocationMirror()); |
| String noSuchMethodName = namer.publicInstanceMethodNameByArity( |
| Compiler.NO_SUCH_METHOD, Compiler.NO_SUCH_METHOD_ARG_COUNT); |
| var type = 0; |
| if (useDiffEncoding) { |
| - statements.addAll([ |
| - js('var objectClassObject = ' |
| - ' collectedClasses["${namer.getNameOfClass(objectClass)}"],' |
| - ' shortNames = "$diffEncoding".split(","),' |
| - ' nameNumber = 0,' |
| - ' diffEncodedString = shortNames[0],' |
| - ' calculatedShortNames = [0, 1]'), // 0, 1 are args for splice. |
| - // If we are loading a deferred library the object class will not be in |
| - // the collectedClasses so objectClassObject is undefined, and we skip |
| - // setting up the names. |
| - js.if_('objectClassObject', [ |
| - js.if_('objectClassObject instanceof Array', |
| - js('objectClassObject = objectClassObject[1]')), |
| - js.for_('var i = 0', 'i < diffEncodedString.length', 'i++', [ |
| - js('var codes = [],' |
| - ' diff = 0,' |
| - ' digit = diffEncodedString.charCodeAt(i)'), |
| - js.if_('digit == ${$PERIOD}', [ |
| - js('nameNumber = 0'), |
| - js('digit = diffEncodedString.charCodeAt(++i)') |
| - ]), |
| - js.while_('digit <= ${$Z}', [ |
| - js('diff *= 26'), |
| - js('diff += (digit - ${$A})'), |
| - js('digit = diffEncodedString.charCodeAt(++i)') |
| - ]), |
| - js('diff *= 26'), |
| - js('diff += (digit - ${$a})'), |
| - js('nameNumber += diff'), |
| - js.for_('var remaining = nameNumber', |
| - 'remaining > 0', |
| - 'remaining = (remaining / 88) | 0', [ |
| - js('codes.unshift(${$HASH} + remaining % 88)') |
| - ]), |
| - js('calculatedShortNames.push(' |
| - ' String.fromCharCode.apply(String, codes))') |
| - ]), |
| - js('shortNames.splice.apply(shortNames, calculatedShortNames)')]) |
| - ]); |
| + statements.add(js.statement('''{ |
| + var objectClassObject = |
| + collectedClasses[#], // # is name of class Object. |
| + shortNames = #.split(","), // # is diffEncoding. |
| + nameNumber = 0, |
| + diffEncodedString = shortNames[0], |
| + calculatedShortNames = [0, 1]; // 0, 1 are args for splice. |
| + // If we are loading a deferred library the object class will not be in |
|
floitsch
2014/04/22 16:11:18
long line.
|
| + // the collectedClasses so objectClassObject is undefined, and we skip |
| + // setting up the names. |
| + |
| + if (objectClassObject) { |
| + if (objectClassObject instanceof Array) |
| + objectClassObject = objectClassObject[1]; |
| + for (var i = 0; i < diffEncodedString.length; i++) { |
| + var codes = [], |
| + diff = 0, |
| + digit = diffEncodedString.charCodeAt(i); |
| + if (digit == ${$PERIOD}) { |
| + nameNumber = 0; |
| + digit = diffEncodedString.charCodeAt(++i); |
| + } |
| + for (; digit <= ${$Z};) { |
| + diff *= 26; |
| + diff += (digit - ${$A}); |
| + digit = diffEncodedString.charCodeAt(++i); |
| + } |
| + diff *= 26; |
| + diff += (digit - ${$a}); |
| + nameNumber += diff; |
| + for (var remaining = nameNumber; |
| + remaining > 0; |
| + remaining = (remaining / 88) | 0) { |
| + codes.unshift(${$HASH} + remaining % 88); |
| + } |
| + calculatedShortNames.push( |
| + String.fromCharCode.apply(String, codes)); |
| + } |
| + shortNames.splice.apply(shortNames, calculatedShortNames); |
| + } |
| + }''', [ |
| + js.string(namer.getNameOfClass(objectClass)), |
| + js.string('$diffEncoding')])); |
| } else { |
| // No useDiffEncoding version. |
| Iterable<String> longs = trivialNsmHandlers.map((selector) => |
| selector.invocationMirrorMemberName); |
| - String longNamesConstant = minify ? "" : |
| - ',longNames = "${longs.join(",")}".split(",")'; |
| - statements.add( |
| - js('var objectClassObject = ' |
| - ' collectedClasses["${namer.getNameOfClass(objectClass)}"],' |
| - ' shortNames = "$diffEncoding".split(",")' |
| - ' $longNamesConstant')); |
| - statements.add( |
| - js.if_('objectClassObject instanceof Array', |
| - js('objectClassObject = objectClassObject[1]'))); |
| + statements.add(js.statement( |
| + 'var objectClassObject = collectedClasses[#],' |
| + ' shortNames = #.split(",")', [ |
| + js.string(namer.getNameOfClass(objectClass)), |
| + js.string('$diffEncoding')])); |
| + if (!minify) { |
| + statements.add(js.statement('var longNames = #.split(",")', |
| + js.string(longs.join(',')))); |
| + } |
| + statements.add(js.statement( |
| + 'if (objectClassObject instanceof Array)' |
| + ' objectClassObject = objectClassObject[1];')); |
| } |
| - String sliceOffset = ', (j < $firstNormalSelector) ? 1 : 0'; |
| - if (firstNormalSelector == 0) sliceOffset = ''; |
| - if (firstNormalSelector == shorts.length) sliceOffset = ', 1'; |
| - |
| + // TODO(9631): This is no longer valid for native methods. |
| String whatToPatch = task.nativeEmitter.handleNoSuchMethod ? |
| "Object.prototype" : |
| "objectClassObject"; |
| - var params = ['name', 'short', 'type']; |
| - var sliceOffsetParam = ''; |
| - var slice = 'Array.prototype.slice.call'; |
| - if (!sliceOffset.isEmpty) { |
| - sliceOffsetParam = ', sliceOffset'; |
| - params.add('sliceOffset'); |
| - } |
| - statements.addAll([ |
| + List<jsAst.Expression> sliceOffsetArguments = |
| + firstNormalSelector == 0 |
| + ? [] |
| + : (firstNormalSelector == shorts.length |
| + ? [js.number(1)] |
| + : [js('(j < #) ? 1 : 0', js.number(firstNormalSelector))]); |
| + |
| + var sliceOffsetParams = sliceOffsetArguments.isEmpty ? [] : ['sliceOffset']; |
| + |
| + statements.add(js.statement(''' |
| // If we are loading a deferred library the object class will not be in |
| // the collectedClasses so objectClassObject is undefined, and we skip |
| // setting up the names. |
| - js.if_('objectClassObject', [ |
| - js.for_('var j = 0', 'j < shortNames.length', 'j++', [ |
| - js('var type = 0'), |
| - js('var short = shortNames[j]'), |
| - js.if_('short[0] == "${namer.getterPrefix[0]}"', js('type = 1')), |
| - js.if_('short[0] == "${namer.setterPrefix[0]}"', js('type = 2')), |
| + if (objectClassObject) { |
| + for (var j = 0; j < shortNames.length; j++) { |
| + var type = 0; |
| + var short = shortNames[j]; |
| + if (short[0] == "${namer.getterPrefix[0]}") type = 1; |
| + if (short[0] == "${namer.setterPrefix[0]}") type = 2; |
| // Generate call to: |
| - // createInvocationMirror(String name, internalName, type, arguments, |
| - // argumentNames) |
| - js('$whatToPatch[short] = #(${minify ? "shortNames" : "longNames"}[j], ' |
| - 'short, type$sliceOffset)', |
| - js.fun(params, [js.return_(js.fun([], |
| - [js.return_(js( |
| - 'this.$noSuchMethodName(' |
| - 'this, ' |
| - '$createInvocationMirror(' |
| - 'name, short, type, ' |
| - '$slice(arguments$sliceOffsetParam), []))'))]))])) |
| - ]) |
| - ]) |
| - ]); |
| + // |
| + // createInvocationMirror(String name, internalName, type, |
| + // arguments, argumentNames) |
| + // |
| + $whatToPatch[short] = (function(name, short, type, #) { |
| + return function() { |
| + return this.#(this, |
| + #(name, short, type, |
| + Array.prototype.slice.call(arguments, #), |
| + [])); |
| + } |
| + })(#[j], short, type, #); |
| + } |
| + }''', [ |
| + sliceOffsetParams, // parameter |
| + noSuchMethodName, |
| + createInvocationMirror, |
| + sliceOffsetParams, // argument to slice |
| + minify ? 'shortNames' : 'longNames', |
| + sliceOffsetArguments |
| + ])); |
| + |
| + return statements; |
| } |
| } |