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) {
// ia32 is a work-in-progress. This will let us make builtins
// isolate-independent one-by-one.
switch (index) {
case kAsyncFunctionLazyDeoptContinuation:
case kContinueToCodeStubBuiltin:
case kContinueToCodeStubBuiltinWithResult:
case kContinueToJavaScriptBuiltin:
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 kWasmCallJavaScript:
case kWasmCompileLazy:
case kWasmGrowMemory:
case kWasmStackGuard:
case kWasmThrow:
case kWasmToNumber:
case kDoubleToI:
return true;
default:
return false;
......
......@@ -23,8 +23,8 @@ namespace internal {
void Builtins::Generate_Adaptor(MacroAssembler* masm, Address address,
ExitFrameType exit_frame_type) {
Assembler::SupportsRootRegisterScope supports_root_register(masm);
__ mov(kJavaScriptCallExtraArg1Register,
Immediate(ExternalReference::Create(address)));
__ Move(kJavaScriptCallExtraArg1Register,
Immediate(ExternalReference::Create(address)));
if (exit_frame_type == BUILTIN_EXIT) {
__ Jump(BUILTIN_CODE(masm->isolate(), AdaptorWithBuiltinExitFrame),
RelocInfo::CODE_TARGET);
......
......@@ -597,7 +597,7 @@ void CodeGenerator::AssembleTailCallBeforeGap(Instruction* instr,
LocationOperand source_location(LocationOperand::cast(source));
__ push(source_location.GetRegister());
} else if (source.IsImmediate()) {
__ push(Immediate(ImmediateOperand::cast(source).inline_value()));
__ Push(Immediate(ImmediateOperand::cast(source).inline_value()));
} else {
// Pushes of non-scalar data types is not supported.
UNIMPLEMENTED();
......@@ -4474,11 +4474,7 @@ void CodeGenerator::AssembleMove(InstructionOperand* source,
Constant src = g.ToConstant(source);
Operand dst = g.ToOperand(destination);
if (destination->IsStackSlot()) {
if (src.type() == Constant::kHeapObject) {
__ mov(dst, src.ToHeapObject());
} else {
__ Move(dst, g.ToImmediate(source));
}
__ Move(dst, g.ToImmediate(source));
} else {
DCHECK(destination->IsFPStackSlot());
if (src.type() == Constant::kFloat32) {
......
......@@ -246,6 +246,14 @@ class 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 {
return rmode() == RelocInfo::EXTERNAL_REFERENCE;
}
......
......@@ -45,6 +45,13 @@ MacroAssembler::MacroAssembler(Isolate* isolate,
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() {
// TODO(v8:6666): Initialize unconditionally once poisoning support has been
// removed.
......@@ -73,8 +80,13 @@ void TurboAssembler::VerifyRootRegister() {
}
void TurboAssembler::LoadRoot(Register destination, RootIndex index) {
// TODO(jgruber, v8:6666): Support loads through the root register once it
// exists.
#ifdef V8_EMBEDDED_BUILTINS
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)) {
Handle<Object> object = isolate()->root_handle(index);
if (object->IsSmi()) {
......@@ -96,6 +108,12 @@ void TurboAssembler::LoadRoot(Register destination, RootIndex index) {
void MacroAssembler::CompareRoot(Register with, Register scratch,
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(isolate());
mov(scratch, Immediate(static_cast<int>(index)));
......@@ -104,16 +122,13 @@ void MacroAssembler::CompareRoot(Register with, Register scratch,
}
void MacroAssembler::CompareRoot(Register with, RootIndex index) {
DCHECK(RootsTable::IsImmortalImmovable(index));
Handle<Object> object = isolate()->root_handle(index);
if (object->IsHeapObject()) {
cmp(with, Handle<HeapObject>::cast(object));
} else {
cmp(with, Immediate(Smi::cast(*object)));
#ifdef V8_EMBEDDED_BUILTINS
if (root_array_available()) {
Assembler::AllowExplicitEbxAccessScope read_only_access(this);
cmp(with, Operand(kRootRegister, RootRegisterOffset(index)));
return;
}
}
void MacroAssembler::CompareRoot(Operand with, RootIndex index) {
#endif // V8_EMBEDDED_BUILTINS
DCHECK(RootsTable::IsImmortalImmovable(index));
Handle<Object> object = isolate()->root_handle(index);
if (object->IsHeapObject()) {
......@@ -124,6 +139,15 @@ void MacroAssembler::CompareRoot(Operand with, 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));
Handle<Object> object = isolate()->root_handle(index);
if (object->IsHeapObject()) {
......@@ -135,13 +159,9 @@ void MacroAssembler::PushRoot(RootIndex index) {
Operand TurboAssembler::ExternalReferenceAsOperand(ExternalReference reference,
Register scratch) {
// TODO(jgruber): Add support for enable_root_array_delta_access.
Assembler::AllowExplicitEbxAccessScope read_only_access(this);
if (root_array_available_ && options().enable_root_array_delta_access) {
intptr_t offset =
RootRegisterOffsetForExternalReference(isolate(), reference);
return Operand(kRootRegister, offset);
}
if (root_array_available_ && options().isolate_independent_code) {
if (root_array_available_ && ShouldGenerateIsolateIndependentCode()) {
if (IsAddressableThroughRootRegister(isolate(), reference)) {
// Some external references can be efficiently loaded as an offset from
// kRootRegister.
......@@ -167,12 +187,48 @@ Operand TurboAssembler::ExternalReferenceAsOperand(ExternalReference reference,
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,
int constant_index) {
DCHECK(!is_ebx_addressable_);
DCHECK(RootsTable::IsImmortalImmovable(RootIndex::kBuiltinsConstantsTable));
// TODO(jgruber): LoadRoot should be a register-relative load once we have
// the kRootRegister.
LoadRoot(destination, RootIndex::kBuiltinsConstantsTable);
mov(destination,
FieldOperand(destination,
......@@ -183,24 +239,27 @@ void TurboAssembler::LoadRootRegisterOffset(Register destination,
intptr_t offset) {
DCHECK(!is_ebx_addressable_);
DCHECK(is_int32(offset));
// TODO(jgruber): Register-relative load once kRootRegister exists.
mov(destination, Immediate(ExternalReference::roots_array_start(isolate())));
if (offset != 0) {
add(destination, Immediate(offset));
DCHECK(root_array_available());
Assembler::AllowExplicitEbxAccessScope read_only_access(this);
if (offset == 0) {
mov(destination, kRootRegister);
} else {
lea(destination, Operand(kRootRegister, static_cast<int32_t>(offset)));
}
}
void TurboAssembler::LoadRootRelative(Register destination, int32_t offset) {
DCHECK(!is_ebx_addressable_);
// TODO(jgruber): Register-relative load once kRootRegister exists.
LoadRootRegisterOffset(destination, offset);
mov(destination, Operand(destination, 0));
DCHECK(root_array_available());
Assembler::AllowExplicitEbxAccessScope read_only_access(this);
mov(destination, Operand(kRootRegister, offset));
}
void TurboAssembler::LoadAddress(Register destination,
ExternalReference source) {
// TODO(jgruber): Add support for enable_root_array_delta_access.
if (FLAG_embedded_builtins) {
if (root_array_available_ && options().isolate_independent_code) {
if (root_array_available_ && ShouldGenerateIsolateIndependentCode()) {
IndirectLoadExternalReference(destination, source);
return;
}
......@@ -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) {
if (stack_elements > 0) {
......@@ -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) {
if (root_array_available_ && options().isolate_independent_code) {
if (root_array_available_ && ShouldGenerateIsolateIndependentCode()) {
IndirectLoadConstant(dst, src);
return;
}
......@@ -1753,7 +1845,7 @@ void TurboAssembler::PrepareCallCFunction(int num_arguments, Register scratch) {
void TurboAssembler::CallCFunction(ExternalReference function,
int num_arguments) {
// Trashing eax is ok as it will be the return value.
mov(eax, Immediate(function));
Move(eax, Immediate(function));
CallCFunction(eax, num_arguments);
}
......
......@@ -226,6 +226,8 @@ class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase {
// Root register utility functions.
bool ShouldGenerateIsolateIndependentCode();
void InitializeRootRegister();
void VerifyRootRegister();
......@@ -245,6 +247,8 @@ class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase {
// that is guaranteed not to be clobbered.
Operand ExternalReferenceAsOperand(ExternalReference reference,
Register scratch);
Operand ExternalReferenceAddressAsOperand(ExternalReference reference);
Operand HeapObjectAsOperand(Handle<HeapObject> object);
void LoadAddress(Register destination, ExternalReference source);
......@@ -423,7 +427,7 @@ class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase {
void Push(Register 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(Smi* smi) { Push(Immediate(smi)); }
......@@ -493,7 +497,6 @@ class MacroAssembler : public TurboAssembler {
// These methods can only be used with constant roots (i.e. non-writable
// and not in new space).
void CompareRoot(Register with, RootIndex index);
void CompareRoot(Operand with, RootIndex index);
void PushRoot(RootIndex index);
// Compare the object in a register to a value and jump if they are equal.
......@@ -502,11 +505,6 @@ class MacroAssembler : public TurboAssembler {
CompareRoot(with, index);
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.
void JumpIfNotRoot(Register with, RootIndex index, Label* if_not_equal,
......@@ -514,11 +512,6 @@ class MacroAssembler : public TurboAssembler {
CompareRoot(with, index);
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
......
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