[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:
parent
c665440b7f
commit
be4c28ebed
@ -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;
|
||||
|
@ -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: {
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user