Chromium Code Reviews| 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 |