Commit ca1d44e3 authored by jgruber's avatar jgruber Committed by Commit Bot

[builtins] Add --stress-off-heap-code to test off-heap code

If enabled, this mode moves code for isolate-independent builtins off
the JS heap at Isolate creation. The Code object itself is rewritten
to tail-call the off-heap instruction stream.

Drive-by-fix: Support lazy deserialization in asm-wasm instantiation.

Bug: v8:6666
Change-Id: Ic109527ff478cfc6e8942e924413fc7532da6eaf
Reviewed-on: https://chromium-review.googlesource.com/888562Reviewed-by: 's avatarMichael Starzinger <mstarzinger@chromium.org>
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#51015}
parent 2778b460
......@@ -1733,6 +1733,8 @@ v8_source_set("v8_base") {
"src/icu_util.h",
"src/identity-map.cc",
"src/identity-map.h",
"src/instruction-stream.cc",
"src/instruction-stream.h",
"src/interface-descriptors.cc",
"src/interface-descriptors.h",
"src/interpreter/block-coverage-builder.h",
......
......@@ -1046,6 +1046,8 @@
'../src/ic/ic.h',
'../src/identity-map.cc',
'../src/identity-map.h',
'../src/instruction-stream.cc',
'../src/instruction-stream.h',
'../src/interface-descriptors.cc',
'../src/interface-descriptors.h',
'../src/interpreter/block-coverage-builder.h',
......
......@@ -18,6 +18,7 @@
#include "src/double.h"
#include "src/external-reference-table.h"
#include "src/frames-inl.h"
#include "src/instruction-stream.h"
#include "src/objects-inl.h"
#include "src/register-configuration.h"
#include "src/runtime/runtime.h"
......@@ -1687,6 +1688,12 @@ void MacroAssembler::JumpToExternalReference(const ExternalReference& builtin,
Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
}
void MacroAssembler::JumpToInstructionStream(const InstructionStream* stream) {
int32_t bytes_address = reinterpret_cast<int32_t>(stream->bytes());
mov(kOffHeapTrampolineRegister, Operand(bytes_address, RelocInfo::NONE));
Jump(kOffHeapTrampolineRegister);
}
void MacroAssembler::IncrementCounter(StatsCounter* counter, int value,
Register scratch1, Register scratch2) {
DCHECK_GT(value, 0);
......
......@@ -27,6 +27,7 @@ constexpr Register kInterpreterDispatchTableRegister = r8;
constexpr Register kInterpreterTargetBytecodeRegister = r4;
constexpr Register kJavaScriptCallArgCountRegister = r0;
constexpr Register kJavaScriptCallNewTargetRegister = r3;
constexpr Register kOffHeapTrampolineRegister = r4;
constexpr Register kRuntimeCallFunctionRegister = r1;
constexpr Register kRuntimeCallArgCountRegister = r0;
......@@ -790,6 +791,9 @@ class MacroAssembler : public TurboAssembler {
void JumpToExternalReference(const ExternalReference& builtin,
bool builtin_exit_frame = false);
// Generates a trampoline to jump to the off-heap instruction stream.
void JumpToInstructionStream(const InstructionStream* stream);
// ---------------------------------------------------------------------------
// StatsCounter support
......
......@@ -15,6 +15,7 @@
#include "src/frame-constants.h"
#include "src/frames-inl.h"
#include "src/heap/heap-inl.h"
#include "src/instruction-stream.h"
#include "src/register-configuration.h"
#include "src/runtime/runtime.h"
......@@ -1761,6 +1762,12 @@ void MacroAssembler::JumpToExternalReference(const ExternalReference& builtin,
Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
}
void MacroAssembler::JumpToInstructionStream(const InstructionStream* stream) {
uint64_t bytes_address = reinterpret_cast<uint64_t>(stream->bytes());
Mov(kOffHeapTrampolineRegister, bytes_address);
Br(kOffHeapTrampolineRegister);
}
void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid) {
const Runtime::Function* function = Runtime::FunctionForId(fid);
DCHECK_EQ(1, function->result_size);
......
......@@ -54,6 +54,7 @@ namespace internal {
#define kInterpreterTargetBytecodeRegister x18
#define kJavaScriptCallArgCountRegister x0
#define kJavaScriptCallNewTargetRegister x3
#define kOffHeapTrampolineRegister ip0
#define kRuntimeCallFunctionRegister x1
#define kRuntimeCallArgCountRegister x0
......@@ -1766,6 +1767,9 @@ class MacroAssembler : public TurboAssembler {
void JumpToExternalReference(const ExternalReference& builtin,
bool builtin_exit_frame = false);
// Generates a trampoline to jump to the off-heap instruction stream.
void JumpToInstructionStream(const InstructionStream* stream);
// Registers used through the invocation chain are hard-coded.
// We force passing the parameters to ensure the contracts are correctly
// honoured by the caller.
......
......@@ -65,18 +65,21 @@ bool AreStdlibMembersValid(Isolate* isolate, Handle<JSReceiver> stdlib,
Handle<Object> value = JSReceiver::GetDataProperty(stdlib, name);
if (!value->IsNaN()) return false;
}
#define STDLIB_MATH_FUNC(fname, FName, ignore1, ignore2) \
if (members.Contains(wasm::AsmJsParser::StandardMember::kMath##FName)) { \
members.Remove(wasm::AsmJsParser::StandardMember::kMath##FName); \
Handle<Name> name(isolate->factory()->InternalizeOneByteString( \
STATIC_CHAR_VECTOR(#fname))); \
Handle<Object> value = StdlibMathMember(isolate, stdlib, name); \
if (!value->IsJSFunction()) return false; \
Handle<JSFunction> func = Handle<JSFunction>::cast(value); \
if (func->shared()->code() != \
isolate->builtins()->builtin(Builtins::kMath##FName)) { \
return false; \
} \
#define STDLIB_MATH_FUNC(fname, FName, ignore1, ignore2) \
if (members.Contains(wasm::AsmJsParser::StandardMember::kMath##FName)) { \
members.Remove(wasm::AsmJsParser::StandardMember::kMath##FName); \
Handle<Name> name(isolate->factory()->InternalizeOneByteString( \
STATIC_CHAR_VECTOR(#fname))); \
Handle<Object> value = StdlibMathMember(isolate, stdlib, name); \
if (!value->IsJSFunction()) return false; \
SharedFunctionInfo* shared = Handle<JSFunction>::cast(value)->shared(); \
if (shared->HasLazyDeserializationBuiltinId()) { \
if (shared->lazy_deserialization_builtin_id() != Builtins::kMath##FName) \
return false; \
} else if (shared->code() != \
isolate->builtins()->builtin(Builtins::kMath##FName)) { \
return false; \
} \
}
STDLIB_MATH_FUNCTION_LIST(STDLIB_MATH_FUNC)
#undef STDLIB_MATH_FUNC
......
......@@ -57,6 +57,7 @@ class ApiFunction;
namespace internal {
// Forward declarations.
class InstructionStream;
class Isolate;
class SourcePosition;
class StatsCounter;
......
......@@ -170,30 +170,11 @@ Callable Builtins::CallableFor(Isolate* isolate, Name name) {
BUILTIN_LIST(IGNORE_BUILTIN, IGNORE_BUILTIN, IGNORE_BUILTIN, CASE_OTHER,
CASE_OTHER, CASE_OTHER, IGNORE_BUILTIN)
#undef CASE_OTHER
case kArrayFilterLoopEagerDeoptContinuation:
case kArrayFilterLoopLazyDeoptContinuation:
case kArrayEveryLoopEagerDeoptContinuation:
case kArrayEveryLoopLazyDeoptContinuation:
case kArrayFindIndexLoopAfterCallbackLazyDeoptContinuation:
case kArrayFindIndexLoopEagerDeoptContinuation:
case kArrayFindIndexLoopLazyDeoptContinuation:
case kArrayFindLoopAfterCallbackLazyDeoptContinuation:
case kArrayFindLoopEagerDeoptContinuation:
case kArrayFindLoopLazyDeoptContinuation:
case kArrayForEach:
case kArrayForEachLoopEagerDeoptContinuation:
case kArrayForEachLoopLazyDeoptContinuation:
case kArrayMapLoopEagerDeoptContinuation:
case kArrayMapLoopLazyDeoptContinuation:
case kArrayReduceLoopEagerDeoptContinuation:
case kArrayReduceLoopLazyDeoptContinuation:
case kArrayReduceRightLoopEagerDeoptContinuation:
case kArrayReduceRightLoopLazyDeoptContinuation:
case kArraySomeLoopEagerDeoptContinuation:
case kArraySomeLoopLazyDeoptContinuation:
case kConsoleAssert:
return Callable(code, BuiltinDescriptor(isolate));
default:
Builtins::Kind kind = Builtins::KindOf(name);
if (kind == TFJ || kind == CPP) {
return Callable(code, BuiltinDescriptor(isolate));
}
UNREACHABLE();
}
CallInterfaceDescriptor descriptor(isolate, key);
......
......@@ -1011,6 +1011,8 @@ DEFINE_INT(fuzzer_random_seed, 0,
DEFINE_BOOL(trace_rail, false, "trace RAIL mode")
DEFINE_BOOL(print_all_exceptions, false,
"print exception object and stack trace on each thrown exception")
DEFINE_BOOL(stress_off_heap_code, false,
"Move code objects off-heap for testing.")
// runtime.cc
DEFINE_BOOL(runtime_call_stats, false, "report runtime call counts and times")
......
......@@ -14,6 +14,7 @@
#include "src/external-reference-table.h"
#include "src/frame-constants.h"
#include "src/frames-inl.h"
#include "src/instruction-stream.h"
#include "src/runtime/runtime.h"
#include "src/ia32/assembler-ia32-inl.h"
......@@ -862,6 +863,12 @@ void MacroAssembler::JumpToExternalReference(const ExternalReference& ext,
jmp(ces.GetCode(), RelocInfo::CODE_TARGET);
}
void MacroAssembler::JumpToInstructionStream(const InstructionStream* stream) {
Address bytes_address = reinterpret_cast<Address>(stream->bytes());
mov(kOffHeapTrampolineRegister, Immediate(bytes_address, RelocInfo::NONE));
jmp(kOffHeapTrampolineRegister);
}
void TurboAssembler::PrepareForTailCall(
const ParameterCount& callee_args_count, Register caller_args_count_reg,
Register scratch0, Register scratch1,
......
......@@ -27,6 +27,7 @@ constexpr Register kInterpreterDispatchTableRegister = esi;
constexpr Register kInterpreterTargetBytecodeRegister = ebx;
constexpr Register kJavaScriptCallArgCountRegister = eax;
constexpr Register kJavaScriptCallNewTargetRegister = edx;
constexpr Register kOffHeapTrampolineRegister = ecx;
constexpr Register kRuntimeCallFunctionRegister = ebx;
constexpr Register kRuntimeCallArgCountRegister = eax;
......@@ -577,6 +578,9 @@ class MacroAssembler : public TurboAssembler {
void JumpToExternalReference(const ExternalReference& ext,
bool builtin_exit_frame = false);
// Generates a trampoline to jump to the off-heap instruction stream.
void JumpToInstructionStream(const InstructionStream* stream);
// ---------------------------------------------------------------------------
// Utilities
......
// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/instruction-stream.h"
#include "src/builtins/builtins.h"
#include "src/heap/heap.h"
#include "src/objects-inl.h"
#include "src/objects/code-inl.h"
namespace v8 {
namespace internal {
InstructionStream::InstructionStream(Code* code) {
DCHECK(Builtins::IsIsolateIndependent(code->builtin_index()));
const size_t page_size = AllocatePageSize();
byte_length_ =
RoundUp(static_cast<size_t>(code->instruction_size()), page_size);
bytes_ = static_cast<uint8_t*>(AllocatePages(
GetRandomMmapAddr(), byte_length_, page_size, PageAllocator::kReadWrite));
CHECK_NOT_NULL(bytes_);
std::memcpy(bytes_, code->instruction_start(), code->instruction_size());
CHECK(SetPermissions(bytes_, byte_length_, PageAllocator::kReadExecute));
}
InstructionStream::~InstructionStream() {
CHECK(FreePages(bytes_, byte_length_));
}
} // namespace internal
} // namespace v8
// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_INSTRUCTION_STREAM_H_
#define V8_INSTRUCTION_STREAM_H_
#include "src/base/macros.h"
namespace v8 {
namespace internal {
class Code;
// Wraps an mmap'ed off-heap instruction stream. This class will likely become
// unneeded once --stress-off-heap-code is removed.
class InstructionStream final {
public:
explicit InstructionStream(Code* code);
~InstructionStream();
size_t byte_length() const { return byte_length_; }
uint8_t* bytes() const { return bytes_; }
private:
size_t byte_length_;
uint8_t* bytes_;
DISALLOW_COPY_AND_ASSIGN(InstructionStream)
};
} // namespace internal
} // namespace v8
#endif // V8_INSTRUCTION_STREAM_H_
......@@ -20,6 +20,7 @@
#include "src/base/utils/random-number-generator.h"
#include "src/basic-block-profiler.h"
#include "src/bootstrapper.h"
#include "src/callable.h"
#include "src/cancelable-task.h"
#include "src/code-stubs.h"
#include "src/compilation-cache.h"
......@@ -32,6 +33,7 @@
#include "src/external-reference-table.h"
#include "src/frames-inl.h"
#include "src/ic/stub-cache.h"
#include "src/instruction-stream.h"
#include "src/interface-descriptors.h"
#include "src/interpreter/interpreter.h"
#include "src/isolate-inl.h"
......@@ -2676,6 +2678,12 @@ void Isolate::Deinit() {
root_index_map_ = nullptr;
ClearSerializerData();
for (InstructionStream* stream : off_heap_code_) {
CHECK(FLAG_stress_off_heap_code);
delete stream;
}
off_heap_code_.clear();
}
......@@ -2832,6 +2840,110 @@ void PrintBuiltinSizes(Isolate* isolate) {
code->instruction_size());
}
}
#ifdef DEBUG
bool BuiltinAliasesOffHeapTrampolineRegister(Isolate* isolate,
int builtin_index) {
switch (Builtins::KindOf(builtin_index)) {
case Builtins::CPP:
case Builtins::TFC:
case Builtins::TFH:
case Builtins::TFJ:
case Builtins::TFS:
break;
case Builtins::API:
case Builtins::ASM:
// TODO(jgruber): Extend checks to remaining kinds.
return false;
}
Callable callable = Builtins::CallableFor(
isolate, static_cast<Builtins::Name>(builtin_index));
CallInterfaceDescriptor descriptor = callable.descriptor();
if (descriptor.ContextRegister() == kOffHeapTrampolineRegister) {
return true;
}
for (int i = 0; i < descriptor.GetRegisterParameterCount(); i++) {
Register reg = descriptor.GetRegisterParameter(i);
if (reg == kOffHeapTrampolineRegister) return true;
}
return false;
}
#endif
void ChangeToOffHeapTrampoline(Isolate* isolate, Handle<Code> code,
InstructionStream* stream) {
DCHECK(Builtins::IsIsolateIndependent(code->builtin_index()));
HandleScope scope(isolate);
constexpr size_t buffer_size = 256; // Enough to fit the single jmp.
byte buffer[buffer_size]; // NOLINT(runtime/arrays)
// Generate replacement code that simply tail-calls the off-heap code.
MacroAssembler masm(isolate, buffer, buffer_size, CodeObjectRequired::kYes);
DCHECK(
!BuiltinAliasesOffHeapTrampolineRegister(isolate, code->builtin_index()));
DCHECK(!masm.has_frame());
{
FrameScope scope(&masm, StackFrame::NONE);
masm.JumpToInstructionStream(stream);
}
CodeDesc desc;
masm.GetCode(isolate, &desc);
// Hack in an empty reloc info to satisfy the GC.
DCHECK_EQ(0, desc.reloc_size);
Handle<ByteArray> reloc_info =
isolate->factory()->NewByteArray(desc.reloc_size, TENURED);
code->set_relocation_info(*reloc_info);
// Overwrites the original code.
code->CopyFrom(desc);
// TODO(jgruber): CopyFrom isn't intended to overwrite existing code, and
// doesn't update things like instruction_size. The result is a code object in
// which the first instructions are overwritten while the rest remain intact
// (but are never executed). That's fine for our current purposes, just
// manually zero the trailing part.
DCHECK_LE(desc.instr_size, code->instruction_size());
byte* trailing_instruction_start =
code->instruction_start() + desc.instr_size;
size_t trailing_instruction_size = code->instruction_size() - desc.instr_size;
std::memset(trailing_instruction_start, 0, trailing_instruction_size);
}
void LogInstructionStream(Isolate* isolate, const InstructionStream* stream) {
// TODO(jgruber): Log the given instruction stream object (the profiler needs
// this to assign ticks to builtins).
}
void MoveBuiltinsOffHeap(Isolate* isolate) {
DCHECK(FLAG_stress_off_heap_code);
HandleScope scope(isolate);
Builtins* builtins = isolate->builtins();
// TODO(jgruber): Support stack iteration with off-heap on-stack builtins.
// Lazy deserialization would defeat our off-heap stress test (we'd
// deserialize later without moving off-heap), so force eager
// deserialization.
Snapshot::EnsureAllBuiltinsAreDeserialized(isolate);
CodeSpaceMemoryModificationScope code_allocation(isolate->heap());
for (int i = 0; i < Builtins::builtin_count; i++) {
if (!Builtins::IsIsolateIndependent(i)) continue;
Handle<Code> code(builtins->builtin(i));
InstructionStream* stream = new InstructionStream(*code);
LogInstructionStream(isolate, stream);
ChangeToOffHeapTrampoline(isolate, code, stream);
isolate->PushOffHeapCode(stream);
}
}
} // namespace
bool Isolate::Init(StartupDeserializer* des) {
......@@ -2980,6 +3092,13 @@ bool Isolate::Init(StartupDeserializer* des) {
if (FLAG_print_builtin_size) PrintBuiltinSizes(this);
if (FLAG_stress_off_heap_code && !serializer_enabled()) {
// Artificially move code off-heap to help find & verify related code
// paths. Lazy deserialization should be off to avoid confusion around
// replacing just the kDeserializeLazy code object.
MoveBuiltinsOffHeap(this);
}
// Finish initialization of ThreadLocal after deserialization is done.
clear_pending_exception();
clear_pending_message();
......
......@@ -75,6 +75,7 @@ class HeapObjectToIndexHashMap;
class HeapProfiler;
class InlineRuntimeFunctionsTable;
class InnerPointerToCodeCache;
class InstructionStream;
class Logger;
class MaterializedObjectStore;
class OptimizingCompileDispatcher;
......@@ -1249,6 +1250,10 @@ class Isolate {
return &partial_snapshot_cache_;
}
void PushOffHeapCode(InstructionStream* stream) {
off_heap_code_.emplace_back(stream);
}
void set_array_buffer_allocator(v8::ArrayBuffer::Allocator* allocator) {
array_buffer_allocator_ = allocator;
}
......@@ -1620,6 +1625,12 @@ class Isolate {
std::vector<Object*> partial_snapshot_cache_;
// Stores off-heap instruction streams. Only used if --stress-off-heap-code
// is enabled.
// TODO(jgruber,v8:6666): Remove once isolate-independent builtins are
// implemented.
std::vector<InstructionStream*> off_heap_code_;
v8::ArrayBuffer::Allocator* array_buffer_allocator_;
FutexWaitListNode futex_wait_list_node_;
......
......@@ -14,6 +14,7 @@
#include "src/debug/debug.h"
#include "src/external-reference-table.h"
#include "src/frames-inl.h"
#include "src/instruction-stream.h"
#include "src/mips/assembler-mips-inl.h"
#include "src/mips/macro-assembler-mips.h"
#include "src/register-configuration.h"
......@@ -4459,6 +4460,12 @@ void MacroAssembler::JumpToExternalReference(const ExternalReference& builtin,
bd);
}
void MacroAssembler::JumpToInstructionStream(const InstructionStream* stream) {
int32_t bytes_address = reinterpret_cast<int32_t>(stream->bytes());
li(kOffHeapTrampolineRegister, Operand(bytes_address, RelocInfo::NONE));
Jump(kOffHeapTrampolineRegister);
}
void MacroAssembler::IncrementCounter(StatsCounter* counter, int value,
Register scratch1, Register scratch2) {
DCHECK_GT(value, 0);
......
......@@ -26,6 +26,7 @@ constexpr Register kInterpreterDispatchTableRegister = t6;
constexpr Register kInterpreterTargetBytecodeRegister = t3;
constexpr Register kJavaScriptCallArgCountRegister = a0;
constexpr Register kJavaScriptCallNewTargetRegister = a3;
constexpr Register kOffHeapTrampolineRegister = at;
constexpr Register kRuntimeCallFunctionRegister = a1;
constexpr Register kRuntimeCallArgCountRegister = a0;
......@@ -1086,6 +1087,9 @@ const Operand& rt = Operand(zero_reg), BranchDelaySlot bd = PROTECT
BranchDelaySlot bd = PROTECT,
bool builtin_exit_frame = false);
// Generates a trampoline to jump to the off-heap instruction stream.
void JumpToInstructionStream(const InstructionStream* stream);
// -------------------------------------------------------------------------
// StatsCounter support.
......
......@@ -14,6 +14,7 @@
#include "src/debug/debug.h"
#include "src/external-reference-table.h"
#include "src/frames-inl.h"
#include "src/instruction-stream.h"
#include "src/mips64/assembler-mips64-inl.h"
#include "src/mips64/macro-assembler-mips64.h"
#include "src/register-configuration.h"
......@@ -4715,6 +4716,12 @@ void MacroAssembler::JumpToExternalReference(const ExternalReference& builtin,
bd);
}
void MacroAssembler::JumpToInstructionStream(const InstructionStream* stream) {
uint64_t bytes_address = reinterpret_cast<uint64_t>(stream->bytes());
li(kOffHeapTrampolineRegister, Operand(bytes_address, RelocInfo::NONE));
Jump(kOffHeapTrampolineRegister);
}
void MacroAssembler::IncrementCounter(StatsCounter* counter, int value,
Register scratch1, Register scratch2) {
DCHECK_GT(value, 0);
......
......@@ -26,6 +26,7 @@ constexpr Register kInterpreterDispatchTableRegister = t2;
constexpr Register kInterpreterTargetBytecodeRegister = a7;
constexpr Register kJavaScriptCallArgCountRegister = a0;
constexpr Register kJavaScriptCallNewTargetRegister = a3;
constexpr Register kOffHeapTrampolineRegister = at;
constexpr Register kRuntimeCallFunctionRegister = a1;
constexpr Register kRuntimeCallArgCountRegister = a0;
......@@ -1153,6 +1154,9 @@ const Operand& rt = Operand(zero_reg), BranchDelaySlot bd = PROTECT
BranchDelaySlot bd = PROTECT,
bool builtin_exit_frame = false);
// Generates a trampoline to jump to the off-heap instruction stream.
void JumpToInstructionStream(const InstructionStream* stream);
// -------------------------------------------------------------------------
// StatsCounter support.
......
......@@ -15,6 +15,7 @@
#include "src/debug/debug.h"
#include "src/external-reference-table.h"
#include "src/frames-inl.h"
#include "src/instruction-stream.h"
#include "src/register-configuration.h"
#include "src/runtime/runtime.h"
......@@ -1618,6 +1619,11 @@ void MacroAssembler::JumpToExternalReference(const ExternalReference& builtin,
Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
}
void MacroAssembler::JumpToInstructionStream(const InstructionStream* stream) {
intptr_t bytes_address = reinterpret_cast<intptr_t>(stream->bytes());
mov(kOffHeapTrampolineRegister, Operand(bytes_address, RelocInfo::NONE));
Jump(kOffHeapTrampolineRegister);
}
void MacroAssembler::IncrementCounter(StatsCounter* counter, int value,
Register scratch1, Register scratch2) {
......
......@@ -28,6 +28,7 @@ const Register kInterpreterDispatchTableRegister = r17;
const Register kInterpreterTargetBytecodeRegister = r14;
const Register kJavaScriptCallArgCountRegister = r3;
const Register kJavaScriptCallNewTargetRegister = r6;
const Register kOffHeapTrampolineRegister = ip;
const Register kRuntimeCallFunctionRegister = r4;
const Register kRuntimeCallArgCountRegister = r3;
......@@ -930,6 +931,9 @@ class MacroAssembler : public TurboAssembler {
void JumpToExternalReference(const ExternalReference& builtin,
bool builtin_exit_frame = false);
// Generates a trampoline to jump to the off-heap instruction stream.
void JumpToInstructionStream(const InstructionStream* stream);
// ---------------------------------------------------------------------------
// StatsCounter support
......
......@@ -1521,6 +1521,12 @@ void MacroAssembler::JumpToExternalReference(const ExternalReference& builtin,
Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
}
void MacroAssembler::JumpToInstructionStream(const InstructionStream* stream) {
intptr_t bytes_address = static_cast<intptr_t>(stream->bytes());
mov(kOffHeapTrampolineRegister, Operand(bytes_address));
Jump(kOffHeapTrampolineRegister);
}
void MacroAssembler::IncrementCounter(StatsCounter* counter, int value,
Register scratch1, Register scratch2) {
DCHECK(value > 0 && is_int8(value));
......
......@@ -27,6 +27,7 @@ const Register kInterpreterDispatchTableRegister = r8;
const Register kInterpreterTargetBytecodeRegister = r5;
const Register kJavaScriptCallArgCountRegister = r2;
const Register kJavaScriptCallNewTargetRegister = r5;
const Register kOffHeapTrampolineRegister = ip;
const Register kRuntimeCallFunctionRegister = r3;
const Register kRuntimeCallArgCountRegister = r2;
......@@ -1083,6 +1084,9 @@ class MacroAssembler : public TurboAssembler {
void JumpToExternalReference(const ExternalReference& builtin,
bool builtin_exit_frame = false);
// Generates a trampoline to jump to the off-heap instruction stream.
void JumpToInstructionStream(const InstructionStream* stream);
// Compare the object in a register to a value and jump if they are equal.
void JumpIfRoot(Register with, Heap::RootListIndex index, Label* if_equal) {
CompareRoot(with, index);
......
......@@ -15,6 +15,7 @@
#include "src/external-reference-table.h"
#include "src/frames-inl.h"
#include "src/heap/heap-inl.h"
#include "src/instruction-stream.h"
#include "src/objects-inl.h"
#include "src/register-configuration.h"
#include "src/x64/assembler-x64.h"
......@@ -1631,6 +1632,12 @@ void MacroAssembler::Jump(Handle<Code> code_object, RelocInfo::Mode rmode) {
jmp(code_object, rmode);
}
void MacroAssembler::JumpToInstructionStream(const InstructionStream* stream) {
Address bytes_address = reinterpret_cast<Address>(stream->bytes());
Move(kOffHeapTrampolineRegister, bytes_address, RelocInfo::NONE);
jmp(kOffHeapTrampolineRegister);
}
int TurboAssembler::CallSize(ExternalReference ext) {
// Opcode for call kScratchRegister is: Rex.B FF D4 (three bytes).
return LoadAddressSize(ext) +
......
......@@ -39,6 +39,7 @@ constexpr Register kRootRegister = r13; // callee save
// Actual value of root register is offset from the root array's start
// to take advantage of negitive 8-bit displacement values.
constexpr int kRootRegisterBias = 128;
constexpr Register kOffHeapTrampolineRegister = kScratchRegister;
// Convenience for platform-independent signatures.
typedef Operand MemOperand;
......@@ -785,6 +786,9 @@ class MacroAssembler : public TurboAssembler {
void Jump(const Operand& op);
void Jump(Handle<Code> code_object, RelocInfo::Mode rmode);
// Generates a trampoline to jump to the off-heap instruction stream.
void JumpToInstructionStream(const InstructionStream* stream);
// Non-x64 instructions.
// Push/pop all general purpose registers.
// Does not push rsp/rbp nor any of the assembler's special purpose registers
......
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