Index: frog/leg/ssa/builder.dart |
=================================================================== |
--- frog/leg/ssa/builder.dart (revision 5637) |
+++ frog/leg/ssa/builder.dart (working copy) |
@@ -1721,53 +1721,124 @@ |
push(new HInvokeClosure(selector, inputs)); |
} |
- visitForeignSend(Send node) { |
- Identifier selector = node.selector; |
- switch (selector.source.slowToString()) { |
- case "JS": |
- Link<Node> link = node.arguments; |
- // If the invoke is on foreign code, don't visit the first |
- // argument, which is the type, and the second argument, |
- // which is the foreign code. |
- link = link.tail.tail; |
- List<HInstruction> inputs = <HInstruction>[]; |
- addGenericSendArgumentsToList(link, inputs); |
- LiteralString type = node.arguments.head; |
- LiteralString literal = node.arguments.tail.head; |
- compiler.ensure(literal is LiteralString); |
- compiler.ensure(type is LiteralString); |
- push(new HForeign(literal.dartString, type.dartString, inputs)); |
- break; |
- case "UNINTERCEPTED": |
- Link<Node> link = node.arguments; |
- if (!link.tail.isEmpty()) { |
- compiler.cancel('More than one expression in UNINTERCEPTED()'); |
- } |
- Expression expression = link.head; |
- disableMethodInterception(); |
- visit(expression); |
- enableMethodInterception(); |
- break; |
- case "JS_HAS_EQUALS": |
- List<HInstruction> inputs = <HInstruction>[]; |
- if (!node.arguments.tail.isEmpty()) { |
- compiler.cancel('More than one expression in JS_HAS_EQUALS()'); |
- } |
- addGenericSendArgumentsToList(node.arguments, inputs); |
- String name = compiler.namer.instanceMethodName( |
- currentLibrary, Namer.OPERATOR_EQUALS, 1); |
- push(new HForeign(new DartString.literal('!!#.$name'), |
- const LiteralDartString('bool'), |
- inputs)); |
- break; |
- case "native": |
- native.handleSsaNative(this, node); |
- break; |
- default: |
- throw "Unknown foreign: ${node.selector}"; |
+ void handleForeignJs(Send node) { |
+ Link<Node> link = node.arguments; |
+ // If the invoke is on foreign code, don't visit the first |
+ // argument, which is the type, and the second argument, |
+ // which is the foreign code. |
+ link = link.tail.tail; |
+ List<HInstruction> inputs = <HInstruction>[]; |
+ addGenericSendArgumentsToList(link, inputs); |
+ LiteralString type = node.arguments.head; |
+ LiteralString literal = node.arguments.tail.head; |
+ compiler.ensure(literal is LiteralString); |
+ compiler.ensure(type is LiteralString); |
+ push(new HForeign(literal.dartString, type.dartString, inputs)); |
+ } |
+ |
+ void handleForeignUnintercepted(Send node) { |
+ Link<Node> link = node.arguments; |
+ if (!link.tail.isEmpty()) { |
+ compiler.cancel( |
+ 'More than one expression in UNINTERCEPTED()', node: node); |
} |
+ Expression expression = link.head; |
+ disableMethodInterception(); |
+ visit(expression); |
+ enableMethodInterception(); |
} |
+ void handleForeignJsHasEquals(Send node) { |
+ List<HInstruction> inputs = <HInstruction>[]; |
+ if (!node.arguments.tail.isEmpty()) { |
+ compiler.cancel( |
+ 'More than one expression in JS_HAS_EQUALS()', node: node); |
+ } |
+ addGenericSendArgumentsToList(node.arguments, inputs); |
+ String name = compiler.namer.instanceMethodName( |
+ currentLibrary, Namer.OPERATOR_EQUALS, 1); |
+ push(new HForeign(new DartString.literal('!!#.$name'), |
+ const LiteralDartString('bool'), |
+ inputs)); |
+ } |
+ |
+ void handleForeignJsCurrentIsolate(Send node) { |
+ if (!node.arguments.isEmpty()) { |
+ compiler.cancel( |
+ 'Too many arguments to JS_CURRENT_ISOLATE', node: node); |
+ } |
+ |
+ if (!compiler.hasIsolateSupport()) { |
+ // If the isolate library is not used, we just generate code |
+ // to fetch the Leg's current isolate. |
+ String name = compiler.namer.CURRENT_ISOLATE; |
+ push(new HForeign(new DartString.literal(name), |
+ const LiteralDartString('var'), |
+ <HInstruction>[])); |
+ } else { |
+ // Call a helper method from the isolate library. The isolate |
+ // library uses its own isolate structure, that encapsulates |
+ // Leg's isolate. |
+ Element element = compiler.isolateLibrary.find( |
+ const SourceString('_currentIsolate')); |
+ if (element === null) { |
+ compiler.cancel( |
+ 'Isolate library and compiler mismatch', node: node); |
+ } |
+ HStatic target = new HStatic(element); |
+ add(target); |
+ push(new HInvokeStatic(Selector.INVOCATION_0, |
+ <HInstruction>[target])); |
+ } |
+ } |
+ |
+ void handleForeignJsCallInIsolate(Send node) { |
+ Link<Node> link = node.arguments; |
+ if (!compiler.hasIsolateSupport()) { |
+ // If the isolate library is not used, we just invoke the |
+ // closure. |
+ visit(link.tail.head); |
+ push(new HInvokeClosure(Selector.INVOCATION_0, |
+ <HInstruction>[pop()])); |
+ } else { |
+ // Call a helper method from the isolate library. |
+ Element element = compiler.isolateLibrary.find( |
+ const SourceString('_callInIsolate')); |
+ if (element === null) { |
+ compiler.cancel( |
+ 'Isolate library and compiler mismatch', node: node); |
+ } |
+ HStatic target = new HStatic(element); |
+ add(target); |
+ List<HInstruction> inputs = <HInstruction>[target]; |
+ addGenericSendArgumentsToList(link, inputs); |
+ push(new HInvokeStatic(Selector.INVOCATION_0, inputs)); |
+ } |
+ } |
+ |
+ handleForeignSend(Send node) { |
+ Element element = elements[node]; |
+ if (element === compiler.findHelper(const SourceString('JS'))) { |
+ handleForeignJs(node); |
+ } else if (element === compiler.findHelper( |
+ const SourceString('UNINTERCEPTED'))) { |
+ handleForeignUnintercepted(node); |
+ } else if (element === compiler.findHelper( |
+ const SourceString('JS_HAS_EQUALS'))) { |
+ handleForeignJsHasEquals(node); |
+ } else if (element === compiler.findHelper( |
+ const SourceString('JS_CURRENT_ISOLATE'))) { |
+ handleForeignJsCurrentIsolate(node); |
+ } else if (element === compiler.findHelper( |
+ const SourceString('JS_CALL_IN_ISOLATE'))) { |
+ handleForeignJsCallInIsolate(node); |
+ } else if (element === currentLibrary.find(const SourceString('native'))) { |
+ native.handleSsaNative(this, node); |
+ } else { |
+ throw "Unknown foreign: ${node.selector}"; |
+ } |
+ } |
+ |
visitSuperSend(Send node) { |
Selector selector = elements.getSelector(node); |
Element element = elements[node]; |
@@ -1839,7 +1910,7 @@ |
// Example: f() with 'f' bound to instance method. |
visitDynamicSend(node); |
} else if (element.kind === ElementKind.FOREIGN) { |
- visitForeignSend(node); |
+ handleForeignSend(node); |
} else if (!element.isInstanceMember()) { |
// Example: A.f() or f() with 'f' bound to a static function. |
// Also includes new A() or new A.named() which is treated like a |