| Index: src/wasm/wasm-module.cc
|
| diff --git a/src/wasm/wasm-module.cc b/src/wasm/wasm-module.cc
|
| index 57e3c60752cfb41b658376ef0849fc3175d96987..f075b1e40903a54f3527bf9eb5f53f40cbc32252 100644
|
| --- a/src/wasm/wasm-module.cc
|
| +++ b/src/wasm/wasm-module.cc
|
| @@ -445,36 +445,99 @@ void CompileSequentially(Isolate* isolate, ModuleBytesEnv* module_env,
|
| }
|
| }
|
|
|
| -void PatchDirectCalls(Handle<FixedArray> old_functions,
|
| - Handle<FixedArray> new_functions, int start) {
|
| - DCHECK_EQ(new_functions->length(), old_functions->length());
|
| +int ExtractDirectCallIndex(wasm::Decoder& decoder, const byte* pc) {
|
| + DCHECK_EQ(static_cast<int>(kExprCallFunction), static_cast<int>(*pc));
|
| + decoder.Reset(pc + 1, pc + 6);
|
| + uint32_t call_idx = decoder.consume_u32v("call index");
|
| + DCHECK(decoder.ok());
|
| + DCHECK_GE(kMaxInt, call_idx);
|
| + return static_cast<int>(call_idx);
|
| +}
|
| +
|
| +int AdvanceSourcePositionTableIterator(SourcePositionTableIterator& iterator,
|
| + size_t offset_l) {
|
| + DCHECK_GE(kMaxInt, offset_l);
|
| + int offset = static_cast<int>(offset_l);
|
| + DCHECK(!iterator.done());
|
| + int byte_pos;
|
| + do {
|
| + byte_pos = iterator.source_position().ScriptOffset();
|
| + iterator.Advance();
|
| + } while (!iterator.done() && iterator.code_offset() <= offset);
|
| + return byte_pos;
|
| +}
|
|
|
| +void PatchDirectCalls(Handle<FixedArray> new_functions,
|
| + Handle<WasmCompiledModule> compiled_module,
|
| + WasmModule* module, int start) {
|
| DisallowHeapAllocation no_gc;
|
| - std::map<Code*, Code*> old_to_new_code;
|
| - for (int i = 0; i < new_functions->length(); ++i) {
|
| - old_to_new_code.insert(std::make_pair(Code::cast(old_functions->get(i)),
|
| - Code::cast(new_functions->get(i))));
|
| - }
|
| - int mode_mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET);
|
| AllowDeferredHandleDereference embedding_raw_address;
|
| - 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 =
|
| - Code::GetCodeFromTargetAddress(it.rinfo()->target_address());
|
| - if (old_code->kind() == Code::WASM_TO_JS_FUNCTION ||
|
| - old_code->kind() == Code::WASM_FUNCTION) {
|
| - auto found = old_to_new_code.find(old_code);
|
| - DCHECK(found != old_to_new_code.end());
|
| - Code* new_code = found->second;
|
| - if (new_code != old_code) {
|
| - it.rinfo()->set_target_address(new_code->instruction_start(),
|
| - UPDATE_WRITE_BARRIER,
|
| - SKIP_ICACHE_FLUSH);
|
| - }
|
| - }
|
| + SeqOneByteString* module_bytes = compiled_module->module_bytes();
|
| + std::vector<WasmFunction>* wasm_functions =
|
| + &compiled_module->module()->functions;
|
| + DCHECK_EQ(wasm_functions->size() +
|
| + compiled_module->module()->num_exported_functions,
|
| + new_functions->length());
|
| + DCHECK_EQ(start, compiled_module->module()->num_imported_functions);
|
| +
|
| + // Allocate decoder outside of the loop and reuse it to decode all function
|
| + // indexes.
|
| + wasm::Decoder decoder(nullptr, nullptr);
|
| + int num_wasm_functions = static_cast<int>(wasm_functions->size());
|
| + int func_index = start;
|
| + // Patch all wasm functions.
|
| + for (; func_index < num_wasm_functions; ++func_index) {
|
| + Code* wasm_function = Code::cast(new_functions->get(func_index));
|
| + DCHECK(wasm_function->kind() == Code::WASM_FUNCTION);
|
| + // Iterate simultaneously over the relocation information and the source
|
| + // position table. For each call in the reloc info, move the source position
|
| + // iterator forward to that position to find the byte offset of the
|
| + // respective call. Then extract the call index from the module wire bytes
|
| + // to find the new compiled function.
|
| + SourcePositionTableIterator source_pos_iterator(
|
| + wasm_function->source_position_table());
|
| + const byte* func_bytes =
|
| + module_bytes->GetChars() +
|
| + compiled_module->module()->functions[func_index].code_start_offset;
|
| + for (RelocIterator it(wasm_function, RelocInfo::kCodeTargetMask);
|
| + !it.done(); it.next()) {
|
| + Code::Kind kind =
|
| + Code::GetCodeFromTargetAddress(it.rinfo()->target_address())->kind();
|
| + if (kind != Code::WASM_FUNCTION && kind != Code::WASM_TO_JS_FUNCTION)
|
| + continue;
|
| + size_t offset = it.rinfo()->pc() - wasm_function->instruction_start();
|
| + int byte_pos =
|
| + AdvanceSourcePositionTableIterator(source_pos_iterator, offset);
|
| + int called_func_index =
|
| + ExtractDirectCallIndex(decoder, func_bytes + byte_pos);
|
| + Code* new_code = Code::cast(new_functions->get(called_func_index));
|
| + it.rinfo()->set_target_address(new_code->instruction_start(),
|
| + UPDATE_WRITE_BARRIER, SKIP_ICACHE_FLUSH);
|
| + }
|
| + }
|
| + // Patch all exported functions.
|
| + for (auto exp : module->export_table) {
|
| + if (exp.kind != kExternalFunction) continue;
|
| + Code* export_wrapper = Code::cast(new_functions->get(func_index));
|
| + DCHECK_EQ(Code::JS_TO_WASM_FUNCTION, export_wrapper->kind());
|
| + // There must be exactly one call to WASM_FUNCTION or WASM_TO_JS_FUNCTION.
|
| + int num_wasm_calls = 0;
|
| + for (RelocIterator it(export_wrapper, RelocInfo::kCodeTargetMask);
|
| + !it.done(); it.next()) {
|
| + Code::Kind kind =
|
| + Code::GetCodeFromTargetAddress(it.rinfo()->target_address())->kind();
|
| + if (kind != Code::WASM_FUNCTION && kind != Code::WASM_TO_JS_FUNCTION)
|
| + continue;
|
| + ++num_wasm_calls;
|
| + Code* new_code = Code::cast(new_functions->get(exp.index));
|
| + DCHECK_EQ(kind, new_code->kind());
|
| + it.rinfo()->set_target_address(new_code->instruction_start(),
|
| + UPDATE_WRITE_BARRIER, SKIP_ICACHE_FLUSH);
|
| }
|
| + DCHECK_EQ(1, num_wasm_calls);
|
| + func_index++;
|
| }
|
| + DCHECK_EQ(new_functions->length(), func_index);
|
| }
|
|
|
| static void ResetCompiledModule(Isolate* isolate, WasmInstanceObject* owner,
|
| @@ -1305,7 +1368,8 @@ class WasmInstanceBuilder {
|
|
|
| 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);
|
| + PatchDirectCalls(code_table, compiled_module_, module_,
|
| + num_imported_functions);
|
| }
|
|
|
| FlushICache(isolate_, code_table);
|
|
|