[sparkplug] Support shorter builtin calls, pt.2

This is a speed-for-memory tradeoff, which can be achieved by
re-mapping the builtins code blob into existing code range.

This CL handles cases where both embedded and un-embedded off-heap
builtins' PCs might appear on the call stack.

The v8_enable_short_builtin_calls build flag is still disabled.

Bug: v8:11527, v8:11421
Change-Id: Ie3db6eb8e264854df42b936a97d3e73d01de5dfd
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2749636
Commit-Queue: Igor Sheludko <ishell@chromium.org>
Reviewed-by: Jakob Gruber <jgruber@chromium.org>
Reviewed-by: Ulan Degenbaev <ulan@chromium.org>
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
Cr-Commit-Position: refs/heads/master@{#73476}
This commit is contained in:
Igor Sheludko 2021-03-17 14:38:11 +01:00 committed by Commit Bot
parent c665440b7f
commit be4c28ebed
15 changed files with 211 additions and 71 deletions

View File

@ -112,7 +112,7 @@ const char* Builtins::Lookup(Address pc) {
// May be called during initialization (disassembler).
if (initialized_) {
for (int i = 0; i < builtin_count; i++) {
if (isolate_->heap()->builtin(i).contains(pc)) return name(i);
if (isolate_->heap()->builtin(i).contains(isolate_, pc)) return name(i);
}
}
return nullptr;

View File

@ -519,8 +519,8 @@ void RelocInfo::Verify(Isolate* isolate) {
Address target = target_internal_reference();
Address pc = target_internal_reference_address();
Code code = Code::cast(isolate->FindCodeObject(pc));
CHECK(target >= code.InstructionStart());
CHECK(target <= code.InstructionEnd());
CHECK(target >= code.InstructionStart(isolate, pc));
CHECK(target <= code.InstructionEnd(isolate, pc));
break;
}
case OFF_HEAP_TARGET: {

View File

@ -18,9 +18,9 @@
namespace v8 {
namespace internal {
SafepointTable::SafepointTable(Code code)
: SafepointTable(code.InstructionStart(), code.SafepointTableAddress(),
code.stack_slots(), true) {}
SafepointTable::SafepointTable(Isolate* isolate, Address pc, Code code)
: SafepointTable(code.InstructionStart(isolate, pc),
code.SafepointTableAddress(), code.stack_slots(), true) {}
#if V8_ENABLE_WEBASSEMBLY
SafepointTable::SafepointTable(const wasm::WasmCode* code)

View File

@ -81,7 +81,9 @@ class SafepointEntry {
class SafepointTable {
public:
explicit SafepointTable(Code code);
// The isolate and pc arguments are used for figuring out whether pc
// belongs to the embedded or un-embedded code blob.
explicit SafepointTable(Isolate* isolate, Address pc, Code code);
#if V8_ENABLE_WEBASSEMBLY
explicit SafepointTable(const wasm::WasmCode* code);
#endif // V8_ENABLE_WEBASSEMBLY

View File

@ -181,7 +181,7 @@ Code Deoptimizer::FindDeoptimizingCode(Address addr) {
while (!element.IsUndefined(isolate)) {
Code code = Code::cast(element);
CHECK(CodeKindCanDeoptimize(code.kind()));
if (code.contains(addr)) return code;
if (code.contains(isolate, addr)) return code;
element = code.next_code_link();
}
}
@ -262,7 +262,8 @@ class ActivationsFinder : public ThreadVisitor {
code.marked_for_deoptimization()) {
codes_->erase(code);
// Obtain the trampoline to the deoptimizer call.
SafepointEntry safepoint = code.GetSafepointEntry(it.frame()->pc());
SafepointEntry safepoint =
code.GetSafepointEntry(isolate, it.frame()->pc());
int trampoline_pc = safepoint.trampoline_pc();
DCHECK_IMPLIES(code == topmost_, safe_to_deopt_);
STATIC_ASSERT(SafepointEntry::kNoTrampolinePC == -1);
@ -308,7 +309,8 @@ void Deoptimizer::DeoptimizeMarkedCodeForContext(NativeContext native_context) {
JSFunction function =
static_cast<OptimizedFrame*>(it.frame())->function();
TraceFoundActivation(isolate, function);
SafepointEntry safepoint = code.GetSafepointEntry(it.frame()->pc());
SafepointEntry safepoint =
code.GetSafepointEntry(isolate, it.frame()->pc());
// Turbofan deopt is checked when we are patching addresses on stack.
bool safe_if_deopt_triggered = safepoint.has_deoptimization_index();

View File

@ -232,9 +232,9 @@ bool IsInterpreterFramePc(Isolate* isolate, Address pc,
Code interpreter_bytecode_dispatch =
isolate->builtins()->builtin(Builtins::kInterpreterEnterBytecodeDispatch);
if (interpreter_entry_trampoline.contains(pc) ||
interpreter_bytecode_advance.contains(pc) ||
interpreter_bytecode_dispatch.contains(pc)) {
if (interpreter_entry_trampoline.contains(isolate, pc) ||
interpreter_bytecode_advance.contains(isolate, pc) ||
interpreter_bytecode_dispatch.contains(isolate, pc)) {
return true;
} else if (FLAG_interpreted_frames_native_stack) {
intptr_t marker = Memory<intptr_t>(
@ -509,23 +509,22 @@ Code GetContainingCode(Isolate* isolate, Address pc) {
Code StackFrame::LookupCode() const {
Code result = GetContainingCode(isolate(), pc());
DCHECK_GE(pc(), result.InstructionStart());
DCHECK_LT(pc(), result.InstructionEnd());
DCHECK_GE(pc(), result.InstructionStart(isolate(), pc()));
DCHECK_LT(pc(), result.InstructionEnd(isolate(), pc()));
return result;
}
void StackFrame::IteratePc(RootVisitor* v, Address* pc_address,
Address* constant_pool_address, Code holder) {
Address* constant_pool_address, Code holder) const {
Address old_pc = ReadPC(pc_address);
DCHECK(ReadOnlyHeap::Contains(holder) ||
holder.GetHeap()->GcSafeCodeContains(holder, old_pc));
unsigned pc_offset =
static_cast<unsigned>(old_pc - holder.InstructionStart());
unsigned pc_offset = holder.GetOffsetFromInstructionStart(isolate_, old_pc);
Object code = holder;
v->VisitRootPointer(Root::kTop, nullptr, FullObjectSlot(&code));
if (code == holder) return;
holder = Code::unchecked_cast(code);
Address pc = holder.InstructionStart() + pc_offset;
Address pc = holder.InstructionStart(isolate_, old_pc) + pc_offset;
// TODO(v8:10026): avoid replacing a signed pointer.
PointerAuthentication::ReplacePC(pc_address, pc, kSystemPointerSize);
if (FLAG_enable_embedded_constant_pool && constant_pool_address) {
@ -902,9 +901,9 @@ Object CommonFrame::context() const {
}
int CommonFrame::position() const {
AbstractCode code = AbstractCode::cast(LookupCode());
int code_offset = static_cast<int>(pc() - code.InstructionStart());
return code.SourcePosition(code_offset);
Code code = LookupCode();
int code_offset = code.GetOffsetFromInstructionStart(isolate(), pc());
return AbstractCode::cast(code).SourcePosition(code_offset);
}
int CommonFrame::ComputeExpressionsCount() const {
@ -963,11 +962,12 @@ void CommonFrame::IterateCompiledFrame(RootVisitor* v) const {
InnerPointerToCodeCache::InnerPointerToCodeCacheEntry* entry =
isolate()->inner_pointer_to_code_cache()->GetCacheEntry(inner_pointer);
if (!entry->safepoint_entry.is_valid()) {
entry->safepoint_entry = entry->code.GetSafepointEntry(inner_pointer);
entry->safepoint_entry =
entry->code.GetSafepointEntry(isolate(), inner_pointer);
DCHECK(entry->safepoint_entry.is_valid());
} else {
DCHECK(entry->safepoint_entry.Equals(
entry->code.GetSafepointEntry(inner_pointer)));
entry->code.GetSafepointEntry(isolate(), inner_pointer)));
}
code = entry->code;
@ -1125,7 +1125,7 @@ int StubFrame::LookupExceptionHandlerInTable() {
DCHECK(code.is_turbofanned());
DCHECK_EQ(code.kind(), CodeKind::BUILTIN);
HandlerTable table(code);
int pc_offset = static_cast<int>(pc() - code.InstructionStart());
int pc_offset = code.GetOffsetFromInstructionStart(isolate(), pc());
return table.LookupReturn(pc_offset);
}
@ -1188,7 +1188,7 @@ void CommonFrameWithJSLinkage::Summarize(
std::vector<FrameSummary>* functions) const {
DCHECK(functions->empty());
Code code = LookupCode();
int offset = static_cast<int>(pc() - code.InstructionStart());
int offset = code.GetOffsetFromInstructionStart(isolate(), pc());
Handle<AbstractCode> abstract_code(AbstractCode::cast(code), isolate());
Handle<FixedArray> params = GetParameters();
FrameSummary::JavaScriptFrameSummary summary(
@ -1276,7 +1276,7 @@ void JavaScriptFrame::PrintTop(Isolate* isolate, FILE* file, bool print_args,
code_offset = iframe->GetBytecodeOffset();
} else {
Code code = frame->unchecked_code();
code_offset = static_cast<int>(frame->pc() - code.InstructionStart());
code_offset = code.GetOffsetFromInstructionStart(isolate, frame->pc());
}
PrintFunctionAndOffset(function, function.abstract_code(isolate),
code_offset, file, print_line_number);
@ -1657,14 +1657,14 @@ int OptimizedFrame::LookupExceptionHandlerInTable(
DCHECK_NULL(prediction);
Code code = LookupCode();
HandlerTable table(code);
int pc_offset = static_cast<int>(pc() - code.InstructionStart());
int pc_offset = code.GetOffsetFromInstructionStart(isolate(), pc());
DCHECK_NULL(data); // Data is not used and will not return a value.
// When the return pc has been replaced by a trampoline there won't be
// a handler for this trampoline. Thus we need to use the return pc that
// _used to be_ on the stack to get the right ExceptionHandler.
if (CodeKindCanDeoptimize(code.kind()) && code.marked_for_deoptimization()) {
SafepointTable safepoints(code);
SafepointTable safepoints(isolate(), pc(), code);
pc_offset = safepoints.find_return_pc(pc_offset);
}
return table.LookupReturn(pc_offset);
@ -1680,13 +1680,13 @@ DeoptimizationData OptimizedFrame::GetDeoptimizationData(
// The code object may have been replaced by lazy deoptimization. Fall
// back to a slow search in this case to find the original optimized
// code object.
if (!code.contains(pc())) {
if (!code.contains(isolate(), pc())) {
code = isolate()->heap()->GcSafeFindCodeForInnerPointer(pc());
}
DCHECK(!code.is_null());
DCHECK(CodeKindCanDeoptimize(code.kind()));
SafepointEntry safepoint_entry = code.GetSafepointEntry(pc());
SafepointEntry safepoint_entry = code.GetSafepointEntry(isolate(), pc());
if (safepoint_entry.has_deoptimization_index()) {
*deopt_index = safepoint_entry.deoptimization_index();
return DeoptimizationData::cast(code.deoptimization_data());
@ -2224,10 +2224,13 @@ void InternalFrame::Iterate(RootVisitor* v) const {
namespace {
// Predictably converts PC to uint32 by calculating offset of the PC in
// from the embedded builtins start or from respective MemoryChunk.
uint32_t PcAddressForHashing(Isolate* isolate, Address address) {
if (InstructionStream::PcIsOffHeap(isolate, address)) {
// Ensure that we get predictable hashes for addresses in embedded code.
return EmbeddedData::FromBlob(isolate).AddressForHashing(address);
uint32_t hashable_address;
if (InstructionStream::TryGetAddressForHashing(isolate, address,
&hashable_address)) {
return hashable_address;
}
return ObjectAddressForHashing(address);
}

View File

@ -286,8 +286,8 @@ class StackFrame {
V8_EXPORT_PRIVATE Code LookupCode() const;
virtual void Iterate(RootVisitor* v) const = 0;
static void IteratePc(RootVisitor* v, Address* pc_address,
Address* constant_pool_address, Code holder);
void IteratePc(RootVisitor* v, Address* pc_address,
Address* constant_pool_address, Code holder) const;
// Sets a callback function for return-address rewriting profilers
// to resolve the location of a return address to the location of the

View File

@ -736,7 +736,7 @@ class StackTraceBuilder {
Handle<Object> receiver(exit_frame->receiver(), isolate_);
Handle<Code> code(exit_frame->LookupCode(), isolate_);
const int offset =
static_cast<int>(exit_frame->pc() - code->InstructionStart());
code->GetOffsetFromInstructionStart(isolate_, exit_frame->pc());
int flags = 0;
if (IsStrictFrame(function)) flags |= StackFrameInfo::kIsStrict;
@ -1724,7 +1724,7 @@ Object Isolate::UnwindAndFindHandler() {
// Gather information from the handler.
Code code = frame->LookupCode();
HandlerTable table(code);
return FoundHandler(Context(), code.InstructionStart(),
return FoundHandler(Context(), code.InstructionStart(this, frame->pc()),
table.LookupReturn(0), code.constant_pool(),
handler->address() + StackHandlerConstants::kSize,
0);
@ -1736,7 +1736,7 @@ Object Isolate::UnwindAndFindHandler() {
thread_local_top()->handler_ = handler->next_address();
Code code = frame->LookupCode();
HandlerTable table(code);
Address instruction_start = code.InstructionStart();
Address instruction_start = code.InstructionStart(this, frame->pc());
int return_offset = static_cast<int>(frame->pc() - instruction_start);
int handler_offset = table.LookupReturn(return_offset);
DCHECK_NE(-1, handler_offset);
@ -1808,8 +1808,9 @@ Object Isolate::UnwindAndFindHandler() {
set_deoptimizer_lazy_throw(true);
}
return FoundHandler(Context(), code.InstructionStart(), offset,
code.constant_pool(), return_sp, frame->fp());
return FoundHandler(Context(), code.InstructionStart(this, frame->pc()),
offset, code.constant_pool(), return_sp,
frame->fp());
}
case StackFrame::STUB: {
@ -1835,8 +1836,9 @@ Object Isolate::UnwindAndFindHandler() {
StandardFrameConstants::kFixedFrameSizeAboveFp -
code.stack_slots() * kSystemPointerSize;
return FoundHandler(Context(), code.InstructionStart(), offset,
code.constant_pool(), return_sp, frame->fp());
return FoundHandler(Context(), code.InstructionStart(this, frame->pc()),
offset, code.constant_pool(), return_sp,
frame->fp());
}
case StackFrame::INTERPRETED:
@ -1874,8 +1876,9 @@ Object Isolate::UnwindAndFindHandler() {
// Patch the context register directly on the frame, so that we don't
// need to have a context read + write in the baseline code.
sp_frame->PatchContext(context);
return FoundHandler(Context(), code.InstructionStart(), pc_offset,
code.constant_pool(), return_sp, sp_frame->fp());
return FoundHandler(
Context(), code.InstructionStart(this, sp_frame->sp()), pc_offset,
code.constant_pool(), return_sp, sp_frame->fp());
} else {
InterpretedFrame::cast(js_frame)->PatchBytecodeOffset(
static_cast<int>(offset));

View File

@ -1876,7 +1876,7 @@ void MarkCompactCollector::ProcessTopOptimizedFrame(ObjectVisitor* visitor) {
if (it.frame()->is_unoptimized()) return;
if (it.frame()->type() == StackFrame::OPTIMIZED) {
Code code = it.frame()->LookupCode();
if (!code.CanDeoptAt(it.frame()->pc())) {
if (!code.CanDeoptAt(isolate(), it.frame()->pc())) {
Code::BodyDescriptor::IterateBody(code.map(), code, visitor);
}
return;

View File

@ -19,6 +19,7 @@
#include "src/objects/oddball.h"
#include "src/objects/shared-function-info.h"
#include "src/objects/smi-inl.h"
#include "src/utils/utils.h"
// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"
@ -275,6 +276,25 @@ Address Code::raw_metadata_start() const {
return raw_instruction_start() + raw_instruction_size();
}
Address Code::InstructionStart(Isolate* isolate, Address pc) const {
return V8_UNLIKELY(is_off_heap_trampoline())
? OffHeapInstructionStart(isolate, pc)
: raw_instruction_start();
}
Address Code::InstructionEnd(Isolate* isolate, Address pc) const {
return V8_UNLIKELY(is_off_heap_trampoline())
? OffHeapInstructionEnd(isolate, pc)
: raw_instruction_end();
}
int Code::GetOffsetFromInstructionStart(Isolate* isolate, Address pc) const {
Address instruction_start = InstructionStart(isolate, pc);
Address offset = pc - instruction_start;
DCHECK_LE(offset, InstructionSize());
return static_cast<int>(offset);
}
Address Code::MetadataStart() const {
STATIC_ASSERT(kOnHeapBodyIsContiguous);
return V8_UNLIKELY(is_off_heap_trampoline()) ? OffHeapMetadataStart()
@ -322,10 +342,10 @@ int Code::relocation_size() const {
Address Code::entry() const { return raw_instruction_start(); }
bool Code::contains(Address inner_pointer) {
bool Code::contains(Isolate* isolate, Address inner_pointer) {
if (is_off_heap_trampoline()) {
if (OffHeapInstructionStart() <= inner_pointer &&
inner_pointer < OffHeapInstructionEnd()) {
if (OffHeapInstructionStart(isolate, inner_pointer) <= inner_pointer &&
inner_pointer < OffHeapInstructionEnd(isolate, inner_pointer)) {
return true;
}
}

View File

@ -131,8 +131,8 @@ void Code::CopyFromNoFlush(Heap* heap, const CodeDesc& desc) {
}
}
SafepointEntry Code::GetSafepointEntry(Address pc) {
SafepointTable table(*this);
SafepointEntry Code::GetSafepointEntry(Isolate* isolate, Address pc) {
SafepointTable table(isolate, pc, *this);
return table.FindEntry(pc);
}
@ -178,6 +178,19 @@ Address Code::OffHeapInstructionEnd() const {
d.InstructionSizeOfBuiltin(builtin_index());
}
Address Code::OffHeapInstructionStart(Isolate* isolate, Address pc) const {
DCHECK(is_off_heap_trampoline());
EmbeddedData d = EmbeddedData::GetEmbeddedDataForPC(isolate, pc);
return d.InstructionStartOfBuiltin(builtin_index());
}
Address Code::OffHeapInstructionEnd(Isolate* isolate, Address pc) const {
DCHECK(is_off_heap_trampoline());
EmbeddedData d = EmbeddedData::GetEmbeddedDataForPC(isolate, pc);
return d.InstructionStartOfBuiltin(builtin_index()) +
d.InstructionSizeOfBuiltin(builtin_index());
}
int Code::OffHeapMetadataSize() const {
DCHECK(is_off_heap_trampoline());
if (Isolate::CurrentEmbeddedBlobCode() == nullptr) {
@ -245,10 +258,10 @@ int AbstractCode::SourceStatementPosition(int offset) {
return statement_position;
}
bool Code::CanDeoptAt(Address pc) {
bool Code::CanDeoptAt(Isolate* isolate, Address pc) {
DeoptimizationData deopt_data =
DeoptimizationData::cast(deoptimization_data());
Address code_start_address = InstructionStart();
Address code_start_address = InstructionStart(isolate, pc);
for (int i = 0; i < deopt_data.DeoptCount(); i++) {
if (deopt_data.Pc(i).value() == -1) continue;
Address address = code_start_address + deopt_data.Pc(i).value();
@ -596,7 +609,7 @@ void Code::Disassemble(const char* name, std::ostream& os, Isolate* isolate,
os << "\n";
if (has_safepoint_info()) {
SafepointTable table(*this);
SafepointTable table(isolate, current_pc, *this);
os << "Safepoints (size = " << table.size() << ")\n";
for (unsigned i = 0; i < table.length(); i++) {
unsigned pc_offset = table.GetPcOffset(i);

View File

@ -150,6 +150,27 @@ class Code : public HeapObject {
inline Address InstructionEnd() const;
V8_EXPORT_PRIVATE Address OffHeapInstructionEnd() const;
// When builtins un-embedding (FLAG_short_builtin_calls) is enabled both
// embedded and un-embedded builtins might be exeuted and thus two kinds of
// |pc|s might appear on the stack.
// Unlike the paremeterless versions of the functions above the below variants
// ensure that the instruction start correspond to the given |pc| value.
// Thus for off-heap trampoline Code objects the result might be the
// instruction start/end of the embedded code stream or of un-embedded one.
// For normal Code objects these functions just return the
// raw_instruction_start/end() values.
// TODO(11527): remove these versions once the full solution is ready.
inline Address InstructionStart(Isolate* isolate, Address pc) const;
V8_EXPORT_PRIVATE Address OffHeapInstructionStart(Isolate* isolate,
Address pc) const;
inline Address InstructionEnd(Isolate* isolate, Address pc) const;
V8_EXPORT_PRIVATE Address OffHeapInstructionEnd(Isolate* isolate,
Address pc) const;
// Computes offset of the |pc| from the instruction start. The |pc| must
// belong to this code.
inline int GetOffsetFromInstructionStart(Isolate* isolate, Address pc) const;
inline int raw_instruction_size() const;
inline void set_raw_instruction_size(int value);
inline int InstructionSize() const;
@ -331,7 +352,7 @@ class Code : public HeapObject {
inline bool is_off_heap_trampoline() const;
// Get the safepoint entry for the given pc.
SafepointEntry GetSafepointEntry(Address pc);
SafepointEntry GetSafepointEntry(Isolate* isolate, Address pc);
// The entire code object including its header is copied verbatim to the
// snapshot so that it can be written in one, fast, memcpy during
@ -370,7 +391,7 @@ class Code : public HeapObject {
inline Address entry() const;
// Returns true if pc is inside this object's instructions.
inline bool contains(Address pc);
inline bool contains(Isolate* isolate, Address pc);
// Relocate the code by delta bytes. Called to signal that this code
// object has been moved by delta bytes.
@ -406,7 +427,7 @@ class Code : public HeapObject {
DECL_PRINTER(Code)
DECL_VERIFIER(Code)
bool CanDeoptAt(Address pc);
bool CanDeoptAt(Isolate* isolate, Address pc);
void SetMarkedForDeoptimization(const char* reason);

View File

@ -13,19 +13,11 @@
namespace v8 {
namespace internal {
// static
bool InstructionStream::PcIsOffHeap(Isolate* isolate, Address pc) {
const Address start =
reinterpret_cast<Address>(isolate->embedded_blob_code());
return start <= pc && pc < start + isolate->embedded_blob_code_size();
}
namespace {
// static
Builtins::Name InstructionStream::TryLookupCode(Isolate* isolate,
Address address) {
if (!PcIsOffHeap(isolate, address)) return Builtins::kNoBuiltinId;
Builtins::Name TryLookupCode(const EmbeddedData& d, Address address) {
if (!d.IsInCodeRange(address)) return Builtins::kNoBuiltinId;
EmbeddedData d = EmbeddedData::FromBlob(isolate);
if (address < d.InstructionStartOfBuiltin(0)) return Builtins::kNoBuiltinId;
// Note: Addresses within the padding section between builtins (i.e. within
@ -50,6 +42,58 @@ Builtins::Name InstructionStream::TryLookupCode(Isolate* isolate,
UNREACHABLE();
}
} // namespace
// static
bool InstructionStream::PcIsOffHeap(Isolate* isolate, Address pc) {
// Mksnapshot calls this while the embedded blob is not available yet.
if (isolate->embedded_blob_code() == nullptr) return false;
DCHECK_NOT_NULL(Isolate::CurrentEmbeddedBlobCode());
if (EmbeddedData::FromBlob(isolate).IsInCodeRange(pc)) return true;
return FLAG_short_builtin_calls && EmbeddedData::FromBlob().IsInCodeRange(pc);
}
// static
bool InstructionStream::TryGetAddressForHashing(Isolate* isolate,
Address address,
uint32_t* hashable_address) {
// Mksnapshot calls this while the embedded blob is not available yet.
if (isolate->embedded_blob_code() == nullptr) return false;
DCHECK_NOT_NULL(Isolate::CurrentEmbeddedBlobCode());
EmbeddedData d = EmbeddedData::FromBlob(isolate);
if (d.IsInCodeRange(address)) {
*hashable_address = d.AddressForHashing(address);
return true;
}
if (FLAG_short_builtin_calls) {
d = EmbeddedData::FromBlob();
if (d.IsInCodeRange(address)) {
*hashable_address = d.AddressForHashing(address);
return true;
}
}
return false;
}
// static
Builtins::Name InstructionStream::TryLookupCode(Isolate* isolate,
Address address) {
// Mksnapshot calls this while the embedded blob is not available yet.
if (isolate->embedded_blob_code() == nullptr) return Builtins::kNoBuiltinId;
DCHECK_NOT_NULL(Isolate::CurrentEmbeddedBlobCode());
Builtins::Name builtin =
i::TryLookupCode(EmbeddedData::FromBlob(isolate), address);
if (FLAG_short_builtin_calls && !Builtins::IsBuiltinId(builtin)) {
builtin = i::TryLookupCode(EmbeddedData::FromBlob(), address);
}
return builtin;
}
// static
void InstructionStream::CreateOffHeapInstructionStream(Isolate* isolate,
uint8_t** code,

View File

@ -23,6 +23,12 @@ class InstructionStream final : public AllStatic {
// Returns true, iff the given pc points into an off-heap instruction stream.
static bool PcIsOffHeap(Isolate* isolate, Address pc);
// If the address belongs to the embedded code blob, predictably converts it
// to uint32 by calculating offset from the embedded code blob start and
// returns true, and false otherwise.
static bool TryGetAddressForHashing(Isolate* isolate, Address address,
uint32_t* hashable_address);
// Returns the corresponding builtin ID if lookup succeeds, and kNoBuiltinId
// otherwise.
static Builtins::Name TryLookupCode(Isolate* isolate, Address address);
@ -61,6 +67,31 @@ class EmbeddedData final {
const uint8_t* data() const { return data_; }
uint32_t data_size() const { return data_size_; }
bool IsInCodeRange(Address pc) const {
Address start = reinterpret_cast<Address>(code_);
return (start <= pc) && (pc < start + code_size_);
}
// When FLAG_short_builtin_calls is enabled, there will be two builtins
// instruction streams executed: the embedded one and the one un-embedded into
// the per-Isolate code range. In most of the cases, the per-Isolate
// instructions will be used but in some cases (like builtin calls from Wasm)
// the embedded instruction stream could be used.
// If the requested PC belongs to the embedded code blob - it'll be returned,
// and the per-Isolate blob otherwise.
// See http://crbug.com/v8/11527 for details.
inline static EmbeddedData GetEmbeddedDataForPC(Isolate* isolate,
Address maybe_builtin_pc) {
EmbeddedData d = EmbeddedData::FromBlob(isolate);
if (FLAG_short_builtin_calls && !d.IsInCodeRange(maybe_builtin_pc)) {
EmbeddedData global_d = EmbeddedData::FromBlob();
// If the pc does not belong to the embedded code blob we should be using
// the un-embedded one.
if (global_d.IsInCodeRange(maybe_builtin_pc)) return global_d;
}
return d;
}
void Dispose() {
delete[] code_;
code_ = nullptr;
@ -78,8 +109,8 @@ class EmbeddedData final {
uint32_t MetadataSizeOfBuiltin(int i) const;
uint32_t AddressForHashing(Address addr) {
DCHECK(IsInCodeRange(addr));
Address start = reinterpret_cast<Address>(code_);
DCHECK(base::IsInRange(addr, start, start + code_size_));
return static_cast<uint32_t>(addr - start);
}

View File

@ -527,13 +527,14 @@ THREADED_TEST(Gc) {
static void StackCheck(Local<String> name,
const v8::PropertyCallbackInfo<v8::Value>& info) {
i::StackFrameIterator iter(reinterpret_cast<i::Isolate*>(info.GetIsolate()));
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
i::StackFrameIterator iter(isolate);
for (int i = 0; !iter.done(); i++) {
i::StackFrame* frame = iter.frame();
CHECK(i != 0 || (frame->type() == i::StackFrame::EXIT));
i::Code code = frame->LookupCode();
CHECK(code.IsCode());
CHECK(code.contains(frame->pc()));
CHECK(code.contains(isolate, frame->pc()));
iter.Advance();
}
}