Commit 1df203a2 authored by Jakob Gruber's avatar Jakob Gruber Committed by Commit Bot

[ia32,root] Extend support for root-relative accesses

This adds root-relative access in a couple of spots (e.g.: LoadRoot,
CompareRoot, PushRoot, Push, Move, etc.). Some methods now dispatch
based on whether the given Immediate is an embedded object.

ShouldGenerateIsolateIndependentCode() was added as a porting crutch:
it forces isolate-independent code for builtins even though the
builtin is not in the Builtins::IsIsolateIndependent() whitelist. This
allows us to easily figure out which builtins can be white-listed with
--print-embedded-builtin-candidates.

Newly isolate-independent builtins are now whitelisted.

Drive-by: Remove dead CompareRoot and JumpIfRoot helpers.

Bug: v8:6666
Change-Id: I6b5f6f71b90ac22e7e15482af0617b0ca1c319da
Reviewed-on: https://chromium-review.googlesource.com/c/1280665
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarSigurd Schneider <sigurds@chromium.org>
Cr-Commit-Position: refs/heads/master@{#56673}
parent 08b8e0ff
...@@ -351,14 +351,30 @@ bool Builtins::IsIsolateIndependent(int index) { ...@@ -351,14 +351,30 @@ bool Builtins::IsIsolateIndependent(int index) {
// ia32 is a work-in-progress. This will let us make builtins // ia32 is a work-in-progress. This will let us make builtins
// isolate-independent one-by-one. // isolate-independent one-by-one.
switch (index) { switch (index) {
case kAsyncFunctionLazyDeoptContinuation:
case kContinueToCodeStubBuiltin: case kContinueToCodeStubBuiltin:
case kContinueToCodeStubBuiltinWithResult: case kContinueToCodeStubBuiltinWithResult:
case kContinueToJavaScriptBuiltin: case kContinueToJavaScriptBuiltin:
case kContinueToJavaScriptBuiltinWithResult: case kContinueToJavaScriptBuiltinWithResult:
case kDoubleToI:
case kMathPowInternal:
case kRecordWrite:
case kThrowWasmTrapDivByZero:
case kThrowWasmTrapDivUnrepresentable:
case kThrowWasmTrapFloatUnrepresentable:
case kThrowWasmTrapFuncInvalid:
case kThrowWasmTrapFuncSigMismatch:
case kThrowWasmTrapMemOutOfBounds:
case kThrowWasmTrapRemByZero:
case kThrowWasmTrapUnalignedAccess:
case kThrowWasmTrapUnreachable:
case kWasmAllocateHeapNumber: case kWasmAllocateHeapNumber:
case kWasmCallJavaScript: case kWasmCallJavaScript:
case kWasmCompileLazy:
case kWasmGrowMemory:
case kWasmStackGuard:
case kWasmThrow:
case kWasmToNumber: case kWasmToNumber:
case kDoubleToI:
return true; return true;
default: default:
return false; return false;
......
...@@ -23,8 +23,8 @@ namespace internal { ...@@ -23,8 +23,8 @@ namespace internal {
void Builtins::Generate_Adaptor(MacroAssembler* masm, Address address, void Builtins::Generate_Adaptor(MacroAssembler* masm, Address address,
ExitFrameType exit_frame_type) { ExitFrameType exit_frame_type) {
Assembler::SupportsRootRegisterScope supports_root_register(masm); Assembler::SupportsRootRegisterScope supports_root_register(masm);
__ mov(kJavaScriptCallExtraArg1Register, __ Move(kJavaScriptCallExtraArg1Register,
Immediate(ExternalReference::Create(address))); Immediate(ExternalReference::Create(address)));
if (exit_frame_type == BUILTIN_EXIT) { if (exit_frame_type == BUILTIN_EXIT) {
__ Jump(BUILTIN_CODE(masm->isolate(), AdaptorWithBuiltinExitFrame), __ Jump(BUILTIN_CODE(masm->isolate(), AdaptorWithBuiltinExitFrame),
RelocInfo::CODE_TARGET); RelocInfo::CODE_TARGET);
......
...@@ -597,7 +597,7 @@ void CodeGenerator::AssembleTailCallBeforeGap(Instruction* instr, ...@@ -597,7 +597,7 @@ void CodeGenerator::AssembleTailCallBeforeGap(Instruction* instr,
LocationOperand source_location(LocationOperand::cast(source)); LocationOperand source_location(LocationOperand::cast(source));
__ push(source_location.GetRegister()); __ push(source_location.GetRegister());
} else if (source.IsImmediate()) { } else if (source.IsImmediate()) {
__ push(Immediate(ImmediateOperand::cast(source).inline_value())); __ Push(Immediate(ImmediateOperand::cast(source).inline_value()));
} else { } else {
// Pushes of non-scalar data types is not supported. // Pushes of non-scalar data types is not supported.
UNIMPLEMENTED(); UNIMPLEMENTED();
...@@ -4474,11 +4474,7 @@ void CodeGenerator::AssembleMove(InstructionOperand* source, ...@@ -4474,11 +4474,7 @@ void CodeGenerator::AssembleMove(InstructionOperand* source,
Constant src = g.ToConstant(source); Constant src = g.ToConstant(source);
Operand dst = g.ToOperand(destination); Operand dst = g.ToOperand(destination);
if (destination->IsStackSlot()) { if (destination->IsStackSlot()) {
if (src.type() == Constant::kHeapObject) { __ Move(dst, g.ToImmediate(source));
__ mov(dst, src.ToHeapObject());
} else {
__ Move(dst, g.ToImmediate(source));
}
} else { } else {
DCHECK(destination->IsFPStackSlot()); DCHECK(destination->IsFPStackSlot());
if (src.type() == Constant::kFloat32) { if (src.type() == Constant::kFloat32) {
......
...@@ -246,6 +246,14 @@ class Immediate { ...@@ -246,6 +246,14 @@ class Immediate {
return value_.immediate; return value_.immediate;
} }
bool is_embedded_object() const {
return !is_heap_object_request() && rmode() == RelocInfo::EMBEDDED_OBJECT;
}
Handle<HeapObject> embedded_object() const {
return Handle<HeapObject>(bit_cast<HeapObject**>(immediate()));
}
bool is_external_reference() const { bool is_external_reference() const {
return rmode() == RelocInfo::EXTERNAL_REFERENCE; return rmode() == RelocInfo::EXTERNAL_REFERENCE;
} }
......
...@@ -45,6 +45,13 @@ MacroAssembler::MacroAssembler(Isolate* isolate, ...@@ -45,6 +45,13 @@ MacroAssembler::MacroAssembler(Isolate* isolate,
set_root_array_available(FLAG_embedded_builtins); set_root_array_available(FLAG_embedded_builtins);
} }
bool TurboAssembler::ShouldGenerateIsolateIndependentCode() {
// TODO(v8:6666): Remove once embedded builtins are fully supported.
// All callsites should use options().isolate_independent_code instead.
// Until then, this will help transition builtins one-by-one.
return isolate() != nullptr && isolate()->ShouldLoadConstantsFromRootList();
}
void TurboAssembler::InitializeRootRegister() { void TurboAssembler::InitializeRootRegister() {
// TODO(v8:6666): Initialize unconditionally once poisoning support has been // TODO(v8:6666): Initialize unconditionally once poisoning support has been
// removed. // removed.
...@@ -73,8 +80,13 @@ void TurboAssembler::VerifyRootRegister() { ...@@ -73,8 +80,13 @@ void TurboAssembler::VerifyRootRegister() {
} }
void TurboAssembler::LoadRoot(Register destination, RootIndex index) { void TurboAssembler::LoadRoot(Register destination, RootIndex index) {
// TODO(jgruber, v8:6666): Support loads through the root register once it #ifdef V8_EMBEDDED_BUILTINS
// exists. if (root_array_available()) {
Assembler::AllowExplicitEbxAccessScope read_only_access(this);
mov(destination, Operand(kRootRegister, RootRegisterOffset(index)));
return;
}
#endif // V8_EMBEDDED_BUILTINS
if (RootsTable::IsImmortalImmovable(index)) { if (RootsTable::IsImmortalImmovable(index)) {
Handle<Object> object = isolate()->root_handle(index); Handle<Object> object = isolate()->root_handle(index);
if (object->IsSmi()) { if (object->IsSmi()) {
...@@ -96,6 +108,12 @@ void TurboAssembler::LoadRoot(Register destination, RootIndex index) { ...@@ -96,6 +108,12 @@ void TurboAssembler::LoadRoot(Register destination, RootIndex index) {
void MacroAssembler::CompareRoot(Register with, Register scratch, void MacroAssembler::CompareRoot(Register with, Register scratch,
RootIndex index) { RootIndex index) {
#ifdef V8_EMBEDDED_BUILTINS
if (root_array_available()) {
CompareRoot(with, index);
return;
}
#endif // V8_EMBEDDED_BUILTINS
ExternalReference roots_array_start = ExternalReference roots_array_start =
ExternalReference::roots_array_start(isolate()); ExternalReference::roots_array_start(isolate());
mov(scratch, Immediate(static_cast<int>(index))); mov(scratch, Immediate(static_cast<int>(index)));
...@@ -104,16 +122,13 @@ void MacroAssembler::CompareRoot(Register with, Register scratch, ...@@ -104,16 +122,13 @@ void MacroAssembler::CompareRoot(Register with, Register scratch,
} }
void MacroAssembler::CompareRoot(Register with, RootIndex index) { void MacroAssembler::CompareRoot(Register with, RootIndex index) {
DCHECK(RootsTable::IsImmortalImmovable(index)); #ifdef V8_EMBEDDED_BUILTINS
Handle<Object> object = isolate()->root_handle(index); if (root_array_available()) {
if (object->IsHeapObject()) { Assembler::AllowExplicitEbxAccessScope read_only_access(this);
cmp(with, Handle<HeapObject>::cast(object)); cmp(with, Operand(kRootRegister, RootRegisterOffset(index)));
} else { return;
cmp(with, Immediate(Smi::cast(*object)));
} }
} #endif // V8_EMBEDDED_BUILTINS
void MacroAssembler::CompareRoot(Operand with, RootIndex index) {
DCHECK(RootsTable::IsImmortalImmovable(index)); DCHECK(RootsTable::IsImmortalImmovable(index));
Handle<Object> object = isolate()->root_handle(index); Handle<Object> object = isolate()->root_handle(index);
if (object->IsHeapObject()) { if (object->IsHeapObject()) {
...@@ -124,6 +139,15 @@ void MacroAssembler::CompareRoot(Operand with, RootIndex index) { ...@@ -124,6 +139,15 @@ void MacroAssembler::CompareRoot(Operand with, RootIndex index) {
} }
void MacroAssembler::PushRoot(RootIndex index) { void MacroAssembler::PushRoot(RootIndex index) {
#ifdef V8_EMBEDDED_BUILTINS
if (root_array_available()) {
DCHECK(RootsTable::IsImmortalImmovable(index));
Assembler::AllowExplicitEbxAccessScope read_only_access(this);
push(Operand(kRootRegister, RootRegisterOffset(index)));
return;
}
#endif // V8_EMBEDDED_BUILTINS
// TODO(v8:6666): Add a scratch register or remove all uses.
DCHECK(RootsTable::IsImmortalImmovable(index)); DCHECK(RootsTable::IsImmortalImmovable(index));
Handle<Object> object = isolate()->root_handle(index); Handle<Object> object = isolate()->root_handle(index);
if (object->IsHeapObject()) { if (object->IsHeapObject()) {
...@@ -135,13 +159,9 @@ void MacroAssembler::PushRoot(RootIndex index) { ...@@ -135,13 +159,9 @@ void MacroAssembler::PushRoot(RootIndex index) {
Operand TurboAssembler::ExternalReferenceAsOperand(ExternalReference reference, Operand TurboAssembler::ExternalReferenceAsOperand(ExternalReference reference,
Register scratch) { Register scratch) {
// TODO(jgruber): Add support for enable_root_array_delta_access.
Assembler::AllowExplicitEbxAccessScope read_only_access(this); Assembler::AllowExplicitEbxAccessScope read_only_access(this);
if (root_array_available_ && options().enable_root_array_delta_access) { if (root_array_available_ && ShouldGenerateIsolateIndependentCode()) {
intptr_t offset =
RootRegisterOffsetForExternalReference(isolate(), reference);
return Operand(kRootRegister, offset);
}
if (root_array_available_ && options().isolate_independent_code) {
if (IsAddressableThroughRootRegister(isolate(), reference)) { if (IsAddressableThroughRootRegister(isolate(), reference)) {
// Some external references can be efficiently loaded as an offset from // Some external references can be efficiently loaded as an offset from
// kRootRegister. // kRootRegister.
...@@ -167,12 +187,48 @@ Operand TurboAssembler::ExternalReferenceAsOperand(ExternalReference reference, ...@@ -167,12 +187,48 @@ Operand TurboAssembler::ExternalReferenceAsOperand(ExternalReference reference,
return Operand(scratch, 0); return Operand(scratch, 0);
} }
// TODO(v8:6666): If possible, refactor into a platform-independent function in
// TurboAssembler.
Operand TurboAssembler::HeapObjectAsOperand(Handle<HeapObject> object) {
DCHECK(FLAG_embedded_builtins);
DCHECK(root_array_available());
Assembler::AllowExplicitEbxAccessScope read_only_access(this);
int builtin_index;
RootIndex root_index;
if (isolate()->roots_table().IsRootHandle(object, &root_index)) {
return Operand(kRootRegister, RootRegisterOffset(root_index));
} else if (isolate()->builtins()->IsBuiltinHandle(object, &builtin_index)) {
return Operand(kRootRegister,
RootRegisterOffsetForBuiltinIndex(builtin_index));
} else if (object.is_identical_to(code_object_) &&
Builtins::IsBuiltinId(maybe_builtin_index_)) {
return Operand(kRootRegister,
RootRegisterOffsetForBuiltinIndex(maybe_builtin_index_));
} else {
// Objects in the constants table need an additional indirection, which
// cannot be represented as a single Operand.
UNREACHABLE();
}
}
// TODO(v8:6666): If possible, refactor into a platform-independent function in
// TurboAssembler.
Operand TurboAssembler::ExternalReferenceAddressAsOperand(
ExternalReference reference) {
DCHECK(FLAG_embedded_builtins);
DCHECK(root_array_available());
DCHECK(ShouldGenerateIsolateIndependentCode());
Assembler::AllowExplicitEbxAccessScope read_only_access(this);
return Operand(kRootRegister,
RootRegisterOffsetForExternalReference(isolate(), reference));
}
void TurboAssembler::LoadFromConstantsTable(Register destination, void TurboAssembler::LoadFromConstantsTable(Register destination,
int constant_index) { int constant_index) {
DCHECK(!is_ebx_addressable_); DCHECK(!is_ebx_addressable_);
DCHECK(RootsTable::IsImmortalImmovable(RootIndex::kBuiltinsConstantsTable)); DCHECK(RootsTable::IsImmortalImmovable(RootIndex::kBuiltinsConstantsTable));
// TODO(jgruber): LoadRoot should be a register-relative load once we have
// the kRootRegister.
LoadRoot(destination, RootIndex::kBuiltinsConstantsTable); LoadRoot(destination, RootIndex::kBuiltinsConstantsTable);
mov(destination, mov(destination,
FieldOperand(destination, FieldOperand(destination,
...@@ -183,24 +239,27 @@ void TurboAssembler::LoadRootRegisterOffset(Register destination, ...@@ -183,24 +239,27 @@ void TurboAssembler::LoadRootRegisterOffset(Register destination,
intptr_t offset) { intptr_t offset) {
DCHECK(!is_ebx_addressable_); DCHECK(!is_ebx_addressable_);
DCHECK(is_int32(offset)); DCHECK(is_int32(offset));
// TODO(jgruber): Register-relative load once kRootRegister exists. DCHECK(root_array_available());
mov(destination, Immediate(ExternalReference::roots_array_start(isolate()))); Assembler::AllowExplicitEbxAccessScope read_only_access(this);
if (offset != 0) { if (offset == 0) {
add(destination, Immediate(offset)); mov(destination, kRootRegister);
} else {
lea(destination, Operand(kRootRegister, static_cast<int32_t>(offset)));
} }
} }
void TurboAssembler::LoadRootRelative(Register destination, int32_t offset) { void TurboAssembler::LoadRootRelative(Register destination, int32_t offset) {
DCHECK(!is_ebx_addressable_); DCHECK(!is_ebx_addressable_);
// TODO(jgruber): Register-relative load once kRootRegister exists. DCHECK(root_array_available());
LoadRootRegisterOffset(destination, offset); Assembler::AllowExplicitEbxAccessScope read_only_access(this);
mov(destination, Operand(destination, 0)); mov(destination, Operand(kRootRegister, offset));
} }
void TurboAssembler::LoadAddress(Register destination, void TurboAssembler::LoadAddress(Register destination,
ExternalReference source) { ExternalReference source) {
// TODO(jgruber): Add support for enable_root_array_delta_access.
if (FLAG_embedded_builtins) { if (FLAG_embedded_builtins) {
if (root_array_available_ && options().isolate_independent_code) { if (root_array_available_ && ShouldGenerateIsolateIndependentCode()) {
IndirectLoadExternalReference(destination, source); IndirectLoadExternalReference(destination, source);
return; return;
} }
...@@ -1288,6 +1347,20 @@ void TurboAssembler::Ret(int bytes_dropped, Register scratch) { ...@@ -1288,6 +1347,20 @@ void TurboAssembler::Ret(int bytes_dropped, Register scratch) {
} }
} }
void TurboAssembler::Push(Immediate value) {
#ifdef V8_EMBEDDED_BUILTINS
if (root_array_available_ && ShouldGenerateIsolateIndependentCode()) {
if (value.is_embedded_object()) {
Push(HeapObjectAsOperand(value.embedded_object()));
return;
} else if (value.is_external_reference()) {
Push(ExternalReferenceAddressAsOperand(value.external_reference()));
return;
}
}
#endif // V8_EMBEDDED_BUILTINS
push(value);
}
void MacroAssembler::Drop(int stack_elements) { void MacroAssembler::Drop(int stack_elements) {
if (stack_elements > 0) { if (stack_elements > 0) {
...@@ -1311,10 +1384,29 @@ void TurboAssembler::Move(Register dst, const Immediate& src) { ...@@ -1311,10 +1384,29 @@ void TurboAssembler::Move(Register dst, const Immediate& src) {
} }
} }
void TurboAssembler::Move(Operand dst, const Immediate& src) { mov(dst, src); } void TurboAssembler::Move(Operand dst, const Immediate& src) {
#ifdef V8_EMBEDDED_BUILTINS
// Since there's no scratch register available, take a detour through the
// stack.
if (root_array_available_ && ShouldGenerateIsolateIndependentCode()) {
if (src.is_embedded_object() || src.is_external_reference() ||
src.is_heap_object_request()) {
Assembler::AllowExplicitEbxAccessScope read_only_access(this);
Push(src);
pop(dst);
return;
}
}
#endif // V8_EMBEDDED_BUILTINS
if (src.is_embedded_object()) {
mov(dst, src.embedded_object());
} else {
mov(dst, src);
}
}
void TurboAssembler::Move(Register dst, Handle<HeapObject> src) { void TurboAssembler::Move(Register dst, Handle<HeapObject> src) {
if (root_array_available_ && options().isolate_independent_code) { if (root_array_available_ && ShouldGenerateIsolateIndependentCode()) {
IndirectLoadConstant(dst, src); IndirectLoadConstant(dst, src);
return; return;
} }
...@@ -1753,7 +1845,7 @@ void TurboAssembler::PrepareCallCFunction(int num_arguments, Register scratch) { ...@@ -1753,7 +1845,7 @@ void TurboAssembler::PrepareCallCFunction(int num_arguments, Register scratch) {
void TurboAssembler::CallCFunction(ExternalReference function, void TurboAssembler::CallCFunction(ExternalReference function,
int num_arguments) { int num_arguments) {
// Trashing eax is ok as it will be the return value. // Trashing eax is ok as it will be the return value.
mov(eax, Immediate(function)); Move(eax, Immediate(function));
CallCFunction(eax, num_arguments); CallCFunction(eax, num_arguments);
} }
......
...@@ -226,6 +226,8 @@ class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase { ...@@ -226,6 +226,8 @@ class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase {
// Root register utility functions. // Root register utility functions.
bool ShouldGenerateIsolateIndependentCode();
void InitializeRootRegister(); void InitializeRootRegister();
void VerifyRootRegister(); void VerifyRootRegister();
...@@ -245,6 +247,8 @@ class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase { ...@@ -245,6 +247,8 @@ class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase {
// that is guaranteed not to be clobbered. // that is guaranteed not to be clobbered.
Operand ExternalReferenceAsOperand(ExternalReference reference, Operand ExternalReferenceAsOperand(ExternalReference reference,
Register scratch); Register scratch);
Operand ExternalReferenceAddressAsOperand(ExternalReference reference);
Operand HeapObjectAsOperand(Handle<HeapObject> object);
void LoadAddress(Register destination, ExternalReference source); void LoadAddress(Register destination, ExternalReference source);
...@@ -423,7 +427,7 @@ class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase { ...@@ -423,7 +427,7 @@ class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase {
void Push(Register src) { push(src); } void Push(Register src) { push(src); }
void Push(Operand src) { push(src); } void Push(Operand src) { push(src); }
void Push(Immediate value) { push(value); } void Push(Immediate value);
void Push(Handle<HeapObject> handle) { push(Immediate(handle)); } void Push(Handle<HeapObject> handle) { push(Immediate(handle)); }
void Push(Smi* smi) { Push(Immediate(smi)); } void Push(Smi* smi) { Push(Immediate(smi)); }
...@@ -493,7 +497,6 @@ class MacroAssembler : public TurboAssembler { ...@@ -493,7 +497,6 @@ class MacroAssembler : public TurboAssembler {
// These methods can only be used with constant roots (i.e. non-writable // These methods can only be used with constant roots (i.e. non-writable
// and not in new space). // and not in new space).
void CompareRoot(Register with, RootIndex index); void CompareRoot(Register with, RootIndex index);
void CompareRoot(Operand with, RootIndex index);
void PushRoot(RootIndex index); void PushRoot(RootIndex index);
// Compare the object in a register to a value and jump if they are equal. // Compare the object in a register to a value and jump if they are equal.
...@@ -502,11 +505,6 @@ class MacroAssembler : public TurboAssembler { ...@@ -502,11 +505,6 @@ class MacroAssembler : public TurboAssembler {
CompareRoot(with, index); CompareRoot(with, index);
j(equal, if_equal, if_equal_distance); j(equal, if_equal, if_equal_distance);
} }
void JumpIfRoot(Operand with, RootIndex index, Label* if_equal,
Label::Distance if_equal_distance = Label::kFar) {
CompareRoot(with, index);
j(equal, if_equal, if_equal_distance);
}
// Compare the object in a register to a value and jump if they are not equal. // Compare the object in a register to a value and jump if they are not equal.
void JumpIfNotRoot(Register with, RootIndex index, Label* if_not_equal, void JumpIfNotRoot(Register with, RootIndex index, Label* if_not_equal,
...@@ -514,11 +512,6 @@ class MacroAssembler : public TurboAssembler { ...@@ -514,11 +512,6 @@ class MacroAssembler : public TurboAssembler {
CompareRoot(with, index); CompareRoot(with, index);
j(not_equal, if_not_equal, if_not_equal_distance); j(not_equal, if_not_equal, if_not_equal_distance);
} }
void JumpIfNotRoot(Operand with, RootIndex index, Label* if_not_equal,
Label::Distance if_not_equal_distance = Label::kFar) {
CompareRoot(with, index);
j(not_equal, if_not_equal, if_not_equal_distance);
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// GC Support // GC Support
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment