[objects] Free one bit in the SharedFunctionInfo::flags.

We'll need one bit in the SharedFunctionInfo::flags to record whether
it's safe to skip arguments adaptor frames (for v8:8895), so this
just removes the SharedFunctionInfo::IsDerivedConstructorBit which is
redundant, since the same information is already available in the
SharedFunctionInfo::FunctionKindBits, and most places in the code
use that already, with the exception of the JSConstructStubGeneric
builtin.

This changes the JSConstructStubGeneric builtin to just check the
function kind instead of testing the explicit bit, which also makes
this more consistent. It seems like there's not much overhead to
that, doing an additional bitmasking plus two comparisons instead
of one. This shouldn't really matter since invocation and execution
of the constructors is going to dominate and optimized code inlines
all of this anyways. If this turns out to affect performance, we
can still look into encoding the FunctionKindBits more cleverly.

Drive-by-fix: Move the FunctionKindBits first in the flags to avoid
the shift when accessing the function kind. This seems logic, since
for the actual boolean bit fields it doesn't matter where they are
in the flags, whereas for the function kind this saves one shift.

Bug: v8:8834, v8:8895
Change-Id: I184a8f5cc5c140bdc272cf9a5ad546093c457306
Reviewed-on: https://chromium-review.googlesource.com/c/1482915
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#59821}
This commit is contained in:
Benedikt Meurer 2019-02-25 11:41:54 +01:00 committed by Commit Bot
parent 83e88b338d
commit 591408cba7
14 changed files with 113 additions and 33 deletions

View File

@ -1728,6 +1728,20 @@ void MacroAssembler::CompareRoot(Register obj, RootIndex index) {
cmp(obj, scratch);
}
void MacroAssembler::JumpIfIsInRange(Register value, unsigned lower_limit,
unsigned higher_limit,
Label* on_in_range) {
if (lower_limit != 0) {
UseScratchRegisterScope temps(this);
Register scratch = temps.Acquire();
sub(scratch, value, Operand(lower_limit));
cmp(scratch, Operand(higher_limit - lower_limit));
} else {
cmp(value, Operand(higher_limit));
}
b(ls, on_in_range);
}
void MacroAssembler::TryDoubleToInt32Exact(Register result,
DwVfpRegister double_input,
LowDwVfpRegister double_scratch) {

View File

@ -682,6 +682,11 @@ class V8_EXPORT_PRIVATE MacroAssembler : public TurboAssembler {
b(ne, if_not_equal);
}
// Checks if value is in range [lower_limit, higher_limit] using a single
// comparison.
void JumpIfIsInRange(Register value, unsigned lower_limit,
unsigned higher_limit, Label* on_in_range);
// Try to convert a double to a signed 32-bit integer.
// Z flag set to one and result assigned if the conversion is exact.
void TryDoubleToInt32Exact(Register result,

View File

@ -2755,6 +2755,22 @@ void MacroAssembler::JumpIfNotRoot(const Register& obj, RootIndex index,
B(ne, if_not_equal);
}
void MacroAssembler::JumpIfIsInRange(const Register& value,
unsigned lower_limit,
unsigned higher_limit,
Label* on_in_range) {
if (lower_limit != 0) {
UseScratchRegisterScope temps(this);
Register scratch = temps.AcquireW();
Sub(scratch, value, Operand(lower_limit));
CompareAndBranch(scratch, Operand(higher_limit - lower_limit), ls,
on_in_range);
} else {
CompareAndBranch(value, Operand(higher_limit - lower_limit), ls,
on_in_range);
}
}
void TurboAssembler::LoadTaggedPointerField(const Register& destination,
const MemOperand& field_operand) {
#ifdef V8_COMPRESS_POINTERS

View File

@ -1837,6 +1837,11 @@ class V8_EXPORT_PRIVATE MacroAssembler : public TurboAssembler {
// Compare the object in a register to a value and jump if they are not equal.
void JumpIfNotRoot(const Register& obj, RootIndex index, Label* if_not_equal);
// Checks if value is in range [lower_limit, higher_limit] using a single
// comparison.
void JumpIfIsInRange(const Register& value, unsigned lower_limit,
unsigned higher_limit, Label* on_in_range);
// Compare the contents of a register with an operand, and branch to true,
// false or fall through, depending on condition.
void CompareAndSplit(const Register& lhs,

View File

@ -219,8 +219,9 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
__ ldr(r4, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
__ ldr(r4, FieldMemOperand(r4, SharedFunctionInfo::kFlagsOffset));
__ tst(r4, Operand(SharedFunctionInfo::IsDerivedConstructorBit::kMask));
__ b(ne, &not_create_implicit_receiver);
__ DecodeField<SharedFunctionInfo::FunctionKindBits>(r4);
__ JumpIfIsInRange(r4, kDefaultDerivedConstructor, kDerivedConstructor,
&not_create_implicit_receiver);
// If not derived class constructor: Allocate the new receiver object.
__ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1,

View File

@ -278,9 +278,9 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
__ LoadTaggedPointerField(
x4, FieldMemOperand(x1, JSFunction::kSharedFunctionInfoOffset));
__ Ldr(w4, FieldMemOperand(x4, SharedFunctionInfo::kFlagsOffset));
__ TestAndBranchIfAnySet(w4,
SharedFunctionInfo::IsDerivedConstructorBit::kMask,
&not_create_implicit_receiver);
__ DecodeField<SharedFunctionInfo::FunctionKindBits>(w4);
__ JumpIfIsInRange(w4, kDefaultDerivedConstructor, kDerivedConstructor,
&not_create_implicit_receiver);
// If not derived class constructor: Allocate the new receiver object.
__ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1,

View File

@ -206,9 +206,10 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
// -----------------------------------
__ mov(eax, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
__ test(FieldOperand(eax, SharedFunctionInfo::kFlagsOffset),
Immediate(SharedFunctionInfo::IsDerivedConstructorBit::kMask));
__ j(not_zero, &not_create_implicit_receiver);
__ mov(eax, FieldOperand(eax, SharedFunctionInfo::kFlagsOffset));
__ DecodeField<SharedFunctionInfo::FunctionKindBits>(eax);
__ JumpIfIsInRange(eax, kDefaultDerivedConstructor, kDerivedConstructor,
ecx, &not_create_implicit_receiver, Label::kNear);
// If not derived class constructor: Allocate the new receiver object.
__ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1,

View File

@ -198,9 +198,10 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
__ LoadTaggedPointerField(
rbx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
__ testl(FieldOperand(rbx, SharedFunctionInfo::kFlagsOffset),
Immediate(SharedFunctionInfo::IsDerivedConstructorBit::kMask));
__ j(not_zero, &not_create_implicit_receiver, Label::kNear);
__ movl(rbx, FieldOperand(rbx, SharedFunctionInfo::kFlagsOffset));
__ DecodeField<SharedFunctionInfo::FunctionKindBits>(rbx);
__ JumpIfIsInRange(rbx, kDefaultDerivedConstructor, kDerivedConstructor,
&not_create_implicit_receiver, Label::kNear);
// If not derived class constructor: Allocate the new receiver object.
__ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1);

View File

@ -130,6 +130,19 @@ void MacroAssembler::PushRoot(RootIndex index) {
}
}
void MacroAssembler::JumpIfIsInRange(Register value, unsigned lower_limit,
unsigned higher_limit, Register scratch,
Label* on_in_range,
Label::Distance near_jump) {
if (lower_limit != 0) {
lea(scratch, Operand(value, 0u - lower_limit));
cmp(scratch, Immediate(higher_limit - lower_limit));
} else {
cmp(value, Immediate(higher_limit));
}
j(below_equal, on_in_range, near_jump);
}
Operand TurboAssembler::ExternalReferenceAsOperand(ExternalReference reference,
Register scratch) {
// TODO(jgruber): Add support for enable_root_array_delta_access.

View File

@ -460,6 +460,13 @@ class V8_EXPORT_PRIVATE MacroAssembler : public TurboAssembler {
j(not_equal, if_not_equal, if_not_equal_distance);
}
// Checks if value is in range [lower_limit, higher_limit] using a single
// comparison.
void JumpIfIsInRange(Register value, unsigned lower_limit,
unsigned higher_limit, Register scratch,
Label* on_in_range,
Label::Distance near_jump = Label::kFar);
// ---------------------------------------------------------------------------
// GC Support
// Notify the garbage collector that we wrote a pointer into an object.

View File

@ -261,7 +261,6 @@ void SharedFunctionInfo::set_kind(FunctionKind kind) {
int hints = flags();
hints = FunctionKindBits::update(hints, kind);
hints = IsClassConstructorBit::update(hints, IsClassConstructor(kind));
hints = IsDerivedConstructorBit::update(hints, IsDerivedConstructor(kind));
set_flags(hints);
UpdateFunctionMapIndex();
}

View File

@ -656,27 +656,27 @@ class SharedFunctionInfo : public HeapObject {
class BodyDescriptor;
// Bit positions in |flags|.
#define FLAGS_BIT_FIELDS(V, _) \
V(IsNativeBit, bool, 1, _) \
V(IsStrictBit, bool, 1, _) \
V(IsWrappedBit, bool, 1, _) \
V(IsClassConstructorBit, bool, 1, _) \
V(IsDerivedConstructorBit, bool, 1, _) \
V(FunctionKindBits, FunctionKind, 5, _) \
V(HasDuplicateParametersBit, bool, 1, _) \
V(AllowLazyCompilationBit, bool, 1, _) \
V(NeedsHomeObjectBit, bool, 1, _) \
V(IsDeclarationBit, bool, 1, _) \
V(IsAsmWasmBrokenBit, bool, 1, _) \
V(FunctionMapIndexBits, int, 5, _) \
V(DisabledOptimizationReasonBits, BailoutReason, 4, _) \
V(RequiresInstanceMembersInitializer, bool, 1, _) \
V(ConstructAsBuiltinBit, bool, 1, _) \
V(IsAnonymousExpressionBit, bool, 1, _) \
V(NameShouldPrintAsAnonymousBit, bool, 1, _) \
V(HasReportedBinaryCoverageBit, bool, 1, _) \
V(IsNamedExpressionBit, bool, 1, _) \
V(IsTopLevelBit, bool, 1, _) \
#define FLAGS_BIT_FIELDS(V, _) \
/* Have FunctionKind first to make it cheaper to access */ \
V(FunctionKindBits, FunctionKind, 5, _) \
V(IsNativeBit, bool, 1, _) \
V(IsStrictBit, bool, 1, _) \
V(IsWrappedBit, bool, 1, _) \
V(IsClassConstructorBit, bool, 1, _) \
V(HasDuplicateParametersBit, bool, 1, _) \
V(AllowLazyCompilationBit, bool, 1, _) \
V(NeedsHomeObjectBit, bool, 1, _) \
V(IsDeclarationBit, bool, 1, _) \
V(IsAsmWasmBrokenBit, bool, 1, _) \
V(FunctionMapIndexBits, int, 5, _) \
V(DisabledOptimizationReasonBits, BailoutReason, 4, _) \
V(RequiresInstanceMembersInitializer, bool, 1, _) \
V(ConstructAsBuiltinBit, bool, 1, _) \
V(IsAnonymousExpressionBit, bool, 1, _) \
V(NameShouldPrintAsAnonymousBit, bool, 1, _) \
V(HasReportedBinaryCoverageBit, bool, 1, _) \
V(IsNamedExpressionBit, bool, 1, _) \
V(IsTopLevelBit, bool, 1, _) \
V(IsOneshotIIFEBit, bool, 1, _)
DEFINE_BIT_FIELDS(FLAGS_BIT_FIELDS)
#undef FLAGS_BIT_FIELDS

View File

@ -1390,6 +1390,18 @@ void MacroAssembler::Cmp(Operand dst, Handle<Object> source) {
}
}
void MacroAssembler::JumpIfIsInRange(Register value, unsigned lower_limit,
unsigned higher_limit, Label* on_in_range,
Label::Distance near_jump) {
if (lower_limit != 0) {
leal(kScratchRegister, Operand(value, 0u - lower_limit));
cmpl(kScratchRegister, Immediate(higher_limit - lower_limit));
} else {
cmpl(value, Immediate(higher_limit));
}
j(below_equal, on_in_range, near_jump);
}
void TurboAssembler::Push(Handle<HeapObject> source) {
Move(kScratchRegister, source);
Push(kScratchRegister);

View File

@ -709,6 +709,12 @@ class V8_EXPORT_PRIVATE MacroAssembler : public TurboAssembler {
void Cmp(Register dst, Smi src);
void Cmp(Operand dst, Smi src);
// Checks if value is in range [lower_limit, higher_limit] using a single
// comparison.
void JumpIfIsInRange(Register value, unsigned lower_limit,
unsigned higher_limit, Label* on_in_range,
Label::Distance near_jump = Label::kFar);
// Emit code to discard a non-negative number of pointer-sized elements
// from the stack, clobbering only the rsp register.
void Drop(int stack_elements);