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) { ...@@ -149,7 +149,7 @@ function ArrayFrom(arrayLike, mapfn, receiver) {
var nextValue; var nextValue;
if (!IS_UNDEFINED(iterable)) { if (!IS_UNDEFINED(iterable)) {
result = IS_SPEC_FUNCTION(this) && this.prototype ? new this() : []; result = %IsConstructor(this) ? new this() : [];
k = 0; k = 0;
for (nextValue of items) { for (nextValue of items) {
...@@ -162,8 +162,7 @@ function ArrayFrom(arrayLike, mapfn, receiver) { ...@@ -162,8 +162,7 @@ function ArrayFrom(arrayLike, mapfn, receiver) {
return result; return result;
} else { } else {
var len = ToLength(items.length); var len = ToLength(items.length);
result = IS_SPEC_FUNCTION(this) && this.prototype ? new this(len) : result = %IsConstructor(this) ? new this(len) : new $Array(len);
new $Array(len);
for (k = 0; k < len; ++k) { for (k = 0; k < len; ++k) {
nextValue = items[k]; nextValue = items[k];
...@@ -182,7 +181,7 @@ function ArrayOf() { ...@@ -182,7 +181,7 @@ function ArrayOf() {
var length = %_ArgumentsLength(); var length = %_ArgumentsLength();
var constructor = this; var constructor = this;
// TODO: Implement IsConstructor (ES6 section 7.2.5) // 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++) { for (var i = 0; i < length; i++) {
%AddElement(array, i, %_Arguments(i), NONE); %AddElement(array, i, %_Arguments(i), NONE);
} }
......
...@@ -326,6 +326,34 @@ RUNTIME_FUNCTION(Runtime_SetNativeFlag) { ...@@ -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) { RUNTIME_FUNCTION(Runtime_SetInlineBuiltinFlag) {
SealHandleScope shs(isolate); SealHandleScope shs(isolate);
RUNTIME_ASSERT(args.length() == 1); RUNTIME_ASSERT(args.length() == 1);
......
...@@ -73,6 +73,7 @@ namespace internal { ...@@ -73,6 +73,7 @@ namespace internal {
F(CompileForOnStackReplacement, 1, 1) \ F(CompileForOnStackReplacement, 1, 1) \
F(SetAllocationTimeout, -1 /* 2 || 3 */, 1) \ F(SetAllocationTimeout, -1 /* 2 || 3 */, 1) \
F(SetNativeFlag, 1, 1) \ F(SetNativeFlag, 1, 1) \
F(IsConstructor, 1, 1) \
F(SetInlineBuiltinFlag, 1, 1) \ F(SetInlineBuiltinFlag, 1, 1) \
F(StoreArrayLiteralElement, 5, 1) \ F(StoreArrayLiteralElement, 5, 1) \
F(DebugPrepareStepInIfStepping, 1, 1) \ F(DebugPrepareStepInIfStepping, 1, 1) \
......
...@@ -118,6 +118,7 @@ testArrayFrom({}, Array); ...@@ -118,6 +118,7 @@ testArrayFrom({}, Array);
testArrayFrom(Object, Object); testArrayFrom(Object, Object);
testArrayFrom(Other, Other); testArrayFrom(Other, Other);
testArrayFrom(Math.cos, Array); 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); ...@@ -159,6 +159,26 @@ assertEquals(Array.of.length, 0);
assertThrows(function() { new Array.of() }, TypeError); // not a constructor assertThrows(function() { new Array.of() }, TypeError); // not a constructor
// When the this-value passed in is not a constructor, the result is an array. // 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