Commit 6dc82c18 authored by caitpotter88's avatar caitpotter88 Committed by Commit bot

Implement IsConstructor() abstract operation

LOG=N
R=dpino@igalia.com, arv@chromium.org, dslomov@chromium.org
BUG=

Review URL: https://codereview.chromium.org/851163007

Cr-Commit-Position: refs/heads/master@{#26130}
parent c15c7373
......@@ -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);
}
......
......@@ -326,6 +326,34 @@ RUNTIME_FUNCTION(Runtime_SetNativeFlag) {
}
RUNTIME_FUNCTION(Runtime_IsConstructor) {
HandleScope handles(isolate);
RUNTIME_ASSERT(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
// TODO(caitp): implement this in a better/simpler way, allow inlining via TF
if (object->IsJSFunction()) {
Handle<JSFunction> func = Handle<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()) {
Handle<JSFunction> bound = Handle<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);
......
......@@ -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) \
......
......@@ -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);
})();
......@@ -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);
})();
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment