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