Index: pkg/compiler/lib/src/js_emitter/new_emitter/model_emitter.dart |
diff --git a/pkg/compiler/lib/src/js_emitter/new_emitter/model_emitter.dart b/pkg/compiler/lib/src/js_emitter/new_emitter/model_emitter.dart |
index ad7057b5154513348953c6f6d30b6f2a4cd1bfc7..d6272700206cab5d3a90d3da3aff06ba682a3717 100644 |
--- a/pkg/compiler/lib/src/js_emitter/new_emitter/model_emitter.dart |
+++ b/pkg/compiler/lib/src/js_emitter/new_emitter/model_emitter.dart |
@@ -4,6 +4,7 @@ |
library dart2js.new_js_emitter.model_emitter; |
+import '../../constants/values.dart' show ConstantValue; |
import '../../dart2jslib.dart' show Compiler; |
import '../../dart_types.dart' show DartType; |
import '../../elements/elements.dart' show ClassElement; |
@@ -113,7 +114,11 @@ class ModelEmitter { |
'holders': emitHolders(program.holders), |
'tearOff': buildTearOffCode(backend), |
'parseFunctionDescriptor': |
- js.js.statement(parseFunctionDescriptorBoilerplate), |
+ js.js.statement(parseFunctionDescriptorBoilerplate, |
+ {'argCnt': js.string(namer.requiredParameterField), |
+ 'defArgValues': js.string(namer.defaultValuesField), |
+ 'callName': js.string(namer.callNameField)}), |
+ |
'cyclicThrow': |
backend.emitter.staticFunctionAccess(backend.getCyclicThrowHelper()), |
'outputContainsConstantList': program.outputContainsConstantList, |
@@ -122,6 +127,7 @@ class ModelEmitter { |
'staticNonFinals': |
emitStaticNonFinalFields(fragment.staticNonFinalFields), |
'operatorIsPrefix': js.string(namer.operatorIsPrefix), |
+ 'callName': js.string(namer.callNameField), |
'eagerClasses': emitEagerClassInitializations(fragment.libraries), |
'invokeMain': fragment.invokeMain, |
'code': code}; |
@@ -552,19 +558,27 @@ class ModelEmitter { |
/// facilitate the generation of tearOffs at runtime. The format is an array |
/// with the following fields: |
/// |
- /// [InstanceMethod.aliasName] (optional). |
- /// [Method.code] |
- /// [DartMethod.callName] |
- /// isInterceptedMethod (optional, present if [DartMethod.needsTearOff]). |
- /// [DartMethod.tearOffName] (optional, present if [DartMethod.needsTearOff]). |
- /// functionType (optional, present if [DartMethod.needsTearOff]). |
+ /// * [InstanceMethod.aliasName] (optional). |
+ /// * [Method.code] |
+ /// * [DartMethod.callName] |
+ /// * isInterceptedMethod (optional, present if [DartMethod.needsTearOff]). |
+ /// * [DartMethod.tearOffName] (optional, present if |
+ /// [DartMethod.needsTearOff]). |
+ /// * functionType (optional, present if [DartMethod.needsTearOff]). |
/// |
/// followed by |
/// |
- /// [ParameterStubMethod.name] |
- /// [ParameterStubMethod.code] |
+ /// * [ParameterStubMethod.name] |
+ /// * [ParameterStubMethod.callName] |
+ /// * [ParameterStubMethod.code] |
/// |
/// for each stub in [DartMethod.parameterStubs]. |
+ /// |
+ /// If the closure could be used in `Function.apply` (i.e. |
+ /// [DartMethod.canBeApplied] is true) then the following fields are appended: |
+ /// |
+ /// * [DartMethod.requiredParameterCount] |
+ /// * [DartMethod.optionalParameterDefaultValues] |
static final String parseFunctionDescriptorBoilerplate = r""" |
function parseFunctionDescriptor(proto, name, descriptor) { |
@@ -581,7 +595,7 @@ function parseFunctionDescriptor(proto, name, descriptor) { |
proto[name] = f; |
var funs = [f]; |
- f.$callName = descriptor[++pos]; |
+ f[#callName] = descriptor[++pos]; |
var isInterceptedOrParameterStubName = descriptor[pos + 1]; |
var isIntercepted, tearOffName, reflectionInfo; |
@@ -591,9 +605,12 @@ function parseFunctionDescriptor(proto, name, descriptor) { |
reflectionInfo = descriptor[++pos]; |
} |
- for (++pos; pos < descriptor.length; pos += 3) { |
+ // We iterate in blocks of 3 but have to stop before we reach the (optional) |
+ // two trailing items. To accomplish this, we only iterate until we reach |
+ // length - 2. |
+ for (++pos; pos < descriptor.length - 2; pos += 3) { |
var stub = descriptor[pos + 2]; |
- stub.$callName = descriptor[pos + 1]; |
+ stub[#callName] = descriptor[pos + 1]; |
proto[descriptor[pos]] = stub; |
funs.push(stub); |
} |
@@ -602,7 +619,10 @@ function parseFunctionDescriptor(proto, name, descriptor) { |
proto[tearOffName] = |
tearOff(funs, reflectionInfo, false, name, isIntercepted); |
} |
- |
+ if (descriptor[pos] != null) { |
+ f[#argCnt] = descriptor[pos]; |
+ f[#defArgValues] = descriptor[pos + 1]; |
+ } |
} else { |
proto[name] = descriptor; |
} |
@@ -618,6 +638,24 @@ function parseFunctionDescriptor(proto, name, descriptor) { |
} |
} |
+ js.Expression _encodeOptionalParameterDefaultValues(DartMethod method) { |
+ js.Expression result; |
+ // TODO(herhut): Replace [js.LiteralNull] with [js.ArrayHole]. |
+ if (method.optionalParameterDefaultValues is List) { |
+ List<ConstantValue> defs = method.optionalParameterDefaultValues; |
+ Iterable<js.Expression> elements = defs.map(constantEmitter.reference); |
+ return new js.ArrayInitializer(elements.toList()); |
+ } else { |
+ Map<String, ConstantValue> defs = method.optionalParameterDefaultValues; |
+ List<js.Property> properties = <js.Property>[]; |
+ defs.forEach((String name, ConstantValue value) { |
+ properties.add(new js.Property(js.string(name), |
+ constantEmitter.reference(value))); |
+ }); |
+ return new js.ObjectInitializer(properties); |
+ } |
+ } |
+ |
Iterable<js.Expression> emitInstanceMethod(Method method) { |
List<js.Expression> makeNameCodePair(Method method) { |
@@ -652,6 +690,10 @@ function parseFunctionDescriptor(proto, name, descriptor) { |
} |
data.addAll(method.parameterStubs.expand(makeNameCallNameCodeTriplet)); |
+ if (method.canBeApplied) { |
+ data.add(js.number(method.requiredParameterCount)); |
+ data.add(_encodeOptionalParameterDefaultValues(method)); |
+ } |
return [js.string(method.name), new js.ArrayInitializer(data)]; |
} else { |
// TODO(floitsch): not the most efficient way... |
@@ -695,6 +737,10 @@ function parseFunctionDescriptor(proto, name, descriptor) { |
data.add(js.string(method.tearOffName)); |
data.add(_generateFunctionType(method.type)); |
data.addAll(method.parameterStubs.expand(makeNameCallNameCodeTriplet)); |
+ if (method.canBeApplied) { |
+ data.add(js.number(method.requiredParameterCount)); |
+ data.add(_encodeOptionalParameterDefaultValues(method)); |
+ } |
return [js.string(method.name), holderIndex, |
new js.ArrayInitializer(data)]; |
} else { |
@@ -782,13 +828,13 @@ function parseFunctionDescriptor(proto, name, descriptor) { |
function compileAllStubs() { |
var funs; |
var fun = compile(name, descriptor[0]); |
- fun.\$callName = descriptor[1]; |
+ fun[#callName] = descriptor[1]; |
holder[name] = fun; |
funs = [fun]; |
for (var pos = 4; pos < descriptor.length; pos += 3) { |
var stubName = descriptor[pos]; |
fun = compile(stubName, descriptor[pos + 2]); |
- fun.\$callName = descriptor[pos + 1]; |
+ fun[#callName] = descriptor[pos + 1]; |
holder[stubName] = fun; |
funs.push(fun); |
} |