Index: src/compiler/wasm-compiler.cc |
diff --git a/src/compiler/wasm-compiler.cc b/src/compiler/wasm-compiler.cc |
index 0a13f98d8593f32e8990752d7d1a64451314ae6d..6a50324e1e14b8b82927441359d429217b9c6707 100644 |
--- a/src/compiler/wasm-compiler.cc |
+++ b/src/compiler/wasm-compiler.cc |
@@ -2493,6 +2493,107 @@ void WasmGraphBuilder::BuildWasmToJSWrapper(Handle<JSFunction> function, |
MergeControlToEnd(jsgraph(), ret); |
} |
+void WasmGraphBuilder::BuildWasmToInterpreter(uint32_t function_index, |
+ wasm::FunctionSig* sig, |
+ Handle<JSObject> wasm_obj) { |
+ int wasm_count = static_cast<int>(sig->parameter_count()); |
+ int param_count = jsgraph()->machine()->Is64() |
+ ? wasm_count |
+ : Int64Lowering::GetParameterCountAfterLowering(sig); |
+ |
+ // Build the start and the parameter nodes. |
+ Node* start = Start(param_count + 3); |
+ *effect_ = start; |
+ *control_ = start; |
+ |
+ auto build_runtime_call = [&](Runtime::FunctionId f) -> Node* { |
+ const Runtime::Function* fun = Runtime::FunctionForId(f); |
+ CallDescriptor* desc = Linkage::GetRuntimeCallDescriptor( |
+ jsgraph()->zone(), f, fun->nargs, Operator::kNoProperties, |
+ CallDescriptor::kNoFlags); |
+ DCHECK_EQ(1, fun->result_size); |
+ DCHECK_EQ(2, fun->nargs); |
+ Node* inputs[] = { |
+ jsgraph()->CEntryStubConstant(fun->result_size), // C entry |
+ jsgraph()->SmiConstant(function_index), // function index |
+ jsgraph()->HeapConstant(wasm_obj), // wasm object |
+ jsgraph()->ExternalConstant( |
+ ExternalReference(f, jsgraph()->isolate())), // ref |
+ jsgraph()->Int32Constant(fun->nargs), // arity |
+ HeapConstant(jsgraph()->isolate()->native_context()), // context |
+ *effect_, |
+ *control_}; |
+ Node* call = *control_ = *effect_ = |
+ graph()->NewNode(jsgraph()->common()->Call(desc), |
+ static_cast<int>(arraysize(inputs)), inputs); |
+ *control_ = call; |
+ *effect_ = call; |
+ return call; |
+ }; |
+ |
+ // Get a buffer to store all parameters. |
+ Node* arg_buffer = build_runtime_call(Runtime::kGetWasmInterpreterBuffer); |
+ |
+ // Now store all our parameters to the buffer. |
+ int param_index = 0; |
+ int offset = 0; |
+ for (int i = 0; i < wasm_count; i++) { |
+ Node* param = |
+ graph()->NewNode(jsgraph()->common()->Parameter(param_index++), start); |
+ bool is_lower_half_i64 = |
+ jsgraph()->machine()->Is32() && sig->GetParam(i) == wasm::kAstI64; |
+ MachineRepresentation param_rep = |
+ is_lower_half_i64 ? wasm::kAstI32 : sig->GetParam(i); |
+ StoreRepresentation store_rep(param_rep, WriteBarrierKind::kNoWriteBarrier); |
+ *effect_ = |
+ graph()->NewNode(jsgraph()->machine()->Store(store_rep), arg_buffer, |
+ Int32Constant(offset), param, *effect_, *control_); |
+ offset += 1 << ElementSizeLog2Of(param_rep); |
+ if (is_lower_half_i64) { |
+ // Also store the upper half. |
+ param = graph()->NewNode(jsgraph()->common()->Parameter(param_index++), |
+ start); |
+ StoreRepresentation store_rep(wasm::kAstI32, |
+ WriteBarrierKind::kNoWriteBarrier); |
+ *effect_ = |
+ graph()->NewNode(jsgraph()->machine()->Store(store_rep), arg_buffer, |
+ Int32Constant(offset), param, *effect_, *control_); |
+ offset += 1 << ElementSizeLog2Of(wasm::kAstI32); |
+ } |
+ } |
+ DCHECK_EQ(param_count, param_index); |
+ |
+ build_runtime_call(Runtime::kWasmRunInterpreter); |
+ |
+ // Convert the return value back. |
+ Node* ret; |
+ if (jsgraph()->machine()->Is32() && sig->return_count() > 0 && |
+ sig->GetReturn() == wasm::kAstI64) { |
+ LoadRepresentation load_rep(wasm::kAstI32, MachineSemantic::kNone); |
+ Node* lower = |
+ graph()->NewNode(jsgraph()->machine()->Load(load_rep), arg_buffer, |
+ Int32Constant(0), *effect_, *control_); |
+ Node* upper = |
+ graph()->NewNode(jsgraph()->machine()->Load(load_rep), arg_buffer, |
+ Int32Constant(4), *effect_, *control_); |
+ ret = graph()->NewNode(jsgraph()->common()->Return(), upper, lower, |
+ *effect_, *control_); |
+ } else { |
+ Node* val; |
+ if (sig->return_count() == 0) { |
+ val = Int32Constant(0); |
+ } else { |
+ LoadRepresentation load_rep(sig->GetReturn(), MachineSemantic::kNone); |
+ val = graph()->NewNode(jsgraph()->machine()->Load(load_rep), arg_buffer, |
+ Int32Constant(0), *effect_, *control_); |
+ } |
+ ret = graph()->NewNode(jsgraph()->common()->Return(), val, *effect_, |
+ *control_); |
+ } |
+ |
+ MergeControlToEnd(jsgraph(), ret); |
+} |
+ |
Node* WasmGraphBuilder::MemBuffer(uint32_t offset) { |
DCHECK(module_ && module_->instance); |
if (offset == 0) { |
@@ -3099,6 +3200,67 @@ Handle<Code> CompileWasmToJSWrapper(Isolate* isolate, |
return code; |
} |
+Handle<Code> CompileWasmToInterpreter(Isolate* isolate, uint32_t func_index, |
+ wasm::FunctionSig* sig, |
+ Handle<JSObject> wasm_obj) { |
+ //---------------------------------------------------------------------------- |
+ // Create the Graph |
+ //---------------------------------------------------------------------------- |
+ Zone zone(isolate->allocator()); |
+ Graph graph(&zone); |
+ CommonOperatorBuilder common(&zone); |
+ MachineOperatorBuilder machine(&zone); |
+ JSGraph jsgraph(isolate, &graph, &common, nullptr, nullptr, &machine); |
+ |
+ Node* control = nullptr; |
+ Node* effect = nullptr; |
+ |
+ WasmGraphBuilder builder(&zone, &jsgraph, sig); |
+ builder.set_control_ptr(&control); |
+ builder.set_effect_ptr(&effect); |
+ builder.BuildWasmToInterpreter(func_index, sig, wasm_obj); |
+ |
+ Handle<Code> code = Handle<Code>::null(); |
+ { |
+ if (FLAG_trace_turbo_graph) { // Simple textual RPO. |
+ OFStream os(stdout); |
+ os << "-- Wasm to interpreter graph -- " << std::endl; |
+ os << AsRPO(graph); |
+ } |
+ |
+ // Schedule and compile to machine code. |
+ CallDescriptor* incoming = |
+ wasm::ModuleEnv::GetWasmCallDescriptor(&zone, sig); |
+ if (machine.Is32()) { |
+ incoming = wasm::ModuleEnv::GetI32WasmCallDescriptor(&zone, incoming); |
+ } |
+ Code::Flags flags = Code::ComputeFlags(Code::WASM_TO_INTERPRETER); |
+ char buf[32]; |
+ int buf_len = |
+ SNPrintF(ArrayVector(buf), "wasm-to-interpreter#%d", func_index); |
+ DCHECK(buf_len > 0 && buf_len < sizeof(buf)); |
+ Vector<const char> debug_name(buf, buf_len); |
+ |
+ CompilationInfo info(debug_name, isolate, &zone, flags); |
+ code = Pipeline::GenerateCodeForTesting(&info, incoming, &graph, nullptr); |
+#ifdef ENABLE_DISASSEMBLER |
+ if (FLAG_print_opt_code && !code.is_null()) { |
+ OFStream os(stdout); |
+ code->Disassemble(buf, os); |
+ } |
+#endif |
+ |
+ RecordFunctionCompilation(CodeEventListener::FUNCTION_TAG, &info, buf, |
+ func_index, debug_name); |
+ } |
+ |
+ Handle<FixedArray> deopt_data = isolate->factory()->NewFixedArray(1); |
+ deopt_data->set(0, *wasm_obj); |
+ code->set_deoptimization_data(*deopt_data); |
+ |
+ return code; |
+} |
+ |
SourcePositionTable* WasmCompilationUnit::BuildGraphForWasmFunction( |
double* decode_ms) { |
base::ElapsedTimer decode_timer; |