[builtins] Support off-heap constant pool access

Access to the constant pool of off-heap builtins must use
Instruction{Start,Size} instead of the raw instruction_{start,size}
accessors, and we need to copy the constant_pool_offset field when
creating trampolines.

This in turn required access to the embedded blob without an
associated isolate, which is now implemented by global variable set by
each isolate. Both writes and reads are relaxed, as races do not
matter since each isolate will attempt to set the same value of the
blob and its size.

Drive-by: Support off-heap code disassembly.

Bug: v8:6666,v8:7575
Change-Id: I4f203acd4dc128339cf2dd54b3253d9552616649
Reviewed-on: https://chromium-review.googlesource.com/973442
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Reviewed-by: Michael Starzinger <mstarzinger@chromium.org>
Cr-Commit-Position: refs/heads/master@{#52209}
This commit is contained in:
jgruber 2018-03-26 09:44:12 +02:00 committed by Commit Bot
parent 451d0c7633
commit 4c5bf68ec8
15 changed files with 87 additions and 64 deletions

View File

@ -66,10 +66,8 @@ declare_args() {
v8_enable_fast_mksnapshot = false v8_enable_fast_mksnapshot = false
# Enable embedded builtins. # Enable embedded builtins.
# TODO(jgruber,v8:6666): Support ppc, ia32 and maybe MSVC. # TODO(jgruber,v8:6666): Support ia32 and maybe MSVC.
v8_enable_embedded_builtins = v8_enable_embedded_builtins = v8_current_cpu != "x86" && (!is_win || is_clang)
v8_current_cpu != "x86" && v8_current_cpu != "ppc" &&
v8_current_cpu != "ppc64" && (!is_win || is_clang)
# Enable code-generation-time checking of types in the CodeStubAssembler. # Enable code-generation-time checking of types in the CodeStubAssembler.
v8_enable_verify_csa = false v8_enable_verify_csa = false

View File

@ -195,12 +195,12 @@ Address Builtins::CppEntryOf(int index) {
} }
// static // static
bool Builtins::IsBuiltin(Code* code) { bool Builtins::IsBuiltin(const Code* code) {
return Builtins::IsBuiltinId(code->builtin_index()); return Builtins::IsBuiltinId(code->builtin_index());
} }
// static // static
bool Builtins::IsOffHeapBuiltin(Code* code) { bool Builtins::IsOffHeapBuiltin(const Code* code) {
#ifdef V8_EMBEDDED_BUILTINS #ifdef V8_EMBEDDED_BUILTINS
return Builtins::IsBuiltinId(code->builtin_index()) && return Builtins::IsBuiltinId(code->builtin_index()) &&
Builtins::IsOffHeapSafe(code->builtin_index()); Builtins::IsOffHeapSafe(code->builtin_index());

View File

@ -111,10 +111,10 @@ class Builtins {
// True, iff the given code object is a builtin. Note that this does not // True, iff the given code object is a builtin. Note that this does not
// necessarily mean that its kind is Code::BUILTIN. // necessarily mean that its kind is Code::BUILTIN.
static bool IsBuiltin(Code* code); static bool IsBuiltin(const Code* code);
// True, iff the given code object is a builtin with off-heap code. // True, iff the given code object is a builtin with off-heap code.
static bool IsOffHeapBuiltin(Code* code); static bool IsOffHeapBuiltin(const Code* code);
// Returns true iff the given builtin can be lazy-loaded from the snapshot. // Returns true iff the given builtin can be lazy-loaded from the snapshot.
// This is true in general for most builtins with the exception of a few // This is true in general for most builtins with the exception of a few

View File

@ -1877,6 +1877,7 @@ Handle<Code> Factory::NewOffHeapTrampolineFor(Handle<Code> code,
result->set_handler_table_offset(code->handler_table_offset()); result->set_handler_table_offset(code->handler_table_offset());
result->code_data_container()->set_kind_specific_flags( result->code_data_container()->set_kind_specific_flags(
code->code_data_container()->kind_specific_flags()); code->code_data_container()->kind_specific_flags());
result->set_constant_pool_offset(code->constant_pool_offset());
if (code->has_safepoint_info()) { if (code->has_safepoint_info()) {
result->set_safepoint_table_offset(code->safepoint_table_offset()); result->set_safepoint_table_offset(code->safepoint_table_offset());
} }

View File

@ -26,8 +26,7 @@ Code* InstructionStream::TryLookupCode(Isolate* isolate, Address address) {
#ifdef V8_EMBEDDED_BUILTINS #ifdef V8_EMBEDDED_BUILTINS
if (!PcIsOffHeap(isolate, address)) return nullptr; if (!PcIsOffHeap(isolate, address)) return nullptr;
EmbeddedData d = EmbeddedData::FromBlob(isolate->embedded_blob(), EmbeddedData d = EmbeddedData::FromBlob();
isolate->embedded_blob_size());
int l = 0, r = Builtins::builtin_count; int l = 0, r = Builtins::builtin_count;
while (l < r) { while (l < r) {

View File

@ -6,6 +6,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <atomic>
#include <fstream> // NOLINT(readability/streams) #include <fstream> // NOLINT(readability/streams)
#include <sstream> #include <sstream>
@ -75,9 +76,40 @@ extern const uint8_t* TrustedEmbeddedBlob();
extern uint32_t TrustedEmbeddedBlobSize(); extern uint32_t TrustedEmbeddedBlobSize();
#endif #endif
namespace {
// These variables provide access to the current embedded blob without requiring
// an isolate instance. This is needed e.g. by Code::InstructionStart, which may
// not have access to an isolate but still needs to access the embedded blob.
// The variables are initialized by each isolate in Init(). Writes and reads are
// relaxed since we can guarantee that the current thread has initialized these
// variables before accessing them. Different threads may race, but this is fine
// since they all attempt to set the same values of the blob pointer and size.
std::atomic<const uint8_t*> current_embedded_blob_(nullptr);
std::atomic<uint32_t> current_embedded_blob_size_(0);
} // namespace
void Isolate::SetEmbeddedBlob(const uint8_t* blob, uint32_t blob_size) {
embedded_blob_ = blob;
embedded_blob_size_ = blob_size;
current_embedded_blob_.store(blob, std::memory_order_relaxed);
current_embedded_blob_size_.store(blob_size, std::memory_order_relaxed);
}
const uint8_t* Isolate::embedded_blob() const { return embedded_blob_; } const uint8_t* Isolate::embedded_blob() const { return embedded_blob_; }
uint32_t Isolate::embedded_blob_size() const { return embedded_blob_size_; } uint32_t Isolate::embedded_blob_size() const { return embedded_blob_size_; }
#endif
// static
const uint8_t* Isolate::CurrentEmbeddedBlob() {
return current_embedded_blob_.load(std::memory_order::memory_order_relaxed);
}
// static
uint32_t Isolate::CurrentEmbeddedBlobSize() {
return current_embedded_blob_size_.load(
std::memory_order::memory_order_relaxed);
}
#endif // V8_EMBEDDED_BUILTINS
int ThreadId::AllocateThreadId() { int ThreadId::AllocateThreadId() {
int new_id = base::Relaxed_AtomicIncrement(&highest_thread_id_, 1); int new_id = base::Relaxed_AtomicIncrement(&highest_thread_id_, 1);
@ -2838,8 +2870,7 @@ void CreateOffHeapTrampolines(Isolate* isolate) {
HandleScope scope(isolate); HandleScope scope(isolate);
Builtins* builtins = isolate->builtins(); Builtins* builtins = isolate->builtins();
EmbeddedData d = EmbeddedData::FromBlob(isolate->embedded_blob(), EmbeddedData d = EmbeddedData::FromBlob();
isolate->embedded_blob_size());
CodeSpaceMemoryModificationScope code_allocation(isolate->heap()); CodeSpaceMemoryModificationScope code_allocation(isolate->heap());
for (int i = 0; i < Builtins::builtin_count; i++) { for (int i = 0; i < Builtins::builtin_count; i++) {
@ -2881,10 +2912,7 @@ void Isolate::PrepareEmbeddedBlobForSerialization() {
uint8_t* data; uint8_t* data;
uint32_t size; uint32_t size;
InstructionStream::CreateOffHeapInstructionStream(this, &data, &size); InstructionStream::CreateOffHeapInstructionStream(this, &data, &size);
SetEmbeddedBlob(const_cast<const uint8_t*>(data), size);
embedded_blob_ = const_cast<const uint8_t*>(data);
embedded_blob_size_ = size;
CreateOffHeapTrampolines(this); CreateOffHeapTrampolines(this);
} }
#endif // V8_EMBEDDED_BUILTINS #endif // V8_EMBEDDED_BUILTINS
@ -2948,15 +2976,12 @@ bool Isolate::Init(StartupDeserializer* des) {
#ifdef V8_EMBEDDED_BUILTINS #ifdef V8_EMBEDDED_BUILTINS
#ifdef V8_MULTI_SNAPSHOTS #ifdef V8_MULTI_SNAPSHOTS
if (FLAG_untrusted_code_mitigations) { if (FLAG_untrusted_code_mitigations) {
embedded_blob_ = DefaultEmbeddedBlob(); SetEmbeddedBlob(DefaultEmbeddedBlob(), DefaultEmbeddedBlobSize());
embedded_blob_size_ = DefaultEmbeddedBlobSize();
} else { } else {
embedded_blob_ = TrustedEmbeddedBlob(); SetEmbeddedBlob(TrustedEmbeddedBlob(), TrustedEmbeddedBlobSize());
embedded_blob_size_ = TrustedEmbeddedBlobSize();
} }
#else #else
embedded_blob_ = DefaultEmbeddedBlob(); SetEmbeddedBlob(DefaultEmbeddedBlob(), DefaultEmbeddedBlobSize());
embedded_blob_size_ = DefaultEmbeddedBlobSize();
#endif #endif
#endif #endif

View File

@ -1268,6 +1268,10 @@ class Isolate {
return builtins_constants_table_builder_; return builtins_constants_table_builder_;
} }
static const uint8_t* CurrentEmbeddedBlob();
static uint32_t CurrentEmbeddedBlobSize();
// TODO(jgruber): Remove these in favor of the static methods above.
const uint8_t* embedded_blob() const; const uint8_t* embedded_blob() const;
uint32_t embedded_blob_size() const; uint32_t embedded_blob_size() const;
#endif #endif
@ -1648,6 +1652,8 @@ class Isolate {
// which is stored on the root list prior to serialization. // which is stored on the root list prior to serialization.
BuiltinsConstantsTableBuilder* builtins_constants_table_builder_ = nullptr; BuiltinsConstantsTableBuilder* builtins_constants_table_builder_ = nullptr;
void SetEmbeddedBlob(const uint8_t* blob, uint32_t blob_size);
const uint8_t* embedded_blob_ = nullptr; const uint8_t* embedded_blob_ = nullptr;
uint32_t embedded_blob_size_ = 0; uint32_t embedded_blob_size_ = 0;
#endif #endif

View File

@ -966,8 +966,8 @@ void CodeDataContainer::CodeDataContainerVerify() {
} }
void Code::CodeVerify() { void Code::CodeVerify() {
CHECK_LE(constant_pool_offset(), instruction_size()); CHECK_LE(constant_pool_offset(), InstructionSize());
CHECK(IsAligned(reinterpret_cast<intptr_t>(instruction_start()), CHECK(IsAligned(reinterpret_cast<intptr_t>(InstructionStart()),
kCodeAlignment)); kCodeAlignment));
relocation_info()->ObjectVerify(); relocation_info()->ObjectVerify();
Address last_gc_pc = nullptr; Address last_gc_pc = nullptr;

View File

@ -14000,31 +14000,25 @@ SafepointEntry Code::GetSafepointEntry(Address pc) {
} }
#ifdef V8_EMBEDDED_BUILTINS #ifdef V8_EMBEDDED_BUILTINS
int Code::OffHeapInstructionSize() { int Code::OffHeapInstructionSize() const {
DCHECK(Builtins::IsOffHeapBuiltin(this)); DCHECK(Builtins::IsOffHeapBuiltin(this));
Isolate* isolate = GetIsolate(); if (Isolate::CurrentEmbeddedBlob() == nullptr) return instruction_size();
if (isolate->embedded_blob() == nullptr) return instruction_size(); EmbeddedData d = EmbeddedData::FromBlob();
EmbeddedData d = EmbeddedData::FromBlob(isolate->embedded_blob(),
isolate->embedded_blob_size());
return d.InstructionSizeOfBuiltin(builtin_index()); return d.InstructionSizeOfBuiltin(builtin_index());
} }
Address Code::OffHeapInstructionStart() { Address Code::OffHeapInstructionStart() const {
DCHECK(Builtins::IsOffHeapBuiltin(this)); DCHECK(Builtins::IsOffHeapBuiltin(this));
Isolate* isolate = GetIsolate(); if (Isolate::CurrentEmbeddedBlob() == nullptr) return instruction_start();
if (isolate->embedded_blob() == nullptr) return instruction_start(); EmbeddedData d = EmbeddedData::FromBlob();
EmbeddedData d = EmbeddedData::FromBlob(isolate->embedded_blob(),
isolate->embedded_blob_size());
return reinterpret_cast<Address>( return reinterpret_cast<Address>(
const_cast<uint8_t*>(d.InstructionStartOfBuiltin(builtin_index()))); const_cast<uint8_t*>(d.InstructionStartOfBuiltin(builtin_index())));
} }
Address Code::OffHeapInstructionEnd() { Address Code::OffHeapInstructionEnd() const {
DCHECK(Builtins::IsOffHeapBuiltin(this)); DCHECK(Builtins::IsOffHeapBuiltin(this));
Isolate* isolate = GetIsolate(); if (Isolate::CurrentEmbeddedBlob() == nullptr) return instruction_end();
if (isolate->embedded_blob() == nullptr) return instruction_end(); EmbeddedData d = EmbeddedData::FromBlob();
EmbeddedData d = EmbeddedData::FromBlob(isolate->embedded_blob(),
isolate->embedded_blob_size());
return reinterpret_cast<Address>( return reinterpret_cast<Address>(
const_cast<uint8_t*>(d.InstructionStartOfBuiltin(builtin_index()) + const_cast<uint8_t*>(d.InstructionStartOfBuiltin(builtin_index()) +
d.InstructionSizeOfBuiltin(builtin_index()))); d.InstructionSizeOfBuiltin(builtin_index())));
@ -14520,10 +14514,10 @@ void Code::Disassemble(const char* name, std::ostream& os, void* current_pc) {
os << "compiler = " << (is_turbofanned() ? "turbofan" : "unknown") << "\n"; os << "compiler = " << (is_turbofanned() ? "turbofan" : "unknown") << "\n";
os << "address = " << static_cast<const void*>(this) << "\n"; os << "address = " << static_cast<const void*>(this) << "\n";
os << "Body (size = " << instruction_size() << ")\n"; os << "Body (size = " << InstructionSize() << ")\n";
{ {
Isolate* isolate = GetIsolate(); Isolate* isolate = GetIsolate();
int size = instruction_size(); int size = InstructionSize();
int safepoint_offset = int safepoint_offset =
has_safepoint_info() ? safepoint_table_offset() : size; has_safepoint_info() ? safepoint_table_offset() : size;
int constant_pool_offset = this->constant_pool_offset(); int constant_pool_offset = this->constant_pool_offset();
@ -14533,7 +14527,7 @@ void Code::Disassemble(const char* name, std::ostream& os, void* current_pc) {
int code_size = int code_size =
Min(handler_offset, Min(safepoint_offset, constant_pool_offset)); Min(handler_offset, Min(safepoint_offset, constant_pool_offset));
os << "Instructions (size = " << code_size << ")\n"; os << "Instructions (size = " << code_size << ")\n";
byte* begin = instruction_start(); byte* begin = InstructionStart();
byte* end = begin + code_size; byte* end = begin + code_size;
Disassembler::Decode(isolate, &os, begin, end, this, current_pc); Disassembler::Decode(isolate, &os, begin, end, this, current_pc);
@ -14574,7 +14568,7 @@ void Code::Disassemble(const char* name, std::ostream& os, void* current_pc) {
os << "Safepoints (size = " << table.size() << ")\n"; os << "Safepoints (size = " << table.size() << ")\n";
for (unsigned i = 0; i < table.length(); i++) { for (unsigned i = 0; i < table.length(); i++) {
unsigned pc_offset = table.GetPcOffset(i); unsigned pc_offset = table.GetPcOffset(i);
os << static_cast<const void*>(instruction_start() + pc_offset) << " "; os << static_cast<const void*>(InstructionStart() + pc_offset) << " ";
os << std::setw(6) << std::hex << pc_offset << " " << std::setw(4); os << std::setw(6) << std::hex << pc_offset << " " << std::setw(4);
int trampoline_pc = table.GetTrampolinePcOffset(i); int trampoline_pc = table.GetTrampolinePcOffset(i);
print_pc(os, trampoline_pc); print_pc(os, trampoline_pc);

View File

@ -224,7 +224,7 @@ void Code::set_next_code_link(Object* value) {
code_data_container()->set_next_code_link(value); code_data_container()->set_next_code_link(value);
} }
int Code::InstructionSize() { int Code::InstructionSize() const {
#ifdef V8_EMBEDDED_BUILTINS #ifdef V8_EMBEDDED_BUILTINS
if (Builtins::IsOffHeapBuiltin(this)) return OffHeapInstructionSize(); if (Builtins::IsOffHeapBuiltin(this)) return OffHeapInstructionSize();
#endif #endif
@ -235,7 +235,7 @@ byte* Code::instruction_start() const {
return const_cast<byte*>(FIELD_ADDR_CONST(this, kHeaderSize)); return const_cast<byte*>(FIELD_ADDR_CONST(this, kHeaderSize));
} }
Address Code::InstructionStart() { Address Code::InstructionStart() const {
#ifdef V8_EMBEDDED_BUILTINS #ifdef V8_EMBEDDED_BUILTINS
if (Builtins::IsOffHeapBuiltin(this)) return OffHeapInstructionStart(); if (Builtins::IsOffHeapBuiltin(this)) return OffHeapInstructionStart();
#endif #endif
@ -246,7 +246,7 @@ byte* Code::instruction_end() const {
return instruction_start() + instruction_size(); return instruction_start() + instruction_size();
} }
Address Code::InstructionEnd() { Address Code::InstructionEnd() const {
#ifdef V8_EMBEDDED_BUILTINS #ifdef V8_EMBEDDED_BUILTINS
if (Builtins::IsOffHeapBuiltin(this)) return OffHeapInstructionEnd(); if (Builtins::IsOffHeapBuiltin(this)) return OffHeapInstructionEnd();
#endif #endif
@ -503,7 +503,7 @@ bool Code::is_optimized_code() const { return kind() == OPTIMIZED_FUNCTION; }
bool Code::is_wasm_code() const { return kind() == WASM_FUNCTION; } bool Code::is_wasm_code() const { return kind() == WASM_FUNCTION; }
int Code::constant_pool_offset() const { int Code::constant_pool_offset() const {
if (!FLAG_enable_embedded_constant_pool) return instruction_size(); if (!FLAG_enable_embedded_constant_pool) return InstructionSize();
return READ_INT_FIELD(this, kConstantPoolOffset); return READ_INT_FIELD(this, kConstantPoolOffset);
} }
@ -512,11 +512,11 @@ void Code::set_constant_pool_offset(int value) {
WRITE_INT_FIELD(this, kConstantPoolOffset, value); WRITE_INT_FIELD(this, kConstantPoolOffset, value);
} }
Address Code::constant_pool() { Address Code::constant_pool() const {
if (FLAG_enable_embedded_constant_pool) { if (FLAG_enable_embedded_constant_pool) {
int offset = constant_pool_offset(); int offset = constant_pool_offset();
if (offset < instruction_size()) { if (offset < InstructionSize()) {
return FIELD_ADDR(this, kHeaderSize + offset); return InstructionStart() + offset;
} }
} }
return nullptr; return nullptr;

View File

@ -63,9 +63,9 @@ class Code : public HeapObject {
// this may from instruction_size in that this will return the size of the // this may from instruction_size in that this will return the size of the
// off-heap instruction stream rather than the on-heap trampoline located // off-heap instruction stream rather than the on-heap trampoline located
// at instruction_start. // at instruction_start.
inline int InstructionSize(); inline int InstructionSize() const;
#ifdef V8_EMBEDDED_BUILTINS #ifdef V8_EMBEDDED_BUILTINS
int OffHeapInstructionSize(); int OffHeapInstructionSize() const;
#endif #endif
// [relocation_info]: Code relocation information // [relocation_info]: Code relocation information
@ -182,7 +182,7 @@ class Code : public HeapObject {
inline void set_is_exception_caught(bool flag); inline void set_is_exception_caught(bool flag);
// [constant_pool]: The constant pool for this function. // [constant_pool]: The constant pool for this function.
inline Address constant_pool(); inline Address constant_pool() const;
// Get the safepoint entry for the given pc. // Get the safepoint entry for the given pc.
SafepointEntry GetSafepointEntry(Address pc); SafepointEntry GetSafepointEntry(Address pc);
@ -219,9 +219,9 @@ class Code : public HeapObject {
// Returns the address of the first instruction. For off-heap code objects // Returns the address of the first instruction. For off-heap code objects
// this differs from instruction_start (which would point to the off-heap // this differs from instruction_start (which would point to the off-heap
// trampoline instead). // trampoline instead).
inline Address InstructionStart(); inline Address InstructionStart() const;
#ifdef V8_EMBEDDED_BUILTINS #ifdef V8_EMBEDDED_BUILTINS
Address OffHeapInstructionStart(); Address OffHeapInstructionStart() const;
#endif #endif
// Returns the address right after the last instruction. // Returns the address right after the last instruction.
@ -230,9 +230,9 @@ class Code : public HeapObject {
// Returns the address right after the last instruction. For off-heap code // Returns the address right after the last instruction. For off-heap code
// objects this differs from instruction_end (which would point to the // objects this differs from instruction_end (which would point to the
// off-heap trampoline instead). // off-heap trampoline instead).
inline Address InstructionEnd(); inline Address InstructionEnd() const;
#ifdef V8_EMBEDDED_BUILTINS #ifdef V8_EMBEDDED_BUILTINS
Address OffHeapInstructionEnd(); Address OffHeapInstructionEnd() const;
#endif #endif
// Returns the size of the instructions, padding, relocation and unwinding // Returns the size of the instructions, padding, relocation and unwinding

View File

@ -524,8 +524,7 @@ bool Deserializer<AllocatorT>::ReadData(MaybeObject** current,
reinterpret_cast<Address>(current) + skip); reinterpret_cast<Address>(current) + skip);
CHECK_NOT_NULL(isolate->embedded_blob()); CHECK_NOT_NULL(isolate->embedded_blob());
EmbeddedData d = EmbeddedData::FromBlob(isolate->embedded_blob(), EmbeddedData d = EmbeddedData::FromBlob();
isolate->embedded_blob_size());
const uint8_t* address = d.InstructionStartOfBuiltin(builtin_index); const uint8_t* address = d.InstructionStartOfBuiltin(builtin_index);
CHECK_NOT_NULL(address); CHECK_NOT_NULL(address);

View File

@ -353,8 +353,7 @@ v8::StartupData WarmUpSnapshotDataBlob(v8::SnapshotCreator* snapshot_creator,
void WriteEmbeddedFile(v8::SnapshotCreator* creator, SnapshotWriter* writer) { void WriteEmbeddedFile(v8::SnapshotCreator* creator, SnapshotWriter* writer) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(creator->GetIsolate()); i::Isolate* isolate = reinterpret_cast<i::Isolate*>(creator->GetIsolate());
isolate->PrepareEmbeddedBlobForSerialization(); isolate->PrepareEmbeddedBlobForSerialization();
i::EmbeddedData embedded_blob = i::EmbeddedData::FromBlob( i::EmbeddedData embedded_blob = i::EmbeddedData::FromBlob();
isolate->embedded_blob(), isolate->embedded_blob_size());
writer->WriteEmbedded(&embedded_blob); writer->WriteEmbedded(&embedded_blob);
} }
#endif // V8_EMBEDDED_BUILTINS #endif // V8_EMBEDDED_BUILTINS

View File

@ -394,7 +394,9 @@ EmbeddedData EmbeddedData::FromIsolate(Isolate* isolate) {
return {blob, blob_size}; return {blob, blob_size};
} }
EmbeddedData EmbeddedData::FromBlob(const uint8_t* data, uint32_t size) { EmbeddedData EmbeddedData::FromBlob() {
const uint8_t* data = Isolate::CurrentEmbeddedBlob();
uint32_t size = Isolate::CurrentEmbeddedBlobSize();
DCHECK_NOT_NULL(data); DCHECK_NOT_NULL(data);
DCHECK_LT(0, size); DCHECK_LT(0, size);
return {data, size}; return {data, size};

View File

@ -83,7 +83,7 @@ class BuiltinSnapshotData final : public SnapshotData {
class EmbeddedData final { class EmbeddedData final {
public: public:
static EmbeddedData FromIsolate(Isolate* isolate); static EmbeddedData FromIsolate(Isolate* isolate);
static EmbeddedData FromBlob(const uint8_t* data, uint32_t size); static EmbeddedData FromBlob();
const uint8_t* data() const { return data_; } const uint8_t* data() const { return data_; }
uint32_t size() const { return size_; } uint32_t size() const { return size_; }