Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 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/access-builder.h" | 5 #include "src/compiler/access-builder.h" |
| 6 #include "src/compiler/js-graph.h" | 6 #include "src/compiler/js-graph.h" |
| 7 #include "src/compiler/js-typed-lowering.h" | 7 #include "src/compiler/js-typed-lowering.h" |
| 8 #include "src/compiler/node-matchers.h" | 8 #include "src/compiler/node-matchers.h" |
| 9 #include "src/compiler/node-properties.h" | 9 #include "src/compiler/node-properties.h" |
| 10 #include "src/compiler/operator-properties.h" | 10 #include "src/compiler/operator-properties.h" |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 55 } | 55 } |
| 56 | 56 |
| 57 | 57 |
| 58 // A helper class to simplify the process of reducing a single binop node with a | 58 // A helper class to simplify the process of reducing a single binop node with a |
| 59 // JSOperator. This class manages the rewriting of context, control, and effect | 59 // JSOperator. This class manages the rewriting of context, control, and effect |
| 60 // dependencies during lowering of a binop and contains numerous helper | 60 // dependencies during lowering of a binop and contains numerous helper |
| 61 // functions for matching the types of inputs to an operation. | 61 // functions for matching the types of inputs to an operation. |
| 62 class JSBinopReduction FINAL { | 62 class JSBinopReduction FINAL { |
| 63 public: | 63 public: |
| 64 JSBinopReduction(JSTypedLowering* lowering, Node* node) | 64 JSBinopReduction(JSTypedLowering* lowering, Node* node) |
| 65 : lowering_(lowering), | 65 : lowering_(lowering), node_(node) {} |
| 66 node_(node), | |
| 67 left_type_(NodeProperties::GetBounds(node->InputAt(0)).upper), | |
| 68 right_type_(NodeProperties::GetBounds(node->InputAt(1)).upper) {} | |
| 69 | 66 |
| 70 void ConvertInputsToNumber() { | 67 void ConvertPrimitiveInputsToNumber() { |
| 71 node_->ReplaceInput(0, ConvertToNumber(left())); | 68 node_->ReplaceInput(0, ConvertPrimitiveToNumber(left())); |
| 72 node_->ReplaceInput(1, ConvertToNumber(right())); | 69 node_->ReplaceInput(1, ConvertPrimitiveToNumber(right())); |
| 70 } | |
| 71 | |
| 72 void ConvertInputsToNumber(Node* frame_state) { | |
| 73 // To convert the inputs to numbers, we have to provide frame states | |
| 74 // for lazy bailouts in the ToNumber conversions. | |
| 75 // We use a little hack here: we take the frame state before the binary | |
| 76 // operation and use it to construct the frame states for the conversion | |
| 77 // so that after the deoptimization, the binary operation IC gets | |
| 78 // already converted values from full code. This way we are sure that we | |
| 79 // will not re-do any of the side effects. | |
| 80 | |
| 81 Node* left_input = | |
| 82 left_type()->Is(Type::PlainPrimitive()) | |
| 83 ? ConvertPrimitiveToNumber(left()) | |
| 84 : ConvertToNumber(left(), | |
| 85 CreateFrameStateForLeftInput(frame_state)); | |
| 86 | |
| 87 Node* right_input = | |
| 88 right_type()->Is(Type::PlainPrimitive()) | |
| 89 ? ConvertPrimitiveToNumber(right()) | |
| 90 : ConvertToNumber(right(), CreateFrameStateForRightInput( | |
| 91 frame_state, left_input)); | |
| 92 | |
| 93 node_->ReplaceInput(0, left_input); | |
| 94 node_->ReplaceInput(1, right_input); | |
| 73 } | 95 } |
| 74 | 96 |
| 75 void ConvertInputsToUI32(Signedness left_signedness, | 97 void ConvertInputsToUI32(Signedness left_signedness, |
| 76 Signedness right_signedness) { | 98 Signedness right_signedness) { |
| 77 node_->ReplaceInput(0, ConvertToUI32(left(), left_signedness)); | 99 node_->ReplaceInput(0, ConvertToUI32(left(), left_signedness)); |
| 78 node_->ReplaceInput(1, ConvertToUI32(right(), right_signedness)); | 100 node_->ReplaceInput(1, ConvertToUI32(right(), right_signedness)); |
| 79 } | 101 } |
| 80 | 102 |
| 81 void ConvertInputsToString() { | 103 void ConvertInputsToString() { |
| 82 node_->ReplaceInput(0, ConvertToString(left())); | 104 node_->ReplaceInput(0, ConvertToString(left())); |
| 83 node_->ReplaceInput(1, ConvertToString(right())); | 105 node_->ReplaceInput(1, ConvertToString(right())); |
| 84 } | 106 } |
| 85 | 107 |
| 86 // Convert inputs for bitwise shift operation (ES5 spec 11.7). | 108 // Convert inputs for bitwise shift operation (ES5 spec 11.7). |
| 87 void ConvertInputsForShift(Signedness left_signedness) { | 109 void ConvertInputsForShift(Signedness left_signedness) { |
| 88 node_->ReplaceInput(0, ConvertToUI32(left(), left_signedness)); | 110 node_->ReplaceInput( |
| 89 Node* rnum = ConvertToUI32(right(), kUnsigned); | 111 0, ConvertToUI32(ConvertPrimitiveToNumber(left()), left_signedness)); |
| 112 Node* rnum = ConvertToUI32(ConvertPrimitiveToNumber(right()), kUnsigned); | |
| 90 Type* rnum_type = NodeProperties::GetBounds(rnum).upper; | 113 Type* rnum_type = NodeProperties::GetBounds(rnum).upper; |
| 91 if (!rnum_type->Is(lowering_->zero_thirtyone_range_)) { | 114 if (!rnum_type->Is(lowering_->zero_thirtyone_range_)) { |
| 92 rnum = graph()->NewNode(machine()->Word32And(), rnum, | 115 rnum = graph()->NewNode(machine()->Word32And(), rnum, |
| 93 jsgraph()->Int32Constant(0x1F)); | 116 jsgraph()->Int32Constant(0x1F)); |
| 94 } | 117 } |
| 95 node_->ReplaceInput(1, rnum); | 118 node_->ReplaceInput(1, rnum); |
| 96 } | 119 } |
| 97 | 120 |
| 98 void SwapInputs() { | 121 void SwapInputs() { |
| 99 Node* l = left(); | 122 Node* l = left(); |
| 100 Node* r = right(); | 123 Node* r = right(); |
| 101 node_->ReplaceInput(0, r); | 124 node_->ReplaceInput(0, r); |
| 102 node_->ReplaceInput(1, l); | 125 node_->ReplaceInput(1, l); |
| 103 std::swap(left_type_, right_type_); | |
| 104 } | 126 } |
| 105 | 127 |
| 106 // Remove all effect and control inputs and outputs to this node and change | 128 // Remove all effect and control inputs and outputs to this node and change |
| 107 // to the pure operator {op}, possibly inserting a boolean inversion. | 129 // to the pure operator {op}, possibly inserting a boolean inversion. |
| 108 Reduction ChangeToPureOperator(const Operator* op, bool invert = false, | 130 Reduction ChangeToPureOperator(const Operator* op, bool invert = false, |
| 109 Type* type = Type::Any()) { | 131 Type* type = Type::Any()) { |
| 110 DCHECK_EQ(0, op->EffectInputCount()); | 132 DCHECK_EQ(0, op->EffectInputCount()); |
| 111 DCHECK_EQ(false, OperatorProperties::HasContextInput(op)); | 133 DCHECK_EQ(false, OperatorProperties::HasContextInput(op)); |
| 112 DCHECK_EQ(0, op->ControlInputCount()); | 134 DCHECK_EQ(0, op->ControlInputCount()); |
| 113 DCHECK_EQ(2, op->ValueInputCount()); | 135 DCHECK_EQ(2, op->ValueInputCount()); |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 134 value->ReplaceInput(0, node_); | 156 value->ReplaceInput(0, node_); |
| 135 return lowering_->Replace(value); | 157 return lowering_->Replace(value); |
| 136 } | 158 } |
| 137 return lowering_->Changed(node_); | 159 return lowering_->Changed(node_); |
| 138 } | 160 } |
| 139 | 161 |
| 140 Reduction ChangeToPureOperator(const Operator* op, Type* type) { | 162 Reduction ChangeToPureOperator(const Operator* op, Type* type) { |
| 141 return ChangeToPureOperator(op, false, type); | 163 return ChangeToPureOperator(op, false, type); |
| 142 } | 164 } |
| 143 | 165 |
| 144 bool OneInputIs(Type* t) { return left_type_->Is(t) || right_type_->Is(t); } | 166 bool OneInputIs(Type* t) { return left_type()->Is(t) || right_type()->Is(t); } |
| 145 | 167 |
| 146 bool BothInputsAre(Type* t) { | 168 bool BothInputsAre(Type* t) { |
| 147 return left_type_->Is(t) && right_type_->Is(t); | 169 return left_type()->Is(t) && right_type()->Is(t); |
| 148 } | 170 } |
| 149 | 171 |
| 150 bool OneInputCannotBe(Type* t) { | 172 bool OneInputCannotBe(Type* t) { |
| 151 return !left_type_->Maybe(t) || !right_type_->Maybe(t); | 173 return !left_type()->Maybe(t) || !right_type()->Maybe(t); |
| 152 } | 174 } |
| 153 | 175 |
| 154 bool NeitherInputCanBe(Type* t) { | 176 bool NeitherInputCanBe(Type* t) { |
| 155 return !left_type_->Maybe(t) && !right_type_->Maybe(t); | 177 return !left_type()->Maybe(t) && !right_type()->Maybe(t); |
| 156 } | 178 } |
| 157 | 179 |
| 158 Node* effect() { return NodeProperties::GetEffectInput(node_); } | 180 Node* effect() { return NodeProperties::GetEffectInput(node_); } |
| 159 Node* control() { return NodeProperties::GetControlInput(node_); } | 181 Node* control() { return NodeProperties::GetControlInput(node_); } |
| 160 Node* context() { return NodeProperties::GetContextInput(node_); } | 182 Node* context() { return NodeProperties::GetContextInput(node_); } |
| 161 Node* left() { return NodeProperties::GetValueInput(node_, 0); } | 183 Node* left() { return NodeProperties::GetValueInput(node_, 0); } |
| 162 Node* right() { return NodeProperties::GetValueInput(node_, 1); } | 184 Node* right() { return NodeProperties::GetValueInput(node_, 1); } |
| 163 Type* left_type() { return left_type_; } | 185 Type* left_type() { |
| 164 Type* right_type() { return right_type_; } | 186 return NodeProperties::GetBounds(node_->InputAt(0)).upper; |
| 187 } | |
| 188 Type* right_type() { | |
| 189 return NodeProperties::GetBounds(node_->InputAt(1)).upper; | |
| 190 } | |
| 165 | 191 |
| 166 SimplifiedOperatorBuilder* simplified() { return lowering_->simplified(); } | 192 SimplifiedOperatorBuilder* simplified() { return lowering_->simplified(); } |
| 167 Graph* graph() const { return lowering_->graph(); } | 193 Graph* graph() const { return lowering_->graph(); } |
| 168 JSGraph* jsgraph() { return lowering_->jsgraph(); } | 194 JSGraph* jsgraph() { return lowering_->jsgraph(); } |
| 169 JSOperatorBuilder* javascript() { return lowering_->javascript(); } | 195 JSOperatorBuilder* javascript() { return lowering_->javascript(); } |
| 170 MachineOperatorBuilder* machine() { return lowering_->machine(); } | 196 MachineOperatorBuilder* machine() { return lowering_->machine(); } |
| 171 Zone* zone() const { return graph()->zone(); } | 197 Zone* zone() const { return graph()->zone(); } |
| 172 | 198 |
| 173 private: | 199 private: |
| 174 JSTypedLowering* lowering_; // The containing lowering instance. | 200 JSTypedLowering* lowering_; // The containing lowering instance. |
| 175 Node* node_; // The original node. | 201 Node* node_; // The original node. |
| 176 Type* left_type_; // Cache of the left input's type. | |
| 177 Type* right_type_; // Cache of the right input's type. | |
| 178 | 202 |
| 179 Node* ConvertToString(Node* node) { | 203 Node* ConvertToString(Node* node) { |
| 180 // Avoid introducing too many eager ToString() operations. | 204 // Avoid introducing too many eager ToString() operations. |
| 181 Reduction reduced = lowering_->ReduceJSToStringInput(node); | 205 Reduction reduced = lowering_->ReduceJSToStringInput(node); |
| 182 if (reduced.Changed()) return reduced.replacement(); | 206 if (reduced.Changed()) return reduced.replacement(); |
| 183 Node* n = graph()->NewNode(javascript()->ToString(), node, context(), | 207 Node* n = graph()->NewNode(javascript()->ToString(), node, context(), |
| 184 effect(), control()); | 208 effect(), control()); |
| 185 update_effect(n); | 209 update_effect(n); |
| 186 return n; | 210 return n; |
| 187 } | 211 } |
| 188 | 212 |
| 189 Node* ConvertToNumber(Node* node) { | 213 Node* CreateFrameStateForLeftInput(Node* frame_state) { |
| 214 if (!FLAG_turbo_deoptimization) return nullptr; | |
| 215 | |
| 216 FrameStateCallInfo state_info = | |
| 217 OpParameter<FrameStateCallInfo>(frame_state); | |
| 218 // If the frame state is already the right one, just return it. | |
| 219 if (state_info.state_combine().kind() == OutputFrameStateCombine::kPokeAt && | |
| 220 state_info.state_combine().GetOffsetToPokeAt() == 1) { | |
| 221 return frame_state; | |
| 222 } | |
| 223 | |
| 224 // Here, we smash the result of the conversion into the slot just below | |
| 225 // the stack top. This is the slot that full code uses to store the | |
| 226 // left operand. | |
| 227 const Operator* op = jsgraph()->common()->FrameState( | |
| 228 state_info.type(), state_info.bailout_id(), | |
| 229 OutputFrameStateCombine::PokeAt(1)); | |
| 230 | |
| 231 return graph()->NewNode(op, frame_state->InputAt(0), | |
|
Benedikt Meurer
2015/03/09 09:57:29
As discussed offline, please add something like No
| |
| 232 frame_state->InputAt(1), frame_state->InputAt(2), | |
| 233 frame_state->InputAt(3), frame_state->InputAt(4)); | |
| 234 } | |
| 235 | |
| 236 Node* CreateFrameStateForRightInput(Node* frame_state, Node* converted_left) { | |
| 237 if (!FLAG_turbo_deoptimization) return nullptr; | |
| 238 | |
| 239 FrameStateCallInfo state_info = | |
| 240 OpParameter<FrameStateCallInfo>(frame_state); | |
| 241 | |
| 242 if (state_info.bailout_id() == BailoutId::None()) { | |
| 243 // Dummy frame state => just leave it as is. | |
| 244 return frame_state; | |
| 245 } | |
| 246 | |
| 247 // Create a frame state that stores the result of the operation to the | |
| 248 // top of the stack (i.e., the slot used for the right operand). | |
| 249 const Operator* op = jsgraph()->common()->FrameState( | |
| 250 state_info.type(), state_info.bailout_id(), | |
| 251 OutputFrameStateCombine::PokeAt(0)); | |
| 252 | |
| 253 // Change the left operand {converted_left} on the expression stack. | |
| 254 Node* stack = frame_state->InputAt(2); | |
| 255 DCHECK_EQ(stack->opcode(), IrOpcode::kStateValues); | |
| 256 DCHECK_GE(stack->InputCount(), 2); | |
| 257 | |
| 258 // TODO(jarin) Allocate in a local zone or a reusable buffer. | |
| 259 NodeVector new_values(stack->InputCount(), zone()); | |
| 260 for (int i = 0; i < stack->InputCount(); i++) { | |
| 261 if (i == stack->InputCount() - 2) { | |
| 262 new_values[i] = converted_left; | |
| 263 } else { | |
| 264 new_values[i] = stack->InputAt(i); | |
| 265 } | |
| 266 } | |
| 267 Node* new_stack = | |
| 268 graph()->NewNode(stack->op(), stack->InputCount(), &new_values.front()); | |
| 269 | |
| 270 return graph()->NewNode(op, frame_state->InputAt(0), | |
|
Benedikt Meurer
2015/03/09 09:57:29
As discussed offline, please add something like No
| |
| 271 frame_state->InputAt(1), new_stack, | |
| 272 frame_state->InputAt(3), frame_state->InputAt(4)); | |
| 273 } | |
| 274 | |
| 275 Node* ConvertPrimitiveToNumber(Node* node) { | |
| 276 return lowering_->ConvertPrimitiveToNumber(node); | |
| 277 } | |
| 278 | |
| 279 Node* ConvertToNumber(Node* node, Node* frame_state) { | |
| 190 if (NodeProperties::GetBounds(node).upper->Is(Type::PlainPrimitive())) { | 280 if (NodeProperties::GetBounds(node).upper->Is(Type::PlainPrimitive())) { |
| 191 return lowering_->ConvertToNumber(node); | 281 return ConvertPrimitiveToNumber(node); |
| 282 } else if (!FLAG_turbo_deoptimization) { | |
| 283 // We cannot use ConvertToPrimitiveNumber here because we need context | |
| 284 // for converting general values. | |
| 285 Node* const n = graph()->NewNode(javascript()->ToNumber(), node, | |
| 286 context(), effect(), control()); | |
| 287 update_effect(n); | |
| 288 return n; | |
| 289 } else { | |
| 290 Node* const n = | |
| 291 graph()->NewNode(javascript()->ToNumber(), node, context(), | |
| 292 frame_state, effect(), control()); | |
| 293 update_effect(n); | |
| 294 return n; | |
| 192 } | 295 } |
| 193 // TODO(jarin) This ToNumber conversion can deoptimize, but we do not really | |
| 194 // have a frame state to deoptimize to. Either we provide such a frame state | |
| 195 // or we exclude the values that could lead to deoptimization (e.g., by | |
| 196 // triggering eager deopt if the value is not plain). | |
| 197 Node* const n = FLAG_turbo_deoptimization | |
| 198 ? graph()->NewNode( | |
| 199 javascript()->ToNumber(), node, context(), | |
| 200 jsgraph()->EmptyFrameState(), effect(), control()) | |
| 201 : graph()->NewNode(javascript()->ToNumber(), node, | |
| 202 context(), effect(), control()); | |
| 203 update_effect(n); | |
| 204 return n; | |
| 205 } | 296 } |
| 206 | 297 |
| 207 Node* ConvertToUI32(Node* node, Signedness signedness) { | 298 Node* ConvertToUI32(Node* node, Signedness signedness) { |
| 208 // Avoid introducing too many eager NumberToXXnt32() operations. | 299 // Avoid introducing too many eager NumberToXXnt32() operations. |
| 209 node = ConvertToNumber(node); | |
| 210 Type* type = NodeProperties::GetBounds(node).upper; | 300 Type* type = NodeProperties::GetBounds(node).upper; |
| 211 if (signedness == kSigned) { | 301 if (signedness == kSigned) { |
| 212 if (!type->Is(Type::Signed32())) { | 302 if (!type->Is(Type::Signed32())) { |
| 213 node = graph()->NewNode(simplified()->NumberToInt32(), node); | 303 node = graph()->NewNode(simplified()->NumberToInt32(), node); |
| 214 } | 304 } |
| 215 } else { | 305 } else { |
| 216 DCHECK_EQ(kUnsigned, signedness); | 306 DCHECK_EQ(kUnsigned, signedness); |
| 217 if (!type->Is(Type::Unsigned32())) { | 307 if (!type->Is(Type::Unsigned32())) { |
| 218 node = graph()->NewNode(simplified()->NumberToUint32(), node); | 308 node = graph()->NewNode(simplified()->NumberToUint32(), node); |
| 219 } | 309 } |
| 220 } | 310 } |
| 221 return node; | 311 return node; |
| 222 } | 312 } |
| 223 | 313 |
| 224 void update_effect(Node* effect) { | 314 void update_effect(Node* effect) { |
| 225 NodeProperties::ReplaceEffectInput(node_, effect); | 315 NodeProperties::ReplaceEffectInput(node_, effect); |
| 226 } | 316 } |
| 227 }; | 317 }; |
| 228 | 318 |
| 229 | 319 |
| 230 Reduction JSTypedLowering::ReduceJSAdd(Node* node) { | 320 Reduction JSTypedLowering::ReduceJSAdd(Node* node) { |
| 231 JSBinopReduction r(this, node); | 321 JSBinopReduction r(this, node); |
| 232 if (r.BothInputsAre(Type::Number())) { | 322 if (r.BothInputsAre(Type::Number())) { |
| 233 // JSAdd(x:number, y:number) => NumberAdd(x, y) | 323 // JSAdd(x:number, y:number) => NumberAdd(x, y) |
| 234 return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number()); | 324 return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number()); |
| 235 } | 325 } |
| 236 if (r.BothInputsAre(Type::Primitive()) && | 326 if (r.NeitherInputCanBe(Type::StringOrReceiver())) { |
| 237 r.NeitherInputCanBe(Type::StringOrReceiver())) { | |
| 238 // JSAdd(x:-string, y:-string) => NumberAdd(ToNumber(x), ToNumber(y)) | 327 // JSAdd(x:-string, y:-string) => NumberAdd(ToNumber(x), ToNumber(y)) |
| 239 r.ConvertInputsToNumber(); | 328 Node* frame_state = FLAG_turbo_deoptimization |
| 329 ? NodeProperties::GetFrameStateInput(node, 1) | |
| 330 : nullptr; | |
| 331 r.ConvertInputsToNumber(frame_state); | |
| 240 return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number()); | 332 return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number()); |
| 241 } | 333 } |
| 242 #if 0 | 334 #if 0 |
| 243 // TODO(turbofan): General ToNumber disabled for now because: | |
| 244 // a) The inserted ToNumber operation screws up observability of valueOf. | |
| 245 // b) Deoptimization at ToNumber doesn't have corresponding bailout id. | |
| 246 Type* maybe_string = Type::Union(Type::String(), Type::Receiver(), zone()); | |
| 247 if (r.NeitherInputCanBe(maybe_string)) { | |
| 248 ... | |
| 249 } | |
| 250 #endif | |
| 251 #if 0 | |
| 252 // TODO(turbofan): Lowering of StringAdd is disabled for now because: | 335 // TODO(turbofan): Lowering of StringAdd is disabled for now because: |
| 253 // a) The inserted ToString operation screws up valueOf vs. toString order. | 336 // a) The inserted ToString operation screws up valueOf vs. toString order. |
| 254 // b) Deoptimization at ToString doesn't have corresponding bailout id. | 337 // b) Deoptimization at ToString doesn't have corresponding bailout id. |
| 255 // c) Our current StringAddStub is actually non-pure and requires context. | 338 // c) Our current StringAddStub is actually non-pure and requires context. |
| 256 if (r.OneInputIs(Type::String())) { | 339 if (r.OneInputIs(Type::String())) { |
| 257 // JSAdd(x:string, y:string) => StringAdd(x, y) | 340 // JSAdd(x:string, y:string) => StringAdd(x, y) |
| 258 // JSAdd(x:string, y) => StringAdd(x, ToString(y)) | 341 // JSAdd(x:string, y) => StringAdd(x, ToString(y)) |
| 259 // JSAdd(x, y:string) => StringAdd(ToString(x), y) | 342 // JSAdd(x, y:string) => StringAdd(ToString(x), y) |
| 260 r.ConvertInputsToString(); | 343 r.ConvertInputsToString(); |
| 261 return r.ChangeToPureOperator(simplified()->StringAdd()); | 344 return r.ChangeToPureOperator(simplified()->StringAdd()); |
| 262 } | 345 } |
| 263 #endif | 346 #endif |
| 264 return NoChange(); | 347 return NoChange(); |
| 265 } | 348 } |
| 266 | 349 |
| 267 | 350 |
| 268 Reduction JSTypedLowering::ReduceJSBitwiseOr(Node* node) { | |
| 269 JSBinopReduction r(this, node); | |
| 270 | |
| 271 // We can only reduce to Word32Or if we are sure the to-number conversions | |
| 272 // cannot lazily deoptimize. | |
| 273 bool shortcut_or_zero = | |
| 274 !FLAG_turbo_deoptimization && r.OneInputIs(zero_range_); | |
| 275 if (r.BothInputsAre(Type::Primitive()) || shortcut_or_zero) { | |
| 276 // TODO(titzer): some Smi bitwise operations don't really require going | |
| 277 // all the way to int32, which can save tagging/untagging for some | |
| 278 // operations on some platforms. | |
| 279 // TODO(turbofan): make this heuristic configurable for code size. | |
| 280 r.ConvertInputsToUI32(kSigned, kSigned); | |
| 281 return r.ChangeToPureOperator(machine()->Word32Or(), Type::Integral32()); | |
| 282 } | |
| 283 return NoChange(); | |
| 284 } | |
| 285 | |
| 286 | |
| 287 Reduction JSTypedLowering::ReduceJSMultiply(Node* node) { | |
| 288 JSBinopReduction r(this, node); | |
| 289 | |
| 290 // We can only reduce to NumberMultiply if we are sure the to-number | |
| 291 // conversions cannot lazily deoptimize. | |
| 292 bool shortcut_multiply_one = | |
| 293 !FLAG_turbo_deoptimization && r.OneInputIs(one_range_); | |
| 294 | |
| 295 if (r.BothInputsAre(Type::Primitive()) || shortcut_multiply_one) { | |
| 296 r.ConvertInputsToNumber(); | |
| 297 return r.ChangeToPureOperator(simplified()->NumberMultiply(), | |
| 298 Type::Number()); | |
| 299 } | |
| 300 // TODO(turbofan): relax/remove the effects of this operator in other cases. | |
| 301 return NoChange(); | |
| 302 } | |
| 303 | |
| 304 | |
| 305 Reduction JSTypedLowering::ReduceNumberBinop(Node* node, | 351 Reduction JSTypedLowering::ReduceNumberBinop(Node* node, |
| 306 const Operator* numberOp) { | 352 const Operator* numberOp) { |
| 307 JSBinopReduction r(this, node); | 353 JSBinopReduction r(this, node); |
| 308 if (r.BothInputsAre(Type::Primitive())) { | 354 Node* frame_state = FLAG_turbo_deoptimization |
| 309 r.ConvertInputsToNumber(); | 355 ? NodeProperties::GetFrameStateInput(node, 1) |
| 310 return r.ChangeToPureOperator(numberOp, Type::Number()); | 356 : nullptr; |
| 311 } | 357 r.ConvertInputsToNumber(frame_state); |
| 312 #if 0 | 358 return r.ChangeToPureOperator(numberOp, Type::Number()); |
| 313 // TODO(turbofan): General ToNumber disabled for now because: | |
| 314 // a) The inserted ToNumber operation screws up observability of valueOf. | |
| 315 // b) Deoptimization at ToNumber doesn't have corresponding bailout id. | |
| 316 if (r.OneInputIs(Type::Primitive())) { | |
| 317 // If at least one input is a primitive, then insert appropriate conversions | |
| 318 // to number and reduce this operator to the given numeric one. | |
| 319 // TODO(turbofan): make this heuristic configurable for code size. | |
| 320 r.ConvertInputsToNumber(); | |
| 321 return r.ChangeToPureOperator(numberOp); | |
| 322 } | |
| 323 #endif | |
| 324 // TODO(turbofan): relax/remove the effects of this operator in other cases. | |
| 325 return NoChange(); | |
| 326 } | 359 } |
| 327 | 360 |
| 328 | 361 |
| 329 Reduction JSTypedLowering::ReduceInt32Binop(Node* node, const Operator* intOp) { | 362 Reduction JSTypedLowering::ReduceInt32Binop(Node* node, const Operator* intOp) { |
| 330 JSBinopReduction r(this, node); | 363 JSBinopReduction r(this, node); |
| 331 if (r.BothInputsAre(Type::Primitive())) { | 364 Node* frame_state = FLAG_turbo_deoptimization |
| 332 // TODO(titzer): some Smi bitwise operations don't really require going | 365 ? NodeProperties::GetFrameStateInput(node, 1) |
| 333 // all the way to int32, which can save tagging/untagging for some | 366 : nullptr; |
| 334 // operations | 367 r.ConvertInputsToNumber(frame_state); |
| 335 // on some platforms. | 368 r.ConvertInputsToUI32(kSigned, kSigned); |
| 336 // TODO(turbofan): make this heuristic configurable for code size. | 369 return r.ChangeToPureOperator(intOp, Type::Integral32()); |
| 337 r.ConvertInputsToUI32(kSigned, kSigned); | |
| 338 return r.ChangeToPureOperator(intOp, Type::Integral32()); | |
| 339 } | |
| 340 return NoChange(); | |
| 341 } | 370 } |
| 342 | 371 |
| 343 | 372 |
| 344 Reduction JSTypedLowering::ReduceUI32Shift(Node* node, | 373 Reduction JSTypedLowering::ReduceUI32Shift(Node* node, |
| 345 Signedness left_signedness, | 374 Signedness left_signedness, |
| 346 const Operator* shift_op) { | 375 const Operator* shift_op) { |
| 347 JSBinopReduction r(this, node); | 376 JSBinopReduction r(this, node); |
| 348 if (r.BothInputsAre(Type::Primitive())) { | 377 if (r.BothInputsAre(Type::Primitive())) { |
| 349 r.ConvertInputsForShift(left_signedness); | 378 r.ConvertInputsForShift(left_signedness); |
| 350 return r.ChangeToPureOperator(shift_op, Type::Integral32()); | 379 return r.ChangeToPureOperator(shift_op, Type::Integral32()); |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 381 #if 0 | 410 #if 0 |
| 382 // TODO(turbofan): General ToNumber disabled for now because: | 411 // TODO(turbofan): General ToNumber disabled for now because: |
| 383 // a) The inserted ToNumber operation screws up observability of valueOf. | 412 // a) The inserted ToNumber operation screws up observability of valueOf. |
| 384 // b) Deoptimization at ToNumber doesn't have corresponding bailout id. | 413 // b) Deoptimization at ToNumber doesn't have corresponding bailout id. |
| 385 Type* maybe_string = Type::Union(Type::String(), Type::Receiver(), zone()); | 414 Type* maybe_string = Type::Union(Type::String(), Type::Receiver(), zone()); |
| 386 if (r.OneInputCannotBe(maybe_string)) { | 415 if (r.OneInputCannotBe(maybe_string)) { |
| 387 // If one input cannot be a string, then emit a number comparison. | 416 // If one input cannot be a string, then emit a number comparison. |
| 388 ... | 417 ... |
| 389 } | 418 } |
| 390 #endif | 419 #endif |
| 391 if (r.BothInputsAre(Type::Primitive()) && | 420 if (r.BothInputsAre(Type::PlainPrimitive()) && |
| 392 r.OneInputCannotBe(Type::StringOrReceiver())) { | 421 r.OneInputCannotBe(Type::StringOrReceiver())) { |
| 393 const Operator* less_than; | 422 const Operator* less_than; |
| 394 const Operator* less_than_or_equal; | 423 const Operator* less_than_or_equal; |
| 395 if (r.BothInputsAre(Type::Unsigned32())) { | 424 if (r.BothInputsAre(Type::Unsigned32())) { |
| 396 less_than = machine()->Uint32LessThan(); | 425 less_than = machine()->Uint32LessThan(); |
| 397 less_than_or_equal = machine()->Uint32LessThanOrEqual(); | 426 less_than_or_equal = machine()->Uint32LessThanOrEqual(); |
| 398 } else if (r.BothInputsAre(Type::Signed32())) { | 427 } else if (r.BothInputsAre(Type::Signed32())) { |
| 399 less_than = machine()->Int32LessThan(); | 428 less_than = machine()->Int32LessThan(); |
| 400 less_than_or_equal = machine()->Int32LessThanOrEqual(); | 429 less_than_or_equal = machine()->Int32LessThanOrEqual(); |
| 401 } else { | 430 } else { |
| 402 // TODO(turbofan): mixed signed/unsigned int32 comparisons. | 431 // TODO(turbofan): mixed signed/unsigned int32 comparisons. |
| 403 r.ConvertInputsToNumber(); | 432 r.ConvertPrimitiveInputsToNumber(); |
| 404 less_than = simplified()->NumberLessThan(); | 433 less_than = simplified()->NumberLessThan(); |
| 405 less_than_or_equal = simplified()->NumberLessThanOrEqual(); | 434 less_than_or_equal = simplified()->NumberLessThanOrEqual(); |
| 406 } | 435 } |
| 407 const Operator* comparison; | 436 const Operator* comparison; |
| 408 switch (node->opcode()) { | 437 switch (node->opcode()) { |
| 409 case IrOpcode::kJSLessThan: | 438 case IrOpcode::kJSLessThan: |
| 410 comparison = less_than; | 439 comparison = less_than; |
| 411 break; | 440 break; |
| 412 case IrOpcode::kJSGreaterThan: | 441 case IrOpcode::kJSGreaterThan: |
| 413 comparison = less_than; | 442 comparison = less_than; |
| (...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 588 DCHECK(!NodeProperties::GetBounds(input).upper->Is(Type::Number())); | 617 DCHECK(!NodeProperties::GetBounds(input).upper->Is(Type::Number())); |
| 589 RelaxEffectsAndControls(node); | 618 RelaxEffectsAndControls(node); |
| 590 node->set_op(common()->Phi(kMachAnyTagged, input_count)); | 619 node->set_op(common()->Phi(kMachAnyTagged, input_count)); |
| 591 for (int i = 0; i < input_count; ++i) { | 620 for (int i = 0; i < input_count; ++i) { |
| 592 // We must be very careful not to introduce cycles when pushing | 621 // We must be very careful not to introduce cycles when pushing |
| 593 // operations into phis. It is safe for {value}, since it appears | 622 // operations into phis. It is safe for {value}, since it appears |
| 594 // as input to the phi that we are replacing, but it's not safe | 623 // as input to the phi that we are replacing, but it's not safe |
| 595 // to simply reuse the context of the {node}. However, ToNumber() | 624 // to simply reuse the context of the {node}. However, ToNumber() |
| 596 // does not require a context anyways, so it's safe to discard it | 625 // does not require a context anyways, so it's safe to discard it |
| 597 // here and pass the dummy context. | 626 // here and pass the dummy context. |
| 598 Node* const value = ConvertToNumber(input->InputAt(i)); | 627 Node* const value = ConvertPrimitiveToNumber(input->InputAt(i)); |
| 599 if (i < node->InputCount()) { | 628 if (i < node->InputCount()) { |
| 600 node->ReplaceInput(i, value); | 629 node->ReplaceInput(i, value); |
| 601 } else { | 630 } else { |
| 602 node->AppendInput(graph()->zone(), value); | 631 node->AppendInput(graph()->zone(), value); |
| 603 } | 632 } |
| 604 } | 633 } |
| 605 if (input_count < node->InputCount()) { | 634 if (input_count < node->InputCount()) { |
| 606 node->ReplaceInput(input_count, control); | 635 node->ReplaceInput(input_count, control); |
| 607 } else { | 636 } else { |
| 608 node->AppendInput(graph()->zone(), control); | 637 node->AppendInput(graph()->zone(), control); |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 621 RelaxEffectsAndControls(node); | 650 RelaxEffectsAndControls(node); |
| 622 node->set_op(common()->Select(kMachAnyTagged, input_hint)); | 651 node->set_op(common()->Select(kMachAnyTagged, input_hint)); |
| 623 node->ReplaceInput(0, input->InputAt(0)); | 652 node->ReplaceInput(0, input->InputAt(0)); |
| 624 for (int i = 1; i < input_count; ++i) { | 653 for (int i = 1; i < input_count; ++i) { |
| 625 // We must be very careful not to introduce cycles when pushing | 654 // We must be very careful not to introduce cycles when pushing |
| 626 // operations into selects. It is safe for {value}, since it appears | 655 // operations into selects. It is safe for {value}, since it appears |
| 627 // as input to the select that we are replacing, but it's not safe | 656 // as input to the select that we are replacing, but it's not safe |
| 628 // to simply reuse the context of the {node}. However, ToNumber() | 657 // to simply reuse the context of the {node}. However, ToNumber() |
| 629 // does not require a context anyways, so it's safe to discard it | 658 // does not require a context anyways, so it's safe to discard it |
| 630 // here and pass the dummy context. | 659 // here and pass the dummy context. |
| 631 Node* const value = ConvertToNumber(input->InputAt(i)); | 660 Node* const value = ConvertPrimitiveToNumber(input->InputAt(i)); |
| 632 node->ReplaceInput(i, value); | 661 node->ReplaceInput(i, value); |
| 633 } | 662 } |
| 634 node->TrimInputCount(input_count); | 663 node->TrimInputCount(input_count); |
| 635 return Changed(node); | 664 return Changed(node); |
| 636 } | 665 } |
| 637 // Remember this conversion. | 666 // Remember this conversion. |
| 638 InsertConversion(node); | 667 InsertConversion(node); |
| 639 if (NodeProperties::GetContextInput(node) != | 668 if (NodeProperties::GetContextInput(node) != |
| 640 jsgraph()->NoContextConstant() || | 669 jsgraph()->NoContextConstant() || |
| 641 NodeProperties::GetEffectInput(node) != graph()->start() || | 670 NodeProperties::GetEffectInput(node) != graph()->start() || |
| (...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 904 case IrOpcode::kJSStrictEqual: | 933 case IrOpcode::kJSStrictEqual: |
| 905 return ReduceJSStrictEqual(node, false); | 934 return ReduceJSStrictEqual(node, false); |
| 906 case IrOpcode::kJSStrictNotEqual: | 935 case IrOpcode::kJSStrictNotEqual: |
| 907 return ReduceJSStrictEqual(node, true); | 936 return ReduceJSStrictEqual(node, true); |
| 908 case IrOpcode::kJSLessThan: // fall through | 937 case IrOpcode::kJSLessThan: // fall through |
| 909 case IrOpcode::kJSGreaterThan: // fall through | 938 case IrOpcode::kJSGreaterThan: // fall through |
| 910 case IrOpcode::kJSLessThanOrEqual: // fall through | 939 case IrOpcode::kJSLessThanOrEqual: // fall through |
| 911 case IrOpcode::kJSGreaterThanOrEqual: | 940 case IrOpcode::kJSGreaterThanOrEqual: |
| 912 return ReduceJSComparison(node); | 941 return ReduceJSComparison(node); |
| 913 case IrOpcode::kJSBitwiseOr: | 942 case IrOpcode::kJSBitwiseOr: |
| 914 return ReduceJSBitwiseOr(node); | 943 return ReduceInt32Binop(node, machine()->Word32Or()); |
| 915 case IrOpcode::kJSBitwiseXor: | 944 case IrOpcode::kJSBitwiseXor: |
| 916 return ReduceInt32Binop(node, machine()->Word32Xor()); | 945 return ReduceInt32Binop(node, machine()->Word32Xor()); |
| 917 case IrOpcode::kJSBitwiseAnd: | 946 case IrOpcode::kJSBitwiseAnd: |
| 918 return ReduceInt32Binop(node, machine()->Word32And()); | 947 return ReduceInt32Binop(node, machine()->Word32And()); |
| 919 case IrOpcode::kJSShiftLeft: | 948 case IrOpcode::kJSShiftLeft: |
| 920 return ReduceUI32Shift(node, kSigned, machine()->Word32Shl()); | 949 return ReduceUI32Shift(node, kSigned, machine()->Word32Shl()); |
| 921 case IrOpcode::kJSShiftRight: | 950 case IrOpcode::kJSShiftRight: |
| 922 return ReduceUI32Shift(node, kSigned, machine()->Word32Sar()); | 951 return ReduceUI32Shift(node, kSigned, machine()->Word32Sar()); |
| 923 case IrOpcode::kJSShiftRightLogical: | 952 case IrOpcode::kJSShiftRightLogical: |
| 924 return ReduceUI32Shift(node, kUnsigned, machine()->Word32Shr()); | 953 return ReduceUI32Shift(node, kUnsigned, machine()->Word32Shr()); |
| 925 case IrOpcode::kJSAdd: | 954 case IrOpcode::kJSAdd: |
| 926 return ReduceJSAdd(node); | 955 return ReduceJSAdd(node); |
| 927 case IrOpcode::kJSSubtract: | 956 case IrOpcode::kJSSubtract: |
| 928 return ReduceNumberBinop(node, simplified()->NumberSubtract()); | 957 return ReduceNumberBinop(node, simplified()->NumberSubtract()); |
| 929 case IrOpcode::kJSMultiply: | 958 case IrOpcode::kJSMultiply: |
| 930 return ReduceJSMultiply(node); | 959 return ReduceNumberBinop(node, simplified()->NumberMultiply()); |
| 931 case IrOpcode::kJSDivide: | 960 case IrOpcode::kJSDivide: |
| 932 return ReduceNumberBinop(node, simplified()->NumberDivide()); | 961 return ReduceNumberBinop(node, simplified()->NumberDivide()); |
| 933 case IrOpcode::kJSModulus: | 962 case IrOpcode::kJSModulus: |
| 934 return ReduceNumberBinop(node, simplified()->NumberModulus()); | 963 return ReduceNumberBinop(node, simplified()->NumberModulus()); |
| 935 case IrOpcode::kJSUnaryNot: | 964 case IrOpcode::kJSUnaryNot: |
| 936 return ReduceJSUnaryNot(node); | 965 return ReduceJSUnaryNot(node); |
| 937 case IrOpcode::kJSToBoolean: | 966 case IrOpcode::kJSToBoolean: |
| 938 return ReduceJSToBoolean(node); | 967 return ReduceJSToBoolean(node); |
| 939 case IrOpcode::kJSToNumber: | 968 case IrOpcode::kJSToNumber: |
| 940 return ReduceJSToNumber(node); | 969 return ReduceJSToNumber(node); |
| 941 case IrOpcode::kJSToString: | 970 case IrOpcode::kJSToString: |
| 942 return ReduceJSToString(node); | 971 return ReduceJSToString(node); |
| 943 case IrOpcode::kJSLoadProperty: | 972 case IrOpcode::kJSLoadProperty: |
| 944 return ReduceJSLoadProperty(node); | 973 return ReduceJSLoadProperty(node); |
| 945 case IrOpcode::kJSStoreProperty: | 974 case IrOpcode::kJSStoreProperty: |
| 946 return ReduceJSStoreProperty(node); | 975 return ReduceJSStoreProperty(node); |
| 947 case IrOpcode::kJSLoadContext: | 976 case IrOpcode::kJSLoadContext: |
| 948 return ReduceJSLoadContext(node); | 977 return ReduceJSLoadContext(node); |
| 949 case IrOpcode::kJSStoreContext: | 978 case IrOpcode::kJSStoreContext: |
| 950 return ReduceJSStoreContext(node); | 979 return ReduceJSStoreContext(node); |
| 951 default: | 980 default: |
| 952 break; | 981 break; |
| 953 } | 982 } |
| 954 return NoChange(); | 983 return NoChange(); |
| 955 } | 984 } |
| 956 | 985 |
| 957 | 986 |
| 958 Node* JSTypedLowering::ConvertToNumber(Node* input) { | 987 Node* JSTypedLowering::ConvertPrimitiveToNumber(Node* input) { |
| 959 DCHECK(NodeProperties::GetBounds(input).upper->Is(Type::PlainPrimitive())); | 988 DCHECK(NodeProperties::GetBounds(input).upper->Is(Type::PlainPrimitive())); |
| 960 // Avoid inserting too many eager ToNumber() operations. | 989 // Avoid inserting too many eager ToNumber() operations. |
| 961 Reduction const reduction = ReduceJSToNumberInput(input); | 990 Reduction const reduction = ReduceJSToNumberInput(input); |
| 962 if (reduction.Changed()) return reduction.replacement(); | 991 if (reduction.Changed()) return reduction.replacement(); |
| 963 // TODO(jarin) Use PlainPrimitiveToNumber once we have it. | 992 // TODO(jarin) Use PlainPrimitiveToNumber once we have it. |
| 964 Node* const conversion = | 993 Node* const conversion = |
| 965 FLAG_turbo_deoptimization | 994 FLAG_turbo_deoptimization |
| 966 ? graph()->NewNode(javascript()->ToNumber(), input, | 995 ? graph()->NewNode(javascript()->ToNumber(), input, |
| 967 jsgraph()->NoContextConstant(), | 996 jsgraph()->NoContextConstant(), |
| 968 jsgraph()->EmptyFrameState(), graph()->start(), | 997 jsgraph()->EmptyFrameState(), graph()->start(), |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1021 } | 1050 } |
| 1022 | 1051 |
| 1023 | 1052 |
| 1024 MachineOperatorBuilder* JSTypedLowering::machine() const { | 1053 MachineOperatorBuilder* JSTypedLowering::machine() const { |
| 1025 return jsgraph()->machine(); | 1054 return jsgraph()->machine(); |
| 1026 } | 1055 } |
| 1027 | 1056 |
| 1028 } // namespace compiler | 1057 } // namespace compiler |
| 1029 } // namespace internal | 1058 } // namespace internal |
| 1030 } // namespace v8 | 1059 } // namespace v8 |
| OLD | NEW |