| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 /** | 5 /** |
| 6 * A function element that represents a closure call. The signature is copied | 6 * A function element that represents a closure call. The signature is copied |
| 7 * from the given element. | 7 * from the given element. |
| 8 */ | 8 */ |
| 9 class ClosureInvocationElement extends FunctionElement { | 9 class ClosureInvocationElement extends FunctionElement { |
| 10 ClosureInvocationElement(SourceString name, | 10 ClosureInvocationElement(SourceString name, |
| (...skipping 30 matching lines...) Expand all Loading... |
| 41 : namer = compiler.namer, | 41 : namer = compiler.namer, |
| 42 boundClosureBuffer = new CodeBuffer(), | 42 boundClosureBuffer = new CodeBuffer(), |
| 43 mainBuffer = new CodeBuffer(), | 43 mainBuffer = new CodeBuffer(), |
| 44 boundClosureCache = new Map<int, String>(), | 44 boundClosureCache = new Map<int, String>(), |
| 45 generateSourceMap = generateSourceMap, | 45 generateSourceMap = generateSourceMap, |
| 46 sourceMapBuilder = new SourceMapBuilder(), | 46 sourceMapBuilder = new SourceMapBuilder(), |
| 47 super(compiler) { | 47 super(compiler) { |
| 48 nativeEmitter = new NativeEmitter(this); | 48 nativeEmitter = new NativeEmitter(this); |
| 49 } | 49 } |
| 50 | 50 |
| 51 String get name() => 'CodeEmitter'; | 51 String get name => 'CodeEmitter'; |
| 52 | 52 |
| 53 String get defineClassName() | 53 String get defineClassName |
| 54 => '${namer.ISOLATE}.\$defineClass'; | 54 => '${namer.ISOLATE}.\$defineClass'; |
| 55 String get finishClassesName() | 55 String get finishClassesName |
| 56 => '${namer.ISOLATE}.\$finishClasses'; | 56 => '${namer.ISOLATE}.\$finishClasses'; |
| 57 String get finishIsolateConstructorName() | 57 String get finishIsolateConstructorName |
| 58 => '${namer.ISOLATE}.\$finishIsolateConstructor'; | 58 => '${namer.ISOLATE}.\$finishIsolateConstructor'; |
| 59 String get pendingClassesName() | 59 String get pendingClassesName |
| 60 => '${namer.ISOLATE}.\$pendingClasses'; | 60 => '${namer.ISOLATE}.\$pendingClasses'; |
| 61 String get isolatePropertiesName() | 61 String get isolatePropertiesName |
| 62 => '${namer.ISOLATE}.${namer.ISOLATE_PROPERTIES}'; | 62 => '${namer.ISOLATE}.${namer.ISOLATE_PROPERTIES}'; |
| 63 String get supportsProtoName() | 63 String get supportsProtoName |
| 64 => 'supportsProto'; | 64 => 'supportsProto'; |
| 65 | 65 |
| 66 final String GETTER_SUFFIX = "?"; | 66 final String GETTER_SUFFIX = "?"; |
| 67 final String SETTER_SUFFIX = "!"; | 67 final String SETTER_SUFFIX = "!"; |
| 68 final String GETTER_SETTER_SUFFIX = "="; | 68 final String GETTER_SETTER_SUFFIX = "="; |
| 69 | 69 |
| 70 String get generateGetterSetterFunction() { | 70 String get generateGetterSetterFunction { |
| 71 return """ | 71 return """ |
| 72 function(field, prototype) { | 72 function(field, prototype) { |
| 73 var len = field.length; | 73 var len = field.length; |
| 74 var lastChar = field[len - 1]; | 74 var lastChar = field[len - 1]; |
| 75 var needsGetter = lastChar == '$GETTER_SUFFIX' || lastChar == '$GETTER_SETTER_
SUFFIX'; | 75 var needsGetter = lastChar == '$GETTER_SUFFIX' || lastChar == '$GETTER_SETTER_
SUFFIX'; |
| 76 var needsSetter = lastChar == '$SETTER_SUFFIX' || lastChar == '$GETTER_SETTER_
SUFFIX'; | 76 var needsSetter = lastChar == '$SETTER_SUFFIX' || lastChar == '$GETTER_SETTER_
SUFFIX'; |
| 77 if (needsGetter || needsSetter) field = field.substring(0, len - 1); | 77 if (needsGetter || needsSetter) field = field.substring(0, len - 1); |
| 78 if (needsGetter) { | 78 if (needsGetter) { |
| 79 var getterString = "return this." + field + ";"; | 79 var getterString = "return this." + field + ";"; |
| 80 """ /* The supportsProtoCheck below depends on the getter/setter convention. | 80 """ /* The supportsProtoCheck below depends on the getter/setter convention. |
| 81 When changing here, update the protoCheck too. */ """ | 81 When changing here, update the protoCheck too. */ """ |
| 82 prototype["get\$" + field] = new Function(getterString); | 82 prototype["get\$" + field] = new Function(getterString); |
| 83 } | 83 } |
| 84 if (needsSetter) { | 84 if (needsSetter) { |
| 85 var setterString = "this." + field + " = v;"; | 85 var setterString = "this." + field + " = v;"; |
| 86 prototype["set\$" + field] = new Function("v", setterString); | 86 prototype["set\$" + field] = new Function("v", setterString); |
| 87 } | 87 } |
| 88 return field; | 88 return field; |
| 89 }"""; | 89 }"""; |
| 90 } | 90 } |
| 91 | 91 |
| 92 String get defineClassFunction() { | 92 String get defineClassFunction { |
| 93 // First the class name, then the super class name, followed by the fields | 93 // First the class name, then the super class name, followed by the fields |
| 94 // (in an array) and the members (inside an Object literal). | 94 // (in an array) and the members (inside an Object literal). |
| 95 // The caller can also pass in the constructor as a function if needed. | 95 // The caller can also pass in the constructor as a function if needed. |
| 96 // | 96 // |
| 97 // Example: | 97 // Example: |
| 98 // defineClass("A", "B", ["x", "y"], { | 98 // defineClass("A", "B", ["x", "y"], { |
| 99 // foo$1: function(y) { | 99 // foo$1: function(y) { |
| 100 // print(this.x + y); | 100 // print(this.x + y); |
| 101 // }, | 101 // }, |
| 102 // bar$2: function(t, v) { | 102 // bar$2: function(t, v) { |
| (...skipping 19 matching lines...) Expand all Loading... |
| 122 str += ") {" + body + "}\\n"; | 122 str += ") {" + body + "}\\n"; |
| 123 str += "return " + cls + ";"; | 123 str += "return " + cls + ";"; |
| 124 constructor = new Function(str)(); | 124 constructor = new Function(str)(); |
| 125 } | 125 } |
| 126 constructor.prototype = prototype; | 126 constructor.prototype = prototype; |
| 127 return constructor; | 127 return constructor; |
| 128 }"""; | 128 }"""; |
| 129 } | 129 } |
| 130 | 130 |
| 131 /** Needs defineClass to be defined. */ | 131 /** Needs defineClass to be defined. */ |
| 132 String get protoSupportCheck() { | 132 String get protoSupportCheck { |
| 133 // On Firefox and Webkit browsers we can manipulate the __proto__ | 133 // On Firefox and Webkit browsers we can manipulate the __proto__ |
| 134 // directly. Opera claims to have __proto__ support, but it is buggy. | 134 // directly. Opera claims to have __proto__ support, but it is buggy. |
| 135 // So we have to do more checks. | 135 // So we have to do more checks. |
| 136 // If the browser does not support __proto__ we need to instantiate an | 136 // If the browser does not support __proto__ we need to instantiate an |
| 137 // object with the correct (internal) prototype set up correctly, and then | 137 // object with the correct (internal) prototype set up correctly, and then |
| 138 // copy the members. | 138 // copy the members. |
| 139 | 139 |
| 140 return ''' | 140 return ''' |
| 141 var $supportsProtoName = false; | 141 var $supportsProtoName = false; |
| 142 var tmp = $defineClassName('c', ['f?'], {}).prototype; | 142 var tmp = $defineClassName('c', ['f?'], {}).prototype; |
| 143 if (tmp.__proto__) { | 143 if (tmp.__proto__) { |
| 144 tmp.__proto__ = {}; | 144 tmp.__proto__ = {}; |
| 145 if (typeof tmp.get\$f !== "undefined") $supportsProtoName = true; | 145 if (typeof tmp.get\$f !== "undefined") $supportsProtoName = true; |
| 146 } | 146 } |
| 147 '''; | 147 '''; |
| 148 } | 148 } |
| 149 | 149 |
| 150 String get finishClassesFunction() { | 150 String get finishClassesFunction { |
| 151 // 'defineClass' does not require the classes to be constructed in order. | 151 // 'defineClass' does not require the classes to be constructed in order. |
| 152 // Classes are initially just stored in the 'pendingClasses' field. | 152 // Classes are initially just stored in the 'pendingClasses' field. |
| 153 // 'finishClasses' takes all pending classes and sets up the prototype. | 153 // 'finishClasses' takes all pending classes and sets up the prototype. |
| 154 // Once set up, the constructors prototype field satisfy: | 154 // Once set up, the constructors prototype field satisfy: |
| 155 // - it contains all (local) members. | 155 // - it contains all (local) members. |
| 156 // - its internal prototype (__proto__) points to the superclass' | 156 // - its internal prototype (__proto__) points to the superclass' |
| 157 // prototype field. | 157 // prototype field. |
| 158 // - the prototype's constructor field points to the JavaScript | 158 // - the prototype's constructor field points to the JavaScript |
| 159 // constructor. | 159 // constructor. |
| 160 // For engines where we have access to the '__proto__' we can manipulate | 160 // For engines where we have access to the '__proto__' we can manipulate |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 201 if (hasOwnProperty.call(prototype, member)) { | 201 if (hasOwnProperty.call(prototype, member)) { |
| 202 newPrototype[member] = prototype[member]; | 202 newPrototype[member] = prototype[member]; |
| 203 } | 203 } |
| 204 } | 204 } |
| 205 } | 205 } |
| 206 } | 206 } |
| 207 for (var cls in pendingClasses) finishClass(cls); | 207 for (var cls in pendingClasses) finishClass(cls); |
| 208 }'''; | 208 }'''; |
| 209 } | 209 } |
| 210 | 210 |
| 211 String get finishIsolateConstructorFunction() { | 211 String get finishIsolateConstructorFunction { |
| 212 String isolate = namer.ISOLATE; | 212 String isolate = namer.ISOLATE; |
| 213 // We replace the old Isolate function with a new one that initializes | 213 // We replace the old Isolate function with a new one that initializes |
| 214 // all its field with the initial (and often final) value of all globals. | 214 // all its field with the initial (and often final) value of all globals. |
| 215 // This has two advantages: | 215 // This has two advantages: |
| 216 // 1. the properties are in the object itself (thus avoiding to go through | 216 // 1. the properties are in the object itself (thus avoiding to go through |
| 217 // the prototype when looking up globals. | 217 // the prototype when looking up globals. |
| 218 // 2. a new isolate goes through a (usually well optimized) constructor | 218 // 2. a new isolate goes through a (usually well optimized) constructor |
| 219 // function of the form: "function() { this.x = ...; this.y = ...; }". | 219 // function of the form: "function() { this.x = ...; this.y = ...; }". |
| 220 // | 220 // |
| 221 // Example: If [isolateProperties] is an object containing: x = 3 and | 221 // Example: If [isolateProperties] is an object containing: x = 3 and |
| (...skipping 483 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 705 | 705 |
| 706 void emitDynamicFunctionGetter(FunctionElement member, | 706 void emitDynamicFunctionGetter(FunctionElement member, |
| 707 DefineMemberFunction defineInstanceMember) { | 707 DefineMemberFunction defineInstanceMember) { |
| 708 // For every method that has the same name as a property-get we create a | 708 // For every method that has the same name as a property-get we create a |
| 709 // getter that returns a bound closure. Say we have a class 'A' with method | 709 // getter that returns a bound closure. Say we have a class 'A' with method |
| 710 // 'foo' and somewhere in the code there is a dynamic property get of | 710 // 'foo' and somewhere in the code there is a dynamic property get of |
| 711 // 'foo'. Then we generate the following code (in pseudo Dart/JavaScript): | 711 // 'foo'. Then we generate the following code (in pseudo Dart/JavaScript): |
| 712 // | 712 // |
| 713 // class A { | 713 // class A { |
| 714 // foo(x, y, z) { ... } // Original function. | 714 // foo(x, y, z) { ... } // Original function. |
| 715 // get foo() { return new BoundClosure499(this, "foo"); } | 715 // get foo { return new BoundClosure499(this, "foo"); } |
| 716 // } | 716 // } |
| 717 // class BoundClosure499 extends Closure { | 717 // class BoundClosure499 extends Closure { |
| 718 // var self; | 718 // var self; |
| 719 // BoundClosure499(this.self, this.name); | 719 // BoundClosure499(this.self, this.name); |
| 720 // $call3(x, y, z) { return self[name](x, y, z); } | 720 // $call3(x, y, z) { return self[name](x, y, z); } |
| 721 // } | 721 // } |
| 722 | 722 |
| 723 // TODO(floitsch): share the closure classes with other classes | 723 // TODO(floitsch): share the closure classes with other classes |
| 724 // if they share methods with the same signature. Currently we do this only | 724 // if they share methods with the same signature. Currently we do this only |
| 725 // if there are no optional parameters. Closures with optional parameters | 725 // if there are no optional parameters. Closures with optional parameters |
| (...skipping 441 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1167 sourceName = token.slowToString(); | 1167 sourceName = token.slowToString(); |
| 1168 } | 1168 } |
| 1169 int totalOffset = bufferOffset + offset; | 1169 int totalOffset = bufferOffset + offset; |
| 1170 sourceMapBuilder.addMapping( | 1170 sourceMapBuilder.addMapping( |
| 1171 sourceFile, token.charOffset, sourceName, totalOffset); | 1171 sourceFile, token.charOffset, sourceName, totalOffset); |
| 1172 }); | 1172 }); |
| 1173 } | 1173 } |
| 1174 } | 1174 } |
| 1175 | 1175 |
| 1176 typedef void DefineMemberFunction(String invocationName, CodeBuffer definition); | 1176 typedef void DefineMemberFunction(String invocationName, CodeBuffer definition); |
| OLD | NEW |