Commit 87f09404 authored by Clemens Backes's avatar Clemens Backes Committed by Commit Bot

Move decoded asm.js offset table off-heap

The asm.js offset table exists in two forms: Delta-encoded in a byte
array, as generated during asm translation, and decoded, for faster
lookup.
This CL moves the encoded version from the {AsmWasmData} and
{WasmModuleObject} to the {WasmModule}, and stores it off-heap in a C++
array instead of a {ByteArray}.
Also, it moves the decoded version off-heap by storing it in a C++ data
structure that makes lookup easy, instead of encoding it again in
another {ByteArray}.

This change is a nice refactoring in itself, but it also prepares adding
more information to the offset table. For reconstructing the source code
of an asm.js function, we will need to store the start and end offsets
of the whole function as well (see linked bug).

R=jkummerow@chromium.org

Bug: chromium:667678
Change-Id: I79b789c3122dd8ba803cedc6bfdcc3d4b1fa0fd4
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2011108
Commit-Queue: Clemens Backes <clemensb@chromium.org>
Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#65900}
parent 182b43d4
...@@ -286,8 +286,8 @@ UnoptimizedCompilationJob::Status AsmJsCompilationJob::FinalizeJobImpl( ...@@ -286,8 +286,8 @@ UnoptimizedCompilationJob::Status AsmJsCompilationJob::FinalizeJobImpl(
->SyncCompileTranslatedAsmJs( ->SyncCompileTranslatedAsmJs(
isolate, &thrower, isolate, &thrower,
wasm::ModuleWireBytes(module_->begin(), module_->end()), wasm::ModuleWireBytes(module_->begin(), module_->end()),
Vector<const byte>(asm_offsets_->begin(), asm_offsets_->size()), VectorOf(*asm_offsets_), uses_bitset,
uses_bitset, shared_info->language_mode()) shared_info->language_mode())
.ToHandleChecked(); .ToHandleChecked();
DCHECK(!thrower.error()); DCHECK(!thrower.error());
compile_time_ = compile_timer.Elapsed().InMillisecondsF(); compile_time_ = compile_timer.Elapsed().InMillisecondsF();
......
...@@ -1674,7 +1674,6 @@ void AsmWasmData::AsmWasmDataPrint(std::ostream& os) { // NOLINT ...@@ -1674,7 +1674,6 @@ void AsmWasmData::AsmWasmDataPrint(std::ostream& os) { // NOLINT
PrintHeader(os, "AsmWasmData"); PrintHeader(os, "AsmWasmData");
os << "\n - native module: " << Brief(managed_native_module()); os << "\n - native module: " << Brief(managed_native_module());
os << "\n - export_wrappers: " << Brief(export_wrappers()); os << "\n - export_wrappers: " << Brief(export_wrappers());
os << "\n - offset table: " << Brief(asm_js_offset_table());
os << "\n - uses bitset: " << uses_bitset().value(); os << "\n - uses bitset: " << uses_bitset().value();
os << "\n"; os << "\n";
} }
...@@ -1763,9 +1762,6 @@ void WasmModuleObject::WasmModuleObjectPrint(std::ostream& os) { // NOLINT ...@@ -1763,9 +1762,6 @@ void WasmModuleObject::WasmModuleObjectPrint(std::ostream& os) { // NOLINT
os << "\n - native module: " << native_module(); os << "\n - native module: " << native_module();
os << "\n - export wrappers: " << Brief(export_wrappers()); os << "\n - export wrappers: " << Brief(export_wrappers());
os << "\n - script: " << Brief(script()); os << "\n - script: " << Brief(script());
if (has_asm_js_offset_table()) {
os << "\n - asm_js_offset_table: " << Brief(asm_js_offset_table());
}
os << "\n"; os << "\n";
} }
......
...@@ -1417,11 +1417,9 @@ WASM_SUMMARY_DISPATCH(int, byte_offset) ...@@ -1417,11 +1417,9 @@ WASM_SUMMARY_DISPATCH(int, byte_offset)
#undef WASM_SUMMARY_DISPATCH #undef WASM_SUMMARY_DISPATCH
int FrameSummary::WasmFrameSummary::SourcePosition() const { int FrameSummary::WasmFrameSummary::SourcePosition() const {
Handle<WasmModuleObject> module_object(wasm_instance()->module_object(), const wasm::WasmModule* module = wasm_instance()->module_object().module();
isolate()); return GetSourcePosition(module, function_index(), byte_offset(),
return WasmModuleObject::GetSourcePosition(module_object, function_index(), at_to_number_conversion());
byte_offset(),
at_to_number_conversion());
} }
Handle<Script> FrameSummary::WasmFrameSummary::script() const { Handle<Script> FrameSummary::WasmFrameSummary::script() const {
......
...@@ -2094,9 +2094,7 @@ bool Isolate::ComputeLocationFromStackTrace(MessageLocation* target, ...@@ -2094,9 +2094,7 @@ bool Isolate::ComputeLocationFromStackTrace(MessageLocation* target,
const int frame_count = elements->FrameCount(); const int frame_count = elements->FrameCount();
for (int i = 0; i < frame_count; i++) { for (int i = 0; i < frame_count; i++) {
if (elements->IsWasmFrame(i) || elements->IsAsmJsWasmFrame(i)) { if (elements->IsWasmFrame(i) || elements->IsAsmJsWasmFrame(i)) {
Handle<WasmInstanceObject> instance(elements->WasmInstance(i), this); int func_index = elements->WasmFunctionIndex(i).value();
uint32_t func_index =
static_cast<uint32_t>(elements->WasmFunctionIndex(i).value());
int offset = elements->Offset(i).value(); int offset = elements->Offset(i).value();
bool is_at_number_conversion = bool is_at_number_conversion =
elements->IsAsmJsWasmFrame(i) && elements->IsAsmJsWasmFrame(i) &&
...@@ -2110,9 +2108,10 @@ bool Isolate::ComputeLocationFromStackTrace(MessageLocation* target, ...@@ -2110,9 +2108,10 @@ bool Isolate::ComputeLocationFromStackTrace(MessageLocation* target,
offset = FrameSummary::WasmCompiledFrameSummary::GetWasmSourcePosition( offset = FrameSummary::WasmCompiledFrameSummary::GetWasmSourcePosition(
code, offset); code, offset);
} }
int pos = WasmModuleObject::GetSourcePosition( Handle<WasmInstanceObject> instance(elements->WasmInstance(i), this);
handle(instance->module_object(), this), func_index, offset, const wasm::WasmModule* module = elements->WasmInstance(i).module();
is_at_number_conversion); int pos = GetSourcePosition(module, func_index, offset,
is_at_number_conversion);
Handle<Script> script(instance->module_object().script(), this); Handle<Script> script(instance->module_object().script(), this);
*target = MessageLocation(script, pos, pos + 1); *target = MessageLocation(script, pos, pos + 1);
......
...@@ -654,12 +654,9 @@ int AsmJsWasmStackFrame::GetPosition() const { ...@@ -654,12 +654,9 @@ int AsmJsWasmStackFrame::GetPosition() const {
int byte_offset = int byte_offset =
FrameSummary::WasmCompiledFrameSummary::GetWasmSourcePosition(code_, FrameSummary::WasmCompiledFrameSummary::GetWasmSourcePosition(code_,
offset_); offset_);
Handle<WasmModuleObject> module_object(wasm_instance_->module_object(), const wasm::WasmModule* module = wasm_instance_->module();
isolate_); return GetSourcePosition(module, wasm_func_index_, byte_offset,
DCHECK_LE(0, byte_offset); is_at_number_conversion_);
return WasmModuleObject::GetSourcePosition(module_object, wasm_func_index_,
static_cast<uint32_t>(byte_offset),
is_at_number_conversion_);
} }
int AsmJsWasmStackFrame::GetLineNumber() { int AsmJsWasmStackFrame::GetLineNumber() {
......
...@@ -2030,21 +2030,20 @@ FunctionResult DecodeWasmFunctionForTesting( ...@@ -2030,21 +2030,20 @@ FunctionResult DecodeWasmFunctionForTesting(
std::make_unique<WasmFunction>()); std::make_unique<WasmFunction>());
} }
AsmJsOffsetsResult DecodeAsmJsOffsets(const byte* tables_start, AsmJsOffsetsResult DecodeAsmJsOffsets(Vector<const uint8_t> encoded_offsets) {
const byte* tables_end) { std::vector<AsmJsOffsetFunctionEntries> functions;
AsmJsOffsets table;
Decoder decoder(tables_start, tables_end); Decoder decoder(encoded_offsets);
uint32_t functions_count = decoder.consume_u32v("functions count"); uint32_t functions_count = decoder.consume_u32v("functions count");
// Reserve space for the entries, taking care of invalid input. // Reserve space for the entries, taking care of invalid input.
if (functions_count < static_cast<uint32_t>(tables_end - tables_start)) { if (functions_count < encoded_offsets.size()) {
table.reserve(functions_count); functions.reserve(functions_count);
} }
for (uint32_t i = 0; i < functions_count && decoder.ok(); ++i) { for (uint32_t i = 0; i < functions_count && decoder.ok(); ++i) {
uint32_t size = decoder.consume_u32v("table size"); uint32_t size = decoder.consume_u32v("table size");
if (size == 0) { if (size == 0) {
table.emplace_back(); functions.emplace_back();
continue; continue;
} }
if (!decoder.checkAvailable(size)) { if (!decoder.checkAvailable(size)) {
...@@ -2073,11 +2072,12 @@ AsmJsOffsetsResult DecodeAsmJsOffsets(const byte* tables_start, ...@@ -2073,11 +2072,12 @@ AsmJsOffsetsResult DecodeAsmJsOffsets(const byte* tables_start,
if (decoder.pc() != table_end) { if (decoder.pc() != table_end) {
decoder.error("broken asm offset table"); decoder.error("broken asm offset table");
} }
table.push_back(std::move(func_asm_offsets)); functions.emplace_back(
AsmJsOffsetFunctionEntries{std::move(func_asm_offsets)});
} }
if (decoder.more()) decoder.error("unexpected additional bytes"); if (decoder.more()) decoder.error("unexpected additional bytes");
return decoder.toResult(std::move(table)); return decoder.toResult(AsmJsOffsets{std::move(functions)});
} }
std::vector<CustomSectionOffset> DecodeCustomSections(const byte* start, std::vector<CustomSectionOffset> DecodeCustomSections(const byte* start,
......
...@@ -39,7 +39,12 @@ struct AsmJsOffsetEntry { ...@@ -39,7 +39,12 @@ struct AsmJsOffsetEntry {
int source_position_call; int source_position_call;
int source_position_number_conversion; int source_position_number_conversion;
}; };
using AsmJsOffsets = std::vector<std::vector<AsmJsOffsetEntry>>; struct AsmJsOffsetFunctionEntries {
std::vector<AsmJsOffsetEntry> entries;
};
struct AsmJsOffsets {
std::vector<AsmJsOffsetFunctionEntries> functions;
};
using AsmJsOffsetsResult = Result<AsmJsOffsets>; using AsmJsOffsetsResult = Result<AsmJsOffsets>;
class LocalName { class LocalName {
...@@ -151,11 +156,7 @@ V8_EXPORT_PRIVATE std::vector<CustomSectionOffset> DecodeCustomSections( ...@@ -151,11 +156,7 @@ V8_EXPORT_PRIVATE std::vector<CustomSectionOffset> DecodeCustomSections(
// Extracts the mapping from wasm byte offset to asm.js source position per // Extracts the mapping from wasm byte offset to asm.js source position per
// function. // function.
// Returns a vector of vectors with <byte_offset, source_position> entries, or AsmJsOffsetsResult DecodeAsmJsOffsets(Vector<const uint8_t> encoded_offsets);
// failure if the wasm bytes are detected as invalid. Note that this validation
// is not complete.
AsmJsOffsetsResult DecodeAsmJsOffsets(const byte* module_start,
const byte* module_end);
// Decode the function names from the name section. // Decode the function names from the name section.
// Returns the result as an unordered map. Only names with valid utf8 encoding // Returns the result as an unordered map. Only names with valid utf8 encoding
......
...@@ -316,6 +316,9 @@ MaybeHandle<AsmWasmData> WasmEngine::SyncCompileTranslatedAsmJs( ...@@ -316,6 +316,9 @@ MaybeHandle<AsmWasmData> WasmEngine::SyncCompileTranslatedAsmJs(
UNREACHABLE(); UNREACHABLE();
} }
result.value()->asm_js_offset_information =
std::make_unique<AsmJsOffsetInformation>(asm_js_offset_table_bytes);
// Transfer ownership of the WasmModule to the {Managed<WasmModule>} generated // Transfer ownership of the WasmModule to the {Managed<WasmModule>} generated
// in {CompileToNativeModule}. // in {CompileToNativeModule}.
Handle<FixedArray> export_wrappers; Handle<FixedArray> export_wrappers;
...@@ -324,15 +327,8 @@ MaybeHandle<AsmWasmData> WasmEngine::SyncCompileTranslatedAsmJs( ...@@ -324,15 +327,8 @@ MaybeHandle<AsmWasmData> WasmEngine::SyncCompileTranslatedAsmJs(
std::move(result).value(), bytes, &export_wrappers); std::move(result).value(), bytes, &export_wrappers);
if (!native_module) return {}; if (!native_module) return {};
// Create heap objects for asm.js offset table to be stored in the module
// object.
Handle<ByteArray> asm_js_offset_table =
isolate->factory()->NewByteArray(asm_js_offset_table_bytes.length());
asm_js_offset_table->copy_in(0, asm_js_offset_table_bytes.begin(),
asm_js_offset_table_bytes.length());
return AsmWasmData::New(isolate, std::move(native_module), export_wrappers, return AsmWasmData::New(isolate, std::move(native_module), export_wrappers,
asm_js_offset_table, uses_bitset); uses_bitset);
} }
Handle<WasmModuleObject> WasmEngine::FinalizeTranslatedAsmJs( Handle<WasmModuleObject> WasmEngine::FinalizeTranslatedAsmJs(
...@@ -344,7 +340,6 @@ Handle<WasmModuleObject> WasmEngine::FinalizeTranslatedAsmJs( ...@@ -344,7 +340,6 @@ Handle<WasmModuleObject> WasmEngine::FinalizeTranslatedAsmJs(
handle(asm_wasm_data->export_wrappers(), isolate); handle(asm_wasm_data->export_wrappers(), isolate);
Handle<WasmModuleObject> module_object = WasmModuleObject::New( Handle<WasmModuleObject> module_object = WasmModuleObject::New(
isolate, std::move(native_module), script, export_wrappers); isolate, std::move(native_module), script, export_wrappers);
module_object->set_asm_js_offset_table(asm_wasm_data->asm_js_offset_table());
return module_object; return module_object;
} }
......
...@@ -711,8 +711,6 @@ void WasmModuleBuilder::WriteAsmJsOffsetTable(ZoneBuffer* buffer) const { ...@@ -711,8 +711,6 @@ void WasmModuleBuilder::WriteAsmJsOffsetTable(ZoneBuffer* buffer) const {
for (auto* function : functions_) { for (auto* function : functions_) {
function->WriteAsmWasmOffsetTable(buffer); function->WriteAsmWasmOffsetTable(buffer);
} }
// Append a 0 to indicate that this is an encoded table.
buffer->write_u8(0);
} }
} // namespace wasm } // namespace wasm
} // namespace internal } // namespace internal
......
...@@ -122,6 +122,7 @@ class ZoneBuffer : public ZoneObject { ...@@ -122,6 +122,7 @@ class ZoneBuffer : public ZoneObject {
size_t offset() const { return static_cast<size_t>(pos_ - buffer_); } size_t offset() const { return static_cast<size_t>(pos_ - buffer_); }
size_t size() const { return static_cast<size_t>(pos_ - buffer_); } size_t size() const { return static_cast<size_t>(pos_ - buffer_); }
const byte* data() const { return buffer_; }
const byte* begin() const { return buffer_; } const byte* begin() const { return buffer_; }
const byte* end() const { return pos_; } const byte* end() const { return pos_; }
......
...@@ -111,6 +111,45 @@ void DecodedFunctionNames::AddForTesting(int function_index, ...@@ -111,6 +111,45 @@ void DecodedFunctionNames::AddForTesting(int function_index,
function_names_->insert(std::make_pair(function_index, name)); function_names_->insert(std::make_pair(function_index, name));
} }
AsmJsOffsetInformation::AsmJsOffsetInformation(
Vector<const byte> encoded_offsets)
: encoded_offsets_(OwnedVector<const uint8_t>::Of(encoded_offsets)) {}
AsmJsOffsetInformation::~AsmJsOffsetInformation() = default;
int AsmJsOffsetInformation::GetSourcePosition(int func_index, int byte_offset,
bool is_at_number_conversion) {
base::MutexGuard lock(&mutex_);
DCHECK_EQ(encoded_offsets_ == nullptr, decoded_offsets_ != nullptr);
if (!decoded_offsets_) {
AsmJsOffsetsResult result =
wasm::DecodeAsmJsOffsets(encoded_offsets_.as_vector());
decoded_offsets_ =
std::make_unique<AsmJsOffsets>(std::move(result).value());
encoded_offsets_.ReleaseData();
}
DCHECK_LE(0, func_index);
DCHECK_GT(decoded_offsets_->functions.size(), func_index);
std::vector<AsmJsOffsetEntry>& function_offsets =
decoded_offsets_->functions[func_index].entries;
auto byte_offset_less = [](const AsmJsOffsetEntry& a,
const AsmJsOffsetEntry& b) {
return a.byte_offset < b.byte_offset;
};
SLOW_DCHECK(std::is_sorted(function_offsets.begin(), function_offsets.end(),
byte_offset_less));
auto it =
std::lower_bound(function_offsets.begin(), function_offsets.end(),
AsmJsOffsetEntry{byte_offset, 0, 0}, byte_offset_less);
DCHECK_NE(function_offsets.end(), it);
DCHECK_EQ(byte_offset, it->byte_offset);
return is_at_number_conversion ? it->source_position_number_conversion
: it->source_position_call;
}
// Get a string stored in the module bytes representing a name. // Get a string stored in the module bytes representing a name.
WasmName ModuleWireBytes::GetNameOrNull(WireBytesRef ref) const { WasmName ModuleWireBytes::GetNameOrNull(WireBytesRef ref) const {
if (!ref.is_set()) return {nullptr, 0}; // no name. if (!ref.is_set()) return {nullptr, 0}; // no name.
...@@ -551,6 +590,27 @@ Handle<JSArray> GetCustomSections(Isolate* isolate, ...@@ -551,6 +590,27 @@ Handle<JSArray> GetCustomSections(Isolate* isolate,
return array_object; return array_object;
} }
// Get the source position from a given function index and byte offset,
// for either asm.js or pure Wasm modules.
int GetSourcePosition(const WasmModule* module, uint32_t func_index,
uint32_t byte_offset, bool is_at_number_conversion) {
DCHECK_EQ(is_asmjs_module(module),
module->asm_js_offset_information != nullptr);
if (!is_asmjs_module(module)) {
// For non-asm.js modules, we just add the function's start offset
// to make a module-relative position.
return byte_offset + GetWasmFunctionOffset(module, func_index);
}
// asm.js modules have an additional offset table that must be searched.
// Note: {AsmJsOffsetInformation::GetSourcePosition} expects the function
// index relative to the first non-imported function.
DCHECK_LE(module->num_imported_functions, func_index);
return module->asm_js_offset_information->GetSourcePosition(
func_index - module->num_imported_functions, byte_offset,
is_at_number_conversion);
}
namespace { namespace {
template <typename T> template <typename T>
inline size_t VectorSize(const std::vector<T>& vector) { inline size_t VectorSize(const std::vector<T>& vector) {
......
...@@ -25,6 +25,7 @@ namespace wasm { ...@@ -25,6 +25,7 @@ namespace wasm {
using WasmName = Vector<const char>; using WasmName = Vector<const char>;
struct AsmJsOffsets;
class ErrorThrower; class ErrorThrower;
// Reference to a string in the wire bytes. // Reference to a string in the wire bytes.
...@@ -191,6 +192,30 @@ class V8_EXPORT_PRIVATE DecodedFunctionNames { ...@@ -191,6 +192,30 @@ class V8_EXPORT_PRIVATE DecodedFunctionNames {
function_names_; function_names_;
}; };
class V8_EXPORT_PRIVATE AsmJsOffsetInformation {
public:
explicit AsmJsOffsetInformation(Vector<const byte> encoded_offsets);
// Destructor defined in wasm-module.cc, where the definition of
// {AsmJsOffsets} is available.
~AsmJsOffsetInformation();
int GetSourcePosition(int func_index, int byte_offset,
bool is_at_number_conversion);
private:
// The offset information table is decoded lazily, hence needs to be
// protected against concurrent accesses.
// Exactly one of the two fields below will be set at a time.
mutable base::Mutex mutex_;
// Holds the encoded offset table bytes.
OwnedVector<const uint8_t> encoded_offsets_;
// Holds the decoded offset table.
std::unique_ptr<AsmJsOffsets> decoded_offsets_;
};
// Static representation of a module. // Static representation of a module.
struct V8_EXPORT_PRIVATE WasmModule { struct V8_EXPORT_PRIVATE WasmModule {
std::unique_ptr<Zone> signature_zone; std::unique_ptr<Zone> signature_zone;
...@@ -230,6 +255,10 @@ struct V8_EXPORT_PRIVATE WasmModule { ...@@ -230,6 +255,10 @@ struct V8_EXPORT_PRIVATE WasmModule {
DecodedFunctionNames function_names; DecodedFunctionNames function_names;
std::string source_map_url; std::string source_map_url;
// Asm.js source position information. Only available for modules compiled
// from asm.js.
std::unique_ptr<AsmJsOffsetInformation> asm_js_offset_information;
explicit WasmModule(std::unique_ptr<Zone> signature_zone = nullptr); explicit WasmModule(std::unique_ptr<Zone> signature_zone = nullptr);
DISALLOW_COPY_AND_ASSIGN(WasmModule); DISALLOW_COPY_AND_ASSIGN(WasmModule);
...@@ -331,6 +360,11 @@ Handle<JSArray> GetCustomSections(Isolate* isolate, ...@@ -331,6 +360,11 @@ Handle<JSArray> GetCustomSections(Isolate* isolate,
Handle<WasmModuleObject> module, Handle<WasmModuleObject> module,
Handle<String> name, ErrorThrower* thrower); Handle<String> name, ErrorThrower* thrower);
// Get the source position from a given function index and byte offset,
// for either asm.js or pure Wasm modules.
int GetSourcePosition(const WasmModule*, uint32_t func_index,
uint32_t byte_offset, bool is_at_number_conversion);
// TruncatedUserString makes it easy to output names up to a certain length, and // TruncatedUserString makes it easy to output names up to a certain length, and
// output a truncation followed by '...' if they exceed a limit. // output a truncation followed by '...' if they exceed a limit.
// Use like this: // Use like this:
......
...@@ -88,8 +88,6 @@ ACCESSORS(WasmModuleObject, managed_native_module, Managed<wasm::NativeModule>, ...@@ -88,8 +88,6 @@ ACCESSORS(WasmModuleObject, managed_native_module, Managed<wasm::NativeModule>,
kNativeModuleOffset) kNativeModuleOffset)
ACCESSORS(WasmModuleObject, export_wrappers, FixedArray, kExportWrappersOffset) ACCESSORS(WasmModuleObject, export_wrappers, FixedArray, kExportWrappersOffset)
ACCESSORS(WasmModuleObject, script, Script, kScriptOffset) ACCESSORS(WasmModuleObject, script, Script, kScriptOffset)
OPTIONAL_ACCESSORS(WasmModuleObject, asm_js_offset_table, ByteArray,
kAsmJsOffsetTableOffset)
wasm::NativeModule* WasmModuleObject::native_module() const { wasm::NativeModule* WasmModuleObject::native_module() const {
return managed_native_module().raw(); return managed_native_module().raw();
} }
...@@ -104,7 +102,6 @@ const wasm::WasmModule* WasmModuleObject::module() const { ...@@ -104,7 +102,6 @@ const wasm::WasmModule* WasmModuleObject::module() const {
bool WasmModuleObject::is_asm_js() { bool WasmModuleObject::is_asm_js() {
bool asm_js = is_asmjs_module(module()); bool asm_js = is_asmjs_module(module());
DCHECK_EQ(asm_js, script().IsUserJavaScript()); DCHECK_EQ(asm_js, script().IsUserJavaScript());
DCHECK_EQ(asm_js, has_asm_js_offset_table());
return asm_js; return asm_js;
} }
...@@ -411,7 +408,6 @@ TQ_SMI_ACCESSORS(WasmExceptionTag, index) ...@@ -411,7 +408,6 @@ TQ_SMI_ACCESSORS(WasmExceptionTag, index)
ACCESSORS(AsmWasmData, managed_native_module, Managed<wasm::NativeModule>, ACCESSORS(AsmWasmData, managed_native_module, Managed<wasm::NativeModule>,
kManagedNativeModuleOffset) kManagedNativeModuleOffset)
ACCESSORS(AsmWasmData, export_wrappers, FixedArray, kExportWrappersOffset) ACCESSORS(AsmWasmData, export_wrappers, FixedArray, kExportWrappersOffset)
ACCESSORS(AsmWasmData, asm_js_offset_table, ByteArray, kAsmJsOffsetTableOffset)
ACCESSORS(AsmWasmData, uses_bitset, HeapNumber, kUsesBitsetOffset) ACCESSORS(AsmWasmData, uses_bitset, HeapNumber, kUsesBitsetOffset)
#include "src/objects/object-macros-undef.h" #include "src/objects/object-macros-undef.h"
......
...@@ -205,125 +205,6 @@ Handle<WasmModuleObject> WasmModuleObject::New( ...@@ -205,125 +205,6 @@ Handle<WasmModuleObject> WasmModuleObject::New(
return module_object; return module_object;
} }
namespace {
enum AsmJsOffsetTableEntryLayout {
kOTEByteOffset,
kOTECallPosition,
kOTENumberConvPosition,
kOTESize
};
Handle<ByteArray> GetDecodedAsmJsOffsetTable(
Handle<WasmModuleObject> module_object, Isolate* isolate) {
DCHECK(module_object->is_asm_js());
Handle<ByteArray> offset_table(module_object->asm_js_offset_table(), isolate);
// The last byte in the asm_js_offset_tables ByteArray tells whether it is
// still encoded (0) or decoded (1).
enum AsmJsTableType : int { Encoded = 0, Decoded = 1 };
int table_type = offset_table->get(offset_table->length() - 1);
DCHECK(table_type == Encoded || table_type == Decoded);
if (table_type == Decoded) return offset_table;
wasm::AsmJsOffsets asm_offsets;
{
DisallowHeapAllocation no_gc;
byte* bytes_start = offset_table->GetDataStartAddress();
byte* bytes_end = reinterpret_cast<byte*>(
reinterpret_cast<Address>(bytes_start) + offset_table->length() - 1);
asm_offsets = wasm::DecodeAsmJsOffsets(bytes_start, bytes_end).value();
}
// Wasm bytes must be valid and must contain asm.js offset table.
DCHECK_GE(kMaxInt, asm_offsets.size());
int num_functions = static_cast<int>(asm_offsets.size());
int num_imported_functions =
static_cast<int>(module_object->module()->num_imported_functions);
DCHECK_EQ(module_object->module()->functions.size(),
static_cast<size_t>(num_functions) + num_imported_functions);
int num_entries = 0;
for (int func = 0; func < num_functions; ++func) {
size_t new_size = asm_offsets[func].size();
DCHECK_LE(new_size, static_cast<size_t>(kMaxInt) - num_entries);
num_entries += static_cast<int>(new_size);
}
// One byte to encode that this is a decoded table.
DCHECK_GE(kMaxInt,
1 + static_cast<uint64_t>(num_entries) * kOTESize * kIntSize);
int total_size = 1 + num_entries * kOTESize * kIntSize;
Handle<ByteArray> decoded_table =
isolate->factory()->NewByteArray(total_size, AllocationType::kOld);
decoded_table->set(total_size - 1, AsmJsTableType::Decoded);
module_object->set_asm_js_offset_table(*decoded_table);
int idx = 0;
const std::vector<WasmFunction>& wasm_funs =
module_object->module()->functions;
for (int func = 0; func < num_functions; ++func) {
std::vector<wasm::AsmJsOffsetEntry>& func_asm_offsets = asm_offsets[func];
if (func_asm_offsets.empty()) continue;
int func_offset = wasm_funs[num_imported_functions + func].code.offset();
for (wasm::AsmJsOffsetEntry& e : func_asm_offsets) {
// Byte offsets must be strictly monotonously increasing:
DCHECK_IMPLIES(idx > 0, func_offset + e.byte_offset >
decoded_table->get_int(idx - kOTESize));
decoded_table->set_int(idx + kOTEByteOffset, func_offset + e.byte_offset);
decoded_table->set_int(idx + kOTECallPosition, e.source_position_call);
decoded_table->set_int(idx + kOTENumberConvPosition,
e.source_position_number_conversion);
idx += kOTESize;
}
}
DCHECK_EQ(total_size, idx * kIntSize + 1);
return decoded_table;
}
} // namespace
int WasmModuleObject::GetSourcePosition(Handle<WasmModuleObject> module_object,
uint32_t func_index,
uint32_t byte_offset,
bool is_at_number_conversion) {
Isolate* isolate = module_object->GetIsolate();
const WasmModule* module = module_object->module();
if (module->origin == wasm::kWasmOrigin) {
// for non-asm.js modules, we just add the function's start offset
// to make a module-relative position.
return byte_offset + GetWasmFunctionOffset(module, func_index);
}
// asm.js modules have an additional offset table that must be searched.
Handle<ByteArray> offset_table =
GetDecodedAsmJsOffsetTable(module_object, isolate);
DCHECK_LT(func_index, module->functions.size());
uint32_t func_code_offset = module->functions[func_index].code.offset();
uint32_t total_offset = func_code_offset + byte_offset;
// Binary search for the total byte offset.
int left = 0; // inclusive
int right = offset_table->length() / kIntSize / kOTESize; // exclusive
DCHECK_LT(left, right);
while (right - left > 1) {
int mid = left + (right - left) / 2;
int mid_entry = offset_table->get_int(kOTESize * mid);
DCHECK_GE(kMaxInt, mid_entry);
if (static_cast<uint32_t>(mid_entry) <= total_offset) {
left = mid;
} else {
right = mid;
}
}
// There should be an entry for each position that could show up on the stack
// trace:
DCHECK_EQ(total_offset, offset_table->get_int(kOTESize * left));
int idx = is_at_number_conversion ? kOTENumberConvPosition : kOTECallPosition;
return offset_table->get_int(kOTESize * left + idx);
}
Handle<String> WasmModuleObject::ExtractUtf8StringFromModuleBytes( Handle<String> WasmModuleObject::ExtractUtf8StringFromModuleBytes(
Isolate* isolate, Handle<WasmModuleObject> module_object, Isolate* isolate, Handle<WasmModuleObject> module_object,
wasm::WireBytesRef ref, InternalizeString internalize) { wasm::WireBytesRef ref, InternalizeString internalize) {
...@@ -2027,8 +1908,7 @@ Handle<WasmExceptionTag> WasmExceptionTag::New(Isolate* isolate, int index) { ...@@ -2027,8 +1908,7 @@ Handle<WasmExceptionTag> WasmExceptionTag::New(Isolate* isolate, int index) {
Handle<AsmWasmData> AsmWasmData::New( Handle<AsmWasmData> AsmWasmData::New(
Isolate* isolate, std::shared_ptr<wasm::NativeModule> native_module, Isolate* isolate, std::shared_ptr<wasm::NativeModule> native_module,
Handle<FixedArray> export_wrappers, Handle<ByteArray> asm_js_offset_table, Handle<FixedArray> export_wrappers, Handle<HeapNumber> uses_bitset) {
Handle<HeapNumber> uses_bitset) {
const WasmModule* module = native_module->module(); const WasmModule* module = native_module->module();
const bool kUsesLiftoff = false; const bool kUsesLiftoff = false;
size_t memory_estimate = size_t memory_estimate =
...@@ -2042,7 +1922,6 @@ Handle<AsmWasmData> AsmWasmData::New( ...@@ -2042,7 +1922,6 @@ Handle<AsmWasmData> AsmWasmData::New(
isolate->factory()->NewStruct(ASM_WASM_DATA_TYPE, AllocationType::kOld)); isolate->factory()->NewStruct(ASM_WASM_DATA_TYPE, AllocationType::kOld));
result->set_managed_native_module(*managed_native_module); result->set_managed_native_module(*managed_native_module);
result->set_export_wrappers(*export_wrappers); result->set_export_wrappers(*export_wrappers);
result->set_asm_js_offset_table(*asm_js_offset_table);
result->set_uses_bitset(*uses_bitset); result->set_uses_bitset(*uses_bitset);
return result; return result;
} }
......
...@@ -130,7 +130,6 @@ class WasmModuleObject : public JSObject { ...@@ -130,7 +130,6 @@ class WasmModuleObject : public JSObject {
DECL_ACCESSORS(managed_native_module, Managed<wasm::NativeModule>) DECL_ACCESSORS(managed_native_module, Managed<wasm::NativeModule>)
DECL_ACCESSORS(export_wrappers, FixedArray) DECL_ACCESSORS(export_wrappers, FixedArray)
DECL_ACCESSORS(script, Script) DECL_ACCESSORS(script, Script)
DECL_OPTIONAL_ACCESSORS(asm_js_offset_table, ByteArray)
inline wasm::NativeModule* native_module() const; inline wasm::NativeModule* native_module() const;
inline const std::shared_ptr<wasm::NativeModule>& shared_native_module() inline const std::shared_ptr<wasm::NativeModule>& shared_native_module()
const; const;
...@@ -182,12 +181,6 @@ class WasmModuleObject : public JSObject { ...@@ -182,12 +181,6 @@ class WasmModuleObject : public JSObject {
// Does not allocate, hence gc-safe. // Does not allocate, hence gc-safe.
Vector<const uint8_t> GetRawFunctionName(uint32_t func_index); Vector<const uint8_t> GetRawFunctionName(uint32_t func_index);
// Get the source position from a given function index and byte offset,
// for either asm.js or pure Wasm modules.
static int GetSourcePosition(Handle<WasmModuleObject>, uint32_t func_index,
uint32_t byte_offset,
bool is_at_number_conversion);
// Extract a portion of the wire bytes as UTF-8 string, optionally // Extract a portion of the wire bytes as UTF-8 string, optionally
// internalized. (Prefer to internalize early if the string will be used for a // internalized. (Prefer to internalize early if the string will be used for a
// property lookup anyway.) // property lookup anyway.)
...@@ -970,16 +963,16 @@ class WasmExceptionTag ...@@ -970,16 +963,16 @@ class WasmExceptionTag
TQ_OBJECT_CONSTRUCTORS(WasmExceptionTag) TQ_OBJECT_CONSTRUCTORS(WasmExceptionTag)
}; };
// Data annotated to the asm.js Module function. Used for later instantiation of
// that function.
class AsmWasmData : public Struct { class AsmWasmData : public Struct {
public: public:
static Handle<AsmWasmData> New( static Handle<AsmWasmData> New(
Isolate* isolate, std::shared_ptr<wasm::NativeModule> native_module, Isolate* isolate, std::shared_ptr<wasm::NativeModule> native_module,
Handle<FixedArray> export_wrappers, Handle<ByteArray> asm_js_offset_table, Handle<FixedArray> export_wrappers, Handle<HeapNumber> uses_bitset);
Handle<HeapNumber> uses_bitset);
DECL_ACCESSORS(managed_native_module, Managed<wasm::NativeModule>) DECL_ACCESSORS(managed_native_module, Managed<wasm::NativeModule>)
DECL_ACCESSORS(export_wrappers, FixedArray) DECL_ACCESSORS(export_wrappers, FixedArray)
DECL_ACCESSORS(asm_js_offset_table, ByteArray)
DECL_ACCESSORS(uses_bitset, HeapNumber) DECL_ACCESSORS(uses_bitset, HeapNumber)
DECL_CAST(AsmWasmData) DECL_CAST(AsmWasmData)
......
...@@ -58,7 +58,6 @@ extern class WasmModuleObject extends JSObject { ...@@ -58,7 +58,6 @@ extern class WasmModuleObject extends JSObject {
native_module: Foreign; native_module: Foreign;
export_wrappers: FixedArray; export_wrappers: FixedArray;
script: Script; script: Script;
asm_js_offset_table: ByteArray|Undefined;
} }
extern class WasmTableObject extends JSObject { extern class WasmTableObject extends JSObject {
...@@ -92,6 +91,5 @@ type WasmExportedFunction extends JSFunction; ...@@ -92,6 +91,5 @@ type WasmExportedFunction extends JSFunction;
extern class AsmWasmData extends Struct { extern class AsmWasmData extends Struct {
managed_native_module: Foreign; // Managed<wasm::NativeModule> managed_native_module: Foreign; // Managed<wasm::NativeModule>
export_wrappers: FixedArray; export_wrappers: FixedArray;
asm_js_offset_table: ByteArray;
uses_bitset: HeapNumber; uses_bitset: HeapNumber;
} }
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