Chromium Code Reviews| 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 * Generates the code for all used classes in the program. Static fields (even | 6 * Generates the code for all used classes in the program. Static fields (even |
| 7 * in classes) are ignored, since they can be treated as non-class elements. | 7 * in classes) are ignored, since they can be treated as non-class elements. |
| 8 * | 8 * |
| 9 * The code for the containing (used) methods must exist in the [:universe:]. | 9 * The code for the containing (used) methods must exist in the [:universe:]. |
| 10 */ | 10 */ |
| 11 class CodeEmitterTask extends CompilerTask { | 11 class CodeEmitterTask extends CompilerTask { |
| 12 static final String INHERIT_FUNCTION = ''' | 12 static final String INHERIT_FUNCTION = ''' |
| 13 function(child, parent) { | 13 function(child, parent) { |
| 14 if (child.prototype.__proto__) { | 14 if (child.prototype.__proto__) { |
| 15 child.prototype.__proto__ = parent.prototype; | 15 child.prototype.__proto__ = parent.prototype; |
| 16 } else { | 16 } else { |
| 17 function tmp() {}; | 17 function tmp() {}; |
| 18 tmp.prototype = parent.prototype; | 18 tmp.prototype = parent.prototype; |
| 19 child.prototype = new tmp(); | 19 child.prototype = new tmp(); |
| 20 child.prototype.constructor = child; | 20 child.prototype.constructor = child; |
| 21 } | 21 } |
| 22 }'''; | 22 }'''; |
| 23 | 23 |
| 24 static final String TYPE_NAME_OF_FUNCTION = ''' | |
| 25 function(obj) { | |
|
ahe
2012/02/19 14:38:02
Could you add a documentation comment for this fun
ngeoffray
2012/02/20 09:09:37
Sure. For the reference, this code is a pure copy
| |
| 26 var constructor = obj.constructor; | |
|
ahe
2012/02/19 14:38:02
What happens if obj is undefined?
ngeoffray
2012/02/20 09:09:37
boom? :)
floitsch
2012/02/21 13:11:15
Note that this function is called on the prototype
| |
| 27 if (typeof(constructor) == 'function') { | |
|
floitsch
2012/02/19 00:59:43
typeof is not a function:
if (typeof constructor =
ngeoffray
2012/02/20 09:09:37
Copy/pasted code.
| |
| 28 // The constructor isn't null or undefined at this point. Try | |
| 29 // to grab hold of its name. | |
| 30 var name = constructor.name; | |
| 31 // If the name is a non-empty string, we use that as the type | |
| 32 // name of this object. On Firefox, we often get 'Object' as | |
| 33 // the constructor name even for more specialized objects so | |
| 34 // we have to fall through to the toString() based implementation | |
| 35 // below in that case. | |
| 36 if (name && typeof(name) == 'string' && name != 'Object') return name; | |
|
floitsch
2012/02/19 00:59:43
exchange typeof and name-check.
It probably does n
ngeoffray
2012/02/20 09:09:37
Copy-pasted code.
| |
| 37 } | |
| 38 var string = Object.prototype.toString.call(obj); | |
| 39 var name = string.substring(8, string.length - 1); | |
|
ahe
2012/02/19 14:38:02
I'm getting a feeling that this is very similar to
ngeoffray
2012/02/20 09:09:37
Not on this code, which is copy-pasted.
| |
| 40 if (name == 'Window') { | |
| 41 name = 'DOMWindow'; | |
| 42 } else if (name == 'Document') { | |
| 43 name = 'HTMLDocument'; | |
| 44 } | |
| 45 return name; | |
| 46 } | |
| 47 '''; | |
| 48 | |
| 49 static final String DEF_PROP_FUNCTION = ''' | |
| 50 function(obj, prop, value) { | |
| 51 Object.defineProperty(obj, prop, | |
| 52 {value: value, enumerable: false, writable: true, configurable: true}); | |
| 53 }'''; | |
| 54 | |
| 55 String get DYNAMIC_FUNCTION() => ''' | |
|
floitsch
2012/02/19 00:59:43
this needs comments.
ahe
2012/02/19 14:38:02
Documentation comment, please.
ngeoffray
2012/02/20 09:09:37
As for TYPE_NAME_OF_FUNCTION, this method was take
ahe
2012/02/20 09:36:10
Whatever information you have about these function
| |
| 56 function(name) { | |
| 57 var f = Object.prototype[name]; | |
| 58 if (f && f.methods) return f.methods; | |
| 59 | |
| 60 var methods = {}; | |
| 61 if (f) methods.Object = f; | |
| 62 function dynamicBind() { | |
| 63 // Find the target method | |
| 64 var obj = this; | |
| 65 var tag = $typeNameOfName(obj); | |
| 66 var method = methods[tag]; | |
| 67 if (!method) { | |
| 68 var table = $dynamicMetadataName; | |
| 69 for (var i = 0; i < table.length; i++) { | |
| 70 var entry = table[i]; | |
| 71 if (entry.map.hasOwnProperty(tag)) { | |
| 72 method = methods[entry.tag]; | |
| 73 if (method) break; | |
| 74 } | |
| 75 } | |
| 76 } | |
| 77 method = method || methods.Object; | |
| 78 var proto = Object.getPrototypeOf(obj); | |
| 79 if (!proto.hasOwnProperty(name)) { | |
| 80 $defPropName(proto, name, method); | |
| 81 } | |
| 82 | |
| 83 return method.apply(this, Array.prototype.slice.call(arguments)); | |
| 84 }; | |
| 85 dynamicBind.methods = methods; | |
| 86 $defPropName(Object.prototype, name, dynamicBind); | |
| 87 return methods; | |
| 88 } | |
| 89 if (typeof $dynamicMetadataName == 'undefined') $dynamicMetadataName = []; | |
|
ahe
2012/02/19 14:38:02
Extra code after function. Shouldn't this be in th
ngeoffray
2012/02/20 09:09:37
Code also comes from frog.
ahe
2012/02/20 09:36:10
You chose the word "DYNAMIC_FUNCTION". Clearly thi
| |
| 90 '''; | |
| 91 | |
| 24 bool addedInheritFunction = false; | 92 bool addedInheritFunction = false; |
| 93 bool addedDynamicFunction = false; | |
| 25 final Namer namer; | 94 final Namer namer; |
| 26 | 95 |
| 27 CodeEmitterTask(Compiler compiler) : namer = compiler.namer, super(compiler); | 96 CodeEmitterTask(Compiler compiler) : namer = compiler.namer, super(compiler); |
| 28 String get name() => 'CodeEmitter'; | 97 String get name() => 'CodeEmitter'; |
| 29 | 98 |
| 30 String get inheritsName() => '${compiler.namer.ISOLATE}.\$inherits'; | 99 String get inheritsName() => '${compiler.namer.ISOLATE}.\$inherits'; |
|
ahe
2012/02/19 14:38:02
Why aren't these strings final values? Generating
ngeoffray
2012/02/20 09:09:37
They cannot be final because compiler.namer.ISOLAT
| |
| 100 String get dynamicName() => '${compiler.namer.ISOLATE}.\$dynamic'; | |
| 101 String get defPropName() => '${compiler.namer.ISOLATE}.\$defProp'; | |
| 102 String get typeNameOfName() => '${compiler.namer.ISOLATE}.\$typeNameOf'; | |
| 103 String get dynamicMetadataName() => | |
| 104 '${compiler.namer.ISOLATE}.\$dynamicMetatada'; | |
|
ahe
2012/02/19 14:38:02
How is this related to line 89?
ngeoffray
2012/02/20 09:09:37
Not sure I understand.
ahe
2012/02/20 09:36:10
I overlooked that the code on 89 wasn't in a raw s
| |
| 31 | 105 |
| 32 void addInheritFunctionIfNecessary(StringBuffer buffer) { | 106 void addInheritFunctionIfNecessary(StringBuffer buffer) { |
| 33 if (addedInheritFunction) return; | 107 if (addedInheritFunction) return; |
| 34 addedInheritFunction = true; | 108 addedInheritFunction = true; |
| 35 buffer.add('$inheritsName = '); | 109 buffer.add('$inheritsName = '); |
| 36 buffer.add(INHERIT_FUNCTION); | 110 buffer.add(INHERIT_FUNCTION); |
| 37 buffer.add(';\n'); | 111 buffer.add(';\n'); |
| 38 } | 112 } |
| 39 | 113 |
| 114 void addDynamicFunctionIfNecessary(StringBuffer buffer) { | |
| 115 if (addedDynamicFunction) return; | |
| 116 addedDynamicFunction = true; | |
| 117 buffer.add('$defPropName = '); | |
| 118 buffer.add(DEF_PROP_FUNCTION); | |
| 119 buffer.add('\n'); | |
| 120 buffer.add('$typeNameOfName = '); | |
| 121 buffer.add(TYPE_NAME_OF_FUNCTION); | |
| 122 buffer.add('\n'); | |
| 123 buffer.add('$dynamicName = '); | |
| 124 buffer.add(DYNAMIC_FUNCTION); | |
| 125 buffer.add(';\n'); | |
| 126 } | |
| 127 | |
| 40 void addParameterStub(FunctionElement member, | 128 void addParameterStub(FunctionElement member, |
| 41 String prototype, | 129 String attachTo(String invocationName), |
| 42 StringBuffer buffer, | 130 StringBuffer buffer, |
| 43 Selector selector) { | 131 Selector selector) { |
| 44 FunctionParameters parameters = member.computeParameters(compiler); | 132 FunctionParameters parameters = member.computeParameters(compiler); |
| 45 int positionalArgumentCount = selector.positionalArgumentCount; | 133 int positionalArgumentCount = selector.positionalArgumentCount; |
| 46 if (positionalArgumentCount == parameters.parameterCount) { | 134 if (positionalArgumentCount == parameters.parameterCount) { |
| 47 assert(selector.namedArgumentCount == 0); | 135 assert(selector.namedArgumentCount == 0); |
| 48 return; | 136 return; |
| 49 } | 137 } |
| 50 CompileTimeConstantHandler constants = compiler.compileTimeConstantHandler; | 138 CompileTimeConstantHandler constants = compiler.compileTimeConstantHandler; |
| 51 List<SourceString> names = selector.getOrderedNamedArguments(); | 139 List<SourceString> names = selector.getOrderedNamedArguments(); |
| 52 | 140 |
| 53 String invocationName = | 141 String invocationName = |
| 54 namer.instanceMethodInvocationName(member.name, selector); | 142 namer.instanceMethodInvocationName(member.name, selector); |
| 55 buffer.add('$prototype.$invocationName = function('); | 143 buffer.add('${attachTo(invocationName)} = function('); |
|
ahe
2012/02/19 14:38:02
How about turning this into a streaming API, that
| |
| 56 | 144 |
| 57 // The parameters that this stub takes. | 145 // The parameters that this stub takes. |
| 58 List<String> parametersBuffer = new List<String>(selector.argumentCount); | 146 List<String> parametersBuffer = new List<String>(selector.argumentCount); |
| 59 // The arguments that will be passed to the real method. | 147 // The arguments that will be passed to the real method. |
| 60 List<String> argumentsBuffer = new List<String>(parameters.parameterCount); | 148 List<String> argumentsBuffer = new List<String>(parameters.parameterCount); |
| 61 | 149 |
| 62 // We fill the lists depending on the selector. For example, | 150 // We fill the lists depending on the selector. For example, |
| 63 // take method foo: | 151 // take method foo: |
| 64 // foo(a, b, [c, d]); | 152 // foo(a, b, [c, d]); |
| 65 // | 153 // |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 114 } | 202 } |
| 115 count++; | 203 count++; |
| 116 }); | 204 }); |
| 117 | 205 |
| 118 buffer.add('${Strings.join(parametersBuffer, ",")}) {\n'); | 206 buffer.add('${Strings.join(parametersBuffer, ",")}) {\n'); |
| 119 buffer.add(' return this.${namer.getName(member)}'); | 207 buffer.add(' return this.${namer.getName(member)}'); |
| 120 buffer.add('(${Strings.join(argumentsBuffer, ",")})\n}\n'); | 208 buffer.add('(${Strings.join(argumentsBuffer, ",")})\n}\n'); |
| 121 } | 209 } |
| 122 | 210 |
| 123 void addParameterStubs(FunctionElement member, | 211 void addParameterStubs(FunctionElement member, |
| 124 String prototype, | 212 String attachTo(String invocationName), |
| 125 StringBuffer buffer) { | 213 StringBuffer buffer) { |
| 126 Set<Selector> selectors = compiler.universe.invokedNames[member.name]; | 214 Set<Selector> selectors = compiler.universe.invokedNames[member.name]; |
| 127 if (selectors == null) return; | 215 if (selectors == null) return; |
| 128 for (Selector selector in selectors) { | 216 for (Selector selector in selectors) { |
| 129 if (!selector.applies(compiler, member)) continue; | 217 if (!selector.applies(compiler, member)) continue; |
| 130 addParameterStub(member, prototype, buffer, selector); | 218 addParameterStub(member, attachTo, buffer, selector); |
| 131 } | 219 } |
| 132 } | 220 } |
| 133 | 221 |
| 134 void addInstanceMember(Element member, | 222 void addInstanceMember(Element member, |
| 135 String prototype, | 223 String prototype, |
| 136 StringBuffer buffer) { | 224 StringBuffer buffer) { |
| 137 assert(member.isInstanceMember()); | 225 assert(member.isInstanceMember()); |
| 138 if (member.kind === ElementKind.FUNCTION | 226 if (member.kind === ElementKind.FUNCTION |
| 139 || member.kind === ElementKind.GENERATIVE_CONSTRUCTOR_BODY | 227 || member.kind === ElementKind.GENERATIVE_CONSTRUCTOR_BODY |
| 140 || member.kind === ElementKind.GETTER | 228 || member.kind === ElementKind.GETTER |
| 141 || member.kind === ElementKind.SETTER) { | 229 || member.kind === ElementKind.SETTER) { |
| 142 String codeBlock = compiler.universe.generatedCode[member]; | 230 String codeBlock = compiler.universe.generatedCode[member]; |
| 143 if (codeBlock !== null) { | 231 if (codeBlock !== null) { |
| 144 buffer.add('$prototype.${namer.getName(member)} = $codeBlock;\n'); | 232 buffer.add('$prototype.${namer.getName(member)} = $codeBlock;\n'); |
| 145 } | 233 } |
| 146 codeBlock = compiler.universe.generatedBailoutCode[member]; | 234 codeBlock = compiler.universe.generatedBailoutCode[member]; |
| 147 if (codeBlock !== null) { | 235 if (codeBlock !== null) { |
| 148 String name = namer.getBailoutName(member); | 236 String name = namer.getBailoutName(member); |
| 149 buffer.add('$prototype.$name = $codeBlock;\n'); | 237 buffer.add('$prototype.$name = $codeBlock;\n'); |
| 150 } | 238 } |
| 151 FunctionElement function = member; | 239 FunctionElement function = member; |
| 152 if (!function.computeParameters(compiler).optionalParameters.isEmpty()) { | 240 if (!function.computeParameters(compiler).optionalParameters.isEmpty()) { |
| 153 addParameterStubs(member, prototype, buffer); | 241 addParameterStubs(member, (name) => '$prototype.$name', buffer); |
| 154 } | 242 } |
| 155 } else if (member.kind === ElementKind.FIELD) { | 243 } else if (member.kind === ElementKind.FIELD) { |
| 156 // TODO(ngeoffray): Have another class generate the code for the | 244 // TODO(ngeoffray): Have another class generate the code for the |
| 157 // fields. | 245 // fields. |
| 158 if (compiler.universe.invokedSetters.contains(member.name)) { | 246 if (compiler.universe.invokedSetters.contains(member.name)) { |
| 159 String setterName = namer.setterName(member.name); | 247 String setterName = namer.setterName(member.name); |
| 160 buffer.add('$prototype.$setterName = function(v){\n' + | 248 buffer.add('$prototype.$setterName = function(v){\n' + |
| 161 ' this.${namer.getName(member)} = v;\n};\n'); | 249 ' this.${namer.getName(member)} = v;\n};\n'); |
| 162 } | 250 } |
| 163 if (compiler.universe.invokedGetters.contains(member.name)) { | 251 if (compiler.universe.invokedGetters.contains(member.name)) { |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 179 // TODO(floitsch): make sure there are no name clashes. | 267 // TODO(floitsch): make sure there are no name clashes. |
| 180 String className = namer.getName(classElement); | 268 String className = namer.getName(classElement); |
| 181 | 269 |
| 182 void generateFieldInit(Element member) { | 270 void generateFieldInit(Element member) { |
| 183 if (member.isInstanceMember() && member.kind == ElementKind.FIELD) { | 271 if (member.isInstanceMember() && member.kind == ElementKind.FIELD) { |
| 184 if (!isFirst) argumentsBuffer.add(', '); | 272 if (!isFirst) argumentsBuffer.add(', '); |
| 185 isFirst = false; | 273 isFirst = false; |
| 186 String memberName = namer.instanceFieldName(member.name); | 274 String memberName = namer.instanceFieldName(member.name); |
| 187 argumentsBuffer.add('${className}_$memberName'); | 275 argumentsBuffer.add('${className}_$memberName'); |
| 188 bodyBuffer.add(' this.$memberName = ${className}_$memberName;\n'); | 276 bodyBuffer.add(' this.$memberName = ${className}_$memberName;\n'); |
| 189 } | 277 } |
| 190 } | 278 } |
| 191 | 279 |
| 192 for (Element element in classElement.members) { | 280 for (Element element in classElement.members) { |
| 193 generateFieldInit(element); | 281 generateFieldInit(element); |
| 194 } | 282 } |
| 195 for (Element element in classElement.backendMembers) { | 283 for (Element element in classElement.backendMembers) { |
| 196 generateFieldInit(element); | 284 generateFieldInit(element); |
| 197 } | 285 } |
| 198 | 286 |
| 199 classElement = classElement.superclass; | 287 classElement = classElement.superclass; |
| 200 } while(classElement !== null); | 288 } while(classElement !== null); |
| 201 } | 289 } |
| 202 | 290 |
| 291 void generateNativeClass(ClassElement classElement, StringBuffer buffer) { | |
| 292 addDynamicFunctionIfNecessary(buffer); | |
| 293 assert(classElement.backendMembers.isEmpty()); | |
| 294 String nativeName = classElement.nativeName.substring( | |
| 295 2, classElement.nativeName.length - 1); | |
| 296 for (Element member in classElement.members) { | |
| 297 if (member.isInstanceMember()) { | |
| 298 String memberName = namer.getName(member); | |
| 299 if (member.kind === ElementKind.FUNCTION | |
| 300 || member.kind === ElementKind.GENERATIVE_CONSTRUCTOR_BODY | |
| 301 || member.kind === ElementKind.GETTER | |
| 302 || member.kind === ElementKind.SETTER) { | |
| 303 String codeBlock = compiler.universe.generatedCode[member]; | |
| 304 if (codeBlock !== null) { | |
| 305 buffer.add( | |
| 306 "$dynamicName('$memberName').$nativeName = $codeBlock;\n"); | |
| 307 } | |
| 308 codeBlock = compiler.universe.generatedBailoutCode[member]; | |
| 309 if (codeBlock !== null) { | |
|
floitsch
2012/02/19 00:59:43
Maybe we should consider making our bailout functi
| |
| 310 String name = namer.getBailoutName(member); | |
| 311 buffer.add("$dynamicName('$name').$nativeName = $codeBlock;\n"); | |
| 312 } | |
| 313 FunctionElement function = member; | |
| 314 FunctionParameters parameters = function.computeParameters(compiler); | |
| 315 if (!parameters.optionalParameters.isEmpty()) { | |
|
ahe
2012/02/19 14:38:02
Is this necessary if there is no code generated?
ngeoffray
2012/02/20 09:09:37
Very good catch. Will remove it.
| |
| 316 addParameterStubs( | |
| 317 member, (name) => "$dynamicName('$name').$nativeName", buffer); | |
| 318 } | |
| 319 } else if (member.kind === ElementKind.FIELD) { | |
| 320 if (compiler.universe.invokedSetters.contains(member.name)) { | |
| 321 String setterName = namer.setterName(member.name); | |
| 322 buffer.add( | |
| 323 "$dynamicName('$setterName').$nativeName = function(v){\n" + | |
| 324 ' this.${member.name} = v;\n};\n'); | |
| 325 } | |
| 326 if (compiler.universe.invokedGetters.contains(member.name)) { | |
| 327 String getterName = namer.getterName(member.name); | |
| 328 buffer.add( | |
| 329 "$dynamicName('$getterName').$nativeName = function(){\n" + | |
| 330 ' return this.${member.name};\n};\n'); | |
| 331 } | |
| 332 } else { | |
| 333 compiler.internalError('unexpected kind: "${member.kind}"', | |
| 334 element: member); | |
| 335 } | |
| 336 } | |
| 337 } | |
| 338 } | |
| 339 | |
| 203 void generateClass(ClassElement classElement, | 340 void generateClass(ClassElement classElement, |
| 204 StringBuffer buffer, | 341 StringBuffer buffer, |
| 205 Set<ClassElement> seenClasses) { | 342 Set<ClassElement> seenClasses) { |
| 206 if (seenClasses.contains(classElement)) return; | 343 if (seenClasses.contains(classElement)) return; |
| 207 seenClasses.add(classElement); | 344 seenClasses.add(classElement); |
| 208 ClassElement superclass = classElement.superclass; | 345 ClassElement superclass = classElement.superclass; |
| 209 if (superclass !== null) { | 346 if (superclass !== null) { |
| 210 generateClass(classElement.superclass, buffer, seenClasses); | 347 generateClass(classElement.superclass, buffer, seenClasses); |
| 211 } | 348 } |
| 212 | 349 |
| 350 if (classElement.isNative()) { | |
| 351 return generateNativeClass(classElement, buffer); | |
|
floitsch
2012/02/19 00:59:43
don't use 'return val' to leave a void function.
| |
| 352 } | |
| 213 String className = namer.isolatePropertyAccess(classElement); | 353 String className = namer.isolatePropertyAccess(classElement); |
| 214 buffer.add('$className = function ${classElement.name}('); | 354 buffer.add('$className = function ${classElement.name}('); |
| 215 StringBuffer bodyBuffer = new StringBuffer(); | 355 StringBuffer bodyBuffer = new StringBuffer(); |
| 216 // If the class is never instantiated we still need to set it up for | 356 // If the class is never instantiated we still need to set it up for |
| 217 // inheritance purposes, but we can leave its JavaScript constructor empty. | 357 // inheritance purposes, but we can leave its JavaScript constructor empty. |
| 218 if (compiler.universe.instantiatedClasses.contains(classElement)) { | 358 if (compiler.universe.instantiatedClasses.contains(classElement)) { |
| 219 generateFieldInits(classElement, buffer, bodyBuffer); | 359 generateFieldInits(classElement, buffer, bodyBuffer); |
| 220 } | 360 } |
| 221 buffer.add(') {\n'); | 361 buffer.add(') {\n'); |
| 222 buffer.add(bodyBuffer); | 362 buffer.add(bodyBuffer); |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 283 // of static functions) and will not have any enclosingElement. | 423 // of static functions) and will not have any enclosingElement. |
| 284 FunctionElement callElement = | 424 FunctionElement callElement = |
| 285 new FunctionElement.from(Namer.CLOSURE_INVOCATION_NAME, | 425 new FunctionElement.from(Namer.CLOSURE_INVOCATION_NAME, |
| 286 element, | 426 element, |
| 287 null); | 427 null); |
| 288 String staticName = namer.isolatePropertyAccess(element); | 428 String staticName = namer.isolatePropertyAccess(element); |
| 289 int parameterCount = element.parameterCount(compiler); | 429 int parameterCount = element.parameterCount(compiler); |
| 290 String invocationName = | 430 String invocationName = |
| 291 namer.instanceMethodName(callElement.name, parameterCount); | 431 namer.instanceMethodName(callElement.name, parameterCount); |
| 292 buffer.add("$staticName.$invocationName = $staticName;\n"); | 432 buffer.add("$staticName.$invocationName = $staticName;\n"); |
| 293 addParameterStubs(callElement, staticName, buffer); | 433 addParameterStubs(callElement, (name) => '$staticName.$name', buffer); |
| 294 } | 434 } |
| 295 } | 435 } |
| 296 | 436 |
| 297 void emitDynamicFunctionGetter(StringBuffer buffer, | 437 void emitDynamicFunctionGetter(StringBuffer buffer, |
| 298 ClassElement enclosingClass, | 438 ClassElement enclosingClass, |
| 299 FunctionElement member) { | 439 FunctionElement member) { |
| 300 // For every method that has the same name as a property-get we create a | 440 // For every method that has the same name as a property-get we create a |
| 301 // getter that returns a bound closure. Say we have a class 'A' with method | 441 // getter that returns a bound closure. Say we have a class 'A' with method |
| 302 // 'foo' and somewhere in the code there is a dynamic property get of | 442 // 'foo' and somewhere in the code there is a dynamic property get of |
| 303 // 'foo'. Then we generate the following code (in pseudo Dart): | 443 // 'foo'. Then we generate the following code (in pseudo Dart): |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 336 namer.instanceMethodName(callElement.name, parameterCount); | 476 namer.instanceMethodName(callElement.name, parameterCount); |
| 337 String targetName = namer.instanceMethodName(member.name, parameterCount); | 477 String targetName = namer.instanceMethodName(member.name, parameterCount); |
| 338 List<String> arguments = new List<String>(parameterCount); | 478 List<String> arguments = new List<String>(parameterCount); |
| 339 for (int i = 0; i < parameterCount; i++) { | 479 for (int i = 0; i < parameterCount; i++) { |
| 340 arguments[i] = "arg$i"; | 480 arguments[i] = "arg$i"; |
| 341 } | 481 } |
| 342 String joinedArgs = Strings.join(arguments, ", "); | 482 String joinedArgs = Strings.join(arguments, ", "); |
| 343 buffer.add("$prototype.$invocationName = function($joinedArgs) {\n"); | 483 buffer.add("$prototype.$invocationName = function($joinedArgs) {\n"); |
| 344 buffer.add(" return this.self.$targetName($joinedArgs);\n"); | 484 buffer.add(" return this.self.$targetName($joinedArgs);\n"); |
| 345 buffer.add("};\n"); | 485 buffer.add("};\n"); |
| 346 addParameterStubs(callElement, prototype, buffer); | 486 addParameterStubs(callElement, (name) => '$prototype.$name', buffer); |
| 347 | 487 |
| 348 // And finally the getter. | 488 // And finally the getter. |
| 349 String enclosingClassAccess = namer.isolatePropertyAccess(enclosingClass); | 489 String enclosingClassAccess = namer.isolatePropertyAccess(enclosingClass); |
| 350 String enclosingClassPrototype = "$enclosingClassAccess.prototype"; | 490 String enclosingClassPrototype = "$enclosingClassAccess.prototype"; |
| 351 String getterName = namer.getterName(member.name); | 491 String getterName = namer.getterName(member.name); |
| 352 String closureClass = namer.isolateAccess(closureClassElement); | 492 String closureClass = namer.isolateAccess(closureClassElement); |
| 353 buffer.add("$enclosingClassPrototype.$getterName = function() {\n"); | 493 buffer.add("$enclosingClassPrototype.$getterName = function() {\n"); |
| 354 buffer.add(" return new $closureClass(this);\n"); | 494 buffer.add(" return new $closureClass(this);\n"); |
| 355 buffer.add("};\n"); | 495 buffer.add("};\n"); |
| 356 } | 496 } |
| (...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 520 emitCallStubForGetters(buffer); | 660 emitCallStubForGetters(buffer); |
| 521 emitStaticFinalFieldInitializations(buffer); | 661 emitStaticFinalFieldInitializations(buffer); |
| 522 buffer.add('var ${namer.CURRENT_ISOLATE} = new ${namer.ISOLATE}();\n'); | 662 buffer.add('var ${namer.CURRENT_ISOLATE} = new ${namer.ISOLATE}();\n'); |
| 523 Element main = compiler.mainApp.find(Compiler.MAIN); | 663 Element main = compiler.mainApp.find(Compiler.MAIN); |
| 524 buffer.add('${namer.isolateAccess(main)}();\n'); | 664 buffer.add('${namer.isolateAccess(main)}();\n'); |
| 525 compiler.assembledCode = buffer.toString(); | 665 compiler.assembledCode = buffer.toString(); |
| 526 }); | 666 }); |
| 527 return compiler.assembledCode; | 667 return compiler.assembledCode; |
| 528 } | 668 } |
| 529 } | 669 } |
| OLD | NEW |