| Index: sdk/lib/_internal/compiler/implementation/js_emitter/old_emitter/nsm_emitter.dart
|
| diff --git a/sdk/lib/_internal/compiler/implementation/js_emitter/old_emitter/nsm_emitter.dart b/sdk/lib/_internal/compiler/implementation/js_emitter/old_emitter/nsm_emitter.dart
|
| deleted file mode 100644
|
| index 36351753178ceaa3a55188d735f60c55d933901e..0000000000000000000000000000000000000000
|
| --- a/sdk/lib/_internal/compiler/implementation/js_emitter/old_emitter/nsm_emitter.dart
|
| +++ /dev/null
|
| @@ -1,388 +0,0 @@
|
| -// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
|
| -// for details. All rights reserved. Use of this source code is governed by a
|
| -// BSD-style license that can be found in the LICENSE file.
|
| -
|
| -part of dart2js.js_emitter;
|
| -
|
| -class NsmEmitter extends CodeEmitterHelper {
|
| - final List<Selector> trivialNsmHandlers = <Selector>[];
|
| -
|
| - /// If this is true then we can generate the noSuchMethod handlers at startup
|
| - /// time, instead of them being emitted as part of the Object class.
|
| - bool get generateTrivialNsmHandlers => true;
|
| -
|
| - // If we need fewer than this many noSuchMethod handlers we can save space by
|
| - // just emitting them in JS, rather than emitting the JS needed to generate
|
| - // them at run time.
|
| - static const VERY_FEW_NO_SUCH_METHOD_HANDLERS = 10;
|
| -
|
| - static const MAX_MINIFIED_LENGTH_FOR_DIFF_ENCODING = 4;
|
| -
|
| - void emitNoSuchMethodHandlers(AddPropertyFunction addProperty) {
|
| - // Do not generate no such method handlers if there is no class.
|
| - if (compiler.codegenWorld.directlyInstantiatedClasses.isEmpty) return;
|
| -
|
| - String noSuchMethodName = namer.publicInstanceMethodNameByArity(
|
| - Compiler.NO_SUCH_METHOD, Compiler.NO_SUCH_METHOD_ARG_COUNT);
|
| -
|
| - // Keep track of the JavaScript names we've already added so we
|
| - // do not introduce duplicates (bad for code size).
|
| - Map<String, Selector> addedJsNames = new Map<String, Selector>();
|
| -
|
| - void addNoSuchMethodHandlers(String ignore, Set<Selector> selectors) {
|
| - // Cache the object class and type.
|
| - ClassElement objectClass = compiler.objectClass;
|
| - DartType objectType = objectClass.rawType;
|
| -
|
| - for (Selector selector in selectors) {
|
| - TypeMask mask = selector.mask;
|
| - if (mask == null) {
|
| - mask = new TypeMask.subclass(compiler.objectClass, compiler.world);
|
| - }
|
| -
|
| - if (!mask.needsNoSuchMethodHandling(selector, compiler.world)) continue;
|
| - String jsName = namer.invocationMirrorInternalName(selector);
|
| - addedJsNames[jsName] = selector;
|
| - String reflectionName = emitter.getReflectionName(selector, jsName);
|
| - if (reflectionName != null) {
|
| - emitter.mangledFieldNames[jsName] = reflectionName;
|
| - }
|
| - }
|
| - }
|
| -
|
| - compiler.codegenWorld.invokedNames.forEach(addNoSuchMethodHandlers);
|
| - compiler.codegenWorld.invokedGetters.forEach(addNoSuchMethodHandlers);
|
| - compiler.codegenWorld.invokedSetters.forEach(addNoSuchMethodHandlers);
|
| -
|
| - // Set flag used by generateMethod helper below. If we have very few
|
| - // handlers we use addProperty for them all, rather than try to generate
|
| - // them at runtime.
|
| - bool haveVeryFewNoSuchMemberHandlers =
|
| - (addedJsNames.length < VERY_FEW_NO_SUCH_METHOD_HANDLERS);
|
| -
|
| - 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.Expression> argNames =
|
| - selector.getOrderedNamedArguments().map((String name) =>
|
| - js.string(name)).toList();
|
| -
|
| - String methodName = selector.invocationMirrorMemberName;
|
| - String internalName = namer.invocationMirrorInternalName(selector);
|
| - String reflectionName = emitter.getReflectionName(selector, internalName);
|
| - if (!haveVeryFewNoSuchMemberHandlers &&
|
| - isTrivialNsmHandler(type, argNames, selector, internalName) &&
|
| - reflectionName == null) {
|
| - trivialNsmHandlers.add(selector);
|
| - return null;
|
| - }
|
| -
|
| - 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]);
|
| - }
|
| - }
|
| -
|
| - for (String jsName in addedJsNames.keys.toList()..sort()) {
|
| - Selector selector = addedJsNames[jsName];
|
| - jsAst.Expression method = generateMethod(jsName, selector);
|
| - if (method != null) {
|
| - addProperty(jsName, method);
|
| - String reflectionName = emitter.getReflectionName(selector, jsName);
|
| - if (reflectionName != null) {
|
| - bool accessible = compiler.world.allFunctions.filter(selector).any(
|
| - (Element e) => backend.isAccessibleByReflection(e));
|
| - addProperty('+$reflectionName', js(accessible ? '2' : '0'));
|
| - }
|
| - }
|
| - }
|
| - }
|
| -
|
| - // Identify the noSuchMethod handlers that are so simple that we can
|
| - // generate them programatically.
|
| - bool isTrivialNsmHandler(
|
| - int type, List argNames, Selector selector, String internalName) {
|
| - if (!generateTrivialNsmHandlers) return false;
|
| - // Check for interceptor calling convention.
|
| - if (backend.isInterceptedName(selector.name)) {
|
| - // We can handle the calling convention used by intercepted names in the
|
| - // diff encoding, but we don't use that for non-minified code.
|
| - if (!compiler.enableMinification) return false;
|
| - String shortName = namer.invocationMirrorInternalName(selector);
|
| - if (shortName.length > MAX_MINIFIED_LENGTH_FOR_DIFF_ENCODING) {
|
| - return false;
|
| - }
|
| - }
|
| - // Check for named arguments.
|
| - if (argNames.length != 0) return false;
|
| - // Check for unexpected name (this doesn't really happen).
|
| - if (internalName.startsWith(namer.getterPrefix[0])) return type == 1;
|
| - if (internalName.startsWith(namer.setterPrefix[0])) return type == 2;
|
| - return type == 0;
|
| - }
|
| -
|
| - /**
|
| - * Adds (at runtime) the handlers to the Object class which catch calls to
|
| - * methods that the object does not have. The handlers create an invocation
|
| - * mirror object.
|
| - *
|
| - * The current version only gives you the minified name when minifying (when
|
| - * not minifying this method is not called).
|
| - *
|
| - * In order to generate the noSuchMethod handlers we only need the minified
|
| - * name of the method. We test the first character of the minified name to
|
| - * determine if it is a getter or a setter, and we use the arguments array at
|
| - * runtime to get the number of arguments and their values. If the method
|
| - * involves named arguments etc. then we don't handle it here, but emit the
|
| - * handler method directly on the Object class.
|
| - *
|
| - * The minified names are mostly 1-4 character names, which we emit in sorted
|
| - * order (primary key is length, secondary ordering is lexicographic). This
|
| - * gives an order like ... dD dI dX da ...
|
| - *
|
| - * Gzip is good with repeated text, but it can't diff-encode, so we do that
|
| - * for it. We encode the minified names in a comma-separated string, but all
|
| - * the 1-4 character names are encoded before the first comma as a series of
|
| - * base 26 numbers. The last digit of each number is lower case, the others
|
| - * are upper case, so 1 is "b" and 26 is "Ba".
|
| - *
|
| - * We think of the minified names as base 88 numbers using the ASCII
|
| - * characters from # to z. The base 26 numbers each encode the delta from
|
| - * the previous minified name to the next. So if there is a minified name
|
| - * called Df and the next is Dh, then they are 2971 and 2973 when thought of
|
| - * as base 88 numbers. The difference is 2, which is "c" in lower-case-
|
| - * terminated base 26.
|
| - *
|
| - * The reason we don't encode long minified names with this method is that
|
| - * decoding the base 88 numbers would overflow JavaScript's puny integers.
|
| - *
|
| - * There are some selectors that have a special calling convention (because
|
| - * 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;
|
| - // Sort by calling convention, JS name length and by JS name.
|
| - trivialNsmHandlers.sort((a, b) {
|
| - bool aIsIntercepted = backend.isInterceptedName(a.name);
|
| - bool bIsIntercepted = backend.isInterceptedName(b.name);
|
| - if (aIsIntercepted != bIsIntercepted) return aIsIntercepted ? -1 : 1;
|
| - String aName = namer.invocationMirrorInternalName(a);
|
| - String bName = namer.invocationMirrorInternalName(b);
|
| - if (aName.length != bName.length) return aName.length - bName.length;
|
| - return aName.compareTo(bName);
|
| - });
|
| -
|
| - // Find out how many selectors there are with the special calling
|
| - // convention.
|
| - int firstNormalSelector = trivialNsmHandlers.length;
|
| - for (int i = 0; i < trivialNsmHandlers.length; i++) {
|
| - if (!backend.isInterceptedName(trivialNsmHandlers[i].name)) {
|
| - firstNormalSelector = i;
|
| - break;
|
| - }
|
| - }
|
| -
|
| - // Get the short names (JS names, perhaps minified).
|
| - Iterable<String> shorts = trivialNsmHandlers.map((selector) =>
|
| - namer.invocationMirrorInternalName(selector));
|
| - final diffShorts = <String>[];
|
| - var diffEncoding = new StringBuffer();
|
| -
|
| - // Treat string as a number in base 88 with digits in ASCII order from # to
|
| - // z. The short name sorting is based on length, and uses ASCII order for
|
| - // equal length strings so this means that names are ascending. The hash
|
| - // character, #, is never given as input, but we need it because it's the
|
| - // implicit leading zero (otherwise we could not code names with leading
|
| - // dollar signs).
|
| - int fromBase88(String x) {
|
| - int answer = 0;
|
| - for (int i = 0; i < x.length; i++) {
|
| - int c = x.codeUnitAt(i);
|
| - // No support for Unicode minified identifiers in JS.
|
| - assert(c >= $$ && c <= $z);
|
| - answer *= 88;
|
| - answer += c - $HASH;
|
| - }
|
| - return answer;
|
| - }
|
| -
|
| - // Big endian encoding, A = 0, B = 1...
|
| - // A lower case letter terminates the number.
|
| - String toBase26(int x) {
|
| - int c = x;
|
| - var encodingChars = <int>[];
|
| - encodingChars.add($a + (c % 26));
|
| - while (true) {
|
| - c ~/= 26;
|
| - if (c == 0) break;
|
| - encodingChars.add($A + (c % 26));
|
| - }
|
| - return new String.fromCharCodes(encodingChars.reversed.toList());
|
| - }
|
| -
|
| - bool minify = compiler.enableMinification;
|
| - bool useDiffEncoding = minify && shorts.length > 30;
|
| -
|
| - int previous = 0;
|
| - int nameCounter = 0;
|
| - for (String short in shorts) {
|
| - // Emit period that resets the diff base to zero when we switch to normal
|
| - // calling convention (this avoids the need to code negative diffs).
|
| - if (useDiffEncoding && nameCounter == firstNormalSelector) {
|
| - diffEncoding.write(".");
|
| - previous = 0;
|
| - }
|
| - if (short.length <= MAX_MINIFIED_LENGTH_FOR_DIFF_ENCODING &&
|
| - useDiffEncoding) {
|
| - int base63 = fromBase88(short);
|
| - int diff = base63 - previous;
|
| - previous = base63;
|
| - String base26Diff = toBase26(diff);
|
| - diffEncoding.write(base26Diff);
|
| - } else {
|
| - if (useDiffEncoding || diffEncoding.length != 0) {
|
| - diffEncoding.write(",");
|
| - }
|
| - diffEncoding.write(short);
|
| - }
|
| - nameCounter++;
|
| - }
|
| -
|
| - // 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(
|
| - 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')]));
|
| - } 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];'));
|
| - }
|
| -
|
| - // TODO(9631): This is no longer valid for native methods.
|
| - String whatToPatch = emitter.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('''
|
| - // 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;
|
| - // 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;
|
| - }
|
| -}
|
|
|