OLD | NEW |
1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/compiler/wasm-compiler.h" | 5 #include "src/compiler/wasm-compiler.h" |
6 | 6 |
7 #include <memory> | 7 #include <memory> |
8 | 8 |
9 #include "src/isolate-inl.h" | 9 #include "src/isolate-inl.h" |
10 | 10 |
(...skipping 18 matching lines...) Expand all Loading... |
29 #include "src/compiler/zone-stats.h" | 29 #include "src/compiler/zone-stats.h" |
30 | 30 |
31 #include "src/code-factory.h" | 31 #include "src/code-factory.h" |
32 #include "src/code-stubs.h" | 32 #include "src/code-stubs.h" |
33 #include "src/factory.h" | 33 #include "src/factory.h" |
34 #include "src/log-inl.h" | 34 #include "src/log-inl.h" |
35 | 35 |
36 #include "src/wasm/function-body-decoder.h" | 36 #include "src/wasm/function-body-decoder.h" |
37 #include "src/wasm/wasm-limits.h" | 37 #include "src/wasm/wasm-limits.h" |
38 #include "src/wasm/wasm-module.h" | 38 #include "src/wasm/wasm-module.h" |
| 39 #include "src/wasm/wasm-objects.h" |
39 #include "src/wasm/wasm-opcodes.h" | 40 #include "src/wasm/wasm-opcodes.h" |
40 #include "src/wasm/wasm-text.h" | 41 #include "src/wasm/wasm-text.h" |
41 | 42 |
42 // TODO(titzer): pull WASM_64 up to a common header. | 43 // TODO(titzer): pull WASM_64 up to a common header. |
43 #if !V8_TARGET_ARCH_32_BIT || V8_TARGET_ARCH_X64 | 44 #if !V8_TARGET_ARCH_32_BIT || V8_TARGET_ARCH_X64 |
44 #define WASM_64 1 | 45 #define WASM_64 1 |
45 #else | 46 #else |
46 #define WASM_64 0 | 47 #define WASM_64 0 |
47 #endif | 48 #endif |
48 | 49 |
(...skipping 14 matching lines...) Expand all Loading... |
63 NodeProperties::MergeControlToEnd(g, jsgraph->common(), node); | 64 NodeProperties::MergeControlToEnd(g, jsgraph->common(), node); |
64 } else { | 65 } else { |
65 g->SetEnd(g->NewNode(jsgraph->common()->End(1), node)); | 66 g->SetEnd(g->NewNode(jsgraph->common()->End(1), node)); |
66 } | 67 } |
67 } | 68 } |
68 | 69 |
69 Node* BuildCallToRuntime(Runtime::FunctionId f, JSGraph* jsgraph, | 70 Node* BuildCallToRuntime(Runtime::FunctionId f, JSGraph* jsgraph, |
70 Handle<Context> context, Node** parameters, | 71 Handle<Context> context, Node** parameters, |
71 int parameter_count, Node** effect_ptr, | 72 int parameter_count, Node** effect_ptr, |
72 Node* control) { | 73 Node* control) { |
73 // At the moment we only allow 2 parameters. If more parameters are needed, | |
74 // then the size of {inputs} below has to be increased accordingly. | |
75 DCHECK(parameter_count <= 2); | |
76 const Runtime::Function* fun = Runtime::FunctionForId(f); | 74 const Runtime::Function* fun = Runtime::FunctionForId(f); |
77 CallDescriptor* desc = Linkage::GetRuntimeCallDescriptor( | 75 CallDescriptor* desc = Linkage::GetRuntimeCallDescriptor( |
78 jsgraph->zone(), f, fun->nargs, Operator::kNoProperties, | 76 jsgraph->zone(), f, fun->nargs, Operator::kNoProperties, |
79 CallDescriptor::kNoFlags); | 77 CallDescriptor::kNoFlags); |
80 // CEntryStubConstant nodes have to be created and cached in the main | 78 // CEntryStubConstant nodes have to be created and cached in the main |
81 // thread. At the moment this is only done for CEntryStubConstant(1). | 79 // thread. At the moment this is only done for CEntryStubConstant(1). |
82 DCHECK_EQ(1, fun->result_size); | 80 DCHECK_EQ(1, fun->result_size); |
83 Node* inputs[8]; | 81 // At the moment we only allow 2 parameters. If more parameters are needed, |
| 82 // increase this constant accordingly. |
| 83 static const int kMaxParams = 3; |
| 84 DCHECK_GE(kMaxParams, parameter_count); |
| 85 Node* inputs[kMaxParams + 6]; |
84 int count = 0; | 86 int count = 0; |
85 inputs[count++] = jsgraph->CEntryStubConstant(fun->result_size); | 87 inputs[count++] = jsgraph->CEntryStubConstant(fun->result_size); |
86 for (int i = 0; i < parameter_count; i++) { | 88 for (int i = 0; i < parameter_count; i++) { |
87 inputs[count++] = parameters[i]; | 89 inputs[count++] = parameters[i]; |
88 } | 90 } |
89 inputs[count++] = jsgraph->ExternalConstant( | 91 inputs[count++] = jsgraph->ExternalConstant( |
90 ExternalReference(f, jsgraph->isolate())); // ref | 92 ExternalReference(f, jsgraph->isolate())); // ref |
91 inputs[count++] = jsgraph->Int32Constant(fun->nargs); // arity | 93 inputs[count++] = jsgraph->Int32Constant(fun->nargs); // arity |
92 inputs[count++] = jsgraph->HeapConstant(context); // context | 94 inputs[count++] = jsgraph->HeapConstant(context); // context |
93 inputs[count++] = *effect_ptr; | 95 inputs[count++] = *effect_ptr; |
(...skipping 2826 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2920 | 2922 |
2921 // Convert the return value back. | 2923 // Convert the return value back. |
2922 Node* i32_zero = jsgraph()->Int32Constant(0); | 2924 Node* i32_zero = jsgraph()->Int32Constant(0); |
2923 Node* val = sig->return_count() == 0 | 2925 Node* val = sig->return_count() == 0 |
2924 ? i32_zero | 2926 ? i32_zero |
2925 : FromJS(call, HeapConstant(isolate->native_context()), | 2927 : FromJS(call, HeapConstant(isolate->native_context()), |
2926 sig->GetReturn()); | 2928 sig->GetReturn()); |
2927 Return(val); | 2929 Return(val); |
2928 } | 2930 } |
2929 | 2931 |
| 2932 void WasmGraphBuilder::BuildWasmInterpreterEntry( |
| 2933 uint32_t function_index, wasm::FunctionSig* sig, |
| 2934 Handle<WasmInstanceObject> instance) { |
| 2935 int wasm_count = static_cast<int>(sig->parameter_count()); |
| 2936 int param_count = jsgraph()->machine()->Is64() |
| 2937 ? wasm_count |
| 2938 : Int64Lowering::GetParameterCountAfterLowering(sig); |
| 2939 |
| 2940 // Build the start and the parameter nodes. |
| 2941 Node* start = Start(param_count + 3); |
| 2942 *effect_ = start; |
| 2943 *control_ = start; |
| 2944 |
| 2945 // Compute size for the argument buffer. |
| 2946 int args_size_bytes = 0; |
| 2947 for (int i = 0; i < wasm_count; i++) { |
| 2948 args_size_bytes += 1 << ElementSizeLog2Of(sig->GetParam(i)); |
| 2949 } |
| 2950 |
| 2951 // The return value is also passed via this buffer: |
| 2952 DCHECK_GE(1, sig->return_count()); |
| 2953 int return_size_bytes = |
| 2954 sig->return_count() == 0 ? 0 : 1 << ElementSizeLog2Of(sig->GetReturn(0)); |
| 2955 |
| 2956 // Get a stack slot for the arguments. |
| 2957 Node* arg_buffer = graph()->NewNode(jsgraph()->machine()->StackSlot( |
| 2958 std::max(args_size_bytes, return_size_bytes))); |
| 2959 |
| 2960 // Now store all our arguments to the buffer. |
| 2961 int param_index = 0; |
| 2962 int offset = 0; |
| 2963 for (int i = 0; i < wasm_count; i++) { |
| 2964 Node* param = Param(param_index++); |
| 2965 bool is_i64_as_two_params = |
| 2966 jsgraph()->machine()->Is32() && sig->GetParam(i) == wasm::kWasmI64; |
| 2967 MachineRepresentation param_rep = |
| 2968 is_i64_as_two_params ? wasm::kWasmI32 : sig->GetParam(i); |
| 2969 StoreRepresentation store_rep(param_rep, WriteBarrierKind::kNoWriteBarrier); |
| 2970 *effect_ = |
| 2971 graph()->NewNode(jsgraph()->machine()->Store(store_rep), arg_buffer, |
| 2972 Int32Constant(offset), param, *effect_, *control_); |
| 2973 offset += 1 << ElementSizeLog2Of(param_rep); |
| 2974 // TODO(clemensh): Respect endianess here. Might need to swap upper and |
| 2975 // lower word. |
| 2976 if (is_i64_as_two_params) { |
| 2977 // Also store the upper half. |
| 2978 param = Param(param_index++); |
| 2979 StoreRepresentation store_rep(wasm::kWasmI32, |
| 2980 WriteBarrierKind::kNoWriteBarrier); |
| 2981 *effect_ = |
| 2982 graph()->NewNode(jsgraph()->machine()->Store(store_rep), arg_buffer, |
| 2983 Int32Constant(offset), param, *effect_, *control_); |
| 2984 offset += 1 << ElementSizeLog2Of(wasm::kWasmI32); |
| 2985 } |
| 2986 } |
| 2987 DCHECK_EQ(param_count, param_index); |
| 2988 DCHECK_EQ(args_size_bytes, offset); |
| 2989 |
| 2990 // We are passing the raw arg_buffer here. To the GC and other parts, it looks |
| 2991 // like a Smi (lowest bit not set). In the runtime function however, don't |
| 2992 // call Smi::value on it, but just cast it to a byte pointer. |
| 2993 Node* parameters[] = { |
| 2994 jsgraph()->HeapConstant(instance), // wasm instance |
| 2995 jsgraph()->SmiConstant(function_index), // function index |
| 2996 arg_buffer, // argument buffer |
| 2997 }; |
| 2998 BuildCallToRuntime(Runtime::kWasmRunInterpreter, jsgraph(), |
| 2999 jsgraph()->isolate()->native_context(), parameters, |
| 3000 arraysize(parameters), effect_, *control_); |
| 3001 |
| 3002 // Read back the return value. |
| 3003 if (jsgraph()->machine()->Is32() && sig->return_count() > 0 && |
| 3004 sig->GetReturn() == wasm::kWasmI64) { |
| 3005 MachineType load_rep = wasm::WasmOpcodes::MachineTypeFor(wasm::kWasmI32); |
| 3006 Node* lower = |
| 3007 graph()->NewNode(jsgraph()->machine()->Load(load_rep), arg_buffer, |
| 3008 Int32Constant(0), *effect_, *control_); |
| 3009 Node* upper = |
| 3010 graph()->NewNode(jsgraph()->machine()->Load(load_rep), arg_buffer, |
| 3011 Int32Constant(sizeof(int32_t)), *effect_, *control_); |
| 3012 Return(upper, lower); |
| 3013 } else { |
| 3014 Node* val; |
| 3015 if (sig->return_count() == 0) { |
| 3016 val = Int32Constant(0); |
| 3017 } else { |
| 3018 MachineType load_rep = |
| 3019 wasm::WasmOpcodes::MachineTypeFor(sig->GetReturn()); |
| 3020 val = graph()->NewNode(jsgraph()->machine()->Load(load_rep), arg_buffer, |
| 3021 Int32Constant(0), *effect_, *control_); |
| 3022 } |
| 3023 Return(val); |
| 3024 } |
| 3025 } |
| 3026 |
2930 Node* WasmGraphBuilder::MemBuffer(uint32_t offset) { | 3027 Node* WasmGraphBuilder::MemBuffer(uint32_t offset) { |
2931 DCHECK(module_ && module_->instance); | 3028 DCHECK(module_ && module_->instance); |
2932 if (offset == 0) { | 3029 if (offset == 0) { |
2933 if (!mem_buffer_) { | 3030 if (!mem_buffer_) { |
2934 mem_buffer_ = jsgraph()->RelocatableIntPtrConstant( | 3031 mem_buffer_ = jsgraph()->RelocatableIntPtrConstant( |
2935 reinterpret_cast<uintptr_t>(module_->instance->mem_start), | 3032 reinterpret_cast<uintptr_t>(module_->instance->mem_start), |
2936 RelocInfo::WASM_MEMORY_REFERENCE); | 3033 RelocInfo::WASM_MEMORY_REFERENCE); |
2937 } | 3034 } |
2938 return mem_buffer_; | 3035 return mem_buffer_; |
2939 } else { | 3036 } else { |
(...skipping 561 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3501 } | 3598 } |
3502 RecordFunctionCompilation( | 3599 RecordFunctionCompilation( |
3503 CodeEventListener::FUNCTION_TAG, isolate, code, "wasm-to-js", index, | 3600 CodeEventListener::FUNCTION_TAG, isolate, code, "wasm-to-js", index, |
3504 {module_name->ToCString().get(), module_name->length()}, | 3601 {module_name->ToCString().get(), module_name->length()}, |
3505 {function_name, function_name_size}); | 3602 {function_name, function_name_size}); |
3506 } | 3603 } |
3507 | 3604 |
3508 return code; | 3605 return code; |
3509 } | 3606 } |
3510 | 3607 |
| 3608 Handle<Code> CompileWasmInterpreterEntry(Isolate* isolate, uint32_t func_index, |
| 3609 wasm::FunctionSig* sig, |
| 3610 Handle<WasmInstanceObject> instance) { |
| 3611 //---------------------------------------------------------------------------- |
| 3612 // Create the Graph |
| 3613 //---------------------------------------------------------------------------- |
| 3614 Zone zone(isolate->allocator(), ZONE_NAME); |
| 3615 Graph graph(&zone); |
| 3616 CommonOperatorBuilder common(&zone); |
| 3617 MachineOperatorBuilder machine(&zone); |
| 3618 JSGraph jsgraph(isolate, &graph, &common, nullptr, nullptr, &machine); |
| 3619 |
| 3620 Node* control = nullptr; |
| 3621 Node* effect = nullptr; |
| 3622 |
| 3623 WasmGraphBuilder builder(nullptr, &zone, &jsgraph, sig); |
| 3624 builder.set_control_ptr(&control); |
| 3625 builder.set_effect_ptr(&effect); |
| 3626 builder.BuildWasmInterpreterEntry(func_index, sig, instance); |
| 3627 |
| 3628 Handle<Code> code = Handle<Code>::null(); |
| 3629 { |
| 3630 if (FLAG_trace_turbo_graph) { // Simple textual RPO. |
| 3631 OFStream os(stdout); |
| 3632 os << "-- Wasm to interpreter graph -- " << std::endl; |
| 3633 os << AsRPO(graph); |
| 3634 } |
| 3635 |
| 3636 // Schedule and compile to machine code. |
| 3637 CallDescriptor* incoming = |
| 3638 wasm::ModuleEnv::GetWasmCallDescriptor(&zone, sig); |
| 3639 if (machine.Is32()) { |
| 3640 incoming = wasm::ModuleEnv::GetI32WasmCallDescriptor(&zone, incoming); |
| 3641 } |
| 3642 Code::Flags flags = Code::ComputeFlags(Code::WASM_INTERPRETER_ENTRY); |
| 3643 EmbeddedVector<char, 32> debug_name; |
| 3644 int name_len = SNPrintF(debug_name, "wasm-to-interpreter#%d", func_index); |
| 3645 DCHECK(name_len > 0 && name_len < debug_name.length()); |
| 3646 debug_name.Truncate(name_len); |
| 3647 DCHECK_EQ('\0', debug_name.start()[debug_name.length()]); |
| 3648 |
| 3649 CompilationInfo info(debug_name, isolate, &zone, flags); |
| 3650 code = Pipeline::GenerateCodeForTesting(&info, incoming, &graph, nullptr); |
| 3651 #ifdef ENABLE_DISASSEMBLER |
| 3652 if (FLAG_print_opt_code && !code.is_null()) { |
| 3653 OFStream os(stdout); |
| 3654 code->Disassemble(debug_name.start(), os); |
| 3655 } |
| 3656 #endif |
| 3657 |
| 3658 if (isolate->logger()->is_logging_code_events() || |
| 3659 isolate->is_profiling()) { |
| 3660 RecordFunctionCompilation(CodeEventListener::FUNCTION_TAG, isolate, code, |
| 3661 "wasm-to-interpreter", func_index, |
| 3662 wasm::WasmName("module"), debug_name); |
| 3663 } |
| 3664 } |
| 3665 |
| 3666 Handle<FixedArray> deopt_data = isolate->factory()->NewFixedArray(1, TENURED); |
| 3667 Handle<WeakCell> weak_instance = isolate->factory()->NewWeakCell(instance); |
| 3668 deopt_data->set(0, *weak_instance); |
| 3669 code->set_deoptimization_data(*deopt_data); |
| 3670 |
| 3671 return code; |
| 3672 } |
| 3673 |
3511 SourcePositionTable* WasmCompilationUnit::BuildGraphForWasmFunction( | 3674 SourcePositionTable* WasmCompilationUnit::BuildGraphForWasmFunction( |
3512 double* decode_ms) { | 3675 double* decode_ms) { |
3513 base::ElapsedTimer decode_timer; | 3676 base::ElapsedTimer decode_timer; |
3514 if (FLAG_trace_wasm_decode_time) { | 3677 if (FLAG_trace_wasm_decode_time) { |
3515 decode_timer.Start(); | 3678 decode_timer.Start(); |
3516 } | 3679 } |
3517 // Create a TF graph during decoding. | 3680 // Create a TF graph during decoding. |
3518 | 3681 |
3519 Graph* graph = jsgraph_->graph(); | 3682 Graph* graph = jsgraph_->graph(); |
3520 CommonOperatorBuilder* common = jsgraph_->common(); | 3683 CommonOperatorBuilder* common = jsgraph_->common(); |
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3708 Smi::FromInt(instruction.instr_offset)); | 3871 Smi::FromInt(instruction.instr_offset)); |
3709 fn_protected->set(Code::kTrapDataSize * i + Code::kTrapLandingOffset, | 3872 fn_protected->set(Code::kTrapDataSize * i + Code::kTrapLandingOffset, |
3710 Smi::FromInt(instruction.landing_offset)); | 3873 Smi::FromInt(instruction.landing_offset)); |
3711 } | 3874 } |
3712 return fn_protected; | 3875 return fn_protected; |
3713 } | 3876 } |
3714 | 3877 |
3715 } // namespace compiler | 3878 } // namespace compiler |
3716 } // namespace internal | 3879 } // namespace internal |
3717 } // namespace v8 | 3880 } // namespace v8 |
OLD | NEW |