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 2596 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2607 } | 2607 } |
2608 } | 2608 } |
2609 | 2609 |
2610 Node* cond = graph()->NewNode( | 2610 Node* cond = graph()->NewNode( |
2611 jsgraph()->machine()->Uint32LessThanOrEqual(), index, | 2611 jsgraph()->machine()->Uint32LessThanOrEqual(), index, |
2612 jsgraph()->Int32Constant(static_cast<uint32_t>(effective_size))); | 2612 jsgraph()->Int32Constant(static_cast<uint32_t>(effective_size))); |
2613 | 2613 |
2614 trap_->AddTrapIfFalse(wasm::kTrapMemOutOfBounds, cond, position); | 2614 trap_->AddTrapIfFalse(wasm::kTrapMemOutOfBounds, cond, position); |
2615 } | 2615 } |
2616 | 2616 |
| 2617 MachineType WasmGraphBuilder::GetTypeForUnalignedAccess(uint32_t alignment, |
| 2618 bool signExtend) { |
| 2619 switch (alignment) { |
| 2620 case 0: |
| 2621 return signExtend ? MachineType::Int8() : MachineType::Uint8(); |
| 2622 case 1: |
| 2623 return signExtend ? MachineType::Int16() : MachineType::Uint16(); |
| 2624 case 2: |
| 2625 return signExtend ? MachineType::Int32() : MachineType::Uint32(); |
| 2626 default: |
| 2627 UNREACHABLE(); |
| 2628 return MachineType::None(); |
| 2629 } |
| 2630 } |
| 2631 |
| 2632 Node* WasmGraphBuilder::GetUnalignedLoadOffsetNode(Node* baseOffset, |
| 2633 int numberOfBytes, |
| 2634 int stride, int current) { |
| 2635 int offset; |
| 2636 wasm::WasmOpcode addOpcode; |
| 2637 |
| 2638 #if defined(V8_TARGET_LITTLE_ENDIAN) |
| 2639 offset = numberOfBytes - stride - current; |
| 2640 #elif defined(V8_TARGET_BIG_ENDIAN) |
| 2641 offset = current; |
| 2642 #else |
| 2643 #error Unsupported endianness |
| 2644 #endif |
| 2645 |
| 2646 #if WASM_64 |
| 2647 addOpcode = wasm::kExprI64Add; |
| 2648 #else |
| 2649 addOpcode = wasm::kExprI32Add; |
| 2650 #endif |
| 2651 |
| 2652 if (offset == 0) { |
| 2653 return baseOffset; |
| 2654 } else { |
| 2655 return Binop(addOpcode, baseOffset, jsgraph()->Int32Constant(offset)); |
| 2656 } |
| 2657 } |
| 2658 |
| 2659 Node* WasmGraphBuilder::BuildUnalignedLoad(wasm::LocalType type, |
| 2660 MachineType memtype, Node* index, |
| 2661 uint32_t offset, |
| 2662 uint32_t alignment) { |
| 2663 Node* result; |
| 2664 Node* load; |
| 2665 bool extendTo64Bit = false; |
| 2666 |
| 2667 wasm::WasmOpcode shiftOpcode; |
| 2668 wasm::WasmOpcode orOpcode; |
| 2669 Node* shiftConst; |
| 2670 |
| 2671 bool signExtend = memtype.IsSigned(); |
| 2672 |
| 2673 bool isFloat = IsFloatingPoint(memtype.representation()); |
| 2674 int stride = |
| 2675 1 << ElementSizeLog2Of( |
| 2676 GetTypeForUnalignedAccess(alignment, false).representation()); |
| 2677 int numberOfBytes = 1 << ElementSizeLog2Of(memtype.representation()); |
| 2678 DCHECK(numberOfBytes % stride == 0); |
| 2679 |
| 2680 switch (type) { |
| 2681 case wasm::kAstI64: |
| 2682 case wasm::kAstF64: |
| 2683 shiftOpcode = wasm::kExprI64Shl; |
| 2684 orOpcode = wasm::kExprI64Ior; |
| 2685 result = jsgraph()->Int64Constant(0); |
| 2686 shiftConst = jsgraph()->Int64Constant(8 * stride); |
| 2687 extendTo64Bit = true; |
| 2688 break; |
| 2689 case wasm::kAstI32: |
| 2690 case wasm::kAstF32: |
| 2691 shiftOpcode = wasm::kExprI32Shl; |
| 2692 orOpcode = wasm::kExprI32Ior; |
| 2693 result = jsgraph()->Int32Constant(0); |
| 2694 shiftConst = jsgraph()->Int32Constant(8 * stride); |
| 2695 break; |
| 2696 default: |
| 2697 UNREACHABLE(); |
| 2698 } |
| 2699 |
| 2700 Node* baseOffset = MemBuffer(offset); |
| 2701 |
| 2702 for (int i = 0; i < numberOfBytes; i += stride) { |
| 2703 result = Binop(shiftOpcode, result, shiftConst); |
| 2704 load = graph()->NewNode( |
| 2705 jsgraph()->machine()->Load( |
| 2706 GetTypeForUnalignedAccess(alignment, signExtend)), |
| 2707 GetUnalignedLoadOffsetNode(baseOffset, numberOfBytes, stride, i), index, |
| 2708 *effect_, *control_); |
| 2709 *effect_ = load; |
| 2710 if (extendTo64Bit) { |
| 2711 if (signExtend) { |
| 2712 load = |
| 2713 graph()->NewNode(jsgraph()->machine()->ChangeInt32ToInt64(), load); |
| 2714 } else { |
| 2715 load = graph()->NewNode(jsgraph()->machine()->ChangeUint32ToUint64(), |
| 2716 load); |
| 2717 } |
| 2718 } |
| 2719 signExtend = false; |
| 2720 result = Binop(orOpcode, result, load); |
| 2721 } |
| 2722 |
| 2723 // Convert to float |
| 2724 if (isFloat) { |
| 2725 switch (type) { |
| 2726 case wasm::kAstF32: |
| 2727 result = Unop(wasm::kExprF32ReinterpretI32, result); |
| 2728 break; |
| 2729 case wasm::kAstF64: |
| 2730 result = Unop(wasm::kExprF64ReinterpretI64, result); |
| 2731 break; |
| 2732 default: |
| 2733 UNREACHABLE(); |
| 2734 } |
| 2735 } |
| 2736 |
| 2737 return result; |
| 2738 } |
| 2739 |
2617 Node* WasmGraphBuilder::LoadMem(wasm::LocalType type, MachineType memtype, | 2740 Node* WasmGraphBuilder::LoadMem(wasm::LocalType type, MachineType memtype, |
2618 Node* index, uint32_t offset, | 2741 Node* index, uint32_t offset, |
| 2742 uint32_t alignment, |
2619 wasm::WasmCodePosition position) { | 2743 wasm::WasmCodePosition position) { |
2620 Node* load; | 2744 Node* load; |
| 2745 |
2621 // WASM semantics throw on OOB. Introduce explicit bounds check. | 2746 // WASM semantics throw on OOB. Introduce explicit bounds check. |
2622 BoundsCheckMem(memtype, index, offset, position); | 2747 BoundsCheckMem(memtype, index, offset, position); |
2623 load = graph()->NewNode(jsgraph()->machine()->Load(memtype), | 2748 bool aligned = static_cast<int>(alignment) >= |
2624 MemBuffer(offset), index, *effect_, *control_); | 2749 ElementSizeLog2Of(memtype.representation()); |
2625 | 2750 |
2626 *effect_ = load; | 2751 if (aligned || |
| 2752 jsgraph()->machine()->UnalignedLoadSupported(memtype, alignment)) { |
| 2753 load = graph()->NewNode(jsgraph()->machine()->Load(memtype), |
| 2754 MemBuffer(offset), index, *effect_, *control_); |
| 2755 *effect_ = load; |
| 2756 } else { |
| 2757 load = BuildUnalignedLoad(type, memtype, index, offset, alignment); |
| 2758 } |
2627 | 2759 |
2628 if (type == wasm::kAstI64 && | 2760 if (type == wasm::kAstI64 && |
2629 ElementSizeLog2Of(memtype.representation()) < 3) { | 2761 ElementSizeLog2Of(memtype.representation()) < 3) { |
2630 // TODO(titzer): TF zeroes the upper bits of 64-bit loads for subword sizes. | 2762 // TODO(titzer): TF zeroes the upper bits of 64-bit loads for subword sizes. |
2631 if (memtype.IsSigned()) { | 2763 if (memtype.IsSigned()) { |
2632 // sign extend | 2764 // sign extend |
2633 load = graph()->NewNode(jsgraph()->machine()->ChangeInt32ToInt64(), load); | 2765 load = graph()->NewNode(jsgraph()->machine()->ChangeInt32ToInt64(), load); |
2634 } else { | 2766 } else { |
2635 // zero extend | 2767 // zero extend |
2636 load = | 2768 load = |
2637 graph()->NewNode(jsgraph()->machine()->ChangeUint32ToUint64(), load); | 2769 graph()->NewNode(jsgraph()->machine()->ChangeUint32ToUint64(), load); |
2638 } | 2770 } |
2639 } | 2771 } |
2640 | 2772 |
2641 return load; | 2773 return load; |
2642 } | 2774 } |
2643 | 2775 |
| 2776 Node* WasmGraphBuilder::GetUnalignedStoreOffsetNode(Node* baseOffset, |
| 2777 int numberOfBytes, |
| 2778 int stride, int current) { |
| 2779 int offset; |
| 2780 wasm::WasmOpcode addOpcode; |
| 2781 |
| 2782 #if defined(V8_TARGET_LITTLE_ENDIAN) |
| 2783 offset = current; |
| 2784 #elif defined(V8_TARGET_BIG_ENDIAN) |
| 2785 offset = numberOfBytes - stride - current; |
| 2786 #else |
| 2787 #error Unsupported endianness |
| 2788 #endif |
| 2789 |
| 2790 #if WASM_64 |
| 2791 addOpcode = wasm::kExprI64Add; |
| 2792 #else |
| 2793 addOpcode = wasm::kExprI32Add; |
| 2794 #endif |
| 2795 |
| 2796 if (offset == 0) { |
| 2797 return baseOffset; |
| 2798 } else { |
| 2799 return Binop(addOpcode, baseOffset, jsgraph()->Int32Constant(offset)); |
| 2800 } |
| 2801 } |
| 2802 |
| 2803 Node* WasmGraphBuilder::BuildUnalignedStore(MachineType memtype, Node* index, |
| 2804 uint32_t offset, uint32_t alignment, |
| 2805 Node* val) { |
| 2806 Node* store; |
| 2807 Node* newValue; |
| 2808 |
| 2809 wasm::WasmOpcode shiftOpcode; |
| 2810 |
| 2811 Node* shiftConst; |
| 2812 bool extendTo64Bit = false; |
| 2813 bool isFloat = IsFloatingPoint(memtype.representation()); |
| 2814 int stride = 1 << ElementSizeLog2Of( |
| 2815 GetTypeForUnalignedAccess(alignment).representation()); |
| 2816 int numberOfBytes = 1 << ElementSizeLog2Of(memtype.representation()); |
| 2817 DCHECK(numberOfBytes % stride == 0); |
| 2818 |
| 2819 StoreRepresentation rep(GetTypeForUnalignedAccess(alignment).representation(), |
| 2820 kNoWriteBarrier); |
| 2821 |
| 2822 if (ElementSizeLog2Of(memtype.representation()) <= 2) { |
| 2823 shiftOpcode = wasm::kExprI32ShrU; |
| 2824 shiftConst = jsgraph()->Int32Constant(8 * stride); |
| 2825 } else { |
| 2826 shiftOpcode = wasm::kExprI64ShrU; |
| 2827 shiftConst = jsgraph()->Int64Constant(8 * stride); |
| 2828 extendTo64Bit = true; |
| 2829 } |
| 2830 |
| 2831 newValue = val; |
| 2832 if (isFloat) { |
| 2833 switch (memtype.representation()) { |
| 2834 case MachineRepresentation::kFloat64: |
| 2835 newValue = Unop(wasm::kExprI64ReinterpretF64, val); |
| 2836 break; |
| 2837 case MachineRepresentation::kFloat32: |
| 2838 newValue = Unop(wasm::kExprI32ReinterpretF32, val); |
| 2839 break; |
| 2840 default: |
| 2841 UNREACHABLE(); |
| 2842 } |
| 2843 } |
| 2844 |
| 2845 Node* baseOffset = MemBuffer(offset); |
| 2846 |
| 2847 for (int i = 0; i < numberOfBytes - stride; i += stride) { |
| 2848 store = graph()->NewNode( |
| 2849 jsgraph()->machine()->Store(rep), |
| 2850 GetUnalignedStoreOffsetNode(baseOffset, numberOfBytes, stride, i), |
| 2851 index, |
| 2852 extendTo64Bit ? Unop(wasm::kExprI32ConvertI64, newValue) : newValue, |
| 2853 *effect_, *control_); |
| 2854 newValue = Binop(shiftOpcode, newValue, shiftConst); |
| 2855 *effect_ = store; |
| 2856 } |
| 2857 store = graph()->NewNode( |
| 2858 jsgraph()->machine()->Store(rep), |
| 2859 GetUnalignedStoreOffsetNode(baseOffset, numberOfBytes, stride, |
| 2860 numberOfBytes - stride), |
| 2861 index, |
| 2862 extendTo64Bit ? Unop(wasm::kExprI32ConvertI64, newValue) : newValue, |
| 2863 *effect_, *control_); |
| 2864 *effect_ = store; |
| 2865 return val; |
| 2866 } |
| 2867 |
2644 Node* WasmGraphBuilder::StoreMem(MachineType memtype, Node* index, | 2868 Node* WasmGraphBuilder::StoreMem(MachineType memtype, Node* index, |
2645 uint32_t offset, Node* val, | 2869 uint32_t offset, uint32_t alignment, Node* val, |
2646 wasm::WasmCodePosition position) { | 2870 wasm::WasmCodePosition position) { |
2647 Node* store; | 2871 Node* store; |
| 2872 |
2648 // WASM semantics throw on OOB. Introduce explicit bounds check. | 2873 // WASM semantics throw on OOB. Introduce explicit bounds check. |
2649 BoundsCheckMem(memtype, index, offset, position); | 2874 BoundsCheckMem(memtype, index, offset, position); |
2650 StoreRepresentation rep(memtype.representation(), kNoWriteBarrier); | 2875 StoreRepresentation rep(memtype.representation(), kNoWriteBarrier); |
2651 store = graph()->NewNode(jsgraph()->machine()->Store(rep), MemBuffer(offset), | 2876 bool aligned = static_cast<int>(alignment) >= |
2652 index, val, *effect_, *control_); | 2877 ElementSizeLog2Of(memtype.representation()); |
2653 *effect_ = store; | 2878 |
| 2879 if (aligned || |
| 2880 jsgraph()->machine()->UnalignedStoreSupported(memtype, alignment)) { |
| 2881 StoreRepresentation rep(memtype.representation(), kNoWriteBarrier); |
| 2882 store = |
| 2883 graph()->NewNode(jsgraph()->machine()->Store(rep), MemBuffer(offset), |
| 2884 index, val, *effect_, *control_); |
| 2885 *effect_ = store; |
| 2886 } else { |
| 2887 store = BuildUnalignedStore(memtype, index, offset, alignment, val); |
| 2888 } |
| 2889 |
2654 return store; | 2890 return store; |
2655 } | 2891 } |
2656 | 2892 |
2657 Node* WasmGraphBuilder::BuildAsmjsLoadMem(MachineType type, Node* index) { | 2893 Node* WasmGraphBuilder::BuildAsmjsLoadMem(MachineType type, Node* index) { |
2658 // TODO(turbofan): fold bounds checks for constant asm.js loads. | 2894 // TODO(turbofan): fold bounds checks for constant asm.js loads. |
2659 // asm.js semantics use CheckedLoad (i.e. OOB reads return 0ish). | 2895 // asm.js semantics use CheckedLoad (i.e. OOB reads return 0ish). |
2660 const Operator* op = jsgraph()->machine()->CheckedLoad(type); | 2896 const Operator* op = jsgraph()->machine()->CheckedLoad(type); |
2661 Node* load = graph()->NewNode(op, MemBuffer(0), index, MemSize(0), *effect_, | 2897 Node* load = graph()->NewNode(op, MemBuffer(0), index, MemSize(0), *effect_, |
2662 *control_); | 2898 *control_); |
2663 *effect_ = load; | 2899 *effect_ = load; |
(...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2889 | 3125 |
2890 std::pair<JSGraph*, SourcePositionTable*> BuildGraphForWasmFunction( | 3126 std::pair<JSGraph*, SourcePositionTable*> BuildGraphForWasmFunction( |
2891 JSGraph* jsgraph, wasm::ErrorThrower* thrower, Isolate* isolate, | 3127 JSGraph* jsgraph, wasm::ErrorThrower* thrower, Isolate* isolate, |
2892 wasm::ModuleEnv*& module_env, const wasm::WasmFunction* function, | 3128 wasm::ModuleEnv*& module_env, const wasm::WasmFunction* function, |
2893 double* decode_ms) { | 3129 double* decode_ms) { |
2894 base::ElapsedTimer decode_timer; | 3130 base::ElapsedTimer decode_timer; |
2895 if (FLAG_trace_wasm_decode_time) { | 3131 if (FLAG_trace_wasm_decode_time) { |
2896 decode_timer.Start(); | 3132 decode_timer.Start(); |
2897 } | 3133 } |
2898 // Create a TF graph during decoding. | 3134 // Create a TF graph during decoding. |
| 3135 |
2899 Graph* graph = jsgraph->graph(); | 3136 Graph* graph = jsgraph->graph(); |
2900 CommonOperatorBuilder* common = jsgraph->common(); | 3137 CommonOperatorBuilder* common = jsgraph->common(); |
2901 MachineOperatorBuilder* machine = jsgraph->machine(); | 3138 MachineOperatorBuilder* machine = jsgraph->machine(); |
2902 SourcePositionTable* source_position_table = | 3139 SourcePositionTable* source_position_table = |
2903 new (jsgraph->zone()) SourcePositionTable(graph); | 3140 new (jsgraph->zone()) SourcePositionTable(graph); |
2904 WasmGraphBuilder builder(jsgraph->zone(), jsgraph, function->sig, | 3141 WasmGraphBuilder builder(jsgraph->zone(), jsgraph, function->sig, |
2905 source_position_table); | 3142 source_position_table); |
2906 wasm::FunctionBody body = { | 3143 wasm::FunctionBody body = { |
2907 module_env, function->sig, module_env->module->module_start, | 3144 module_env, function->sig, module_env->module->module_start, |
2908 module_env->module->module_start + function->code_start_offset, | 3145 module_env->module->module_start + function->code_start_offset, |
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3064 function_->code_start_offset), | 3301 function_->code_start_offset), |
3065 compile_ms); | 3302 compile_ms); |
3066 } | 3303 } |
3067 | 3304 |
3068 return code; | 3305 return code; |
3069 } | 3306 } |
3070 | 3307 |
3071 } // namespace compiler | 3308 } // namespace compiler |
3072 } // namespace internal | 3309 } // namespace internal |
3073 } // namespace v8 | 3310 } // namespace v8 |
OLD | NEW |