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, |