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 2811 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2905 | 2907 |
2906 // Convert the return value back. | 2908 // Convert the return value back. |
2907 Node* i32_zero = jsgraph()->Int32Constant(0); | 2909 Node* i32_zero = jsgraph()->Int32Constant(0); |
2908 Node* val = sig->return_count() == 0 | 2910 Node* val = sig->return_count() == 0 |
2909 ? i32_zero | 2911 ? i32_zero |
2910 : FromJS(call, HeapConstant(isolate->native_context()), | 2912 : FromJS(call, HeapConstant(isolate->native_context()), |
2911 sig->GetReturn()); | 2913 sig->GetReturn()); |
2912 Return(val); | 2914 Return(val); |
2913 } | 2915 } |
2914 | 2916 |
2917 void WasmGraphBuilder::BuildWasmInterpreterEntry( | |
2918 uint32_t function_index, wasm::FunctionSig* sig, | |
2919 Handle<WasmInstanceObject> instance) { | |
2920 int wasm_count = static_cast<int>(sig->parameter_count()); | |
2921 int param_count = jsgraph()->machine()->Is64() | |
2922 ? wasm_count | |
2923 : Int64Lowering::GetParameterCountAfterLowering(sig); | |
2924 | |
2925 // Build the start and the parameter nodes. | |
2926 Node* start = Start(param_count + 3); | |
2927 *effect_ = start; | |
2928 *control_ = start; | |
2929 | |
2930 // Compute size for the argument buffer. | |
2931 int args_size_bytes = 0; | |
2932 for (int i = 0; i < wasm_count; i++) { | |
2933 args_size_bytes += 1 << ElementSizeLog2Of(sig->GetParam(i)); | |
2934 } | |
2935 | |
2936 // The return value is also passed via this buffer: | |
2937 DCHECK_GE(1, sig->return_count()); | |
2938 int return_size_bytes = | |
2939 sig->return_count() == 0 ? 0 : 1 << ElementSizeLog2Of(sig->GetReturn(0)); | |
2940 | |
2941 // Get a stack slot for the arguments. | |
2942 Node* arg_buffer = graph()->NewNode(jsgraph()->machine()->StackSlot( | |
2943 std::max(args_size_bytes, return_size_bytes))); | |
2944 | |
2945 // Now store all our arguments to the buffer. | |
2946 int param_index = 0; | |
2947 int offset = 0; | |
2948 for (int i = 0; i < wasm_count; i++) { | |
2949 Node* param = Param(param_index++); | |
2950 bool is_i64_as_two_params = | |
2951 jsgraph()->machine()->Is32() && sig->GetParam(i) == wasm::kWasmI64; | |
2952 MachineRepresentation param_rep = | |
2953 is_i64_as_two_params ? wasm::kWasmI32 : sig->GetParam(i); | |
2954 StoreRepresentation store_rep(param_rep, WriteBarrierKind::kNoWriteBarrier); | |
2955 *effect_ = | |
2956 graph()->NewNode(jsgraph()->machine()->Store(store_rep), arg_buffer, | |
2957 Int32Constant(offset), param, *effect_, *control_); | |
2958 offset += 1 << ElementSizeLog2Of(param_rep); | |
2959 if (is_i64_as_two_params) { | |
titzer
2017/01/11 15:52:34
As discussed in person, you'll have to check the e
Clemens Hammacher
2017/01/11 16:56:10
Done.
| |
2960 // Also store the upper half. | |
2961 param = Param(param_index++); | |
2962 StoreRepresentation store_rep(wasm::kWasmI32, | |
2963 WriteBarrierKind::kNoWriteBarrier); | |
2964 *effect_ = | |
2965 graph()->NewNode(jsgraph()->machine()->Store(store_rep), arg_buffer, | |
2966 Int32Constant(offset), param, *effect_, *control_); | |
2967 offset += 1 << ElementSizeLog2Of(wasm::kWasmI32); | |
2968 } | |
2969 } | |
2970 DCHECK_EQ(param_count, param_index); | |
2971 DCHECK_EQ(args_size_bytes, offset); | |
2972 | |
2973 Node* parameters[] = { | |
2974 jsgraph()->HeapConstant(instance), // wasm instance | |
2975 jsgraph()->SmiConstant(function_index), // function index | |
2976 arg_buffer, // argument buffer | |
titzer
2017/01/11 15:52:34
Can you add a TODO or other comment that we are pa
Clemens Hammacher
2017/01/11 16:56:10
I think IsSmi would actually return true, even tho
| |
2977 }; | |
2978 BuildCallToRuntime(Runtime::kWasmRunInterpreter, jsgraph(), | |
2979 jsgraph()->isolate()->native_context(), parameters, | |
2980 arraysize(parameters), effect_, *control_); | |
2981 | |
2982 // Read back the return value. | |
2983 if (jsgraph()->machine()->Is32() && sig->return_count() > 0 && | |
2984 sig->GetReturn() == wasm::kWasmI64) { | |
2985 MachineType load_rep = wasm::WasmOpcodes::MachineTypeFor(wasm::kWasmI32); | |
2986 Node* lower = | |
2987 graph()->NewNode(jsgraph()->machine()->Load(load_rep), arg_buffer, | |
2988 Int32Constant(0), *effect_, *control_); | |
2989 Node* upper = | |
2990 graph()->NewNode(jsgraph()->machine()->Load(load_rep), arg_buffer, | |
2991 Int32Constant(sizeof(int32_t)), *effect_, *control_); | |
2992 Return(upper, lower); | |
2993 } else { | |
2994 Node* val; | |
2995 if (sig->return_count() == 0) { | |
2996 val = Int32Constant(0); | |
2997 } else { | |
2998 MachineType load_rep = | |
2999 wasm::WasmOpcodes::MachineTypeFor(sig->GetReturn()); | |
3000 val = graph()->NewNode(jsgraph()->machine()->Load(load_rep), arg_buffer, | |
3001 Int32Constant(0), *effect_, *control_); | |
3002 } | |
3003 Return(val); | |
3004 } | |
3005 } | |
3006 | |
2915 Node* WasmGraphBuilder::MemBuffer(uint32_t offset) { | 3007 Node* WasmGraphBuilder::MemBuffer(uint32_t offset) { |
2916 DCHECK(module_ && module_->instance); | 3008 DCHECK(module_ && module_->instance); |
2917 if (offset == 0) { | 3009 if (offset == 0) { |
2918 if (!mem_buffer_) { | 3010 if (!mem_buffer_) { |
2919 mem_buffer_ = jsgraph()->RelocatableIntPtrConstant( | 3011 mem_buffer_ = jsgraph()->RelocatableIntPtrConstant( |
2920 reinterpret_cast<uintptr_t>(module_->instance->mem_start), | 3012 reinterpret_cast<uintptr_t>(module_->instance->mem_start), |
2921 RelocInfo::WASM_MEMORY_REFERENCE); | 3013 RelocInfo::WASM_MEMORY_REFERENCE); |
2922 } | 3014 } |
2923 return mem_buffer_; | 3015 return mem_buffer_; |
2924 } else { | 3016 } else { |
(...skipping 561 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3486 } | 3578 } |
3487 RecordFunctionCompilation( | 3579 RecordFunctionCompilation( |
3488 CodeEventListener::FUNCTION_TAG, isolate, code, "wasm-to-js", index, | 3580 CodeEventListener::FUNCTION_TAG, isolate, code, "wasm-to-js", index, |
3489 {module_name->ToCString().get(), module_name->length()}, | 3581 {module_name->ToCString().get(), module_name->length()}, |
3490 {function_name, function_name_size}); | 3582 {function_name, function_name_size}); |
3491 } | 3583 } |
3492 | 3584 |
3493 return code; | 3585 return code; |
3494 } | 3586 } |
3495 | 3587 |
3588 Handle<Code> CompileWasmInterpreterEntry(Isolate* isolate, uint32_t func_index, | |
3589 wasm::FunctionSig* sig, | |
3590 Handle<WasmInstanceObject> instance) { | |
3591 //---------------------------------------------------------------------------- | |
3592 // Create the Graph | |
3593 //---------------------------------------------------------------------------- | |
3594 Zone zone(isolate->allocator(), ZONE_NAME); | |
3595 Graph graph(&zone); | |
3596 CommonOperatorBuilder common(&zone); | |
3597 MachineOperatorBuilder machine(&zone); | |
3598 JSGraph jsgraph(isolate, &graph, &common, nullptr, nullptr, &machine); | |
3599 | |
3600 Node* control = nullptr; | |
3601 Node* effect = nullptr; | |
3602 | |
3603 WasmGraphBuilder builder(nullptr, &zone, &jsgraph, sig); | |
3604 builder.set_control_ptr(&control); | |
3605 builder.set_effect_ptr(&effect); | |
3606 builder.BuildWasmInterpreterEntry(func_index, sig, instance); | |
3607 | |
3608 Handle<Code> code = Handle<Code>::null(); | |
3609 { | |
3610 if (FLAG_trace_turbo_graph) { // Simple textual RPO. | |
3611 OFStream os(stdout); | |
3612 os << "-- Wasm to interpreter graph -- " << std::endl; | |
3613 os << AsRPO(graph); | |
3614 } | |
3615 | |
3616 // Schedule and compile to machine code. | |
3617 CallDescriptor* incoming = | |
3618 wasm::ModuleEnv::GetWasmCallDescriptor(&zone, sig); | |
3619 if (machine.Is32()) { | |
3620 incoming = wasm::ModuleEnv::GetI32WasmCallDescriptor(&zone, incoming); | |
3621 } | |
3622 Code::Flags flags = Code::ComputeFlags(Code::WASM_INTERPRETER_ENTRY); | |
3623 EmbeddedVector<char, 32> debug_name; | |
3624 int name_len = SNPrintF(debug_name, "wasm-to-interpreter#%d", func_index); | |
3625 DCHECK(name_len > 0 && name_len < debug_name.length()); | |
3626 debug_name.Truncate(name_len); | |
3627 DCHECK_EQ('\0', debug_name.start()[debug_name.length()]); | |
3628 | |
3629 CompilationInfo info(debug_name, isolate, &zone, flags); | |
3630 code = Pipeline::GenerateCodeForTesting(&info, incoming, &graph, nullptr); | |
3631 #ifdef ENABLE_DISASSEMBLER | |
3632 if (FLAG_print_opt_code && !code.is_null()) { | |
3633 OFStream os(stdout); | |
3634 code->Disassemble(debug_name.start(), os); | |
3635 } | |
3636 #endif | |
3637 | |
3638 if (isolate->logger()->is_logging_code_events() || | |
3639 isolate->is_profiling()) { | |
3640 RecordFunctionCompilation(CodeEventListener::FUNCTION_TAG, isolate, code, | |
3641 "wasm-to-interpreter", func_index, | |
3642 wasm::WasmName("module"), debug_name); | |
3643 } | |
3644 } | |
3645 | |
3646 Handle<FixedArray> deopt_data = isolate->factory()->NewFixedArray(1, TENURED); | |
3647 Handle<WeakCell> weak_instance = isolate->factory()->NewWeakCell(instance); | |
3648 deopt_data->set(0, *weak_instance); | |
3649 code->set_deoptimization_data(*deopt_data); | |
3650 | |
3651 return code; | |
3652 } | |
3653 | |
3496 SourcePositionTable* WasmCompilationUnit::BuildGraphForWasmFunction( | 3654 SourcePositionTable* WasmCompilationUnit::BuildGraphForWasmFunction( |
3497 double* decode_ms) { | 3655 double* decode_ms) { |
3498 base::ElapsedTimer decode_timer; | 3656 base::ElapsedTimer decode_timer; |
3499 if (FLAG_trace_wasm_decode_time) { | 3657 if (FLAG_trace_wasm_decode_time) { |
3500 decode_timer.Start(); | 3658 decode_timer.Start(); |
3501 } | 3659 } |
3502 // Create a TF graph during decoding. | 3660 // Create a TF graph during decoding. |
3503 | 3661 |
3504 Graph* graph = jsgraph_->graph(); | 3662 Graph* graph = jsgraph_->graph(); |
3505 CommonOperatorBuilder* common = jsgraph_->common(); | 3663 CommonOperatorBuilder* common = jsgraph_->common(); |
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3693 Smi::FromInt(instruction.instr_offset)); | 3851 Smi::FromInt(instruction.instr_offset)); |
3694 fn_protected->set(Code::kTrapDataSize * i + Code::kTrapLandingOffset, | 3852 fn_protected->set(Code::kTrapDataSize * i + Code::kTrapLandingOffset, |
3695 Smi::FromInt(instruction.landing_offset)); | 3853 Smi::FromInt(instruction.landing_offset)); |
3696 } | 3854 } |
3697 return fn_protected; | 3855 return fn_protected; |
3698 } | 3856 } |
3699 | 3857 |
3700 } // namespace compiler | 3858 } // namespace compiler |
3701 } // namespace internal | 3859 } // namespace internal |
3702 } // namespace v8 | 3860 } // namespace v8 |
OLD | NEW |