| 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 #library('native'); | 5 #library('native'); |
| 6 #import('../../uri/uri.dart'); | 6 #import('../../uri/uri.dart'); |
| 7 #import('leg.dart'); | 7 #import('leg.dart'); |
| 8 #import('elements/elements.dart'); | 8 #import('elements/elements.dart'); |
| 9 #import('scanner/scannerlib.dart'); | 9 #import('scanner/scannerlib.dart'); |
| 10 #import('ssa/ssa.dart'); | 10 #import('ssa/ssa.dart'); |
| (...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 171 NativeEmitter nativeEmitter) { | 171 NativeEmitter nativeEmitter) { |
| 172 List<ClassElement> subtypes = nativeEmitter.subtypes[cls]; | 172 List<ClassElement> subtypes = nativeEmitter.subtypes[cls]; |
| 173 if (subtypes == null) return false; | 173 if (subtypes == null) return false; |
| 174 for (ClassElement subtype in subtypes) { | 174 for (ClassElement subtype in subtypes) { |
| 175 if (subtype.lookupLocalMember(element.name) != null) return true; | 175 if (subtype.lookupLocalMember(element.name) != null) return true; |
| 176 } | 176 } |
| 177 return false; | 177 return false; |
| 178 } | 178 } |
| 179 | 179 |
| 180 void handleSsaNative(SsaBuilder builder, Send node) { | 180 void handleSsaNative(SsaBuilder builder, Send node) { |
| 181 // Register NoSuchMethodException and captureStackTrace in the compiler | |
| 182 // because the dynamic dispatch for native classes may use them. | |
| 183 Compiler compiler = builder.compiler; | 181 Compiler compiler = builder.compiler; |
| 184 ClassElement cls = compiler.coreLibrary.find( | |
| 185 Compiler.NO_SUCH_METHOD_EXCEPTION); | |
| 186 cls.ensureResolved(compiler); | |
| 187 compiler.addToWorkList(cls.lookupConstructor(cls.name)); | |
| 188 compiler.registerStaticUse( | |
| 189 compiler.findHelper(new SourceString('captureStackTrace'))); | |
| 190 | |
| 191 FunctionElement element = builder.work.element; | 182 FunctionElement element = builder.work.element; |
| 192 element.setNative(); | 183 element.setNative(); |
| 193 NativeEmitter nativeEmitter = compiler.emitter.nativeEmitter; | 184 NativeEmitter nativeEmitter = compiler.emitter.nativeEmitter; |
| 194 // If what we're compiling is a getter named 'typeName' and the native | 185 // If what we're compiling is a getter named 'typeName' and the native |
| 195 // class is named 'DOMType', we generate a call to the typeNameOf | 186 // class is named 'DOMType', we generate a call to the typeNameOf |
| 196 // function attached on the isolate. | 187 // function attached on the isolate. |
| 197 // The DOM classes assume that their 'typeName' property, which is | 188 // The DOM classes assume that their 'typeName' property, which is |
| 198 // not a JS property on the DOM types, returns the type name. | 189 // not a JS property on the DOM types, returns the type name. |
| 199 if (element.name == const SourceString('typeName') | 190 if (element.name == const SourceString('typeName') |
| 200 && element.isGetter() | 191 && element.isGetter() |
| 201 && nativeEmitter.toNativeName(element.enclosingElement) == 'DOMType') { | 192 && nativeEmitter.toNativeName(element.enclosingElement) == 'DOMType') { |
| 202 DartString jsCode = new DartString.literal( | 193 Element element = compiler.findHelper(const SourceString('getTypeNameOf')); |
| 203 '${nativeEmitter.typeNameOfName}(#)'); | 194 HStatic method = new HStatic(element); |
| 204 List<HInstruction> inputs = | 195 builder.add(method); |
| 205 <HInstruction>[builder.localsHandler.readThis()]; | 196 builder.push(new HInvokeStatic(Selector.INVOCATION_1, |
| 206 builder.push(new HForeign( | 197 <HInstruction>[method, builder.localsHandler.readThis()])); |
| 207 jsCode, const LiteralDartString('String'), inputs)); | |
| 208 return; | 198 return; |
| 209 } | 199 } |
| 210 | 200 |
| 211 HInstruction convertDartClosure(Element parameter) { | 201 HInstruction convertDartClosure(Element parameter) { |
| 212 HInstruction local = builder.localsHandler.readLocal(parameter); | 202 HInstruction local = builder.localsHandler.readLocal(parameter); |
| 213 // TODO(ngeoffray): by better analyzing the function type and | 203 // TODO(ngeoffray): by better analyzing the function type and |
| 214 // its formal parameters, we could just pass, eg closure.$call$0. | 204 // its formal parameters, we could pass a method with a defined arity. |
| 215 builder.push(new HStatic(builder.interceptors.getClosureConverter())); | 205 builder.push(new HStatic(builder.interceptors.getClosureConverter())); |
| 216 List<HInstruction> callInputs = <HInstruction>[builder.pop(), local]; | 206 List<HInstruction> callInputs = <HInstruction>[builder.pop(), local]; |
| 217 HInstruction closure = new HInvokeStatic(Selector.INVOCATION_1, callInputs); | 207 HInstruction closure = new HInvokeStatic(Selector.INVOCATION_1, callInputs); |
| 218 builder.add(closure); | 208 builder.add(closure); |
| 219 return closure; | 209 return closure; |
| 220 } | 210 } |
| 221 | 211 |
| 212 |
| 213 // Check which pattern this native method follows: |
| 214 // 1) foo() native; hasBody = false, isRedirecting = false |
| 215 // 2) foo() native "bar"; hasBody = false, isRedirecting = true |
| 216 // 3) foo() native "return 42"; hasBody = true, isRedirecting = false |
| 217 bool hasBody = false; |
| 218 bool isRedirecting = false; |
| 219 String nativeMethodName = element.name.slowToString(); |
| 220 if (!node.arguments.isEmpty()) { |
| 221 if (!node.arguments.tail.isEmpty()) { |
| 222 builder.compiler.cancel('More than one argument to native'); |
| 223 } |
| 224 LiteralString jsCode = node.arguments.head; |
| 225 String str = jsCode.dartString.slowToString(); |
| 226 if (const RegExp(@'^[a-zA-Z][a-zA-Z_$0-9]*$').hasMatch(str)) { |
| 227 nativeMethodName = str; |
| 228 isRedirecting = true; |
| 229 } else { |
| 230 hasBody = true; |
| 231 } |
| 232 } |
| 233 |
| 222 FunctionParameters parameters = element.computeParameters(builder.compiler); | 234 FunctionParameters parameters = element.computeParameters(builder.compiler); |
| 223 if (node.arguments.isEmpty()) { | 235 if (!hasBody) { |
| 224 List<String> arguments = <String>[]; | 236 List<String> arguments = <String>[]; |
| 225 List<HInstruction> inputs = <HInstruction>[]; | 237 List<HInstruction> inputs = <HInstruction>[]; |
| 226 String receiver = ''; | 238 String receiver = ''; |
| 227 if (element.isInstanceMember()) { | 239 if (element.isInstanceMember()) { |
| 228 receiver = '#.'; | 240 receiver = '#.'; |
| 229 inputs.add(builder.localsHandler.readThis()); | 241 inputs.add(builder.localsHandler.readThis()); |
| 230 } | 242 } |
| 231 parameters.forEachParameter((Element parameter) { | 243 parameters.forEachParameter((Element parameter) { |
| 232 Type type = parameter.computeType(compiler); | 244 Type type = parameter.computeType(compiler); |
| 233 HInstruction input = builder.localsHandler.readLocal(parameter); | 245 HInstruction input = builder.localsHandler.readLocal(parameter); |
| 234 if (type is FunctionType) input = convertDartClosure(parameter); | 246 if (type is FunctionType) input = convertDartClosure(parameter); |
| 235 inputs.add(input); | 247 inputs.add(input); |
| 236 arguments.add('#'); | 248 arguments.add('#'); |
| 237 }); | 249 }); |
| 238 String foreignParameters = Strings.join(arguments, ','); | 250 String foreignParameters = Strings.join(arguments, ','); |
| 239 | 251 |
| 240 String dartMethodName; | 252 String dartMethodName; |
| 241 String nativeMethodName = element.name.slowToString(); | |
| 242 String nativeMethodCall; | 253 String nativeMethodCall; |
| 243 | 254 |
| 244 if (element.kind == ElementKind.FUNCTION) { | 255 if (element.kind == ElementKind.FUNCTION) { |
| 245 dartMethodName = builder.compiler.namer.instanceMethodName( | 256 dartMethodName = builder.compiler.namer.instanceMethodName( |
| 246 element.getLibrary(), element.name, parameters.parameterCount); | 257 element.getLibrary(), element.name, parameters.parameterCount); |
| 247 nativeMethodCall = '$receiver$nativeMethodName($foreignParameters)'; | 258 nativeMethodCall = '$receiver$nativeMethodName($foreignParameters)'; |
| 248 } else if (element.kind == ElementKind.GETTER) { | 259 } else if (element.kind == ElementKind.GETTER) { |
| 249 dartMethodName = builder.compiler.namer.getterName( | 260 dartMethodName = builder.compiler.namer.getterName( |
| 250 element.getLibrary(), element.name); | 261 element.getLibrary(), element.name); |
| 251 nativeMethodCall = '$receiver$nativeMethodName'; | 262 nativeMethodCall = '$receiver$nativeMethodName'; |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 314 jsCode, const LiteralDartString('Object'), | 325 jsCode, const LiteralDartString('Object'), |
| 315 <HInstruction>[builder.localsHandler.readThis(), constant])); | 326 <HInstruction>[builder.localsHandler.readThis(), constant])); |
| 316 | 327 |
| 317 builder.handleIf(visitThen, visitElse); | 328 builder.handleIf(visitThen, visitElse); |
| 318 | 329 |
| 319 HPhi phi = new HPhi.manyInputs( | 330 HPhi phi = new HPhi.manyInputs( |
| 320 null, <HInstruction>[thenInstruction, elseInstruction]); | 331 null, <HInstruction>[thenInstruction, elseInstruction]); |
| 321 builder.current.addPhi(phi); | 332 builder.current.addPhi(phi); |
| 322 builder.stack.add(phi); | 333 builder.stack.add(phi); |
| 323 } | 334 } |
| 324 | 335 if (isRedirecting) { |
| 325 } else if (!node.arguments.tail.isEmpty()) { | 336 // The parser creates a return node if there is no string literal |
| 326 builder.compiler.cancel('More than one argument to native'); | 337 // after the native keyword. In case of a redirecting method, there |
| 338 // is a string literal, therefore we must emit a return instruction |
| 339 // in the builder. |
| 340 builder.push(new HReturn(builder.pop())); |
| 341 } |
| 327 } else { | 342 } else { |
| 328 // This is JS code written in a Dart file with the construct | 343 // This is JS code written in a Dart file with the construct |
| 329 // native """ ... """;. It does not work well with mangling, | 344 // native """ ... """;. It does not work well with mangling, |
| 330 // but there should currently be no clash between leg mangling | 345 // but there should currently be no clash between leg mangling |
| 331 // and the library where this construct is being used. This | 346 // and the library where this construct is being used. This |
| 332 // mangling problem will go away once we switch these libraries | 347 // mangling problem will go away once we switch these libraries |
| 333 // to use Leg's 'JS' function. | 348 // to use Leg's 'JS' function. |
| 334 parameters.forEachParameter((Element parameter) { | 349 parameters.forEachParameter((Element parameter) { |
| 335 Type type = parameter.computeType(compiler); | 350 Type type = parameter.computeType(compiler); |
| 336 if (type is FunctionType) { | 351 if (type is FunctionType) { |
| 337 HInstruction jsClosure = convertDartClosure(parameter); | 352 HInstruction jsClosure = convertDartClosure(parameter); |
| 338 // Because the JS code references the argument name directly, | 353 // Because the JS code references the argument name directly, |
| 339 // we must keep the name and assign the JS closure to it. | 354 // we must keep the name and assign the JS closure to it. |
| 340 builder.add(new HForeign( | 355 builder.add(new HForeign( |
| 341 new DartString.literal('${parameter.name.slowToString()} = #'), | 356 new DartString.literal('${parameter.name.slowToString()} = #'), |
| 342 const LiteralDartString('void'), | 357 const LiteralDartString('void'), |
| 343 <HInstruction>[jsClosure])); | 358 <HInstruction>[jsClosure])); |
| 344 } | 359 } |
| 345 }); | 360 }); |
| 346 LiteralString jsCode = node.arguments.head; | 361 LiteralString jsCode = node.arguments.head; |
| 347 builder.push(new HForeign(jsCode.dartString, | 362 builder.push(new HForeign(jsCode.dartString, |
| 348 const LiteralDartString('Object'), | 363 const LiteralDartString('Object'), |
| 349 <HInstruction>[])); | 364 <HInstruction>[])); |
| 350 } | 365 } |
| 351 } | 366 } |
| OLD | NEW |