Commit 7b4721f8 authored by Igor Sheludko's avatar Igor Sheludko Committed by V8 LUCI CQ

[ext-code-space] Introduce CodeLookupResult

... as a pair of Code and CodeDataContainer.

In order to stop creating and using trampoline Code objects for
builtins we need a different way to represent an "embedded builtin"
code lookup result of builtin trampoline Code objects.
We can't switch to CodeT for this purpose because GC still needs to
be able to locate not yet evacuated Code objects in order to update
old code pointers on the stack once Code objects are moved.

Bug: v8:11880
Change-Id: I296636a6728a11c8e3220b3fee43fd12ff633c1b
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3684813Reviewed-by: 's avatarDominik Inführ <dinfuehr@chromium.org>
Reviewed-by: 's avatarToon Verwaest <verwaest@chromium.org>
Commit-Queue: Igor Sheludko <ishell@chromium.org>
Cr-Commit-Position: refs/heads/main@{#80937}
parent 574b5611
......@@ -504,16 +504,18 @@ void RelocInfo::Verify(Isolate* isolate) {
CHECK_NE(addr, kNullAddress);
// Check that we can find the right code object.
Code code = Code::GetCodeFromTargetAddress(addr);
Object found = isolate->FindCodeObject(addr);
CHECK(found.IsCode());
CHECK(code.address() == HeapObject::cast(found).address());
CodeLookupResult lookup_result = isolate->FindCodeObject(addr);
CHECK(lookup_result.IsFound());
CHECK_EQ(code.address(), lookup_result.code().address());
break;
}
case INTERNAL_REFERENCE:
case INTERNAL_REFERENCE_ENCODED: {
Address target = target_internal_reference();
Address pc = target_internal_reference_address();
Code code = Code::cast(isolate->FindCodeObject(pc));
CodeLookupResult lookup_result = isolate->FindCodeObject(pc);
CHECK(lookup_result.IsFound());
Code code = lookup_result.code();
CHECK(target >= code.InstructionStart(isolate, pc));
CHECK(target <= code.InstructionEnd(isolate, pc));
break;
......
......@@ -16,6 +16,7 @@
#include "src/execution/isolate-inl.h"
#include "src/interpreter/bytecode-array-iterator.h"
#include "src/interpreter/bytecodes.h"
#include "src/objects/code-inl.h"
#include "src/objects/contexts.h"
#include "src/snapshot/snapshot.h"
......@@ -1207,10 +1208,11 @@ void DebugEvaluate::VerifyTransitiveBuiltins(Isolate* isolate) {
for (RelocIterator it(code, mode); !it.done(); it.next()) {
RelocInfo* rinfo = it.rinfo();
DCHECK(RelocInfo::IsCodeTargetMode(rinfo->rmode()));
Code callee_code = isolate->heap()->GcSafeFindCodeForInnerPointer(
rinfo->target_address());
if (!callee_code.is_builtin()) continue;
Builtin callee = static_cast<Builtin>(callee_code.builtin_id());
CodeLookupResult lookup_result =
isolate->heap()->GcSafeFindCodeForInnerPointer(
rinfo->target_address());
CHECK(lookup_result.IsFound());
Builtin callee = lookup_result.builtin_id();
if (BuiltinGetSideEffectState(callee) == DebugInfo::kHasNoSideEffect) {
continue;
}
......
......@@ -549,8 +549,9 @@ Deoptimizer::Deoptimizer(Isolate* isolate, JSFunction function,
Code Deoptimizer::FindOptimizedCode() {
Code compiled_code = FindDeoptimizingCode(from_);
return !compiled_code.is_null() ? compiled_code
: isolate_->FindCodeObject(from_);
if (!compiled_code.is_null()) return compiled_code;
CodeLookupResult lookup_result = isolate_->FindCodeObject(from_);
return lookup_result.code();
}
Handle<JSFunction> Deoptimizer::function() const {
......
......@@ -257,8 +257,10 @@ static void PrintRelocInfo(std::ostringstream& out, Isolate* isolate,
out << " ;; external reference (" << reference_name << ")";
} else if (RelocInfo::IsCodeTargetMode(rmode)) {
out << " ;; code:";
Code code = isolate->heap()->GcSafeFindCodeForInnerPointer(
relocinfo->target_address());
CodeT code =
isolate->heap()
->GcSafeFindCodeForInnerPointer(relocinfo->target_address())
.ToCodeT();
CodeKind kind = code.kind();
if (code.is_builtin()) {
out << " Builtin::" << Builtins::name(code.builtin_id());
......
......@@ -23,6 +23,7 @@
#include "src/execution/frames.h"
#include "src/handles/global-handles.h"
#include "src/init/bootstrapper.h"
#include "src/objects/code-inl.h"
#include "src/objects/objects.h"
#include "src/utils/ostreams.h"
#include "src/zone/zone-chunk-list.h"
......@@ -2063,8 +2064,10 @@ void EventHandler(const v8::JitCodeEvent* event) {
// use event->code_type here instead of finding the Code.
// TODO(zhin): Rename is_function to be more accurate.
if (event->code_type == v8::JitCodeEvent::JIT_CODE) {
Code code = isolate->heap()->GcSafeFindCodeForInnerPointer(addr);
is_function = CodeKindIsOptimizedJSFunction(code.kind());
CodeLookupResult lookup_result =
isolate->heap()->GcSafeFindCodeForInnerPointer(addr);
CHECK(lookup_result.IsFound());
is_function = CodeKindIsOptimizedJSFunction(lookup_result.kind());
}
AddCode(event_name.c_str(), {addr, event->code_len}, shared, lineinfo,
isolate, is_function);
......
......@@ -18,6 +18,7 @@
#include "src/objects/bigint.h"
#include "src/objects/call-site-info-inl.h"
#include "src/objects/cell-inl.h"
#include "src/objects/code-inl.h"
#include "src/objects/data-handler-inl.h"
#include "src/objects/debug-objects-inl.h"
#include "src/objects/elements.h"
......@@ -1088,9 +1089,11 @@ void CodeDataContainer::CodeDataContainerVerify(Isolate* isolate) {
// So, do a reverse Code object lookup via code_entry_point value to
// ensure it corresponds to the same Code object associated with this
// CodeDataContainer.
Code the_code = isolate->heap()->GcSafeFindCodeForInnerPointer(
code_entry_point());
CHECK_EQ(the_code, code());
CodeLookupResult lookup_result =
isolate->heap()->GcSafeFindCodeForInnerPointer(
code_entry_point());
CHECK(lookup_result.IsFound());
CHECK_EQ(lookup_result.ToCode(), code());
}
} else {
CHECK_EQ(code().InstructionStart(), code_entry_point());
......
......@@ -2920,11 +2920,14 @@ V8_EXPORT_PRIVATE extern void _v8_internal_Print_Code(void* object) {
return;
}
i::Code code = isolate->FindCodeObject(address);
if (!code.IsCode()) {
i::CodeLookupResult lookup_result = isolate->FindCodeObject(address);
if (!lookup_result.IsFound()) {
i::PrintF("No code object found containing %p\n", object);
return;
}
i::Code code = lookup_result.ToCode();
#ifdef ENABLE_DISASSEMBLER
i::StdoutStream os;
code.Disassemble(nullptr, os, isolate, address);
......
......@@ -19,7 +19,7 @@ class InnerPointerToCodeCache {
public:
struct InnerPointerToCodeCacheEntry {
Address inner_pointer;
Code code;
CodeLookupResult code;
SafepointEntry safepoint_entry;
};
......
This diff is collapsed.
......@@ -294,11 +294,13 @@ class StackFrame {
virtual Code unchecked_code() const = 0;
// Search for the code associated with this frame.
// TODO(v8:11880): migrate all usages to LookupCodeT().
V8_EXPORT_PRIVATE Code LookupCode() const;
V8_EXPORT_PRIVATE CodeLookupResult LookupCodeT() const;
virtual void Iterate(RootVisitor* v) const = 0;
void IteratePc(RootVisitor* v, Address* pc_address,
Address* constant_pool_address, Code holder) const;
Address* constant_pool_address, CodeLookupResult holder) const;
// Sets a callback function for return-address rewriting profilers
// to resolve the location of a return address to the location of the
......
......@@ -2269,21 +2269,23 @@ Isolate::CatchType Isolate::PredictExceptionCatcher() {
}
case StackFrame::STUB: {
Handle<Code> code(frame->LookupCode(), this);
if (!code->IsCode() || code->kind() != CodeKind::BUILTIN ||
!code->has_handler_table() || !code->is_turbofanned()) {
Code code = frame->LookupCode();
if (code.kind() != CodeKind::BUILTIN || !code.has_handler_table() ||
!code.is_turbofanned()) {
break;
}
CatchType prediction = ToCatchType(code->GetBuiltinCatchPrediction());
CatchType prediction = ToCatchType(code.GetBuiltinCatchPrediction());
if (prediction != NOT_CAUGHT) return prediction;
} break;
break;
}
case StackFrame::JAVA_SCRIPT_BUILTIN_CONTINUATION_WITH_CATCH: {
Handle<Code> code(frame->LookupCode(), this);
CatchType prediction = ToCatchType(code->GetBuiltinCatchPrediction());
Code code = frame->LookupCode();
CatchType prediction = ToCatchType(code.GetBuiltinCatchPrediction());
if (prediction != NOT_CAUGHT) return prediction;
} break;
break;
}
default:
// All other types can not handle exception.
......@@ -4547,7 +4549,7 @@ int Isolate::GenerateIdentityHash(uint32_t mask) {
return hash != 0 ? hash : 1;
}
Code Isolate::FindCodeObject(Address a) {
CodeLookupResult Isolate::FindCodeObject(Address a) {
return heap()->GcSafeFindCodeForInnerPointer(a);
}
......
......@@ -1569,7 +1569,7 @@ class V8_EXPORT_PRIVATE Isolate final : private HiddenFactory {
int GenerateIdentityHash(uint32_t mask);
// Given an address occupied by a live code object, return that object.
Code FindCodeObject(Address a);
CodeLookupResult FindCodeObject(Address a);
int NextOptimizationId() {
int id = next_optimization_id_++;
......
......@@ -7190,11 +7190,12 @@ Map Heap::GcSafeMapOfCodeSpaceObject(HeapObject object) {
return map_word.ToMap();
}
Code Heap::GcSafeCastToCode(HeapObject object, Address inner_pointer) {
CodeLookupResult Heap::GcSafeCastToCode(HeapObject object,
Address inner_pointer) {
Code code = Code::unchecked_cast(object);
DCHECK(!code.is_null());
DCHECK(GcSafeCodeContains(code, inner_pointer));
return code;
return CodeLookupResult{code};
}
bool Heap::GcSafeCodeContains(Code code, Address addr) {
......@@ -7211,11 +7212,11 @@ bool Heap::GcSafeCodeContains(Code code, Address addr) {
return start <= addr && addr < end;
}
Code Heap::GcSafeFindCodeForInnerPointer(Address inner_pointer) {
CodeLookupResult Heap::GcSafeFindCodeForInnerPointer(Address inner_pointer) {
Builtin maybe_builtin =
OffHeapInstructionStream::TryLookupCode(isolate(), inner_pointer);
if (Builtins::IsBuiltinId(maybe_builtin)) {
return FromCodeT(isolate()->builtins()->code(maybe_builtin));
return CodeLookupResult{isolate()->builtins()->code(maybe_builtin)};
}
if (V8_ENABLE_THIRD_PARTY_HEAP_BOOL) {
......@@ -7256,7 +7257,7 @@ Code Heap::GcSafeFindCodeForInnerPointer(Address inner_pointer) {
Code code = Code::cast(object);
if (inner_pointer >= code.address() &&
inner_pointer < code.address() + code.Size()) {
return code;
return CodeLookupResult{code};
}
}
// TODO(1241665): Remove once the issue is solved.
......
......@@ -1609,7 +1609,7 @@ class Heap {
// ===========================================================================
// Returns the Code object for a given interior pointer.
Code GcSafeFindCodeForInnerPointer(Address inner_pointer);
CodeLookupResult GcSafeFindCodeForInnerPointer(Address inner_pointer);
// Returns true if {addr} is contained within {code} and false otherwise.
// Mostly useful for debugging.
......@@ -1617,7 +1617,7 @@ class Heap {
// Casts a heap object to a code object and checks if the inner_pointer is
// within the object.
Code GcSafeCastToCode(HeapObject object, Address inner_pointer);
CodeLookupResult GcSafeCastToCode(HeapObject object, Address inner_pointer);
// Returns the map of an object. Can be used during garbage collection, i.e.
// it supports a forwarded map. Fails if the map is not the code map.
......
......@@ -332,6 +332,40 @@ inline CodeDataContainer CodeDataContainerFromCodeT(CodeT code) {
#endif
}
CodeKind CodeLookupResult::kind() const {
DCHECK(IsFound());
#ifdef V8_EXTERNAL_CODE_SPACE
return IsCode() ? code().kind() : code_data_container().kind();
#else
return code().kind();
#endif
}
Builtin CodeLookupResult::builtin_id() const {
DCHECK(IsFound());
#ifdef V8_EXTERNAL_CODE_SPACE
return IsCode() ? code().builtin_id() : code_data_container().builtin_id();
#else
return code().builtin_id();
#endif
}
Code CodeLookupResult::ToCode() const {
#ifdef V8_EXTERNAL_CODE_SPACE
return IsCode() ? code() : FromCodeT(code_data_container());
#else
return code();
#endif
}
CodeT CodeLookupResult::ToCodeT() const {
#ifdef V8_EXTERNAL_CODE_SPACE
return IsCodeDataContainer() ? code_data_container() : i::ToCodeT(code());
#else
return code();
#endif
}
void Code::WipeOutHeader() {
WRITE_FIELD(*this, kRelocationInfoOffset, Smi::FromInt(0));
WRITE_FIELD(*this, kDeoptimizationDataOrInterpreterDataOffset,
......@@ -418,12 +452,31 @@ Address Code::InstructionStart(Isolate* isolate, Address pc) const {
: raw_instruction_start();
}
#ifdef V8_EXTERNAL_CODE_SPACE
Address CodeDataContainer::InstructionStart(Isolate* isolate,
Address pc) const {
CHECK(V8_EXTERNAL_CODE_SPACE_BOOL);
return V8_UNLIKELY(is_off_heap_trampoline())
? OffHeapInstructionStart(isolate, pc)
: raw_instruction_start();
}
#endif
Address Code::InstructionEnd(Isolate* isolate, Address pc) const {
return V8_UNLIKELY(is_off_heap_trampoline())
? OffHeapInstructionEnd(isolate, pc)
: raw_instruction_end();
}
#ifdef V8_EXTERNAL_CODE_SPACE
Address CodeDataContainer::InstructionEnd(Isolate* isolate, Address pc) const {
CHECK(V8_EXTERNAL_CODE_SPACE_BOOL);
return V8_UNLIKELY(is_off_heap_trampoline())
? OffHeapInstructionEnd(isolate, pc)
: code().raw_instruction_end();
}
#endif
int Code::GetOffsetFromInstructionStart(Isolate* isolate, Address pc) const {
Address instruction_start = InstructionStart(isolate, pc);
Address offset = pc - instruction_start;
......@@ -1068,7 +1121,7 @@ Address CodeDataContainer::InstructionStart() const {
return code_entry_point();
}
Address CodeDataContainer::raw_instruction_start() {
Address CodeDataContainer::raw_instruction_start() const {
return code_entry_point();
}
......
......@@ -225,6 +225,15 @@ Address Code::OffHeapInstructionStart(Isolate* isolate, Address pc) const {
return d.InstructionStartOfBuiltin(builtin_id());
}
#ifdef V8_EXTERNAL_CODE_SPACE
Address CodeDataContainer::OffHeapInstructionStart(Isolate* isolate,
Address pc) const {
DCHECK(is_off_heap_trampoline());
EmbeddedData d = EmbeddedData::GetEmbeddedDataForPC(isolate, pc);
return d.InstructionStartOfBuiltin(builtin_id());
}
#endif
Address Code::OffHeapInstructionEnd(Isolate* isolate, Address pc) const {
DCHECK(is_off_heap_trampoline());
EmbeddedData d = EmbeddedData::GetEmbeddedDataForPC(isolate, pc);
......@@ -232,6 +241,16 @@ Address Code::OffHeapInstructionEnd(Isolate* isolate, Address pc) const {
d.InstructionSizeOfBuiltin(builtin_id());
}
#ifdef V8_EXTERNAL_CODE_SPACE
Address CodeDataContainer::OffHeapInstructionEnd(Isolate* isolate,
Address pc) const {
DCHECK(is_off_heap_trampoline());
EmbeddedData d = EmbeddedData::GetEmbeddedDataForPC(isolate, pc);
return d.InstructionStartOfBuiltin(builtin_id()) +
d.InstructionSizeOfBuiltin(builtin_id());
}
#endif
// TODO(cbruni): Move to BytecodeArray
int AbstractCode::SourcePosition(int offset) {
CHECK_NE(kind(), CodeKind::BASELINE);
......
......@@ -107,7 +107,7 @@ class CodeDataContainer : public HeapObject {
inline Address InstructionStart() const;
// Alias for code_entry_point to make it API compatible with Code.
inline Address raw_instruction_start();
inline Address raw_instruction_start() const;
// Alias for code_entry_point to make it API compatible with Code.
inline Address entry() const;
......@@ -156,6 +156,23 @@ class CodeDataContainer : public HeapObject {
DECL_GETTER(source_position_table, ByteArray)
DECL_GETTER(bytecode_offset_table, ByteArray)
// When builtins un-embedding is enabled for the Isolate
// (see Isolate::is_short_builtin_calls_enabled()) then 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.
Address OffHeapInstructionStart(Isolate* isolate, Address pc) const;
Address OffHeapInstructionEnd(Isolate* isolate, Address pc) const;
inline Address InstructionStart(Isolate* isolate, Address pc) const;
inline Address InstructionEnd(Isolate* isolate, Address pc) const;
#endif // V8_EXTERNAL_CODE_SPACE
DECL_CAST(CodeDataContainer)
......@@ -767,6 +784,108 @@ V8_EXPORT_PRIVATE Address OffHeapUnwindingInfoAddress(HeapObject code,
V8_EXPORT_PRIVATE int OffHeapUnwindingInfoSize(HeapObject code,
Builtin builtin);
// Represents result of the code by inner address (or pc) lookup.
// When V8_EXTERNAL_CODE_SPACE is disabled there might be two variants:
// - the pc does not correspond to any known code and IsFound() will return
// false,
// - the pc corresponds to existing Code object or embedded builtin (in which
// case the code() will return the respective Code object or the trampoline
// Code object that corresponds to the builtin).
//
// When V8_EXTERNAL_CODE_SPACE is enabled there might be three variants:
// - the pc does not correspond to any known code (in which case IsFound()
// will return false),
// - the pc corresponds to existing Code object (in which case the code() will
// return the respective Code object),
// - the pc corresponds to an embedded builtin (in which case the
// code_data_container() will return CodeDataContainer object corresponding
// to the builtin).
class CodeLookupResult {
public:
// Not found.
CodeLookupResult() = default;
// Code object was found.
explicit CodeLookupResult(Code code) : code_(code) {}
#ifdef V8_EXTERNAL_CODE_SPACE
// Embedded builtin was found.
explicit CodeLookupResult(CodeDataContainer code_data_container)
: code_data_container_(code_data_container) {}
#endif
// Returns true if the lookup was successful.
bool IsFound() const { return IsCode() || IsCodeDataContainer(); }
// Returns true if the lookup found a Code object.
bool IsCode() const { return !code_.is_null(); }
// Returns true if V8_EXTERNAL_CODE_SPACE is enabled and the lookup found
// an embedded builtin.
bool IsCodeDataContainer() const {
#ifdef V8_EXTERNAL_CODE_SPACE
return !code_data_container_.is_null();
#else
return false;
#endif
}
// Returns the Code object containing the address in question.
Code code() const {
DCHECK(IsCode());
return code_;
}
// Returns the CodeDataContainer object corresponding to an embedded builtin
// containing the address in question.
// Can be used only when V8_EXTERNAL_CODE_SPACE is enabled.
CodeDataContainer code_data_container() const {
#ifdef V8_EXTERNAL_CODE_SPACE
DCHECK(IsCodeDataContainer());
return code_data_container_;
#else
UNREACHABLE();
#endif
}
// Helper method, in case of successful lookup returns the kind() of
// the Code/CodeDataContainer object found.
// It's safe use from GC.
inline CodeKind kind() const;
// Helper method, in case of successful lookup returns the builtin_id() of
// the Code/CodeDataContainer object found.
// It's safe use from GC.
inline Builtin builtin_id() const;
// Helper method, coverts the successful lookup result to Code object.
// It's not safe to be used from GC because conversion to Code might perform
// a map check.
inline Code ToCode() const;
// Helper method, coverts the successful lookup result to CodeT object.
// It's not safe to be used from GC because conversion to CodeT might perform
// a map check.
inline CodeT ToCodeT() const;
bool operator==(const CodeLookupResult& other) const {
return code_ == other.code_
#ifdef V8_EXTERNAL_CODE_SPACE
&& code_data_container_ == other.code_data_container_
#endif
;
}
bool operator!=(const CodeLookupResult& other) const {
return !operator==(other);
}
private:
Code code_;
#ifdef V8_EXTERNAL_CODE_SPACE
CodeDataContainer code_data_container_;
#endif
};
class Code::OptimizedCodeIterator {
public:
explicit OptimizedCodeIterator(Isolate* isolate);
......
......@@ -252,16 +252,17 @@ static void CheckFindCodeObject(Isolate* isolate) {
Address obj_addr = obj.address();
for (int i = 0; i < obj.Size(cage_base); i += kTaggedSize) {
Object found = isolate->FindCodeObject(obj_addr + i);
CHECK_EQ(*code, found);
CodeLookupResult lookup_result = isolate->FindCodeObject(obj_addr + i);
CHECK_EQ(*code, lookup_result.code());
}
Handle<Code> copy =
Factory::CodeBuilder(isolate, desc, CodeKind::FOR_TESTING).Build();
HeapObject obj_copy = HeapObject::cast(*copy);
Object not_right = isolate->FindCodeObject(obj_copy.address() +
obj_copy.Size(cage_base) / 2);
CHECK(not_right != *code);
CodeLookupResult not_right = isolate->FindCodeObject(
obj_copy.address() + obj_copy.Size(cage_base) / 2);
CHECK_NE(not_right.code(), *code);
CHECK_EQ(not_right.code(), *copy);
}
......
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