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 "src/isolate-inl.h" | 7 #include "src/isolate-inl.h" |
8 | 8 |
9 #include "src/base/platform/elapsed-timer.h" | 9 #include "src/base/platform/elapsed-timer.h" |
10 #include "src/base/platform/platform.h" | 10 #include "src/base/platform/platform.h" |
(...skipping 2573 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2584 size_t limit = size - offset - memsize; | 2584 size_t limit = size - offset - memsize; |
2585 CHECK(limit <= kMaxUInt32); | 2585 CHECK(limit <= kMaxUInt32); |
2586 cond = graph()->NewNode( | 2586 cond = graph()->NewNode( |
2587 jsgraph()->machine()->Uint32LessThanOrEqual(), index, | 2587 jsgraph()->machine()->Uint32LessThanOrEqual(), index, |
2588 jsgraph()->Int32Constant(static_cast<uint32_t>(limit))); | 2588 jsgraph()->Int32Constant(static_cast<uint32_t>(limit))); |
2589 } | 2589 } |
2590 | 2590 |
2591 trap_->AddTrapIfFalse(wasm::kTrapMemOutOfBounds, cond, position); | 2591 trap_->AddTrapIfFalse(wasm::kTrapMemOutOfBounds, cond, position); |
2592 } | 2592 } |
2593 | 2593 |
| 2594 MachineType WasmGraphBuilder::GetTypeForUnalignedAccess(uint32_t alignment, |
| 2595 bool signExtend) { |
| 2596 switch (alignment) { |
| 2597 case 0: |
| 2598 return signExtend ? MachineType::Int8() : MachineType::Uint8(); |
| 2599 case 1: |
| 2600 return signExtend ? MachineType::Int16() : MachineType::Uint16(); |
| 2601 case 2: |
| 2602 return signExtend ? MachineType::Int32() : MachineType::Uint32(); |
| 2603 default: |
| 2604 UNREACHABLE(); |
| 2605 } |
| 2606 } |
| 2607 |
| 2608 Node* WasmGraphBuilder::GetUnalignedLoadOffsetNode(Node* baseOffset, |
| 2609 int numberOfBytes, |
| 2610 int stride, int current) { |
| 2611 int offset; |
| 2612 |
| 2613 #if defined(V8_TARGET_LITTLE_ENDIAN) |
| 2614 offset = numberOfBytes - stride - current; |
| 2615 #elif defined(V8_TARGET_BIG_ENDIAN) |
| 2616 offset = current; |
| 2617 #else |
| 2618 #error Unsupported endianness |
| 2619 #endif |
| 2620 |
| 2621 if (offset == 0) { |
| 2622 return baseOffset; |
| 2623 } else { |
| 2624 return Binop(wasm::kExprI32Add, baseOffset, |
| 2625 jsgraph()->Int32Constant(offset)); |
| 2626 } |
| 2627 } |
| 2628 |
| 2629 Node* WasmGraphBuilder::BuildUnalignedLoad(wasm::LocalType type, |
| 2630 MachineType memtype, Node* index, |
| 2631 uint32_t offset, |
| 2632 uint32_t alignment) { |
| 2633 Node* result; |
| 2634 Node* load; |
| 2635 bool extendTo64Bit = false; |
| 2636 |
| 2637 wasm::WasmOpcode shiftOpcode; |
| 2638 wasm::WasmOpcode orOpcode; |
| 2639 Node* shiftConst; |
| 2640 |
| 2641 bool signExtend = memtype.IsSigned(); |
| 2642 |
| 2643 bool isFloat = IsFloatingPoint(memtype.representation()); |
| 2644 int stride = |
| 2645 1 << ElementSizeLog2Of( |
| 2646 GetTypeForUnalignedAccess(alignment, false).representation()); |
| 2647 int numberOfBytes = 1 << ElementSizeLog2Of(memtype.representation()); |
| 2648 int numberOfLoads = numberOfBytes / stride; |
| 2649 |
| 2650 DCHECK(numberOfBytes % stride == 0); |
| 2651 DCHECK(numberOfLoads >= 2); |
| 2652 |
| 2653 switch (type) { |
| 2654 case wasm::kAstI64: |
| 2655 case wasm::kAstF64: |
| 2656 shiftOpcode = wasm::kExprI64Shl; |
| 2657 orOpcode = wasm::kExprI64Ior; |
| 2658 result = jsgraph()->Int64Constant(0); |
| 2659 shiftConst = jsgraph()->Int64Constant(8 * stride); |
| 2660 extendTo64Bit = true; |
| 2661 break; |
| 2662 case wasm::kAstI32: |
| 2663 case wasm::kAstF32: |
| 2664 shiftOpcode = wasm::kExprI32Shl; |
| 2665 orOpcode = wasm::kExprI32Ior; |
| 2666 result = jsgraph()->Int32Constant(0); |
| 2667 shiftConst = jsgraph()->Int32Constant(8 * stride); |
| 2668 break; |
| 2669 default: |
| 2670 UNREACHABLE(); |
| 2671 } |
| 2672 |
| 2673 Node* baseOffset = MemBuffer(offset); |
| 2674 |
| 2675 for (int i = 0; i < numberOfBytes; i += stride) { |
| 2676 result = Binop(shiftOpcode, result, shiftConst); |
| 2677 load = graph()->NewNode( |
| 2678 jsgraph()->machine()->Load( |
| 2679 GetTypeForUnalignedAccess(alignment, signExtend)), |
| 2680 GetUnalignedLoadOffsetNode(baseOffset, numberOfBytes, stride, i), index, |
| 2681 *effect_, *control_); |
| 2682 *effect_ = load; |
| 2683 if (extendTo64Bit) { |
| 2684 if (signExtend) { |
| 2685 load = |
| 2686 graph()->NewNode(jsgraph()->machine()->ChangeInt32ToInt64(), load); |
| 2687 } else { |
| 2688 load = graph()->NewNode(jsgraph()->machine()->ChangeUint32ToUint64(), |
| 2689 load); |
| 2690 } |
| 2691 } |
| 2692 signExtend = false; |
| 2693 result = Binop(orOpcode, result, load); |
| 2694 } |
| 2695 |
| 2696 // Convert to float |
| 2697 if (isFloat) { |
| 2698 switch (type) { |
| 2699 case wasm::kAstF32: |
| 2700 result = Unop(wasm::kExprF32ReinterpretI32, result); |
| 2701 break; |
| 2702 case wasm::kAstF64: |
| 2703 result = Unop(wasm::kExprF64ReinterpretI64, result); |
| 2704 break; |
| 2705 default: |
| 2706 UNREACHABLE(); |
| 2707 } |
| 2708 } |
| 2709 |
| 2710 return result; |
| 2711 } |
| 2712 |
2594 Node* WasmGraphBuilder::LoadMem(wasm::LocalType type, MachineType memtype, | 2713 Node* WasmGraphBuilder::LoadMem(wasm::LocalType type, MachineType memtype, |
2595 Node* index, uint32_t offset, | 2714 Node* index, uint32_t offset, |
| 2715 uint32_t alignment, |
2596 wasm::WasmCodePosition position) { | 2716 wasm::WasmCodePosition position) { |
2597 Node* load; | 2717 Node* load; |
2598 | 2718 |
2599 if (module_ && module_->asm_js()) { | 2719 if (module_ && module_->asm_js()) { |
2600 // asm.js semantics use CheckedLoad (i.e. OOB reads return 0ish). | 2720 // asm.js semantics use CheckedLoad (i.e. OOB reads return 0ish). |
2601 DCHECK_EQ(0, offset); | 2721 DCHECK_EQ(0, offset); |
2602 const Operator* op = jsgraph()->machine()->CheckedLoad(memtype); | 2722 const Operator* op = jsgraph()->machine()->CheckedLoad(memtype); |
2603 load = graph()->NewNode(op, MemBuffer(0), index, MemSize(0), *effect_, | 2723 load = graph()->NewNode(op, MemBuffer(0), index, MemSize(0), *effect_, |
2604 *control_); | 2724 *control_); |
| 2725 *effect_ = load; |
2605 } else { | 2726 } else { |
2606 // WASM semantics throw on OOB. Introduce explicit bounds check. | 2727 // WASM semantics throw on OOB. Introduce explicit bounds check. |
2607 BoundsCheckMem(memtype, index, offset, position); | 2728 BoundsCheckMem(memtype, index, offset, position); |
2608 load = graph()->NewNode(jsgraph()->machine()->Load(memtype), | 2729 bool aligned = alignment >= ElementSizeLog2Of(memtype.representation()); |
2609 MemBuffer(offset), index, *effect_, *control_); | 2730 |
| 2731 if (aligned || |
| 2732 jsgraph()->machine()->UnalignedLoadSupported(memtype, alignment)) { |
| 2733 load = graph()->NewNode(jsgraph()->machine()->Load(memtype), |
| 2734 MemBuffer(offset), index, *effect_, *control_); |
| 2735 *effect_ = load; |
| 2736 } else { |
| 2737 load = BuildUnalignedLoad(type, memtype, index, offset, alignment); |
| 2738 } |
2610 } | 2739 } |
2611 | 2740 |
2612 *effect_ = load; | |
2613 | |
2614 if (type == wasm::kAstI64 && | 2741 if (type == wasm::kAstI64 && |
2615 ElementSizeLog2Of(memtype.representation()) < 3) { | 2742 ElementSizeLog2Of(memtype.representation()) < 3) { |
2616 // TODO(titzer): TF zeroes the upper bits of 64-bit loads for subword sizes. | 2743 // TODO(titzer): TF zeroes the upper bits of 64-bit loads for subword sizes. |
2617 if (memtype.IsSigned()) { | 2744 if (memtype.IsSigned()) { |
2618 // sign extend | 2745 // sign extend |
2619 load = graph()->NewNode(jsgraph()->machine()->ChangeInt32ToInt64(), load); | 2746 load = graph()->NewNode(jsgraph()->machine()->ChangeInt32ToInt64(), load); |
2620 } else { | 2747 } else { |
2621 // zero extend | 2748 // zero extend |
2622 load = | 2749 load = |
2623 graph()->NewNode(jsgraph()->machine()->ChangeUint32ToUint64(), load); | 2750 graph()->NewNode(jsgraph()->machine()->ChangeUint32ToUint64(), load); |
2624 } | 2751 } |
2625 } | 2752 } |
2626 | 2753 |
2627 return load; | 2754 return load; |
2628 } | 2755 } |
2629 | 2756 |
| 2757 Node* WasmGraphBuilder::GetUnalignedStoreOffsetNode(Node* baseOffset, |
| 2758 int numberOfBytes, |
| 2759 int stride, int current) { |
| 2760 int offset; |
| 2761 #if defined(V8_TARGET_LITTLE_ENDIAN) |
| 2762 offset = current; |
| 2763 #elif defined(V8_TARGET_BIG_ENDIAN) |
| 2764 offset = numberOfBytes - stride - current; |
| 2765 #else |
| 2766 #error Unsupported endianness |
| 2767 #endif |
| 2768 if (offset == 0) { |
| 2769 return baseOffset; |
| 2770 } else { |
| 2771 return Binop(wasm::kExprI32Add, baseOffset, |
| 2772 jsgraph()->Int32Constant(offset)); |
| 2773 } |
| 2774 } |
| 2775 |
| 2776 Node* WasmGraphBuilder::BuildUnalignedStore(MachineType memtype, Node* index, |
| 2777 uint32_t offset, uint32_t alignment, |
| 2778 Node* val) { |
| 2779 Node* store; |
| 2780 Node* newValue; |
| 2781 |
| 2782 wasm::WasmOpcode shiftOpcode; |
| 2783 |
| 2784 Node* shiftConst; |
| 2785 bool extendTo64Bit = false; |
| 2786 bool isFloat = IsFloatingPoint(memtype.representation()); |
| 2787 int stride = 1 << ElementSizeLog2Of( |
| 2788 GetTypeForUnalignedAccess(alignment).representation()); |
| 2789 int numberOfBytes = 1 << ElementSizeLog2Of(memtype.representation()); |
| 2790 int numberOfLoads = numberOfBytes / stride; |
| 2791 |
| 2792 DCHECK(numberOfBytes % stride == 0); |
| 2793 DCHECK(numberOfLoads >= 2); |
| 2794 |
| 2795 StoreRepresentation rep(GetTypeForUnalignedAccess(alignment).representation(), |
| 2796 kNoWriteBarrier); |
| 2797 |
| 2798 if (ElementSizeLog2Of(memtype.representation()) <= 2) { |
| 2799 shiftOpcode = wasm::kExprI32ShrU; |
| 2800 shiftConst = jsgraph()->Int32Constant(8 * stride); |
| 2801 } else { |
| 2802 shiftOpcode = wasm::kExprI64ShrU; |
| 2803 shiftConst = jsgraph()->Int64Constant(8 * stride); |
| 2804 extendTo64Bit = true; |
| 2805 } |
| 2806 |
| 2807 newValue = val; |
| 2808 if (isFloat) { |
| 2809 switch (memtype.representation()) { |
| 2810 case MachineRepresentation::kFloat64: |
| 2811 newValue = Unop(wasm::kExprI64ReinterpretF64, val); |
| 2812 break; |
| 2813 case MachineRepresentation::kFloat32: |
| 2814 newValue = Unop(wasm::kExprI32ReinterpretF32, val); |
| 2815 break; |
| 2816 default: |
| 2817 UNREACHABLE(); |
| 2818 } |
| 2819 } |
| 2820 |
| 2821 Node* baseOffset = MemBuffer(offset); |
| 2822 |
| 2823 for (int i = 0; i < numberOfBytes - stride; i += stride) { |
| 2824 store = graph()->NewNode( |
| 2825 jsgraph()->machine()->Store(rep), |
| 2826 GetUnalignedStoreOffsetNode(baseOffset, numberOfBytes, stride, i), |
| 2827 index, |
| 2828 extendTo64Bit ? Unop(wasm::kExprI32ConvertI64, newValue) : newValue, |
| 2829 *effect_, *control_); |
| 2830 newValue = Binop(shiftOpcode, newValue, shiftConst); |
| 2831 *effect_ = store; |
| 2832 } |
| 2833 store = graph()->NewNode( |
| 2834 jsgraph()->machine()->Store(rep), |
| 2835 GetUnalignedStoreOffsetNode(baseOffset, numberOfBytes, stride, |
| 2836 numberOfBytes - stride), |
| 2837 index, |
| 2838 extendTo64Bit ? Unop(wasm::kExprI32ConvertI64, newValue) : newValue, |
| 2839 *effect_, *control_); |
| 2840 *effect_ = store; |
| 2841 return val; |
| 2842 } |
| 2843 |
2630 Node* WasmGraphBuilder::StoreMem(MachineType memtype, Node* index, | 2844 Node* WasmGraphBuilder::StoreMem(MachineType memtype, Node* index, |
2631 uint32_t offset, Node* val, | 2845 uint32_t offset, uint32_t alignment, Node* val, |
2632 wasm::WasmCodePosition position) { | 2846 wasm::WasmCodePosition position) { |
2633 Node* store; | 2847 Node* store; |
2634 if (module_ && module_->asm_js()) { | 2848 if (module_ && module_->asm_js()) { |
2635 // asm.js semantics use CheckedStore (i.e. ignore OOB writes). | 2849 // asm.js semantics use CheckedStore (i.e. ignore OOB writes). |
2636 DCHECK_EQ(0, offset); | 2850 DCHECK_EQ(0, offset); |
2637 const Operator* op = | 2851 const Operator* op = |
2638 jsgraph()->machine()->CheckedStore(memtype.representation()); | 2852 jsgraph()->machine()->CheckedStore(memtype.representation()); |
2639 store = graph()->NewNode(op, MemBuffer(0), index, MemSize(0), val, *effect_, | 2853 store = graph()->NewNode(op, MemBuffer(0), index, MemSize(0), val, *effect_, |
2640 *control_); | 2854 *control_); |
| 2855 *effect_ = store; |
2641 } else { | 2856 } else { |
2642 // WASM semantics throw on OOB. Introduce explicit bounds check. | 2857 // WASM semantics throw on OOB. Introduce explicit bounds check. |
2643 BoundsCheckMem(memtype, index, offset, position); | 2858 BoundsCheckMem(memtype, index, offset, position); |
2644 StoreRepresentation rep(memtype.representation(), kNoWriteBarrier); | 2859 StoreRepresentation rep(memtype.representation(), kNoWriteBarrier); |
2645 store = | 2860 bool aligned = alignment >= ElementSizeLog2Of(memtype.representation()); |
2646 graph()->NewNode(jsgraph()->machine()->Store(rep), MemBuffer(offset), | 2861 |
2647 index, val, *effect_, *control_); | 2862 if (aligned || |
| 2863 jsgraph()->machine()->UnalignedStoreSupported(memtype, alignment)) { |
| 2864 StoreRepresentation rep(memtype.representation(), kNoWriteBarrier); |
| 2865 store = |
| 2866 graph()->NewNode(jsgraph()->machine()->Store(rep), MemBuffer(offset), |
| 2867 index, val, *effect_, *control_); |
| 2868 *effect_ = store; |
| 2869 } else { |
| 2870 store = BuildUnalignedStore(memtype, index, offset, alignment, val); |
| 2871 } |
2648 } | 2872 } |
2649 *effect_ = store; | 2873 |
2650 return store; | 2874 return store; |
2651 } | 2875 } |
2652 | 2876 |
2653 | 2877 |
2654 void WasmGraphBuilder::PrintDebugName(Node* node) { | 2878 void WasmGraphBuilder::PrintDebugName(Node* node) { |
2655 PrintF("#%d:%s", node->id(), node->op()->mnemonic()); | 2879 PrintF("#%d:%s", node->id(), node->op()->mnemonic()); |
2656 } | 2880 } |
2657 | 2881 |
2658 | 2882 |
2659 Node* WasmGraphBuilder::String(const char* string) { | 2883 Node* WasmGraphBuilder::String(const char* string) { |
(...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2870 double* decode_ms) { | 3094 double* decode_ms) { |
2871 base::ElapsedTimer decode_timer; | 3095 base::ElapsedTimer decode_timer; |
2872 if (FLAG_trace_wasm_decode_time) { | 3096 if (FLAG_trace_wasm_decode_time) { |
2873 decode_timer.Start(); | 3097 decode_timer.Start(); |
2874 } | 3098 } |
2875 // Create a TF graph during decoding. | 3099 // Create a TF graph during decoding. |
2876 Graph* graph = new (zone) Graph(zone); | 3100 Graph* graph = new (zone) Graph(zone); |
2877 CommonOperatorBuilder* common = new (zone) CommonOperatorBuilder(zone); | 3101 CommonOperatorBuilder* common = new (zone) CommonOperatorBuilder(zone); |
2878 MachineOperatorBuilder* machine = new (zone) MachineOperatorBuilder( | 3102 MachineOperatorBuilder* machine = new (zone) MachineOperatorBuilder( |
2879 zone, MachineType::PointerRepresentation(), | 3103 zone, MachineType::PointerRepresentation(), |
2880 InstructionSelector::SupportedMachineOperatorFlags()); | 3104 InstructionSelector::SupportedMachineOperatorFlags(), |
| 3105 InstructionSelector::AlignmentRequirements()); |
2881 JSGraph* jsgraph = | 3106 JSGraph* jsgraph = |
2882 new (zone) JSGraph(isolate, graph, common, nullptr, nullptr, machine); | 3107 new (zone) JSGraph(isolate, graph, common, nullptr, nullptr, machine); |
2883 SourcePositionTable* source_position_table = | 3108 SourcePositionTable* source_position_table = |
2884 new (zone) SourcePositionTable(graph); | 3109 new (zone) SourcePositionTable(graph); |
2885 WasmGraphBuilder builder(zone, jsgraph, function->sig, source_position_table); | 3110 WasmGraphBuilder builder(zone, jsgraph, function->sig, source_position_table); |
2886 wasm::FunctionBody body = { | 3111 wasm::FunctionBody body = { |
2887 module_env, function->sig, module_env->module->module_start, | 3112 module_env, function->sig, module_env->module->module_start, |
2888 module_env->module->module_start + function->code_start_offset, | 3113 module_env->module->module_start + function->code_start_offset, |
2889 module_env->module->module_start + function->code_end_offset}; | 3114 module_env->module->module_start + function->code_end_offset}; |
2890 wasm::TreeResult result = | 3115 wasm::TreeResult result = |
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3077 const wasm::WasmFunction* function) { | 3302 const wasm::WasmFunction* function) { |
3078 WasmCompilationUnit* unit = | 3303 WasmCompilationUnit* unit = |
3079 CreateWasmCompilationUnit(thrower, isolate, module_env, function, 0); | 3304 CreateWasmCompilationUnit(thrower, isolate, module_env, function, 0); |
3080 ExecuteCompilation(unit); | 3305 ExecuteCompilation(unit); |
3081 return FinishCompilation(unit); | 3306 return FinishCompilation(unit); |
3082 } | 3307 } |
3083 | 3308 |
3084 } // namespace compiler | 3309 } // namespace compiler |
3085 } // namespace internal | 3310 } // namespace internal |
3086 } // namespace v8 | 3311 } // namespace v8 |
OLD | NEW |