| 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 class NativeEmitter { | 5 class NativeEmitter { |
| 6 | 6 |
| 7 Compiler compiler; | 7 Compiler compiler; |
| 8 bool addedDynamicFunction = false; | 8 bool addedDynamicFunction = false; |
| 9 bool addedTypeNameOfFunction = false; | 9 bool addedTypeNameOfFunction = false; |
| 10 bool addedDefPropFunction = false; | 10 bool addedDefPropFunction = false; |
| (...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 200 buffer.add('\n'); | 200 buffer.add('\n'); |
| 201 } | 201 } |
| 202 | 202 |
| 203 void addNativePropertyIfNecessary(StringBuffer buffer) { | 203 void addNativePropertyIfNecessary(StringBuffer buffer) { |
| 204 if (addedNativeProperty) return; | 204 if (addedNativeProperty) return; |
| 205 addedNativeProperty = true; | 205 addedNativeProperty = true; |
| 206 buffer.add(buildNativePropertyCode()); | 206 buffer.add(buildNativePropertyCode()); |
| 207 buffer.add('\n'); | 207 buffer.add('\n'); |
| 208 } | 208 } |
| 209 | 209 |
| 210 void generateNativeLiteral(ClassElement classElement, StringBuffer buffer) { |
| 211 String quotedNative = classElement.nativeName.slowToString(); |
| 212 String nativeCode = quotedNative.substring(2, quotedNative.length - 1); |
| 213 String className = compiler.namer.getName(classElement); |
| 214 buffer.add(className); |
| 215 buffer.add(' = '); |
| 216 buffer.add(nativeCode); |
| 217 buffer.add(';\n'); |
| 218 |
| 219 String attachTo(name) => "$className.$name"; |
| 220 |
| 221 for (Element member in classElement.members) { |
| 222 if (member.isInstanceMember()) { |
| 223 compiler.emitter.addInstanceMember( |
| 224 member, attachTo, buffer, isNative: true); |
| 225 } |
| 226 } |
| 227 } |
| 228 |
| 229 bool isNativeLiteral(String nativeName) { |
| 230 return nativeName[1] === '='; |
| 231 } |
| 232 |
| 233 bool isNativeGlobal(String nativeName) { |
| 234 return nativeName[1] === '@'; |
| 235 } |
| 210 | 236 |
| 211 void generateNativeClass(ClassElement classElement, StringBuffer buffer) { | 237 void generateNativeClass(ClassElement classElement, StringBuffer buffer) { |
| 212 nativeClasses.add(classElement); | 238 nativeClasses.add(classElement); |
| 213 | 239 |
| 214 assert(classElement.backendMembers.isEmpty()); | 240 assert(classElement.backendMembers.isEmpty()); |
| 215 String nativeName = classElement.nativeName.slowToString(); | 241 String nativeName = classElement.nativeName.slowToString(); |
| 216 if (nativeName[1] === '@') { | 242 if (isNativeLiteral(nativeName)) { |
| 243 generateNativeLiteral(classElement, buffer); |
| 244 // The native literal kind needs to be dealt with specially when |
| 245 // generating code for it. |
| 246 return; |
| 247 } |
| 248 |
| 249 if (isNativeGlobal(nativeName)) { |
| 217 // Global object, just be like the other types for now. | 250 // Global object, just be like the other types for now. |
| 218 nativeName = nativeName.substring(3, nativeName.length - 1); | 251 nativeName = nativeName.substring(3, nativeName.length - 1); |
| 219 } else { | 252 } else { |
| 220 nativeName = nativeName.substring(2, nativeName.length - 1); | 253 nativeName = nativeName.substring(2, nativeName.length - 1); |
| 221 } | 254 } |
| 222 bool hasUsedSelectors = false; | 255 bool hasUsedSelectors = false; |
| 223 | 256 |
| 224 String attachTo(name) => "$dynamicName('$name').$nativeName"; | 257 String attachTo(String name) { |
| 258 hasUsedSelectors = true; |
| 259 addDynamicFunctionIfNecessary(buffer); |
| 260 return "$dynamicName('$name').$nativeName"; |
| 261 } |
| 225 | 262 |
| 226 for (Element member in classElement.members) { | 263 for (Element member in classElement.members) { |
| 227 if (member.isInstanceMember()) { | 264 if (member.isInstanceMember()) { |
| 228 String memberName = compiler.namer.getName(member); | 265 compiler.emitter.addInstanceMember( |
| 229 if (member.kind === ElementKind.FUNCTION | 266 member, attachTo, buffer, isNative: true); |
| 230 || member.kind === ElementKind.GENERATIVE_CONSTRUCTOR_BODY | |
| 231 || member.kind === ElementKind.GETTER | |
| 232 || member.kind === ElementKind.SETTER) { | |
| 233 String codeBlock = compiler.universe.generatedCode[member]; | |
| 234 if (codeBlock == null) continue; | |
| 235 addDynamicFunctionIfNecessary(buffer); | |
| 236 hasUsedSelectors = true; | |
| 237 buffer.add( | |
| 238 "$dynamicName('$memberName').$nativeName = $codeBlock;\n"); | |
| 239 codeBlock = compiler.universe.generatedBailoutCode[member]; | |
| 240 if (codeBlock !== null) { | |
| 241 String name = compiler.namer.getBailoutName(member); | |
| 242 buffer.add("$dynamicName('$name').$nativeName = $codeBlock;\n"); | |
| 243 } | |
| 244 FunctionElement function = member; | |
| 245 FunctionParameters parameters = function.computeParameters(compiler); | |
| 246 if (!parameters.optionalParameters.isEmpty()) { | |
| 247 compiler.emitter.addParameterStubs( | |
| 248 member, attachTo, buffer, isNative: true); | |
| 249 } | |
| 250 } else if (member.kind === ElementKind.FIELD) { | |
| 251 if (compiler.universe.invokedSetters.contains(member.name)) { | |
| 252 addDynamicFunctionIfNecessary(buffer); | |
| 253 hasUsedSelectors = true; | |
| 254 String setterName = compiler.namer.setterName(member.name); | |
| 255 buffer.add( | |
| 256 "$dynamicName('$setterName').$nativeName = function(v){\n" + | |
| 257 ' this.${member.name.slowToString()} = v;\n};\n'); | |
| 258 } | |
| 259 if (compiler.universe.invokedGetters.contains(member.name)) { | |
| 260 addDynamicFunctionIfNecessary(buffer); | |
| 261 hasUsedSelectors = true; | |
| 262 String getterName = compiler.namer.getterName(member.name); | |
| 263 buffer.add( | |
| 264 "$dynamicName('$getterName').$nativeName = function(){\n" + | |
| 265 ' return this.${member.name.slowToString()};\n};\n'); | |
| 266 } | |
| 267 } else { | |
| 268 compiler.internalError('unexpected kind: "${member.kind}"', | |
| 269 element: member); | |
| 270 } | |
| 271 if (member.kind == ElementKind.GETTER | |
| 272 || member.kind == ElementKind.FIELD) { | |
| 273 Set<Selector> selectors = compiler.universe.invokedNames[member.name]; | |
| 274 if (selectors !== null && !selectors.isEmpty()) { | |
| 275 emitCallStubForGetter(buffer, attachTo, member, selectors); | |
| 276 } | |
| 277 } else if (member.kind == ElementKind.FUNCTION) { | |
| 278 if (compiler.universe.invokedGetters.contains(member.name)) { | |
| 279 emitDynamicFunctionGetter(buffer, attachTo, member); | |
| 280 } | |
| 281 } | |
| 282 } | 267 } |
| 283 } | 268 } |
| 284 | 269 |
| 285 addNativePropertyIfNecessary(buffer); | 270 addNativePropertyIfNecessary(buffer); |
| 286 // Create an object that contains the is checks properties. The | 271 // Create an object that contains the is checks properties. The |
| 287 // object will be used when entering [buildDynamicIsCheckCode]. | 272 // object will be used when entering [buildDynamicIsCheckCode]. |
| 288 buffer.add('${compiler.namer.ISOLATE}.prototype.native.$nativeName = { '); | 273 buffer.add('${compiler.namer.ISOLATE}.prototype.native.$nativeName = { '); |
| 289 List<String> tests = <String>[]; | 274 List<String> tests = <String>[]; |
| 290 | 275 |
| 291 ClassElement objectClass = | 276 ClassElement objectClass = |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 327 // For example, for the following Dart method: | 312 // For example, for the following Dart method: |
| 328 // foo([x, y, z]); | 313 // foo([x, y, z]); |
| 329 // The call: | 314 // The call: |
| 330 // foo(y: 1) | 315 // foo(y: 1) |
| 331 // must be turned into a JS call to: | 316 // must be turned into a JS call to: |
| 332 // foo(null, y). | 317 // foo(null, y). |
| 333 | 318 |
| 334 List<String> nativeArgumentsBuffer = argumentsBuffer.getRange( | 319 List<String> nativeArgumentsBuffer = argumentsBuffer.getRange( |
| 335 0, indexOfLastOptionalArgumentInParameters + 1); | 320 0, indexOfLastOptionalArgumentInParameters + 1); |
| 336 | 321 |
| 322 ClassElement classElement = member.enclosingElement; |
| 323 String nativeName = classElement.nativeName.slowToString(); |
| 337 String nativeArguments = Strings.join(nativeArgumentsBuffer, ","); | 324 String nativeArguments = Strings.join(nativeArgumentsBuffer, ","); |
| 338 | 325 |
| 326 if (isNativeLiteral(nativeName)) { |
| 327 // If it's the native literal, we know there is no subclass, so |
| 328 // we can call the method directly. |
| 329 buffer.add(' return this.${member.name.slowToString()}'); |
| 330 buffer.add('($nativeArguments)'); |
| 331 return; |
| 332 } |
| 333 |
| 339 buffer.add(' if (Object.getPrototypeOf(this).hasOwnProperty('); | 334 buffer.add(' if (Object.getPrototypeOf(this).hasOwnProperty('); |
| 340 buffer.add("'$invocationName')) {\n"); | 335 buffer.add("'$invocationName')) {\n"); |
| 341 buffer.add(' return this.${member.name.slowToString()}'); | 336 buffer.add(' return this.${member.name.slowToString()}'); |
| 342 buffer.add('($nativeArguments)'); | 337 buffer.add('($nativeArguments)'); |
| 343 buffer.add('\n }\n'); | 338 buffer.add('\n }\n'); |
| 344 buffer.add(' return Object.prototype.$invocationName.call(this'); | 339 buffer.add(' return Object.prototype.$invocationName.call(this'); |
| 345 buffer.add(stubParameters == '' ? '' : ', $stubParameters'); | 340 buffer.add(stubParameters == '' ? '' : ', $stubParameters'); |
| 346 buffer.add(');'); | 341 buffer.add(');'); |
| 347 } | 342 } |
| 348 | 343 |
| (...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 478 entries.add("\n ['$clsName', ${tagDefns[clsName]}]"); | 473 entries.add("\n ['$clsName', ${tagDefns[clsName]}]"); |
| 479 } | 474 } |
| 480 buffer.add(Strings.join(entries, ',')); | 475 buffer.add(Strings.join(entries, ',')); |
| 481 buffer.add('];\n'); | 476 buffer.add('];\n'); |
| 482 buffer.add('$dynamicSetMetadataName(table);\n'); | 477 buffer.add('$dynamicSetMetadataName(table);\n'); |
| 483 | 478 |
| 484 buffer.add('})();\n'); | 479 buffer.add('})();\n'); |
| 485 } | 480 } |
| 486 } | 481 } |
| 487 } | 482 } |
| OLD | NEW |