Version 1.1.0-dev.5.1
svn merge -c 31331 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 31389 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 31390 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 31403 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 31431 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 31460 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 31461 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 31462 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 31470 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 31473 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 31474 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
R=kasperl@google.com
Review URL: https://codereview.chromium.org//125033003
git-svn-id: http://dart.googlecode.com/svn/trunk@31475 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/runtime/bin/process_android.cc b/runtime/bin/process_android.cc
index 2567cbe..5d17d04 100644
--- a/runtime/bin/process_android.cc
+++ b/runtime/bin/process_android.cc
@@ -696,6 +696,10 @@
struct sigaction act;
bzero(&act, sizeof(act));
act.sa_handler = SignalHandler;
+ sigemptyset(&act.sa_mask);
+ for (int i = 0; i < kSignalsCount; i++) {
+ sigaddset(&act.sa_mask, kSignals[i]);
+ }
int status = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(
sigaction(signal, &act, NULL));
if (status < 0) {
diff --git a/runtime/bin/process_linux.cc b/runtime/bin/process_linux.cc
index 7479064..175e36d 100644
--- a/runtime/bin/process_linux.cc
+++ b/runtime/bin/process_linux.cc
@@ -695,6 +695,10 @@
struct sigaction act;
bzero(&act, sizeof(act));
act.sa_handler = SignalHandler;
+ sigemptyset(&act.sa_mask);
+ for (int i = 0; i < kSignalsCount; i++) {
+ sigaddset(&act.sa_mask, kSignals[i]);
+ }
int status = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(
sigaction(signal, &act, NULL));
if (status < 0) {
diff --git a/runtime/bin/process_macos.cc b/runtime/bin/process_macos.cc
index ae0f37e..e369b21 100644
--- a/runtime/bin/process_macos.cc
+++ b/runtime/bin/process_macos.cc
@@ -739,6 +739,10 @@
struct sigaction act;
bzero(&act, sizeof(act));
act.sa_handler = SignalHandler;
+ sigemptyset(&act.sa_mask);
+ for (int i = 0; i < kSignalsCount; i++) {
+ sigaddset(&act.sa_mask, kSignals[i]);
+ }
int status = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(
sigaction(signal, &act, NULL));
if (status < 0) {
diff --git a/runtime/vm/flow_graph_inliner.cc b/runtime/vm/flow_graph_inliner.cc
index c6e88b6..f467d52 100644
--- a/runtime/vm/flow_graph_inliner.cc
+++ b/runtime/vm/flow_graph_inliner.cc
@@ -544,6 +544,7 @@
callee_graph)) {
function.set_is_inlinable(false);
TRACE_INLINING(OS::Print(" Bailout: optional arg mismatch\n"));
+ isolate->set_long_jump_base(base);
return false;
}
}
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index 72f93d8..9e74db6 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -743,7 +743,8 @@
*(param[i].default_value));
const Object* metadata = param[i].metadata;
if ((metadata != NULL) && (*metadata).IsError()) {
- return (*metadata).raw(); // Error evaluating the metadata.
+ isolate->set_long_jump_base(base);
+ return metadata->raw(); // Error evaluating the metadata.
}
param_descriptor.SetAt(j + kParameterMetadataOffset,
(param[i].metadata == NULL) ? Object::null_instance() :
@@ -864,7 +865,10 @@
Parser parser(script, lib, token_pos);
parser.set_current_class(cls);
parser.set_parsing_metadata(true);
- return parser.EvaluateMetadata();
+
+ RawObject* metadata = parser.EvaluateMetadata();
+ isolate->set_long_jump_base(base);
+ return metadata;
} else {
Error& error = Error::Handle();
error = isolate->object_store()->sticky_error();
diff --git a/sdk/lib/_internal/compiler/implementation/js_emitter/container_builder.dart b/sdk/lib/_internal/compiler/implementation/js_emitter/container_builder.dart
index f55026a..c3a33a5 100644
--- a/sdk/lib/_internal/compiler/implementation/js_emitter/container_builder.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_emitter/container_builder.dart
@@ -391,6 +391,8 @@
// P. Unmangled name (if reflectable).
// P+1. First metadata (if reflectable).
// ...
+ // TODO(ahe): Consider one of the parameter counts can be replaced by the
+ // length property of the JavaScript function object.
List expressions = [];
@@ -421,14 +423,14 @@
if (member.isInstanceMember()) {
Set invokedSelectors =
compiler.codegenWorld.invokedNames[member.name];
- if (invokedSelectors != null && invokedSelectors.contains(selector)) {
+ //if (invokedSelectors != null && invokedSelectors.contains(selector)) {
expressions.add(js.string(namer.invocationName(selector)));
- } else {
- // Don't add a stub for calling this as a regular instance method,
- // we only need the "call" stub for implicit closures of this
- // method.
- expressions.add("null");
- }
+ //} else {
+ // // Don't add a stub for calling this as a regular instance method,
+ // // we only need the "call" stub for implicit closures of this
+ // // method.
+ // expressions.add("null");
+ //}
} else {
// Static methods don't need "named" stubs as the default arguments
// are inlined at call sites. But static methods might need "call"
diff --git a/sdk/lib/_internal/compiler/implementation/js_emitter/reflection_data_parser.dart b/sdk/lib/_internal/compiler/implementation/js_emitter/reflection_data_parser.dart
index 1076afe..92b95c9 100644
--- a/sdk/lib/_internal/compiler/implementation/js_emitter/reflection_data_parser.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_emitter/reflection_data_parser.dart
@@ -18,12 +18,21 @@
Namer namer = backend.namer;
Compiler compiler = backend.compiler;
Element closureFromTearOff = compiler.findHelper('closureFromTearOff');
- String tearOffAccess =
- // Default value for mocked-up test libraries.
- 'function () { throw "Helper \'closureFromTearOff\' missing." }';
+ String tearOffAccess;
+ String tearOffGlobalObjectName;
+ String tearOffGlobalObject;
if (closureFromTearOff != null) {
tearOffAccess = namer.isolateAccess(closureFromTearOff);
+ tearOffGlobalObjectName = tearOffGlobalObject =
+ namer.globalObjectFor(closureFromTearOff);
+ } else {
+ // Default values for mocked-up test libraries.
+ tearOffAccess =
+ 'function() { throw "Helper \'closureFromTearOff\' missing." }';
+ tearOffGlobalObjectName = 'MissingHelperFunction';
+ tearOffGlobalObject = '($tearOffAccess())';
}
+
String metadataField = '"${namer.metadataField}"';
String reflectableField = namer.reflectableField;
@@ -83,11 +92,13 @@
var optionalParameterInfo = ${readInt("array", "1")};
var optionalParameterCount = optionalParameterInfo >> 1;
var optionalParametersAreNamed = (optionalParameterInfo & 1) === 1;
+ var isIntercepted =''' // Break long line.
+ ''' requiredParameterCount + optionalParameterCount != funcs[0].length;
var functionTypeIndex = ${readFunctionType("array", "2")};
var isReflectable =''' // Break long line.
''' array.length > requiredParameterCount + optionalParameterCount + 3;
if (getterStubName) {
- f = tearOff(funcs, array, isStatic, name);
+ f = tearOff(funcs, array, isStatic, name, isIntercepted);
'''
/* Used to create an isolate using spawnFunction.*/
'''
@@ -129,15 +140,56 @@
''';
String tearOff = '''
- function tearOff(funcs, reflectionInfo, isStatic, name) {
- return function() {
- return $tearOffAccess(''' // Break long line.
- '''this, funcs, reflectionInfo, isStatic, arguments, name);
- }
+ function tearOffGetterNoCsp(funcs, reflectionInfo, name, isIntercepted) {
+ return isIntercepted
+ ? new Function("funcs", "reflectionInfo", "name",''' // Break long line.
+ ''' "$tearOffGlobalObjectName", "c",
+ "return function tearOff_" + name + (functionCounter++)+ "(x) {" +
+ "if (c === null) c = $tearOffAccess(" +
+ "this, funcs, reflectionInfo, false, [x], name);" +
+ "return new c(this, funcs[0], x, name);" +
+ "}")(funcs, reflectionInfo, name, $tearOffGlobalObject, null)
+ : new Function("funcs", "reflectionInfo", "name",''' // Break long line.
+ ''' "$tearOffGlobalObjectName", "c",
+ "return function tearOff_" + name + (functionCounter++)+ "() {" +
+ "if (c === null) c = $tearOffAccess(" +
+ "this, funcs, reflectionInfo, false, [], name);" +
+ "return new c(this, funcs[0], null, name);" +
+ "}")(funcs, reflectionInfo, name, $tearOffGlobalObject, null)
+ }
+ function tearOffGetterCsp(funcs, reflectionInfo, name, isIntercepted) {
+ var cache = null;
+ return isIntercepted
+ ? function(x) {
+ if (cache === null) cache = $tearOffAccess(''' // Break long line.
+ '''this, funcs, reflectionInfo, false, [x], name);
+ return new cache(this, funcs[0], x, name)
+ }
+ : function() {
+ if (cache === null) cache = $tearOffAccess(''' // Break long line.
+ '''this, funcs, reflectionInfo, false, [], name);
+ return new cache(this, funcs[0], null, name)
+ }
+ }
+ function tearOff(funcs, reflectionInfo, isStatic, name, isIntercepted) {
+ var cache;
+ return isStatic
+ ? function() {
+ if (cache === void 0) cache = $tearOffAccess(''' // Break long line.
+ '''this, funcs, reflectionInfo, true, [], name).prototype;
+ return cache;
+ }
+ : tearOffGetter(funcs, reflectionInfo, name, isIntercepted);
}
''';
+
+
+
String init = '''
+ var functionCounter = 0;
+ var tearOffGetter = (typeof dart_precompiled == "function")
+ ? tearOffGetterCsp : tearOffGetterNoCsp;
if (!init.libraries) init.libraries = [];
if (!init.mangledNames) init.mangledNames = map();
if (!init.mangledGlobalNames) init.mangledGlobalNames = map();
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
index 77d6903..6d233b5 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
@@ -3615,18 +3615,19 @@
'"$name" does not handle closure with optional parameters',
node: closure);
}
- visit(closure);
+
+ compiler.enqueuer.codegen.registerStaticUse(element);
+ push(new HForeign(backend.namer.elementAccess(element),
+ backend.dynamicType,
+ <HInstruction>[]));
return params;
}
void handleForeignDartClosureToJs(Send node, String name) {
- FunctionSignature params = handleForeignRawFunctionRef(node, name);
- List<HInstruction> inputs = <HInstruction>[pop()];
- String invocationName = backend.namer.invocationName(
- new Selector.callClosure(params.requiredParameterCount));
- push(new HForeign(js.js('#.$invocationName'),
- backend.dynamicType,
- inputs));
+ // TODO(ahe): This implements DART_CLOSURE_TO_JS and should probably take
+ // care to wrap the closure in another closure that saves the current
+ // isolate.
+ handleForeignRawFunctionRef(node, name);
}
void handleForeignSetCurrentIsolate(Send node) {
diff --git a/sdk/lib/_internal/lib/foreign_helper.dart b/sdk/lib/_internal/lib/foreign_helper.dart
index 95b5907..5c2d64a 100644
--- a/sdk/lib/_internal/lib/foreign_helper.dart
+++ b/sdk/lib/_internal/lib/foreign_helper.dart
@@ -128,6 +128,9 @@
/**
* Converts the Dart closure [function] into a JavaScript closure.
+ *
+ * Warning: This is no different from [RAW_DART_FUNCTION_REF] which means care
+ * must be taken to store the current isolate.
*/
DART_CLOSURE_TO_JS(Function function) {}
diff --git a/sdk/lib/_internal/lib/js_helper.dart b/sdk/lib/_internal/lib/js_helper.dart
index ba5cf5b..bc490dd 100644
--- a/sdk/lib/_internal/lib/js_helper.dart
+++ b/sdk/lib/_internal/lib/js_helper.dart
@@ -5,29 +5,33 @@
library _js_helper;
import 'dart:collection';
-import 'dart:_foreign_helper' show DART_CLOSURE_TO_JS,
- JS,
- JS_CALL_IN_ISOLATE,
- JS_CONST,
- JS_CURRENT_ISOLATE,
- JS_CURRENT_ISOLATE_CONTEXT,
- JS_DART_OBJECT_CONSTRUCTOR,
- JS_FUNCTION_CLASS_NAME,
- JS_FUNCTION_TYPE_NAMED_PARAMETERS_TAG,
- JS_FUNCTION_TYPE_OPTIONAL_PARAMETERS_TAG,
- JS_FUNCTION_TYPE_REQUIRED_PARAMETERS_TAG,
- JS_FUNCTION_TYPE_RETURN_TYPE_TAG,
- JS_FUNCTION_TYPE_TAG,
- JS_FUNCTION_TYPE_VOID_RETURN_TAG,
- JS_GET_NAME,
- JS_HAS_EQUALS,
- JS_IS_INDEXABLE_FIELD_NAME,
- JS_OBJECT_CLASS_NAME,
- JS_NULL_CLASS_NAME,
- JS_OPERATOR_AS_PREFIX,
- JS_OPERATOR_IS_PREFIX,
- JS_SIGNATURE_NAME,
- RAW_DART_FUNCTION_REF;
+
+import 'dart:_foreign_helper' show
+ DART_CLOSURE_TO_JS,
+ JS,
+ JS_CALL_IN_ISOLATE,
+ JS_CONST,
+ JS_CURRENT_ISOLATE,
+ JS_CURRENT_ISOLATE_CONTEXT,
+ JS_DART_OBJECT_CONSTRUCTOR,
+ JS_EFFECT,
+ JS_FUNCTION_CLASS_NAME,
+ JS_FUNCTION_TYPE_NAMED_PARAMETERS_TAG,
+ JS_FUNCTION_TYPE_OPTIONAL_PARAMETERS_TAG,
+ JS_FUNCTION_TYPE_REQUIRED_PARAMETERS_TAG,
+ JS_FUNCTION_TYPE_RETURN_TYPE_TAG,
+ JS_FUNCTION_TYPE_TAG,
+ JS_FUNCTION_TYPE_VOID_RETURN_TAG,
+ JS_GET_NAME,
+ JS_HAS_EQUALS,
+ JS_IS_INDEXABLE_FIELD_NAME,
+ JS_NULL_CLASS_NAME,
+ JS_OBJECT_CLASS_NAME,
+ JS_OPERATOR_AS_PREFIX,
+ JS_OPERATOR_IS_PREFIX,
+ JS_SIGNATURE_NAME,
+ RAW_DART_FUNCTION_REF;
+
import 'dart:_interceptors';
import 'dart:_collection-dev' as _symbol_dev;
import 'dart:_collection-dev' show MappedIterable;
@@ -1741,10 +1745,21 @@
static const OPTIONAL_PARAMETER_INDEX = 4;
static const DEFAULT_ARGUMENTS_INDEX = 5;
+ /**
+ * Global counter to prevent reusing function code objects.
+ *
+ * V8 will share the underlying function code objects when the same string is
+ * passed to "new Function". Shared function code objects can lead to
+ * sub-optimal performance due to polymorhism, and can be prevented by
+ * ensuring the strings are different.
+ */
+ static int functionCounter = 0;
+
Closure();
/**
- * Creates a closure for use by implicit getters associated with a method.
+ * Creates a new closure class for use by implicit getters associated with a
+ * method.
*
* In other words, creates a tear-off closure.
*
@@ -1762,46 +1777,83 @@
* Caution: this function may be called when building constants.
* TODO(ahe): Don't call this function when building constants.
*/
- factory Closure.fromTearOff(receiver,
- List functions,
- List reflectionInfo,
- bool isStatic,
- jsArguments,
- String propertyName) {
+ static fromTearOff(receiver,
+ List functions,
+ List reflectionInfo,
+ bool isStatic,
+ jsArguments,
+ String propertyName) {
+ JS_EFFECT(() {
+ BoundClosure.receiverOf(JS('BoundClosure', 'void 0'));
+ BoundClosure.selfOf(JS('BoundClosure', 'void 0'));
+ });
// TODO(ahe): All the place below using \$ should be rewritten to go
// through the namer.
var function = JS('', '#[#]', functions, 0);
- // TODO(ahe): Try fetching the property directly instead of using "in".
- if (isStatic && JS('bool', '"\$tearOff" in #', function)) {
- // The implicit closure of a static function is always the same.
- return JS('Closure', '#.\$tearOff', function);
- }
-
String name = JS('String|Null', '#.\$stubName', function);
String callName = JS('String|Null', '#.\$callName', function);
- JS('', r'#.$reflectionInfo = #', function, reflectionInfo);
+ JS('', '#.\$reflectionInfo = #', function, reflectionInfo);
ReflectionInfo info = new ReflectionInfo(function);
var functionType = info.functionType;
+ // function tmp() {};
+ // tmp.prototype = BC.prototype;
+ // var proto = new tmp;
+ // for each computed prototype property:
+ // proto[property] = ...;
+ // proto._init = BC;
+ // var dynClosureConstructor =
+ // new Function('self', 'target', 'receiver', 'name',
+ // 'this._init(self, target, receiver, name)');
+ // proto.constructor = dynClosureConstructor; // Necessary?
+ // dynClosureConstructor.prototype = proto;
+ // return dynClosureConstructor;
+
+ // We need to create a new subclass of either TearOffClosure or
+ // BoundClosure. For this, we need to create an object whose prototype is
+ // the prototype is either TearOffClosure.prototype or
+ // BoundClosure.prototype, respectively in pseudo JavaScript code. The
+ // simplest way to access the JavaScript construction function of a Dart
+ // class is to create an instance and access its constructor property. The
+ // newly created instance could in theory be used directly as the
+ // prototype, but it might include additional fields that we don't need.
+ // So we only use the new instance to access the constructor property and
+ // use Object.create to create the desired prototype.
+ var prototype = isStatic
+ // TODO(ahe): Safe to use Object.create?
+ ? JS('TearOffClosure', 'Object.create(#.constructor.prototype)',
+ new TearOffClosure())
+ : JS('BoundClosure', 'Object.create(#.constructor.prototype)',
+ new BoundClosure(null, null, null, null));
+
+ JS('', '#.\$initialize = #', prototype, JS('', '#.constructor', prototype));
+ var constructor = isStatic
+ ? JS('', 'function(){this.\$initialize()}')
+ : isCsp
+ ? JS('', 'function(a,b,c,d) {this.\$initialize(a,b,c,d)}')
+ : JS('',
+ 'new Function("a","b","c","d",'
+ '"this.\$initialize(a,b,c,d);"+#)',
+ functionCounter++);
+
+ // TODO(ahe): Is it necessary to set the constructor property?
+ JS('', '#.constructor = #', prototype, constructor);
+
+ JS('', '#.prototype = #', constructor, prototype);
+
// Create a closure and "monkey" patch it with call stubs.
- Closure closure;
var trampoline = function;
+ var isIntercepted = false;
if (!isStatic) {
if (JS('bool', '#.length == 1', jsArguments)) {
// Intercepted call.
- var argument = JS('', '#[0]', jsArguments);
- trampoline = forwardInterceptedCallTo(argument, receiver, function);
- closure = new BoundClosure(receiver, function, argument, name);
- } else {
- trampoline = forwardTo(receiver, function);
- closure = new BoundClosure(receiver, function, null, name);
+ isIntercepted = true;
}
+ trampoline = forwardCallTo(function, isIntercepted);
} else {
- closure = new TearOffClosure();
- JS('', '#.\$tearOff = #', function, closure);
- JS('', r'#.$name = #', closure, propertyName);
+ JS('', '#.\$name = #', prototype, propertyName);
}
var signatureFunction;
@@ -1811,54 +1863,241 @@
functionType);
} else if (!isStatic
&& JS('bool', 'typeof # == "function"', functionType)) {
- signatureFunction = functionType;
- JS('', r'#.$receiver = #', closure, receiver);
+ var getReceiver = isIntercepted
+ ? RAW_DART_FUNCTION_REF(BoundClosure.receiverOf)
+ : RAW_DART_FUNCTION_REF(BoundClosure.selfOf);
+ signatureFunction = JS(
+ '',
+ 'function(f,r){'
+ 'return function(){'
+ 'return f.apply({\$receiver:r(this)},arguments)'
+ '}'
+ '}(#,#)', functionType, getReceiver);
} else {
throw 'Error in reflectionInfo.';
}
- JS('', '#.\$signature = #', closure, signatureFunction);
+ JS('', '#.\$signature = #', prototype, signatureFunction);
- JS('', '#[#] = #', closure, callName, trampoline);
+ JS('', '#[#] = #', prototype, callName, trampoline);
for (int i = 1; i < functions.length; i++) {
var stub = functions[i];
var stubCallName = JS('String|Null', '#.\$callName', stub);
- // TODO(ahe): Support interceptors here.
- JS('', '#[#] = #', closure, stubCallName,
- isStatic ? stub : forwardTo(receiver, stub));
+ if (stubCallName != null) {
+ JS('', '#[#] = #', prototype, stubCallName,
+ isStatic ? stub : forwardCallTo(stub, isIntercepted));
+ }
}
- JS('', '#["call*"] = #', closure, function);
+ JS('', '#["call*"] = #', prototype, function);
- return closure;
+ return constructor;
}
- static forwardTo(receiver, function) {
- return JS(
- '',
- 'function(r,f){return function(){return f.apply(r,arguments)}}(#,#)',
- receiver, function);
+ static cspForwardCall(int arity, function) {
+ var getSelf = RAW_DART_FUNCTION_REF(BoundClosure.selfOf);
+ switch (arity) {
+ case 0:
+ return JS(
+ '',
+ 'function(F,S){'
+ 'return function(){'
+ 'return F.call(S(this))'
+ '}'
+ '}(#,#)', function, getSelf);
+ case 1:
+ return JS(
+ '',
+ 'function(F,S){'
+ 'return function(a){'
+ 'return F.call(S(this),a)'
+ '}'
+ '}(#,#)', function, getSelf);
+ case 2:
+ return JS(
+ '',
+ 'function(F,S){'
+ 'return function(a,b){'
+ 'return F.call(S(this),a,b)'
+ '}'
+ '}(#,#)', function, getSelf);
+ case 3:
+ return JS(
+ '',
+ 'function(F,S){'
+ 'return function(a,b,c){'
+ 'return F.call(S(this),a,b,c)'
+ '}'
+ '}(#,#)', function, getSelf);
+ case 4:
+ return JS(
+ '',
+ 'function(F,S){'
+ 'return function(a,b,c,d){'
+ 'return F.call(S(this),a,b,c,d)'
+ '}'
+ '}(#,#)', function, getSelf);
+ case 5:
+ return JS(
+ '',
+ 'function(F,S){'
+ 'return function(a,b,c,d,e){'
+ 'return F.call(S(this),a,b,c,d,e)'
+ '}'
+ '}(#,#)', function, getSelf);
+ default:
+ return JS(
+ '',
+ 'function(f,s){'
+ 'return function(){'
+ 'return f.apply(s(this),arguments)'
+ '}'
+ '}(#,#)', function, getSelf);
+ }
}
- static forwardInterceptedCallTo(self, interceptor, function) {
- return JS(
- '',
- 'function(i,s,f){return function(){'
- 'return f.call.bind(f,i,s).apply(i,arguments)}}(#,#,#)',
- interceptor, self, function);
+ static bool get isCsp => JS('bool', 'typeof dart_precompiled == "function"');
+
+ static forwardCallTo(function, bool isIntercepted) {
+ if (isIntercepted) return forwardInterceptedCallTo(function);
+ int arity = JS('int', '#.length', function);
+ if (isCsp) {
+ return cspForwardCall(arity, function);
+ } else if (arity == 0) {
+ return JS(
+ '',
+ '(new Function("F",#))(#)',
+ 'return function(){'
+ 'return F.call(this.${BoundClosure.selfFieldName()});${functionCounter++}'
+ '}',
+ function);
+ } else if (1 <= arity && arity < 27) {
+ String arguments = JS(
+ 'String',
+ '"abcdefghijklmnopqrstuvwxyz".split("").splice(0,#).join(",")',
+ arity);
+ return JS(
+ '',
+ '(new Function("F",#))(#)',
+ 'return function($arguments){'
+ 'return F.call(this.${BoundClosure.selfFieldName()},$arguments);'
+ '${functionCounter++}'
+ '}',
+ function);
+ } else {
+ return cspForwardCall(arity, function);
+ }
+ }
+
+ static cspForwardInterceptedCall(int arity, String name, function) {
+ var getSelf = RAW_DART_FUNCTION_REF(BoundClosure.selfOf);
+ var getReceiver = RAW_DART_FUNCTION_REF(BoundClosure.receiverOf);
+ switch (arity) {
+ case 0:
+ // Intercepted functions always takes at least one argument (the
+ // receiver).
+ throw new RuntimeError('Intercepted function with no arguments.');
+ case 1:
+ return JS(
+ '',
+ 'function(n,s,r){'
+ 'return function(){'
+ 'return s(this)[n](r(this))'
+ '}'
+ '}(#,#,#)', name, getSelf, getReceiver);
+ case 2:
+ return JS(
+ '',
+ 'function(n,s,r){'
+ 'return function(a){'
+ 'return s(this)[n](r(this),a)'
+ '}'
+ '}(#,#,#)', name, getSelf, getReceiver);
+ case 3:
+ return JS(
+ '',
+ 'function(n,s,r){'
+ 'return function(a,b){'
+ 'return s(this)[n](r(this),a,b)'
+ '}'
+ '}(#,#,#)', name, getSelf, getReceiver);
+ case 4:
+ return JS(
+ '',
+ 'function(n,s,r){'
+ 'return function(a,b,c){'
+ 'return s(this)[n](r(this),a,b,c)'
+ '}'
+ '}(#,#,#)', name, getSelf, getReceiver);
+ case 5:
+ return JS(
+ '',
+ 'function(n,s,r){'
+ 'return function(a,b,c,d){'
+ 'return s(this)[n](r(this),a,b,c,d)'
+ '}'
+ '}(#,#,#)', name, getSelf, getReceiver);
+ case 6:
+ return JS(
+ '',
+ 'function(n,s,r){'
+ 'return function(a,b,c,d,e){'
+ 'return s(this)[n](r(this),a,b,c,d,e)'
+ '}'
+ '}(#,#,#)', name, getSelf, getReceiver);
+ default:
+ return JS(
+ '',
+ 'function(f,s,r,a){'
+ 'return function(){'
+ 'a=[r(this)];'
+ 'Array.prototype.push.apply(a,arguments);'
+ 'return f.apply(s(this),a)'
+ '}'
+ '}(#,#,#)', function, getSelf, getReceiver);
+ }
+ }
+
+ static forwardInterceptedCallTo(function) {
+ String stubName = JS('String|Null', '#.\$stubName', function);
+ int arity = JS('int', '#.length', function);
+ bool isCsp = JS('bool', 'typeof dart_precompiled == "function"');
+ if (isCsp) {
+ return cspForwardInterceptedCall(arity, stubName, function);
+ } else if (arity == 1) {
+ return JS('', 'new Function(#)',
+ 'return this.${BoundClosure.selfFieldName()}.$stubName('
+ 'this.${BoundClosure.receiverFieldName()});'
+ '${functionCounter++}');
+ } else if (1 < arity && arity < 28) {
+ String arguments = JS(
+ 'String',
+ '"abcdefghijklmnopqrstuvwxyz".split("").splice(0,#).join(",")',
+ arity - 1);
+ return JS(
+ '',
+ '(new Function(#))()',
+ 'return function($arguments){'
+ 'return this.${BoundClosure.selfFieldName()}.$stubName('
+ 'this.${BoundClosure.receiverFieldName()},$arguments);'
+ '${functionCounter++}'
+ '}');
+ } else {
+ return cspForwardInterceptedCall(arity, stubName, function);
+ }
}
String toString() => "Closure";
}
/// Called from implicit method getter (aka tear-off).
-Closure closureFromTearOff(receiver,
- functions,
- reflectionInfo,
- isStatic,
- jsArguments,
- name) {
- return new Closure.fromTearOff(
+closureFromTearOff(receiver,
+ functions,
+ reflectionInfo,
+ isStatic,
+ jsArguments,
+ name) {
+ return Closure.fromTearOff(
receiver,
JSArray.markFixedList(functions),
JSArray.markFixedList(reflectionInfo),
@@ -1917,13 +2156,46 @@
return receiverHashCode ^ Primitives.objectHashCode(_target);
}
+ @NoInline
static selfOf(BoundClosure closure) => closure._self;
static targetOf(BoundClosure closure) => closure._target;
+ @NoInline
static receiverOf(BoundClosure closure) => closure._receiver;
static nameOf(BoundClosure closure) => closure._name;
+
+ static String selfFieldNameCache;
+
+ static String selfFieldName() {
+ if (selfFieldNameCache == null) {
+ selfFieldNameCache = computeFieldNamed('self');
+ }
+ return selfFieldNameCache;
+ }
+
+ static String receiverFieldNameCache;
+
+ static String receiverFieldName() {
+ if (receiverFieldNameCache == null) {
+ receiverFieldNameCache = computeFieldNamed('receiver');
+ }
+ return receiverFieldNameCache;
+ }
+
+ @NoInline() @NoSideEffects()
+ static String computeFieldNamed(String fieldName) {
+ var template = new BoundClosure('self', 'target', 'receiver', 'name');
+ var names = JSArray.markFixedList(
+ JS('', 'Object.getOwnPropertyNames(#)', template));
+ for (int i = 0; i < names.length; i++) {
+ var name = names[i];
+ if (JS('bool', '#[#] === #', template, name, fieldName)) {
+ return JS('String', '#', name);
+ }
+ }
+ }
}
bool jsHasOwnProperty(var jsObject, String property) {
diff --git a/sdk/lib/_internal/lib/js_rti.dart b/sdk/lib/_internal/lib/js_rti.dart
index ca1d2d1..f389abb 100644
--- a/sdk/lib/_internal/lib/js_rti.dart
+++ b/sdk/lib/_internal/lib/js_rti.dart
@@ -523,21 +523,18 @@
assert(isJsObject(s));
assert(isJsObject(t));
- return JS('bool', r'''
- function (t, s, isAssignable) {
- for (var $name in t) {
- if (!s.hasOwnProperty($name)) {
- return false;
- }
- var tType = t[$name];
- var sType = s[$name];
- if (!isAssignable.call$2(sType, tType)) {
- return false;
- }
- }
- return true;
- }(#, #, #)
- ''', t, s, RAW_DART_FUNCTION_REF(isAssignable));
+ List names =
+ JSArray.markFixedList(JS('', 'Object.getOwnPropertyNames(#)', t));
+ for (int i = 0; i < names.length; i++) {
+ var name = names[i];
+ if (JS('bool', '!Object.hasOwnProperty.call(#, #)', s, name)) {
+ return false;
+ }
+ var tType = JS('', '#[#]', t, name);
+ var sType = JS('', '#[#]', s, name);
+ if (!isAssignable(tType, sType)) return false;
+ }
+ return true;
}
bool isFunctionSubtype(var s, var t) {
diff --git a/sdk/lib/js/dart2js/js_dart2js.dart b/sdk/lib/js/dart2js/js_dart2js.dart
index 536de09..b1003d9 100644
--- a/sdk/lib/js/dart2js/js_dart2js.dart
+++ b/sdk/lib/js/dart2js/js_dart2js.dart
@@ -544,7 +544,14 @@
Object _getDartProxy(o, String propertyName, createProxy(o)) {
var dartProxy = JS('', '#[#]', o, propertyName);
- if (dartProxy == null) {
+ // Temporary fix for dartbug.com/15193
+ // In some cases it's possible to see a JavaScript object that
+ // came from a different context and was previously proxied to
+ // Dart in that context. The JS object will have a cached proxy
+ // but it won't be a valid Dart object in this context.
+ // For now we throw away the cached proxy, but we should be able
+ // to cache proxies from multiple JS contexts and Dart isolates.
+ if (dartProxy == null || !_isLocalObject(o)) {
dartProxy = createProxy(o);
_defineProperty(o, propertyName, dartProxy);
}
diff --git a/tests/compiler/dart2js/mirrors_used_test.dart b/tests/compiler/dart2js/mirrors_used_test.dart
index 9415463..e0193c3 100644
--- a/tests/compiler/dart2js/mirrors_used_test.dart
+++ b/tests/compiler/dart2js/mirrors_used_test.dart
@@ -58,7 +58,7 @@
// 2. Some code was refactored, and there are more methods.
// Either situation could be problematic, but in situation 2, it is often
// acceptable to increase [expectedMethodCount] a little.
- int expectedMethodCount = 352;
+ int expectedMethodCount = 363;
Expect.isTrue(
generatedCode.length <= expectedMethodCount,
'Too many compiled methods: '
diff --git a/tests/compiler/dart2js_native/dart2js_native.status b/tests/compiler/dart2js_native/dart2js_native.status
index 499d474..c8bc459d 100644
--- a/tests/compiler/dart2js_native/dart2js_native.status
+++ b/tests/compiler/dart2js_native/dart2js_native.status
@@ -6,7 +6,6 @@
*: Skip
[ $compiler == dart2js ]
-bound_closure_test: Fail
call_on_native_class_test: CompileTimeError # Issue 14813
native_no_such_method_exception4_frog_test: Fail # Issue 9631
native_no_such_method_exception5_frog_test: Fail # Issue 9631
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index 1762ceb..7679ca1 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -89,6 +89,7 @@
[ $runtime == safari ]
typed_data/setRange_2_test: Fail # Safari doesn't fully implement spec for TypedArray.set
typed_data/setRange_3_test: Fail # Safari doesn't fully implement spec for TypedArray.set
+mirrors/to_string_test: Fail # Safari bug TODO(ahe): Add bug number if able to submit bug.
[ $compiler == dart2js && $runtime == chromeOnAndroid ]
typed_data/setRange_2_test: RuntimeError # TODO(dart2js-team): Please triage this failure.
@@ -141,6 +142,7 @@
[ $compiler == dart2js && $checked ]
convert/utf85_test: Pass, Slow # Issue 12029.
+async/stream_transform_test: Fail # https://code.google.com/p/v8/issues/detail?id=3084
[ $compiler == dart2js ]
convert/chunked_conversion_utf88_test: Slow, Pass
@@ -199,6 +201,7 @@
typed_data/setRange_1_test: Fail # Issue 15413
typed_data/setRange_2_test: Fail # Issue 15413
typed_data/setRange_3_test: Fail # Issue 15413
+mirrors/syntax_error_test/01: Fail # Issue 15886
[ $compiler == none ]
mirrors/hierarchy_test: Fail # TODO(ahe): This test is slightly broken. http://dartbug.com/12464
diff --git a/tests/lib/mirrors/syntax_error_test.dart b/tests/lib/mirrors/syntax_error_test.dart
new file mode 100644
index 0000000..8888ce5
--- /dev/null
+++ b/tests/lib/mirrors/syntax_error_test.dart
@@ -0,0 +1,26 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Regression test for Issue 15744
+// Also, tests that syntax errors in reflected classes are reported correctly.
+
+import 'dart:mirrors';
+
+class MD {
+ final String name;
+ const MD({this.name});
+}
+
+@MD(name:'A')
+class A {}
+
+@MD(name:'B')
+class B {
+ static x = { 0: 0; }; /// 01: compile-time error
+}
+
+main() {
+ reflectClass(A).metadata;
+ reflectClass(B).newInstance(const Symbol(''), []);
+}
diff --git a/tools/VERSION b/tools/VERSION
index 64ffd99..d775a81 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -28,4 +28,4 @@
MINOR 1
PATCH 0
PRERELEASE 5
-PRERELEASE_PATCH 0
+PRERELEASE_PATCH 1