| Index: sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart
|
| diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart b/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart
|
| index 4d25e3a6beee49848c4bc94adbf2546da46d74ba..8a1d51734affbbb56b2080bf07c2f19a3a70eccd 100644
|
| --- a/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart
|
| +++ b/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart
|
| @@ -92,50 +92,72 @@ class CodeEmitterTask extends CompilerTask {
|
| String get name => 'CodeEmitter';
|
|
|
| String get defineClassName
|
| - => '${namer.ISOLATE}.\$defineClass';
|
| + => '${namer.isolateName}.\$defineClass';
|
| String get currentGenerateAccessorName
|
| => '${namer.CURRENT_ISOLATE}.\$generateAccessor';
|
| String get generateAccessorHolder
|
| => '$isolatePropertiesName.\$generateAccessor';
|
| String get finishClassesName
|
| - => '${namer.ISOLATE}.\$finishClasses';
|
| + => '${namer.isolateName}.\$finishClasses';
|
| String get finishIsolateConstructorName
|
| - => '${namer.ISOLATE}.\$finishIsolateConstructor';
|
| + => '${namer.isolateName}.\$finishIsolateConstructor';
|
| String get pendingClassesName
|
| - => '${namer.ISOLATE}.\$pendingClasses';
|
| + => '${namer.isolateName}.\$pendingClasses';
|
| String get isolatePropertiesName
|
| - => '${namer.ISOLATE}.${namer.ISOLATE_PROPERTIES}';
|
| + => '${namer.isolateName}.${namer.isolatePropertiesName}';
|
| String get supportsProtoName
|
| => 'supportsProto';
|
| String get lazyInitializerName
|
| - => '${namer.ISOLATE}.\$lazy';
|
| -
|
| - final String GETTER_SUFFIX = "?";
|
| - final String SETTER_SUFFIX = "!";
|
| - final String GETTER_SETTER_SUFFIX = "=";
|
| + => '${namer.isolateName}.\$lazy';
|
| +
|
| + // Property name suffixes. If the accessors are renaming then the format
|
| + // is <accessorName>:<fieldName><suffix>. We use the suffix to know whether
|
| + // to look for the ':' separator in order to avoid doing the indexOf operation
|
| + // on every single property (they are quite rare). None of these characters
|
| + // are legal in an identifier and they are related by bit patterns.
|
| + // setter < 0x3c
|
| + // both = 0x3d
|
| + // getter > 0x3e
|
| + // renaming setter | 0x7c
|
| + // renaming both } 0x7d
|
| + // renaming getter ~ 0x7e
|
| + const SUFFIX_MASK = 0x3f;
|
| + const FIRST_SUFFIX_CODE = 0x3c;
|
| + const SETTER_CODE = 0x3c;
|
| + const GETTER_SETTER_CODE = 0x3d;
|
| + const GETTER_CODE = 0x3e;
|
| + const RENAMING_FLAG = 0x40;
|
| + String needsGetterCode(String variable) => '($variable & 3) > 0';
|
| + String needsSetterCode(String variable) => '($variable & 2) == 0';
|
| + String isRenaming(String variable) => '($variable & $RENAMING_FLAG) != 0';
|
|
|
| String get generateAccessorFunction {
|
| return """
|
| function generateAccessor(field, prototype) {
|
| var len = field.length;
|
| - var lastChar = field[len - 1];
|
| - var needsGetter = lastChar == '$GETTER_SUFFIX' || lastChar == '$GETTER_SETTER_SUFFIX';
|
| - var needsSetter = lastChar == '$SETTER_SUFFIX' || lastChar == '$GETTER_SETTER_SUFFIX';
|
| - if (needsGetter || needsSetter) field = field.substring(0, len - 1);
|
| - if (needsGetter) {
|
| - var getterString = "return this." + field + ";";
|
| -"""
|
| - /* The supportsProtoCheck below depends on the getter/setter convention.
|
| - When changing here, update the protoCheck too. */
|
| - """
|
| - prototype["get\$" + field] = new Function(getterString);
|
| + var lastCharCode = field.charCodeAt(len - 1);
|
| + var needsAccessor = (lastCharCode & $SUFFIX_MASK) >= $FIRST_SUFFIX_CODE;
|
| + if (needsAccessor) {
|
| + var needsGetter = ${needsGetterCode('lastCharCode')};
|
| + var needsSetter = ${needsSetterCode('lastCharCode')};
|
| + var renaming = ${isRenaming('lastCharCode')};
|
| + var accessorName = field = field.substring(0, len - 1);
|
| + if (renaming) {
|
| + var divider = field.indexOf(":");
|
| + accessorName = field.substring(0, divider);
|
| + field = field.substring(divider + 1);
|
| + }
|
| + if (needsGetter) {
|
| + var getterString = "return this." + field + ";";
|
| + prototype["get\$" + accessorName] = new Function(getterString);
|
| }
|
| if (needsSetter) {
|
| var setterString = "this." + field + " = v;";
|
| - prototype["set\$" + field] = new Function("v", setterString);
|
| + prototype["set\$" + accessorName] = new Function("v", setterString);
|
| }
|
| - return field;
|
| - }""";
|
| + }
|
| + return field;
|
| +}""";
|
| }
|
|
|
| String get defineClassFunction {
|
| @@ -193,7 +215,7 @@ var $supportsProtoName = false;
|
| var tmp = $defineClassName('c', ['f?'], {}).prototype;
|
| if (tmp.__proto__) {
|
| tmp.__proto__ = {};
|
| - if (typeof tmp.get\$f !== "undefined") $supportsProtoName = true;
|
| + if (typeof tmp.get\$f !== 'undefined') $supportsProtoName = true;
|
| }
|
| ''';
|
| }
|
| @@ -265,7 +287,7 @@ function(collectedClasses) {
|
| }
|
|
|
| String get finishIsolateConstructorFunction {
|
| - String isolate = namer.ISOLATE;
|
| + String isolate = namer.isolateName;
|
| // We replace the old Isolate function with a new one that initializes
|
| // all its field with the initial (and often final) value of all globals.
|
| // This has two advantages:
|
| @@ -287,10 +309,10 @@ function(collectedClasses) {
|
| // We also copy over old values like the prototype, and the
|
| // isolateProperties themselves.
|
| return """function(oldIsolate) {
|
| - var isolateProperties = oldIsolate.${namer.ISOLATE_PROPERTIES};
|
| + var isolateProperties = oldIsolate.${namer.isolatePropertiesName};
|
| var isolatePrototype = oldIsolate.prototype;
|
| var str = "{\\n";
|
| - str += "var properties = $isolate.${namer.ISOLATE_PROPERTIES};\\n";
|
| + str += "var properties = $isolate.${namer.isolatePropertiesName};\\n";
|
| for (var staticName in isolateProperties) {
|
| if (Object.prototype.hasOwnProperty.call(isolateProperties, staticName)) {
|
| str += "this." + staticName + "= properties." + staticName + ";\\n";
|
| @@ -300,7 +322,7 @@ function(collectedClasses) {
|
| var newIsolate = new Function(str);
|
| newIsolate.prototype = isolatePrototype;
|
| isolatePrototype.constructor = newIsolate;
|
| - newIsolate.${namer.ISOLATE_PROPERTIES} = isolateProperties;
|
| + newIsolate.${namer.isolatePropertiesName} = isolateProperties;
|
| return newIsolate;
|
| }""";
|
| }
|
| @@ -371,7 +393,7 @@ $lazyInitializerLogic
|
| }
|
|
|
| void emitFinishIsolateConstructorInvocation(CodeBuffer buffer) {
|
| - String isolate = namer.ISOLATE;
|
| + String isolate = namer.isolateName;
|
| buffer.add("$isolate = $finishIsolateConstructorName($isolate);\n");
|
| }
|
|
|
| @@ -527,7 +549,7 @@ $lazyInitializerLogic
|
| // on A and a typed selector on B could yield the same stub.
|
| Set<String> generatedStubNames = new Set<String>();
|
| if (compiler.enabledFunctionApply
|
| - && member.name == Namer.CLOSURE_INVOCATION_NAME) {
|
| + && member.name == namer.closureInvocationSelector) {
|
| // If [Function.apply] is called, we pessimistically compile all
|
| // possible stubs for this closure.
|
| FunctionSignature signature = member.computeSignature(compiler);
|
| @@ -622,7 +644,7 @@ $lazyInitializerLogic
|
| String compiledFieldName(Element member) {
|
| assert(member.isField());
|
| return member.isNative()
|
| - ? member.name.slowToString()
|
| + ? member.nativeName()
|
| : namer.getName(member);
|
| }
|
|
|
| @@ -726,6 +748,7 @@ $lazyInitializerLogic
|
| void visitClassFields(ClassElement classElement,
|
| void addField(Element member,
|
| String name,
|
| + String accessorName,
|
| bool needsGetter,
|
| bool needsSetter,
|
| bool needsCheckedSetter)) {
|
| @@ -775,6 +798,7 @@ $lazyInitializerLogic
|
| // Getters and setters with suffixes will be generated dynamically.
|
| addField(member,
|
| fieldName,
|
| + accessorName,
|
| needsGetter,
|
| needsSetter,
|
| needsCheckedSetter);
|
| @@ -791,16 +815,6 @@ $lazyInitializerLogic
|
| includeSuperMembers: isInstantiated && !classElement.isNative());
|
| }
|
|
|
| - void generateGetter(Element member, String fieldName, CodeBuffer buffer) {
|
| - String getterName = namer.getterName(member.getLibrary(), member.name);
|
| - buffer.add("$getterName: function() { return this.$fieldName; }");
|
| - }
|
| -
|
| - void generateSetter(Element member, String fieldName, CodeBuffer buffer) {
|
| - String setterName = namer.setterName(member.getLibrary(), member.name);
|
| - buffer.add("$setterName: function(v) { this.$fieldName = v; }");
|
| - }
|
| -
|
| bool canGenerateCheckedSetter(Element member) {
|
| DartType type = member.computeType(compiler);
|
| if (type.element.isTypeVariable()
|
| @@ -814,6 +828,7 @@ $lazyInitializerLogic
|
|
|
| void generateCheckedSetter(Element member,
|
| String fieldName,
|
| + String accessorName,
|
| CodeBuffer buffer) {
|
| assert(canGenerateCheckedSetter(member));
|
| DartType type = member.computeType(compiler);
|
| @@ -824,7 +839,7 @@ $lazyInitializerLogic
|
| if (helperElement.computeSignature(compiler).parameterCount != 1) {
|
| additionalArgument = ", '${namer.operatorIs(type.element)}'";
|
| }
|
| - String setterName = namer.setterName(member.getLibrary(), member.name);
|
| + String setterName = namer.setterNameFromAccessorName(accessorName);
|
| buffer.add("$setterName: function(v) { "
|
| "this.$fieldName = $helperName(v$additionalArgument); }");
|
| }
|
| @@ -846,13 +861,10 @@ $lazyInitializerLogic
|
| }
|
| visitClassFields(classElement, (Element member,
|
| String name,
|
| + String accessorName,
|
| bool needsGetter,
|
| bool needsSetter,
|
| bool needsCheckedSetter) {
|
| - if (!getterAndSetterCanBeImplementedByFieldSpec(
|
| - member, name, needsGetter, needsSetter)) {
|
| - return;
|
| - }
|
| if (!isNative || needsCheckedSetter || needsGetter || needsSetter) {
|
| if (isFirstField) {
|
| isFirstField = false;
|
| @@ -863,13 +875,19 @@ $lazyInitializerLogic
|
| } else {
|
| buffer.add(",");
|
| }
|
| - buffer.add('$name');
|
| + buffer.add('$accessorName');
|
| + int flag = 0;
|
| + if (name != accessorName) {
|
| + buffer.add(':$name');
|
| + assert(needsGetter || needsSetter);
|
| + flag = RENAMING_FLAG;
|
| + }
|
| if (needsGetter && needsSetter) {
|
| - buffer.add(GETTER_SETTER_SUFFIX);
|
| + buffer.addCharCode(GETTER_SETTER_CODE + flag);
|
| } else if (needsGetter) {
|
| - buffer.add(GETTER_SUFFIX);
|
| + buffer.addCharCode(GETTER_CODE + flag);
|
| } else if (needsSetter) {
|
| - buffer.add(SETTER_SUFFIX);
|
| + buffer.addCharCode(SETTER_CODE + flag);
|
| }
|
| }
|
| });
|
| @@ -895,48 +913,18 @@ $lazyInitializerLogic
|
|
|
| visitClassFields(classElement, (Element member,
|
| String name,
|
| + String accessorName,
|
| bool needsGetter,
|
| bool needsSetter,
|
| bool needsCheckedSetter) {
|
| - if (name == null) throw 123;
|
| - if (getterAndSetterCanBeImplementedByFieldSpec(
|
| - member, name, needsGetter, needsSetter)) {
|
| - needsGetter = false;
|
| - needsSetter = false;
|
| - }
|
| - if (needsGetter) {
|
| - emitComma();
|
| - generateGetter(member, name, buffer);
|
| - }
|
| - if (needsSetter) {
|
| - emitComma();
|
| - generateSetter(member, name, buffer);
|
| - }
|
| if (needsCheckedSetter) {
|
| assert(!needsSetter);
|
| emitComma();
|
| - generateCheckedSetter(member, name, buffer);
|
| + generateCheckedSetter(member, name, accessorName, buffer);
|
| }
|
| });
|
| }
|
|
|
| - bool getterAndSetterCanBeImplementedByFieldSpec(Element member,
|
| - String name,
|
| - bool needsGetter,
|
| - bool needsSetter) {
|
| - if (needsGetter) {
|
| - if (namer.getterName(member.getLibrary(), member.name) != 'get\$$name') {
|
| - return false;
|
| - }
|
| - }
|
| - if (needsSetter) {
|
| - if (namer.setterName(member.getLibrary(), member.name) != 'set\$$name') {
|
| - return false;
|
| - }
|
| - }
|
| - return true;
|
| - }
|
| -
|
| /**
|
| * Documentation wanted -- johnniwinther
|
| *
|
| @@ -1168,7 +1156,7 @@ $lazyInitializerLogic
|
| // create a fake element with the correct name.
|
| // Note: the callElement will not have any enclosingElement.
|
| FunctionElement callElement =
|
| - new ClosureInvocationElement(Namer.CLOSURE_INVOCATION_NAME, element);
|
| + new ClosureInvocationElement(namer.closureInvocationSelector, element);
|
| String staticName = namer.getName(element);
|
| String invocationName = namer.instanceMethodName(callElement);
|
| String fieldAccess = '$isolateProperties.$staticName';
|
| @@ -1265,8 +1253,8 @@ $classesCollector.$mangledName = {'':
|
| // its stubs we simply create a fake element with the correct name.
|
| // Note: the callElement will not have any enclosingElement.
|
| FunctionElement callElement =
|
| - new ClosureInvocationElement(Namer.CLOSURE_INVOCATION_NAME, member);
|
| -
|
| + new ClosureInvocationElement(namer.closureInvocationSelector, member);
|
| +
|
| String invocationName = namer.instanceMethodName(callElement);
|
| List<String> arguments = new List<String>(parameterCount);
|
| for (int i = 0; i < parameterCount; i++) {
|
| @@ -1342,7 +1330,7 @@ $classesCollector.$mangledName = {'':
|
| String invocationName =
|
| namer.instanceMethodInvocationName(memberLibrary, member.name,
|
| selector);
|
| - SourceString callName = Namer.CLOSURE_INVOCATION_NAME;
|
| + SourceString callName = namer.closureInvocationSelector;
|
| String closureCallName =
|
| namer.instanceMethodInvocationName(memberLibrary, callName,
|
| selector);
|
| @@ -1459,7 +1447,7 @@ $classesCollector.$mangledName = {'':
|
| }
|
|
|
| void emitMakeConstantList(CodeBuffer buffer) {
|
| - buffer.add(namer.ISOLATE);
|
| + buffer.add(namer.isolateName);
|
| buffer.add(r'''.makeConstantList = function(list) {
|
| list.immutable$list = true;
|
| list.fixed$length = true;
|
| @@ -1547,11 +1535,14 @@ $classesCollector.$mangledName = {'':
|
| }
|
| String internalName = namer.instanceMethodInvocationName(
|
| selector.library, new SourceString(methodName), selector);
|
| + Element createInvocationMirror =
|
| + compiler.findHelper(const SourceString('createInvocationMirror'));
|
| CodeBuffer buffer = new CodeBuffer();
|
| buffer.add('function($args) {\n');
|
| buffer.add(' return this.$noSuchMethodName('
|
| - '\$.createInvocationMirror("$methodName", "$internalName",'
|
| - ' $type, [$args], [$argNames]));\n');
|
| + '${namer.isolateAccess(createInvocationMirror)}('
|
| + '"$methodName", "$internalName",'
|
| + '$type, [$args], [$argNames]));\n');
|
| buffer.add(' }');
|
| return buffer;
|
| }
|
| @@ -1697,7 +1688,7 @@ var \$thisScriptUrl;
|
| function \$static_init(){};
|
|
|
| function \$initGlobals(context) {
|
| - context.isolateStatics = new ${namer.ISOLATE}();
|
| + context.isolateStatics = new ${namer.isolateName}();
|
| }
|
| function \$setGlobals(context) {
|
| $currentIsolate = context.isolateStatics;
|
| @@ -1724,10 +1715,10 @@ $mainEnsureGetter
|
| //
|
| // BEGIN invoke [main].
|
| //
|
| -if (typeof document != 'undefined' && document.readyState != 'complete') {
|
| +if (typeof document !== 'undefined' && document.readyState !== 'complete') {
|
| document.addEventListener('readystatechange', function () {
|
| if (document.readyState == 'complete') {
|
| - if (typeof dartMainRunner == 'function') {
|
| + if (typeof dartMainRunner === 'function') {
|
| dartMainRunner(function() { ${mainCall}; });
|
| } else {
|
| ${mainCall};
|
| @@ -1735,7 +1726,7 @@ if (typeof document != 'undefined' && document.readyState != 'complete') {
|
| }
|
| }, false);
|
| } else {
|
| - if (typeof dartMainRunner == 'function') {
|
| + if (typeof dartMainRunner === 'function') {
|
| dartMainRunner(function() { ${mainCall}; });
|
| } else {
|
| ${mainCall};
|
| @@ -1798,7 +1789,7 @@ if (typeof document != 'undefined' && document.readyState != 'complete') {
|
| String assembleProgram() {
|
| measure(() {
|
| mainBuffer.add(HOOKS_API_USAGE);
|
| - mainBuffer.add('function ${namer.ISOLATE}() {}\n');
|
| + mainBuffer.add('function ${namer.isolateName}() {}\n');
|
| mainBuffer.add('init();\n\n');
|
| // Shorten the code by using "$$" as temporary.
|
| classesCollector = r"$$";
|
| @@ -1834,7 +1825,7 @@ if (typeof document != 'undefined' && document.readyState != 'complete') {
|
|
|
| emitFinishIsolateConstructorInvocation(mainBuffer);
|
| mainBuffer.add(
|
| - 'var ${namer.CURRENT_ISOLATE} = new ${namer.ISOLATE}();\n');
|
| + 'var ${namer.CURRENT_ISOLATE} = new ${namer.isolateName}();\n');
|
|
|
| nativeEmitter.assembleCode(mainBuffer);
|
| emitMain(mainBuffer);
|
|
|