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:
parent
ca8623eaa4
commit
1cf8b105d6
@ -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
|
||||
|
@ -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,
|
||||
|
32
src/api.cc
32
src/api.cc
@ -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));
|
||||
}
|
||||
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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));
|
||||
|
@ -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()) {
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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));
|
||||
|
@ -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()) {
|
||||
|
@ -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);
|
||||
|
@ -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") \
|
||||
|
@ -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(),
|
||||
|
@ -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(
|
||||
|
@ -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])
|
||||
|
@ -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());
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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") \
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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(),
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
|
@ -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));
|
||||
|
@ -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()) {
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
|
@ -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));
|
||||
|
@ -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()) {
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
115
src/objects.cc
115
src/objects.cc
@ -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();
|
||||
|
138
src/objects.h
138
src/objects.h
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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());
|
||||
|
||||
|
@ -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) \
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -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(),
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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");
|
||||
|
@ -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.
|
||||
|
||||
|
146
test/mjsunit/regress/regress-1229.js
Normal file
146
test/mjsunit/regress/regress-1229.js
Normal 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]);
|
49
test/mjsunit/regress/regress-351315.js
Normal file
49
test/mjsunit/regress/regress-351315.js
Normal 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]);
|
@ -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],
|
||||
|
@ -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))))));
|
||||
|
Loading…
Reference in New Issue
Block a user