Revert of [runtime] Introduce dedicated JSBoundFunction to represent bound functions. (patchset #14 id:260001 of https://codereview.chromium.org/1542963002/ )

Reason for revert:
Breaks arm64 sim nosnap: https://build.chromium.org/p/client.v8/builders/V8%20Linux%20-%20arm64%20-%20sim%20-%20nosnap%20-%20debug/builds/805/steps/Check/logs/function-bind

Original issue's description:
> [runtime] Introduce dedicated JSBoundFunction to represent bound functions.
>
> According to the ES2015 specification, bound functions are exotic
> objects, and thus don't need to be implemented as JSFunctions. So
> we introduce a new JSBoundFunction type to represent bound functions
> and make them optimizable. This already improves the performance of
> calling or constructing bound functions by 10-100x depending on the
> use case because we avoid the crazy dance between JavaScript and C++
> that was implemented in v8natives.js previously.
>
> There's still room for improvement in the performance of actually
> creating bound functions, which is also relevant in practice, but
> we already have a plan how to accomplish that later.
>
> The mips/mips64 ports were contributed by akos.palfi@imgtec.com.
>
> CQ_INCLUDE_TRYBOTS=tryserver.chromium.linux:linux_chromium_rel_ng;tryserver.blink:linux_blink_rel
> BUG=chromium:535408, chromium:571299, v8:4629
> LOG=n
>
> Committed: https://crrev.com/ca8623eaa468cba65a5adafcdfb4615966f43ce2
> Cr-Commit-Position: refs/heads/master@{#33042}

TBR=cbruni@chromium.org,hpayer@chromium.org,yangguo@chromium.org,akos.palfi@imgtec.com
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=chromium:535408, chromium:571299, v8:4629

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

Cr-Commit-Position: refs/heads/master@{#33043}
This commit is contained in:
bmeurer 2015-12-26 20:41:46 -08:00 committed by Commit bot
parent ca8623eaa4
commit 1cf8b105d6
69 changed files with 891 additions and 1674 deletions

View File

@ -1329,6 +1329,12 @@ MaybeHandle<JSFunction> FindCaller(Isolate* isolate,
if (!caller->shared()->native() && potential_caller != NULL) {
caller = potential_caller;
}
// If caller is bound, return null. This is compatible with JSC, and
// allows us to make bound functions use the strict function map
// and its associated throwing caller and arguments.
if (caller->shared()->bound()) {
return MaybeHandle<JSFunction>();
}
// Censor if the caller is not a sloppy mode function.
// Change from ES5, which used to throw, see:
// https://bugs.ecmascript.org/show_bug.cgi?id=310

View File

@ -548,7 +548,7 @@ Handle<JSFunction> ApiNatives::CreateApiFunction(
// Mark instance as callable in the map.
if (!obj->instance_call_handler()->IsUndefined()) {
map->set_is_callable();
map->set_is_constructor();
map->set_is_constructor(true);
}
// Recursively copy parent instance templates' accessors,

View File

@ -4412,16 +4412,13 @@ void Function::SetName(v8::Local<v8::String> name) {
Local<Value> Function::GetName() const {
auto self = Utils::OpenHandle(this);
if (self->IsJSBoundFunction()) {
auto func = i::Handle<i::JSBoundFunction>::cast(self);
return Utils::ToLocal(handle(func->name(), func->GetIsolate()));
if (!self->IsJSFunction()) {
return ToApiHandle<Primitive>(
self->GetIsolate()->factory()->undefined_value());
}
if (self->IsJSFunction()) {
auto func = i::Handle<i::JSFunction>::cast(self);
return Utils::ToLocal(handle(func->shared()->name(), func->GetIsolate()));
}
return ToApiHandle<Primitive>(
self->GetIsolate()->factory()->undefined_value());
auto func = i::Handle<i::JSFunction>::cast(self);
return Utils::ToLocal(i::Handle<i::Object>(func->shared()->name(),
func->GetIsolate()));
}
@ -4540,13 +4537,18 @@ int Function::ScriptId() const {
Local<v8::Value> Function::GetBoundFunction() const {
auto self = Utils::OpenHandle(this);
if (self->IsJSBoundFunction()) {
auto bound_function = i::Handle<i::JSBoundFunction>::cast(self);
auto bound_target_function = i::handle(
bound_function->bound_target_function(), bound_function->GetIsolate());
return Utils::CallableToLocal(bound_target_function);
if (!self->IsJSFunction()) {
return v8::Undefined(reinterpret_cast<v8::Isolate*>(self->GetIsolate()));
}
return v8::Undefined(reinterpret_cast<v8::Isolate*>(self->GetIsolate()));
auto func = i::Handle<i::JSFunction>::cast(self);
if (!func->shared()->bound()) {
return v8::Undefined(reinterpret_cast<v8::Isolate*>(func->GetIsolate()));
}
i::Handle<i::BindingsArray> bound_args = i::Handle<i::BindingsArray>(
i::BindingsArray::cast(func->function_bindings()));
i::Handle<i::Object> original(bound_args->bound_function(),
func->GetIsolate());
return Utils::CallableToLocal(i::Handle<i::JSFunction>::cast(original));
}

View File

@ -1893,109 +1893,6 @@ void Builtins::Generate_CallFunction(MacroAssembler* masm,
}
namespace {
void Generate_PushBoundArguments(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- r0 : the number of arguments (not including the receiver)
// -- r1 : target (checked to be a JSBoundFunction)
// -- r3 : new.target (only in case of [[Construct]])
// -----------------------------------
// Load [[BoundArguments]] into r2 and length of that into r4.
Label no_bound_arguments;
__ ldr(r2, FieldMemOperand(r1, JSBoundFunction::kBoundArgumentsOffset));
__ ldr(r4, FieldMemOperand(r2, FixedArray::kLengthOffset));
__ SmiUntag(r4);
__ cmp(r4, Operand(0));
__ b(eq, &no_bound_arguments);
{
// ----------- S t a t e -------------
// -- r0 : the number of arguments (not including the receiver)
// -- r1 : target (checked to be a JSBoundFunction)
// -- r2 : the [[BoundArguments]] (implemented as FixedArray)
// -- r3 : new.target (only in case of [[Construct]])
// -- r4 : the number of [[BoundArguments]]
// -----------------------------------
// Reserve stack space for the [[BoundArguments]].
{
Label done;
__ sub(sp, sp, Operand(r4, LSL, kPointerSizeLog2));
// Check the stack for overflow. We are not trying to catch interruptions
// (i.e. debug break and preemption) here, so check the "real stack
// limit".
__ CompareRoot(sp, Heap::kRealStackLimitRootIndex);
__ b(gt, &done); // Signed comparison.
// Restore the stack pointer.
__ add(sp, sp, Operand(r4, LSL, kPointerSizeLog2));
{
FrameScope scope(masm, StackFrame::MANUAL);
__ EnterFrame(StackFrame::INTERNAL);
__ CallRuntime(Runtime::kThrowStackOverflow, 0);
}
__ bind(&done);
}
// Relocate arguments down the stack.
{
Label loop, done_loop;
__ mov(r5, Operand(0));
__ bind(&loop);
__ cmp(r5, r0);
__ b(gt, &done_loop);
__ ldr(ip, MemOperand(sp, r4, LSL, kPointerSizeLog2));
__ str(ip, MemOperand(sp, r5, LSL, kPointerSizeLog2));
__ add(r4, r4, Operand(1));
__ add(r5, r5, Operand(1));
__ b(&loop);
__ bind(&done_loop);
}
// Copy [[BoundArguments]] to the stack (below the arguments).
{
Label loop;
__ ldr(r4, FieldMemOperand(r2, FixedArray::kLengthOffset));
__ SmiUntag(r4);
__ add(r2, r2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
__ bind(&loop);
__ sub(r4, r4, Operand(1), SetCC);
__ ldr(ip, MemOperand(r2, r4, LSL, kPointerSizeLog2));
__ str(ip, MemOperand(sp, r0, LSL, kPointerSizeLog2));
__ add(r0, r0, Operand(1));
__ b(gt, &loop);
}
}
__ bind(&no_bound_arguments);
}
} // namespace
// static
void Builtins::Generate_CallBoundFunction(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- r0 : the number of arguments (not including the receiver)
// -- r1 : the function to call (checked to be a JSBoundFunction)
// -----------------------------------
__ AssertBoundFunction(r1);
// Patch the receiver to [[BoundThis]].
__ ldr(ip, FieldMemOperand(r1, JSBoundFunction::kBoundThisOffset));
__ str(ip, MemOperand(sp, r0, LSL, kPointerSizeLog2));
// Push the [[BoundArguments]] onto the stack.
Generate_PushBoundArguments(masm);
// Call the [[BoundTargetFunction]] via the Call builtin.
__ ldr(r1, FieldMemOperand(r1, JSBoundFunction::kBoundTargetFunctionOffset));
__ mov(ip, Operand(ExternalReference(Builtins::kCall_ReceiverIsAny,
masm->isolate())));
__ ldr(ip, MemOperand(ip));
__ add(pc, ip, Operand(Code::kHeaderSize - kHeapObjectTag));
}
// static
void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) {
// ----------- S t a t e -------------
@ -2009,9 +1906,6 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) {
__ CompareObjectType(r1, r4, r5, JS_FUNCTION_TYPE);
__ Jump(masm->isolate()->builtins()->CallFunction(mode),
RelocInfo::CODE_TARGET, eq);
__ cmp(r5, Operand(JS_BOUND_FUNCTION_TYPE));
__ Jump(masm->isolate()->builtins()->CallBoundFunction(),
RelocInfo::CODE_TARGET, eq);
__ cmp(r5, Operand(JS_PROXY_TYPE));
__ b(ne, &non_function);
@ -2070,31 +1964,6 @@ void Builtins::Generate_ConstructFunction(MacroAssembler* masm) {
}
// static
void Builtins::Generate_ConstructBoundFunction(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- r0 : the number of arguments (not including the receiver)
// -- r1 : the function to call (checked to be a JSBoundFunction)
// -- r3 : the new target (checked to be a constructor)
// -----------------------------------
__ AssertBoundFunction(r1);
// Push the [[BoundArguments]] onto the stack.
Generate_PushBoundArguments(masm);
// Patch new.target to [[BoundTargetFunction]] if new.target equals target.
__ cmp(r1, r3);
__ ldr(r3, FieldMemOperand(r1, JSBoundFunction::kBoundTargetFunctionOffset),
eq);
// Construct the [[BoundTargetFunction]] via the Construct builtin.
__ ldr(r1, FieldMemOperand(r1, JSBoundFunction::kBoundTargetFunctionOffset));
__ mov(ip, Operand(ExternalReference(Builtins::kConstruct, masm->isolate())));
__ ldr(ip, MemOperand(ip));
__ add(pc, ip, Operand(Code::kHeaderSize - kHeapObjectTag));
}
// static
void Builtins::Generate_ConstructProxy(MacroAssembler* masm) {
// ----------- S t a t e -------------
@ -2138,12 +2007,6 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
__ tst(r2, Operand(1 << Map::kIsConstructor));
__ b(eq, &non_constructor);
// Only dispatch to bound functions after checking whether they are
// constructors.
__ cmp(r5, Operand(JS_BOUND_FUNCTION_TYPE));
__ Jump(masm->isolate()->builtins()->ConstructBoundFunction(),
RelocInfo::CODE_TARGET, eq);
// Only dispatch to proxies after checking whether they are constructors.
__ cmp(r5, Operand(JS_PROXY_TYPE));
__ Jump(masm->isolate()->builtins()->ConstructProxy(), RelocInfo::CODE_TARGET,

View File

@ -1346,6 +1346,16 @@ void InstanceOfStub::Generate(MacroAssembler* masm) {
__ tst(scratch, Operand(1 << Map::kHasNonInstancePrototype));
__ b(ne, &slow_case);
// Ensure that {function} is not bound.
Register const shared_info = scratch;
__ ldr(shared_info,
FieldMemOperand(function, JSFunction::kSharedFunctionInfoOffset));
__ ldr(scratch, FieldMemOperand(shared_info,
SharedFunctionInfo::kCompilerHintsOffset));
__ tst(scratch,
Operand(Smi::FromInt(1 << SharedFunctionInfo::kBoundFunction)));
__ b(ne, &slow_case);
// Get the "prototype" (or initial map) of the {function}.
__ ldr(function_prototype,
FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset));

View File

@ -2815,19 +2815,6 @@ void MacroAssembler::AssertFunction(Register object) {
}
void MacroAssembler::AssertBoundFunction(Register object) {
if (emit_debug_code()) {
STATIC_ASSERT(kSmiTag == 0);
tst(object, Operand(kSmiTagMask));
Check(ne, kOperandIsASmiAndNotABoundFunction);
push(object);
CompareObjectType(object, object, object, JS_BOUND_FUNCTION_TYPE);
pop(object);
Check(eq, kOperandIsNotABoundFunction);
}
}
void MacroAssembler::AssertUndefinedOrAllocationSite(Register object,
Register scratch) {
if (emit_debug_code()) {

View File

@ -1291,10 +1291,6 @@ class MacroAssembler: public Assembler {
// Abort execution if argument is not a JSFunction, enabled via --debug-code.
void AssertFunction(Register object);
// Abort execution if argument is not a JSBoundFunction,
// enabled via --debug-code.
void AssertBoundFunction(Register object);
// Abort execution if argument is not undefined or an AllocationSite, enabled
// via --debug-code.
void AssertUndefinedOrAllocationSite(Register object, Register scratch);

View File

@ -1881,108 +1881,6 @@ void Builtins::Generate_CallFunction(MacroAssembler* masm,
}
namespace {
void Generate_PushBoundArguments(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- x0 : the number of arguments (not including the receiver)
// -- x1 : target (checked to be a JSBoundFunction)
// -- x3 : new.target (only in case of [[Construct]])
// -----------------------------------
// Load [[BoundArguments]] into x2 and length of that into x4.
Label no_bound_arguments;
__ Ldr(x2, FieldMemOperand(x1, JSBoundFunction::kBoundArgumentsOffset));
__ Ldrsw(x4, UntagSmiFieldMemOperand(x2, FixedArray::kLengthOffset));
__ Cmp(x4, 0);
__ B(eq, &no_bound_arguments);
{
// ----------- S t a t e -------------
// -- x0 : the number of arguments (not including the receiver)
// -- x1 : target (checked to be a JSBoundFunction)
// -- x2 : the [[BoundArguments]] (implemented as FixedArray)
// -- x3 : new.target (only in case of [[Construct]])
// -- x4 : the number of [[BoundArguments]]
// -----------------------------------
// Reserve stack space for the [[BoundArguments]].
{
Label done;
__ Claim(x4);
// Check the stack for overflow. We are not trying to catch interruptions
// (i.e. debug break and preemption) here, so check the "real stack
// limit".
__ CompareRoot(jssp, Heap::kRealStackLimitRootIndex);
__ B(gt, &done); // Signed comparison.
// Restore the stack pointer.
__ Drop(x4);
{
FrameScope scope(masm, StackFrame::MANUAL);
__ EnterFrame(StackFrame::INTERNAL);
__ CallRuntime(Runtime::kThrowStackOverflow, 0);
}
__ Bind(&done);
}
// Relocate arguments down the stack.
{
Label loop, done_loop;
__ Mov(x5, 0);
__ Bind(&loop);
__ Cmp(x5, x0);
__ B(gt, &done_loop);
__ Peek(x10, Operand(x4, LSL, kPointerSizeLog2));
__ Poke(x10, Operand(x5, LSL, kPointerSizeLog2));
__ Add(x4, x4, 1);
__ Add(x5, x5, 1);
__ B(&loop);
__ Bind(&done_loop);
}
// Copy [[BoundArguments]] to the stack (below the arguments).
{
Label loop;
__ Ldrsw(x4, UntagSmiFieldMemOperand(x2, FixedArray::kLengthOffset));
__ Add(x2, x2, FixedArray::kHeaderSize - kHeapObjectTag);
__ Bind(&loop);
__ Subs(x4, x4, 1);
__ Ldr(x10, MemOperand(x2, x4, LSL, kPointerSizeLog2));
__ Poke(x10, Operand(x0, LSL, kPointerSizeLog2));
__ Add(x0, x0, 1);
__ B(gt, &loop);
}
}
__ Bind(&no_bound_arguments);
}
} // namespace
// static
void Builtins::Generate_CallBoundFunction(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- x0 : the number of arguments (not including the receiver)
// -- x1 : the function to call (checked to be a JSBoundFunction)
// -----------------------------------
__ AssertBoundFunction(x1);
// Patch the receiver to [[BoundThis]].
__ Ldr(x10, FieldMemOperand(x1, JSBoundFunction::kBoundThisOffset));
__ Poke(x10, Operand(x0, LSL, kPointerSizeLog2));
// Push the [[BoundArguments]] onto the stack.
Generate_PushBoundArguments(masm);
// Call the [[BoundTargetFunction]] via the Call builtin.
__ Ldr(x1, FieldMemOperand(x1, JSBoundFunction::kBoundTargetFunctionOffset));
__ Mov(x10,
ExternalReference(Builtins::kCall_ReceiverIsAny, masm->isolate()));
__ Ldr(x11, MemOperand(x10));
__ Add(x12, x11, Code::kHeaderSize - kHeapObjectTag);
__ Br(x12);
}
// static
void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) {
// ----------- S t a t e -------------
@ -1996,9 +1894,6 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) {
__ CompareObjectType(x1, x4, x5, JS_FUNCTION_TYPE);
__ Jump(masm->isolate()->builtins()->CallFunction(mode),
RelocInfo::CODE_TARGET, eq);
__ Cmp(x5, JS_BOUND_FUNCTION_TYPE);
__ Jump(masm->isolate()->builtins()->CallBoundFunction(),
RelocInfo::CODE_TARGET, eq);
__ Cmp(x5, JS_PROXY_TYPE);
__ B(ne, &non_function);
@ -2057,37 +1952,6 @@ void Builtins::Generate_ConstructFunction(MacroAssembler* masm) {
}
// static
void Builtins::Generate_ConstructBoundFunction(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- x0 : the number of arguments (not including the receiver)
// -- x1 : the function to call (checked to be a JSBoundFunction)
// -- x3 : the new target (checked to be a constructor)
// -----------------------------------
__ AssertBoundFunction(x1);
// Push the [[BoundArguments]] onto the stack.
Generate_PushBoundArguments(masm);
// Patch new.target to [[BoundTargetFunction]] if new.target equals target.
{
Label done;
__ Cmp(x1, x3);
__ B(ne, &done);
__ Ldr(x3,
FieldMemOperand(x1, JSBoundFunction::kBoundTargetFunctionOffset));
__ Bind(&done);
}
// Construct the [[BoundTargetFunction]] via the Construct builtin.
__ Ldr(x1, FieldMemOperand(x1, JSBoundFunction::kBoundTargetFunctionOffset));
__ Mov(x10, ExternalReference(Builtins::kConstruct, masm->isolate()));
__ Ldr(x11, MemOperand(x10));
__ Add(x12, x11, Code::kHeaderSize - kHeapObjectTag);
__ Br(x12);
}
// static
void Builtins::Generate_ConstructProxy(MacroAssembler* masm) {
// ----------- S t a t e -------------
@ -2130,12 +1994,6 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
__ Ldrb(x2, FieldMemOperand(x4, Map::kBitFieldOffset));
__ TestAndBranchIfAllClear(x2, 1 << Map::kIsConstructor, &non_constructor);
// Only dispatch to bound functions after checking whether they are
// constructors.
__ Cmp(x5, JS_BOUND_FUNCTION_TYPE);
__ Jump(masm->isolate()->builtins()->ConstructBoundFunction(),
RelocInfo::CODE_TARGET, eq);
// Only dispatch to proxies after checking whether they are constructors.
__ Cmp(x5, JS_PROXY_TYPE);
__ Jump(masm->isolate()->builtins()->ConstructProxy(), RelocInfo::CODE_TARGET,

View File

@ -1550,6 +1550,17 @@ void InstanceOfStub::Generate(MacroAssembler* masm) {
__ Ldrb(scratch, FieldMemOperand(function_map, Map::kBitFieldOffset));
__ Tbnz(scratch, Map::kHasNonInstancePrototype, &slow_case);
// Ensure that {function} is not bound.
Register const shared_info = scratch;
Register const scratch_w = scratch.W();
__ Ldr(shared_info,
FieldMemOperand(function, JSFunction::kSharedFunctionInfoOffset));
// On 64-bit platforms, compiler hints field is not a smi. See definition of
// kCompilerHintsOffset in src/objects.h.
__ Ldr(scratch_w, FieldMemOperand(shared_info,
SharedFunctionInfo::kCompilerHintsOffset));
__ Tbnz(scratch_w, SharedFunctionInfo::kBoundFunction, &slow_case);
// Get the "prototype" (or initial map) of the {function}.
__ Ldr(function_prototype,
FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset));

View File

@ -1626,19 +1626,6 @@ void MacroAssembler::AssertFunction(Register object) {
}
void MacroAssembler::AssertBoundFunction(Register object) {
if (emit_debug_code()) {
AssertNotSmi(object, kOperandIsASmiAndNotABoundFunction);
UseScratchRegisterScope temps(this);
Register temp = temps.AcquireX();
CompareObjectType(object, temp, temp, JS_BOUND_FUNCTION_TYPE);
Check(eq, kOperandIsNotABoundFunction);
}
}
void MacroAssembler::AssertUndefinedOrAllocationSite(Register object,
Register scratch) {
if (emit_debug_code()) {

View File

@ -966,10 +966,6 @@ class MacroAssembler : public Assembler {
// Abort execution if argument is not a JSFunction, enabled via --debug-code.
void AssertFunction(Register object);
// Abort execution if argument is not a JSBoundFunction,
// enabled via --debug-code.
void AssertBoundFunction(Register object);
// Abort execution if argument is not undefined or an AllocationSite, enabled
// via --debug-code.
void AssertUndefinedOrAllocationSite(Register object, Register scratch);

View File

@ -146,14 +146,11 @@ namespace internal {
V(kObjectFoundInSmiOnlyArray, "Object found in smi-only array") \
V(kObjectLiteralWithComplexProperty, "Object literal with complex property") \
V(kOffsetOutOfRange, "Offset out of range") \
V(kOperandIsASmiAndNotABoundFunction, \
"Operand is a smi and not a bound function") \
V(kOperandIsASmiAndNotAFunction, "Operand is a smi and not a function") \
V(kOperandIsASmiAndNotAName, "Operand is a smi and not a name") \
V(kOperandIsASmiAndNotAString, "Operand is a smi and not a string") \
V(kOperandIsASmi, "Operand is a smi") \
V(kOperandIsNotADate, "Operand is not a date") \
V(kOperandIsNotABoundFunction, "Operand is not a bound function") \
V(kOperandIsNotAFunction, "Operand is not a function") \
V(kOperandIsNotAName, "Operand is not a name") \
V(kOperandIsNotANumber, "Operand is not a number") \

View File

@ -269,7 +269,8 @@ class Genesis BASE_EMBEDDED {
FUNCTION_WITH_WRITEABLE_PROTOTYPE,
FUNCTION_WITH_READONLY_PROTOTYPE,
// Without prototype.
FUNCTION_WITHOUT_PROTOTYPE
FUNCTION_WITHOUT_PROTOTYPE,
BOUND_FUNCTION
};
static bool IsFunctionModeWithPrototype(FunctionMode function_mode) {
@ -485,7 +486,7 @@ void Genesis::SetFunctionInstanceDescriptor(Handle<Map> map,
Handle<Map> Genesis::CreateSloppyFunctionMap(FunctionMode function_mode) {
Handle<Map> map = factory()->NewMap(JS_FUNCTION_TYPE, JSFunction::kSize);
SetFunctionInstanceDescriptor(map, function_mode);
if (IsFunctionModeWithPrototype(function_mode)) map->set_is_constructor();
map->set_is_constructor(IsFunctionModeWithPrototype(function_mode));
map->set_is_callable();
return map;
}
@ -608,22 +609,35 @@ void Genesis::SetStrictFunctionInstanceDescriptor(Handle<Map> map,
PropertyAttributes roc_attribs =
static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY);
DCHECK(function_mode == FUNCTION_WITH_WRITEABLE_PROTOTYPE ||
function_mode == FUNCTION_WITH_READONLY_PROTOTYPE ||
function_mode == FUNCTION_WITHOUT_PROTOTYPE);
{ // Add length.
Handle<AccessorInfo> length =
Accessors::FunctionLengthInfo(isolate(), roc_attribs);
AccessorConstantDescriptor d(Handle<Name>(Name::cast(length->name())),
length, roc_attribs);
map->AppendDescriptor(&d);
}
{ // Add name.
Handle<AccessorInfo> name =
Accessors::FunctionNameInfo(isolate(), roc_attribs);
AccessorConstantDescriptor d(Handle<Name>(Name::cast(name->name())), name,
roc_attribs);
map->AppendDescriptor(&d);
if (function_mode == BOUND_FUNCTION) {
{ // Add length.
Handle<String> length_string = isolate()->factory()->length_string();
DataDescriptor d(length_string, 0, roc_attribs, Representation::Tagged());
map->AppendDescriptor(&d);
}
{ // Add name.
Handle<String> name_string = isolate()->factory()->name_string();
DataDescriptor d(name_string, 1, roc_attribs, Representation::Tagged());
map->AppendDescriptor(&d);
}
} else {
DCHECK(function_mode == FUNCTION_WITH_WRITEABLE_PROTOTYPE ||
function_mode == FUNCTION_WITH_READONLY_PROTOTYPE ||
function_mode == FUNCTION_WITHOUT_PROTOTYPE);
{ // Add length.
Handle<AccessorInfo> length =
Accessors::FunctionLengthInfo(isolate(), roc_attribs);
AccessorConstantDescriptor d(Handle<Name>(Name::cast(length->name())),
length, roc_attribs);
map->AppendDescriptor(&d);
}
{ // Add name.
Handle<AccessorInfo> name =
Accessors::FunctionNameInfo(isolate(), roc_attribs);
AccessorConstantDescriptor d(Handle<Name>(Name::cast(name->name())), name,
roc_attribs);
map->AppendDescriptor(&d);
}
}
if (IsFunctionModeWithPrototype(function_mode)) {
// Add prototype.
@ -718,7 +732,7 @@ Handle<Map> Genesis::CreateStrictFunctionMap(
FunctionMode function_mode, Handle<JSFunction> empty_function) {
Handle<Map> map = factory()->NewMap(JS_FUNCTION_TYPE, JSFunction::kSize);
SetStrictFunctionInstanceDescriptor(map, function_mode);
if (IsFunctionModeWithPrototype(function_mode)) map->set_is_constructor();
map->set_is_constructor(IsFunctionModeWithPrototype(function_mode));
map->set_is_callable();
Map::SetPrototype(map, empty_function);
return map;
@ -729,7 +743,7 @@ Handle<Map> Genesis::CreateStrongFunctionMap(
Handle<JSFunction> empty_function, bool is_constructor) {
Handle<Map> map = factory()->NewMap(JS_FUNCTION_TYPE, JSFunction::kSize);
SetStrongFunctionInstanceDescriptor(map);
if (is_constructor) map->set_is_constructor();
map->set_is_constructor(is_constructor);
Map::SetPrototype(map, empty_function);
map->set_is_callable();
map->set_is_extensible(is_constructor);
@ -756,6 +770,21 @@ void Genesis::CreateStrictModeFunctionMaps(Handle<JSFunction> empty) {
// This map is installed in MakeFunctionInstancePrototypeWritable.
strict_function_map_writable_prototype_ =
CreateStrictFunctionMap(FUNCTION_WITH_WRITEABLE_PROTOTYPE, empty);
// Special map for non-constructor bound functions.
// TODO(bmeurer): Bound functions should not be represented as JSFunctions.
Handle<Map> bound_function_without_constructor_map =
CreateStrictFunctionMap(BOUND_FUNCTION, empty);
native_context()->set_bound_function_without_constructor_map(
*bound_function_without_constructor_map);
// Special map for constructor bound functions.
// TODO(bmeurer): Bound functions should not be represented as JSFunctions.
Handle<Map> bound_function_with_constructor_map =
Map::Copy(bound_function_without_constructor_map, "IsConstructor");
bound_function_with_constructor_map->set_is_constructor(true);
native_context()->set_bound_function_with_constructor_map(
*bound_function_with_constructor_map);
}
@ -1430,35 +1459,6 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
Context::JS_WEAK_SET_FUN_INDEX);
}
{ // --- B o u n d F u n c t i o n
Handle<Map> map =
factory->NewMap(JS_BOUND_FUNCTION_TYPE, JSBoundFunction::kSize);
map->set_is_callable();
Map::SetPrototype(map, empty_function);
PropertyAttributes roc_attribs =
static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY);
Map::EnsureDescriptorSlack(map, 2);
{ // length
DataDescriptor d(factory->length_string(), JSBoundFunction::kLengthIndex,
roc_attribs, Representation::Tagged());
map->AppendDescriptor(&d);
}
{ // name
DataDescriptor d(factory->name_string(), JSBoundFunction::kNameIndex,
roc_attribs, Representation::Tagged());
map->AppendDescriptor(&d);
}
map->SetInObjectProperties(2);
native_context()->set_bound_function_without_constructor_map(*map);
map = Map::Copy(map, "IsConstructor");
map->set_is_constructor();
native_context()->set_bound_function_with_constructor_map(*map);
}
{ // --- sloppy arguments map
// Make sure we can recognize argument objects at runtime.
// This is done by introducing an anonymous function with
@ -2285,7 +2285,7 @@ void Genesis::InstallJSProxyMaps() {
Handle<Map> proxy_function_map =
Map::Copy(isolate()->sloppy_function_without_prototype_map(), "Proxy");
proxy_function_map->set_is_constructor();
proxy_function_map->set_is_constructor(true);
native_context()->set_proxy_function_map(*proxy_function_map);
Handle<Map> proxy_map =
@ -2299,7 +2299,7 @@ void Genesis::InstallJSProxyMaps() {
Handle<Map> proxy_constructor_map =
Map::Copy(proxy_callable_map, "constructor Proxy");
proxy_constructor_map->set_is_constructor();
proxy_constructor_map->set_is_constructor(true);
native_context()->set_proxy_constructor_map(*proxy_constructor_map);
}
@ -2525,8 +2525,7 @@ bool Genesis::InstallNatives(ContextType context_type) {
// Set the lengths for the functions to satisfy ECMA-262.
concat->shared()->set_length(1);
}
// Install Function.prototype.apply, bind, call, and toString.
// Install Function.prototype.apply, call, and toString.
{
Handle<String> key = factory()->Function_string();
Handle<JSFunction> function =
@ -2535,11 +2534,9 @@ bool Genesis::InstallNatives(ContextType context_type) {
Handle<JSObject> proto =
Handle<JSObject>(JSObject::cast(function->instance_prototype()));
// Install the apply, bind, call and toString functions.
// Install the apply, call and toString functions.
SimpleInstallFunction(proto, factory()->apply_string(),
Builtins::kFunctionPrototypeApply, 2, false);
SimpleInstallFunction(proto, factory()->bind_string(),
Builtins::kFunctionPrototypeBind, 1, false);
SimpleInstallFunction(proto, factory()->call_string(),
Builtins::kFunctionPrototypeCall, 1, false);
SimpleInstallFunction(proto, factory()->toString_string(),

View File

@ -1973,78 +1973,12 @@ BUILTIN(FunctionConstructor) {
}
// ES6 section 19.2.3.2 Function.prototype.bind ( thisArg, ...args )
BUILTIN(FunctionPrototypeBind) {
HandleScope scope(isolate);
DCHECK_LE(1, args.length());
if (!args.receiver()->IsCallable()) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kFunctionBind));
}
// Allocate the bound function with the given {this_arg} and {args}.
Handle<JSReceiver> target = args.at<JSReceiver>(0);
Handle<Object> this_arg = isolate->factory()->undefined_value();
ScopedVector<Handle<Object>> argv(std::max(0, args.length() - 2));
if (args.length() > 1) {
this_arg = args.at<Object>(1);
for (int i = 2; i < args.length(); ++i) {
argv[i - 2] = args.at<Object>(i);
}
}
Handle<JSBoundFunction> function;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, function,
isolate->factory()->NewJSBoundFunction(target, this_arg, argv));
// TODO(bmeurer): Optimize the rest for the common cases where {target} is
// a function with some initial map or even a bound function.
// Setup the "length" property based on the "length" of the {target}.
Handle<Object> length(Smi::FromInt(0), isolate);
Maybe<bool> target_has_length =
JSReceiver::HasOwnProperty(target, isolate->factory()->length_string());
if (!target_has_length.IsJust()) {
return isolate->heap()->exception();
} else if (target_has_length.FromJust()) {
Handle<Object> target_length;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, target_length,
JSReceiver::GetProperty(target, isolate->factory()->length_string()));
if (target_length->IsNumber()) {
length = isolate->factory()->NewNumber(std::max(
0.0, DoubleToInteger(target_length->Number()) - argv.length()));
}
}
function->set_length(*length);
// Setup the "name" property based on the "name" of the {target}.
Handle<Object> target_name;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, target_name,
JSReceiver::GetProperty(target, isolate->factory()->name_string()));
Handle<String> name;
if (!target_name->IsString()) {
name = isolate->factory()->bound__string();
} else {
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, name, Name::ToFunctionName(Handle<String>::cast(target_name)));
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, name, isolate->factory()->NewConsString(
isolate->factory()->bound__string(), name));
}
function->set_name(*name);
return *function;
}
// ES6 section 19.2.3.5 Function.prototype.toString ( )
BUILTIN(FunctionPrototypeToString) {
HandleScope scope(isolate);
Handle<Object> receiver = args.receiver();
if (receiver->IsJSBoundFunction()) {
return *JSBoundFunction::ToString(Handle<JSBoundFunction>::cast(receiver));
} else if (receiver->IsJSFunction()) {
if (receiver->IsJSFunction()) {
return *JSFunction::ToString(Handle<JSFunction>::cast(receiver));
}
THROW_NEW_ERROR_RETURN_FAILURE(

View File

@ -68,7 +68,6 @@ inline bool operator&(BuiltinExtraArguments lhs, BuiltinExtraArguments rhs) {
V(DateToPrimitive, kNone) \
\
V(FunctionConstructor, kTargetAndNewTarget) \
V(FunctionPrototypeBind, kNone) \
V(FunctionPrototypeToString, kNone) \
\
V(GeneratorFunctionConstructor, kTargetAndNewTarget) \
@ -115,14 +114,12 @@ inline bool operator&(BuiltinExtraArguments lhs, BuiltinExtraArguments rhs) {
V(CallFunction_ReceiverIsNotNullOrUndefined, BUILTIN, UNINITIALIZED, \
kNoExtraICState) \
V(CallFunction_ReceiverIsAny, BUILTIN, UNINITIALIZED, kNoExtraICState) \
V(CallBoundFunction, BUILTIN, UNINITIALIZED, kNoExtraICState) \
V(Call_ReceiverIsNullOrUndefined, BUILTIN, UNINITIALIZED, kNoExtraICState) \
V(Call_ReceiverIsNotNullOrUndefined, BUILTIN, UNINITIALIZED, \
kNoExtraICState) \
V(Call_ReceiverIsAny, BUILTIN, UNINITIALIZED, kNoExtraICState) \
\
V(ConstructFunction, BUILTIN, UNINITIALIZED, kNoExtraICState) \
V(ConstructBoundFunction, BUILTIN, UNINITIALIZED, kNoExtraICState) \
V(ConstructProxy, BUILTIN, UNINITIALIZED, kNoExtraICState) \
V(Construct, BUILTIN, UNINITIALIZED, kNoExtraICState) \
\
@ -346,8 +343,6 @@ class Builtins {
static void Generate_CallFunction_ReceiverIsAny(MacroAssembler* masm) {
Generate_CallFunction(masm, ConvertReceiverMode::kAny);
}
// ES6 section 9.4.1.1 [[Call]] ( thisArgument, argumentsList)
static void Generate_CallBoundFunction(MacroAssembler* masm);
// ES6 section 7.3.12 Call(F, V, [argumentsList])
static void Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode);
static void Generate_Call_ReceiverIsNullOrUndefined(MacroAssembler* masm) {
@ -362,8 +357,6 @@ class Builtins {
// ES6 section 9.2.2 [[Construct]] ( argumentsList, newTarget)
static void Generate_ConstructFunction(MacroAssembler* masm);
// ES6 section 9.4.1.2 [[Construct]] (argumentsList, newTarget)
static void Generate_ConstructBoundFunction(MacroAssembler* masm);
// ES6 section 9.5.14 [[Construct]] ( argumentsList, newTarget)
static void Generate_ConstructProxy(MacroAssembler* masm);
// ES6 section 7.3.13 Construct (F, [argumentsList], [newTarget])

View File

@ -815,8 +815,11 @@ static void InsertCodeIntoOptimizedCodeMap(CompilationInfo* info) {
// Frame specialization implies function context specialization.
DCHECK(!info->is_frame_specializing());
// Cache optimized context-specific code.
// Do not cache bound functions.
Handle<JSFunction> function = info->closure();
if (function->shared()->bound()) return;
// Cache optimized context-specific code.
Handle<SharedFunctionInfo> shared(function->shared());
Handle<LiteralsArray> literals(function->literals());
Handle<Context> native_context(function->context()->native_context());

View File

@ -56,7 +56,7 @@ Reduction JSIntrinsicLowering::Reduce(Node* node) {
case Runtime::kInlineIsTypedArray:
return ReduceIsInstanceType(node, JS_TYPED_ARRAY_TYPE);
case Runtime::kInlineIsFunction:
return ReduceIsFunction(node);
return ReduceIsInstanceType(node, JS_FUNCTION_TYPE);
case Runtime::kInlineIsRegExp:
return ReduceIsInstanceType(node, JS_REGEXP_TYPE);
case Runtime::kInlineIsJSReceiver:
@ -251,48 +251,6 @@ Reduction JSIntrinsicLowering::ReduceIsInstanceType(
}
Reduction JSIntrinsicLowering::ReduceIsFunction(Node* node) {
Node* value = NodeProperties::GetValueInput(node, 0);
Type* value_type = NodeProperties::GetType(value);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
if (value_type->Is(Type::Function())) {
value = jsgraph()->TrueConstant();
} else {
// if (%_IsSmi(value)) {
// return false;
// } else {
// return FIRST_FUNCTION_TYPE <= %_GetInstanceType(%_GetMap(value))
// }
STATIC_ASSERT(LAST_TYPE == LAST_FUNCTION_TYPE);
Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), value);
Node* branch = graph()->NewNode(common()->Branch(), check, control);
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
Node* etrue = effect;
Node* vtrue = jsgraph()->FalseConstant();
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
Node* efalse = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForMapInstanceType()),
graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
value, effect, if_false),
effect, if_false);
Node* vfalse =
graph()->NewNode(machine()->Uint32LessThanOrEqual(),
jsgraph()->Int32Constant(FIRST_FUNCTION_TYPE), efalse);
control = graph()->NewNode(common()->Merge(2), if_true, if_false);
effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
value = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
vtrue, vfalse, control);
}
ReplaceWithValue(node, node, effect, control);
return Replace(value);
}
Reduction JSIntrinsicLowering::ReduceIsJSReceiver(Node* node) {
Node* value = NodeProperties::GetValueInput(node, 0);
Type* value_type = NodeProperties::GetType(value);

View File

@ -47,7 +47,6 @@ class JSIntrinsicLowering final : public AdvancedReducer {
Reduction ReduceIncrementStatsCounter(Node* node);
Reduction ReduceIsMinusZero(Node* node);
Reduction ReduceIsInstanceType(Node* node, InstanceType instance_type);
Reduction ReduceIsFunction(Node* node);
Reduction ReduceIsJSReceiver(Node* node);
Reduction ReduceIsSmi(Node* node);
Reduction ReduceJSValueGetValue(Node* node);

View File

@ -12182,8 +12182,8 @@ void HOptimizedGraphBuilder::GenerateIsFunction(CallRuntime* call) {
DCHECK(call->arguments()->length() == 1);
CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
HValue* value = Pop();
HHasInstanceTypeAndBranch* result = New<HHasInstanceTypeAndBranch>(
value, FIRST_FUNCTION_TYPE, LAST_FUNCTION_TYPE);
HHasInstanceTypeAndBranch* result =
New<HHasInstanceTypeAndBranch>(value, JS_FUNCTION_TYPE);
return ast_context()->ReturnControl(result, call->id());
}

View File

@ -1194,7 +1194,7 @@ Handle<JSFunction> Factory::NewFunction(Handle<Map> map,
function->set_code(info->code());
function->set_context(*context);
function->set_prototype_or_initial_map(*the_hole_value());
function->set_literals(LiteralsArray::cast(*empty_fixed_array()));
function->set_literals_or_bindings(*empty_fixed_array());
function->set_next_function_link(*undefined_value(), SKIP_WRITE_BARRIER);
isolate()->heap()->InitializeJSObjectBody(*function, *map, JSFunction::kSize);
return function;
@ -1359,7 +1359,8 @@ Handle<JSFunction> Factory::NewFunctionFromSharedFunctionInfo(
if (cached.literals != nullptr) {
result->set_literals(cached.literals);
} else {
} else if (!info->bound()) {
int number_of_literals = info->num_literals();
Handle<LiteralsArray> literals =
LiteralsArray::New(isolate(), handle(info->feedback_vector()),
@ -1941,60 +1942,6 @@ Handle<JSDataView> Factory::NewJSDataView(Handle<JSArrayBuffer> buffer,
}
MaybeHandle<JSBoundFunction> Factory::NewJSBoundFunction(
Handle<JSReceiver> target_function, Handle<Object> bound_this,
Vector<Handle<Object>> bound_args) {
DCHECK(target_function->IsCallable());
STATIC_ASSERT(Code::kMaxArguments <= FixedArray::kMaxLength);
if (bound_args.length() >= Code::kMaxArguments) {
THROW_NEW_ERROR(isolate(),
NewRangeError(MessageTemplate::kTooManyArguments),
JSBoundFunction);
}
// Determine the prototype of the {target_function}.
Handle<Object> prototype;
ASSIGN_RETURN_ON_EXCEPTION(isolate(), prototype,
Object::GetPrototype(isolate(), target_function),
JSBoundFunction);
// Create the [[BoundArguments]] for the result.
Handle<FixedArray> bound_arguments;
if (bound_args.length() == 0) {
bound_arguments = empty_fixed_array();
} else {
bound_arguments = NewFixedArray(bound_args.length());
for (int i = 0; i < bound_args.length(); ++i) {
bound_arguments->set(i, *bound_args[i]);
}
}
// Setup the map for the JSBoundFunction instance.
Handle<Map> map = handle(
target_function->IsConstructor()
? isolate()->native_context()->bound_function_with_constructor_map()
: isolate()
->native_context()
->bound_function_without_constructor_map(),
isolate());
if (map->prototype() != *prototype) {
map = Map::TransitionToPrototype(map, prototype, REGULAR_PROTOTYPE);
}
DCHECK_EQ(target_function->IsConstructor(), map->is_constructor());
// Setup the JSBoundFunction instance.
Handle<JSBoundFunction> result =
Handle<JSBoundFunction>::cast(NewJSObjectFromMap(map));
result->set_bound_target_function(*target_function);
result->set_bound_this(*bound_this);
result->set_bound_arguments(*bound_arguments);
result->set_creation_context(*isolate()->native_context());
result->set_length(Smi::FromInt(0));
result->set_name(*undefined_value(), SKIP_WRITE_BARRIER);
return result;
}
// ES6 section 9.5.15 ProxyCreate (target, handler)
Handle<JSProxy> Factory::NewJSProxy(Handle<JSReceiver> target,
Handle<JSReceiver> handler) {

View File

@ -477,11 +477,6 @@ class Factory final {
Handle<JSIteratorResult> NewJSIteratorResult(Handle<Object> value,
Handle<Object> done);
// Allocates a bound function.
MaybeHandle<JSBoundFunction> NewJSBoundFunction(
Handle<JSReceiver> target_function, Handle<Object> bound_this,
Vector<Handle<Object>> bound_args);
// Allocates a Harmony proxy.
Handle<JSProxy> NewJSProxy(Handle<JSReceiver> target,
Handle<JSReceiver> handler);

View File

@ -3157,9 +3157,9 @@ void FullCodeGenerator::EmitIsFunction(CallRuntime* expr) {
&if_true, &if_false, &fall_through);
__ JumpIfSmi(r0, if_false);
__ CompareObjectType(r0, r1, r2, FIRST_FUNCTION_TYPE);
__ CompareObjectType(r0, r1, r2, JS_FUNCTION_TYPE);
PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Split(hs, if_true, if_false, fall_through);
Split(eq, if_true, if_false, fall_through);
context()->Plug(if_true, if_false);
}

View File

@ -2866,9 +2866,9 @@ void FullCodeGenerator::EmitIsFunction(CallRuntime* expr) {
&if_true, &if_false, &fall_through);
__ JumpIfSmi(x0, if_false);
__ CompareObjectType(x0, x10, x11, FIRST_FUNCTION_TYPE);
__ CompareObjectType(x0, x10, x11, JS_FUNCTION_TYPE);
PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Split(hs, if_true, if_false, fall_through);
Split(eq, if_true, if_false, fall_through);
context()->Plug(if_true, if_false);
}

View File

@ -3032,9 +3032,9 @@ void FullCodeGenerator::EmitIsFunction(CallRuntime* expr) {
&if_true, &if_false, &fall_through);
__ JumpIfSmi(eax, if_false);
__ CmpObjectType(eax, FIRST_FUNCTION_TYPE, ebx);
__ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Split(above_equal, if_true, if_false, fall_through);
Split(equal, if_true, if_false, fall_through);
context()->Plug(if_true, if_false);
}

View File

@ -3146,7 +3146,7 @@ void FullCodeGenerator::EmitIsFunction(CallRuntime* expr) {
__ JumpIfSmi(v0, if_false);
__ GetObjectType(v0, a1, a2);
PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
__ Branch(if_true, hs, a2, Operand(FIRST_FUNCTION_TYPE));
__ Branch(if_true, eq, a2, Operand(JS_FUNCTION_TYPE));
__ Branch(if_false);
context()->Plug(if_true, if_false);

View File

@ -3152,7 +3152,7 @@ void FullCodeGenerator::EmitIsFunction(CallRuntime* expr) {
__ JumpIfSmi(v0, if_false);
__ GetObjectType(v0, a1, a2);
PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
__ Branch(if_true, hs, a2, Operand(FIRST_FUNCTION_TYPE));
__ Branch(if_true, eq, a2, Operand(JS_FUNCTION_TYPE));
__ Branch(if_false);
context()->Plug(if_true, if_false);

View File

@ -3020,9 +3020,9 @@ void FullCodeGenerator::EmitIsFunction(CallRuntime* expr) {
&if_true, &if_false, &fall_through);
__ JumpIfSmi(rax, if_false);
__ CmpObjectType(rax, FIRST_FUNCTION_TYPE, rbx);
__ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx);
PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Split(above_equal, if_true, if_false, fall_through);
Split(equal, if_true, if_false, fall_through);
context()->Plug(if_true, if_false);
}

View File

@ -215,7 +215,6 @@ namespace internal {
V(arguments_string, "arguments") \
V(Arguments_string, "Arguments") \
V(Array_string, "Array") \
V(bind_string, "bind") \
V(bool16x8_string, "bool16x8") \
V(Bool16x8_string, "Bool16x8") \
V(bool32x4_string, "bool32x4") \
@ -224,7 +223,6 @@ namespace internal {
V(Bool8x16_string, "Bool8x16") \
V(boolean_string, "boolean") \
V(Boolean_string, "Boolean") \
V(bound__string, "bound ") \
V(byte_length_string, "byteLength") \
V(byte_offset_string, "byteOffset") \
V(call_string, "call") \

View File

@ -120,7 +120,6 @@ StaticVisitorBase::VisitorId StaticVisitorBase::GetVisitorId(
case JS_MAP_ITERATOR_TYPE:
case JS_ITERATOR_RESULT_TYPE:
case JS_PROMISE_TYPE:
case JS_BOUND_FUNCTION_TYPE:
return GetVisitorIdForSize(kVisitJSObject, kVisitJSObjectGeneric,
instance_size, has_unboxed_fields);

View File

@ -1766,117 +1766,6 @@ void Builtins::Generate_CallFunction(MacroAssembler* masm,
}
namespace {
void Generate_PushBoundArguments(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- eax : the number of arguments (not including the receiver)
// -- edx : new.target (only in case of [[Construct]])
// -- edi : target (checked to be a JSBoundFunction)
// -----------------------------------
// Load [[BoundArguments]] into ecx and length of that into ebx.
Label no_bound_arguments;
__ mov(ecx, FieldOperand(edi, JSBoundFunction::kBoundArgumentsOffset));
__ mov(ebx, FieldOperand(ecx, FixedArray::kLengthOffset));
__ SmiUntag(ebx);
__ test(ebx, ebx);
__ j(zero, &no_bound_arguments);
{
// ----------- S t a t e -------------
// -- eax : the number of arguments (not including the receiver)
// -- edx : new.target (only in case of [[Construct]])
// -- edi : target (checked to be a JSBoundFunction)
// -- ecx : the [[BoundArguments]] (implemented as FixedArray)
// -- ebx : the number of [[BoundArguments]]
// -----------------------------------
// Reserve stack space for the [[BoundArguments]].
{
Label done;
__ lea(ecx, Operand(ebx, times_pointer_size, 0));
__ sub(esp, ecx);
// Check the stack for overflow. We are not trying to catch interruptions
// (i.e. debug break and preemption) here, so check the "real stack
// limit".
__ CompareRoot(esp, ecx, Heap::kRealStackLimitRootIndex);
__ j(greater, &done, Label::kNear); // Signed comparison.
// Restore the stack pointer.
__ lea(esp, Operand(esp, ebx, times_pointer_size, 0));
{
FrameScope scope(masm, StackFrame::MANUAL);
__ EnterFrame(StackFrame::INTERNAL);
__ CallRuntime(Runtime::kThrowStackOverflow, 0);
}
__ bind(&done);
}
// Adjust effective number of arguments to include return address.
__ inc(eax);
// Relocate arguments and return address down the stack.
{
Label loop;
__ Set(ecx, 0);
__ lea(ebx, Operand(esp, ebx, times_pointer_size, 0));
__ bind(&loop);
__ movd(xmm0, Operand(ebx, ecx, times_pointer_size, 0));
__ movd(Operand(esp, ecx, times_pointer_size, 0), xmm0);
__ inc(ecx);
__ cmp(ecx, eax);
__ j(less, &loop);
}
// Copy [[BoundArguments]] to the stack (below the arguments).
{
Label loop;
__ mov(ecx, FieldOperand(edi, JSBoundFunction::kBoundArgumentsOffset));
__ mov(ebx, FieldOperand(ecx, FixedArray::kLengthOffset));
__ SmiUntag(ebx);
__ bind(&loop);
__ dec(ebx);
__ movd(xmm0, FieldOperand(ecx, ebx, times_pointer_size,
FixedArray::kHeaderSize));
__ movd(Operand(esp, eax, times_pointer_size, 0), xmm0);
__ lea(eax, Operand(eax, 1));
__ j(greater, &loop);
}
// Adjust effective number of arguments (eax contains the number of
// arguments from the call plus return address plus the number of
// [[BoundArguments]]), so we need to subtract one for the return address.
__ dec(eax);
}
__ bind(&no_bound_arguments);
}
} // namespace
// static
void Builtins::Generate_CallBoundFunction(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- eax : the number of arguments (not including the receiver)
// -- edi : the function to call (checked to be a JSBoundFunction)
// -----------------------------------
__ AssertBoundFunction(edi);
// Patch the receiver to [[BoundThis]].
__ mov(ebx, FieldOperand(edi, JSBoundFunction::kBoundThisOffset));
__ mov(Operand(esp, eax, times_pointer_size, kPointerSize), ebx);
// Push the [[BoundArguments]] onto the stack.
Generate_PushBoundArguments(masm);
// Call the [[BoundTargetFunction]] via the Call builtin.
__ mov(edi, FieldOperand(edi, JSBoundFunction::kBoundTargetFunctionOffset));
__ mov(ecx, Operand::StaticVariable(ExternalReference(
Builtins::kCall_ReceiverIsAny, masm->isolate())));
__ lea(ecx, FieldOperand(ecx, Code::kHeaderSize));
__ jmp(ecx);
}
// static
void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) {
// ----------- S t a t e -------------
@ -1890,9 +1779,6 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) {
__ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
__ j(equal, masm->isolate()->builtins()->CallFunction(mode),
RelocInfo::CODE_TARGET);
__ CmpInstanceType(ecx, JS_BOUND_FUNCTION_TYPE);
__ j(equal, masm->isolate()->builtins()->CallBoundFunction(),
RelocInfo::CODE_TARGET);
__ CmpInstanceType(ecx, JS_PROXY_TYPE);
__ j(not_equal, &non_function);
@ -1953,36 +1839,6 @@ void Builtins::Generate_ConstructFunction(MacroAssembler* masm) {
}
// static
void Builtins::Generate_ConstructBoundFunction(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- eax : the number of arguments (not including the receiver)
// -- edx : the new target (checked to be a constructor)
// -- edi : the constructor to call (checked to be a JSBoundFunction)
// -----------------------------------
__ AssertBoundFunction(edi);
// Push the [[BoundArguments]] onto the stack.
Generate_PushBoundArguments(masm);
// Patch new.target to [[BoundTargetFunction]] if new.target equals target.
{
Label done;
__ cmp(edi, edx);
__ j(not_equal, &done, Label::kNear);
__ mov(edx, FieldOperand(edi, JSBoundFunction::kBoundTargetFunctionOffset));
__ bind(&done);
}
// Construct the [[BoundTargetFunction]] via the Construct builtin.
__ mov(edi, FieldOperand(edi, JSBoundFunction::kBoundTargetFunctionOffset));
__ mov(ecx, Operand::StaticVariable(
ExternalReference(Builtins::kConstruct, masm->isolate())));
__ lea(ecx, FieldOperand(ecx, Code::kHeaderSize));
__ jmp(ecx);
}
// static
void Builtins::Generate_ConstructProxy(MacroAssembler* masm) {
// ----------- S t a t e -------------
@ -2027,12 +1883,6 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
__ test_b(FieldOperand(ecx, Map::kBitFieldOffset), 1 << Map::kIsConstructor);
__ j(zero, &non_constructor, Label::kNear);
// Only dispatch to bound functions after checking whether they are
// constructors.
__ CmpInstanceType(ecx, JS_BOUND_FUNCTION_TYPE);
__ j(equal, masm->isolate()->builtins()->ConstructBoundFunction(),
RelocInfo::CODE_TARGET);
// Only dispatch to proxies after checking whether they are constructors.
__ CmpInstanceType(ecx, JS_PROXY_TYPE);
__ j(equal, masm->isolate()->builtins()->ConstructProxy(),

View File

@ -2557,6 +2557,14 @@ void InstanceOfStub::Generate(MacroAssembler* masm) {
static_cast<uint8_t>(1 << Map::kHasNonInstancePrototype));
__ j(not_zero, &slow_case);
// Ensure that {function} is not bound.
Register const shared_info = scratch;
__ mov(shared_info,
FieldOperand(function, JSFunction::kSharedFunctionInfoOffset));
__ BooleanBitTest(shared_info, SharedFunctionInfo::kCompilerHintsOffset,
SharedFunctionInfo::kBoundFunction);
__ j(not_zero, &slow_case);
// Get the "prototype" (or initial map) of the {function}.
__ mov(function_prototype,
FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset));

View File

@ -821,18 +821,6 @@ void MacroAssembler::AssertFunction(Register object) {
}
void MacroAssembler::AssertBoundFunction(Register object) {
if (emit_debug_code()) {
test(object, Immediate(kSmiTagMask));
Check(not_equal, kOperandIsASmiAndNotABoundFunction);
Push(object);
CmpObjectType(object, JS_BOUND_FUNCTION_TYPE, object);
Pop(object);
Check(equal, kOperandIsNotABoundFunction);
}
}
void MacroAssembler::AssertUndefinedOrAllocationSite(Register object) {
if (emit_debug_code()) {
Label done_checking;

View File

@ -524,10 +524,6 @@ class MacroAssembler: public Assembler {
// Abort execution if argument is not a JSFunction, enabled via --debug-code.
void AssertFunction(Register object);
// Abort execution if argument is not a JSBoundFunction,
// enabled via --debug-code.
void AssertBoundFunction(Register object);
// Abort execution if argument is not undefined or an AllocationSite, enabled
// via --debug-code.
void AssertUndefinedOrAllocationSite(Register object);

View File

@ -1236,11 +1236,81 @@ utils.InstallFunctions(GlobalNumber, DONT_ENUM, [
// ----------------------------------------------------------------------------
// Function
// ES6 9.2.3.2 Function.prototype.bind(thisArg , ...args)
function FunctionBind(this_arg) { // Length is 1.
if (!IS_CALLABLE(this)) throw MakeTypeError(kFunctionBind);
var boundFunction = function () {
// Poison .arguments and .caller, but is otherwise not detectable.
"use strict";
// This function must not use any object literals (Object, Array, RegExp),
// since the literals-array is being used to store the bound data.
if (!IS_UNDEFINED(new.target)) {
return %NewObjectFromBound(boundFunction);
}
var bindings = %BoundFunctionGetBindings(boundFunction);
var argc = %_ArgumentsLength();
if (argc == 0) {
return %Apply(bindings[0], bindings[1], bindings, 2, bindings.length - 2);
}
if (bindings.length === 2) {
return %Apply(bindings[0], bindings[1], arguments, 0, argc);
}
var bound_argc = bindings.length - 2;
var argv = new InternalArray(bound_argc + argc);
for (var i = 0; i < bound_argc; i++) {
argv[i] = bindings[i + 2];
}
for (var j = 0; j < argc; j++) {
argv[i++] = %_Arguments(j);
}
return %Apply(bindings[0], bindings[1], argv, 0, bound_argc + argc);
};
var proto = %_GetPrototype(this); // in ES6 9.4.1.3 BoundFunctionCreate
var new_length = 0;
if (ObjectGetOwnPropertyDescriptor(this, "length") !== UNDEFINED) {
var old_length = this.length;
if (IS_NUMBER(old_length)) {
var argc = %_ArgumentsLength();
if (argc > 0) argc--; // Don't count the thisArg as parameter.
new_length = TO_INTEGER(old_length) - argc;
if (new_length < 0) new_length = 0;
}
}
// This runtime function finds any remaining arguments on the stack,
// so we don't pass the arguments object.
var result = %FunctionBindArguments(boundFunction, this, this_arg,
new_length, proto);
var name = this.name;
var bound_name = IS_STRING(name) ? name : "";
%DefineDataPropertyUnchecked(result, "name", "bound " + bound_name,
DONT_ENUM | READ_ONLY);
// We already have caller and arguments properties on functions,
// which are non-configurable. It therefore makes no sence to
// try to redefine these as defined by the spec. The spec says
// that bind should make these throw a TypeError if get or set
// is called and make them non-enumerable and non-configurable.
// To be consistent with our normal functions we leave this as it is.
// TODO(lrn): Do set these to be thrower.
return result;
}
// ----------------------------------------------------------------------------
%AddNamedProperty(GlobalFunction.prototype, "constructor", GlobalFunction,
DONT_ENUM);
utils.InstallFunctions(GlobalFunction.prototype, DONT_ENUM, [
"bind", FunctionBind,
]);
// ----------------------------------------------------------------------------
// Iterator related spec functions.

View File

@ -337,13 +337,14 @@ BasicJsonStringifier::Result BasicJsonStringifier::Serialize_(
case JS_VALUE_TYPE:
if (deferred_string_key) SerializeDeferredKey(comma, key);
return SerializeJSValue(Handle<JSValue>::cast(object));
case JS_FUNCTION_TYPE:
return UNCHANGED;
default:
if (object->IsString()) {
if (deferred_string_key) SerializeDeferredKey(comma, key);
SerializeString(Handle<String>::cast(object));
return SUCCESS;
} else if (object->IsJSObject()) {
if (object->IsCallable()) return UNCHANGED;
// Go to slow path for global proxy and objects requiring access checks.
if (object->IsAccessCheckNeeded() || object->IsJSGlobalProxy()) break;
if (deferred_string_key) SerializeDeferredKey(comma, key);

View File

@ -1925,101 +1925,6 @@ void Builtins::Generate_CallFunction(MacroAssembler* masm,
}
// static
void Builtins::Generate_CallBoundFunction(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- a0 : the number of arguments (not including the receiver)
// -- a1 : the function to call (checked to be a JSBoundFunction)
// -----------------------------------
__ AssertBoundFunction(a1);
// Patch the receiver to [[BoundThis]].
{
__ lw(at, FieldMemOperand(a1, JSBoundFunction::kBoundThisOffset));
__ sll(t0, a0, kPointerSizeLog2);
__ addu(t0, t0, sp);
__ sw(at, MemOperand(t0));
}
// Load [[BoundArguments]] into a2 and length of that into t0.
__ lw(a2, FieldMemOperand(a1, JSBoundFunction::kBoundArgumentsOffset));
__ lw(t0, FieldMemOperand(a2, FixedArray::kLengthOffset));
__ SmiUntag(t0);
// ----------- S t a t e -------------
// -- a0 : the number of arguments (not including the receiver)
// -- a1 : the function to call (checked to be a JSBoundFunction)
// -- a2 : the [[BoundArguments]] (implemented as FixedArray)
// -- t0 : the number of [[BoundArguments]]
// -----------------------------------
// Reserve stack space for the [[BoundArguments]].
{
Label done;
__ sll(t1, t0, kPointerSizeLog2);
__ Subu(sp, sp, Operand(t1));
// Check the stack for overflow. We are not trying to catch interruptions
// (i.e. debug break and preemption) here, so check the "real stack limit".
__ LoadRoot(at, Heap::kRealStackLimitRootIndex);
__ Branch(&done, gt, sp, Operand(at)); // Signed comparison.
// Restore the stack pointer.
__ Addu(sp, sp, Operand(t1));
{
FrameScope scope(masm, StackFrame::MANUAL);
__ EnterFrame(StackFrame::INTERNAL);
__ CallRuntime(Runtime::kThrowStackOverflow, 0);
}
__ bind(&done);
}
// Relocate arguments down the stack.
{
Label loop, done_loop;
__ mov(t1, zero_reg);
__ bind(&loop);
__ Branch(&done_loop, gt, t1, Operand(a0));
__ sll(t2, t0, kPointerSizeLog2);
__ addu(t2, t2, sp);
__ lw(at, MemOperand(t2));
__ sll(t2, t1, kPointerSizeLog2);
__ addu(t2, t2, sp);
__ sw(at, MemOperand(t2));
__ Addu(t0, t0, Operand(1));
__ Addu(t1, t1, Operand(1));
__ Branch(&loop);
__ bind(&done_loop);
}
// Copy [[BoundArguments]] to the stack (below the arguments).
{
Label loop, done_loop;
__ lw(t0, FieldMemOperand(a2, FixedArray::kLengthOffset));
__ SmiUntag(t0);
__ Addu(a2, a2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
__ bind(&loop);
__ Subu(t0, t0, Operand(1));
__ Branch(&done_loop, lt, t0, Operand(zero_reg));
__ sll(t1, t0, kPointerSizeLog2);
__ addu(t1, t1, a2);
__ lw(at, MemOperand(t1));
__ sll(t1, a0, kPointerSizeLog2);
__ addu(t1, t1, sp);
__ sw(at, MemOperand(t1));
__ Addu(a0, a0, Operand(1));
__ Branch(&loop);
__ bind(&done_loop);
}
// Call the [[BoundTargetFunction]] via the Call builtin.
__ lw(a1, FieldMemOperand(a1, JSBoundFunction::kBoundTargetFunctionOffset));
__ li(at, Operand(ExternalReference(Builtins::kCall_ReceiverIsAny,
masm->isolate())));
__ lw(at, MemOperand(at));
__ Addu(at, at, Operand(Code::kHeaderSize - kHeapObjectTag));
__ Jump(at);
}
// static
void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) {
// ----------- S t a t e -------------
@ -2033,8 +1938,6 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) {
__ GetObjectType(a1, t1, t2);
__ Jump(masm->isolate()->builtins()->CallFunction(mode),
RelocInfo::CODE_TARGET, eq, t2, Operand(JS_FUNCTION_TYPE));
__ Jump(masm->isolate()->builtins()->CallBoundFunction(),
RelocInfo::CODE_TARGET, eq, t2, Operand(JS_BOUND_FUNCTION_TYPE));
__ Branch(&non_function, ne, t2, Operand(JS_PROXY_TYPE));
// 1. Runtime fallback for Proxy [[Call]].
@ -2095,102 +1998,6 @@ void Builtins::Generate_ConstructFunction(MacroAssembler* masm) {
}
// static
void Builtins::Generate_ConstructBoundFunction(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- a0 : the number of arguments (not including the receiver)
// -- a1 : the function to call (checked to be a JSBoundFunction)
// -- a3 : the new target (checked to be a constructor)
// -----------------------------------
__ AssertBoundFunction(a1);
// Load [[BoundArguments]] into a2 and length of that into t0.
__ lw(a2, FieldMemOperand(a1, JSBoundFunction::kBoundArgumentsOffset));
__ lw(t0, FieldMemOperand(a2, FixedArray::kLengthOffset));
__ SmiUntag(t0);
// ----------- S t a t e -------------
// -- a0 : the number of arguments (not including the receiver)
// -- a1 : the function to call (checked to be a JSBoundFunction)
// -- a2 : the [[BoundArguments]] (implemented as FixedArray)
// -- a3 : the new target (checked to be a constructor)
// -- t0 : the number of [[BoundArguments]]
// -----------------------------------
// Reserve stack space for the [[BoundArguments]].
{
Label done;
__ sll(t1, t0, kPointerSizeLog2);
__ Subu(sp, sp, Operand(t1));
// Check the stack for overflow. We are not trying to catch interruptions
// (i.e. debug break and preemption) here, so check the "real stack limit".
__ LoadRoot(at, Heap::kRealStackLimitRootIndex);
__ Branch(&done, gt, sp, Operand(at)); // Signed comparison.
// Restore the stack pointer.
__ Addu(sp, sp, Operand(t1));
{
FrameScope scope(masm, StackFrame::MANUAL);
__ EnterFrame(StackFrame::INTERNAL);
__ CallRuntime(Runtime::kThrowStackOverflow, 0);
}
__ bind(&done);
}
// Relocate arguments down the stack.
{
Label loop, done_loop;
__ mov(t1, zero_reg);
__ bind(&loop);
__ Branch(&done_loop, ge, t1, Operand(a0));
__ sll(t2, t0, kPointerSizeLog2);
__ addu(t2, t2, sp);
__ lw(at, MemOperand(t2));
__ sll(t2, t1, kPointerSizeLog2);
__ addu(t2, t2, sp);
__ sw(at, MemOperand(t2));
__ Addu(t0, t0, Operand(1));
__ Addu(t1, t1, Operand(1));
__ Branch(&loop);
__ bind(&done_loop);
}
// Copy [[BoundArguments]] to the stack (below the arguments).
{
Label loop, done_loop;
__ lw(t0, FieldMemOperand(a2, FixedArray::kLengthOffset));
__ SmiUntag(t0);
__ Addu(a2, a2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
__ bind(&loop);
__ Subu(t0, t0, Operand(1));
__ Branch(&done_loop, lt, t0, Operand(zero_reg));
__ sll(t1, t0, kPointerSizeLog2);
__ addu(t1, t1, a2);
__ lw(at, MemOperand(t1));
__ sll(t1, a0, kPointerSizeLog2);
__ addu(t1, t1, sp);
__ sw(at, MemOperand(t1));
__ Addu(a0, a0, Operand(1));
__ Branch(&loop);
__ bind(&done_loop);
}
// Patch new.target to [[BoundTargetFunction]] if new.target equals target.
{
Label skip_load;
__ Branch(&skip_load, ne, a1, Operand(a3));
__ lw(a3, FieldMemOperand(a1, JSBoundFunction::kBoundTargetFunctionOffset));
__ bind(&skip_load);
}
// Construct the [[BoundTargetFunction]] via the Construct builtin.
__ lw(a1, FieldMemOperand(a1, JSBoundFunction::kBoundTargetFunctionOffset));
__ li(at, Operand(ExternalReference(Builtins::kConstruct, masm->isolate())));
__ lw(at, MemOperand(at));
__ Addu(at, at, Operand(Code::kHeaderSize - kHeapObjectTag));
__ Jump(at);
}
// static
void Builtins::Generate_ConstructProxy(MacroAssembler* masm) {
// ----------- S t a t e -------------
@ -2234,11 +2041,6 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
__ And(t3, t3, Operand(1 << Map::kIsConstructor));
__ Branch(&non_constructor, eq, t3, Operand(zero_reg));
// Only dispatch to bound functions after checking whether they are
// constructors.
__ Jump(masm->isolate()->builtins()->ConstructBoundFunction(),
RelocInfo::CODE_TARGET, eq, t2, Operand(JS_BOUND_FUNCTION_TYPE));
// Only dispatch to proxies after checking whether they are constructors.
__ Jump(masm->isolate()->builtins()->ConstructProxy(), RelocInfo::CODE_TARGET,
eq, t2, Operand(JS_PROXY_TYPE));

View File

@ -1472,6 +1472,15 @@ void InstanceOfStub::Generate(MacroAssembler* masm) {
__ And(at, scratch, Operand(1 << Map::kHasNonInstancePrototype));
__ Branch(&slow_case, ne, at, Operand(zero_reg));
// Ensure that {function} is not bound.
Register const shared_info = scratch;
__ lw(shared_info,
FieldMemOperand(function, JSFunction::kSharedFunctionInfoOffset));
__ lbu(scratch,
FieldMemOperand(shared_info, SharedFunctionInfo::kBoundByteOffset));
__ And(at, scratch, Operand(1 << SharedFunctionInfo::kBoundBitWithinByte));
__ Branch(&slow_case, ne, at, Operand(zero_reg));
// Get the "prototype" (or initial map) of the {function}.
__ lw(function_prototype,
FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset));

View File

@ -5123,17 +5123,6 @@ void MacroAssembler::AssertFunction(Register object) {
}
void MacroAssembler::AssertBoundFunction(Register object) {
if (emit_debug_code()) {
STATIC_ASSERT(kSmiTag == 0);
SmiTst(object, t8);
Check(ne, kOperandIsASmiAndNotABoundFunction, t8, Operand(zero_reg));
GetObjectType(object, t8, t8);
Check(eq, kOperandIsNotABoundFunction, t8, Operand(JS_BOUND_FUNCTION_TYPE));
}
}
void MacroAssembler::AssertUndefinedOrAllocationSite(Register object,
Register scratch) {
if (emit_debug_code()) {

View File

@ -1476,10 +1476,6 @@ const Operand& rt = Operand(zero_reg), BranchDelaySlot bd = PROTECT
// Abort execution if argument is not a JSFunction, enabled via --debug-code.
void AssertFunction(Register object);
// Abort execution if argument is not a JSBoundFunction,
// enabled via --debug-code.
void AssertBoundFunction(Register object);
// Abort execution if argument is not undefined or an AllocationSite, enabled
// via --debug-code.
void AssertUndefinedOrAllocationSite(Register object, Register scratch);

View File

@ -1916,101 +1916,6 @@ void Builtins::Generate_CallFunction(MacroAssembler* masm,
}
// static
void Builtins::Generate_CallBoundFunction(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- a0 : the number of arguments (not including the receiver)
// -- a1 : the function to call (checked to be a JSBoundFunction)
// -----------------------------------
__ AssertBoundFunction(a1);
// Patch the receiver to [[BoundThis]].
{
__ ld(at, FieldMemOperand(a1, JSBoundFunction::kBoundThisOffset));
__ dsll(a4, a0, kPointerSizeLog2);
__ daddu(a4, a4, sp);
__ sd(at, MemOperand(a4));
}
// Load [[BoundArguments]] into a2 and length of that into a4.
__ ld(a2, FieldMemOperand(a1, JSBoundFunction::kBoundArgumentsOffset));
__ ld(a4, FieldMemOperand(a2, FixedArray::kLengthOffset));
__ SmiUntag(a4);
// ----------- S t a t e -------------
// -- a0 : the number of arguments (not including the receiver)
// -- a1 : the function to call (checked to be a JSBoundFunction)
// -- a2 : the [[BoundArguments]] (implemented as FixedArray)
// -- a4 : the number of [[BoundArguments]]
// -----------------------------------
// Reserve stack space for the [[BoundArguments]].
{
Label done;
__ dsll(a5, a4, kPointerSizeLog2);
__ Dsubu(sp, sp, Operand(a5));
// Check the stack for overflow. We are not trying to catch interruptions
// (i.e. debug break and preemption) here, so check the "real stack limit".
__ LoadRoot(at, Heap::kRealStackLimitRootIndex);
__ Branch(&done, gt, sp, Operand(at)); // Signed comparison.
// Restore the stack pointer.
__ Daddu(sp, sp, Operand(a5));
{
FrameScope scope(masm, StackFrame::MANUAL);
__ EnterFrame(StackFrame::INTERNAL);
__ CallRuntime(Runtime::kThrowStackOverflow, 0);
}
__ bind(&done);
}
// Relocate arguments down the stack.
{
Label loop, done_loop;
__ mov(a5, zero_reg);
__ bind(&loop);
__ Branch(&done_loop, gt, a5, Operand(a0));
__ dsll(a6, a4, kPointerSizeLog2);
__ daddu(a6, a6, sp);
__ ld(at, MemOperand(a6));
__ dsll(a6, a5, kPointerSizeLog2);
__ daddu(a6, a6, sp);
__ sd(at, MemOperand(a6));
__ Daddu(a4, a4, Operand(1));
__ Daddu(a5, a5, Operand(1));
__ Branch(&loop);
__ bind(&done_loop);
}
// Copy [[BoundArguments]] to the stack (below the arguments).
{
Label loop, done_loop;
__ ld(a4, FieldMemOperand(a2, FixedArray::kLengthOffset));
__ SmiUntag(a4);
__ Daddu(a2, a2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
__ bind(&loop);
__ Dsubu(a4, a4, Operand(1));
__ Branch(&done_loop, lt, a4, Operand(zero_reg));
__ dsll(a5, a4, kPointerSizeLog2);
__ daddu(a5, a5, a2);
__ ld(at, MemOperand(a5));
__ dsll(a5, a0, kPointerSizeLog2);
__ daddu(a5, a5, sp);
__ sd(at, MemOperand(a5));
__ Daddu(a0, a0, Operand(1));
__ Branch(&loop);
__ bind(&done_loop);
}
// Call the [[BoundTargetFunction]] via the Call builtin.
__ ld(a1, FieldMemOperand(a1, JSBoundFunction::kBoundTargetFunctionOffset));
__ li(at, Operand(ExternalReference(Builtins::kCall_ReceiverIsAny,
masm->isolate())));
__ ld(at, MemOperand(at));
__ Daddu(at, at, Operand(Code::kHeaderSize - kHeapObjectTag));
__ Jump(at);
}
// static
void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) {
// ----------- S t a t e -------------
@ -2024,8 +1929,6 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) {
__ GetObjectType(a1, t1, t2);
__ Jump(masm->isolate()->builtins()->CallFunction(mode),
RelocInfo::CODE_TARGET, eq, t2, Operand(JS_FUNCTION_TYPE));
__ Jump(masm->isolate()->builtins()->CallBoundFunction(),
RelocInfo::CODE_TARGET, eq, t2, Operand(JS_BOUND_FUNCTION_TYPE));
__ Branch(&non_function, ne, t2, Operand(JS_PROXY_TYPE));
// 1. Runtime fallback for Proxy [[Call]].
@ -2085,102 +1988,6 @@ void Builtins::Generate_ConstructFunction(MacroAssembler* masm) {
}
// static
void Builtins::Generate_ConstructBoundFunction(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- a0 : the number of arguments (not including the receiver)
// -- a1 : the function to call (checked to be a JSBoundFunction)
// -- a3 : the new target (checked to be a constructor)
// -----------------------------------
__ AssertBoundFunction(a1);
// Load [[BoundArguments]] into a2 and length of that into a4.
__ ld(a2, FieldMemOperand(a1, JSBoundFunction::kBoundArgumentsOffset));
__ ld(a4, FieldMemOperand(a2, FixedArray::kLengthOffset));
__ SmiUntag(a4);
// ----------- S t a t e -------------
// -- a0 : the number of arguments (not including the receiver)
// -- a1 : the function to call (checked to be a JSBoundFunction)
// -- a2 : the [[BoundArguments]] (implemented as FixedArray)
// -- a3 : the new target (checked to be a constructor)
// -- a4 : the number of [[BoundArguments]]
// -----------------------------------
// Reserve stack space for the [[BoundArguments]].
{
Label done;
__ dsll(a5, a4, kPointerSizeLog2);
__ Dsubu(sp, sp, Operand(a5));
// Check the stack for overflow. We are not trying to catch interruptions
// (i.e. debug break and preemption) here, so check the "real stack limit".
__ LoadRoot(at, Heap::kRealStackLimitRootIndex);
__ Branch(&done, gt, sp, Operand(at)); // Signed comparison.
// Restore the stack pointer.
__ Daddu(sp, sp, Operand(a5));
{
FrameScope scope(masm, StackFrame::MANUAL);
__ EnterFrame(StackFrame::INTERNAL);
__ CallRuntime(Runtime::kThrowStackOverflow, 0);
}
__ bind(&done);
}
// Relocate arguments down the stack.
{
Label loop, done_loop;
__ mov(a5, zero_reg);
__ bind(&loop);
__ Branch(&done_loop, ge, a5, Operand(a0));
__ dsll(a6, a4, kPointerSizeLog2);
__ daddu(a6, a6, sp);
__ ld(at, MemOperand(a6));
__ dsll(a6, a5, kPointerSizeLog2);
__ daddu(a6, a6, sp);
__ sd(at, MemOperand(a6));
__ Daddu(a4, a4, Operand(1));
__ Daddu(a5, a5, Operand(1));
__ Branch(&loop);
__ bind(&done_loop);
}
// Copy [[BoundArguments]] to the stack (below the arguments).
{
Label loop, done_loop;
__ ld(a4, FieldMemOperand(a2, FixedArray::kLengthOffset));
__ SmiUntag(a4);
__ Daddu(a2, a2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
__ bind(&loop);
__ Dsubu(a4, a4, Operand(1));
__ Branch(&done_loop, lt, a4, Operand(zero_reg));
__ dsll(a5, a4, kPointerSizeLog2);
__ daddu(a5, a5, a2);
__ ld(at, MemOperand(a5));
__ dsll(a5, a0, kPointerSizeLog2);
__ daddu(a5, a5, sp);
__ sd(at, MemOperand(a5));
__ Daddu(a0, a0, Operand(1));
__ Branch(&loop);
__ bind(&done_loop);
}
// Patch new.target to [[BoundTargetFunction]] if new.target equals target.
{
Label skip_load;
__ Branch(&skip_load, ne, a1, Operand(a3));
__ ld(a3, FieldMemOperand(a1, JSBoundFunction::kBoundTargetFunctionOffset));
__ bind(&skip_load);
}
// Construct the [[BoundTargetFunction]] via the Construct builtin.
__ ld(a1, FieldMemOperand(a1, JSBoundFunction::kBoundTargetFunctionOffset));
__ li(at, Operand(ExternalReference(Builtins::kConstruct, masm->isolate())));
__ ld(at, MemOperand(at));
__ Addu(at, at, Operand(Code::kHeaderSize - kHeapObjectTag));
__ Jump(at);
}
// static
void Builtins::Generate_ConstructProxy(MacroAssembler* masm) {
// ----------- S t a t e -------------
@ -2224,11 +2031,6 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
__ And(t3, t3, Operand(1 << Map::kIsConstructor));
__ Branch(&non_constructor, eq, t3, Operand(zero_reg));
// Only dispatch to bound functions after checking whether they are
// constructors.
__ Jump(masm->isolate()->builtins()->ConstructBoundFunction(),
RelocInfo::CODE_TARGET, eq, t2, Operand(JS_BOUND_FUNCTION_TYPE));
// Only dispatch to proxies after checking whether they are constructors.
__ Jump(masm->isolate()->builtins()->ConstructProxy(), RelocInfo::CODE_TARGET,
eq, t2, Operand(JS_PROXY_TYPE));

View File

@ -1474,6 +1474,15 @@ void InstanceOfStub::Generate(MacroAssembler* masm) {
__ And(at, scratch, Operand(1 << Map::kHasNonInstancePrototype));
__ Branch(&slow_case, ne, at, Operand(zero_reg));
// Ensure that {function} is not bound.
Register const shared_info = scratch;
__ ld(shared_info,
FieldMemOperand(function, JSFunction::kSharedFunctionInfoOffset));
__ lbu(scratch,
FieldMemOperand(shared_info, SharedFunctionInfo::kBoundByteOffset));
__ And(at, scratch, Operand(1 << SharedFunctionInfo::kBoundBitWithinByte));
__ Branch(&slow_case, ne, at, Operand(zero_reg));
// Get the "prototype" (or initial map) of the {function}.
__ ld(function_prototype,
FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset));

View File

@ -5726,17 +5726,6 @@ void MacroAssembler::AssertFunction(Register object) {
}
void MacroAssembler::AssertBoundFunction(Register object) {
if (emit_debug_code()) {
STATIC_ASSERT(kSmiTag == 0);
SmiTst(object, t8);
Check(ne, kOperandIsASmiAndNotABoundFunction, t8, Operand(zero_reg));
GetObjectType(object, t8, t8);
Check(eq, kOperandIsNotABoundFunction, t8, Operand(JS_BOUND_FUNCTION_TYPE));
}
}
void MacroAssembler::AssertUndefinedOrAllocationSite(Register object,
Register scratch) {
if (emit_debug_code()) {

View File

@ -1628,10 +1628,6 @@ const Operand& rt = Operand(zero_reg), BranchDelaySlot bd = PROTECT
// Abort execution if argument is not a JSFunction, enabled via --debug-code.
void AssertFunction(Register object);
// Abort execution if argument is not a JSBoundFunction,
// enabled via --debug-code.
void AssertBoundFunction(Register object);
// Abort execution if argument is not undefined or an AllocationSite, enabled
// via --debug-code.
void AssertUndefinedOrAllocationSite(Register object, Register scratch);

View File

@ -469,7 +469,6 @@ ReturnType BodyDescriptorApply(InstanceType type, T1 p1, T2 p2, T3 p3) {
case JS_GLOBAL_PROXY_TYPE:
case JS_GLOBAL_OBJECT_TYPE:
case JS_MESSAGE_OBJECT_TYPE:
case JS_BOUND_FUNCTION_TYPE:
return Op::template apply<JSObject::BodyDescriptor>(p1, p2, p3);
case JS_WEAK_MAP_TYPE:
case JS_WEAK_SET_TYPE:

View File

@ -114,9 +114,6 @@ void HeapObject::HeapObjectVerify() {
case JS_DATE_TYPE:
JSDate::cast(this)->JSDateVerify();
break;
case JS_BOUND_FUNCTION_TYPE:
JSBoundFunction::cast(this)->JSBoundFunctionVerify();
break;
case JS_FUNCTION_TYPE:
JSFunction::cast(this)->JSFunctionVerify();
break;
@ -547,21 +544,6 @@ void SlicedString::SlicedStringVerify() {
}
void JSBoundFunction::JSBoundFunctionVerify() {
CHECK(IsJSBoundFunction());
VerifyObjectField(kLengthOffset);
VerifyObjectField(kNameOffset);
VerifyObjectField(kBoundThisOffset);
VerifyObjectField(kBoundTargetFunctionOffset);
VerifyObjectField(kBoundArgumentsOffset);
VerifyObjectField(kCreationContextOffset);
CHECK(bound_target_function()->IsCallable());
CHECK(creation_context()->IsNativeContext());
CHECK(IsCallable());
CHECK_EQ(IsConstructor(), bound_target_function()->IsConstructor());
}
void JSFunction::JSFunctionVerify() {
CHECK(IsJSFunction());
VerifyObjectField(kPrototypeOrInitialMapOffset);

View File

@ -187,13 +187,6 @@ bool Object::IsUniqueName() const {
}
bool Object::IsFunction() const {
STATIC_ASSERT(LAST_FUNCTION_TYPE == LAST_TYPE);
return Object::IsHeapObject() &&
HeapObject::cast(this)->map()->instance_type() >= FIRST_FUNCTION_TYPE;
}
bool Object::IsCallable() const {
return Object::IsHeapObject() && HeapObject::cast(this)->map()->is_callable();
}
@ -748,6 +741,7 @@ bool Object::IsTypeFeedbackMetadata() const { return IsFixedArray(); }
bool Object::IsLiteralsArray() const { return IsFixedArray(); }
bool Object::IsBindingsArray() const { return IsFixedArray(); }
bool Object::IsDeoptimizationInputData() const {
@ -828,7 +822,6 @@ bool Object::IsScopeInfo() const {
}
TYPE_CHECKER(JSBoundFunction, JS_BOUND_FUNCTION_TYPE)
TYPE_CHECKER(JSFunction, JS_FUNCTION_TYPE)
@ -2091,8 +2084,6 @@ int JSObject::GetHeaderSize(InstanceType type) {
return JSGlobalProxy::kSize;
case JS_GLOBAL_OBJECT_TYPE:
return JSGlobalObject::kSize;
case JS_BOUND_FUNCTION_TYPE:
return JSBoundFunction::kSize;
case JS_FUNCTION_TYPE:
return JSFunction::kSize;
case JS_VALUE_TYPE:
@ -3226,7 +3217,6 @@ CAST_ACCESSOR(Int8x16)
CAST_ACCESSOR(JSArray)
CAST_ACCESSOR(JSArrayBuffer)
CAST_ACCESSOR(JSArrayBufferView)
CAST_ACCESSOR(JSBoundFunction)
CAST_ACCESSOR(JSDataView)
CAST_ACCESSOR(JSDate)
CAST_ACCESSOR(JSFunction)
@ -3430,6 +3420,75 @@ int LiteralsArray::literals_count() const {
}
Object* BindingsArray::get(int index) const { return FixedArray::get(index); }
void BindingsArray::set(int index, Object* value) {
FixedArray::set(index, value);
}
void BindingsArray::set(int index, Smi* value) {
FixedArray::set(index, value);
}
void BindingsArray::set(int index, Object* value, WriteBarrierMode mode) {
FixedArray::set(index, value, mode);
}
int BindingsArray::length() const { return FixedArray::length(); }
BindingsArray* BindingsArray::cast(Object* object) {
SLOW_DCHECK(object->IsBindingsArray());
return reinterpret_cast<BindingsArray*>(object);
}
void BindingsArray::set_feedback_vector(TypeFeedbackVector* vector) {
set(kVectorIndex, vector);
}
TypeFeedbackVector* BindingsArray::feedback_vector() const {
return TypeFeedbackVector::cast(get(kVectorIndex));
}
JSReceiver* BindingsArray::bound_function() const {
return JSReceiver::cast(get(kBoundFunctionIndex));
}
void BindingsArray::set_bound_function(JSReceiver* function) {
set(kBoundFunctionIndex, function);
}
Object* BindingsArray::bound_this() const { return get(kBoundThisIndex); }
void BindingsArray::set_bound_this(Object* bound_this) {
set(kBoundThisIndex, bound_this);
}
Object* BindingsArray::binding(int binding_index) const {
return get(kFirstBindingIndex + binding_index);
}
void BindingsArray::set_binding(int binding_index, Object* binding) {
set(kFirstBindingIndex + binding_index, binding);
}
int BindingsArray::bindings_count() const {
return length() - kFirstBindingIndex;
}
void HandlerTable::SetRangeStart(int index, int value) {
set(index * kRangeEntrySize + kRangeStartIndex, Smi::FromInt(value));
}
@ -4481,8 +4540,12 @@ bool Map::has_non_instance_prototype() {
}
void Map::set_is_constructor() {
set_bit_field(bit_field() | (1 << kIsConstructor));
void Map::set_is_constructor(bool value) {
if (value) {
set_bit_field(bit_field() | (1 << kIsConstructor));
} else {
set_bit_field(bit_field() & ~(1 << kIsConstructor));
}
}
@ -5468,16 +5531,8 @@ Handle<Map> Map::CopyInitialMap(Handle<Map> map) {
}
ACCESSORS(JSBoundFunction, length, Object, kLengthOffset)
ACCESSORS(JSBoundFunction, name, Object, kNameOffset)
ACCESSORS(JSBoundFunction, bound_target_function, JSReceiver,
kBoundTargetFunctionOffset)
ACCESSORS(JSBoundFunction, bound_this, Object, kBoundThisOffset)
ACCESSORS(JSBoundFunction, bound_arguments, FixedArray, kBoundArgumentsOffset)
ACCESSORS(JSBoundFunction, creation_context, Context, kCreationContextOffset)
ACCESSORS(JSFunction, shared, SharedFunctionInfo, kSharedFunctionInfoOffset)
ACCESSORS(JSFunction, literals, LiteralsArray, kLiteralsOffset)
ACCESSORS(JSFunction, literals_or_bindings, FixedArray, kLiteralsOffset)
ACCESSORS(JSFunction, next_function_link, Object, kNextFunctionLinkOffset)
ACCESSORS(JSGlobalObject, native_context, Context, kNativeContextOffset)
@ -5820,6 +5875,7 @@ BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, force_inline, kForceInline)
BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints,
name_should_print_as_anonymous,
kNameShouldPrintAsAnonymous)
BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, bound, kBoundFunction)
BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, is_anonymous, kIsAnonymous)
BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, is_function, kIsFunction)
BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, dont_crankshaft,
@ -6264,7 +6320,36 @@ bool JSFunction::is_compiled() {
}
LiteralsArray* JSFunction::literals() {
DCHECK(!shared()->bound());
return LiteralsArray::cast(literals_or_bindings());
}
void JSFunction::set_literals(LiteralsArray* literals) {
DCHECK(!shared()->bound());
set_literals_or_bindings(literals);
}
BindingsArray* JSFunction::function_bindings() {
DCHECK(shared()->bound());
return BindingsArray::cast(literals_or_bindings());
}
void JSFunction::set_function_bindings(BindingsArray* bindings) {
DCHECK(shared()->bound());
// Bound function literal may be initialized to the empty fixed array
// before the bindings are set.
DCHECK(bindings == GetHeap()->empty_fixed_array() ||
bindings->map() == GetHeap()->fixed_array_map());
set_literals_or_bindings(bindings);
}
int JSFunction::NumberOfLiterals() {
DCHECK(!shared()->bound());
return literals()->length();
}

View File

@ -110,9 +110,6 @@ void HeapObject::HeapObjectPrint(std::ostream& os) { // NOLINT
case JS_MODULE_TYPE:
JSModule::cast(this)->JSModulePrint(os);
break;
case JS_BOUND_FUNCTION_TYPE:
JSBoundFunction::cast(this)->JSBoundFunctionPrint(os);
break;
case JS_FUNCTION_TYPE:
JSFunction::cast(this)->JSFunctionPrint(os);
break;
@ -847,15 +844,6 @@ void JSDataView::JSDataViewPrint(std::ostream& os) { // NOLINT
}
void JSBoundFunction::JSBoundFunctionPrint(std::ostream& os) { // NOLINT
JSObjectPrintHeader(os, this, "JSBoundFunction");
os << "\n - bound_target_function = " << Brief(bound_target_function());
os << "\n - bound_this = " << Brief(bound_this());
os << "\n - bound_arguments = " << Brief(bound_arguments());
JSObjectPrintBody(os, this);
}
void JSFunction::JSFunctionPrint(std::ostream& os) { // NOLINT
JSObjectPrintHeader(os, this, "Function");
os << "\n - initial_map = ";
@ -866,7 +854,11 @@ void JSFunction::JSFunctionPrint(std::ostream& os) { // NOLINT
os << "\n - generator";
}
os << "\n - context = " << Brief(context());
os << "\n - literals = " << Brief(literals());
if (shared()->bound()) {
os << "\n - bindings = " << Brief(function_bindings());
} else {
os << "\n - literals = " << Brief(literals());
}
os << "\n - code = " << Brief(code());
JSObjectPrintBody(os, this);
}

View File

@ -1868,22 +1868,6 @@ void JSObject::JSObjectShortPrint(StringStream* accumulator) {
accumulator->Add("<JS Array[%u]>", static_cast<uint32_t>(length));
break;
}
case JS_BOUND_FUNCTION_TYPE: {
JSBoundFunction* bound_function = JSBoundFunction::cast(this);
Object* name = bound_function->name();
accumulator->Add("<JS BoundFunction");
if (name->IsString()) {
String* str = String::cast(name);
if (str->length() > 0) {
accumulator->Add(" ");
accumulator->Put(str);
}
}
accumulator->Add(
" (BoundTargetFunction %p)>",
reinterpret_cast<void*>(bound_function->bound_target_function()));
break;
}
case JS_WEAK_MAP_TYPE: {
accumulator->Add("<JS WeakMap>");
break;
@ -2407,7 +2391,7 @@ void Simd128Value::CopyBits(void* destination) const {
String* JSReceiver::class_name() {
if (IsFunction()) {
if (IsJSFunction()) {
return GetHeap()->Function_string();
}
Object* maybe_constructor = map()->GetConstructor();
@ -2423,19 +2407,12 @@ String* JSReceiver::class_name() {
MaybeHandle<String> JSReceiver::BuiltinStringTag(Handle<JSReceiver> object) {
Maybe<bool> is_array = Object::IsArray(object);
MAYBE_RETURN(is_array, MaybeHandle<String>());
Isolate* const isolate = object->GetIsolate();
if (is_array.FromJust()) {
return isolate->factory()->Array_string();
return object->GetIsolate()->factory()->Array_string();
}
// TODO(adamk): According to ES2015, we should return "Function" when
// object has a [[Call]] internal method (corresponds to IsCallable).
// But this is well cemented in layout tests and might cause webbreakage.
// if (object->IsCallable()) {
// return isolate->factory()->Function_string();
// }
// TODO(adamk): class_name() is expensive, replace with instance type
// checks where possible.
return handle(object->class_name(), isolate);
return handle(object->class_name());
}
@ -2488,18 +2465,14 @@ Handle<String> JSReceiver::GetConstructorName(Handle<JSReceiver> receiver) {
Context* JSReceiver::GetCreationContext() {
if (IsJSBoundFunction()) {
return JSBoundFunction::cast(this)->creation_context();
}
Object* constructor = map()->GetConstructor();
JSFunction* function;
if (constructor->IsJSFunction()) {
function = JSFunction::cast(constructor);
} else {
if (!constructor->IsJSFunction()) {
// Functions have null as a constructor,
// but any JSFunction knows its context immediately.
CHECK(IsJSFunction());
function = JSFunction::cast(this);
} else {
function = JSFunction::cast(constructor);
}
return function->context()->native_context();
@ -4975,15 +4948,6 @@ MaybeHandle<Context> JSProxy::GetFunctionRealm(Handle<JSProxy> proxy) {
}
// static
MaybeHandle<Context> JSBoundFunction::GetFunctionRealm(
Handle<JSBoundFunction> function) {
DCHECK(function->map()->is_constructor());
return JSReceiver::GetFunctionRealm(
handle(function->bound_target_function()));
}
// static
Handle<Context> JSFunction::GetFunctionRealm(Handle<JSFunction> function) {
DCHECK(function->map()->is_constructor());
@ -5009,11 +4973,6 @@ MaybeHandle<Context> JSReceiver::GetFunctionRealm(Handle<JSReceiver> receiver) {
return JSFunction::GetFunctionRealm(Handle<JSFunction>::cast(receiver));
}
if (receiver->IsJSBoundFunction()) {
return JSBoundFunction::GetFunctionRealm(
Handle<JSBoundFunction>::cast(receiver));
}
return JSObject::GetFunctionRealm(Handle<JSObject>::cast(receiver));
}
@ -10789,6 +10748,47 @@ Handle<LiteralsArray> LiteralsArray::New(Isolate* isolate,
}
// static
Handle<BindingsArray> BindingsArray::New(Isolate* isolate,
Handle<TypeFeedbackVector> vector,
Handle<JSReceiver> bound_function,
Handle<Object> bound_this,
int number_of_bindings) {
Handle<FixedArray> bindings = isolate->factory()->NewFixedArray(
number_of_bindings + kFirstBindingIndex);
Handle<BindingsArray> casted_bindings = Handle<BindingsArray>::cast(bindings);
casted_bindings->set_feedback_vector(*vector);
casted_bindings->set_bound_function(*bound_function);
casted_bindings->set_bound_this(*bound_this);
return casted_bindings;
}
// static
Handle<JSArray> BindingsArray::CreateBoundArguments(
Handle<BindingsArray> bindings) {
int bound_argument_count = bindings->bindings_count();
Factory* factory = bindings->GetIsolate()->factory();
Handle<FixedArray> arguments = factory->NewFixedArray(bound_argument_count);
bindings->CopyTo(kFirstBindingIndex, *arguments, 0, bound_argument_count);
return factory->NewJSArrayWithElements(arguments);
}
// static
Handle<JSArray> BindingsArray::CreateRuntimeBindings(
Handle<BindingsArray> bindings) {
Factory* factory = bindings->GetIsolate()->factory();
// A runtime bindings array consists of
// [bound function, bound this, [arg0, arg1, ...]].
Handle<FixedArray> runtime_bindings =
factory->NewFixedArray(2 + bindings->bindings_count());
bindings->CopyTo(kBoundFunctionIndex, *runtime_bindings, 0,
2 + bindings->bindings_count());
return factory->NewJSArrayWithElements(runtime_bindings);
}
int HandlerTable::LookupRange(int pc_offset, int* stack_depth_out,
CatchPrediction* prediction_out) {
int innermost_handler = -1, innermost_start = -1;
@ -12851,7 +12851,6 @@ bool CanSubclassHaveInobjectProperties(InstanceType instance_type) {
case JS_FUNCTION_TYPE:
return true;
case JS_BOUND_FUNCTION_TYPE:
case JS_PROXY_TYPE:
case JS_GLOBAL_PROXY_TYPE:
case JS_GLOBAL_OBJECT_TYPE:
@ -12996,16 +12995,17 @@ MaybeHandle<Map> JSFunction::GetDerivedMap(Isolate* isolate,
// new.target.prototype is not guaranteed to be a JSReceiver, and may need to
// fall back to the intrinsicDefaultProto.
Handle<Object> prototype;
if (new_target->IsJSFunction()) {
if (new_target->IsJSProxy()) {
Handle<JSProxy> new_target_proxy = Handle<JSProxy>::cast(new_target);
Handle<String> prototype_string = isolate->factory()->prototype_string();
ASSIGN_RETURN_ON_EXCEPTION(
isolate, prototype,
JSReceiver::GetProperty(new_target_proxy, prototype_string), Map);
} else {
Handle<JSFunction> function = Handle<JSFunction>::cast(new_target);
// Make sure the new.target.prototype is cached.
EnsureHasInitialMap(function);
prototype = handle(function->prototype(), isolate);
} else {
Handle<String> prototype_string = isolate->factory()->prototype_string();
ASSIGN_RETURN_ON_EXCEPTION(
isolate, prototype,
JSReceiver::GetProperty(new_target, prototype_string), Map);
}
// If prototype is not a JSReceiver, fetch the intrinsicDefaultProto from the
@ -13118,13 +13118,6 @@ Handle<String> NativeCodeFunctionSourceString(
} // namespace
// static
Handle<String> JSBoundFunction::ToString(Handle<JSBoundFunction> function) {
Isolate* const isolate = function->GetIsolate();
return isolate->factory()->NewStringFromAsciiChecked(kNativeCodeSource);
}
// static
Handle<String> JSFunction::ToString(Handle<JSFunction> function) {
Isolate* const isolate = function->GetIsolate();

View File

@ -51,7 +51,6 @@
// - JSArrayBufferView
// - JSTypedArray
// - JSDataView
// - JSBoundFunction
// - JSCollection
// - JSSet
// - JSMap
@ -76,6 +75,7 @@
// - FixedArray
// - DescriptorArray
// - LiteralsArray
// - BindingsArray
// - HashTable
// - Dictionary
// - StringTable
@ -437,7 +437,6 @@ const int kStubMinorKeyBits = kSmiValueSize - kStubMajorKeyBits - 1;
V(JS_PROMISE_TYPE) \
V(JS_REGEXP_TYPE) \
\
V(JS_BOUND_FUNCTION_TYPE) \
V(JS_FUNCTION_TYPE) \
V(DEBUG_INFO_TYPE) \
V(BREAK_POINT_INFO_TYPE)
@ -733,7 +732,6 @@ enum InstanceType {
JS_WEAK_SET_TYPE,
JS_PROMISE_TYPE,
JS_REGEXP_TYPE,
JS_BOUND_FUNCTION_TYPE,
JS_FUNCTION_TYPE, // LAST_JS_OBJECT_TYPE, LAST_JS_RECEIVER_TYPE
// Pseudo-types
@ -746,8 +744,6 @@ enum InstanceType {
FIRST_NONSTRING_TYPE = SYMBOL_TYPE,
FIRST_PRIMITIVE_TYPE = FIRST_NAME_TYPE,
LAST_PRIMITIVE_TYPE = ODDBALL_TYPE,
FIRST_FUNCTION_TYPE = JS_BOUND_FUNCTION_TYPE,
LAST_FUNCTION_TYPE = JS_FUNCTION_TYPE,
// Boundaries for testing for a fixed typed array.
FIRST_FIXED_TYPED_ARRAY_TYPE = FIXED_INT8_ARRAY_TYPE,
LAST_FIXED_TYPED_ARRAY_TYPE = FIXED_UINT8_CLAMPED_ARRAY_TYPE,
@ -934,6 +930,7 @@ template <class C> inline bool Is(Object* obj);
V(LayoutDescriptor) \
V(Map) \
V(DescriptorArray) \
V(BindingsArray) \
V(TransitionArray) \
V(LiteralsArray) \
V(TypeFeedbackMetadata) \
@ -950,7 +947,6 @@ template <class C> inline bool Is(Object* obj);
V(ScriptContextTable) \
V(NativeContext) \
V(ScopeInfo) \
V(JSBoundFunction) \
V(JSFunction) \
V(Code) \
V(Oddball) \
@ -1054,9 +1050,6 @@ class Object {
// ES6, section 7.2.2 IsArray. NOT to be confused with %_IsArray.
MUST_USE_RESULT static Maybe<bool> IsArray(Handle<Object> object);
// Test for JSBoundFunction or JSFunction.
INLINE(bool IsFunction() const);
// ES6, section 7.2.3 IsCallable.
INLINE(bool IsCallable() const);
@ -4671,6 +4664,48 @@ class LiteralsArray : public FixedArray {
};
// A bindings array contains the bindings for a bound function. It also holds
// the type feedback vector.
class BindingsArray : public FixedArray {
public:
inline TypeFeedbackVector* feedback_vector() const;
inline void set_feedback_vector(TypeFeedbackVector* vector);
inline JSReceiver* bound_function() const;
inline void set_bound_function(JSReceiver* function);
inline Object* bound_this() const;
inline void set_bound_this(Object* bound_this);
inline Object* binding(int binding_index) const;
inline void set_binding(int binding_index, Object* binding);
inline int bindings_count() const;
static Handle<BindingsArray> New(Isolate* isolate,
Handle<TypeFeedbackVector> vector,
Handle<JSReceiver> bound_function,
Handle<Object> bound_this,
int number_of_bindings);
static Handle<JSArray> CreateBoundArguments(Handle<BindingsArray> bindings);
static Handle<JSArray> CreateRuntimeBindings(Handle<BindingsArray> bindings);
DECLARE_CAST(BindingsArray)
private:
static const int kVectorIndex = 0;
static const int kBoundFunctionIndex = 1;
static const int kBoundThisIndex = 2;
static const int kFirstBindingIndex = 3;
inline Object* get(int index) const;
inline void set(int index, Object* value);
inline void set(int index, Smi* value);
inline void set(int index, Object* value, WriteBarrierMode mode);
inline int length() const;
};
// HandlerTable is a fixed array containing entries for exception handlers in
// the code object it is associated with. The tables comes in two flavors:
// 1) Based on ranges: Used for unoptimized code. Contains one entry per
@ -5529,7 +5564,7 @@ class Map: public HeapObject {
// Tells whether the instance has a [[Construct]] internal method.
// This property is implemented according to ES6, section 7.2.4.
inline void set_is_constructor();
inline void set_is_constructor(bool value);
inline bool is_constructor() const;
// Tells whether the instance with this map should be ignored by the
@ -6704,6 +6739,10 @@ class SharedFunctionInfo: public HeapObject {
// see a binding for it.
DECL_BOOLEAN_ACCESSORS(name_should_print_as_anonymous)
// Indicates whether the function is a bound function created using
// the bind function.
DECL_BOOLEAN_ACCESSORS(bound)
// Indicates that the function is anonymous (the name field can be set
// through the API, which does not change this flag).
DECL_BOOLEAN_ACCESSORS(is_anonymous)
@ -6993,7 +7032,7 @@ class SharedFunctionInfo: public HeapObject {
// byte 1
kHasDuplicateParameters,
kForceInline,
kIsAsmFunction,
kBoundFunction,
kIsAnonymous,
kNameShouldPrintAsAnonymous,
kIsFunction,
@ -7010,6 +7049,7 @@ class SharedFunctionInfo: public HeapObject {
kIsBaseConstructor,
kIsInObjectLiteral,
// byte 3
kIsAsmFunction,
kDeserialized,
kNeverCompiled,
kCompilerHintsCount, // Pseudo entry
@ -7063,6 +7103,7 @@ class SharedFunctionInfo: public HeapObject {
static const int kStrongModeBit =
kStrongModeFunction + kCompilerHintsSmiTagSize;
static const int kNativeBit = kNative + kCompilerHintsSmiTagSize;
static const int kBoundBit = kBoundFunction + kCompilerHintsSmiTagSize;
static const int kClassConstructorBits =
FunctionKind::kClassConstructor
@ -7074,6 +7115,7 @@ class SharedFunctionInfo: public HeapObject {
static const int kStrictModeBitWithinByte = kStrictModeBit % kBitsPerByte;
static const int kStrongModeBitWithinByte = kStrongModeBit % kBitsPerByte;
static const int kNativeBitWithinByte = kNativeBit % kBitsPerByte;
static const int kBoundBitWithinByte = kBoundBit % kBitsPerByte;
static const int kClassConstructorBitsWithinByte =
FunctionKind::kClassConstructor << kCompilerHintsSmiTagSize;
@ -7093,6 +7135,7 @@ class SharedFunctionInfo: public HeapObject {
static const int kStrictModeByteOffset = BYTE_OFFSET(kStrictModeFunction);
static const int kStrongModeByteOffset = BYTE_OFFSET(kStrongModeFunction);
static const int kNativeByteOffset = BYTE_OFFSET(kNative);
static const int kBoundByteOffset = BYTE_OFFSET(kBoundFunction);
static const int kFunctionKindByteOffset = BYTE_OFFSET(kFunctionKind);
#undef BYTE_OFFSET
@ -7202,64 +7245,6 @@ class JSModule: public JSObject {
};
// JSBoundFunction describes a bound function exotic object.
class JSBoundFunction : public JSObject {
public:
// [length]: The bound function "length" property.
DECL_ACCESSORS(length, Object)
// [name]: The bound function "name" property.
DECL_ACCESSORS(name, Object)
// [bound_target_function]: The wrapped function object.
DECL_ACCESSORS(bound_target_function, JSReceiver)
// [bound_this]: The value that is always passed as the this value when
// calling the wrapped function.
DECL_ACCESSORS(bound_this, Object)
// [bound_arguments]: A list of values whose elements are used as the first
// arguments to any call to the wrapped function.
DECL_ACCESSORS(bound_arguments, FixedArray)
// [creation_context]: The native context in which the function was bound.
// TODO(bmeurer, verwaest): Can we (mis)use (unused) constructor field in
// the Map instead of putting this into the object? Only required for
// JSReceiver::GetCreationContext() anyway.
DECL_ACCESSORS(creation_context, Context)
static MaybeHandle<Context> GetFunctionRealm(
Handle<JSBoundFunction> function);
DECLARE_CAST(JSBoundFunction)
// Dispatched behavior.
DECLARE_PRINTER(JSBoundFunction)
DECLARE_VERIFIER(JSBoundFunction)
// The bound function's string representation implemented according
// to ES6 section 19.2.3.5 Function.prototype.toString ( ).
static Handle<String> ToString(Handle<JSBoundFunction> function);
// Layout description.
static const int kBoundTargetFunctionOffset = JSObject::kHeaderSize;
static const int kBoundThisOffset = kBoundTargetFunctionOffset + kPointerSize;
static const int kBoundArgumentsOffset = kBoundThisOffset + kPointerSize;
static const int kCreationContextOffset =
kBoundArgumentsOffset + kPointerSize;
static const int kLengthOffset = kCreationContextOffset + kPointerSize;
static const int kNameOffset = kLengthOffset + kPointerSize;
static const int kSize = kNameOffset + kPointerSize;
// Indices of in-object properties.
static const int kLengthIndex = 0;
static const int kNameIndex = 1;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(JSBoundFunction);
};
// JSFunction describes JavaScript functions.
class JSFunction: public JSObject {
public:
@ -7309,7 +7294,8 @@ class JSFunction: public JSObject {
// Completes inobject slack tracking on initial map if it is active.
inline void CompleteInobjectSlackTrackingIfActive();
// [literals]: Fixed array holding the materialized literals.
// [literals_or_bindings]: Fixed array holding either
// the materialized literals or the bindings of a bound function.
//
// If the function contains object, regexp or array literals, the
// literals array prefix contains the object, regexp, and array
@ -7318,7 +7304,17 @@ class JSFunction: public JSObject {
// or array functions. Performing a dynamic lookup, we might end up
// using the functions from a new context that we should not have
// access to.
DECL_ACCESSORS(literals, LiteralsArray)
//
// On bound functions, the array is a (copy-on-write) fixed-array containing
// the function that was bound, bound this-value and any bound
// arguments. Bound functions never contain literals.
DECL_ACCESSORS(literals_or_bindings, FixedArray)
inline LiteralsArray* literals();
inline void set_literals(LiteralsArray* literals);
inline BindingsArray* function_bindings();
inline void set_function_bindings(BindingsArray* bindings);
// The initial map for an object created by this constructor.
inline Map* initial_map();

View File

@ -805,10 +805,9 @@ HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object) {
if (object->IsJSFunction()) {
JSFunction* func = JSFunction::cast(object);
SharedFunctionInfo* shared = func->shared();
const char* name = names_->GetName(String::cast(shared->name()));
const char* name = shared->bound() ? "native_bind" :
names_->GetName(String::cast(shared->name()));
return AddEntry(object, HeapEntry::kClosure, name);
} else if (object->IsJSBoundFunction()) {
return AddEntry(object, HeapEntry::kClosure, "native_bind");
} else if (object->IsJSRegExp()) {
JSRegExp* re = JSRegExp::cast(object);
return AddEntry(object,
@ -1099,29 +1098,13 @@ void V8HeapExplorer::ExtractJSGlobalProxyReferences(
void V8HeapExplorer::ExtractJSObjectReferences(
int entry, JSObject* js_obj) {
HeapObject* obj = js_obj;
ExtractClosureReferences(js_obj, entry);
ExtractPropertyReferences(js_obj, entry);
ExtractElementReferences(js_obj, entry);
ExtractInternalReferences(js_obj, entry);
PrototypeIterator iter(heap_->isolate(), js_obj);
SetPropertyReference(obj, entry, heap_->proto_string(), iter.GetCurrent());
if (obj->IsJSBoundFunction()) {
JSBoundFunction* js_fun = JSBoundFunction::cast(obj);
TagObject(js_fun->bound_arguments(), "(bound arguments)");
SetInternalReference(js_fun, entry, "bindings", js_fun->bound_arguments(),
JSBoundFunction::kBoundArgumentsOffset);
TagObject(js_fun->creation_context(), "(creation context)");
SetInternalReference(js_fun, entry, "creation_context",
js_fun->creation_context(),
JSBoundFunction::kCreationContextOffset);
SetNativeBindReference(js_obj, entry, "bound_this", js_fun->bound_this());
SetNativeBindReference(js_obj, entry, "bound_function",
js_fun->bound_target_function());
FixedArray* bindings = js_fun->bound_arguments();
for (int i = 0; i < bindings->length(); i++) {
const char* reference_name = names_->GetFormatted("bound_argument_%d", i);
SetNativeBindReference(js_obj, entry, reference_name, bindings->get(i));
}
} else if (obj->IsJSFunction()) {
if (obj->IsJSFunction()) {
JSFunction* js_fun = JSFunction::cast(js_obj);
Object* proto_or_map = js_fun->prototype_or_initial_map();
if (!proto_or_map->IsTheHole()) {
@ -1141,8 +1124,13 @@ void V8HeapExplorer::ExtractJSObjectReferences(
}
}
SharedFunctionInfo* shared_info = js_fun->shared();
TagObject(js_fun->literals(), "(function literals)");
SetInternalReference(js_fun, entry, "literals", js_fun->literals(),
// JSFunction has either bindings or literals and never both.
bool bound = shared_info->bound();
TagObject(js_fun->literals_or_bindings(),
bound ? "(function bindings)" : "(function literals)");
SetInternalReference(js_fun, entry,
bound ? "bindings" : "literals",
js_fun->literals_or_bindings(),
JSFunction::kLiteralsOffset);
TagObject(shared_info, "(shared function info)");
SetInternalReference(js_fun, entry,
@ -1587,6 +1575,24 @@ void V8HeapExplorer::ExtractFixedArrayReferences(int entry, FixedArray* array) {
}
void V8HeapExplorer::ExtractClosureReferences(JSObject* js_obj, int entry) {
if (!js_obj->IsJSFunction()) return;
JSFunction* func = JSFunction::cast(js_obj);
if (func->shared()->bound()) {
BindingsArray* bindings = func->function_bindings();
SetNativeBindReference(js_obj, entry, "bound_this", bindings->bound_this());
SetNativeBindReference(js_obj, entry, "bound_function",
bindings->bound_function());
for (int i = 0; i < bindings->bindings_count(); i++) {
const char* reference_name = names_->GetFormatted("bound_argument_%d", i);
SetNativeBindReference(js_obj, entry, reference_name,
bindings->binding(i));
}
}
}
void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj, int entry) {
if (js_obj->HasFastProperties()) {
DescriptorArray* descs = js_obj->map()->instance_descriptors();

View File

@ -390,6 +390,7 @@ class V8HeapExplorer : public HeapEntriesAllocator {
void ExtractAllocationSiteReferences(int entry, AllocationSite* site);
void ExtractJSArrayBufferReferences(int entry, JSArrayBuffer* buffer);
void ExtractFixedArrayReferences(int entry, FixedArray* array);
void ExtractClosureReferences(JSObject* js_obj, int entry);
void ExtractPropertyReferences(JSObject* js_obj, int entry);
void ExtractAccessorPairProperty(JSObject* js_obj, int entry, Name* key,
Object* callback_obj, int field_offset = -1);

View File

@ -150,29 +150,33 @@ static MaybeHandle<JSArray> GetIteratorInternalProperties(
MaybeHandle<JSArray> Runtime::GetInternalProperties(Isolate* isolate,
Handle<Object> object) {
Factory* factory = isolate->factory();
if (object->IsJSBoundFunction()) {
Handle<JSBoundFunction> function = Handle<JSBoundFunction>::cast(object);
if (object->IsJSFunction()) {
Handle<JSFunction> function = Handle<JSFunction>::cast(object);
if (function->shared()->bound()) {
RUNTIME_ASSERT_HANDLIFIED(function->function_bindings()->IsFixedArray(),
JSArray);
Handle<FixedArray> result = factory->NewFixedArray(2 * 3);
Handle<String> target =
factory->NewStringFromAsciiChecked("[[TargetFunction]]");
result->set(0, *target);
result->set(1, function->bound_target_function());
Handle<BindingsArray> bindings(function->function_bindings());
Handle<String> bound_this =
factory->NewStringFromAsciiChecked("[[BoundThis]]");
result->set(2, *bound_this);
result->set(3, function->bound_this());
Handle<FixedArray> result = factory->NewFixedArray(2 * 3);
Handle<String> target =
factory->NewStringFromAsciiChecked("[[TargetFunction]]");
result->set(0, *target);
result->set(1, bindings->bound_function());
Handle<String> bound_args =
factory->NewStringFromAsciiChecked("[[BoundArgs]]");
result->set(4, *bound_args);
Handle<FixedArray> bound_arguments =
factory->CopyFixedArray(handle(function->bound_arguments(), isolate));
Handle<JSArray> arguments_array =
factory->NewJSArrayWithElements(bound_arguments);
result->set(5, *arguments_array);
return factory->NewJSArrayWithElements(result);
Handle<String> bound_this =
factory->NewStringFromAsciiChecked("[[BoundThis]]");
result->set(2, *bound_this);
result->set(3, bindings->bound_this());
Handle<String> bound_args =
factory->NewStringFromAsciiChecked("[[BoundArgs]]");
result->set(4, *bound_args);
Handle<JSArray> arguments_array =
BindingsArray::CreateBoundArguments(bindings);
result->set(5, *arguments_array);
return factory->NewJSArrayWithElements(result);
}
} else if (object->IsJSMapIterator()) {
Handle<JSMapIterator> iterator = Handle<JSMapIterator>::cast(object);
return GetIteratorInternalProperties(isolate, iterator);
@ -869,18 +873,15 @@ RUNTIME_FUNCTION(Runtime_GetAllScopesDetails) {
RUNTIME_FUNCTION(Runtime_GetFunctionScopeCount) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
DCHECK(args.length() == 1);
// Check arguments.
CONVERT_ARG_HANDLE_CHECKED(JSReceiver, function, 0);
CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
// Count the visible scopes.
int n = 0;
if (function->IsJSFunction()) {
for (ScopeIterator it(isolate, Handle<JSFunction>::cast(function));
!it.Done(); it.Next()) {
n++;
}
for (ScopeIterator it(isolate, fun); !it.Done(); it.Next()) {
n++;
}
return Smi::FromInt(n);
@ -1467,27 +1468,19 @@ RUNTIME_FUNCTION(Runtime_DebugSetScriptSource) {
RUNTIME_FUNCTION(Runtime_FunctionGetInferredName) {
SealHandleScope shs(isolate);
DCHECK_EQ(1, args.length());
DCHECK(args.length() == 1);
CONVERT_ARG_CHECKED(Object, f, 0);
if (f->IsJSFunction()) {
return JSFunction::cast(f)->shared()->inferred_name();
}
return isolate->heap()->empty_string();
CONVERT_ARG_CHECKED(JSFunction, f, 0);
return f->shared()->inferred_name();
}
RUNTIME_FUNCTION(Runtime_FunctionGetDebugName) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
DCHECK(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(JSReceiver, function, 0);
if (function->IsJSBoundFunction()) {
return Handle<JSBoundFunction>::cast(function)->name();
}
Handle<Object> name =
JSFunction::GetDebugName(Handle<JSFunction>::cast(function));
CONVERT_ARG_HANDLE_CHECKED(JSFunction, f, 0);
Handle<Object> name = JSFunction::GetDebugName(f);
return *name;
}

View File

@ -53,23 +53,23 @@ RUNTIME_FUNCTION(Runtime_FunctionRemovePrototype) {
RUNTIME_FUNCTION(Runtime_FunctionGetScript) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSReceiver, function, 0);
DCHECK(args.length() == 1);
if (function->IsJSBoundFunction()) return isolate->heap()->undefined_value();
Handle<Object> script(Handle<JSFunction>::cast(function)->shared()->script(),
isolate);
CONVERT_ARG_CHECKED(JSFunction, fun, 0);
Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
if (!script->IsScript()) return isolate->heap()->undefined_value();
return *Script::GetWrapper(Handle<Script>::cast(script));
}
RUNTIME_FUNCTION(Runtime_FunctionGetSourceCode) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSReceiver, function, 0);
if (function->IsJSBoundFunction()) return isolate->heap()->undefined_value();
return *Handle<JSFunction>::cast(function)->shared()->GetSourceCode();
DCHECK(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(JSFunction, f, 0);
Handle<SharedFunctionInfo> shared(f->shared());
return *shared->GetSourceCode();
}
@ -152,6 +152,7 @@ RUNTIME_FUNCTION(Runtime_SetCode) {
Handle<SharedFunctionInfo> target_shared(target->shared());
Handle<SharedFunctionInfo> source_shared(source->shared());
RUNTIME_ASSERT(!source_shared->bound());
if (!Compiler::Compile(source, KEEP_EXCEPTION)) {
return isolate->heap()->exception();
@ -308,6 +309,137 @@ base::SmartArrayPointer<Handle<Object>> Runtime::GetCallerArguments(
}
RUNTIME_FUNCTION(Runtime_FunctionBindArguments) {
HandleScope scope(isolate);
DCHECK(args.length() == 5);
CONVERT_ARG_HANDLE_CHECKED(JSFunction, bound_function, 0);
CONVERT_ARG_HANDLE_CHECKED(JSReceiver, bindee, 1);
CONVERT_ARG_HANDLE_CHECKED(Object, this_object, 2);
CONVERT_NUMBER_ARG_HANDLE_CHECKED(new_length, 3);
CONVERT_ARG_HANDLE_CHECKED(Object, proto, 4);
// TODO(lrn): Create bound function in C++ code from premade shared info.
bound_function->shared()->set_bound(true);
bound_function->shared()->set_optimized_code_map(
isolate->heap()->cleared_optimized_code_map());
bound_function->shared()->set_inferred_name(isolate->heap()->empty_string());
bound_function->shared()->set_construct_stub(
*isolate->builtins()->JSBuiltinsConstructStub());
// Get all arguments of calling function (Function.prototype.bind).
int argc = 0;
base::SmartArrayPointer<Handle<Object>> arguments =
Runtime::GetCallerArguments(isolate, 0, &argc);
// Don't count the this-arg.
if (argc > 0) {
RUNTIME_ASSERT(arguments[0].is_identical_to(this_object));
argc--;
} else {
RUNTIME_ASSERT(this_object->IsUndefined());
}
// Initialize array of bindings (function, this, and any existing arguments
// if the function was already bound).
Handle<BindingsArray> new_bindings;
int out_index = 0;
Handle<TypeFeedbackVector> vector(
bound_function->shared()->feedback_vector());
if (bindee->IsJSFunction() && JSFunction::cast(*bindee)->shared()->bound()) {
Handle<BindingsArray> old_bindings(
JSFunction::cast(*bindee)->function_bindings());
RUNTIME_ASSERT(old_bindings->bindings_count() >= 0);
bindee = handle(old_bindings->bound_function(), isolate);
Handle<Object> old_bound_this(old_bindings->bound_this(), isolate);
new_bindings = BindingsArray::New(isolate, vector, bindee, old_bound_this,
old_bindings->bindings_count() + argc);
for (int n = old_bindings->bindings_count(); out_index < n; out_index++) {
new_bindings->set_binding(out_index, old_bindings->binding(out_index));
}
} else {
new_bindings =
BindingsArray::New(isolate, vector, bindee, this_object, argc);
}
// Copy arguments, skipping the first which is "this_arg".
for (int j = 0; j < argc; j++, out_index++) {
new_bindings->set_binding(out_index, *arguments[j + 1]);
}
new_bindings->set_map_no_write_barrier(isolate->heap()->fixed_array_map());
bound_function->set_function_bindings(*new_bindings);
// Update length. Have to remove the prototype first so that map migration
// is happy about the number of fields.
RUNTIME_ASSERT(bound_function->RemovePrototype());
// The new function should have the given prototype.
Handle<Map> bound_function_map =
bindee->IsConstructor()
? isolate->bound_function_with_constructor_map()
: isolate->bound_function_without_constructor_map();
if (bound_function_map->prototype() != *proto) {
bound_function_map = Map::TransitionToPrototype(bound_function_map, proto,
REGULAR_PROTOTYPE);
}
JSObject::MigrateToMap(bound_function, bound_function_map);
DCHECK_EQ(bindee->IsConstructor(), bound_function->IsConstructor());
Handle<String> length_string = isolate->factory()->length_string();
// These attributes must be kept in sync with how the bootstrapper
// configures the bound_function_map retrieved above.
// We use ...IgnoreAttributes() here because of length's read-onliness.
PropertyAttributes attr =
static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY);
RETURN_FAILURE_ON_EXCEPTION(
isolate, JSObject::SetOwnPropertyIgnoreAttributes(
bound_function, length_string, new_length, attr));
return *bound_function;
}
RUNTIME_FUNCTION(Runtime_BoundFunctionGetBindings) {
HandleScope handles(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(JSReceiver, callable, 0);
if (callable->IsJSFunction()) {
Handle<JSFunction> function = Handle<JSFunction>::cast(callable);
if (function->shared()->bound()) {
RUNTIME_ASSERT(function->function_bindings()->IsBindingsArray());
Handle<BindingsArray> bindings(function->function_bindings());
return *BindingsArray::CreateRuntimeBindings(bindings);
}
}
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_NewObjectFromBound) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
// First argument is a function to use as a constructor.
CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
RUNTIME_ASSERT(function->shared()->bound());
// The argument is a bound function. Extract its bound arguments
// and callable.
Handle<BindingsArray> bound_args =
handle(BindingsArray::cast(function->function_bindings()));
int bound_argc = bound_args->bindings_count();
Handle<Object> bound_function(bound_args->bound_function(), isolate);
DCHECK(!bound_function->IsJSFunction() ||
!Handle<JSFunction>::cast(bound_function)->shared()->bound());
int total_argc = 0;
base::SmartArrayPointer<Handle<Object>> param_data =
Runtime::GetCallerArguments(isolate, bound_argc, &total_argc);
for (int i = 0; i < bound_argc; i++) {
param_data[i] = handle(bound_args->binding(i), isolate);
}
Handle<Object> result;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, result, Execution::New(isolate, bound_function, bound_function,
total_argc, param_data.get()));
return *result;
}
RUNTIME_FUNCTION(Runtime_Call) {
HandleScope scope(isolate);
DCHECK_LE(2, args.length());
@ -395,9 +527,9 @@ RUNTIME_FUNCTION(Runtime_ConvertReceiver) {
RUNTIME_FUNCTION(Runtime_IsFunction) {
SealHandleScope shs(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_CHECKED(Object, object, 0);
return isolate->heap()->ToBoolean(object->IsFunction());
DCHECK(args.length() == 1);
CONVERT_ARG_CHECKED(Object, obj, 0);
return isolate->heap()->ToBoolean(obj->IsJSFunction());
}
@ -412,11 +544,8 @@ RUNTIME_FUNCTION(Runtime_ThrowStrongModeTooFewArguments) {
RUNTIME_FUNCTION(Runtime_FunctionToString) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSReceiver, function, 0);
return function->IsJSBoundFunction()
? *JSBoundFunction::ToString(
Handle<JSBoundFunction>::cast(function))
: *JSFunction::ToString(Handle<JSFunction>::cast(function));
CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
return *JSFunction::ToString(function);
}
} // namespace internal

View File

@ -1346,12 +1346,14 @@ RUNTIME_FUNCTION(Runtime_InstanceOf) {
if (!object->IsJSReceiver()) {
return isolate->heap()->false_value();
}
// Check if {callable} is bound, if so, get [[BoundTargetFunction]] from it
// and use that instead of {callable}.
while (callable->IsJSBoundFunction()) {
callable =
handle(Handle<JSBoundFunction>::cast(callable)->bound_target_function(),
isolate);
// Check if {callable} is bound, if so, get [[BoundFunction]] from it and use
// that instead of {callable}.
if (callable->IsJSFunction()) {
Handle<JSFunction> function = Handle<JSFunction>::cast(callable);
if (function->shared()->bound()) {
Handle<BindingsArray> bindings(function->function_bindings(), isolate);
callable = handle(bindings->bound_function(), isolate);
}
}
DCHECK(callable->IsCallable());
// Get the "prototype" of {callable}; raise an error if it's not a receiver.

View File

@ -56,7 +56,7 @@ RUNTIME_FUNCTION(Runtime_RunMicrotasks) {
RUNTIME_FUNCTION(Runtime_DeliverObservationChangeRecords) {
HandleScope scope(isolate);
DCHECK(args.length() == 2);
CONVERT_ARG_HANDLE_CHECKED(JSReceiver, callback, 0);
CONVERT_ARG_HANDLE_CHECKED(JSFunction, callback, 0);
CONVERT_ARG_HANDLE_CHECKED(Object, argument, 1);
v8::TryCatch catcher(reinterpret_cast<v8::Isolate*>(isolate));
// We should send a message on uncaught exception thrown during
@ -96,18 +96,11 @@ static bool ContextsHaveSameOrigin(Handle<Context> context1,
RUNTIME_FUNCTION(Runtime_ObserverObjectAndRecordHaveSameOrigin) {
HandleScope scope(isolate);
DCHECK(args.length() == 3);
CONVERT_ARG_HANDLE_CHECKED(JSReceiver, observer, 0);
CONVERT_ARG_HANDLE_CHECKED(JSFunction, observer, 0);
CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 1);
CONVERT_ARG_HANDLE_CHECKED(JSObject, record, 2);
while (observer->IsJSBoundFunction()) {
observer = handle(
Handle<JSBoundFunction>::cast(observer)->bound_target_function());
}
if (!observer->IsJSFunction()) return isolate->heap()->false_value();
Handle<Context> observer_context(
Handle<JSFunction>::cast(observer)->context()->native_context());
Handle<Context> observer_context(observer->context()->native_context());
Handle<Context> object_context(object->GetCreationContext());
Handle<Context> record_context(record->GetCreationContext());

View File

@ -247,6 +247,9 @@ namespace internal {
F(ThrowStrongModeTooFewArguments, 0, 1) \
F(IsConstructor, 1, 1) \
F(SetForceInlineFlag, 1, 1) \
F(FunctionBindArguments, 5, 1) \
F(BoundFunctionGetBindings, 1, 1) \
F(NewObjectFromBound, 1, 1) \
F(Call, -1 /* >= 2 */, 1) \
F(TailCall, -1 /* >= 2 */, 1) \
F(Apply, 5, 1) \

View File

@ -1796,7 +1796,7 @@ void PartialSerializer::SerializeObject(HeapObject* obj, HowToCode how_to_code,
FlushSkip(skip);
// Clear literal boilerplates.
if (obj->IsJSFunction()) {
if (obj->IsJSFunction() && !JSFunction::cast(obj)->shared()->bound()) {
FixedArray* literals = JSFunction::cast(obj)->literals();
for (int i = 0; i < literals->length(); i++) literals->set_undefined(i);
}

View File

@ -245,7 +245,6 @@ TypeImpl<Config>::BitsetType::Lub(i::Map* map) {
case JS_WEAK_MAP_TYPE:
case JS_WEAK_SET_TYPE:
case JS_PROMISE_TYPE:
case JS_BOUND_FUNCTION_TYPE:
if (map->is_undetectable()) return kUndetectable;
return kOtherObject;
case JS_FUNCTION_TYPE:

View File

@ -1973,116 +1973,6 @@ void Builtins::Generate_CallFunction(MacroAssembler* masm,
}
namespace {
void Generate_PushBoundArguments(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- rax : the number of arguments (not including the receiver)
// -- rdx : new.target (only in case of [[Construct]])
// -- rdi : target (checked to be a JSBoundFunction)
// -----------------------------------
// Load [[BoundArguments]] into rcx and length of that into rbx.
Label no_bound_arguments;
__ movp(rcx, FieldOperand(rdi, JSBoundFunction::kBoundArgumentsOffset));
__ SmiToInteger32(rbx, FieldOperand(rcx, FixedArray::kLengthOffset));
__ testl(rbx, rbx);
__ j(zero, &no_bound_arguments);
{
// ----------- S t a t e -------------
// -- rax : the number of arguments (not including the receiver)
// -- rdx : new.target (only in case of [[Construct]])
// -- rdi : target (checked to be a JSBoundFunction)
// -- rcx : the [[BoundArguments]] (implemented as FixedArray)
// -- rbx : the number of [[BoundArguments]] (checked to be non-zero)
// -----------------------------------
// Reserve stack space for the [[BoundArguments]].
{
Label done;
__ leap(kScratchRegister, Operand(rbx, times_pointer_size, 0));
__ subp(rsp, kScratchRegister);
// Check the stack for overflow. We are not trying to catch interruptions
// (i.e. debug break and preemption) here, so check the "real stack
// limit".
__ CompareRoot(rsp, Heap::kRealStackLimitRootIndex);
__ j(greater, &done, Label::kNear); // Signed comparison.
// Restore the stack pointer.
__ leap(rsp, Operand(rsp, rbx, times_pointer_size, 0));
{
FrameScope scope(masm, StackFrame::MANUAL);
__ EnterFrame(StackFrame::INTERNAL);
__ CallRuntime(Runtime::kThrowStackOverflow, 0);
}
__ bind(&done);
}
// Adjust effective number of arguments to include return address.
__ incl(rax);
// Relocate arguments and return address down the stack.
{
Label loop;
__ Set(rcx, 0);
__ leap(rbx, Operand(rsp, rbx, times_pointer_size, 0));
__ bind(&loop);
__ movp(kScratchRegister, Operand(rbx, rcx, times_pointer_size, 0));
__ movp(Operand(rsp, rcx, times_pointer_size, 0), kScratchRegister);
__ incl(rcx);
__ cmpl(rcx, rax);
__ j(less, &loop);
}
// Copy [[BoundArguments]] to the stack (below the arguments).
{
Label loop;
__ movp(rcx, FieldOperand(rdi, JSBoundFunction::kBoundArgumentsOffset));
__ SmiToInteger32(rbx, FieldOperand(rcx, FixedArray::kLengthOffset));
__ bind(&loop);
__ decl(rbx);
__ movp(kScratchRegister, FieldOperand(rcx, rbx, times_pointer_size,
FixedArray::kHeaderSize));
__ movp(Operand(rsp, rax, times_pointer_size, 0), kScratchRegister);
__ leal(rax, Operand(rax, 1));
__ j(greater, &loop);
}
// Adjust effective number of arguments (rax contains the number of
// arguments from the call plus return address plus the number of
// [[BoundArguments]]), so we need to subtract one for the return address.
__ decl(rax);
}
__ bind(&no_bound_arguments);
}
} // namespace
// static
void Builtins::Generate_CallBoundFunction(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- rax : the number of arguments (not including the receiver)
// -- rdi : the function to call (checked to be a JSBoundFunction)
// -----------------------------------
__ AssertBoundFunction(rdi);
// Patch the receiver to [[BoundThis]].
StackArgumentsAccessor args(rsp, rax);
__ movp(rbx, FieldOperand(rdi, JSBoundFunction::kBoundThisOffset));
__ movp(args.GetReceiverOperand(), rbx);
// Push the [[BoundArguments]] onto the stack.
Generate_PushBoundArguments(masm);
// Call the [[BoundTargetFunction]] via the Call builtin.
__ movp(rdi, FieldOperand(rdi, JSBoundFunction::kBoundTargetFunctionOffset));
__ Load(rcx,
ExternalReference(Builtins::kCall_ReceiverIsAny, masm->isolate()));
__ leap(rcx, FieldOperand(rcx, Code::kHeaderSize));
__ jmp(rcx);
}
// static
void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) {
// ----------- S t a t e -------------
@ -2097,9 +1987,6 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) {
__ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
__ j(equal, masm->isolate()->builtins()->CallFunction(mode),
RelocInfo::CODE_TARGET);
__ CmpInstanceType(rcx, JS_BOUND_FUNCTION_TYPE);
__ j(equal, masm->isolate()->builtins()->CallBoundFunction(),
RelocInfo::CODE_TARGET);
__ CmpInstanceType(rcx, JS_PROXY_TYPE);
__ j(not_equal, &non_function);
@ -2161,36 +2048,6 @@ void Builtins::Generate_ConstructFunction(MacroAssembler* masm) {
}
// static
void Builtins::Generate_ConstructBoundFunction(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- rax : the number of arguments (not including the receiver)
// -- rdx : the new target (checked to be a constructor)
// -- rdi : the constructor to call (checked to be a JSBoundFunction)
// -----------------------------------
__ AssertBoundFunction(rdi);
// Push the [[BoundArguments]] onto the stack.
Generate_PushBoundArguments(masm);
// Patch new.target to [[BoundTargetFunction]] if new.target equals target.
{
Label done;
__ cmpp(rdi, rdx);
__ j(not_equal, &done, Label::kNear);
__ movp(rdx,
FieldOperand(rdi, JSBoundFunction::kBoundTargetFunctionOffset));
__ bind(&done);
}
// Construct the [[BoundTargetFunction]] via the Construct builtin.
__ movp(rdi, FieldOperand(rdi, JSBoundFunction::kBoundTargetFunctionOffset));
__ Load(rcx, ExternalReference(Builtins::kConstruct, masm->isolate()));
__ leap(rcx, FieldOperand(rcx, Code::kHeaderSize));
__ jmp(rcx);
}
// static
void Builtins::Generate_ConstructProxy(MacroAssembler* masm) {
// ----------- S t a t e -------------
@ -2236,12 +2093,6 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
Immediate(1 << Map::kIsConstructor));
__ j(zero, &non_constructor, Label::kNear);
// Only dispatch to bound functions after checking whether they are
// constructors.
__ CmpInstanceType(rcx, JS_BOUND_FUNCTION_TYPE);
__ j(equal, masm->isolate()->builtins()->ConstructBoundFunction(),
RelocInfo::CODE_TARGET);
// Only dispatch to proxies after checking whether they are constructors.
__ CmpInstanceType(rcx, JS_PROXY_TYPE);
__ j(equal, masm->isolate()->builtins()->ConstructProxy(),

View File

@ -2511,6 +2511,15 @@ void InstanceOfStub::Generate(MacroAssembler* masm) {
Immediate(1 << Map::kHasNonInstancePrototype));
__ j(not_zero, &slow_case);
// Ensure that {function} is not bound.
Register const shared_info = kScratchRegister;
__ movp(shared_info,
FieldOperand(function, JSFunction::kSharedFunctionInfoOffset));
__ TestBitSharedFunctionInfoSpecialField(
shared_info, SharedFunctionInfo::kCompilerHintsOffset,
SharedFunctionInfo::kBoundFunction);
__ j(not_zero, &slow_case);
// Get the "prototype" (or initial map) of the {function}.
__ movp(function_prototype,
FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset));

View File

@ -3862,18 +3862,6 @@ void MacroAssembler::AssertFunction(Register object) {
}
void MacroAssembler::AssertBoundFunction(Register object) {
if (emit_debug_code()) {
testb(object, Immediate(kSmiTagMask));
Check(not_equal, kOperandIsASmiAndNotABoundFunction);
Push(object);
CmpObjectType(object, JS_BOUND_FUNCTION_TYPE, object);
Pop(object);
Check(equal, kOperandIsNotABoundFunction);
}
}
void MacroAssembler::AssertUndefinedOrAllocationSite(Register object) {
if (emit_debug_code()) {
Label done_checking;

View File

@ -1202,10 +1202,6 @@ class MacroAssembler: public Assembler {
// Abort execution if argument is not a JSFunction, enabled via --debug-code.
void AssertFunction(Register object);
// Abort execution if argument is not a JSBoundFunction,
// enabled via --debug-code.
void AssertBoundFunction(Register object);
// Abort execution if argument is not undefined or an AllocationSite, enabled
// via --debug-code.
void AssertUndefinedOrAllocationSite(Register object);

View File

@ -19646,39 +19646,6 @@ THREADED_TEST(CreationContextOfJsFunction) {
}
THREADED_TEST(CreationContextOfJsBoundFunction) {
HandleScope handle_scope(CcTest::isolate());
Local<Context> context1 = Context::New(CcTest::isolate());
InstallContextId(context1, 1);
Local<Context> context2 = Context::New(CcTest::isolate());
InstallContextId(context2, 2);
Local<Function> target_function;
{
Context::Scope scope(context1);
target_function = CompileRun("function foo() {}; foo").As<Function>();
}
Local<Function> bound_function1, bound_function2;
{
Context::Scope scope(context2);
CHECK(context2->Global()
->Set(context2, v8_str("foo"), target_function)
.FromJust());
bound_function1 = CompileRun("foo.bind(1)").As<Function>();
bound_function2 =
CompileRun("Function.prototype.bind.call(foo, 2)").As<Function>();
}
Local<Context> other_context = Context::New(CcTest::isolate());
Context::Scope scope(other_context);
CHECK(bound_function1->CreationContext() == context1);
CheckContextId(bound_function1, 1);
CHECK(bound_function2->CreationContext() == context2);
CheckContextId(bound_function2, 1);
}
void HasOwnPropertyIndexedPropertyGetter(
uint32_t index,
const v8::PropertyCallbackInfo<v8::Value>& info) {

View File

@ -251,7 +251,7 @@ TEST(BoundFunctionInSnapshot) {
GetProperty(f, v8::HeapGraphEdge::kInternal, "bindings");
CHECK(bindings);
CHECK_EQ(v8::HeapGraphNode::kArray, bindings->GetType());
CHECK_EQ(1, bindings->GetChildrenCount());
CHECK_EQ(3, bindings->GetChildrenCount());
const v8::HeapGraphNode* bound_this = GetProperty(
f, v8::HeapGraphEdge::kShortcut, "bound_this");

View File

@ -40,29 +40,24 @@ assertEquals(3, foo.length);
var f = foo.bind(foo);
assertEquals([foo, 3, 1], f(1, 2, 3));
assertEquals(3, f.length);
assertEquals("function () { [native code] }", f.toString());
f = foo.bind(foo, 1);
assertEquals([foo, 3, 1], f(2, 3));
assertEquals(2, f.length);
assertEquals("function () { [native code] }", f.toString());
f = foo.bind(foo, 1, 2);
assertEquals([foo, 3, 1], f(3));
assertEquals(1, f.length);
assertEquals("function () { [native code] }", f.toString());
f = foo.bind(foo, 1, 2, 3);
assertEquals([foo, 3, 1], f());
assertEquals(0, f.length);
assertEquals("function () { [native code] }", f.toString());
// Test that length works correctly even if more than the actual number
// of arguments are given when binding.
f = foo.bind(foo, 1, 2, 3, 4, 5, 6, 7, 8, 9);
assertEquals([foo, 9, 1], f());
assertEquals(0, f.length);
assertEquals("function () { [native code] }", f.toString());
// Use a different bound object.
var obj = {x: 42, y: 43};
@ -82,7 +77,6 @@ assertEquals(1, f.length);
f = f_bound_this.bind(obj, 2);
assertEquals(3, f());
assertEquals(0, f.length);
assertEquals('[object Function]', Object.prototype.toString.call(f));
// Test chained binds.

View File

@ -0,0 +1,146 @@
// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Flags: --allow-natives-syntax
// Check that %NewObjectFromBound works correctly when called from optimized
// frame.
function foo1(x, y, z) {
assertEquals(1, x);
assertEquals(2, y);
assertEquals(3, z);
}
function foo2(x, y, z) {
assertEquals(1, x);
assertEquals(2, y);
assertEquals(undefined, z);
}
function foo3(x, y, z) {
assertEquals(1, x);
assertEquals(2, y);
assertEquals(3, z);
}
var foob1 = foo1.bind({}, 1);
var foob2 = foo2.bind({}, 1);
var foob3 = foo3.bind({}, 1);
function f1(y, z) {
return %NewObjectFromBound(foob1);
}
function f2(y, z) {
return %NewObjectFromBound(foob2);
}
function f3(y, z) {
return %NewObjectFromBound(foob3);
}
// Check that %NewObjectFromBound looks at correct frame for inlined function.
function g1(z, y) {
return f1(y, z); /* f should be inlined into g, note rotated arguments */
}
function g2(z, y, x) {
return f2(y); /* f should be inlined into g, note argument count mismatch */
}
function g3(z, y, x) {
return f3(x, y, z); /* f should be inlined into g, note argument count mismatch */
}
// Check that %NewObjectFromBound looks at correct frame for inlined function.
function ff(x) { }
function h1(z2, y2) {
var local_z = z2 >> 1;
ff(local_z);
var local_y = y2 >> 1;
ff(local_y);
return f1(local_y, local_z); /* f should be inlined into h */
}
function h2(z2, y2, x2) {
var local_z = z2 >> 1;
ff(local_z);
var local_y = y2 >> 1;
ff(local_y);
return f2(local_y); /* f should be inlined into h */
}
function h3(z2, y2, x2) {
var local_z = z2 >> 1;
ff(local_z);
var local_y = y2 >> 1;
ff(local_y);
var local_x = x2 >> 1;
ff(local_x);
return f3(local_x, local_y, local_z); /* f should be inlined into h */
}
function invoke(f, args) {
for (var i = 0; i < 5; i++) f.apply(this, args);
%OptimizeFunctionOnNextCall(f);
f.apply(this, args);
}
invoke(f1, [2, 3]);
invoke(f2, [2]);
invoke(f3, [2, 3, 4]);
invoke(g1, [3, 2]);
invoke(g2, [3, 2, 4]);
invoke(g3, [4, 3, 2]);
invoke(h1, [6, 4]);
invoke(h2, [6, 4, 8]);
invoke(h3, [8, 6, 4]);
// Check that new.target returns correct value when inlined
var NON_CONSTRUCT_MARKER = {};
var CONSTRUCT_MARKER = {};
function baz(x) {
return (new.target === undefined) ? NON_CONSTRUCT_MARKER : CONSTRUCT_MARKER;
}
function bar(x, y, z) {
var non_construct = baz(0); /* baz should be inlined */
assertSame(non_construct, NON_CONSTRUCT_MARKER);
var non_construct = baz(); /* baz should be inlined */
assertSame(non_construct, NON_CONSTRUCT_MARKER);
var non_construct = baz(0, 0); /* baz should be inlined */
assertSame(non_construct, NON_CONSTRUCT_MARKER);
var construct = new baz(0);
assertSame(construct, CONSTRUCT_MARKER);
var construct = new baz(0, 0);
assertSame(construct, CONSTRUCT_MARKER);
}
invoke(bar, [1, 2, 3]);

View File

@ -0,0 +1,49 @@
// Copyright 2014 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Flags: --allow-natives-syntax
function f_13(x, y, z) { }
v_5 = f_13.bind({}, -7);
function f_0(z) {
return %NewObjectFromBound(v_5);
}
function f_8(z2, y2) {
var v_0 = { f1 : 0.5, f2 : 0.25 };
return f_0(v_0);
}
function f_12(f, args) {
f.apply(this, args);
%OptimizeFunctionOnNextCall(f);
f.apply(this, args);
}
f_12(f_8, [6, 4]);

View File

@ -401,6 +401,10 @@
'language/eval-code/non-definable-function-with-variable': [FAIL],
'language/eval-code/non-definable-function-with-function': [FAIL],
# https://bugs.chromium.org/p/v8/issues/detail?id=4629
'built-ins/ArrayBuffer/data-allocation-after-object-creation': [FAIL],
'built-ins/ArrayBuffer/prototype-from-newtarget': [FAIL],
# https://bugs.chromium.org/p/v8/issues/detail?id=4592
'built-ins/ArrayBuffer/length-is-absent': [FAIL],
'built-ins/ArrayBuffer/length-is-not-number': [FAIL],

View File

@ -228,8 +228,8 @@ TEST_F(JSIntrinsicLoweringTest, InlineIsTypedArray) {
TEST_F(JSIntrinsicLoweringTest, InlineIsFunction) {
Node* const input = Parameter(Type::Any());
Node* const context = Parameter(Type::Any());
Node* const input = Parameter(0);
Node* const context = Parameter(1);
Node* const effect = graph()->start();
Node* const control = graph()->start();
Reduction const r = Reduce(
@ -243,12 +243,11 @@ TEST_F(JSIntrinsicLoweringTest, InlineIsFunction) {
phi,
IsPhi(
MachineRepresentation::kTagged, IsFalseConstant(),
IsUint32LessThanOrEqual(
IsInt32Constant(FIRST_FUNCTION_TYPE),
IsLoadField(AccessBuilder::ForMapInstanceType(),
IsLoadField(AccessBuilder::ForMap(), input, effect,
CaptureEq(&if_false)),
effect, _)),
IsWord32Equal(IsLoadField(AccessBuilder::ForMapInstanceType(),
IsLoadField(AccessBuilder::ForMap(), input,
effect, CaptureEq(&if_false)),
effect, _),
IsInt32Constant(JS_FUNCTION_TYPE)),
IsMerge(IsIfTrue(AllOf(CaptureEq(&branch),
IsBranch(IsObjectIsSmi(input), control))),
AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch))))));