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 2164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2175 | 2175 |
2176 // Allocate the box for the {value}. | 2176 // Allocate the box for the {value}. |
2177 vbox = BuildAllocateHeapNumberWithValue(value, if_box); | 2177 vbox = BuildAllocateHeapNumberWithValue(value, if_box); |
2178 | 2178 |
2179 Node* control = graph()->NewNode(common->Merge(2), if_smi, if_box); | 2179 Node* control = graph()->NewNode(common->Merge(2), if_smi, if_box); |
2180 value = graph()->NewNode(common->Phi(MachineRepresentation::kTagged, 2), vsmi, | 2180 value = graph()->NewNode(common->Phi(MachineRepresentation::kTagged, 2), vsmi, |
2181 vbox, control); | 2181 vbox, control); |
2182 return value; | 2182 return value; |
2183 } | 2183 } |
2184 | 2184 |
2185 Node* WasmGraphBuilder::ToJS(Node* node, Node* context, wasm::LocalType type) { | 2185 Node* WasmGraphBuilder::ToJS(Node* node, wasm::LocalType type) { |
2186 switch (type) { | 2186 switch (type) { |
2187 case wasm::kAstI32: | 2187 case wasm::kAstI32: |
2188 return BuildChangeInt32ToTagged(node); | 2188 return BuildChangeInt32ToTagged(node); |
2189 case wasm::kAstI64: | 2189 case wasm::kAstI64: |
2190 // TODO(titzer): i64->JS has no good solution right now. Using lower 32 | 2190 // TODO(titzer): i64->JS has no good solution right now. Using lower 32 |
2191 // bits. | 2191 // bits. |
2192 if (jsgraph()->machine()->Is64()) { | 2192 if (jsgraph()->machine()->Is64()) { |
2193 // On 32 bit platforms we do not have to do the truncation because the | 2193 // On 32 bit platforms we do not have to do the truncation because the |
2194 // node we get in as a parameter only contains the low word anyways. | 2194 // node we get in as a parameter only contains the low word anyways. |
2195 node = graph()->NewNode(jsgraph()->machine()->TruncateInt64ToInt32(), | 2195 node = graph()->NewNode(jsgraph()->machine()->TruncateInt64ToInt32(), |
(...skipping 312 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2508 desc = wasm::ModuleEnv::GetI32WasmCallDescriptor(jsgraph()->zone(), desc); | 2508 desc = wasm::ModuleEnv::GetI32WasmCallDescriptor(jsgraph()->zone(), desc); |
2509 } | 2509 } |
2510 Node* call = graph()->NewNode(jsgraph()->common()->Call(desc), count, args); | 2510 Node* call = graph()->NewNode(jsgraph()->common()->Call(desc), count, args); |
2511 Node* retval = call; | 2511 Node* retval = call; |
2512 if (jsgraph()->machine()->Is32() && sig->return_count() > 0 && | 2512 if (jsgraph()->machine()->Is32() && sig->return_count() > 0 && |
2513 sig->GetReturn(0) == wasm::kAstI64) { | 2513 sig->GetReturn(0) == wasm::kAstI64) { |
2514 // The return values comes as two values, we pick the low word. | 2514 // The return values comes as two values, we pick the low word. |
2515 retval = graph()->NewNode(jsgraph()->common()->Projection(0), retval, | 2515 retval = graph()->NewNode(jsgraph()->common()->Projection(0), retval, |
2516 graph()->start()); | 2516 graph()->start()); |
2517 } | 2517 } |
2518 Node* jsval = | 2518 Node* jsval = ToJS( |
2519 ToJS(retval, context, | 2519 retval, sig->return_count() == 0 ? wasm::kAstStmt : sig->GetReturn()); |
2520 sig->return_count() == 0 ? wasm::kAstStmt : sig->GetReturn()); | |
2521 Node* ret = | 2520 Node* ret = |
2522 graph()->NewNode(jsgraph()->common()->Return(), jsval, call, start); | 2521 graph()->NewNode(jsgraph()->common()->Return(), jsval, call, start); |
2523 | 2522 |
2524 MergeControlToEnd(jsgraph(), ret); | 2523 MergeControlToEnd(jsgraph(), ret); |
2525 } | 2524 } |
2526 | 2525 |
2527 void WasmGraphBuilder::BuildWasmToJSWrapper(Handle<JSFunction> function, | 2526 void WasmGraphBuilder::BuildWasmToJSWrapper(Handle<JSReceiver> target, |
2528 wasm::FunctionSig* sig) { | 2527 wasm::FunctionSig* sig) { |
2529 int js_count = function->shared()->internal_formal_parameter_count(); | 2528 DCHECK(target->IsCallable()); |
| 2529 |
2530 int wasm_count = static_cast<int>(sig->parameter_count()); | 2530 int wasm_count = static_cast<int>(sig->parameter_count()); |
2531 int param_count; | 2531 int param_count; |
2532 if (jsgraph()->machine()->Is64()) { | 2532 if (jsgraph()->machine()->Is64()) { |
2533 param_count = wasm_count; | 2533 param_count = wasm_count; |
2534 } else { | 2534 } else { |
2535 param_count = Int64Lowering::GetParameterCountAfterLowering(sig); | 2535 param_count = Int64Lowering::GetParameterCountAfterLowering(sig); |
2536 } | 2536 } |
2537 | 2537 |
2538 // Build the start and the parameter nodes. | 2538 // Build the start and the parameter nodes. |
2539 Isolate* isolate = jsgraph()->isolate(); | 2539 Isolate* isolate = jsgraph()->isolate(); |
2540 CallDescriptor* desc; | 2540 CallDescriptor* desc; |
2541 Node* start = Start(param_count + 3); | 2541 Node* start = Start(param_count + 3); |
2542 *effect_ = start; | 2542 *effect_ = start; |
2543 *control_ = start; | 2543 *control_ = start; |
2544 // JS context is the last parameter. | |
2545 Node* context = HeapConstant(Handle<Context>(function->context(), isolate)); | |
2546 Node** args = Buffer(wasm_count + 7); | 2544 Node** args = Buffer(wasm_count + 7); |
2547 | 2545 |
2548 bool arg_count_before_args = false; | 2546 // The default context of the target. |
2549 bool add_new_target_undefined = false; | 2547 Handle<Context> target_context = isolate->native_context(); |
2550 | 2548 |
| 2549 // Optimization: check if the target is a JSFunction with the right arity so |
| 2550 // that we can call it directly. |
| 2551 bool call_direct = false; |
2551 int pos = 0; | 2552 int pos = 0; |
2552 if (js_count == wasm_count) { | 2553 if (target->IsJSFunction()) { |
2553 // exact arity match, just call the function directly. | 2554 Handle<JSFunction> function = Handle<JSFunction>::cast(target); |
2554 desc = Linkage::GetJSCallDescriptor(graph()->zone(), false, wasm_count + 1, | 2555 if (function->shared()->internal_formal_parameter_count() == wasm_count) { |
2555 CallDescriptor::kNoFlags); | 2556 call_direct = true; |
2556 arg_count_before_args = false; | 2557 |
2557 add_new_target_undefined = true; | 2558 args[pos++] = jsgraph()->Constant(target); // target callable. |
2558 } else { | 2559 // Receiver. |
2559 // Use the Call builtin. | 2560 if (is_sloppy(function->shared()->language_mode()) && |
| 2561 !function->shared()->native()) { |
| 2562 args[pos++] = |
| 2563 HeapConstant(handle(function->context()->global_proxy(), isolate)); |
| 2564 } else { |
| 2565 args[pos++] = jsgraph()->Constant( |
| 2566 handle(isolate->heap()->undefined_value(), isolate)); |
| 2567 } |
| 2568 |
| 2569 desc = Linkage::GetJSCallDescriptor( |
| 2570 graph()->zone(), false, wasm_count + 1, CallDescriptor::kNoFlags); |
| 2571 |
| 2572 // For a direct call we have to use the context of the JSFunction. |
| 2573 target_context = handle(function->context()); |
| 2574 } |
| 2575 } |
| 2576 |
| 2577 // We cannot call the target directly, we have to use the Call builtin. |
| 2578 if (!call_direct) { |
2560 Callable callable = CodeFactory::Call(isolate); | 2579 Callable callable = CodeFactory::Call(isolate); |
2561 args[pos++] = jsgraph()->HeapConstant(callable.code()); | 2580 args[pos++] = jsgraph()->HeapConstant(callable.code()); |
| 2581 args[pos++] = jsgraph()->Constant(target); // target callable |
| 2582 args[pos++] = jsgraph()->Int32Constant(wasm_count); // argument count |
| 2583 args[pos++] = jsgraph()->Constant( |
| 2584 handle(isolate->heap()->undefined_value(), isolate)); // receiver |
| 2585 |
2562 desc = Linkage::GetStubCallDescriptor(isolate, graph()->zone(), | 2586 desc = Linkage::GetStubCallDescriptor(isolate, graph()->zone(), |
2563 callable.descriptor(), wasm_count + 1, | 2587 callable.descriptor(), wasm_count + 1, |
2564 CallDescriptor::kNoFlags); | 2588 CallDescriptor::kNoFlags); |
2565 arg_count_before_args = true; | |
2566 } | 2589 } |
2567 | 2590 |
2568 args[pos++] = jsgraph()->Constant(function); // JS function. | |
2569 if (arg_count_before_args) { | |
2570 args[pos++] = jsgraph()->Int32Constant(wasm_count); // argument count | |
2571 } | |
2572 // Create the receiver constant (either undefined or the global proxy). | |
2573 Handle<Object> receiver(isolate->heap()->undefined_value(), isolate); | |
2574 if (is_sloppy(function->shared()->language_mode())) { | |
2575 receiver = Handle<Object>(function->context()->global_proxy(), isolate); | |
2576 } | |
2577 args[pos++] = jsgraph()->Constant(receiver); | |
2578 | |
2579 // Convert WASM numbers to JS values. | 2591 // Convert WASM numbers to JS values. |
2580 int param_index = 0; | 2592 int param_index = 0; |
2581 for (int i = 0; i < wasm_count; ++i) { | 2593 for (int i = 0; i < wasm_count; ++i) { |
2582 Node* param = | 2594 Node* param = |
2583 graph()->NewNode(jsgraph()->common()->Parameter(param_index++), start); | 2595 graph()->NewNode(jsgraph()->common()->Parameter(param_index++), start); |
2584 args[pos++] = ToJS(param, context, sig->GetParam(i)); | 2596 args[pos++] = ToJS(param, sig->GetParam(i)); |
2585 if (jsgraph()->machine()->Is32() && sig->GetParam(i) == wasm::kAstI64) { | 2597 if (jsgraph()->machine()->Is32() && sig->GetParam(i) == wasm::kAstI64) { |
2586 // On 32 bit platforms we have to skip the high word of int64 parameters. | 2598 // On 32 bit platforms we have to skip the high word of int64 parameters. |
2587 param_index++; | 2599 param_index++; |
2588 } | 2600 } |
2589 } | 2601 } |
2590 | 2602 |
2591 if (add_new_target_undefined) { | 2603 if (call_direct) { |
2592 args[pos++] = jsgraph()->UndefinedConstant(); // new target | 2604 args[pos++] = jsgraph()->UndefinedConstant(); // new target |
| 2605 args[pos++] = jsgraph()->Int32Constant(wasm_count); // argument count |
2593 } | 2606 } |
2594 | 2607 |
2595 if (!arg_count_before_args) { | 2608 args[pos++] = HeapConstant(target_context); |
2596 args[pos++] = jsgraph()->Int32Constant(wasm_count); // argument count | |
2597 } | |
2598 args[pos++] = context; | |
2599 args[pos++] = *effect_; | 2609 args[pos++] = *effect_; |
2600 args[pos++] = *control_; | 2610 args[pos++] = *control_; |
2601 | 2611 |
2602 Node* call = graph()->NewNode(jsgraph()->common()->Call(desc), pos, args); | 2612 Node* call = graph()->NewNode(jsgraph()->common()->Call(desc), pos, args); |
2603 | 2613 |
2604 // Convert the return value back. | 2614 // Convert the return value back. |
2605 Node* ret; | 2615 Node* ret; |
2606 Node* val = | 2616 Node* val = |
2607 FromJS(call, context, | 2617 FromJS(call, HeapConstant(isolate->native_context()), |
2608 sig->return_count() == 0 ? wasm::kAstStmt : sig->GetReturn()); | 2618 sig->return_count() == 0 ? wasm::kAstStmt : sig->GetReturn()); |
2609 if (jsgraph()->machine()->Is32() && sig->return_count() > 0 && | 2619 if (jsgraph()->machine()->Is32() && sig->return_count() > 0 && |
2610 sig->GetReturn() == wasm::kAstI64) { | 2620 sig->GetReturn() == wasm::kAstI64) { |
2611 ret = graph()->NewNode(jsgraph()->common()->Return(), val, | 2621 ret = graph()->NewNode(jsgraph()->common()->Return(), val, |
2612 graph()->NewNode(jsgraph()->machine()->Word32Sar(), | 2622 graph()->NewNode(jsgraph()->machine()->Word32Sar(), |
2613 val, jsgraph()->Int32Constant(31)), | 2623 val, jsgraph()->Int32Constant(31)), |
2614 call, start); | 2624 call, start); |
2615 } else { | 2625 } else { |
2616 ret = graph()->NewNode(jsgraph()->common()->Return(), val, call, start); | 2626 ret = graph()->NewNode(jsgraph()->common()->Return(), val, call, start); |
2617 } | 2627 } |
(...skipping 335 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2953 | 2963 |
2954 if (isolate->logger()->is_logging_code_events() || isolate->is_profiling()) { | 2964 if (isolate->logger()->is_logging_code_events() || isolate->is_profiling()) { |
2955 RecordFunctionCompilation( | 2965 RecordFunctionCompilation( |
2956 CodeEventListener::FUNCTION_TAG, isolate, code, "js-to-wasm", index, | 2966 CodeEventListener::FUNCTION_TAG, isolate, code, "js-to-wasm", index, |
2957 wasm::WasmName("export"), | 2967 wasm::WasmName("export"), |
2958 module->module->GetName(func->name_offset, func->name_length)); | 2968 module->module->GetName(func->name_offset, func->name_length)); |
2959 } | 2969 } |
2960 return code; | 2970 return code; |
2961 } | 2971 } |
2962 | 2972 |
2963 Handle<Code> CompileWasmToJSWrapper(Isolate* isolate, | 2973 Handle<Code> CompileWasmToJSWrapper(Isolate* isolate, Handle<JSReceiver> target, |
2964 Handle<JSFunction> function, | |
2965 wasm::FunctionSig* sig, uint32_t index, | 2974 wasm::FunctionSig* sig, uint32_t index, |
2966 Handle<String> import_module, | 2975 Handle<String> import_module, |
2967 MaybeHandle<String> import_function) { | 2976 MaybeHandle<String> import_function) { |
2968 //---------------------------------------------------------------------------- | 2977 //---------------------------------------------------------------------------- |
2969 // Create the Graph | 2978 // Create the Graph |
2970 //---------------------------------------------------------------------------- | 2979 //---------------------------------------------------------------------------- |
2971 Zone zone(isolate->allocator()); | 2980 Zone zone(isolate->allocator()); |
2972 Graph graph(&zone); | 2981 Graph graph(&zone); |
2973 CommonOperatorBuilder common(&zone); | 2982 CommonOperatorBuilder common(&zone); |
2974 MachineOperatorBuilder machine(&zone); | 2983 MachineOperatorBuilder machine(&zone); |
2975 JSGraph jsgraph(isolate, &graph, &common, nullptr, nullptr, &machine); | 2984 JSGraph jsgraph(isolate, &graph, &common, nullptr, nullptr, &machine); |
2976 | 2985 |
2977 Node* control = nullptr; | 2986 Node* control = nullptr; |
2978 Node* effect = nullptr; | 2987 Node* effect = nullptr; |
2979 | 2988 |
2980 WasmGraphBuilder builder(&zone, &jsgraph, sig); | 2989 WasmGraphBuilder builder(&zone, &jsgraph, sig); |
2981 builder.set_control_ptr(&control); | 2990 builder.set_control_ptr(&control); |
2982 builder.set_effect_ptr(&effect); | 2991 builder.set_effect_ptr(&effect); |
2983 builder.BuildWasmToJSWrapper(function, sig); | 2992 builder.BuildWasmToJSWrapper(target, sig); |
2984 | 2993 |
2985 Handle<Code> code = Handle<Code>::null(); | 2994 Handle<Code> code = Handle<Code>::null(); |
2986 { | 2995 { |
2987 if (FLAG_trace_turbo_graph) { // Simple textual RPO. | 2996 if (FLAG_trace_turbo_graph) { // Simple textual RPO. |
2988 OFStream os(stdout); | 2997 OFStream os(stdout); |
2989 os << "-- Graph after change lowering -- " << std::endl; | 2998 os << "-- Graph after change lowering -- " << std::endl; |
2990 os << AsRPO(graph); | 2999 os << AsRPO(graph); |
2991 } | 3000 } |
2992 | 3001 |
2993 // Schedule and compile to machine code. | 3002 // Schedule and compile to machine code. |
(...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3218 function_->code_start_offset), | 3227 function_->code_start_offset), |
3219 compile_ms); | 3228 compile_ms); |
3220 } | 3229 } |
3221 | 3230 |
3222 return code; | 3231 return code; |
3223 } | 3232 } |
3224 | 3233 |
3225 } // namespace compiler | 3234 } // namespace compiler |
3226 } // namespace internal | 3235 } // namespace internal |
3227 } // namespace v8 | 3236 } // namespace v8 |
OLD | NEW |