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 #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( | |
|
floitsch
2012/03/29 23:25:52
this is not necessary anymore, because the functio
ngeoffray
2012/03/30 09:30:19
Correct.
| |
| 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( |
|
floitsch
2012/03/29 23:25:52
Are you sure this doesn't fit on one line?
If not,
ngeoffray
2012/03/30 09:30:19
Done.
| |
| 203 '${nativeEmitter.typeNameOfName}(#)'); | 194 const SourceString('getTypeNameOf')); |
| 204 List<HInstruction> inputs = | 195 HStatic method = new HStatic(element); |
| 205 <HInstruction>[builder.localsHandler.readThis()]; | 196 builder.add(method); |
| 206 builder.push(new HForeign( | 197 builder.push(new HInvokeStatic(Selector.INVOCATION_1, |
| 207 jsCode, const LiteralDartString('String'), inputs)); | 198 <HInstruction>[method, builder.localsHandler.readThis()])); |
| 208 return; | 199 return; |
| 209 } | 200 } |
| 210 | 201 |
| 211 HInstruction convertDartClosure(Element parameter) { | 202 HInstruction convertDartClosure(Element parameter) { |
| 212 HInstruction local = builder.localsHandler.readLocal(parameter); | 203 HInstruction local = builder.localsHandler.readLocal(parameter); |
| 213 // TODO(ngeoffray): by better analyzing the function type and | 204 // TODO(ngeoffray): by better analyzing the function type and |
| 214 // its formal parameters, we could just pass, eg closure.$call$0. | 205 // its formal parameters, we could pass a method with a defined arity. |
| 215 builder.push(new HStatic(builder.interceptors.getClosureConverter())); | 206 builder.push(new HStatic(builder.interceptors.getClosureConverter())); |
| 216 List<HInstruction> callInputs = <HInstruction>[builder.pop(), local]; | 207 List<HInstruction> callInputs = <HInstruction>[builder.pop(), local]; |
| 217 HInstruction closure = new HInvokeStatic(Selector.INVOCATION_1, callInputs); | 208 HInstruction closure = new HInvokeStatic(Selector.INVOCATION_1, callInputs); |
| 218 builder.add(closure); | 209 builder.add(closure); |
| 219 return closure; | 210 return closure; |
| 220 } | 211 } |
| 221 | 212 |
| 213 | |
| 214 // Check which pattern this native method follows: | |
| 215 // 1) foo() native; hasBody = false, isRedirecting = false | |
| 216 // 2) foo() native "bar"; hasBody = false, isRedirecting = true | |
| 217 // 3) foo() native "return 42"; hasBody = true, isRedirecting = false | |
| 218 bool hasBody = false; | |
| 219 bool isRedirecting = false; | |
| 220 String nativeMethodName = element.name.slowToString(); | |
| 221 if (!node.arguments.isEmpty()) { | |
| 222 if (!node.arguments.tail.isEmpty()) { | |
| 223 builder.compiler.cancel('More than one argument to native'); | |
| 224 } | |
| 225 LiteralString jsCode = node.arguments.head; | |
| 226 String str = jsCode.dartString.slowToString(); | |
| 227 if (const RegExp(@'^[a-zA-Z][a-zA-Z_$0-9]*$').hasMatch(str)) { | |
| 228 nativeMethodName = str; | |
| 229 isRedirecting = true; | |
| 230 } else { | |
| 231 hasBody = true; | |
| 232 } | |
| 233 } | |
| 234 | |
| 222 FunctionParameters parameters = element.computeParameters(builder.compiler); | 235 FunctionParameters parameters = element.computeParameters(builder.compiler); |
| 223 if (node.arguments.isEmpty()) { | 236 if (!hasBody) { |
| 224 List<String> arguments = <String>[]; | 237 List<String> arguments = <String>[]; |
| 225 List<HInstruction> inputs = <HInstruction>[]; | 238 List<HInstruction> inputs = <HInstruction>[]; |
| 226 String receiver = ''; | 239 String receiver = ''; |
| 227 if (element.isInstanceMember()) { | 240 if (element.isInstanceMember()) { |
| 228 receiver = '#.'; | 241 receiver = '#.'; |
| 229 inputs.add(builder.localsHandler.readThis()); | 242 inputs.add(builder.localsHandler.readThis()); |
| 230 } | 243 } |
| 231 parameters.forEachParameter((Element parameter) { | 244 parameters.forEachParameter((Element parameter) { |
| 232 Type type = parameter.computeType(compiler); | 245 Type type = parameter.computeType(compiler); |
| 233 HInstruction input = builder.localsHandler.readLocal(parameter); | 246 HInstruction input = builder.localsHandler.readLocal(parameter); |
| 234 if (type is FunctionType) input = convertDartClosure(parameter); | 247 if (type is FunctionType) input = convertDartClosure(parameter); |
| 235 inputs.add(input); | 248 inputs.add(input); |
| 236 arguments.add('#'); | 249 arguments.add('#'); |
| 237 }); | 250 }); |
| 238 String foreignParameters = Strings.join(arguments, ','); | 251 String foreignParameters = Strings.join(arguments, ','); |
| 239 | 252 |
| 240 String dartMethodName; | 253 String dartMethodName; |
| 241 String nativeMethodName = element.name.slowToString(); | |
| 242 String nativeMethodCall; | 254 String nativeMethodCall; |
| 243 | 255 |
| 244 if (element.kind == ElementKind.FUNCTION) { | 256 if (element.kind == ElementKind.FUNCTION) { |
| 245 dartMethodName = builder.compiler.namer.instanceMethodName( | 257 dartMethodName = builder.compiler.namer.instanceMethodName( |
| 246 element.getLibrary(), element.name, parameters.parameterCount); | 258 element.getLibrary(), element.name, parameters.parameterCount); |
| 247 nativeMethodCall = '$receiver$nativeMethodName($foreignParameters)'; | 259 nativeMethodCall = '$receiver$nativeMethodName($foreignParameters)'; |
| 248 } else if (element.kind == ElementKind.GETTER) { | 260 } else if (element.kind == ElementKind.GETTER) { |
| 249 dartMethodName = builder.compiler.namer.getterName( | 261 dartMethodName = builder.compiler.namer.getterName( |
| 250 element.getLibrary(), element.name); | 262 element.getLibrary(), element.name); |
| 251 nativeMethodCall = '$receiver$nativeMethodName'; | 263 nativeMethodCall = '$receiver$nativeMethodName'; |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 314 jsCode, const LiteralDartString('Object'), | 326 jsCode, const LiteralDartString('Object'), |
| 315 <HInstruction>[builder.localsHandler.readThis(), constant])); | 327 <HInstruction>[builder.localsHandler.readThis(), constant])); |
| 316 | 328 |
| 317 builder.handleIf(visitThen, visitElse); | 329 builder.handleIf(visitThen, visitElse); |
| 318 | 330 |
| 319 HPhi phi = new HPhi.manyInputs( | 331 HPhi phi = new HPhi.manyInputs( |
| 320 null, <HInstruction>[thenInstruction, elseInstruction]); | 332 null, <HInstruction>[thenInstruction, elseInstruction]); |
| 321 builder.current.addPhi(phi); | 333 builder.current.addPhi(phi); |
| 322 builder.stack.add(phi); | 334 builder.stack.add(phi); |
| 323 } | 335 } |
| 324 | 336 if (isRedirecting) { |
| 325 } else if (!node.arguments.tail.isEmpty()) { | 337 // The parser creates a return node if there is no string literal |
| 326 builder.compiler.cancel('More than one argument to native'); | 338 // after the native keyword. In case of a redirecting method, there |
| 339 // is a string literal, therefore we must emit a return instruction | |
| 340 // in the builder. | |
| 341 builder.push(new HReturn(builder.pop())); | |
| 342 } | |
| 327 } else { | 343 } else { |
| 328 // This is JS code written in a Dart file with the construct | 344 // This is JS code written in a Dart file with the construct |
| 329 // native """ ... """;. It does not work well with mangling, | 345 // native """ ... """;. It does not work well with mangling, |
| 330 // but there should currently be no clash between leg mangling | 346 // but there should currently be no clash between leg mangling |
| 331 // and the library where this construct is being used. This | 347 // and the library where this construct is being used. This |
| 332 // mangling problem will go away once we switch these libraries | 348 // mangling problem will go away once we switch these libraries |
| 333 // to use Leg's 'JS' function. | 349 // to use Leg's 'JS' function. |
| 334 parameters.forEachParameter((Element parameter) { | 350 parameters.forEachParameter((Element parameter) { |
| 335 Type type = parameter.computeType(compiler); | 351 Type type = parameter.computeType(compiler); |
| 336 if (type is FunctionType) { | 352 if (type is FunctionType) { |
| 337 HInstruction jsClosure = convertDartClosure(parameter); | 353 HInstruction jsClosure = convertDartClosure(parameter); |
| 338 // Because the JS code references the argument name directly, | 354 // Because the JS code references the argument name directly, |
| 339 // we must keep the name and assign the JS closure to it. | 355 // we must keep the name and assign the JS closure to it. |
| 340 builder.add(new HForeign( | 356 builder.add(new HForeign( |
| 341 new DartString.literal('${parameter.name.slowToString()} = #'), | 357 new DartString.literal('${parameter.name.slowToString()} = #'), |
| 342 const LiteralDartString('void'), | 358 const LiteralDartString('void'), |
| 343 <HInstruction>[jsClosure])); | 359 <HInstruction>[jsClosure])); |
| 344 } | 360 } |
| 345 }); | 361 }); |
| 346 LiteralString jsCode = node.arguments.head; | 362 LiteralString jsCode = node.arguments.head; |
| 347 builder.push(new HForeign(jsCode.dartString, | 363 builder.push(new HForeign(jsCode.dartString, |
| 348 const LiteralDartString('Object'), | 364 const LiteralDartString('Object'), |
| 349 <HInstruction>[])); | 365 <HInstruction>[])); |
| 350 } | 366 } |
| 351 } | 367 } |
| OLD | NEW |