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 Node* WasmGraphBuilder::BuildUnalignedLoad(wasm::LocalType type, | |
2595 MachineType memtype, Node* index, | |
2596 uint32_t offset, | |
2597 uint32_t alignment) { | |
2598 Node* result; | |
2599 Node* load; | |
2600 bool extendTo64Bit = false; | |
2601 | |
2602 wasm::WasmOpcode shiftOpcode; | |
2603 wasm::WasmOpcode orOpcode; | |
2604 Node* shiftConst; | |
2605 | |
2606 auto determineType = [](bool signExtend, uint32_t alignment) -> MachineType { | |
titzer
2016/05/11 15:22:35
Can we lift this out to a helper method instead of
| |
2607 switch (alignment) { | |
2608 case 0: | |
2609 return signExtend ? MachineType::Int8() : MachineType::Uint8(); | |
2610 case 1: | |
2611 return signExtend ? MachineType::Int16() : MachineType::Uint16(); | |
2612 case 2: | |
2613 return signExtend ? MachineType::Int32() : MachineType::Uint32(); | |
2614 default: | |
2615 UNREACHABLE(); | |
2616 } | |
2617 }; | |
2618 | |
2619 auto calculateOffset = [this](Node* baseOffset, int numberOfBytes, int stride, | |
2620 int current) -> Node* { | |
2621 int offset; | |
2622 | |
2623 #if defined(V8_TARGET_LITTLE_ENDIAN) | |
2624 offset = numberOfBytes - stride - current; | |
2625 #elif defined(V8_TARGET_BIG_ENDIAN) | |
2626 offset = current; | |
2627 #else | |
2628 #error Unsupported endianness | |
2629 #endif | |
2630 | |
2631 if (offset == 0) { | |
2632 return baseOffset; | |
2633 } else { | |
2634 return Binop(wasm::kExprI32Add, baseOffset, | |
2635 jsgraph()->Int32Constant(offset)); | |
2636 } | |
2637 }; | |
2638 | |
2639 bool signExtend = memtype.IsSigned(); | |
2640 | |
2641 bool isFloat = IsFloatingPoint(memtype.representation()); | |
2642 int stride = | |
2643 1 << ElementSizeLog2Of(determineType(false, alignment).representation()); | |
2644 int numberOfBytes = 1 << ElementSizeLog2Of(memtype.representation()); | |
2645 int numberOfLoads = numberOfBytes / stride; | |
2646 | |
2647 DCHECK(numberOfBytes % stride == 0); | |
2648 DCHECK(numberOfLoads >= 2); | |
2649 | |
2650 switch (type) { | |
2651 case wasm::kAstI64: | |
2652 case wasm::kAstF64: | |
2653 shiftOpcode = wasm::kExprI64Shl; | |
2654 orOpcode = wasm::kExprI64Ior; | |
2655 result = jsgraph()->Int64Constant(0); | |
2656 shiftConst = jsgraph()->Int64Constant(8 * stride); | |
2657 extendTo64Bit = true; | |
2658 break; | |
2659 case wasm::kAstI32: | |
2660 case wasm::kAstF32: | |
2661 shiftOpcode = wasm::kExprI32Shl; | |
2662 orOpcode = wasm::kExprI32Ior; | |
2663 result = jsgraph()->Int32Constant(0); | |
2664 shiftConst = jsgraph()->Int32Constant(8 * stride); | |
2665 break; | |
2666 default: | |
2667 UNREACHABLE(); | |
2668 } | |
2669 | |
2670 Node* baseOffset = MemBuffer(offset); | |
2671 | |
2672 for (int i = 0; i < numberOfBytes; i += stride) { | |
2673 result = Binop(shiftOpcode, result, shiftConst); | |
2674 load = graph()->NewNode( | |
2675 jsgraph()->machine()->Load(determineType(signExtend, alignment)), | |
2676 calculateOffset(baseOffset, numberOfBytes, stride, i), index, *effect_, | |
2677 *control_); | |
2678 *effect_ = load; | |
2679 if (extendTo64Bit) { | |
2680 if (signExtend) { | |
2681 load = | |
2682 graph()->NewNode(jsgraph()->machine()->ChangeInt32ToInt64(), load); | |
2683 } else { | |
2684 load = graph()->NewNode(jsgraph()->machine()->ChangeUint32ToUint64(), | |
2685 load); | |
2686 } | |
2687 } | |
2688 signExtend = false; | |
2689 result = Binop(orOpcode, result, load); | |
2690 } | |
2691 | |
2692 // Convert to float | |
2693 if (isFloat) { | |
2694 switch (type) { | |
2695 case wasm::kAstF32: | |
2696 result = Unop(wasm::kExprF32ReinterpretI32, result); | |
2697 break; | |
2698 case wasm::kAstF64: | |
2699 result = Unop(wasm::kExprF64ReinterpretI64, result); | |
2700 break; | |
2701 default: | |
2702 UNREACHABLE(); | |
2703 } | |
2704 } | |
2705 | |
2706 return result; | |
2707 } | |
2708 | |
2594 Node* WasmGraphBuilder::LoadMem(wasm::LocalType type, MachineType memtype, | 2709 Node* WasmGraphBuilder::LoadMem(wasm::LocalType type, MachineType memtype, |
2595 Node* index, uint32_t offset, | 2710 Node* index, uint32_t offset, |
2711 uint32_t alignment, | |
2596 wasm::WasmCodePosition position) { | 2712 wasm::WasmCodePosition position) { |
2597 Node* load; | 2713 Node* load; |
2714 bool skip = false; | |
2598 | 2715 |
2599 if (module_ && module_->asm_js()) { | 2716 if (module_ && module_->asm_js()) { |
2600 // asm.js semantics use CheckedLoad (i.e. OOB reads return 0ish). | 2717 // asm.js semantics use CheckedLoad (i.e. OOB reads return 0ish). |
2601 DCHECK_EQ(0, offset); | 2718 DCHECK_EQ(0, offset); |
2602 const Operator* op = jsgraph()->machine()->CheckedLoad(memtype); | 2719 const Operator* op = jsgraph()->machine()->CheckedLoad(memtype); |
2603 load = graph()->NewNode(op, MemBuffer(0), index, MemSize(0), *effect_, | 2720 load = graph()->NewNode(op, MemBuffer(0), index, MemSize(0), *effect_, |
2604 *control_); | 2721 *control_); |
2605 } else { | 2722 } else { |
2606 // WASM semantics throw on OOB. Introduce explicit bounds check. | 2723 // WASM semantics throw on OOB. Introduce explicit bounds check. |
2607 BoundsCheckMem(memtype, index, offset, position); | 2724 BoundsCheckMem(memtype, index, offset, position); |
2608 load = graph()->NewNode(jsgraph()->machine()->Load(memtype), | 2725 bool aligned = alignment >= ElementSizeLog2Of(memtype.representation()); |
2609 MemBuffer(offset), index, *effect_, *control_); | 2726 |
2727 if (aligned || | |
2728 jsgraph()->machine()->UnalignedLoadSupported(memtype, alignment)) { | |
2729 load = graph()->NewNode(jsgraph()->machine()->Load(memtype), | |
2730 MemBuffer(offset), index, *effect_, *control_); | |
2731 } else { | |
2732 load = BuildUnalignedLoad(type, memtype, index, offset, alignment); | |
2733 skip = true; | |
2734 } | |
2610 } | 2735 } |
2611 | 2736 |
2612 *effect_ = load; | 2737 if (!skip) { |
titzer
2016/05/11 15:22:35
Can you lift this up into the branch instead of us
| |
2738 *effect_ = load; | |
2739 } | |
2613 | 2740 |
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::BuildUnalignedStore(MachineType memtype, Node* index, | |
2758 uint32_t offset, uint32_t alignment, | |
2759 Node* val) { | |
2760 Node* store; | |
2761 Node* newValue; | |
2762 | |
2763 wasm::WasmOpcode shiftOpcode; | |
2764 | |
2765 Node* shiftConst; | |
2766 bool extendTo64Bit = false; | |
2767 | |
2768 auto determineType = [](uint32_t alignment) -> MachineType { | |
2769 switch (alignment) { | |
2770 case 0: | |
2771 return MachineType::Uint8(); | |
2772 case 1: | |
2773 return MachineType::Uint16(); | |
2774 case 2: | |
2775 return MachineType::Uint32(); | |
2776 default: | |
2777 UNREACHABLE(); | |
2778 } | |
2779 }; | |
2780 | |
2781 auto calculateOffset = [this](Node* baseOffset, int numberOfBytes, int stride, | |
2782 int current) -> Node* { | |
2783 int offset; | |
2784 #if defined(V8_TARGET_LITTLE_ENDIAN) | |
2785 offset = current; | |
2786 #elif defined(V8_TARGET_BIG_ENDIAN) | |
2787 offset = numberOfBytes - stride - current; | |
2788 #else | |
2789 #error Unsupported endianness | |
2790 #endif | |
2791 if (offset == 0) { | |
2792 return baseOffset; | |
2793 } else { | |
2794 return Binop(wasm::kExprI32Add, baseOffset, | |
2795 jsgraph()->Int32Constant(offset)); | |
2796 } | |
2797 }; | |
2798 | |
2799 bool isFloat = IsFloatingPoint(memtype.representation()); | |
2800 int stride = | |
2801 1 << ElementSizeLog2Of(determineType(alignment).representation()); | |
2802 int numberOfBytes = 1 << ElementSizeLog2Of(memtype.representation()); | |
2803 int numberOfLoads = numberOfBytes / stride; | |
2804 | |
2805 DCHECK(numberOfBytes % stride == 0); | |
2806 DCHECK(numberOfLoads >= 2); | |
2807 | |
2808 StoreRepresentation rep(determineType(alignment).representation(), | |
2809 kNoWriteBarrier); | |
2810 | |
2811 if (ElementSizeLog2Of(memtype.representation()) <= 2) { | |
2812 shiftOpcode = wasm::kExprI32ShrU; | |
2813 shiftConst = jsgraph()->Int32Constant(8 * stride); | |
2814 } else { | |
2815 shiftOpcode = wasm::kExprI64ShrU; | |
2816 shiftConst = jsgraph()->Int64Constant(8 * stride); | |
2817 extendTo64Bit = true; | |
2818 } | |
2819 | |
2820 newValue = val; | |
2821 if (isFloat) { | |
2822 switch (memtype.representation()) { | |
2823 case MachineRepresentation::kFloat64: | |
2824 newValue = Unop(wasm::kExprI64ReinterpretF64, val); | |
2825 break; | |
2826 case MachineRepresentation::kFloat32: | |
2827 newValue = Unop(wasm::kExprI32ReinterpretF32, val); | |
2828 break; | |
2829 default: | |
2830 UNREACHABLE(); | |
2831 } | |
2832 } | |
2833 | |
2834 Node* baseOffset = MemBuffer(offset); | |
2835 | |
2836 for (int i = 0; i < numberOfBytes - stride; i += stride) { | |
2837 store = graph()->NewNode( | |
2838 jsgraph()->machine()->Store(rep), | |
2839 calculateOffset(baseOffset, numberOfBytes, stride, i), index, | |
2840 extendTo64Bit ? Unop(wasm::kExprI32ConvertI64, newValue) : newValue, | |
2841 *effect_, *control_); | |
2842 newValue = Binop(shiftOpcode, newValue, shiftConst); | |
2843 *effect_ = store; | |
2844 } | |
2845 store = graph()->NewNode( | |
2846 jsgraph()->machine()->Store(rep), | |
2847 calculateOffset(baseOffset, numberOfBytes, stride, | |
2848 numberOfBytes - stride), | |
2849 index, | |
2850 extendTo64Bit ? Unop(wasm::kExprI32ConvertI64, newValue) : newValue, | |
2851 *effect_, *control_); | |
2852 *effect_ = store; | |
2853 return val; | |
2854 } | |
2855 | |
2630 Node* WasmGraphBuilder::StoreMem(MachineType memtype, Node* index, | 2856 Node* WasmGraphBuilder::StoreMem(MachineType memtype, Node* index, |
2631 uint32_t offset, Node* val, | 2857 uint32_t offset, uint32_t alignment, Node* val, |
2632 wasm::WasmCodePosition position) { | 2858 wasm::WasmCodePosition position) { |
2633 Node* store; | 2859 Node* store; |
2860 bool skip = false; | |
2634 if (module_ && module_->asm_js()) { | 2861 if (module_ && module_->asm_js()) { |
2635 // asm.js semantics use CheckedStore (i.e. ignore OOB writes). | 2862 // asm.js semantics use CheckedStore (i.e. ignore OOB writes). |
2636 DCHECK_EQ(0, offset); | 2863 DCHECK_EQ(0, offset); |
2637 const Operator* op = | 2864 const Operator* op = |
2638 jsgraph()->machine()->CheckedStore(memtype.representation()); | 2865 jsgraph()->machine()->CheckedStore(memtype.representation()); |
2639 store = graph()->NewNode(op, MemBuffer(0), index, MemSize(0), val, *effect_, | 2866 store = graph()->NewNode(op, MemBuffer(0), index, MemSize(0), val, *effect_, |
2640 *control_); | 2867 *control_); |
2641 } else { | 2868 } else { |
2642 // WASM semantics throw on OOB. Introduce explicit bounds check. | 2869 // WASM semantics throw on OOB. Introduce explicit bounds check. |
2643 BoundsCheckMem(memtype, index, offset, position); | 2870 BoundsCheckMem(memtype, index, offset, position); |
2644 StoreRepresentation rep(memtype.representation(), kNoWriteBarrier); | 2871 StoreRepresentation rep(memtype.representation(), kNoWriteBarrier); |
2645 store = | 2872 bool aligned = alignment >= ElementSizeLog2Of(memtype.representation()); |
2646 graph()->NewNode(jsgraph()->machine()->Store(rep), MemBuffer(offset), | 2873 |
2647 index, val, *effect_, *control_); | 2874 if (aligned || |
2875 jsgraph()->machine()->UnalignedStoreSupported(memtype, alignment)) { | |
2876 StoreRepresentation rep(memtype.representation(), kNoWriteBarrier); | |
2877 store = | |
2878 graph()->NewNode(jsgraph()->machine()->Store(rep), MemBuffer(offset), | |
2879 index, val, *effect_, *control_); | |
2880 } else { | |
2881 store = BuildUnalignedStore(memtype, index, offset, alignment, val); | |
2882 skip = true; | |
2883 } | |
2648 } | 2884 } |
2649 *effect_ = store; | 2885 |
2886 if (!skip) { | |
2887 *effect_ = store; | |
2888 } | |
2889 | |
2650 return store; | 2890 return store; |
2651 } | 2891 } |
2652 | 2892 |
2653 | 2893 |
2654 void WasmGraphBuilder::PrintDebugName(Node* node) { | 2894 void WasmGraphBuilder::PrintDebugName(Node* node) { |
2655 PrintF("#%d:%s", node->id(), node->op()->mnemonic()); | 2895 PrintF("#%d:%s", node->id(), node->op()->mnemonic()); |
2656 } | 2896 } |
2657 | 2897 |
2658 | 2898 |
2659 Node* WasmGraphBuilder::String(const char* string) { | 2899 Node* WasmGraphBuilder::String(const char* string) { |
(...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2870 double* decode_ms) { | 3110 double* decode_ms) { |
2871 base::ElapsedTimer decode_timer; | 3111 base::ElapsedTimer decode_timer; |
2872 if (FLAG_trace_wasm_decode_time) { | 3112 if (FLAG_trace_wasm_decode_time) { |
2873 decode_timer.Start(); | 3113 decode_timer.Start(); |
2874 } | 3114 } |
2875 // Create a TF graph during decoding. | 3115 // Create a TF graph during decoding. |
2876 Graph* graph = new (zone) Graph(zone); | 3116 Graph* graph = new (zone) Graph(zone); |
2877 CommonOperatorBuilder* common = new (zone) CommonOperatorBuilder(zone); | 3117 CommonOperatorBuilder* common = new (zone) CommonOperatorBuilder(zone); |
2878 MachineOperatorBuilder* machine = new (zone) MachineOperatorBuilder( | 3118 MachineOperatorBuilder* machine = new (zone) MachineOperatorBuilder( |
2879 zone, MachineType::PointerRepresentation(), | 3119 zone, MachineType::PointerRepresentation(), |
2880 InstructionSelector::SupportedMachineOperatorFlags()); | 3120 InstructionSelector::SupportedMachineOperatorFlags(), |
3121 InstructionSelector::AlignmentConfiguration()); | |
2881 JSGraph* jsgraph = | 3122 JSGraph* jsgraph = |
2882 new (zone) JSGraph(isolate, graph, common, nullptr, nullptr, machine); | 3123 new (zone) JSGraph(isolate, graph, common, nullptr, nullptr, machine); |
2883 SourcePositionTable* source_position_table = | 3124 SourcePositionTable* source_position_table = |
2884 new (zone) SourcePositionTable(graph); | 3125 new (zone) SourcePositionTable(graph); |
2885 WasmGraphBuilder builder(zone, jsgraph, function->sig, source_position_table); | 3126 WasmGraphBuilder builder(zone, jsgraph, function->sig, source_position_table); |
2886 wasm::FunctionBody body = { | 3127 wasm::FunctionBody body = { |
2887 module_env, function->sig, module_env->module->module_start, | 3128 module_env, function->sig, module_env->module->module_start, |
2888 module_env->module->module_start + function->code_start_offset, | 3129 module_env->module->module_start + function->code_start_offset, |
2889 module_env->module->module_start + function->code_end_offset}; | 3130 module_env->module->module_start + function->code_end_offset}; |
2890 wasm::TreeResult result = | 3131 wasm::TreeResult result = |
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3077 const wasm::WasmFunction* function) { | 3318 const wasm::WasmFunction* function) { |
3078 WasmCompilationUnit* unit = | 3319 WasmCompilationUnit* unit = |
3079 CreateWasmCompilationUnit(thrower, isolate, module_env, function, 0); | 3320 CreateWasmCompilationUnit(thrower, isolate, module_env, function, 0); |
3080 ExecuteCompilation(unit); | 3321 ExecuteCompilation(unit); |
3081 return FinishCompilation(unit); | 3322 return FinishCompilation(unit); |
3082 } | 3323 } |
3083 | 3324 |
3084 } // namespace compiler | 3325 } // namespace compiler |
3085 } // namespace internal | 3326 } // namespace internal |
3086 } // namespace v8 | 3327 } // namespace v8 |
OLD | NEW |