| 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 2929 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2940 } | 2940 } |
| 2941 } | 2941 } |
| 2942 | 2942 |
| 2943 Node* cond = graph()->NewNode(jsgraph()->machine()->Uint32LessThan(), index, | 2943 Node* cond = graph()->NewNode(jsgraph()->machine()->Uint32LessThan(), index, |
| 2944 jsgraph()->RelocatableInt32Constant( | 2944 jsgraph()->RelocatableInt32Constant( |
| 2945 static_cast<uint32_t>(effective_size), | 2945 static_cast<uint32_t>(effective_size), |
| 2946 RelocInfo::WASM_MEMORY_SIZE_REFERENCE)); | 2946 RelocInfo::WASM_MEMORY_SIZE_REFERENCE)); |
| 2947 trap_->AddTrapIfFalse(wasm::kTrapMemOutOfBounds, cond, position); | 2947 trap_->AddTrapIfFalse(wasm::kTrapMemOutOfBounds, cond, position); |
| 2948 } | 2948 } |
| 2949 | 2949 |
| 2950 MachineType WasmGraphBuilder::GetTypeForUnalignedAccess(uint32_t alignment, | |
| 2951 bool signExtend) { | |
| 2952 switch (alignment) { | |
| 2953 case 0: | |
| 2954 return signExtend ? MachineType::Int8() : MachineType::Uint8(); | |
| 2955 case 1: | |
| 2956 return signExtend ? MachineType::Int16() : MachineType::Uint16(); | |
| 2957 case 2: | |
| 2958 return signExtend ? MachineType::Int32() : MachineType::Uint32(); | |
| 2959 default: | |
| 2960 UNREACHABLE(); | |
| 2961 return MachineType::None(); | |
| 2962 } | |
| 2963 } | |
| 2964 | |
| 2965 Node* WasmGraphBuilder::GetUnalignedLoadOffsetNode(Node* baseOffset, | |
| 2966 int numberOfBytes, | |
| 2967 int stride, int current) { | |
| 2968 int offset; | |
| 2969 wasm::WasmOpcode addOpcode; | |
| 2970 | |
| 2971 #if defined(V8_TARGET_LITTLE_ENDIAN) | |
| 2972 offset = numberOfBytes - stride - current; | |
| 2973 #elif defined(V8_TARGET_BIG_ENDIAN) | |
| 2974 offset = current; | |
| 2975 #else | |
| 2976 #error Unsupported endianness | |
| 2977 #endif | |
| 2978 | |
| 2979 #if WASM_64 | |
| 2980 addOpcode = wasm::kExprI64Add; | |
| 2981 #else | |
| 2982 addOpcode = wasm::kExprI32Add; | |
| 2983 #endif | |
| 2984 | |
| 2985 if (offset == 0) { | |
| 2986 return baseOffset; | |
| 2987 } else { | |
| 2988 return Binop(addOpcode, baseOffset, jsgraph()->Int32Constant(offset)); | |
| 2989 } | |
| 2990 } | |
| 2991 | |
| 2992 Node* WasmGraphBuilder::BuildUnalignedLoad(wasm::LocalType type, | |
| 2993 MachineType memtype, Node* index, | |
| 2994 uint32_t offset, | |
| 2995 uint32_t alignment) { | |
| 2996 Node* result; | |
| 2997 Node* load; | |
| 2998 bool extendTo64Bit = false; | |
| 2999 | |
| 3000 wasm::WasmOpcode shiftOpcode; | |
| 3001 wasm::WasmOpcode orOpcode; | |
| 3002 Node* shiftConst; | |
| 3003 | |
| 3004 bool signExtend = memtype.IsSigned(); | |
| 3005 | |
| 3006 bool isFloat = IsFloatingPoint(memtype.representation()); | |
| 3007 int stride = | |
| 3008 1 << ElementSizeLog2Of( | |
| 3009 GetTypeForUnalignedAccess(alignment, false).representation()); | |
| 3010 int numberOfBytes = 1 << ElementSizeLog2Of(memtype.representation()); | |
| 3011 DCHECK(numberOfBytes % stride == 0); | |
| 3012 | |
| 3013 switch (type) { | |
| 3014 case wasm::kAstI64: | |
| 3015 case wasm::kAstF64: | |
| 3016 shiftOpcode = wasm::kExprI64Shl; | |
| 3017 orOpcode = wasm::kExprI64Ior; | |
| 3018 result = jsgraph()->Int64Constant(0); | |
| 3019 shiftConst = jsgraph()->Int64Constant(8 * stride); | |
| 3020 extendTo64Bit = true; | |
| 3021 break; | |
| 3022 case wasm::kAstI32: | |
| 3023 case wasm::kAstF32: | |
| 3024 shiftOpcode = wasm::kExprI32Shl; | |
| 3025 orOpcode = wasm::kExprI32Ior; | |
| 3026 result = jsgraph()->Int32Constant(0); | |
| 3027 shiftConst = jsgraph()->Int32Constant(8 * stride); | |
| 3028 break; | |
| 3029 default: | |
| 3030 UNREACHABLE(); | |
| 3031 } | |
| 3032 | |
| 3033 Node* baseOffset = MemBuffer(offset); | |
| 3034 | |
| 3035 for (int i = 0; i < numberOfBytes; i += stride) { | |
| 3036 result = Binop(shiftOpcode, result, shiftConst); | |
| 3037 load = graph()->NewNode( | |
| 3038 jsgraph()->machine()->Load( | |
| 3039 GetTypeForUnalignedAccess(alignment, signExtend)), | |
| 3040 GetUnalignedLoadOffsetNode(baseOffset, numberOfBytes, stride, i), index, | |
| 3041 *effect_, *control_); | |
| 3042 *effect_ = load; | |
| 3043 if (extendTo64Bit) { | |
| 3044 if (signExtend) { | |
| 3045 load = | |
| 3046 graph()->NewNode(jsgraph()->machine()->ChangeInt32ToInt64(), load); | |
| 3047 } else { | |
| 3048 load = graph()->NewNode(jsgraph()->machine()->ChangeUint32ToUint64(), | |
| 3049 load); | |
| 3050 } | |
| 3051 } | |
| 3052 signExtend = false; | |
| 3053 result = Binop(orOpcode, result, load); | |
| 3054 } | |
| 3055 | |
| 3056 // Convert to float | |
| 3057 if (isFloat) { | |
| 3058 switch (type) { | |
| 3059 case wasm::kAstF32: | |
| 3060 result = Unop(wasm::kExprF32ReinterpretI32, result); | |
| 3061 break; | |
| 3062 case wasm::kAstF64: | |
| 3063 result = Unop(wasm::kExprF64ReinterpretI64, result); | |
| 3064 break; | |
| 3065 default: | |
| 3066 UNREACHABLE(); | |
| 3067 } | |
| 3068 } | |
| 3069 | |
| 3070 return result; | |
| 3071 } | |
| 3072 | 2950 |
| 3073 Node* WasmGraphBuilder::LoadMem(wasm::LocalType type, MachineType memtype, | 2951 Node* WasmGraphBuilder::LoadMem(wasm::LocalType type, MachineType memtype, |
| 3074 Node* index, uint32_t offset, | 2952 Node* index, uint32_t offset, |
| 3075 uint32_t alignment, | 2953 uint32_t alignment, |
| 3076 wasm::WasmCodePosition position) { | 2954 wasm::WasmCodePosition position) { |
| 3077 Node* load; | 2955 Node* load; |
| 3078 | 2956 |
| 3079 // WASM semantics throw on OOB. Introduce explicit bounds check. | 2957 // WASM semantics throw on OOB. Introduce explicit bounds check. |
| 3080 BoundsCheckMem(memtype, index, offset, position); | 2958 BoundsCheckMem(memtype, index, offset, position); |
| 3081 bool aligned = static_cast<int>(alignment) >= | 2959 bool aligned = static_cast<int>(alignment) >= |
| 3082 ElementSizeLog2Of(memtype.representation()); | 2960 ElementSizeLog2Of(memtype.representation()); |
| 3083 | 2961 |
| 3084 if (aligned || | 2962 if (aligned || |
| 3085 jsgraph()->machine()->UnalignedLoadSupported(memtype, alignment)) { | 2963 jsgraph()->machine()->UnalignedLoadSupported(memtype, alignment)) { |
| 3086 load = graph()->NewNode(jsgraph()->machine()->Load(memtype), | 2964 load = graph()->NewNode(jsgraph()->machine()->Load(memtype), |
| 3087 MemBuffer(offset), index, *effect_, *control_); | 2965 MemBuffer(offset), index, *effect_, *control_); |
| 3088 *effect_ = load; | |
| 3089 } else { | 2966 } else { |
| 3090 load = BuildUnalignedLoad(type, memtype, index, offset, alignment); | 2967 load = graph()->NewNode(jsgraph()->machine()->UnalignedLoad(memtype), |
| 2968 MemBuffer(offset), index, *effect_, *control_); |
| 3091 } | 2969 } |
| 2970 |
| 2971 *effect_ = load; |
| 2972 |
| 3092 #if defined(V8_TARGET_BIG_ENDIAN) | 2973 #if defined(V8_TARGET_BIG_ENDIAN) |
| 3093 // TODO(john.yan) Implement byte swap turbofan operator | 2974 // TODO(john.yan) Implement byte swap turbofan operator |
| 3094 // and use it if available for better performance | 2975 // and use it if available for better performance |
| 3095 load = BuildChangeEndianness(load, memtype, type); | 2976 load = BuildChangeEndianness(load, memtype, type); |
| 3096 #endif | 2977 #endif |
| 3097 | 2978 |
| 3098 if (type == wasm::kAstI64 && | 2979 if (type == wasm::kAstI64 && |
| 3099 ElementSizeLog2Of(memtype.representation()) < 3) { | 2980 ElementSizeLog2Of(memtype.representation()) < 3) { |
| 3100 // TODO(titzer): TF zeroes the upper bits of 64-bit loads for subword sizes. | 2981 // TODO(titzer): TF zeroes the upper bits of 64-bit loads for subword sizes. |
| 3101 if (memtype.IsSigned()) { | 2982 if (memtype.IsSigned()) { |
| 3102 // sign extend | 2983 // sign extend |
| 3103 load = graph()->NewNode(jsgraph()->machine()->ChangeInt32ToInt64(), load); | 2984 load = graph()->NewNode(jsgraph()->machine()->ChangeInt32ToInt64(), load); |
| 3104 } else { | 2985 } else { |
| 3105 // zero extend | 2986 // zero extend |
| 3106 load = | 2987 load = |
| 3107 graph()->NewNode(jsgraph()->machine()->ChangeUint32ToUint64(), load); | 2988 graph()->NewNode(jsgraph()->machine()->ChangeUint32ToUint64(), load); |
| 3108 } | 2989 } |
| 3109 } | 2990 } |
| 3110 | 2991 |
| 3111 return load; | 2992 return load; |
| 3112 } | 2993 } |
| 3113 | 2994 |
| 3114 Node* WasmGraphBuilder::GetUnalignedStoreOffsetNode(Node* baseOffset, | |
| 3115 int numberOfBytes, | |
| 3116 int stride, int current) { | |
| 3117 int offset; | |
| 3118 wasm::WasmOpcode addOpcode; | |
| 3119 | |
| 3120 #if defined(V8_TARGET_LITTLE_ENDIAN) | |
| 3121 offset = current; | |
| 3122 #elif defined(V8_TARGET_BIG_ENDIAN) | |
| 3123 offset = numberOfBytes - stride - current; | |
| 3124 #else | |
| 3125 #error Unsupported endianness | |
| 3126 #endif | |
| 3127 | |
| 3128 #if WASM_64 | |
| 3129 addOpcode = wasm::kExprI64Add; | |
| 3130 #else | |
| 3131 addOpcode = wasm::kExprI32Add; | |
| 3132 #endif | |
| 3133 | |
| 3134 if (offset == 0) { | |
| 3135 return baseOffset; | |
| 3136 } else { | |
| 3137 return Binop(addOpcode, baseOffset, jsgraph()->Int32Constant(offset)); | |
| 3138 } | |
| 3139 } | |
| 3140 | |
| 3141 Node* WasmGraphBuilder::BuildUnalignedStore(MachineType memtype, Node* index, | |
| 3142 uint32_t offset, uint32_t alignment, | |
| 3143 Node* val) { | |
| 3144 Node* store; | |
| 3145 Node* newValue; | |
| 3146 | |
| 3147 wasm::WasmOpcode shiftOpcode; | |
| 3148 | |
| 3149 Node* shiftConst; | |
| 3150 bool extendTo64Bit = false; | |
| 3151 bool isFloat = IsFloatingPoint(memtype.representation()); | |
| 3152 int stride = 1 << ElementSizeLog2Of( | |
| 3153 GetTypeForUnalignedAccess(alignment).representation()); | |
| 3154 int numberOfBytes = 1 << ElementSizeLog2Of(memtype.representation()); | |
| 3155 DCHECK(numberOfBytes % stride == 0); | |
| 3156 | |
| 3157 StoreRepresentation rep(GetTypeForUnalignedAccess(alignment).representation(), | |
| 3158 kNoWriteBarrier); | |
| 3159 | |
| 3160 if (ElementSizeLog2Of(memtype.representation()) <= 2) { | |
| 3161 shiftOpcode = wasm::kExprI32ShrU; | |
| 3162 shiftConst = jsgraph()->Int32Constant(8 * stride); | |
| 3163 } else { | |
| 3164 shiftOpcode = wasm::kExprI64ShrU; | |
| 3165 shiftConst = jsgraph()->Int64Constant(8 * stride); | |
| 3166 extendTo64Bit = true; | |
| 3167 } | |
| 3168 | |
| 3169 newValue = val; | |
| 3170 if (isFloat) { | |
| 3171 switch (memtype.representation()) { | |
| 3172 case MachineRepresentation::kFloat64: | |
| 3173 newValue = Unop(wasm::kExprI64ReinterpretF64, val); | |
| 3174 break; | |
| 3175 case MachineRepresentation::kFloat32: | |
| 3176 newValue = Unop(wasm::kExprI32ReinterpretF32, val); | |
| 3177 break; | |
| 3178 default: | |
| 3179 UNREACHABLE(); | |
| 3180 } | |
| 3181 } | |
| 3182 | |
| 3183 Node* baseOffset = MemBuffer(offset); | |
| 3184 | |
| 3185 for (int i = 0; i < numberOfBytes - stride; i += stride) { | |
| 3186 store = graph()->NewNode( | |
| 3187 jsgraph()->machine()->Store(rep), | |
| 3188 GetUnalignedStoreOffsetNode(baseOffset, numberOfBytes, stride, i), | |
| 3189 index, | |
| 3190 extendTo64Bit ? Unop(wasm::kExprI32ConvertI64, newValue) : newValue, | |
| 3191 *effect_, *control_); | |
| 3192 newValue = Binop(shiftOpcode, newValue, shiftConst); | |
| 3193 *effect_ = store; | |
| 3194 } | |
| 3195 store = graph()->NewNode( | |
| 3196 jsgraph()->machine()->Store(rep), | |
| 3197 GetUnalignedStoreOffsetNode(baseOffset, numberOfBytes, stride, | |
| 3198 numberOfBytes - stride), | |
| 3199 index, | |
| 3200 extendTo64Bit ? Unop(wasm::kExprI32ConvertI64, newValue) : newValue, | |
| 3201 *effect_, *control_); | |
| 3202 *effect_ = store; | |
| 3203 return val; | |
| 3204 } | |
| 3205 | 2995 |
| 3206 Node* WasmGraphBuilder::StoreMem(MachineType memtype, Node* index, | 2996 Node* WasmGraphBuilder::StoreMem(MachineType memtype, Node* index, |
| 3207 uint32_t offset, uint32_t alignment, Node* val, | 2997 uint32_t offset, uint32_t alignment, Node* val, |
| 3208 wasm::WasmCodePosition position) { | 2998 wasm::WasmCodePosition position) { |
| 3209 Node* store; | 2999 Node* store; |
| 3210 | 3000 |
| 3211 // WASM semantics throw on OOB. Introduce explicit bounds check. | 3001 // WASM semantics throw on OOB. Introduce explicit bounds check. |
| 3212 BoundsCheckMem(memtype, index, offset, position); | 3002 BoundsCheckMem(memtype, index, offset, position); |
| 3213 StoreRepresentation rep(memtype.representation(), kNoWriteBarrier); | 3003 StoreRepresentation rep(memtype.representation(), kNoWriteBarrier); |
| 3214 bool aligned = static_cast<int>(alignment) >= | 3004 bool aligned = static_cast<int>(alignment) >= |
| 3215 ElementSizeLog2Of(memtype.representation()); | 3005 ElementSizeLog2Of(memtype.representation()); |
| 3216 | 3006 |
| 3217 #if defined(V8_TARGET_BIG_ENDIAN) | 3007 #if defined(V8_TARGET_BIG_ENDIAN) |
| 3218 // TODO(john.yan) Implement byte swap turbofan operator | 3008 // TODO(john.yan) Implement byte swap turbofan operator |
| 3219 // and use it if available for better performance | 3009 // and use it if available for better performance |
| 3220 val = BuildChangeEndianness(val, memtype); | 3010 val = BuildChangeEndianness(val, memtype); |
| 3221 #endif | 3011 #endif |
| 3222 | 3012 |
| 3223 if (aligned || | 3013 if (aligned || |
| 3224 jsgraph()->machine()->UnalignedStoreSupported(memtype, alignment)) { | 3014 jsgraph()->machine()->UnalignedStoreSupported(memtype, alignment)) { |
| 3225 StoreRepresentation rep(memtype.representation(), kNoWriteBarrier); | 3015 StoreRepresentation rep(memtype.representation(), kNoWriteBarrier); |
| 3226 store = | 3016 store = |
| 3227 graph()->NewNode(jsgraph()->machine()->Store(rep), MemBuffer(offset), | 3017 graph()->NewNode(jsgraph()->machine()->Store(rep), MemBuffer(offset), |
| 3228 index, val, *effect_, *control_); | 3018 index, val, *effect_, *control_); |
| 3229 *effect_ = store; | |
| 3230 } else { | 3019 } else { |
| 3231 store = BuildUnalignedStore(memtype, index, offset, alignment, val); | 3020 UnalignedStoreRepresentation rep(memtype.representation()); |
| 3021 store = |
| 3022 graph()->NewNode(jsgraph()->machine()->UnalignedStore(rep), |
| 3023 MemBuffer(offset), index, val, *effect_, *control_); |
| 3232 } | 3024 } |
| 3233 | 3025 |
| 3026 *effect_ = store; |
| 3027 |
| 3234 return store; | 3028 return store; |
| 3235 } | 3029 } |
| 3236 | 3030 |
| 3237 Node* WasmGraphBuilder::BuildAsmjsLoadMem(MachineType type, Node* index) { | 3031 Node* WasmGraphBuilder::BuildAsmjsLoadMem(MachineType type, Node* index) { |
| 3238 // TODO(turbofan): fold bounds checks for constant asm.js loads. | 3032 // TODO(turbofan): fold bounds checks for constant asm.js loads. |
| 3239 // asm.js semantics use CheckedLoad (i.e. OOB reads return 0ish). | 3033 // asm.js semantics use CheckedLoad (i.e. OOB reads return 0ish). |
| 3240 const Operator* op = jsgraph()->machine()->CheckedLoad(type); | 3034 const Operator* op = jsgraph()->machine()->CheckedLoad(type); |
| 3241 Node* load = graph()->NewNode(op, MemBuffer(0), index, MemSize(0), *effect_, | 3035 Node* load = graph()->NewNode(op, MemBuffer(0), index, MemSize(0), *effect_, |
| 3242 *control_); | 3036 *control_); |
| 3243 *effect_ = load; | 3037 *effect_ = load; |
| (...skipping 304 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3548 : thrower_(thrower), | 3342 : thrower_(thrower), |
| 3549 isolate_(isolate), | 3343 isolate_(isolate), |
| 3550 module_env_(module_env), | 3344 module_env_(module_env), |
| 3551 function_(function), | 3345 function_(function), |
| 3552 graph_zone_(new Zone(isolate->allocator())), | 3346 graph_zone_(new Zone(isolate->allocator())), |
| 3553 jsgraph_(new (graph_zone()) JSGraph( | 3347 jsgraph_(new (graph_zone()) JSGraph( |
| 3554 isolate, new (graph_zone()) Graph(graph_zone()), | 3348 isolate, new (graph_zone()) Graph(graph_zone()), |
| 3555 new (graph_zone()) CommonOperatorBuilder(graph_zone()), nullptr, | 3349 new (graph_zone()) CommonOperatorBuilder(graph_zone()), nullptr, |
| 3556 nullptr, new (graph_zone()) MachineOperatorBuilder( | 3350 nullptr, new (graph_zone()) MachineOperatorBuilder( |
| 3557 graph_zone(), MachineType::PointerRepresentation(), | 3351 graph_zone(), MachineType::PointerRepresentation(), |
| 3558 InstructionSelector::SupportedMachineOperatorFlags()))), | 3352 InstructionSelector::SupportedMachineOperatorFlags(), |
| 3353 InstructionSelector::AlignmentRequirements()))), |
| 3559 compilation_zone_(isolate->allocator()), | 3354 compilation_zone_(isolate->allocator()), |
| 3560 info_(function->name_length != 0 | 3355 info_(function->name_length != 0 |
| 3561 ? module_env->module->GetNameOrNull(function->name_offset, | 3356 ? module_env->module->GetNameOrNull(function->name_offset, |
| 3562 function->name_length) | 3357 function->name_length) |
| 3563 : ArrayVector("wasm"), | 3358 : ArrayVector("wasm"), |
| 3564 isolate, &compilation_zone_, | 3359 isolate, &compilation_zone_, |
| 3565 Code::ComputeFlags(Code::WASM_FUNCTION)), | 3360 Code::ComputeFlags(Code::WASM_FUNCTION)), |
| 3566 job_(), | 3361 job_(), |
| 3567 index_(index), | 3362 index_(index), |
| 3568 ok_(true) { | 3363 ok_(true) { |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3669 function_->code_start_offset), | 3464 function_->code_start_offset), |
| 3670 compile_ms); | 3465 compile_ms); |
| 3671 } | 3466 } |
| 3672 | 3467 |
| 3673 return code; | 3468 return code; |
| 3674 } | 3469 } |
| 3675 | 3470 |
| 3676 } // namespace compiler | 3471 } // namespace compiler |
| 3677 } // namespace internal | 3472 } // namespace internal |
| 3678 } // namespace v8 | 3473 } // namespace v8 |
| OLD | NEW |