[runtime] Don't set ConstructedNonConstructable as a construct_stub

Part of ongoing work to remove the construct_stub.

For non-constructable functions, don't use the non-constructable stub,
instead handle non-constructables explicitly in ConstructFunction.

Bug: v8:7503
Change-Id: I24aa7c2d5e934d5e80cd96afaf005342773d57af
Reviewed-on: https://chromium-review.googlesource.com/975961
Commit-Queue: Peter Marshall <petermarshall@chromium.org>
Reviewed-by: Benedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#52185}
This commit is contained in:
Peter Marshall 2018-03-23 15:23:20 +01:00 committed by Commit Bot
parent ed3636e21b
commit d663614591
23 changed files with 164 additions and 65 deletions

View File

@ -1885,6 +1885,20 @@ void MacroAssembler::AssertFixedArray(Register object) {
}
}
void MacroAssembler::AssertConstructor(Register object) {
if (emit_debug_code()) {
STATIC_ASSERT(kSmiTag == 0);
tst(object, Operand(kSmiTagMask));
Check(ne, AbortReason::kOperandIsASmiAndNotAConstructor);
push(object);
ldr(object, FieldMemOperand(object, HeapObject::kMapOffset));
ldrb(object, FieldMemOperand(object, Map::kBitFieldOffset));
tst(object, Operand(Map::IsConstructorBit::kMask));
pop(object);
Check(ne, AbortReason::kOperandIsNotAConstructor);
}
}
void MacroAssembler::AssertFunction(Register object) {
if (emit_debug_code()) {
STATIC_ASSERT(kSmiTag == 0);

View File

@ -837,6 +837,9 @@ class MacroAssembler : public TurboAssembler {
// Abort execution if argument is not a FixedArray, enabled via --debug-code.
void AssertFixedArray(Register object);
// Abort execution if argument is not a Constructor, enabled via --debug-code.
void AssertConstructor(Register object);
// Abort execution if argument is not a JSFunction, enabled via --debug-code.
void AssertFunction(Register object);

View File

@ -1625,6 +1625,21 @@ void MacroAssembler::AssertFixedArray(Register object) {
}
}
void MacroAssembler::AssertConstructor(Register object) {
if (emit_debug_code()) {
AssertNotSmi(object, AbortReason::kOperandIsASmiAndNotAConstructor);
UseScratchRegisterScope temps(this);
Register temp = temps.AcquireX();
Ldr(temp, FieldMemOperand(object, HeapObject::kMapOffset));
Ldrb(temp, FieldMemOperand(temp, Map::kBitFieldOffset));
Tst(temp, Operand(Map::IsConstructorBit::kMask));
Check(ne, AbortReason::kOperandIsNotAConstructor);
}
}
void MacroAssembler::AssertFunction(Register object) {
if (emit_debug_code()) {
AssertNotSmi(object, AbortReason::kOperandIsASmiAndNotAFunction);

View File

@ -1713,6 +1713,9 @@ class MacroAssembler : public TurboAssembler {
// Abort execution if argument is not a FixedArray, enabled via --debug-code.
void AssertFixedArray(Register object);
// Abort execution if argument is not a Constructor, enabled via --debug-code.
void AssertConstructor(Register object);
// Abort execution if argument is not a JSFunction, enabled via --debug-code.
void AssertFunction(Register object);

View File

@ -40,11 +40,14 @@ namespace internal {
V(kOperandIsASmi, "Operand is a smi") \
V(kOperandIsASmiAndNotABoundFunction, \
"Operand is a smi and not a bound function") \
V(kOperandIsASmiAndNotAConstructor, \
"Operand is a smi and not a constructor") \
V(kOperandIsASmiAndNotAFixedArray, "Operand is a smi and not a fixed array") \
V(kOperandIsASmiAndNotAFunction, "Operand is a smi and not a function") \
V(kOperandIsASmiAndNotAGeneratorObject, \
"Operand is a smi and not a generator object") \
V(kOperandIsNotABoundFunction, "Operand is not a bound function") \
V(kOperandIsNotAConstructor, "Operand is not a constructor") \
V(kOperandIsNotAFixedArray, "Operand is not a fixed array") \
V(kOperandIsNotAFunction, "Operand is not a function") \
V(kOperandIsNotAGeneratorObject, "Operand is not a generator object") \

View File

@ -2233,6 +2233,7 @@ void Builtins::Generate_ConstructFunction(MacroAssembler* masm) {
// -- r1 : the constructor to call (checked to be a JSFunction)
// -- r3 : the new target (checked to be a constructor)
// -----------------------------------
__ AssertConstructor(r1);
__ AssertFunction(r1);
// Calling convention for function specific ConstructStubs require
@ -2253,6 +2254,7 @@ void Builtins::Generate_ConstructBoundFunction(MacroAssembler* masm) {
// -- r1 : the function to call (checked to be a JSBoundFunction)
// -- r3 : the new target (checked to be a constructor)
// -----------------------------------
__ AssertConstructor(r1);
__ AssertBoundFunction(r1);
// Push the [[BoundArguments]] onto the stack.
@ -2281,16 +2283,17 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
Label non_constructor, non_proxy;
__ JumpIfSmi(r1, &non_constructor);
// Dispatch based on instance type.
__ CompareObjectType(r1, r4, r5, JS_FUNCTION_TYPE);
__ Jump(BUILTIN_CODE(masm->isolate(), ConstructFunction),
RelocInfo::CODE_TARGET, eq);
// Check if target has a [[Construct]] internal method.
__ ldr(r4, FieldMemOperand(r1, HeapObject::kMapOffset));
__ ldrb(r2, FieldMemOperand(r4, Map::kBitFieldOffset));
__ tst(r2, Operand(Map::IsConstructorBit::kMask));
__ b(eq, &non_constructor);
// Dispatch based on instance type.
__ CompareInstanceType(r4, r5, JS_FUNCTION_TYPE);
__ Jump(BUILTIN_CODE(masm->isolate(), ConstructFunction),
RelocInfo::CODE_TARGET, eq);
// Only dispatch to bound functions after checking whether they are
// constructors.
__ cmp(r5, Operand(JS_BOUND_FUNCTION_TYPE));

View File

@ -2637,6 +2637,7 @@ void Builtins::Generate_ConstructFunction(MacroAssembler* masm) {
// -- x1 : the constructor to call (checked to be a JSFunction)
// -- x3 : the new target (checked to be a constructor)
// -----------------------------------
__ AssertConstructor(x1);
__ AssertFunction(x1);
// Calling convention for function specific ConstructStubs require
@ -2658,6 +2659,7 @@ void Builtins::Generate_ConstructBoundFunction(MacroAssembler* masm) {
// -- x1 : the function to call (checked to be a JSBoundFunction)
// -- x3 : the new target (checked to be a constructor)
// -----------------------------------
__ AssertConstructor(x1);
__ AssertBoundFunction(x1);
// Push the [[BoundArguments]] onto the stack.
@ -2691,16 +2693,17 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
Label non_constructor, non_proxy;
__ JumpIfSmi(x1, &non_constructor);
// Dispatch based on instance type.
__ CompareObjectType(x1, x4, x5, JS_FUNCTION_TYPE);
__ Jump(BUILTIN_CODE(masm->isolate(), ConstructFunction),
RelocInfo::CODE_TARGET, eq);
// Check if target has a [[Construct]] internal method.
__ Ldr(x4, FieldMemOperand(x1, HeapObject::kMapOffset));
__ Ldrb(x2, FieldMemOperand(x4, Map::kBitFieldOffset));
__ TestAndBranchIfAllClear(x2, Map::IsConstructorBit::kMask,
&non_constructor);
// Dispatch based on instance type.
__ CompareInstanceType(x4, x5, JS_FUNCTION_TYPE);
__ Jump(BUILTIN_CODE(masm->isolate(), ConstructFunction),
RelocInfo::CODE_TARGET, eq);
// Only dispatch to bound functions after checking whether they are
// constructors.
__ Cmp(x5, JS_BOUND_FUNCTION_TYPE);

View File

@ -2377,6 +2377,7 @@ void Builtins::Generate_ConstructFunction(MacroAssembler* masm) {
// -- edx : the new target (checked to be a constructor)
// -- edi : the constructor to call (checked to be a JSFunction)
// -----------------------------------
__ AssertConstructor(edi);
__ AssertFunction(edi);
// Calling convention for function specific ConstructStubs require
@ -2398,6 +2399,7 @@ void Builtins::Generate_ConstructBoundFunction(MacroAssembler* masm) {
// -- edx : the new target (checked to be a constructor)
// -- edi : the constructor to call (checked to be a JSBoundFunction)
// -----------------------------------
__ AssertConstructor(edi);
__ AssertBoundFunction(edi);
// Push the [[BoundArguments]] onto the stack.
@ -2430,16 +2432,17 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
Label non_constructor, non_proxy;
__ JumpIfSmi(edi, &non_constructor, Label::kNear);
// Dispatch based on instance type.
__ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
__ j(equal, BUILTIN_CODE(masm->isolate(), ConstructFunction),
RelocInfo::CODE_TARGET);
// Check if target has a [[Construct]] internal method.
__ mov(ecx, FieldOperand(edi, HeapObject::kMapOffset));
__ test_b(FieldOperand(ecx, Map::kBitFieldOffset),
Immediate(Map::IsConstructorBit::kMask));
__ j(zero, &non_constructor, Label::kNear);
// Dispatch based on instance type.
__ CmpInstanceType(ecx, JS_FUNCTION_TYPE);
__ j(equal, BUILTIN_CODE(masm->isolate(), ConstructFunction),
RelocInfo::CODE_TARGET);
// Only dispatch to bound functions after checking whether they are
// constructors.
__ CmpInstanceType(ecx, JS_BOUND_FUNCTION_TYPE);

View File

@ -2230,6 +2230,7 @@ void Builtins::Generate_ConstructFunction(MacroAssembler* masm) {
// -- a1 : the constructor to call (checked to be a JSFunction)
// -- a3 : the new target (checked to be a constructor)
// -----------------------------------
__ AssertConstructor(a1);
__ AssertFunction(a1);
// Calling convention for function specific ConstructStubs require
@ -2250,6 +2251,7 @@ void Builtins::Generate_ConstructBoundFunction(MacroAssembler* masm) {
// -- a1 : the function to call (checked to be a JSBoundFunction)
// -- a3 : the new target (checked to be a constructor)
// -----------------------------------
__ AssertConstructor(a1);
__ AssertBoundFunction(a1);
// Load [[BoundArguments]] into a2 and length of that into t0.
@ -2344,16 +2346,17 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
Label non_constructor, non_proxy;
__ JumpIfSmi(a1, &non_constructor);
// Dispatch based on instance type.
__ GetObjectType(a1, t1, t2);
__ Jump(BUILTIN_CODE(masm->isolate(), ConstructFunction),
RelocInfo::CODE_TARGET, eq, t2, Operand(JS_FUNCTION_TYPE));
// Check if target has a [[Construct]] internal method.
__ lw(t1, FieldMemOperand(a1, HeapObject::kMapOffset));
__ lbu(t3, FieldMemOperand(t1, Map::kBitFieldOffset));
__ And(t3, t3, Operand(Map::IsConstructorBit::kMask));
__ Branch(&non_constructor, eq, t3, Operand(zero_reg));
// Dispatch based on instance type.
__ lhu(t2, FieldMemOperand(t1, Map::kInstanceTypeOffset));
__ Jump(BUILTIN_CODE(masm->isolate(), ConstructFunction),
RelocInfo::CODE_TARGET, eq, t2, Operand(JS_FUNCTION_TYPE));
// Only dispatch to bound functions after checking whether they are
// constructors.
__ Jump(BUILTIN_CODE(masm->isolate(), ConstructBoundFunction),

View File

@ -2249,6 +2249,7 @@ void Builtins::Generate_ConstructFunction(MacroAssembler* masm) {
// -- a1 : the constructor to call (checked to be a JSFunction)
// -- a3 : the new target (checked to be a constructor)
// -----------------------------------
__ AssertConstructor(a1);
__ AssertFunction(a1);
// Calling convention for function specific ConstructStubs require
@ -2270,6 +2271,7 @@ void Builtins::Generate_ConstructBoundFunction(MacroAssembler* masm) {
// -- a1 : the function to call (checked to be a JSBoundFunction)
// -- a3 : the new target (checked to be a constructor)
// -----------------------------------
__ AssertConstructor(a1);
__ AssertBoundFunction(a1);
// Load [[BoundArguments]] into a2 and length of that into a4.
@ -2362,16 +2364,17 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
Label non_constructor, non_proxy;
__ JumpIfSmi(a1, &non_constructor);
// Dispatch based on instance type.
__ GetObjectType(a1, t1, t2);
__ Jump(BUILTIN_CODE(masm->isolate(), ConstructFunction),
RelocInfo::CODE_TARGET, eq, t2, Operand(JS_FUNCTION_TYPE));
// Check if target has a [[Construct]] internal method.
__ ld(t1, FieldMemOperand(a1, HeapObject::kMapOffset));
__ Lbu(t3, FieldMemOperand(t1, Map::kBitFieldOffset));
__ And(t3, t3, Operand(Map::IsConstructorBit::kMask));
__ Branch(&non_constructor, eq, t3, Operand(zero_reg));
// Dispatch based on instance type.
__ Lhu(t2, FieldMemOperand(t1, Map::kInstanceTypeOffset));
__ Jump(BUILTIN_CODE(masm->isolate(), ConstructFunction),
RelocInfo::CODE_TARGET, eq, t2, Operand(JS_FUNCTION_TYPE));
// Only dispatch to bound functions after checking whether they are
// constructors.
__ Jump(BUILTIN_CODE(masm->isolate(), ConstructBoundFunction),

View File

@ -2484,6 +2484,7 @@ void Builtins::Generate_ConstructFunction(MacroAssembler* masm) {
// -- rdx : the new target (checked to be a constructor)
// -- rdi : the constructor to call (checked to be a JSFunction)
// -----------------------------------
__ AssertConstructor(rdi);
__ AssertFunction(rdi);
// Calling convention for function specific ConstructStubs require
@ -2505,6 +2506,7 @@ void Builtins::Generate_ConstructBoundFunction(MacroAssembler* masm) {
// -- rdx : the new target (checked to be a constructor)
// -- rdi : the constructor to call (checked to be a JSBoundFunction)
// -----------------------------------
__ AssertConstructor(rdi);
__ AssertBoundFunction(rdi);
// Push the [[BoundArguments]] onto the stack.
@ -2539,16 +2541,17 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
Label non_constructor, non_proxy;
__ JumpIfSmi(rdi, &non_constructor, Label::kNear);
// Dispatch based on instance type.
__ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
__ j(equal, BUILTIN_CODE(masm->isolate(), ConstructFunction),
RelocInfo::CODE_TARGET);
// Check if target has a [[Construct]] internal method.
__ movq(rcx, FieldOperand(rdi, HeapObject::kMapOffset));
__ testb(FieldOperand(rcx, Map::kBitFieldOffset),
Immediate(Map::IsConstructorBit::kMask));
__ j(zero, &non_constructor, Label::kNear);
// Dispatch based on instance type.
__ CmpInstanceType(rcx, JS_FUNCTION_TYPE);
__ j(equal, BUILTIN_CODE(masm->isolate(), ConstructFunction),
RelocInfo::CODE_TARGET);
// Only dispatch to bound functions after checking whether they are
// constructors.
__ CmpInstanceType(rcx, JS_BOUND_FUNCTION_TYPE);

View File

@ -270,13 +270,6 @@ bool NeedsImplicitReceiver(Handle<SharedFunctionInfo> shared_info) {
}
}
bool IsNonConstructible(Handle<SharedFunctionInfo> shared_info) {
DisallowHeapAllocation no_gc;
Isolate* const isolate = shared_info->GetIsolate();
Code* const construct_stub = shared_info->construct_stub();
return construct_stub == *BUILTIN_CODE(isolate, ConstructedNonConstructable);
}
} // namespace
// Determines whether the call target of the given call {node} is statically
@ -402,7 +395,7 @@ Reduction JSInliner::ReduceJSCall(Node* node) {
// Constructor must be constructable.
if (node->opcode() == IrOpcode::kJSConstruct &&
IsNonConstructible(shared_info)) {
!IsConstructable(shared_info->kind())) {
TRACE("Not inlining %s into %s because constructor is not constructable.\n",
shared_info->DebugName()->ToCString().get(),
info_->shared_info()->DebugName()->ToCString().get());

View File

@ -1528,7 +1528,12 @@ Reduction JSTypedLowering::ReduceJSConstructForwardVarargs(Node* node) {
Node* new_target = NodeProperties::GetValueInput(node, arity + 1);
// Check if {target} is a JSFunction.
if (target_type->Is(Type::Function())) {
if (target_type->IsHeapConstant() &&
target_type->AsHeapConstant()->Value()->IsJSFunction()) {
// Only optimize [[Construct]] here if {function} is a Constructor.
Handle<JSFunction> function =
Handle<JSFunction>::cast(target_type->AsHeapConstant()->Value());
if (!function->IsConstructor()) return NoChange();
// Patch {node} to an indirect call via ConstructFunctionForwardVarargs.
Callable callable = CodeFactory::ConstructFunctionForwardVarargs(isolate());
node->RemoveInput(arity + 1);
@ -1568,6 +1573,9 @@ Reduction JSTypedLowering::ReduceJSConstruct(Node* node) {
const int builtin_index = shared->construct_stub()->builtin_index();
const bool is_builtin = (builtin_index != -1);
// Only optimize [[Construct]] here if {function} is a Constructor.
if (!function->IsConstructor()) return NoChange();
CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
if (is_builtin && Builtins::HasCppImplementation(builtin_index) &&
@ -1603,23 +1611,6 @@ Reduction JSTypedLowering::ReduceJSConstruct(Node* node) {
return Changed(node);
}
// Check if {target} is a JSFunction.
if (target_type->Is(Type::Function())) {
// Patch {node} to an indirect call via the ConstructFunction builtin.
Callable callable = CodeFactory::ConstructFunction(isolate());
node->RemoveInput(arity + 1);
node->InsertInput(graph()->zone(), 0,
jsgraph()->HeapConstant(callable.code()));
node->InsertInput(graph()->zone(), 2, new_target);
node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(arity));
node->InsertInput(graph()->zone(), 4, jsgraph()->UndefinedConstant());
NodeProperties::ChangeOp(
node, common()->Call(Linkage::GetStubCallDescriptor(
isolate(), graph()->zone(), callable.descriptor(), 1 + arity,
CallDescriptor::kNeedsFrameState)));
return Changed(node);
}
return NoChange();
}

View File

@ -2625,11 +2625,7 @@ Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfo(
share->set_builtin_id(Builtins::kIllegal);
}
share->set_outer_scope_info(*the_hole_value());
DCHECK(!Builtins::IsLazy(Builtins::kConstructedNonConstructable));
Handle<Code> construct_stub =
is_constructor ? isolate()->builtins()->JSConstructStubGeneric()
: BUILTIN_CODE(isolate(), ConstructedNonConstructable);
share->SetConstructStub(*construct_stub);
share->SetConstructStub(*isolate()->builtins()->JSConstructStubGeneric());
share->set_script(*undefined_value(), SKIP_WRITE_BARRIER);
share->set_debug_info(Smi::kZero, SKIP_WRITE_BARRIER);
share->set_function_identifier(*undefined_value(), SKIP_WRITE_BARRIER);

View File

@ -488,6 +488,19 @@ void MacroAssembler::AssertFixedArray(Register object) {
}
}
void MacroAssembler::AssertConstructor(Register object) {
if (emit_debug_code()) {
test(object, Immediate(kSmiTagMask));
Check(not_equal, AbortReason::kOperandIsASmiAndNotAConstructor);
Push(object);
mov(object, FieldOperand(object, HeapObject::kMapOffset));
test_b(FieldOperand(object, Map::kBitFieldOffset),
Immediate(Map::IsConstructorBit::kMask));
Pop(object);
Check(not_zero, AbortReason::kOperandIsNotAConstructor);
}
}
void MacroAssembler::AssertFunction(Register object) {
if (emit_debug_code()) {
test(object, Immediate(kSmiTagMask));

View File

@ -536,6 +536,9 @@ class MacroAssembler : public TurboAssembler {
// Abort execution if argument is not a JSFunction, enabled via --debug-code.
void AssertFunction(Register object);
// Abort execution if argument is not a Constructor, enabled via --debug-code.
void AssertConstructor(Register object);
// Abort execution if argument is not a JSBoundFunction,
// enabled via --debug-code.
void AssertBoundFunction(Register object);

View File

@ -4809,6 +4809,20 @@ void MacroAssembler::AssertFixedArray(Register object) {
}
}
void MacroAssembler::AssertConstructor(Register object) {
if (emit_debug_code()) {
STATIC_ASSERT(kSmiTag == 0);
SmiTst(object, t8);
Check(ne, AbortReason::kOperandIsASmiAndNotAConstructor, t8,
Operand(zero_reg));
lw(t8, FieldMemOperand(object, HeapObject::kMapOffset));
lbu(t8, FieldMemOperand(t8, Map::kBitFieldOffset));
And(t8, t8, Operand(Map::IsConstructorBit::kMask));
Check(ne, AbortReason::kOperandIsNotAConstructor, t8, Operand(zero_reg));
}
}
void MacroAssembler::AssertFunction(Register object) {
if (emit_debug_code()) {
STATIC_ASSERT(kSmiTag == 0);

View File

@ -1105,6 +1105,9 @@ const Operand& rt = Operand(zero_reg), BranchDelaySlot bd = PROTECT
// Abort execution if argument is not a FixedArray, enabled via --debug-code.
void AssertFixedArray(Register object);
// Abort execution if argument is not a Constructor, enabled via --debug-code.
void AssertConstructor(Register object);
// Abort execution if argument is not a JSFunction, enabled via --debug-code.
void AssertFunction(Register object);

View File

@ -5147,6 +5147,20 @@ void MacroAssembler::AssertFixedArray(Register object) {
}
}
void MacroAssembler::AssertConstructor(Register object) {
if (emit_debug_code()) {
STATIC_ASSERT(kSmiTag == 0);
SmiTst(object, t8);
Check(ne, AbortReason::kOperandIsASmiAndNotAConstructor, t8,
Operand(zero_reg));
ld(t8, FieldMemOperand(object, HeapObject::kMapOffset));
Lbu(t8, FieldMemOperand(t8, Map::kBitFieldOffset));
And(t8, t8, Operand(Map::IsConstructorBit::kMask));
Check(ne, AbortReason::kOperandIsNotAConstructor, t8, Operand(zero_reg));
}
}
void MacroAssembler::AssertFunction(Register object) {
if (emit_debug_code()) {
STATIC_ASSERT(kSmiTag == 0);

View File

@ -1197,6 +1197,9 @@ const Operand& rt = Operand(zero_reg), BranchDelaySlot bd = PROTECT
// Abort execution if argument is not a FixedArray, enabled via --debug-code.
void AssertFixedArray(Register object);
// Abort execution if argument is not a Constructor, enabled via --debug-code.
void AssertConstructor(Register object);
// Abort execution if argument is not a JSFunction, enabled via --debug-code.
void AssertFunction(Register object);

View File

@ -13807,10 +13807,8 @@ void SharedFunctionInfo::InitFromFunctionLiteral(
// shared_info->set_kind(lit->kind());
// FunctionKind must have already been set.
DCHECK(lit->kind() == shared_info->kind());
if (!IsConstructable(lit->kind())) {
shared_info->SetConstructStub(
*BUILTIN_CODE(shared_info->GetIsolate(), ConstructedNonConstructable));
}
DCHECK_EQ(*shared_info->GetIsolate()->builtins()->JSConstructStubGeneric(),
shared_info->construct_stub());
shared_info->set_needs_home_object(lit->scope()->NeedsHomeObject());
shared_info->set_function_literal_id(lit->function_literal_id());
DCHECK_IMPLIES(lit->requires_instance_fields_initializer(),

View File

@ -1835,6 +1835,18 @@ void TurboAssembler::AssertZeroExtended(Register int32_register) {
}
}
void MacroAssembler::AssertConstructor(Register object) {
if (emit_debug_code()) {
testb(object, Immediate(kSmiTagMask));
Check(not_equal, AbortReason::kOperandIsASmiAndNotAConstructor);
Push(object);
movq(object, FieldOperand(object, HeapObject::kMapOffset));
testb(FieldOperand(object, Map::kBitFieldOffset),
Immediate(Map::IsConstructorBit::kMask));
Pop(object);
Check(not_zero, AbortReason::kOperandIsNotAConstructor);
}
}
void MacroAssembler::AssertFunction(Register object) {
if (emit_debug_code()) {

View File

@ -816,6 +816,9 @@ class MacroAssembler : public TurboAssembler {
// Abort execution if argument is not a FixedArray, enabled via --debug-code.
void AssertFixedArray(Register object);
// Abort execution if argument is not a Constructor, enabled via --debug-code.
void AssertConstructor(Register object);
// Abort execution if argument is not a JSFunction, enabled via --debug-code.
void AssertFunction(Register object);