Index: src/wasm/wasm-module.cc |
diff --git a/src/wasm/wasm-module.cc b/src/wasm/wasm-module.cc |
index ce65b9b729a8b34710b27fd59495f6b49f44036a..8dbb3c4ece4952fe19afa193be76b68adb6574d8 100644 |
--- a/src/wasm/wasm-module.cc |
+++ b/src/wasm/wasm-module.cc |
@@ -154,11 +154,11 @@ enum CompiledWasmObjectFields { |
kExports, // maybe FixedArray of FixedArray of WasmExportMetadata |
// structure |
kStartupFunction, // maybe FixedArray of WasmExportMetadata structure |
- kIndirectFunctionTableSize, // Smi. Size of indirect function table. |
- kIndirectFunctionTablePrototype, // maybe FixedArray |
- kModuleBytes, // maybe String |
- kFunctionNameTable, // maybe ByteArray |
- kMinRequiredMemory, // Smi. an uint32_t |
+ kTableOfIndirectFunctionTables, // maybe FixedArray of FixedArray of |
+ // WasmIndirectFunctionTableMetadata |
+ kModuleBytes, // maybe String |
+ kFunctionNameTable, // maybe ByteArray |
+ kMinRequiredMemory, // Smi. an uint32_t |
// The following 2 are either together present or absent: |
kDataSegmentsInfo, // maybe FixedArray of FixedArray respecting the |
// WasmSegmentInfo structure |
@@ -192,6 +192,12 @@ enum WasmSegmentInfo { |
kWasmSegmentInfoSize // Sentinel value. |
}; |
+enum WasmIndirectFunctionTableMetadata { |
+ kSize, // Smi. an uint32_t |
+ kTable, // FixedArray of indirect function table |
+ kWasmIndirectFunctionTableMetadataSize // Sentinel value. |
+}; |
+ |
uint32_t GetMinModuleMemSize(const WasmModule* module) { |
return WasmModule::kPageSize * module->min_mem_pages; |
} |
@@ -257,39 +263,6 @@ void SaveDataSegmentInfo(Factory* factory, const WasmModule* module, |
compiled_module->set(kDataSegments, *data); |
} |
-MaybeHandle<FixedArray> BuildFunctionTable(Isolate* isolate, |
- const WasmModule* module) { |
- // Compute the size of the indirect function table |
- uint32_t table_size = module->FunctionTableSize(); |
- if (table_size == 0) { |
- return MaybeHandle<FixedArray>(); |
- } |
- |
- DCHECK_GE(table_size, module->function_table.size()); |
- |
- Handle<FixedArray> fixed = isolate->factory()->NewFixedArray(2 * table_size); |
- for (uint32_t i = 0; i < module->function_table.size(); ++i) { |
- const WasmFunction* function = |
- &module->functions[module->function_table[i]]; |
- int fixed_array_index = static_cast<int>(i); |
- fixed->set(fixed_array_index, Smi::FromInt(function->sig_index)); |
- fixed->set(fixed_array_index + table_size, |
- Smi::FromInt(module->function_table[fixed_array_index])); |
- } |
- |
- // Set the remaining elements to -1 (instead of "undefined"). These |
- // elements are accessed directly as SMIs (without a check). On 64-bit |
- // platforms, it is possible to have the top bits of "undefined" take |
- // small integer values (or zero), which are more likely to be equal to |
- // the signature index we check against. |
- for (uint32_t i = static_cast<uint32_t>(module->function_table.size()); |
- i < table_size; |
- ++i) { |
- fixed->set(i, Smi::FromInt(-1)); |
- } |
- return fixed; |
-} |
- |
void PatchFunctionTable(Handle<Code> code, |
Handle<FixedArray> old_indirect_table, |
Handle<FixedArray> new_indirect_table) { |
@@ -377,7 +350,8 @@ Handle<Code> CreatePlaceholder(Factory* factory, uint32_t index, |
// the {constant_pool_offset} field of the code object. |
// TODO(titzer): placeholder code objects are somewhat dangerous. |
static byte buffer[] = {0, 0, 0, 0, 0, 0, 0, 0}; // fake instructions. |
- static CodeDesc desc = {buffer, 8, 8, 0, 0, nullptr, 0, nullptr}; |
+ static CodeDesc desc = { |
+ buffer, arraysize(buffer), arraysize(buffer), 0, 0, nullptr, 0, nullptr}; |
Handle<Code> code = factory->NewCode(desc, Code::KindField::encode(kind), |
Handle<Object>::null()); |
code->set_constant_pool_offset(static_cast<int>(index) + kPlaceholderMarker); |
@@ -461,7 +435,6 @@ WasmModule::WasmModule(byte* module_start) |
start_function_index(-1), |
origin(kWasmOrigin), |
globals_size(0), |
- indirect_table_size(0), |
pending_tasks(new base::Semaphore(0)) {} |
static MaybeHandle<JSFunction> ReportFFIError( |
@@ -1027,10 +1000,19 @@ MaybeHandle<FixedArray> WasmModule::CompileFunctions( |
temp_instance_for_compilation.mem_start = nullptr; |
temp_instance_for_compilation.globals_start = nullptr; |
- MaybeHandle<FixedArray> indirect_table = BuildFunctionTable(isolate, this); |
- if (!indirect_table.is_null()) { |
- temp_instance_for_compilation.function_table = |
- indirect_table.ToHandleChecked(); |
+ MaybeHandle<FixedArray> indirect_table = |
+ function_tables.size() |
+ ? factory->NewFixedArray(static_cast<int>(function_tables.size())) |
+ : 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; |
+ |
+ Handle<FixedArray> metadata = isolate->factory()->NewFixedArray( |
+ kWasmIndirectFunctionTableMetadataSize); |
+ metadata->set(kSize, Smi::FromInt(function_tables[i].size)); |
+ metadata->set(kTable, *values); |
+ indirect_table.ToHandleChecked()->set(i, *metadata); |
} |
HistogramTimerScope wasm_compile_module_time_scope( |
@@ -1077,11 +1059,8 @@ MaybeHandle<FixedArray> WasmModule::CompileFunctions( |
Handle<FixedArray> ret = |
factory->NewFixedArray(kCompiledWasmObjectTableSize, TENURED); |
ret->set(kFunctions, *compiled_functions); |
- ret->set(kIndirectFunctionTableSize, |
- Smi::FromInt(static_cast<int>(function_table.size()))); |
if (!indirect_table.is_null()) { |
- ret->set(kIndirectFunctionTablePrototype, |
- *indirect_table.ToHandleChecked()); |
+ ret->set(kTableOfIndirectFunctionTables, *indirect_table.ToHandleChecked()); |
} |
Handle<FixedArray> import_data = GetImportsMetadata(factory, this); |
ret->set(kImportData, *import_data); |
@@ -1183,28 +1162,54 @@ Handle<FixedArray> CloneModuleForInstance(Isolate* isolate, |
Factory* factory = isolate->factory(); |
Handle<FixedArray> clone = factory->CopyFixedArray(original); |
+ // Copy the outer table, each WasmIndirectFunctionTableMetadata table, and the |
+ // inner kTable. |
+ MaybeHandle<FixedArray> maybe_indirect_tables = |
+ original->GetValue<FixedArray>(kTableOfIndirectFunctionTables); |
+ Handle<FixedArray> indirect_tables, clone_indirect_tables; |
+ if (maybe_indirect_tables.ToHandle(&indirect_tables)) { |
+ clone_indirect_tables = factory->CopyFixedArray(indirect_tables); |
+ clone->set(kTableOfIndirectFunctionTables, *clone_indirect_tables); |
+ for (int i = 0; i < clone_indirect_tables->length(); ++i) { |
+ Handle<FixedArray> orig_metadata = |
+ clone_indirect_tables->GetValueChecked<FixedArray>(i); |
+ Handle<FixedArray> clone_metadata = |
+ factory->CopyFixedArray(orig_metadata); |
+ clone_indirect_tables->set(i, *clone_metadata); |
+ |
+ Handle<FixedArray> orig_table = |
+ clone_metadata->GetValueChecked<FixedArray>(kTable); |
+ Handle<FixedArray> clone_table = factory->CopyFixedArray(orig_table); |
+ clone_metadata->set(kTable, *clone_table); |
+ } |
+ } |
+ |
+ // Clone each code, then if indirect tables are used, patch the cloned code to |
+ // refer to the cloned kTable. |
Handle<FixedArray> orig_wasm_functions = |
original->GetValueChecked<FixedArray>(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>(i); |
+ Handle<Code> cloned_code = factory->CopyCode(orig_code); |
+ clone_wasm_functions->set(i, *cloned_code); |
- MaybeHandle<FixedArray> maybe_indirect_table = |
- original->GetValue<FixedArray>(kIndirectFunctionTablePrototype); |
+ if (!clone_indirect_tables.is_null()) { |
+ for (int j = 0; j < clone_indirect_tables->length(); ++j) { |
+ Handle<FixedArray> orig_metadata = |
+ indirect_tables->GetValueChecked<FixedArray>(j); |
+ Handle<FixedArray> orig_table = |
+ orig_metadata->GetValueChecked<FixedArray>(kTable); |
- Handle<FixedArray> indirect_table; |
- Handle<FixedArray> old_table; |
- if (maybe_indirect_table.ToHandle(&old_table)) { |
- indirect_table = factory->CopyFixedArray(old_table); |
- clone->set(kIndirectFunctionTablePrototype, *indirect_table); |
- } |
+ Handle<FixedArray> clone_metadata = |
+ clone_indirect_tables->GetValueChecked<FixedArray>(j); |
+ Handle<FixedArray> clone_table = |
+ clone_metadata->GetValueChecked<FixedArray>(kTable); |
- for (int i = 0; i < orig_wasm_functions->length(); ++i) { |
- Handle<Code> orig_code = orig_wasm_functions->GetValueChecked<Code>(i); |
- Handle<Code> cloned_code = factory->CopyCode(orig_code); |
- clone_wasm_functions->set(i, *cloned_code); |
- if (!maybe_indirect_table.is_null()) { |
- PatchFunctionTable(cloned_code, old_table, indirect_table); |
+ PatchFunctionTable(cloned_code, orig_table, clone_table); |
+ } |
} |
} |
@@ -1276,14 +1281,12 @@ MaybeHandle<JSObject> WasmModule::Instantiate( |
Handle<FixedArray> code_table = |
compiled_module->GetValueChecked<FixedArray>(kFunctions); |
- { |
- 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>(i); |
- } |
- LinkModuleFunctions(isolate, functions); |
+ 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>(i); |
} |
+ LinkModuleFunctions(isolate, functions); |
RecordStats(isolate, code_table); |
@@ -1307,20 +1310,18 @@ MaybeHandle<JSObject> WasmModule::Instantiate( |
FlushAssemblyCache(isolate, code_table); |
- MaybeHandle<FixedArray> maybe_indirect_table = |
- compiled_module->GetValue<FixedArray>(kIndirectFunctionTablePrototype); |
- Handle<FixedArray> indirect_table; |
- if (maybe_indirect_table.ToHandle(&indirect_table)) { |
- int table_size = |
- Smi::cast(compiled_module->get(kIndirectFunctionTableSize))->value(); |
- int half_point = indirect_table->length() / 2; |
- for (int i = half_point; i < half_point + table_size; ++i) { |
- int index = Smi::cast(indirect_table->get(i))->value(); |
- DCHECK_GE(index, 0); |
- DCHECK_LT(index, code_table->length()); |
- indirect_table->set(i, code_table->get(index)); |
+ MaybeHandle<FixedArray> maybe_indirect_tables = |
+ compiled_module->GetValue<FixedArray>(kTableOfIndirectFunctionTables); |
+ Handle<FixedArray> indirect_tables; |
+ if (maybe_indirect_tables.ToHandle(&indirect_tables)) { |
+ for (int i = 0; i < indirect_tables->length(); ++i) { |
+ Handle<FixedArray> metadata = |
+ indirect_tables->GetValueChecked<FixedArray>(i); |
+ uint32_t size = Smi::cast(metadata->get(kSize))->value(); |
+ Handle<FixedArray> table = metadata->GetValueChecked<FixedArray>(kTable); |
+ wasm::PopulateFunctionTable(table, size, &functions); |
} |
- js_object->SetInternalField(kWasmModuleFunctionTable, *indirect_table); |
+ js_object->SetInternalField(kWasmModuleFunctionTable, *indirect_tables); |
} |
// Run the start function if one was specified. |
@@ -1475,6 +1476,40 @@ bool UpdateWasmModuleMemory(Handle<JSObject> object, Address old_start, |
return true; |
} |
+Handle<FixedArray> BuildFunctionTable(Isolate* isolate, uint32_t index, |
+ const WasmModule* module) { |
+ const WasmIndirectFunctionTable* table = &module->function_tables[index]; |
+ DCHECK_EQ(table->size, table->values.size()); |
+ DCHECK_GE(table->max_size, table->size); |
+ Handle<FixedArray> values = |
+ isolate->factory()->NewFixedArray(2 * table->max_size); |
+ for (uint32_t i = 0; i < table->size; ++i) { |
+ const WasmFunction* function = &module->functions[table->values[i]]; |
+ values->set(i, Smi::FromInt(function->sig_index)); |
+ values->set(i + table->max_size, Smi::FromInt(table->values[i])); |
+ } |
+ // Set the remaining elements to -1 (instead of "undefined"). These |
+ // elements are accessed directly as SMIs (without a check). On 64-bit |
+ // platforms, it is possible to have the top bits of "undefined" take |
+ // small integer values (or zero), which are more likely to be equal to |
+ // the signature index we check against. |
+ for (uint32_t i = table->size; i < table->max_size; i++) { |
+ values->set(i, Smi::FromInt(-1)); |
+ } |
+ return values; |
+} |
+ |
+void PopulateFunctionTable(Handle<FixedArray> table, uint32_t table_size, |
+ const std::vector<Handle<Code>>* code_table) { |
+ uint32_t max_size = table->length() / 2; |
+ for (uint32_t i = max_size; i < max_size + table_size; ++i) { |
+ int index = Smi::cast(table->get(static_cast<int>(i)))->value(); |
+ DCHECK_GE(index, 0); |
+ DCHECK_LT(static_cast<size_t>(index), code_table->size()); |
+ table->set(static_cast<int>(i), *(*code_table)[index]); |
+ } |
+} |
+ |
int GetNumberOfFunctions(JSObject* wasm) { |
Object* func_names_obj = wasm->GetInternalField(kWasmFunctionNamesArray); |
// TODO(clemensh): this looks inside an array constructed elsewhere. Refactor. |