Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1542)

Unified Diff: sdk/lib/_internal/compiler/implementation/js_emitter/old_emitter/nsm_emitter.dart

Issue 694353007: Move dart2js from sdk/lib/_internal/compiler to pkg/compiler (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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;
- }
-}

Powered by Google App Engine
This is Rietveld 408576698