Reviewers: arv, Diego Pino, Dmitry Lomov (chromium),
Message:
PTAL --- I realized today ArrayFrom was doing "the wrong thing" by not
supporting bound functions. In particular, it should only care about the
presence of a [[Construct]] internal slot.
Unfortunately, construct_stub doesn't offer a great way to check this, but
should_have_prototype seems to be a rough way of doing this.
It would be nice to inline this, and maybe make heuristics for checking if a
function is a constructor better.
Description:
Implement IsConstructor() abstract operation
LOG=N
[email protected], [email protected], [email protected]
BUG=
Please review this at https://codereview.chromium.org/851163007/
Base URL: https://chromium.googlesource.com/v8/v8.git@master
Affected files (+55, -7 lines):
M src/harmony-array.js
M src/runtime/runtime.h
M src/runtime/runtime-function.cc
M test/mjsunit/harmony/array-from.js
M test/mjsunit/harmony/array-of.js
Index: src/harmony-array.js
diff --git a/src/harmony-array.js b/src/harmony-array.js
index
5d1262a06d75bfd2444ade2f1fca0fa178079a90..762f746e56d923f1330ac177fa41403a331c18c8
100644
--- a/src/harmony-array.js
+++ b/src/harmony-array.js
@@ -149,7 +149,7 @@ function ArrayFrom(arrayLike, mapfn, receiver) {
var nextValue;
if (!IS_UNDEFINED(iterable)) {
- result = IS_SPEC_FUNCTION(this) && this.prototype ? new this() : [];
+ result = %IsConstructor(this) ? new this() : [];
k = 0;
for (nextValue of items) {
@@ -162,8 +162,7 @@ function ArrayFrom(arrayLike, mapfn, receiver) {
return result;
} else {
var len = ToLength(items.length);
- result = IS_SPEC_FUNCTION(this) && this.prototype ? new this(len) :
- new $Array(len);
+ result = %IsConstructor(this) ? new this(len) : new $Array(len);
for (k = 0; k < len; ++k) {
nextValue = items[k];
@@ -182,7 +181,7 @@ function ArrayOf() {
var length = %_ArgumentsLength();
var constructor = this;
// TODO: Implement IsConstructor (ES6 section 7.2.5)
- var array = IS_SPEC_FUNCTION(constructor) ? new constructor(length) : [];
+ var array = %IsConstructor(constructor) ? new constructor(length) : [];
for (var i = 0; i < length; i++) {
%AddElement(array, i, %_Arguments(i), NONE);
}
Index: src/runtime/runtime-function.cc
diff --git a/src/runtime/runtime-function.cc
b/src/runtime/runtime-function.cc
index
608cc9548423a34543b739c6a6d85e0571200579..4233c585f65f8a119be7975a752a384d22d217b6
100644
--- a/src/runtime/runtime-function.cc
+++ b/src/runtime/runtime-function.cc
@@ -326,6 +326,33 @@ RUNTIME_FUNCTION(Runtime_SetNativeFlag) {
}
+RUNTIME_FUNCTION(Runtime_IsConstructor) {
+ SealHandleScope shs(isolate);
+ RUNTIME_ASSERT(args.length() == 1);
+
+ CONVERT_ARG_CHECKED(Object, object, 0);
+
+ if (object->IsJSFunction()) {
+ JSFunction* func = JSFunction::cast(object);
+ bool should_have_prototype = func->should_have_prototype();
+ if (func->shared()->bound()) {
+ Handle<FixedArray> bound_args =
+ Handle<FixedArray>(FixedArray::cast(func->function_bindings()));
+ Handle<Object> bound_function(
+
JSReceiver::cast(bound_args->get(JSFunction::kBoundFunctionIndex)),
+ isolate);
+ if (bound_function->IsJSFunction()) {
+ JSFunction* bound = JSFunction::cast(*bound_function);
+ DCHECK(!bound->shared()->bound());
+ should_have_prototype = bound->should_have_prototype();
+ }
+ }
+ return isolate->heap()->ToBoolean(should_have_prototype);
+ }
+ return isolate->heap()->false_value();
+}
+
+
RUNTIME_FUNCTION(Runtime_SetInlineBuiltinFlag) {
SealHandleScope shs(isolate);
RUNTIME_ASSERT(args.length() == 1);
Index: src/runtime/runtime.h
diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h
index
a39e320f1138ddfc378cf9a75e73af453c5bbdef..9c7c379e45b496c37b1caa081e6e93eaf62e6867
100644
--- a/src/runtime/runtime.h
+++ b/src/runtime/runtime.h
@@ -73,6 +73,7 @@ namespace internal {
F(CompileForOnStackReplacement, 1, 1) \
F(SetAllocationTimeout, -1 /* 2 || 3 */, 1) \
F(SetNativeFlag, 1, 1) \
+ F(IsConstructor, 1, 1) \
F(SetInlineBuiltinFlag, 1, 1) \
F(StoreArrayLiteralElement, 5, 1) \
F(DebugPrepareStepInIfStepping, 1, 1) \
Index: test/mjsunit/harmony/array-from.js
diff --git a/test/mjsunit/harmony/array-from.js
b/test/mjsunit/harmony/array-from.js
index
e7c9fef7d5d8a3826451e1c9d6fb133af26060cc..e8dde163fc227bb21bdeaab6d14ff944cec65b96
100644
--- a/test/mjsunit/harmony/array-from.js
+++ b/test/mjsunit/harmony/array-from.js
@@ -118,6 +118,7 @@ testArrayFrom({}, Array);
testArrayFrom(Object, Object);
testArrayFrom(Other, Other);
testArrayFrom(Math.cos, Array);
-testArrayFrom(boundFn, Array);
+testArrayFrom(Math.cos.bind(Math), Array);
+testArrayFrom(boundFn, boundFn);
})();
Index: test/mjsunit/harmony/array-of.js
diff --git a/test/mjsunit/harmony/array-of.js
b/test/mjsunit/harmony/array-of.js
index
c0a8ed183e597fd538b2b8a52ba983f62a2f0cfd..adf7cb547cdae9eebd9fdec14f01c8d562526e65
100644
--- a/test/mjsunit/harmony/array-of.js
+++ b/test/mjsunit/harmony/array-of.js
@@ -159,6 +159,26 @@ assertEquals(Array.of.length, 0);
assertThrows(function() { new Array.of() }, TypeError); // not a
constructor
// When the this-value passed in is not a constructor, the result is an
array.
-[undefined, null, false, "cow"].forEach(function(val) {
- assertEquals(Array.isArray(Array.of(val)), true);
+[
+ undefined,
+ null,
+ false,
+ "cow",
+ NaN,
+ 67,
+ Infinity,
+ -Infinity,
+ Math.cos, // builtin functions with no [[Construct]] slot
+ Math.cos.bind(Math) // bound builtin functions with no [[Construct]] slot
+].forEach(function(val) {
+ assertEquals(Array.isArray(Array.of.call(val, val)), true);
});
+
+
+(function testBoundConstructor() {
+ var boundFn = (function() {}).bind(null);
+ var instance = Array.of.call(boundFn, 1, 2, 3);
+ assertEquals(instance.length, 3);
+ assertEquals(instance instanceof boundFn, true);
+ assertEquals(Array.isArray(instance), false);
+})();
--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
---
You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.