Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(819)

Unified Diff: src/wasm/wasm-module.cc

Issue 2345593003: [wasm] Master CL for Binary 0xC changes. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Fix test failures and TSAN races. Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/wasm/wasm-module.h ('k') | src/wasm/wasm-opcodes.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/wasm/wasm-module.cc
diff --git a/src/wasm/wasm-module.cc b/src/wasm/wasm-module.cc
index 582e5eb07bad1ae6f6ee667c3981dc6e2c3d7121..4f0b885ee020c91fd12bc500dab0d8a9643b6aa2 100644
--- a/src/wasm/wasm-module.cc
+++ b/src/wasm/wasm-module.cc
@@ -18,6 +18,7 @@
#include "src/wasm/module-decoder.h"
#include "src/wasm/wasm-debug.h"
#include "src/wasm/wasm-function-name-table.h"
+#include "src/wasm/wasm-js.h"
#include "src/wasm/wasm-module.h"
#include "src/wasm/wasm-result.h"
@@ -27,6 +28,39 @@ namespace v8 {
namespace internal {
namespace wasm {
+const char* SectionName(WasmSectionCode code) {
+ switch (code) {
+ case kUnknownSectionCode:
+ return "Unknown";
+ case kTypeSectionCode:
+ return "Type";
+ case kImportSectionCode:
+ return "Import";
+ case kFunctionSectionCode:
+ return "Function";
+ case kTableSectionCode:
+ return "Table";
+ case kMemorySectionCode:
+ return "Memory";
+ case kGlobalSectionCode:
+ return "Global";
+ case kExportSectionCode:
+ return "Export";
+ case kStartSectionCode:
+ return "Start";
+ case kCodeSectionCode:
+ return "Code";
+ case kElementSectionCode:
+ return "Element";
+ case kDataSectionCode:
+ return "Data";
+ case kNameSectionCode:
+ return "Name";
+ default:
+ return "<unknown>";
+ }
+}
+
enum JSFunctionExportInternalField {
kInternalModuleInstance,
kInternalArity,
@@ -35,59 +69,6 @@ enum JSFunctionExportInternalField {
static const int kPlaceholderMarker = 1000000000;
-static const char* wasmSections[] = {
-#define F(enumerator, order, string) string,
- FOR_EACH_WASM_SECTION_TYPE(F)
-#undef F
- "<unknown>" // entry for "Max"
-};
-
-static uint8_t wasmSectionsLengths[]{
-#define F(enumerator, order, string) sizeof(string) - 1,
- FOR_EACH_WASM_SECTION_TYPE(F)
-#undef F
- 9 // entry for "Max"
-};
-
-static uint8_t wasmSectionsOrders[]{
-#define F(enumerator, order, string) order,
- FOR_EACH_WASM_SECTION_TYPE(F)
-#undef F
- 0 // entry for "Max"
-};
-
-static_assert(sizeof(wasmSections) / sizeof(wasmSections[0]) ==
- (size_t)WasmSection::Code::Max + 1,
- "expected enum WasmSection::Code to be monotonic from 0");
-
-WasmSection::Code WasmSection::begin() { return (WasmSection::Code)0; }
-WasmSection::Code WasmSection::end() { return WasmSection::Code::Max; }
-WasmSection::Code WasmSection::next(WasmSection::Code code) {
- return (WasmSection::Code)(1 + (uint32_t)code);
-}
-
-const char* WasmSection::getName(WasmSection::Code code) {
- return wasmSections[(size_t)code];
-}
-
-size_t WasmSection::getNameLength(WasmSection::Code code) {
- return wasmSectionsLengths[(size_t)code];
-}
-
-int WasmSection::getOrder(WasmSection::Code code) {
- return wasmSectionsOrders[(size_t)code];
-}
-
-WasmSection::Code WasmSection::lookup(const byte* string, uint32_t length) {
- // TODO(jfb) Linear search, it may be better to do a common-prefix search.
- for (Code i = begin(); i != end(); i = next(i)) {
- if (getNameLength(i) == length && 0 == memcmp(getName(i), string, length)) {
- return i;
- }
- }
- return Code::Max;
-}
-
std::ostream& operator<<(std::ostream& os, const WasmModule& module) {
os << "WASM module with ";
os << (module.min_mem_pages * module.kPageSize) << " min mem";
@@ -158,7 +139,7 @@ Object* GetOwningWasmInstance(Object* undefined, Code* code) {
namespace {
// Internal constants for the layout of the module object.
-enum WasmInstanceFields {
+enum WasmInstanceObjectFields {
kWasmCompiledModule = 0,
kWasmModuleFunctionTable,
kWasmModuleCodeTable,
@@ -169,6 +150,7 @@ enum WasmInstanceFields {
kWasmFunctionNamesArray,
kWasmModuleBytesString,
kWasmDebugInfo,
+ kWasmNumImportedFunctions,
kWasmModuleInternalFieldCount
};
@@ -178,17 +160,15 @@ enum WasmInstanceFields {
// the compiled module is either obtained from the current v8 instance, or from
// a snapshot produced by a compatible (==identical) v8 instance, we simply
// fail at instantiation time, in the face of invalid data.
-enum CompiledWasmObjectFields {
- kFunctions, // FixedArray of Code
- kImportData, // maybe FixedArray of FixedArray respecting the
- // WasmImportMetadata structure.
- kImportMap, // FixedArray. The i-th element is the Code object used for
- // import i
- kExports, // maybe FixedArray of FixedArray of WasmExportMetadata
- // structure
- kStartupFunction, // maybe FixedArray of WasmExportMetadata structure
+enum WasmCompiledModule {
+ kCodeTable, // FixedArray of Code
+ kImportData, // maybe FixedArray of FixedArray respecting the
+ // WasmImportData structure.
+ kExportData, // maybe FixedArray of FixedArray of WasmExportData
+ // structure
+ kStartupData, // maybe FixedArray of WasmExportData structure
kTableOfIndirectFunctionTables, // maybe FixedArray of FixedArray of
- // WasmIndirectFunctionTableMetadata
+ // WasmIndirectFunctionTableData
kModuleBytes, // maybe String
kFunctionNameTable, // maybe ByteArray
kMinRequiredMemory, // Smi. an uint32_t
@@ -197,33 +177,32 @@ enum CompiledWasmObjectFields {
// WasmSegmentInfo structure
kDataSegments, // maybe ByteArray.
- kGlobalsSize, // Smi. an uint32_t
- kMemSize, // Smi.an uint32_t
- kMemStart, // MaybeHandle<ArrayBuffer>
- kExportMem, // Smi. bool
- kOrigin, // Smi. ModuleOrigin
- kNextInstance, // WeakCell. See compiled code cloning.
- kPrevInstance, // WeakCell. See compiled code cloning.
- kOwningInstance, // WeakCell, pointing to the owning instance.
- kModuleObject, // WeakCell, pointing to the module object.
- kCompiledWasmObjectTableSize // Sentinel value.
+ kGlobalsSize, // Smi. an uint32_t
+ kMemSize, // Smi.an uint32_t
+ kMemStart, // MaybeHandle<ArrayBuffer>
+ kExportMem, // Smi. bool
+ kOrigin, // Smi. ModuleOrigin
+ kNextInstance, // WeakCell. See compiled code cloning.
+ kPrevInstance, // WeakCell. See compiled code cloning.
+ kOwningInstance, // WeakCell, pointing to the owning instance.
+ kModuleObject, // WeakCell, pointing to the module object.
+ kWasmCompiledModuleSize // Sentinel value.
};
-enum WasmImportMetadata {
- kModuleName, // String
- kFunctionName, // maybe String
- kOutputCount, // Smi. an uint32_t
- kSignature, // ByteArray. A copy of the data in FunctionSig
- kWasmImportDataTableSize // Sentinel value.
+enum WasmImportData {
+ kModuleName, // String
+ kFunctionName, // maybe String
+ kOutputCount, // Smi. an uint32_t
+ kSignature, // ByteArray. A copy of the data in FunctionSig
+ kWasmImportDataSize // Sentinel value.
};
-enum WasmExportMetadata {
- kExportCode, // Code
- kExportName, // String
- kExportArity, // Smi, an int
- kExportedFunctionIndex, // Smi, an uint32_t
- kExportedSignature, // ByteArray. A copy of the data in FunctionSig
- kWasmExportMetadataTableSize // Sentinel value.
+enum WasmExportData {
+ kExportName, // String
+ kExportArity, // Smi, an int
+ kExportedFunctionIndex, // Smi, an uint32_t
+ kExportedSignature, // ByteArray. A copy of the data in FunctionSig
+ kWasmExportDataSize // Sentinel value.
};
enum WasmSegmentInfo {
@@ -232,10 +211,10 @@ enum WasmSegmentInfo {
kWasmSegmentInfoSize // Sentinel value.
};
-enum WasmIndirectFunctionTableMetadata {
- kSize, // Smi. an uint32_t
- kTable, // FixedArray of indirect function table
- kWasmIndirectFunctionTableMetadataSize // Sentinel value.
+enum WasmIndirectFunctionTableData {
+ kSize, // Smi. an uint32_t
+ kTable, // FixedArray of indirect function table
+ kWasmIndirectFunctionTableDataSize // Sentinel value.
};
uint32_t GetMinModuleMemSize(const WasmModule* module) {
@@ -279,7 +258,6 @@ void SaveDataSegmentInfo(Factory* factory, const WasmModule* module,
static_cast<int>(module->data_segments.size()), TENURED);
uint32_t data_size = 0;
for (const WasmDataSegment& segment : module->data_segments) {
- if (!segment.init) continue;
if (segment.source_size == 0) continue;
data_size += segment.source_size;
}
@@ -288,11 +266,12 @@ void SaveDataSegmentInfo(Factory* factory, const WasmModule* module,
uint32_t last_insertion_pos = 0;
for (uint32_t i = 0; i < module->data_segments.size(); ++i) {
const WasmDataSegment& segment = module->data_segments[i];
- if (!segment.init) continue;
if (segment.source_size == 0) continue;
Handle<ByteArray> js_segment =
factory->NewByteArray(kWasmSegmentInfoSize * sizeof(uint32_t), TENURED);
- js_segment->set_int(kDestAddr, segment.dest_addr);
+ // TODO(titzer): add support for global offsets for dest_addr
+ CHECK_EQ(WasmInitExpr::kI32Const, segment.dest_addr.kind);
+ js_segment->set_int(kDestAddr, segment.dest_addr.val.i32_const);
js_segment->set_int(kSourceSize, segment.source_size);
segments->set(i, *js_segment);
data->copy_in(last_insertion_pos,
@@ -401,86 +380,67 @@ Handle<Code> CreatePlaceholder(Factory* factory, uint32_t index,
return code;
}
-// TODO(mtrofin): remove when we stop relying on placeholders.
-void InitializePlaceholders(Factory* factory,
- std::vector<Handle<Code>>* placeholders,
- size_t size) {
- DCHECK(placeholders->empty());
- placeholders->reserve(size);
-
- for (uint32_t i = 0; i < size; ++i) {
- placeholders->push_back(CreatePlaceholder(factory, i, Code::WASM_FUNCTION));
- }
-}
-
-bool LinkFunction(Isolate* isolate, Handle<Code> unlinked,
- Handle<FixedArray> code_targets,
- Code::Kind kind = Code::WASM_FUNCTION) {
+bool LinkFunction(Handle<Code> unlinked,
+ std::vector<Handle<Code>>& code_table) {
bool modified = false;
int mode_mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET);
AllowDeferredHandleDereference embedding_raw_address;
for (RelocIterator it(*unlinked, mode_mask); !it.done(); it.next()) {
- Code* target = Code::GetCodeFromTargetAddress(it.rinfo()->target_address());
- if (target->kind() == kind &&
- target->constant_pool_offset() >= kPlaceholderMarker) {
- // Patch direct calls to placeholder code objects.
- uint32_t index = target->constant_pool_offset() - kPlaceholderMarker;
- CHECK(index < static_cast<uint32_t>(code_targets->length()));
- Handle<Code> new_target =
- code_targets->GetValueChecked<Code>(isolate, index);
- if (target != *new_target) {
- it.rinfo()->set_target_address(new_target->instruction_start(),
- UPDATE_WRITE_BARRIER, SKIP_ICACHE_FLUSH);
- modified = true;
+ RelocInfo::Mode mode = it.rinfo()->rmode();
+ if (RelocInfo::IsCodeTarget(mode)) {
+ Code* target =
+ Code::GetCodeFromTargetAddress(it.rinfo()->target_address());
+ if (target->constant_pool_offset() < kPlaceholderMarker) continue;
+ switch (target->kind()) {
+ case Code::WASM_FUNCTION: // fall through
+ case Code::WASM_TO_JS_FUNCTION: // fall through
+ case Code::JS_TO_WASM_FUNCTION: {
+ // Patch direct calls to placeholder code objects.
+ uint32_t index = target->constant_pool_offset() - kPlaceholderMarker;
+ Handle<Code> new_target = code_table[index];
+ if (target != *new_target) {
+ it.rinfo()->set_target_address(new_target->instruction_start(),
+ UPDATE_WRITE_BARRIER,
+ SKIP_ICACHE_FLUSH);
+ modified = true;
+ }
+ break;
+ }
+ default:
+ break;
}
}
}
return modified;
}
-void LinkModuleFunctions(Isolate* isolate, Handle<FixedArray> functions) {
- for (int i = 0; i < functions->length(); ++i) {
- Handle<Code> code = functions->GetValueChecked<Code>(isolate, i);
- LinkFunction(isolate, code, functions);
- }
-}
-
-void FlushAssemblyCache(Isolate* isolate, Handle<FixedArray> functions) {
+void FlushICache(Isolate* isolate, Handle<FixedArray> functions) {
for (int i = 0; i < functions->length(); ++i) {
Handle<Code> code = functions->GetValueChecked<Code>(isolate, i);
Assembler::FlushICache(isolate, code->instruction_start(),
code->instruction_size());
}
}
+} // namespace
-void SetRuntimeSupport(Isolate* isolate, Handle<JSObject> js_object) {
- Handle<FixedArray> functions = Handle<FixedArray>(
- FixedArray::cast(js_object->GetInternalField(kWasmModuleCodeTable)));
- Handle<WeakCell> weak_link = isolate->factory()->NewWeakCell(js_object);
-
- for (int i = FLAG_skip_compiling_wasm_funcs; i < functions->length(); ++i) {
- Handle<Code> code = functions->GetValueChecked<Code>(isolate, i);
- Handle<FixedArray> deopt_data =
- isolate->factory()->NewFixedArray(2, TENURED);
- deopt_data->set(0, *weak_link);
- deopt_data->set(1, Smi::FromInt(static_cast<int>(i)));
- deopt_data->set_length(2);
- code->set_deoptimization_data(*deopt_data);
- }
+uint32_t GetNumImportedFunctions(Handle<JSObject> wasm_object) {
+ return static_cast<uint32_t>(
+ Smi::cast(wasm_object->GetInternalField(kWasmNumImportedFunctions))
+ ->value());
}
-} // namespace
-
WasmModule::WasmModule(byte* module_start)
: module_start(module_start),
module_end(nullptr),
min_mem_pages(0),
max_mem_pages(0),
mem_export(false),
- mem_external(false),
start_function_index(-1),
origin(kWasmOrigin),
globals_size(0),
+ num_imported_functions(0),
+ num_declared_functions(0),
+ num_exported_functions(0),
pending_tasks(new base::Semaphore(0)) {}
static MaybeHandle<JSFunction> ReportFFIError(
@@ -560,7 +520,7 @@ bool FetchAndExecuteCompilationUnit(
DisallowHandleDereference no_deref;
DisallowCodeDependencyChange no_dependency_change;
- // - 1 because AtomicIntrement returns the value after the atomic increment.
+ // - 1 because AtomicIncrement returns the value after the atomic increment.
size_t index = next_unit->Increment(1) - 1;
if (index >= compilation_units->size()) {
return false;
@@ -569,10 +529,8 @@ bool FetchAndExecuteCompilationUnit(
compiler::WasmCompilationUnit* unit = compilation_units->at(index);
if (unit != nullptr) {
unit->ExecuteCompilation();
- {
- base::LockGuard<base::Mutex> guard(result_mutex);
- executed_units->push(unit);
- }
+ base::LockGuard<base::Mutex> guard(result_mutex);
+ executed_units->push(unit);
}
return true;
}
@@ -615,11 +573,6 @@ static void RecordStats(Isolate* isolate, Code* code) {
code->relocation_info()->length());
}
-static void RecordStats(Isolate* isolate,
- const std::vector<Handle<Code>>& functions) {
- for (Handle<Code> c : functions) RecordStats(isolate, *c);
-}
-
static void RecordStats(Isolate* isolate, Handle<FixedArray> functions) {
DisallowHeapAllocation no_gc;
for (int i = 0; i < functions->length(); ++i) {
@@ -638,16 +591,16 @@ Address GetGlobalStartAddressFromCodeTemplate(Object* undefined,
return old_address;
}
-Handle<FixedArray> GetImportsMetadata(Factory* factory,
- const WasmModule* module) {
+Handle<FixedArray> GetImportsData(Factory* factory, const WasmModule* module) {
Handle<FixedArray> ret = factory->NewFixedArray(
static_cast<int>(module->import_table.size()), TENURED);
for (size_t i = 0; i < module->import_table.size(); ++i) {
const WasmImport& import = module->import_table[i];
+ if (import.kind != kExternalFunction) continue;
WasmName module_name = module->GetNameOrNull(import.module_name_offset,
import.module_name_length);
- WasmName function_name = module->GetNameOrNull(import.function_name_offset,
- import.function_name_length);
+ WasmName function_name = module->GetNameOrNull(import.field_name_offset,
+ import.field_name_length);
Handle<String> module_name_string =
factory->InternalizeUtf8String(module_name);
@@ -655,107 +608,97 @@ Handle<FixedArray> GetImportsMetadata(Factory* factory,
function_name.is_empty()
? Handle<String>::null()
: factory->InternalizeUtf8String(function_name);
- Handle<ByteArray> sig =
- factory->NewByteArray(static_cast<int>(import.sig->parameter_count() +
- import.sig->return_count()),
- TENURED);
- sig->copy_in(0, reinterpret_cast<const byte*>(import.sig->raw_data()),
+ FunctionSig* fsig = module->functions[import.index].sig;
+ Handle<ByteArray> sig = factory->NewByteArray(
+ static_cast<int>(fsig->parameter_count() + fsig->return_count()),
+ TENURED);
+ sig->copy_in(0, reinterpret_cast<const byte*>(fsig->raw_data()),
sig->length());
Handle<FixedArray> encoded_import =
- factory->NewFixedArray(kWasmImportDataTableSize, TENURED);
+ factory->NewFixedArray(kWasmImportDataSize, TENURED);
encoded_import->set(kModuleName, *module_name_string);
if (!function_name_string.is_null()) {
encoded_import->set(kFunctionName, *function_name_string);
}
- encoded_import->set(
- kOutputCount,
- Smi::FromInt(static_cast<int>(import.sig->return_count())));
+ encoded_import->set(kOutputCount,
+ Smi::FromInt(static_cast<int>(fsig->return_count())));
encoded_import->set(kSignature, *sig);
ret->set(static_cast<int>(i), *encoded_import);
}
return ret;
}
-bool CompileWrappersToImportedFunctions(Isolate* isolate,
- const Handle<JSReceiver> ffi,
- std::vector<Handle<Code>>& imports,
- Handle<FixedArray> import_data,
- ErrorThrower* thrower) {
- uint32_t import_count = static_cast<uint32_t>(import_data->length());
- if (import_count > 0) {
- imports.reserve(import_count);
- for (uint32_t index = 0; index < import_count; ++index) {
- Handle<FixedArray> data =
- import_data->GetValueChecked<FixedArray>(isolate, index);
- Handle<String> module_name =
- data->GetValueChecked<String>(isolate, kModuleName);
- MaybeHandle<String> function_name =
- data->GetValue<String>(isolate, kFunctionName);
-
- // TODO(mtrofin): this is an uint32_t, actually. We should rationalize
- // it when we rationalize signed/unsigned stuff.
- int ret_count = Smi::cast(data->get(kOutputCount))->value();
- CHECK(ret_count >= 0);
- Handle<ByteArray> sig_data =
- data->GetValueChecked<ByteArray>(isolate, kSignature);
- int sig_data_size = sig_data->length();
- int param_count = sig_data_size - ret_count;
- CHECK(param_count >= 0);
-
- MaybeHandle<JSReceiver> function = LookupFunction(
- thrower, isolate->factory(), ffi, index, module_name, function_name);
- if (function.is_null()) return false;
- Handle<Code> code;
- Handle<JSReceiver> target = function.ToHandleChecked();
- bool isMatch = false;
- Handle<Code> export_wrapper_code;
- if (target->IsJSFunction()) {
- Handle<JSFunction> func = Handle<JSFunction>::cast(target);
- export_wrapper_code = handle(func->code());
- if (export_wrapper_code->kind() == Code::JS_TO_WASM_FUNCTION) {
- int exported_param_count =
- Smi::cast(func->GetInternalField(kInternalArity))->value();
- Handle<ByteArray> exportedSig = Handle<ByteArray>(
- ByteArray::cast(func->GetInternalField(kInternalSignature)));
- if (exported_param_count == param_count &&
- exportedSig->length() == sig_data->length() &&
- memcmp(exportedSig->data(), sig_data->data(),
- exportedSig->length()) == 0) {
- isMatch = true;
- }
- }
+Handle<Code> CompileImportWrapper(Isolate* isolate,
+ const Handle<JSReceiver> ffi, int index,
+ Handle<FixedArray> import_data,
+ ErrorThrower* thrower) {
+ Handle<FixedArray> data =
+ import_data->GetValueChecked<FixedArray>(isolate, index);
+ Handle<String> module_name =
+ data->GetValueChecked<String>(isolate, kModuleName);
+ MaybeHandle<String> function_name =
+ data->GetValue<String>(isolate, kFunctionName);
+
+ // TODO(mtrofin): this is an uint32_t, actually. We should rationalize
+ // it when we rationalize signed/unsigned stuff.
+ int ret_count = Smi::cast(data->get(kOutputCount))->value();
+ CHECK_GE(ret_count, 0);
+ Handle<ByteArray> sig_data =
+ data->GetValueChecked<ByteArray>(isolate, kSignature);
+ int sig_data_size = sig_data->length();
+ int param_count = sig_data_size - ret_count;
+ CHECK(param_count >= 0);
+
+ MaybeHandle<JSReceiver> function = LookupFunction(
+ thrower, isolate->factory(), ffi, index, module_name, function_name);
+ if (function.is_null()) return Handle<Code>::null();
+ Handle<Code> code;
+ Handle<JSReceiver> target = function.ToHandleChecked();
+ bool isMatch = false;
+ Handle<Code> export_wrapper_code;
+ if (target->IsJSFunction()) {
+ Handle<JSFunction> func = Handle<JSFunction>::cast(target);
+ export_wrapper_code = handle(func->code());
+ if (export_wrapper_code->kind() == Code::JS_TO_WASM_FUNCTION) {
+ int exported_param_count =
+ Smi::cast(func->GetInternalField(kInternalArity))->value();
+ Handle<ByteArray> exportedSig = Handle<ByteArray>(
+ ByteArray::cast(func->GetInternalField(kInternalSignature)));
+ if (exported_param_count == param_count &&
+ exportedSig->length() == sig_data->length() &&
+ memcmp(exportedSig->data(), sig_data->data(),
+ exportedSig->length()) == 0) {
+ isMatch = true;
}
- if (isMatch) {
- int wasm_count = 0;
- int const mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET);
- for (RelocIterator it(*export_wrapper_code, mask); !it.done();
- it.next()) {
- RelocInfo* rinfo = it.rinfo();
- Address target_address = rinfo->target_address();
- Code* target = Code::GetCodeFromTargetAddress(target_address);
- if (target->kind() == Code::WASM_FUNCTION) {
- ++wasm_count;
- code = handle(target);
- }
- }
- DCHECK(wasm_count == 1);
- } else {
- // Copy the signature to avoid a raw pointer into a heap object when
- // GC can happen.
- Zone zone(isolate->allocator());
- MachineRepresentation* reps =
- zone.NewArray<MachineRepresentation>(sig_data_size);
- memcpy(reps, sig_data->data(),
- sizeof(MachineRepresentation) * sig_data_size);
- FunctionSig sig(ret_count, param_count, reps);
-
- code = compiler::CompileWasmToJSWrapper(isolate, target, &sig, index,
- module_name, function_name);
+ }
+ }
+ if (isMatch) {
+ int wasm_count = 0;
+ int const mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET);
+ for (RelocIterator it(*export_wrapper_code, mask); !it.done(); it.next()) {
+ RelocInfo* rinfo = it.rinfo();
+ Address target_address = rinfo->target_address();
+ Code* target = Code::GetCodeFromTargetAddress(target_address);
+ if (target->kind() == Code::WASM_FUNCTION) {
+ ++wasm_count;
+ code = handle(target);
}
- imports.push_back(code);
}
+ DCHECK(wasm_count == 1);
+ return code;
+ } else {
+ // Copy the signature to avoid a raw pointer into a heap object when
+ // GC can happen.
+ Zone zone(isolate->allocator());
+ MachineRepresentation* reps =
+ zone.NewArray<MachineRepresentation>(sig_data_size);
+ memcpy(reps, sig_data->data(),
+ sizeof(MachineRepresentation) * sig_data_size);
+ FunctionSig sig(ret_count, param_count, reps);
+
+ return compiler::CompileWasmToJSWrapper(isolate, target, &sig, index,
+ module_name, function_name);
}
- return true;
}
void InitializeParallelCompilation(
@@ -763,8 +706,10 @@ void InitializeParallelCompilation(
std::vector<compiler::WasmCompilationUnit*>& compilation_units,
ModuleEnv& module_env, ErrorThrower* thrower) {
for (uint32_t i = FLAG_skip_compiling_wasm_funcs; i < functions.size(); ++i) {
- compilation_units[i] = new compiler::WasmCompilationUnit(
- thrower, isolate, &module_env, &functions[i], i);
+ const WasmFunction* func = &functions[i];
+ compilation_units[i] =
+ func->imported ? nullptr : new compiler::WasmCompilationUnit(
+ thrower, isolate, &module_env, func, i);
}
}
@@ -894,8 +839,8 @@ void CompileSequentially(Isolate* isolate, const WasmModule* module,
for (uint32_t i = FLAG_skip_compiling_wasm_funcs;
i < module->functions.size(); ++i) {
const WasmFunction& func = module->functions[i];
+ if (func.imported) continue; // Imports are compiled at instantiation time.
- DCHECK_EQ(i, func.func_index);
WasmName str = module->GetName(func.name_offset, func.name_length);
Handle<Code> code = Handle<Code>::null();
// Compile the function.
@@ -911,91 +856,8 @@ void CompileSequentially(Isolate* isolate, const WasmModule* module,
}
}
-void SetDebugSupport(Factory* factory, Handle<FixedArray> compiled_module,
- Handle<JSObject> js_object) {
- Isolate* isolate = compiled_module->GetIsolate();
- MaybeHandle<String> module_bytes_string =
- compiled_module->GetValue<String>(isolate, kModuleBytes);
- if (!module_bytes_string.is_null()) {
- js_object->SetInternalField(kWasmModuleBytesString,
- *module_bytes_string.ToHandleChecked());
- }
-
- MaybeHandle<ByteArray> function_name_table =
- compiled_module->GetValue<ByteArray>(isolate, kFunctionNameTable);
- if (!function_name_table.is_null()) {
- js_object->SetInternalField(kWasmFunctionNamesArray,
- *function_name_table.ToHandleChecked());
- }
-}
-
-bool SetupGlobals(Isolate* isolate, MaybeHandle<JSObject> template_owner,
- Handle<FixedArray> compiled_module, Handle<JSObject> instance,
- ErrorThrower* thrower) {
- uint32_t globals_size = static_cast<uint32_t>(
- Smi::cast(compiled_module->get(kGlobalsSize))->value());
- if (globals_size > 0) {
- Handle<JSArrayBuffer> globals_buffer =
- NewArrayBuffer(isolate, globals_size);
- if (globals_buffer.is_null()) {
- thrower->Error("Out of memory: wasm globals");
- return false;
- }
- Address old_address =
- template_owner.is_null()
- ? nullptr
- : GetGlobalStartAddressFromCodeTemplate(
- *isolate->factory()->undefined_value(),
- JSObject::cast(*template_owner.ToHandleChecked()));
- RelocateGlobals(instance, old_address,
- static_cast<Address>(globals_buffer->backing_store()));
- instance->SetInternalField(kWasmGlobalsArrayBuffer, *globals_buffer);
- }
- return true;
-}
-
-bool SetupInstanceHeap(Isolate* isolate, Handle<FixedArray> compiled_module,
- Handle<JSObject> instance, Handle<JSArrayBuffer> memory,
- ErrorThrower* thrower) {
- uint32_t min_mem_pages = static_cast<uint32_t>(
- Smi::cast(compiled_module->get(kMinRequiredMemory))->value());
- isolate->counters()->wasm_min_mem_pages_count()->AddSample(min_mem_pages);
- // TODO(wasm): re-enable counter for max_mem_pages when we use that field.
-
- if (memory.is_null() && min_mem_pages > 0) {
- memory = AllocateMemory(thrower, isolate, min_mem_pages);
- if (memory.is_null()) {
- return false;
- }
- }
-
- if (!memory.is_null()) {
- instance->SetInternalField(kWasmMemArrayBuffer, *memory);
- Address mem_start = static_cast<Address>(memory->backing_store());
- uint32_t mem_size = static_cast<uint32_t>(memory->byte_length()->Number());
- uint32_t old_mem_size = static_cast<uint32_t>(
- compiled_module->GetValueChecked<HeapNumber>(isolate, kMemSize)
- ->value());
- MaybeHandle<JSArrayBuffer> old_mem =
- compiled_module->GetValue<JSArrayBuffer>(isolate, kMemStart);
- Address old_mem_start =
- old_mem.is_null()
- ? nullptr
- : static_cast<Address>(old_mem.ToHandleChecked()->backing_store());
- RelocateInstanceCode(instance, old_mem_start, mem_start, old_mem_size,
- mem_size);
- LoadDataSegments(compiled_module, mem_start, mem_size);
- compiled_module->GetValueChecked<HeapNumber>(isolate, kMemSize)
- ->set_value(static_cast<double>(mem_size));
- compiled_module->set(kMemStart, *memory);
- }
- return true;
-}
-
-void FixupFunctionsAndImports(Handle<FixedArray> old_functions,
- Handle<FixedArray> new_functions,
- MaybeHandle<FixedArray> maybe_old_imports,
- MaybeHandle<FixedArray> maybe_new_imports) {
+void PatchDirectCalls(Handle<FixedArray> old_functions,
+ Handle<FixedArray> new_functions, int start) {
DCHECK_EQ(new_functions->length(), old_functions->length());
DisallowHeapAllocation no_gc;
@@ -1004,19 +866,9 @@ void FixupFunctionsAndImports(Handle<FixedArray> old_functions,
old_to_new_code.insert(std::make_pair(Code::cast(old_functions->get(i)),
Code::cast(new_functions->get(i))));
}
- DCHECK_EQ(maybe_old_imports.is_null(), maybe_new_imports.is_null());
- if (!maybe_old_imports.is_null()) {
- Handle<FixedArray> old_imports = maybe_old_imports.ToHandleChecked();
- Handle<FixedArray> new_imports = maybe_new_imports.ToHandleChecked();
- DCHECK_EQ(new_imports->length(), old_imports->length());
- for (int i = 0; i < new_imports->length(); ++i) {
- old_to_new_code.insert(std::make_pair(Code::cast(old_imports->get(i)),
- Code::cast(new_imports->get(i))));
- }
- }
int mode_mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET);
AllowDeferredHandleDereference embedding_raw_address;
- for (int i = 0; i < new_functions->length(); ++i) {
+ for (int i = start; i < new_functions->length(); ++i) {
Code* wasm_function = Code::cast(new_functions->get(i));
for (RelocIterator it(wasm_function, mode_mask); !it.done(); it.next()) {
Code* old_code =
@@ -1026,109 +878,16 @@ void FixupFunctionsAndImports(Handle<FixedArray> old_functions,
auto found = old_to_new_code.find(old_code);
DCHECK(found != old_to_new_code.end());
Code* new_code = found->second;
- // Avoid redundant updates, expected for wasm functions, if we're at the
- // first instance.
- if (new_code == old_code) {
- DCHECK(new_code->kind() == Code::WASM_FUNCTION);
- continue;
+ if (new_code != old_code) {
+ it.rinfo()->set_target_address(new_code->instruction_start(),
+ UPDATE_WRITE_BARRIER,
+ SKIP_ICACHE_FLUSH);
}
- it.rinfo()->set_target_address(new_code->instruction_start(),
- UPDATE_WRITE_BARRIER, SKIP_ICACHE_FLUSH);
}
}
}
}
-bool SetupImports(Isolate* isolate, Handle<FixedArray> compiled_module,
- Handle<JSObject> instance, ErrorThrower* thrower,
- Handle<JSReceiver> ffi) {
- //-------------------------------------------------------------------------
- // Compile wrappers to imported functions.
- //-------------------------------------------------------------------------
- std::vector<Handle<Code>> import_code;
- MaybeHandle<FixedArray> maybe_import_data =
- compiled_module->GetValue<FixedArray>(isolate, kImportData);
- Handle<FixedArray> import_data;
- if (maybe_import_data.ToHandle(&import_data)) {
- if (!CompileWrappersToImportedFunctions(isolate, ffi, import_code,
- import_data, thrower)) {
- return false;
- }
- }
-
- RecordStats(isolate, import_code);
- if (import_code.empty()) return true;
-
- Handle<FixedArray> new_imports =
- isolate->factory()->NewFixedArray(static_cast<int>(import_code.size()));
- for (int i = 0; i < new_imports->length(); ++i) {
- new_imports->set(i, *import_code[i]);
- }
- compiled_module->set(kImportMap, *new_imports);
- return true;
-}
-
-bool SetupExportsObject(Handle<FixedArray> compiled_module, Isolate* isolate,
- Handle<JSObject> instance, ErrorThrower* thrower) {
- Factory* factory = isolate->factory();
- bool mem_export =
- static_cast<bool>(Smi::cast(compiled_module->get(kExportMem))->value());
- ModuleOrigin origin = static_cast<ModuleOrigin>(
- Smi::cast(compiled_module->get(kOrigin))->value());
-
- MaybeHandle<FixedArray> maybe_exports =
- compiled_module->GetValue<FixedArray>(isolate, kExports);
- if (!maybe_exports.is_null() || mem_export) {
- PropertyDescriptor desc;
- desc.set_writable(false);
-
- Handle<JSObject> exports_object = instance;
- if (origin == kWasmOrigin) {
- // Create the "exports" object.
- Handle<JSFunction> object_function = Handle<JSFunction>(
- isolate->native_context()->object_function(), isolate);
- exports_object = factory->NewJSObject(object_function, TENURED);
- Handle<String> exports_name = factory->InternalizeUtf8String("exports");
- JSObject::AddProperty(instance, exports_name, exports_object, READ_ONLY);
- }
- Handle<FixedArray> exports;
- if (maybe_exports.ToHandle(&exports)) {
- int exports_size = exports->length();
- for (int i = 0; i < exports_size; ++i) {
- if (thrower->error()) return false;
- Handle<FixedArray> export_metadata =
- exports->GetValueChecked<FixedArray>(isolate, i);
- Handle<Code> export_code =
- export_metadata->GetValueChecked<Code>(isolate, kExportCode);
- RecordStats(isolate, *export_code);
- Handle<String> name =
- export_metadata->GetValueChecked<String>(isolate, kExportName);
- int arity = Smi::cast(export_metadata->get(kExportArity))->value();
- MaybeHandle<ByteArray> signature =
- export_metadata->GetValue<ByteArray>(isolate, kExportedSignature);
- Handle<JSFunction> function = WrapExportCodeAsJSFunction(
- isolate, export_code, name, arity, signature, instance);
- desc.set_value(function);
- Maybe<bool> status = JSReceiver::DefineOwnProperty(
- isolate, exports_object, name, &desc, Object::THROW_ON_ERROR);
- if (!status.IsJust()) {
- thrower->Error("export of %.*s failed.", name->length(),
- name->ToCString().get());
- return false;
- }
- }
- }
- if (mem_export) {
- // Export the memory as a named property.
- Handle<String> name = factory->InternalizeUtf8String("memory");
- Handle<JSArrayBuffer> memory = Handle<JSArrayBuffer>(
- JSArrayBuffer::cast(instance->GetInternalField(kWasmMemArrayBuffer)));
- JSObject::AddProperty(exports_object, name, memory, READ_ONLY);
- }
- }
- return true;
-}
-
#define GET_COMPILED_MODULE_WEAK_RELATION_OR_NULL(Field) \
WeakCell* Get##Field(const FixedArray* compiled_module) { \
Object* obj = compiled_module->get(k##Field); \
@@ -1166,7 +925,7 @@ static void ResetCompiledModule(Isolate* isolate, JSObject* owner,
RelocInfo::ModeMask(RelocInfo::WASM_MEMORY_SIZE_REFERENCE) |
RelocInfo::ModeMask(RelocInfo::WASM_GLOBAL_REFERENCE);
- Object* fct_obj = compiled_module->get(kFunctions);
+ Object* fct_obj = compiled_module->get(kCodeTable);
if (fct_obj != nullptr && fct_obj != undefined &&
(old_mem_size > 0 || globals_start != nullptr)) {
FixedArray* functions = FixedArray::cast(fct_obj);
@@ -1253,11 +1012,11 @@ MaybeHandle<FixedArray> WasmModule::CompileFunctions(
MaybeHandle<FixedArray> nothing;
- WasmModuleInstance temp_instance_for_compilation(this);
- temp_instance_for_compilation.context = isolate->native_context();
- temp_instance_for_compilation.mem_size = GetMinModuleMemSize(this);
- temp_instance_for_compilation.mem_start = nullptr;
- temp_instance_for_compilation.globals_start = nullptr;
+ WasmModuleInstance temp_instance(this);
+ temp_instance.context = isolate->native_context();
+ temp_instance.mem_size = GetMinModuleMemSize(this);
+ temp_instance.mem_start = nullptr;
+ temp_instance.globals_start = nullptr;
MaybeHandle<FixedArray> indirect_table =
function_tables.size()
@@ -1266,10 +1025,10 @@ MaybeHandle<FixedArray> WasmModule::CompileFunctions(
: MaybeHandle<FixedArray>();
for (uint32_t i = 0; i < function_tables.size(); ++i) {
Handle<FixedArray> values = wasm::BuildFunctionTable(isolate, i, this);
- temp_instance_for_compilation.function_tables[i] = values;
+ temp_instance.function_tables[i] = values;
Handle<FixedArray> metadata = isolate->factory()->NewFixedArray(
- kWasmIndirectFunctionTableMetadataSize, TENURED);
+ kWasmIndirectFunctionTableDataSize, TENURED);
metadata->set(kSize, Smi::FromInt(function_tables[i].size));
metadata->set(kTable, *values);
indirect_table.ToHandleChecked()->set(i, *metadata);
@@ -1280,77 +1039,90 @@ MaybeHandle<FixedArray> WasmModule::CompileFunctions(
ModuleEnv module_env;
module_env.module = this;
- module_env.instance = &temp_instance_for_compilation;
+ module_env.instance = &temp_instance;
module_env.origin = origin;
- InitializePlaceholders(factory, &module_env.placeholders, functions.size());
-
- Handle<FixedArray> compiled_functions =
- factory->NewFixedArray(static_cast<int>(functions.size()), TENURED);
-
- MaybeHandle<FixedArray> maybe_imports;
- if (import_table.size() > 0) {
- temp_instance_for_compilation.import_code.resize(import_table.size());
- Handle<FixedArray> imports =
- factory->NewFixedArray(static_cast<int>(import_table.size()));
- for (uint32_t i = 0; i < import_table.size(); ++i) {
- Handle<Code> placeholder =
- CreatePlaceholder(factory, i, Code::WASM_TO_JS_FUNCTION);
- temp_instance_for_compilation.import_code[i] = placeholder;
- imports->set(i, *placeholder);
- }
- maybe_imports = imports;
+
+ // The {code_table} array contains import wrappers and functions (which
+ // are both included in {functions.size()}, and export wrappers.
+ int code_table_size =
+ static_cast<int>(functions.size() + num_exported_functions);
+ Handle<FixedArray> code_table =
+ factory->NewFixedArray(static_cast<int>(code_table_size), TENURED);
+
+ // Initialize the code table with placeholders.
+ for (uint32_t i = 0; i < functions.size(); i++) {
+ Code::Kind kind = Code::WASM_FUNCTION;
+ if (i < num_imported_functions) kind = Code::WASM_TO_JS_FUNCTION;
+ Handle<Code> placeholder = CreatePlaceholder(factory, i, kind);
+ code_table->set(static_cast<int>(i), *placeholder);
+ temp_instance.function_code[i] = placeholder;
}
+
isolate->counters()->wasm_functions_per_module()->AddSample(
static_cast<int>(functions.size()));
- if (FLAG_wasm_num_compilation_tasks != 0) {
- CompileInParallel(isolate, this,
- temp_instance_for_compilation.function_code, thrower,
- &module_env);
+ if (!FLAG_trace_wasm_decoder && FLAG_wasm_num_compilation_tasks != 0) {
+ // Avoid a race condition by collecting results into a second vector.
+ std::vector<Handle<Code>> results;
+ results.reserve(temp_instance.function_code.size());
+ for (size_t i = 0; i < temp_instance.function_code.size(); i++) {
+ results.push_back(temp_instance.function_code[i]);
+ }
+ CompileInParallel(isolate, this, results, thrower, &module_env);
+
+ for (size_t i = 0; i < results.size(); i++) {
+ temp_instance.function_code[i] = results[i];
+ }
} else {
- CompileSequentially(isolate, this,
- temp_instance_for_compilation.function_code, thrower,
+ CompileSequentially(isolate, this, temp_instance.function_code, thrower,
&module_env);
}
if (thrower->error()) return nothing;
// At this point, compilation has completed. Update the code table.
for (size_t i = FLAG_skip_compiling_wasm_funcs;
- i < temp_instance_for_compilation.function_code.size(); ++i) {
- Code* code = *temp_instance_for_compilation.function_code[i];
- compiled_functions->set(static_cast<int>(i), code);
+ i < temp_instance.function_code.size(); ++i) {
+ Code* code = *temp_instance.function_code[i];
+ code_table->set(static_cast<int>(i), code);
}
- LinkModuleFunctions(isolate, compiled_functions);
-
- // TODO(mtrofin): do we need to flush the cache here?
- FlushAssemblyCache(isolate, compiled_functions);
+ // Link the functions in the module.
+ for (size_t i = FLAG_skip_compiling_wasm_funcs;
+ i < temp_instance.function_code.size(); ++i) {
+ Handle<Code> code = temp_instance.function_code[i];
+ bool modified = LinkFunction(code, temp_instance.function_code);
+ if (modified) {
+ // TODO(mtrofin): do we need to flush the cache here?
+ Assembler::FlushICache(isolate, code->instruction_start(),
+ code->instruction_size());
+ }
+ }
// Create the compiled module object, and populate with compiled functions
// and information needed at instantiation time. This object needs to be
// serializable. Instantiation may occur off a deserialized version of this
// object.
Handle<FixedArray> ret =
- factory->NewFixedArray(kCompiledWasmObjectTableSize, TENURED);
- ret->set(kFunctions, *compiled_functions);
+ factory->NewFixedArray(kWasmCompiledModuleSize, TENURED);
+ ret->set(kCodeTable, *code_table);
if (!indirect_table.is_null()) {
ret->set(kTableOfIndirectFunctionTables, *indirect_table.ToHandleChecked());
}
- if (!maybe_imports.is_null()) {
- ret->set(kImportMap, *maybe_imports.ToHandleChecked());
- }
- Handle<FixedArray> import_data = GetImportsMetadata(factory, this);
+ Handle<FixedArray> import_data = GetImportsData(factory, this);
ret->set(kImportData, *import_data);
- // Compile export functions.
- int export_size = static_cast<int>(export_table.size());
- Handle<Code> startup_fct;
+ // Compile exported function wrappers.
+ int export_size = static_cast<int>(num_exported_functions);
if (export_size > 0) {
Handle<FixedArray> exports = factory->NewFixedArray(export_size, TENURED);
- for (int i = 0; i < export_size; ++i) {
- Handle<FixedArray> export_metadata =
- factory->NewFixedArray(kWasmExportMetadataTableSize, TENURED);
- const WasmExport& exp = export_table[i];
- FunctionSig* funcSig = functions[exp.func_index].sig;
+ int index = -1;
+
+ for (const WasmExport& exp : export_table) {
+ if (exp.kind != kExternalFunction)
+ continue; // skip non-function exports.
+ index++;
+ Handle<FixedArray> export_data =
+ factory->NewFixedArray(kWasmExportDataSize, TENURED);
+ FunctionSig* funcSig = functions[exp.index].sig;
Handle<ByteArray> exportedSig =
factory->NewByteArray(static_cast<int>(funcSig->parameter_count() +
funcSig->return_count()),
@@ -1358,45 +1130,34 @@ MaybeHandle<FixedArray> WasmModule::CompileFunctions(
exportedSig->copy_in(0,
reinterpret_cast<const byte*>(funcSig->raw_data()),
exportedSig->length());
- export_metadata->set(kExportedSignature, *exportedSig);
+ export_data->set(kExportedSignature, *exportedSig);
WasmName str = GetName(exp.name_offset, exp.name_length);
Handle<String> name = factory->InternalizeUtf8String(str);
- Handle<Code> code =
- temp_instance_for_compilation.function_code[exp.func_index];
+ Handle<Code> code = code_table->GetValueChecked<Code>(isolate, exp.index);
Handle<Code> export_code = compiler::CompileJSToWasmWrapper(
- isolate, &module_env, code, exp.func_index);
+ isolate, &module_env, code, exp.index);
if (thrower->error()) return nothing;
- export_metadata->set(kExportCode, *export_code);
- export_metadata->set(kExportName, *name);
- export_metadata->set(
- kExportArity, Smi::FromInt(static_cast<int>(
- functions[exp.func_index].sig->parameter_count())));
- export_metadata->set(kExportedFunctionIndex,
- Smi::FromInt(static_cast<int>(exp.func_index)));
- exports->set(i, *export_metadata);
- if (exp.func_index == start_function_index) {
- startup_fct = export_code;
- }
+ export_data->set(kExportName, *name);
+ export_data->set(kExportArity,
+ Smi::FromInt(static_cast<int>(
+ functions[exp.index].sig->parameter_count())));
+ export_data->set(kExportedFunctionIndex,
+ Smi::FromInt(static_cast<int>(exp.index)));
+ exports->set(index, *export_data);
+ code_table->set(static_cast<int>(functions.size() + index), *export_code);
}
- ret->set(kExports, *exports);
+ ret->set(kExportData, *exports);
}
- // Compile startup function, if we haven't already.
+ // Record data for startup function.
if (start_function_index >= 0) {
- uint32_t index = static_cast<uint32_t>(start_function_index);
HandleScope scope(isolate);
- if (startup_fct.is_null()) {
- Handle<Code> code = temp_instance_for_compilation.function_code[index];
- DCHECK_EQ(0, functions[index].sig->parameter_count());
- startup_fct =
- compiler::CompileJSToWasmWrapper(isolate, &module_env, code, index);
- }
- Handle<FixedArray> metadata =
- factory->NewFixedArray(kWasmExportMetadataTableSize, TENURED);
- metadata->set(kExportCode, *startup_fct);
- metadata->set(kExportArity, Smi::FromInt(0));
- metadata->set(kExportedFunctionIndex, Smi::FromInt(start_function_index));
- ret->set(kStartupFunction, *metadata);
+ Handle<FixedArray> startup_data =
+ factory->NewFixedArray(kWasmExportDataSize, TENURED);
+ startup_data->set(kExportArity, Smi::FromInt(0));
+ startup_data->set(kExportedFunctionIndex,
+ Smi::FromInt(start_function_index));
+ ret->set(kStartupData, *startup_data);
}
// TODO(wasm): saving the module bytes for debugging is wasteful. We should
@@ -1421,8 +1182,7 @@ MaybeHandle<FixedArray> WasmModule::CompileFunctions(
ret->set(kExportMem, Smi::FromInt(mem_export));
ret->set(kOrigin, Smi::FromInt(origin));
Handle<HeapNumber> size_as_object = factory->NewHeapNumber(
- static_cast<double>(temp_instance_for_compilation.mem_size), MUTABLE,
- TENURED);
+ static_cast<double>(temp_instance.mem_size), MUTABLE, TENURED);
ret->set(kMemSize, *size_as_object);
return ret;
}
@@ -1476,173 +1236,211 @@ Handle<FixedArray> SetupIndirectFunctionTable(
return cloned_indirect_tables;
}
-Handle<FixedArray> CloneModuleForInstance(Isolate* isolate,
- Handle<JSObject> module_object,
- bool* template_is_owned,
- Handle<FixedArray>* module_template) {
- Factory* factory = isolate->factory();
-
- Handle<FixedArray> original;
- for (int i = 0; i < 2; ++i) {
- original = handle(FixedArray::cast(module_object->GetInternalField(0)));
- if (GetOwningInstance(*original) == nullptr) {
- *template_is_owned = false;
- *module_template = original;
- return original;
- }
- if (i < 1) {
- isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags,
- GarbageCollectionReason::kRuntime);
- }
- }
- *template_is_owned = true;
- *module_template = original;
-
- // We insert the latest clone in front.
- Handle<FixedArray> clone = factory->CopyFixedArray(original);
- Handle<WeakCell> weak_link_to_wasm_obj =
- original->GetValueChecked<WeakCell>(isolate, kModuleObject);
-
- clone->set(kModuleObject, *weak_link_to_wasm_obj);
- Handle<WeakCell> link_to_original = factory->NewWeakCell(original);
- clone->set(kNextInstance, *link_to_original);
- Handle<WeakCell> link_to_clone = factory->NewWeakCell(clone);
- original->set(kPrevInstance, *link_to_clone);
- JSObject::cast(weak_link_to_wasm_obj->value())->SetInternalField(0, *clone);
-
- // Clone each wasm code object.
- Handle<FixedArray> orig_wasm_functions =
- original->GetValueChecked<FixedArray>(isolate, kFunctions);
- Handle<FixedArray> clone_wasm_functions =
- factory->CopyFixedArray(orig_wasm_functions);
- clone->set(kFunctions, *clone_wasm_functions);
- for (int i = 0; i < clone_wasm_functions->length(); ++i) {
- Handle<Code> orig_code =
- clone_wasm_functions->GetValueChecked<Code>(isolate, i);
- Handle<Code> cloned_code = factory->CopyCode(orig_code);
- clone_wasm_functions->set(i, *cloned_code);
- }
-
- MaybeHandle<FixedArray> maybe_orig_exports =
- original->GetValue<FixedArray>(isolate, kExports);
- Handle<FixedArray> orig_exports;
- if (maybe_orig_exports.ToHandle(&orig_exports)) {
- Handle<FixedArray> cloned_exports = factory->CopyFixedArray(orig_exports);
- clone->set(kExports, *cloned_exports);
- for (int i = 0; i < orig_exports->length(); ++i) {
- Handle<FixedArray> export_metadata =
- orig_exports->GetValueChecked<FixedArray>(isolate, i);
- Handle<FixedArray> clone_metadata =
- factory->CopyFixedArray(export_metadata);
- cloned_exports->set(i, *clone_metadata);
- Handle<Code> orig_code =
- export_metadata->GetValueChecked<Code>(isolate, kExportCode);
- Handle<Code> cloned_code = factory->CopyCode(orig_code);
- clone_metadata->set(kExportCode, *cloned_code);
- // TODO(wasm): This is actually a uint32_t, but since FixedArray indexes
- // in int, we are taking the risk of invalid values.
- int exported_fct_index =
- Smi::cast(export_metadata->get(kExportedFunctionIndex))->value();
- CHECK_GE(exported_fct_index, 0);
- CHECK_LT(exported_fct_index, clone_wasm_functions->length());
- Handle<Code> new_target = clone_wasm_functions->GetValueChecked<Code>(
- isolate, exported_fct_index);
- PatchJSWrapper(isolate, cloned_code, new_target);
- }
- }
-
- MaybeHandle<FixedArray> maybe_startup =
- original->GetValue<FixedArray>(isolate, kStartupFunction);
- if (!maybe_startup.is_null()) {
- Handle<FixedArray> startup_metadata =
- factory->CopyFixedArray(maybe_startup.ToHandleChecked());
- Handle<Code> startup_fct_clone = factory->CopyCode(
- startup_metadata->GetValueChecked<Code>(isolate, kExportCode));
- startup_metadata->set(kExportCode, *startup_fct_clone);
- clone->set(kStartupFunction, *startup_metadata);
- // TODO(wasm): see todo above about int vs size_t indexing in FixedArray.
- int startup_fct_index =
- Smi::cast(startup_metadata->get(kExportedFunctionIndex))->value();
- CHECK_GE(startup_fct_index, 0);
- CHECK_LT(startup_fct_index, clone_wasm_functions->length());
- Handle<Code> new_target =
- clone_wasm_functions->GetValueChecked<Code>(isolate, startup_fct_index);
- PatchJSWrapper(isolate, startup_fct_clone, new_target);
- }
- clone->set(kImportMap, *isolate->factory()->undefined_value());
- return clone;
-}
-
-// Instantiates a wasm module as a JSObject.
-// * allocates a backing store of {mem_size} bytes.
-// * installs a named property "memory" for that buffer if exported
-// * installs named properties on the object for exported functions
-// * compiles wasm code to machine code
+// Instantiates a WASM module, creating a WebAssembly.Instance from a
+// WebAssembly.Module.
MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate,
+ ErrorThrower* thrower,
Handle<JSObject> module_object,
Handle<JSReceiver> ffi,
Handle<JSArrayBuffer> memory) {
+ MaybeHandle<JSObject> nothing;
HistogramTimerScope wasm_instantiate_module_time_scope(
isolate->counters()->wasm_instantiate_module_time());
- ErrorThrower thrower(isolate, "WasmModule::Instantiate()");
Factory* factory = isolate->factory();
- bool template_is_owned = false;
- Handle<FixedArray> compiled_module_template;
- Handle<FixedArray> compiled_module = CloneModuleForInstance(
- isolate, module_object, &template_is_owned, &compiled_module_template);
-
- MaybeHandle<JSObject> template_owner;
- if (template_is_owned) {
- Handle<WeakCell> weak_owner =
- compiled_module_template->GetValueChecked<WeakCell>(isolate,
- kOwningInstance);
- template_owner = handle(JSObject::cast(weak_owner->value()));
+ //--------------------------------------------------------------------------
+ // Reuse the compiled module (if no owner), otherwise clone.
+ //--------------------------------------------------------------------------
+ Handle<FixedArray> compiled_module;
+ Handle<FixedArray> code_table;
+ Handle<FixedArray> old_code_table;
+ Handle<JSObject> owner;
+ {
+ Handle<FixedArray> original(
+ FixedArray::cast(module_object->GetInternalField(0)), isolate);
+ // Always make a new copy of the code_table, since the old_code_table
+ // may still have placeholders for imports.
+ old_code_table = original->GetValueChecked<FixedArray>(isolate, kCodeTable);
+ code_table = factory->CopyFixedArray(old_code_table);
+
+ WeakCell* tmp = GetOwningInstance(*original);
+ if (tmp != nullptr) {
+ // There is already an owner, clone everything.
+ owner = Handle<JSObject>(JSObject::cast(tmp->value()), isolate);
+ // Insert the latest clone in front.
+ compiled_module = factory->CopyFixedArray(original);
+ Handle<WeakCell> weak_link_to_wasm_obj =
+ original->GetValueChecked<WeakCell>(isolate, kModuleObject);
+
+ compiled_module->set(kModuleObject, *weak_link_to_wasm_obj);
+ Handle<WeakCell> link_to_original = factory->NewWeakCell(original);
+ compiled_module->set(kNextInstance, *link_to_original);
+ Handle<WeakCell> link_to_clone = factory->NewWeakCell(compiled_module);
+ original->set(kPrevInstance, *link_to_clone);
+ JSObject::cast(weak_link_to_wasm_obj->value())
+ ->SetInternalField(0, *compiled_module);
+
+ // Clone the code for WASM functions and exports.
+ for (int i = 0; i < code_table->length(); ++i) {
+ Handle<Code> orig_code = code_table->GetValueChecked<Code>(isolate, i);
+ switch (orig_code->kind()) {
+ case Code::WASM_TO_JS_FUNCTION:
+ // Imports will be overwritten with newly compiled wrappers.
+ break;
+ case Code::JS_TO_WASM_FUNCTION:
+ case Code::WASM_FUNCTION: {
+ Handle<Code> code = factory->CopyCode(orig_code);
+ code_table->set(i, *code);
+ break;
+ }
+ default:
+ UNREACHABLE();
+ }
+ }
+ RecordStats(isolate, code_table);
+ } else {
+ // There was no owner, so we can reuse the original.
+ compiled_module = original;
+ }
+ compiled_module->set(kCodeTable, *code_table);
}
- // These fields are compulsory.
- Handle<FixedArray> code_table =
- compiled_module->GetValueChecked<FixedArray>(isolate, kFunctions);
-
- RecordStats(isolate, code_table);
-
- MaybeHandle<JSObject> nothing;
+ //--------------------------------------------------------------------------
+ // Allocate the instance object.
+ //--------------------------------------------------------------------------
Handle<Map> map = factory->NewMap(
JS_OBJECT_TYPE,
JSObject::kHeaderSize + kWasmModuleInternalFieldCount * kPointerSize);
- Handle<JSObject> js_object = factory->NewJSObjectFromMap(map, TENURED);
- js_object->SetInternalField(kWasmModuleCodeTable, *code_table);
-
- // Remember the old imports, for the case when we are at the first instance -
- // they will be replaced with the instance's actual imports in SetupImports.
- MaybeHandle<FixedArray> old_imports =
- compiled_module_template->GetValue<FixedArray>(isolate, kImportMap);
- if (!(SetupInstanceHeap(isolate, compiled_module, js_object, memory,
- &thrower) &&
- SetupGlobals(isolate, template_owner, compiled_module, js_object,
- &thrower) &&
- SetupImports(isolate, compiled_module, js_object, &thrower, ffi) &&
- SetupExportsObject(compiled_module, isolate, js_object, &thrower))) {
- return nothing;
+ Handle<JSObject> instance = factory->NewJSObjectFromMap(map, TENURED);
+ instance->SetInternalField(kWasmModuleCodeTable, *code_table);
+
+ //--------------------------------------------------------------------------
+ // Set up the memory for the new instance.
+ //--------------------------------------------------------------------------
+ MaybeHandle<JSArrayBuffer> old_memory;
+ // TODO(titzer): handle imported memory properly.
+
+ uint32_t min_mem_pages = static_cast<uint32_t>(
+ Smi::cast(compiled_module->get(kMinRequiredMemory))->value());
+ isolate->counters()->wasm_min_mem_pages_count()->AddSample(min_mem_pages);
+ // TODO(wasm): re-enable counter for max_mem_pages when we use that field.
+
+ if (memory.is_null() && min_mem_pages > 0) {
+ memory = AllocateMemory(thrower, isolate, min_mem_pages);
+ if (memory.is_null()) return nothing; // failed to allocate memory
+ }
+
+ if (!memory.is_null()) {
+ instance->SetInternalField(kWasmMemArrayBuffer, *memory);
+ Address mem_start = static_cast<Address>(memory->backing_store());
+ uint32_t mem_size = static_cast<uint32_t>(memory->byte_length()->Number());
+ LoadDataSegments(compiled_module, mem_start, mem_size);
+
+ uint32_t old_mem_size = static_cast<uint32_t>(
+ compiled_module->GetValueChecked<HeapNumber>(isolate, kMemSize)
+ ->value());
+ MaybeHandle<JSArrayBuffer> old_mem =
+ compiled_module->GetValue<JSArrayBuffer>(isolate, kMemStart);
+ Address old_mem_start =
+ old_mem.is_null()
+ ? nullptr
+ : static_cast<Address>(old_mem.ToHandleChecked()->backing_store());
+ RelocateInstanceCode(instance, old_mem_start, mem_start, old_mem_size,
+ mem_size);
+ compiled_module->GetValueChecked<HeapNumber>(isolate, kMemSize)
+ ->set_value(static_cast<double>(mem_size));
+ compiled_module->set(kMemStart, *memory);
}
- FixupFunctionsAndImports(
- compiled_module_template->GetValueChecked<FixedArray>(isolate,
- kFunctions),
- code_table, old_imports,
- compiled_module->GetValue<FixedArray>(isolate, kImportMap));
+ //--------------------------------------------------------------------------
+ // Set up the globals for the new instance.
+ //--------------------------------------------------------------------------
+ MaybeHandle<JSArrayBuffer> old_globals;
+ MaybeHandle<JSArrayBuffer> globals;
+ uint32_t globals_size = static_cast<uint32_t>(
+ Smi::cast(compiled_module->get(kGlobalsSize))->value());
+ if (globals_size > 0) {
+ Handle<JSArrayBuffer> global_buffer = NewArrayBuffer(isolate, globals_size);
+ globals = global_buffer;
+ if (globals.is_null()) {
+ thrower->Error("Out of memory: wasm globals");
+ return nothing;
+ }
+ Address old_address =
+ owner.is_null() ? nullptr : GetGlobalStartAddressFromCodeTemplate(
+ *isolate->factory()->undefined_value(),
+ JSObject::cast(*owner));
+ RelocateGlobals(instance, old_address,
+ static_cast<Address>(global_buffer->backing_store()));
+ instance->SetInternalField(kWasmGlobalsArrayBuffer, *global_buffer);
+ }
+
+ //--------------------------------------------------------------------------
+ // Compile the import wrappers for the new instance.
+ //--------------------------------------------------------------------------
+ // TODO(titzer): handle imported globals and function tables.
+ Handle<FixedArray> import_data;
+ int num_imported_functions = 0;
+ if (compiled_module->GetValue<FixedArray>(isolate, kImportData)
+ .ToHandle(&import_data)) {
+ num_imported_functions = import_data->length();
+ for (int index = 0; index < num_imported_functions; index++) {
+ Handle<Code> import_wrapper =
+ CompileImportWrapper(isolate, ffi, index, import_data, thrower);
+ if (thrower->error()) return nothing;
+ code_table->set(index, *import_wrapper);
+ RecordStats(isolate, *import_wrapper);
+ }
+ }
+
+ //--------------------------------------------------------------------------
+ // Set up the debug support for the new instance.
+ //--------------------------------------------------------------------------
+ MaybeHandle<String> module_bytes_string =
+ compiled_module->GetValue<String>(isolate, kModuleBytes);
+ if (!module_bytes_string.is_null()) {
+ instance->SetInternalField(kWasmModuleBytesString,
+ *module_bytes_string.ToHandleChecked());
+ }
- SetDebugSupport(factory, compiled_module, js_object);
- SetRuntimeSupport(isolate, js_object);
+ MaybeHandle<ByteArray> function_name_table =
+ compiled_module->GetValue<ByteArray>(isolate, kFunctionNameTable);
+ if (!function_name_table.is_null()) {
+ Handle<ByteArray> handle = function_name_table.ToHandleChecked();
+ instance->SetInternalField(kWasmFunctionNamesArray, *handle);
+ }
- FlushAssemblyCache(isolate, code_table);
+ {
+ Handle<Object> handle = factory->NewNumber(num_imported_functions);
+ instance->SetInternalField(kWasmNumImportedFunctions, *handle);
+ }
+
+ //--------------------------------------------------------------------------
+ // Set up the runtime support for the new instance.
+ //--------------------------------------------------------------------------
+ Handle<WeakCell> weak_link = isolate->factory()->NewWeakCell(instance);
+
+ for (int i = num_imported_functions + FLAG_skip_compiling_wasm_funcs;
+ i < code_table->length(); ++i) {
+ Handle<Code> code = code_table->GetValueChecked<Code>(isolate, i);
+ if (code->kind() == Code::WASM_FUNCTION) {
+ Handle<FixedArray> deopt_data =
+ isolate->factory()->NewFixedArray(2, TENURED);
+ deopt_data->set(0, *weak_link);
+ deopt_data->set(1, Smi::FromInt(static_cast<int>(i)));
+ deopt_data->set_length(2);
+ code->set_deoptimization_data(*deopt_data);
+ }
+ }
+ //--------------------------------------------------------------------------
+ // Set up the indirect function tables for the new instance.
+ //--------------------------------------------------------------------------
{
std::vector<Handle<Code>> functions(
static_cast<size_t>(code_table->length()));
for (int i = 0; i < code_table->length(); ++i) {
- functions[static_cast<size_t>(i)] =
- code_table->GetValueChecked<Code>(isolate, i);
+ functions[i] = code_table->GetValueChecked<Code>(isolate, i);
}
MaybeHandle<FixedArray> maybe_indirect_tables =
@@ -1651,11 +1449,9 @@ MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate,
Handle<FixedArray> indirect_tables_template;
if (maybe_indirect_tables.ToHandle(&indirect_tables_template)) {
Handle<FixedArray> to_replace =
- template_owner.is_null()
- ? indirect_tables_template
- : handle(FixedArray::cast(
- template_owner.ToHandleChecked()->GetInternalField(
- kWasmModuleFunctionTable)));
+ owner.is_null() ? indirect_tables_template
+ : handle(FixedArray::cast(owner->GetInternalField(
+ kWasmModuleFunctionTable)));
Handle<FixedArray> indirect_tables = SetupIndirectFunctionTable(
isolate, code_table, indirect_tables_template, to_replace);
for (int i = 0; i < indirect_tables->length(); ++i) {
@@ -1666,24 +1462,104 @@ MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate,
metadata->GetValueChecked<FixedArray>(isolate, kTable);
wasm::PopulateFunctionTable(table, size, &functions);
}
- js_object->SetInternalField(kWasmModuleFunctionTable, *indirect_tables);
+ instance->SetInternalField(kWasmModuleFunctionTable, *indirect_tables);
+ }
+ }
+
+ //--------------------------------------------------------------------------
+ // Set up the exports object for the new instance.
+ //--------------------------------------------------------------------------
+ bool mem_export =
+ static_cast<bool>(Smi::cast(compiled_module->get(kExportMem))->value());
+ ModuleOrigin origin = static_cast<ModuleOrigin>(
+ Smi::cast(compiled_module->get(kOrigin))->value());
+
+ MaybeHandle<FixedArray> maybe_exports =
+ compiled_module->GetValue<FixedArray>(isolate, kExportData);
+ if (!maybe_exports.is_null() || mem_export) {
+ PropertyDescriptor desc;
+ desc.set_writable(false);
+
+ Handle<JSObject> exports_object = instance;
+ if (origin == kWasmOrigin) {
+ // Create the "exports" object.
+ Handle<JSFunction> object_function = Handle<JSFunction>(
+ isolate->native_context()->object_function(), isolate);
+ exports_object = factory->NewJSObject(object_function, TENURED);
+ Handle<String> exports_name = factory->InternalizeUtf8String("exports");
+ JSObject::AddProperty(instance, exports_name, exports_object, READ_ONLY);
+ }
+ Handle<FixedArray> exports;
+ int first_export = -1;
+ // TODO(wasm): another iteration over the code objects.
+ for (int i = 0; i < code_table->length(); i++) {
+ Handle<Code> code = code_table->GetValueChecked<Code>(isolate, i);
+ if (code->kind() == Code::JS_TO_WASM_FUNCTION) {
+ first_export = i;
+ break;
+ }
+ }
+ if (maybe_exports.ToHandle(&exports)) {
+ int export_size = exports->length();
+ for (int i = 0; i < export_size; ++i) {
+ Handle<FixedArray> export_data =
+ exports->GetValueChecked<FixedArray>(isolate, i);
+ Handle<String> name =
+ export_data->GetValueChecked<String>(isolate, kExportName);
+ int arity = Smi::cast(export_data->get(kExportArity))->value();
+ MaybeHandle<ByteArray> signature =
+ export_data->GetValue<ByteArray>(isolate, kExportedSignature);
+ Handle<Code> export_code =
+ code_table->GetValueChecked<Code>(isolate, first_export + i);
+ Handle<JSFunction> function = WrapExportCodeAsJSFunction(
+ isolate, export_code, name, arity, signature, instance);
+ desc.set_value(function);
+ Maybe<bool> status = JSReceiver::DefineOwnProperty(
+ isolate, exports_object, name, &desc, Object::THROW_ON_ERROR);
+ if (!status.IsJust()) {
+ thrower->Error("export of %.*s failed.", name->length(),
+ name->ToCString().get());
+ return nothing;
+ }
+ }
+ }
+ if (mem_export) {
+ // Export the memory as a named property.
+ Handle<JSArrayBuffer> buffer = Handle<JSArrayBuffer>(
+ JSArrayBuffer::cast(instance->GetInternalField(kWasmMemArrayBuffer)));
+ Handle<Object> memory_object =
+ WasmJs::CreateWasmMemoryObject(isolate, buffer, false, 0);
+ // TODO(titzer): export the memory with the correct name.
+ Handle<String> name = factory->InternalizeUtf8String("memory");
+ JSObject::AddProperty(exports_object, name, memory_object, READ_ONLY);
}
}
+ if (num_imported_functions > 0 || !owner.is_null()) {
+ // If the code was cloned, or new imports were compiled, patch.
+ PatchDirectCalls(old_code_table, code_table, num_imported_functions);
+ }
+
+ FlushICache(isolate, code_table);
+
+ //--------------------------------------------------------------------------
// Run the start function if one was specified.
- MaybeHandle<FixedArray> maybe_startup_fct =
- compiled_module->GetValue<FixedArray>(isolate, kStartupFunction);
- Handle<FixedArray> metadata;
- if (maybe_startup_fct.ToHandle(&metadata)) {
+ //--------------------------------------------------------------------------
+ Handle<FixedArray> startup_data;
+ if (compiled_module->GetValue<FixedArray>(isolate, kStartupData)
+ .ToHandle(&startup_data)) {
HandleScope scope(isolate);
+ int32_t start_index =
+ startup_data->GetValueChecked<Smi>(isolate, kExportedFunctionIndex)
+ ->value();
Handle<Code> startup_code =
- metadata->GetValueChecked<Code>(isolate, kExportCode);
- int arity = Smi::cast(metadata->get(kExportArity))->value();
+ code_table->GetValueChecked<Code>(isolate, start_index);
+ int arity = Smi::cast(startup_data->get(kExportArity))->value();
MaybeHandle<ByteArray> startup_signature =
- metadata->GetValue<ByteArray>(isolate, kExportedSignature);
+ startup_data->GetValue<ByteArray>(isolate, kExportedSignature);
Handle<JSFunction> startup_fct = WrapExportCodeAsJSFunction(
isolate, startup_code, factory->InternalizeUtf8String("start"), arity,
- startup_signature, js_object);
+ startup_signature, instance);
RecordStats(isolate, *startup_code);
// Call the JS function.
Handle<Object> undefined = isolate->factory()->undefined_value();
@@ -1691,39 +1567,25 @@ MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate,
Execution::Call(isolate, startup_fct, undefined, 0, nullptr);
if (retval.is_null()) {
- thrower.Error("WASM.instantiateModule(): start function failed");
+ thrower->Error("WASM.instantiateModule(): start function failed");
return nothing;
}
}
- DCHECK(wasm::IsWasmObject(*js_object));
+ DCHECK(wasm::IsWasmObject(*instance));
if (!compiled_module->GetValue<WeakCell>(isolate, kModuleObject).is_null()) {
- js_object->SetInternalField(kWasmCompiledModule, *compiled_module);
- Handle<WeakCell> link_to_owner = factory->NewWeakCell(js_object);
+ instance->SetInternalField(kWasmCompiledModule, *compiled_module);
+ Handle<WeakCell> link_to_owner = factory->NewWeakCell(instance);
compiled_module->set(kOwningInstance, *link_to_owner);
- Handle<Object> global_handle =
- isolate->global_handles()->Create(*js_object);
+ Handle<Object> global_handle = isolate->global_handles()->Create(*instance);
GlobalHandles::MakeWeak(global_handle.location(), global_handle.location(),
&InstanceFinalizer,
v8::WeakCallbackType::kFinalizer);
}
- return js_object;
-}
-
-// TODO(mtrofin): remove this once we move to WASM_DIRECT_CALL
-Handle<Code> ModuleEnv::GetCodeOrPlaceholder(uint32_t index) const {
- DCHECK(IsValidFunction(index));
- if (!placeholders.empty()) return placeholders[index];
- DCHECK_NOT_NULL(instance);
- return instance->function_code[index];
-}
-
-Handle<Code> ModuleEnv::GetImportCode(uint32_t index) {
- DCHECK(IsValidImport(index));
- return instance ? instance->import_code[index] : Handle<Code>::null();
+ return instance;
}
compiler::CallDescriptor* ModuleEnv::GetCallDescriptor(Zone* zone,
« no previous file with comments | « src/wasm/wasm-module.h ('k') | src/wasm/wasm-opcodes.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698