 Chromium Code Reviews
 Chromium Code Reviews Issue 2134593002:
  [wasm] cloning compiled module before instantiation  (Closed) 
  Base URL: https://chromium.googlesource.com/v8/v8.git@master
    
  
    Issue 2134593002:
  [wasm] cloning compiled module before instantiation  (Closed) 
  Base URL: https://chromium.googlesource.com/v8/v8.git@master| Index: src/wasm/wasm-module.cc | 
| diff --git a/src/wasm/wasm-module.cc b/src/wasm/wasm-module.cc | 
| index 27d9e63bc60cb00c4fbfea63c61680081f9dacfd..d0fab43292c8c71ba44112e0ab24979495d7760b 100644 | 
| --- a/src/wasm/wasm-module.cc | 
| +++ b/src/wasm/wasm-module.cc | 
| @@ -112,6 +112,32 @@ std::ostream& operator<<(std::ostream& os, const WasmFunctionName& pair) { | 
| return os; | 
| } | 
| +Handle<JSFunction> CreateExport(Isolate* isolate, Handle<Code> export_code, | 
| + Handle<String> name, int arity, | 
| + Handle<JSObject> module_instance) { | 
| + Handle<SharedFunctionInfo> shared = | 
| + isolate->factory()->NewSharedFunctionInfo(name, export_code, false); | 
| + shared->set_length(arity); | 
| + shared->set_internal_formal_parameter_count(arity); | 
| + Handle<JSFunction> function = isolate->factory()->NewFunction( | 
| + isolate->wasm_function_map(), name, export_code); | 
| + function->set_shared(*shared); | 
| + | 
| + function->SetInternalField(0, *module_instance); | 
| + return function; | 
| +} | 
| + | 
| +void PatchFunctionTable(Handle<Code> code, | 
| 
rossberg
2016/07/11 10:49:45
Nit: static or in namespace?
 
Mircea Trofin
2016/07/11 16:52:57
Done.
 | 
| + Handle<FixedArray> old_indirect_table, | 
| + Handle<FixedArray> new_indirect_table) { | 
| + for (RelocIterator it(*code, 1 << RelocInfo::EMBEDDED_OBJECT); !it.done(); | 
| + it.next()) { | 
| + if (it.rinfo()->target_object() == *old_indirect_table) { | 
| + it.rinfo()->set_target_object(*new_indirect_table); | 
| + } | 
| + } | 
| +} | 
| + | 
| namespace { | 
| // Internal constants for the layout of the module object. | 
| const int kWasmModuleFunctionTable = 0; | 
| @@ -131,14 +157,17 @@ const int kWasmModuleInternalFieldCount = 7; | 
| // 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. | 
| - kExports, // maybe FixedArray of JSFunction | 
| - kStartupFunction, // maybe JSFunction | 
| - kModuleBytes, // maybe String | 
| - kFunctionNameTable, // maybe ByteArray | 
| - kMinRequiredMemory, // Smi. an uint32_t | 
| + kFunctions, // FixedArray of Code | 
| + kImportData, // maybe FixedArray of FixedArray respecting the | 
| + // WasmImportMetadata structure. | 
| + 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 | 
| // The following 2 are either together present or absent: | 
| kDataSegmentsInfo, // maybe FixedArray of FixedArray respecting the | 
| // WasmSegmentInfo structure | 
| @@ -158,6 +187,14 @@ enum WasmImportMetadata { | 
| kWasmImportDataTableSize // Sentinel value. | 
| }; | 
| +enum WasmExportMetadata { | 
| 
titzer
2016/07/11 08:25:35
I didn't see the prior CL where these started popp
 
Mircea Trofin
2016/07/11 16:52:57
My short term goal is to get an end-to-end indexed
 | 
| + kExportCode, // Code | 
| + kExportName, // String | 
| + kExportArity, // Smi, an int | 
| + kExportedFunctionIndex, // Smi, an uint32_t | 
| + kWasmExportMetadataTableSize // Sentinel value. | 
| +}; | 
| + | 
| enum WasmSegmentInfo { | 
| kDestAddr, // Smi. an uint32_t | 
| kSourceSize, // Smi. an uint32_t | 
| @@ -229,22 +266,26 @@ void SaveDataSegmentInfo(Factory* factory, const WasmModule* module, | 
| compiled_module->set(kDataSegments, *data); | 
| } | 
| -Handle<FixedArray> BuildFunctionTable(Isolate* isolate, | 
| - const WasmModule* module) { | 
| +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 Handle<FixedArray>::null(); | 
| + 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 < static_cast<uint32_t>(module->function_table.size()); | 
| - ++i) { | 
| + for (uint32_t i = 0; i < module->function_table.size(); ++i) { | 
| const WasmFunction* function = | 
| &module->functions[module->function_table[i]]; | 
| - fixed->set(i, Smi::FromInt(function->sig_index)); | 
| + 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 | 
| @@ -386,11 +427,7 @@ void LinkModuleFunctions(Isolate* isolate, | 
| std::vector<Handle<Code>>& functions) { | 
| for (size_t i = 0; i < functions.size(); ++i) { | 
| Handle<Code> code = functions[i]; | 
| - bool modified = LinkFunction(code, functions, Code::WASM_FUNCTION); | 
| - if (modified) { | 
| - Assembler::FlushICache(isolate, code->instruction_start(), | 
| - code->instruction_size()); | 
| - } | 
| + LinkFunction(code, functions, Code::WASM_FUNCTION); | 
| } | 
| } | 
| @@ -398,11 +435,15 @@ void LinkImports(Isolate* isolate, std::vector<Handle<Code>>& functions, | 
| const std::vector<Handle<Code>>& imports) { | 
| for (uint32_t i = 0; i < functions.size(); ++i) { | 
| Handle<Code> code = functions[i]; | 
| - bool modified = LinkFunction(code, imports, Code::WASM_TO_JS_FUNCTION); | 
| - if (modified) { | 
| - Assembler::FlushICache(isolate, code->instruction_start(), | 
| - code->instruction_size()); | 
| - } | 
| + LinkFunction(code, imports, Code::WASM_TO_JS_FUNCTION); | 
| + } | 
| +} | 
| + | 
| +void FlushAssemblyCache(Isolate* isolate, Handle<FixedArray> functions) { | 
| + for (int i = 0; i < functions->length(); ++i) { | 
| + Handle<Code> code = functions->GetValueChecked<Code>(i); | 
| + Assembler::FlushICache(isolate, code->instruction_start(), | 
| + code->instruction_size()); | 
| } | 
| } | 
| @@ -802,20 +843,6 @@ void CompileSequentially(Isolate* isolate, const WasmModule* module, | 
| } | 
| } | 
| -void PopulateFunctionTable(WasmModuleInstance* instance) { | 
| - if (!instance->function_table.is_null()) { | 
| - uint32_t table_size = instance->module->FunctionTableSize(); | 
| - DCHECK_EQ(table_size * 2, instance->function_table->length()); | 
| - uint32_t populated_table_size = | 
| - static_cast<uint32_t>(instance->module->function_table.size()); | 
| - for (uint32_t i = 0; i < populated_table_size; ++i) { | 
| - instance->function_table->set( | 
| - i + table_size, | 
| - *instance->function_code[instance->module->function_table[i]]); | 
| - } | 
| - } | 
| -} | 
| - | 
| void SetDebugSupport(Factory* factory, Handle<FixedArray> compiled_module, | 
| Handle<JSObject> js_object) { | 
| MaybeHandle<String> module_bytes_string = | 
| @@ -921,7 +948,6 @@ bool SetupImports(Isolate* isolate, Handle<FixedArray> compiled_module, | 
| function_code[i] = code; | 
| } | 
| - instance->SetInternalField(kWasmModuleFunctionTable, Smi::FromInt(0)); | 
| LinkImports(isolate, function_code, import_code); | 
| return true; | 
| } | 
| @@ -955,12 +981,16 @@ bool SetupExportsObject(Handle<FixedArray> compiled_module, Isolate* isolate, | 
| int exports_size = exports->length(); | 
| for (int i = 0; i < exports_size; ++i) { | 
| if (thrower->error()) return false; | 
| - Handle<JSFunction> function = exports->GetValueChecked<JSFunction>(i); | 
| - RecordStats(isolate, function->code()); | 
| + Handle<FixedArray> export_metadata = | 
| + exports->GetValueChecked<FixedArray>(i); | 
| + Handle<Code> export_code = | 
| + export_metadata->GetValueChecked<Code>(kExportCode); | 
| + RecordStats(isolate, *export_code); | 
| Handle<String> name = | 
| - Handle<String>(String::cast(function->shared()->name())); | 
| - function->SetInternalField(0, *instance); | 
| - | 
| + export_metadata->GetValueChecked<String>(kExportName); | 
| + int arity = Smi::cast(export_metadata->get(kExportArity))->value(); | 
| + Handle<JSFunction> function = | 
| + CreateExport(isolate, export_code, name, arity, instance); | 
| desc.set_value(function); | 
| Maybe<bool> status = JSReceiver::DefineOwnProperty( | 
| isolate, exports_object, name, &desc, Object::THROW_ON_ERROR); | 
| @@ -991,13 +1021,17 @@ MaybeHandle<FixedArray> WasmModule::CompileFunctions(Isolate* isolate) const { | 
| MaybeHandle<FixedArray> nothing; | 
| WasmModuleInstance temp_instance_for_compilation(this); | 
| - temp_instance_for_compilation.function_table = | 
| - BuildFunctionTable(isolate, 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; | 
| + MaybeHandle<FixedArray> indirect_table = BuildFunctionTable(isolate, this); | 
| + if (!indirect_table.is_null()) { | 
| + temp_instance_for_compilation.function_table = | 
| + indirect_table.ToHandleChecked(); | 
| + } | 
| + | 
| HistogramTimerScope wasm_compile_module_time_scope( | 
| isolate->counters()->wasm_compile_module_time()); | 
| @@ -1028,8 +1062,6 @@ MaybeHandle<FixedArray> WasmModule::CompileFunctions(Isolate* isolate) const { | 
| } | 
| if (thrower.error()) return nothing; | 
| - LinkModuleFunctions(isolate, temp_instance_for_compilation.function_code); | 
| - | 
| // 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) { | 
| @@ -1037,8 +1069,6 @@ MaybeHandle<FixedArray> WasmModule::CompileFunctions(Isolate* isolate) const { | 
| compiled_functions->set(static_cast<int>(i), code); | 
| } | 
| - PopulateFunctionTable(&temp_instance_for_compilation); | 
| - | 
| // 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 | 
| @@ -1046,27 +1076,41 @@ MaybeHandle<FixedArray> WasmModule::CompileFunctions(Isolate* isolate) const { | 
| 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()); | 
| + } | 
| Handle<FixedArray> import_data = GetImportsMetadata(factory, this); | 
| ret->set(kImportData, *import_data); | 
| // Compile export functions. | 
| int export_size = static_cast<int>(export_table.size()); | 
| - Handle<JSFunction> startup_fct; | 
| + Handle<Code> startup_fct; | 
| 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]; | 
| 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<JSFunction> function = compiler::CompileJSToWasmWrapper( | 
| - isolate, &module_env, name, code, exp.func_index); | 
| + Handle<Code> export_code = compiler::CompileJSToWasmWrapper( | 
| + isolate, &module_env, code, exp.func_index); | 
| if (thrower.error()) return nothing; | 
| - exports->set(i, *function); | 
| + export_metadata->set(kExportCode, *export_code); | 
| 
rossberg
2016/07/11 10:49:45
Instead of spreading the details here and elsewher
 
Mircea Trofin
2016/07/11 16:52:57
It's not really a WasmExport anymore, because it h
 | 
| + 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 = function; | 
| + startup_fct = export_code; | 
| } | 
| } | 
| ret->set(kExports, *exports); | 
| @@ -1074,15 +1118,20 @@ MaybeHandle<FixedArray> WasmModule::CompileFunctions(Isolate* isolate) const { | 
| // Compile startup function, if we haven't already. | 
| if (start_function_index >= 0) { | 
| + uint32_t index = static_cast<uint32_t>(start_function_index); | 
| HandleScope scope(isolate); | 
| if (startup_fct.is_null()) { | 
| - uint32_t index = static_cast<uint32_t>(start_function_index); | 
| - Handle<String> name = factory->NewStringFromStaticChars("start"); | 
| Handle<Code> code = temp_instance_for_compilation.function_code[index]; | 
| - startup_fct = compiler::CompileJSToWasmWrapper(isolate, &module_env, name, | 
| - code, index); | 
| + DCHECK_EQ(0, functions[index].sig->parameter_count()); | 
| + startup_fct = | 
| + compiler::CompileJSToWasmWrapper(isolate, &module_env, code, index); | 
| } | 
| - ret->set(kStartupFunction, *startup_fct); | 
| + 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); | 
| } | 
| // TODO(wasm): saving the module bytes for debugging is wasteful. We should | 
| @@ -1109,6 +1158,108 @@ MaybeHandle<FixedArray> WasmModule::CompileFunctions(Isolate* isolate) const { | 
| return ret; | 
| } | 
| +void PatchJSWrapper(Isolate* isolate, Handle<Code> wrapper, | 
| + Handle<Code> new_target) { | 
| + AllowDeferredHandleDereference embedding_raw_address; | 
| + bool seen = false; | 
| + for (RelocIterator it(*wrapper, 1 << RelocInfo::CODE_TARGET); !it.done(); | 
| + it.next()) { | 
| + Code* target = Code::GetCodeFromTargetAddress(it.rinfo()->target_address()); | 
| + if (target->kind() == Code::WASM_FUNCTION) { | 
| + DCHECK(!seen); | 
| + seen = true; | 
| + it.rinfo()->set_target_address(new_target->instruction_start(), | 
| + UPDATE_WRITE_BARRIER, SKIP_ICACHE_FLUSH); | 
| + } | 
| + } | 
| + CHECK(seen); | 
| + Assembler::FlushICache(isolate, wrapper->instruction_start(), | 
| + wrapper->instruction_size()); | 
| +} | 
| + | 
| +Handle<FixedArray> CloneModuleForInstance(Isolate* isolate, | 
| + Handle<FixedArray> original) { | 
| + Factory* factory = isolate->factory(); | 
| + Handle<FixedArray> clone = factory->CopyFixedArray(original); | 
| + | 
| + 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); | 
| + | 
| + MaybeHandle<FixedArray> maybe_indirect_table = | 
| + original->GetValue<FixedArray>(kIndirectFunctionTablePrototype); | 
| + | 
| + Handle<FixedArray> indirect_table; | 
| + Handle<FixedArray> old_table; | 
| + if (!maybe_indirect_table.is_null()) { | 
| 
rossberg
2016/07/11 10:49:45
Nit: use ToHandle instead of separate is_null and
 
Mircea Trofin
2016/07/11 16:52:57
Done.
 | 
| + old_table = maybe_indirect_table.ToHandleChecked(); | 
| + indirect_table = factory->CopyFixedArray(old_table); | 
| + clone->set(kIndirectFunctionTablePrototype, *indirect_table); | 
| + } | 
| + | 
| + 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); | 
| + } | 
| + } | 
| + | 
| + MaybeHandle<FixedArray> maybe_orig_exports = | 
| + original->GetValue<FixedArray>(kExports); | 
| + if (!maybe_orig_exports.is_null()) { | 
| + Handle<FixedArray> orig_exports = maybe_orig_exports.ToHandleChecked(); | 
| + 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>(i); | 
| + Handle<FixedArray> clone_metadata = | 
| + factory->CopyFixedArray(export_metadata); | 
| + cloned_exports->set(i, *clone_metadata); | 
| + Handle<Code> orig_code = | 
| + export_metadata->GetValueChecked<Code>(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. We should fix this in | 
| 
rossberg
2016/07/11 10:49:45
FixedArray cannot actually support the full uint32
 
Mircea Trofin
2016/07/11 16:52:57
We should talk about this separately. I trimmed th
 | 
| + // FixedArray, by | 
| + // moving it to size_t indexing, like std::vector does. | 
| + 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>(exported_fct_index); | 
| + PatchJSWrapper(isolate, cloned_code, new_target); | 
| + } | 
| + } | 
| + | 
| + MaybeHandle<FixedArray> maybe_startup = | 
| + original->GetValue<FixedArray>(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>(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>(startup_fct_index); | 
| + PatchJSWrapper(isolate, startup_fct_clone, new_target); | 
| + } | 
| + 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 | 
| @@ -1122,10 +1273,21 @@ MaybeHandle<JSObject> WasmModule::Instantiate( | 
| ErrorThrower thrower(isolate, "WasmModule::Instantiate()"); | 
| Factory* factory = isolate->factory(); | 
| + compiled_module = CloneModuleForInstance(isolate, compiled_module); | 
| + | 
| // These fields are compulsory. | 
| 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); | 
| + } | 
| + | 
| RecordStats(isolate, code_table); | 
| MaybeHandle<JSObject> nothing; | 
| @@ -1146,14 +1308,36 @@ MaybeHandle<JSObject> WasmModule::Instantiate( | 
| SetDebugSupport(factory, compiled_module, js_object); | 
| + FlushAssemblyCache(isolate, code_table); | 
| + | 
| + MaybeHandle<FixedArray> maybe_indirect_table = | 
| + compiled_module->GetValue<FixedArray>(kIndirectFunctionTablePrototype); | 
| + if (!maybe_indirect_table.is_null()) { | 
| + int table_size = | 
| + Smi::cast(compiled_module->get(kIndirectFunctionTableSize))->value(); | 
| + Handle<FixedArray> indirect_table = maybe_indirect_table.ToHandleChecked(); | 
| + 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)); | 
| + } | 
| + js_object->SetInternalField(kWasmModuleFunctionTable, *indirect_table); | 
| + } | 
| + | 
| // Run the start function if one was specified. | 
| - MaybeHandle<JSFunction> maybe_startup_fct = | 
| - compiled_module->GetValue<JSFunction>(kStartupFunction); | 
| + MaybeHandle<FixedArray> maybe_startup_fct = | 
| + compiled_module->GetValue<FixedArray>(kStartupFunction); | 
| if (!maybe_startup_fct.is_null()) { | 
| HandleScope scope(isolate); | 
| - Handle<JSFunction> startup_fct = maybe_startup_fct.ToHandleChecked(); | 
| - RecordStats(isolate, startup_fct->code()); | 
| - startup_fct->SetInternalField(0, *js_object); | 
| + Handle<FixedArray> metadata = maybe_startup_fct.ToHandleChecked(); | 
| + Handle<Code> startup_code = metadata->GetValueChecked<Code>(kExportCode); | 
| + int arity = Smi::cast(metadata->get(kExportArity))->value(); | 
| + Handle<JSFunction> startup_fct = | 
| + CreateExport(isolate, startup_code, | 
| + factory->InternalizeUtf8String("start"), arity, js_object); | 
| + RecordStats(isolate, *startup_code); | 
| // Call the JS function. | 
| Handle<Object> undefined = isolate->factory()->undefined_value(); | 
| MaybeHandle<Object> retval = | 
| @@ -1334,10 +1518,9 @@ int32_t CompileAndRunWasmModule(Isolate* isolate, const byte* module_start, | 
| if (compiled_module.is_null()) return -1; | 
| Handle<JSObject> instance = | 
| - module | 
| - ->Instantiate(isolate, compiled_module.ToHandleChecked(), | 
| - Handle<JSReceiver>::null(), | 
| - Handle<JSArrayBuffer>::null()) | 
| + WasmModule::Instantiate(isolate, compiled_module.ToHandleChecked(), | 
| + Handle<JSReceiver>::null(), | 
| + Handle<JSArrayBuffer>::null()) | 
| .ToHandleChecked(); | 
| Handle<Name> exports = isolate->factory()->InternalizeUtf8String("exports"); |