| 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 0ec41fbb37c8c04499b232fbf0cfbc79dc9c65c9..c298c5709861b6693c6e4c76b2c19688b2435630 100644
|
| --- a/sdk/lib/_internal/compiler/implementation/js_emitter/nsm_emitter.dart
|
| +++ b/sdk/lib/_internal/compiler/implementation/js_emitter/nsm_emitter.dart
|
| @@ -63,8 +63,10 @@ class NsmEmitter extends CodeEmitterHelper {
|
| jsAst.Expression generateMethod(String jsName, Selector selector) {
|
| // Values match JSInvocationMirror in js-helper library.
|
| int type = selector.invocationMirrorKind;
|
| - List<String> parameterNames =
|
| - new List.generate(selector.argumentCount, (i) => '\$$i');
|
| + List<jsAst.Parameter> parameters = <jsAst.Parameter>[];
|
| + for (int i = 0; i < selector.argumentCount; i++) {
|
| + parameters.add(new jsAst.Parameter('\$$i'));
|
| + }
|
|
|
| List<jsAst.Expression> argNames =
|
| selector.getOrderedNamedArguments().map((String name) =>
|
| @@ -81,22 +83,20 @@ class NsmEmitter extends CodeEmitterHelper {
|
| }
|
|
|
| assert(backend.isInterceptedName(Compiler.NO_SUCH_METHOD));
|
| - 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]);
|
| - } else {
|
| - return js(r'function(#) { return # }', [parameterNames, expression]);
|
| - }
|
| + 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));
|
| }
|
|
|
| for (String jsName in addedJsNames.keys.toList()..sort()) {
|
| @@ -176,9 +176,8 @@ 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.
|
| */
|
| - List<jsAst.Statement> buildTrivialNsmHandlers() {
|
| - List<jsAst.Statement> statements = <jsAst.Statement>[];
|
| - if (trivialNsmHandlers.length == 0) return statements;
|
| + void addTrivialNsmHandlers(List<jsAst.Node> statements) {
|
| + if (trivialNsmHandlers.length == 0) return;
|
| // Sort by calling convention, JS name length and by JS name.
|
| trivialNsmHandlers.sort((a, b) {
|
| bool aIsIntercepted = backend.isInterceptedName(a.name);
|
| @@ -269,120 +268,106 @@ 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;
|
| - jsAst.Expression createInvocationMirror = namer.elementAccess(
|
| + String createInvocationMirror = namer.isolateAccess(
|
| backend.getCreateInvocationMirror());
|
| String noSuchMethodName = namer.publicInstanceMethodNameByArity(
|
| Compiler.NO_SUCH_METHOD, Compiler.NO_SUCH_METHOD_ARG_COUNT);
|
| var type = 0;
|
| if (useDiffEncoding) {
|
| - 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
|
| - // 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')]));
|
| + 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)')])
|
| + ]);
|
| } else {
|
| // No useDiffEncoding version.
|
| Iterable<String> longs = trivialNsmHandlers.map((selector) =>
|
| selector.invocationMirrorMemberName);
|
| - 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 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]')));
|
| }
|
|
|
| - // TODO(9631): This is no longer valid for native methods.
|
| + String sliceOffset = ', (j < $firstNormalSelector) ? 1 : 0';
|
| + if (firstNormalSelector == 0) sliceOffset = '';
|
| + if (firstNormalSelector == shorts.length) sliceOffset = ', 1';
|
| +
|
| String whatToPatch = task.nativeEmitter.handleNoSuchMethod ?
|
| "Object.prototype" :
|
| "objectClassObject";
|
|
|
| - 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('''
|
| + var params = ['name', 'short', 'type'];
|
| + var sliceOffsetParam = '';
|
| + var slice = 'Array.prototype.slice.call';
|
| + if (!sliceOffset.isEmpty) {
|
| + sliceOffsetParam = ', sliceOffset';
|
| + params.add('sliceOffset');
|
| + }
|
| + statements.addAll([
|
| // 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.
|
| - 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;
|
| + 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')),
|
| // Generate call to:
|
| - //
|
| - // 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;
|
| + // 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), []))'))]))]))
|
| + ])
|
| + ])
|
| + ]);
|
| }
|
| }
|
|
|