Index: dart/sdk/lib/_internal/lib/js_helper.dart |
diff --git a/dart/sdk/lib/_internal/lib/js_helper.dart b/dart/sdk/lib/_internal/lib/js_helper.dart |
index e346734f1b13f6f0b4f5e06622b5d618d70c3138..21789e2a792dd3a1e8514be2429ce07d9befc3da 100644 |
--- a/dart/sdk/lib/_internal/lib/js_helper.dart |
+++ b/dart/sdk/lib/_internal/lib/js_helper.dart |
@@ -1553,9 +1553,70 @@ convertDartClosureToJS(closure, int arity) { |
* Super class for Dart closures. |
*/ |
class Closure implements Function { |
+ // TODO(ahe): These constants must be in sync with |
+ // reflection_data_parser.dart. |
+ static const FUNCTION_INDEX = 0; |
+ static const NAME_INDEX = 1; |
+ static const CALL_NAME_INDEX = 2; |
+ static const REQUIRED_PARAMETER_INDEX = 3; |
+ static const OPTIONAL_PARAMETER_INDEX = 4; |
+ static const DEFAULT_ARGUMENTS_INDEX = 5; |
+ |
+ Closure(); |
+ |
+ /** |
+ * Creates a closure for use by implicit getters associated with a method. |
+ * |
+ * In other words, creates a tear-off closure. |
+ * |
+ * Called from [closureFromTearOff] as well as from reflection when tearing |
+ * of a method via [:getField:]. |
+ * |
+ * This method assumes that [array] was created by |
+ * [dart2js.js_emitter.ContainerBuilder.addMemberMethod]. |
+ */ |
+ factory Closure.fromTearOff(receiver, List array, bool isStatic) { |
+ var function = array[FUNCTION_INDEX]; |
+ String name = array[NAME_INDEX]; |
+ String callName = array[CALL_NAME_INDEX]; |
+ int requiredParameterCount = array[REQUIRED_PARAMETER_INDEX] - 1; |
+ bool isReflectable = requiredParameterCount != -1; |
+ int optionalParameterCount = array[OPTIONAL_PARAMETER_INDEX]; |
+ int index = DEFAULT_ARGUMENTS_INDEX + optionalParameterCount; |
+ |
+ // Create a closure and "monkey" patch it with call stubs. |
+ Closure closure = new Closure(); |
+ JS('', '#[#] = #', closure, callName, |
+ isStatic ? function : forwardTo(receiver, function)); |
+ while (index < array.length) { |
+ if (!JS('bool', 'typeof # == "function"', array[index])) break; |
+ var stub = array[index++]; |
+ var stubName = array[index++]; |
+ var stubCallName = array[index++]; |
+ JS('', '#[#] = #', closure, stubCallName, |
+ isStatic ? stub : forwardTo(receiver, stub)); |
+ } |
+ |
+ return closure; |
+ } |
+ |
+ static forwardTo(receiver, function) { |
+ return JS( |
+ '', |
+ 'function(r,f){return function(){return f.apply(r,arguments)}}(#,#)', |
+ receiver, function); |
+ } |
+ |
String toString() => "Closure"; |
} |
+/// Called from implicit method getter (aka tear-off). |
+Closure closureFromTearOff(receiver, jsArray, isStatic) { |
+ return new Closure.fromTearOff( |
+ receiver, JS('JSExtendableArray', '#', jsArray), |
+ JS('bool', '!!#', isStatic)); |
+} |
+ |
/// Represents a 'tear-off' closure, that is an instance method bound |
/// to a specific receiver (instance). |
class BoundClosure extends Closure { |