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 3 // found in the LICENSE file. 4 5 #include "src/compiler/js-intrinsic-lowering.h" 6 7 #include <stack> 8 9 #include "src/code-factory.h" 10 #include "src/compiler/access-builder.h" 11 #include "src/compiler/js-graph.h" 12 #include "src/compiler/linkage.h" 13 #include "src/compiler/node-matchers.h" 14 #include "src/compiler/node-properties.h" 15 #include "src/compiler/operator-properties.h" 16 #include "src/counters.h" 17 #include "src/objects-inl.h" 18 19 namespace v8 { 20 namespace internal { 21 namespace compiler { 22 23 JSIntrinsicLowering::JSIntrinsicLowering(Editor* editor, JSGraph* jsgraph, 24 DeoptimizationMode mode) 25 : AdvancedReducer(editor), jsgraph_(jsgraph), mode_(mode) {} 26 27 Reduction JSIntrinsicLowering::Reduce(Node* node) { 28 if (node->opcode() != IrOpcode::kJSCallRuntime) return NoChange(); 29 const Runtime::Function* const f = 30 Runtime::FunctionForId(CallRuntimeParametersOf(node->op()).id()); 31 if (f->intrinsic_type != Runtime::IntrinsicType::INLINE) return NoChange(); 32 switch (f->function_id) { 33 case Runtime::kInlineCreateIterResultObject: 34 return ReduceCreateIterResultObject(node); 35 case Runtime::kInlineDebugIsActive: 36 return ReduceDebugIsActive(node); 37 case Runtime::kInlineDeoptimizeNow: 38 return ReduceDeoptimizeNow(node); 39 case Runtime::kInlineGeneratorClose: 40 return ReduceGeneratorClose(node); 41 case Runtime::kInlineGeneratorGetInputOrDebugPos: 42 return ReduceGeneratorGetInputOrDebugPos(node); 43 case Runtime::kInlineGeneratorGetResumeMode: 44 return ReduceGeneratorGetResumeMode(node); 45 case Runtime::kInlineGeneratorGetContext: 46 return ReduceGeneratorGetContext(node); 47 case Runtime::kInlineIsArray: 48 return ReduceIsInstanceType(node, JS_ARRAY_TYPE); 49 case Runtime::kInlineIsTypedArray: 50 return ReduceIsInstanceType(node, JS_TYPED_ARRAY_TYPE); 51 case Runtime::kInlineIsJSProxy: 52 return ReduceIsInstanceType(node, JS_PROXY_TYPE); 53 case Runtime::kInlineIsJSReceiver: 54 return ReduceIsJSReceiver(node); 55 case Runtime::kInlineIsSmi: 56 return ReduceIsSmi(node); 57 case Runtime::kInlineFixedArrayGet: 58 return ReduceFixedArrayGet(node); 59 case Runtime::kInlineFixedArraySet: 60 return ReduceFixedArraySet(node); 61 case Runtime::kInlineSubString: 62 return ReduceSubString(node); 63 case Runtime::kInlineToInteger: 64 return ReduceToInteger(node); 65 case Runtime::kInlineToLength: 66 return ReduceToLength(node); 67 case Runtime::kInlineToNumber: 68 return ReduceToNumber(node); 69 case Runtime::kInlineToObject: 70 return ReduceToObject(node); 71 case Runtime::kInlineToString: 72 return ReduceToString(node); 73 case Runtime::kInlineCall: 74 return ReduceCall(node); 75 case Runtime::kInlineGetSuperConstructor: 76 return ReduceGetSuperConstructor(node); 77 case Runtime::kInlineArrayBufferViewGetByteLength: 78 return ReduceArrayBufferViewField( 79 node, AccessBuilder::ForJSArrayBufferViewByteLength()); 80 case Runtime::kInlineArrayBufferViewGetByteOffset: 81 return ReduceArrayBufferViewField( 82 node, AccessBuilder::ForJSArrayBufferViewByteOffset()); 83 case Runtime::kInlineMaxSmi: 84 return ReduceMaxSmi(node); 85 case Runtime::kInlineTypedArrayGetLength: 86 return ReduceArrayBufferViewField(node, 87 AccessBuilder::ForJSTypedArrayLength()); 88 case Runtime::kInlineTypedArrayMaxSizeInHeap: 89 return ReduceTypedArrayMaxSizeInHeap(node); 90 case Runtime::kInlineJSCollectionGetTable: 91 return ReduceJSCollectionGetTable(node); 92 case Runtime::kInlineStringGetRawHashField: 93 return ReduceStringGetRawHashField(node); 94 case Runtime::kInlineTheHole: 95 return ReduceTheHole(node); 96 case Runtime::kInlineClassOf: 97 return ReduceClassOf(node); 98 default: 99 break; 100 } 101 return NoChange(); 102 } 103 104 105 Reduction JSIntrinsicLowering::ReduceCreateIterResultObject(Node* node) { 106 Node* const value = NodeProperties::GetValueInput(node, 0); 107 Node* const done = NodeProperties::GetValueInput(node, 1); 108 Node* const context = NodeProperties::GetContextInput(node); 109 Node* const effect = NodeProperties::GetEffectInput(node); 110 return Change(node, javascript()->CreateIterResultObject(), value, done, 111 context, effect); 112 } 113 114 Reduction JSIntrinsicLowering::ReduceDebugIsActive(Node* node) { 115 Node* const value = jsgraph()->ExternalConstant( 116 ExternalReference::debug_is_active_address(isolate())); 117 Node* const effect = NodeProperties::GetEffectInput(node); 118 Node* const control = NodeProperties::GetControlInput(node); 119 Operator const* const op = 120 simplified()->LoadField(AccessBuilder::ForExternalUint8Value()); 121 return Change(node, op, value, effect, control); 122 } 123 124 Reduction JSIntrinsicLowering::ReduceDeoptimizeNow(Node* node) { 125 if (mode() != kDeoptimizationEnabled) return NoChange(); 126 Node* const frame_state = NodeProperties::GetFrameStateInput(node); 127 Node* const effect = NodeProperties::GetEffectInput(node); 128 Node* const control = NodeProperties::GetControlInput(node); 129 130 // TODO(bmeurer): Move MergeControlToEnd() to the AdvancedReducer. 131 Node* deoptimize = graph()->NewNode( 132 common()->Deoptimize(DeoptimizeKind::kEager, DeoptimizeReason::kNoReason), 133 frame_state, effect, control); 134 NodeProperties::MergeControlToEnd(graph(), common(), deoptimize); 135 Revisit(graph()->end()); 136 137 node->TrimInputCount(0); 138 NodeProperties::ChangeOp(node, common()->Dead()); 139 return Changed(node); 140 } 141 142 Reduction JSIntrinsicLowering::ReduceGeneratorClose(Node* node) { 143 Node* const generator = NodeProperties::GetValueInput(node, 0); 144 Node* const effect = NodeProperties::GetEffectInput(node); 145 Node* const control = NodeProperties::GetControlInput(node); 146 Node* const closed = jsgraph()->Constant(JSGeneratorObject::kGeneratorClosed); 147 Node* const undefined = jsgraph()->UndefinedConstant(); 148 Operator const* const op = simplified()->StoreField( 149 AccessBuilder::ForJSGeneratorObjectContinuation()); 150 151 ReplaceWithValue(node, undefined, node); 152 NodeProperties::RemoveType(node); 153 return Change(node, op, generator, closed, effect, control); 154 } 155 156 Reduction JSIntrinsicLowering::ReduceGeneratorGetInputOrDebugPos(Node* node) { 157 Node* const generator = NodeProperties::GetValueInput(node, 0); 158 Node* const effect = NodeProperties::GetEffectInput(node); 159 Node* const control = NodeProperties::GetControlInput(node); 160 Operator const* const op = simplified()->LoadField( 161 AccessBuilder::ForJSGeneratorObjectInputOrDebugPos()); 162 163 return Change(node, op, generator, effect, control); 164 } 165 166 Reduction JSIntrinsicLowering::ReduceGeneratorGetContext(Node* node) { 167 Node* const generator = NodeProperties::GetValueInput(node, 0); 168 Node* const effect = NodeProperties::GetEffectInput(node); 169 Node* const control = NodeProperties::GetControlInput(node); 170 Operator const* const op = 171 simplified()->LoadField(AccessBuilder::ForJSGeneratorObjectContext()); 172 173 return Change(node, op, generator, effect, control); 174 } 175 176 Reduction JSIntrinsicLowering::ReduceGeneratorGetResumeMode(Node* node) { 177 Node* const generator = NodeProperties::GetValueInput(node, 0); 178 Node* const effect = NodeProperties::GetEffectInput(node); 179 Node* const control = NodeProperties::GetControlInput(node); 180 Operator const* const op = 181 simplified()->LoadField(AccessBuilder::ForJSGeneratorObjectResumeMode()); 182 183 return Change(node, op, generator, effect, control); 184 } 185 186 Reduction JSIntrinsicLowering::ReduceIsInstanceType( 187 Node* node, InstanceType instance_type) { 188 // if (%_IsSmi(value)) { 189 // return false; 190 // } else { 191 // return %_GetInstanceType(%_GetMap(value)) == instance_type; 192 // } 193 Node* value = NodeProperties::GetValueInput(node, 0); 194 Node* effect = NodeProperties::GetEffectInput(node); 195 Node* control = NodeProperties::GetControlInput(node); 196 197 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), value); 198 Node* branch = graph()->NewNode(common()->Branch(), check, control); 199 200 Node* if_true = graph()->NewNode(common()->IfTrue(), branch); 201 Node* etrue = effect; 202 Node* vtrue = jsgraph()->FalseConstant(); 203 204 Node* if_false = graph()->NewNode(common()->IfFalse(), branch); 205 Node* efalse = graph()->NewNode( 206 simplified()->LoadField(AccessBuilder::ForMapInstanceType()), 207 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), value, 208 effect, if_false), 209 effect, if_false); 210 Node* vfalse = graph()->NewNode(simplified()->NumberEqual(), efalse, 211 jsgraph()->Constant(instance_type)); 212 213 Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false); 214 215 // Replace all effect uses of {node} with the {ephi}. 216 Node* ephi = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, merge); 217 ReplaceWithValue(node, node, ephi); 218 219 // Turn the {node} into a Phi. 220 return Change(node, common()->Phi(MachineRepresentation::kTagged, 2), vtrue, 221 vfalse, merge); 222 } 223 224 225 Reduction JSIntrinsicLowering::ReduceIsJSReceiver(Node* node) { 226 return Change(node, simplified()->ObjectIsReceiver()); 227 } 228 229 230 Reduction JSIntrinsicLowering::ReduceIsSmi(Node* node) { 231 return Change(node, simplified()->ObjectIsSmi()); 232 } 233 234 235 Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op) { 236 // Replace all effect uses of {node} with the effect dependency. 237 RelaxEffectsAndControls(node); 238 // Remove the inputs corresponding to context, effect and control. 239 NodeProperties::RemoveNonValueInputs(node); 240 // Finally update the operator to the new one. 241 NodeProperties::ChangeOp(node, op); 242 return Changed(node); 243 } 244 245 246 Reduction JSIntrinsicLowering::ReduceFixedArrayGet(Node* node) { 247 Node* base = node->InputAt(0); 248 Node* index = node->InputAt(1); 249 Node* effect = NodeProperties::GetEffectInput(node); 250 Node* control = NodeProperties::GetControlInput(node); 251 return Change( 252 node, simplified()->LoadElement(AccessBuilder::ForFixedArrayElement()), 253 base, index, effect, control); 254 } 255 256 257 Reduction JSIntrinsicLowering::ReduceFixedArraySet(Node* node) { 258 Node* base = node->InputAt(0); 259 Node* index = node->InputAt(1); 260 Node* value = node->InputAt(2); 261 Node* effect = NodeProperties::GetEffectInput(node); 262 Node* control = NodeProperties::GetControlInput(node); 263 Node* store = (graph()->NewNode( 264 simplified()->StoreElement(AccessBuilder::ForFixedArrayElement()), base, 265 index, value, effect, control)); 266 ReplaceWithValue(node, value, store); 267 return Changed(store); 268 } 269 270 271 Reduction JSIntrinsicLowering::ReduceSubString(Node* node) { 272 return Change(node, CodeFactory::SubString(isolate()), 3); 273 } 274 275 276 Reduction JSIntrinsicLowering::ReduceToInteger(Node* node) { 277 NodeProperties::ChangeOp(node, javascript()->ToInteger()); 278 return Changed(node); 279 } 280 281 282 Reduction JSIntrinsicLowering::ReduceToNumber(Node* node) { 283 NodeProperties::ChangeOp(node, javascript()->ToNumber()); 284 return Changed(node); 285 } 286 287 288 Reduction JSIntrinsicLowering::ReduceToLength(Node* node) { 289 NodeProperties::ChangeOp(node, javascript()->ToLength()); 290 return Changed(node); 291 } 292 293 294 Reduction JSIntrinsicLowering::ReduceToObject(Node* node) { 295 NodeProperties::ChangeOp(node, javascript()->ToObject()); 296 return Changed(node); 297 } 298 299 300 Reduction JSIntrinsicLowering::ReduceToString(Node* node) { 301 NodeProperties::ChangeOp(node, javascript()->ToString()); 302 return Changed(node); 303 } 304 305 306 Reduction JSIntrinsicLowering::ReduceCall(Node* node) { 307 size_t const arity = CallRuntimeParametersOf(node->op()).arity(); 308 NodeProperties::ChangeOp( 309 node, 310 javascript()->Call(arity, 0.0f, VectorSlotPair(), 311 ConvertReceiverMode::kAny, TailCallMode::kDisallow)); 312 return Changed(node); 313 } 314 315 Reduction JSIntrinsicLowering::ReduceGetSuperConstructor(Node* node) { 316 Node* active_function = NodeProperties::GetValueInput(node, 0); 317 Node* effect = NodeProperties::GetEffectInput(node); 318 Node* control = NodeProperties::GetControlInput(node); 319 Node* active_function_map = effect = 320 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), 321 active_function, effect, control); 322 return Change(node, simplified()->LoadField(AccessBuilder::ForMapPrototype()), 323 active_function_map, effect, control); 324 } 325 326 Reduction JSIntrinsicLowering::ReduceArrayBufferViewField( 327 Node* node, FieldAccess const& access) { 328 Node* receiver = NodeProperties::GetValueInput(node, 0); 329 Node* effect = NodeProperties::GetEffectInput(node); 330 Node* control = NodeProperties::GetControlInput(node); 331 332 // Load the {receiver}s field. 333 Node* value = effect = graph()->NewNode(simplified()->LoadField(access), 334 receiver, effect, control); 335 336 // Check if the {receiver}s buffer was neutered. 337 Node* receiver_buffer = effect = graph()->NewNode( 338 simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()), 339 receiver, effect, control); 340 Node* check = effect = graph()->NewNode( 341 simplified()->ArrayBufferWasNeutered(), receiver_buffer, effect, control); 342 343 // Default to zero if the {receiver}s buffer was neutered. 344 value = graph()->NewNode( 345 common()->Select(MachineRepresentation::kTagged, BranchHint::kFalse), 346 check, jsgraph()->ZeroConstant(), value); 347 348 ReplaceWithValue(node, value, effect, control); 349 return Replace(value); 350 } 351 352 Reduction JSIntrinsicLowering::ReduceMaxSmi(Node* node) { 353 Node* value = jsgraph()->Constant(Smi::kMaxValue); 354 ReplaceWithValue(node, value); 355 return Replace(value); 356 } 357 358 Reduction JSIntrinsicLowering::ReduceTypedArrayMaxSizeInHeap(Node* node) { 359 Node* value = jsgraph()->Constant(FLAG_typed_array_max_size_in_heap); 360 ReplaceWithValue(node, value); 361 return Replace(value); 362 } 363 364 Reduction JSIntrinsicLowering::ReduceJSCollectionGetTable(Node* node) { 365 Node* collection = NodeProperties::GetValueInput(node, 0); 366 Node* effect = NodeProperties::GetEffectInput(node); 367 Node* control = NodeProperties::GetControlInput(node); 368 return Change(node, 369 simplified()->LoadField(AccessBuilder::ForJSCollectionTable()), 370 collection, effect, control); 371 } 372 373 Reduction JSIntrinsicLowering::ReduceStringGetRawHashField(Node* node) { 374 Node* string = NodeProperties::GetValueInput(node, 0); 375 Node* effect = NodeProperties::GetEffectInput(node); 376 Node* control = NodeProperties::GetControlInput(node); 377 return Change(node, 378 simplified()->LoadField(AccessBuilder::ForNameHashField()), 379 string, effect, control); 380 } 381 382 Reduction JSIntrinsicLowering::ReduceTheHole(Node* node) { 383 Node* value = jsgraph()->TheHoleConstant(); 384 ReplaceWithValue(node, value); 385 return Replace(value); 386 } 387 388 Reduction JSIntrinsicLowering::ReduceClassOf(Node* node) { 389 RelaxEffectsAndControls(node); 390 node->TrimInputCount(2); 391 NodeProperties::ChangeOp(node, javascript()->ClassOf()); 392 return Changed(node); 393 } 394 395 Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op, Node* a, 396 Node* b) { 397 RelaxControls(node); 398 node->ReplaceInput(0, a); 399 node->ReplaceInput(1, b); 400 node->TrimInputCount(2); 401 NodeProperties::ChangeOp(node, op); 402 return Changed(node); 403 } 404 405 406 Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op, Node* a, 407 Node* b, Node* c) { 408 RelaxControls(node); 409 node->ReplaceInput(0, a); 410 node->ReplaceInput(1, b); 411 node->ReplaceInput(2, c); 412 node->TrimInputCount(3); 413 NodeProperties::ChangeOp(node, op); 414 return Changed(node); 415 } 416 417 418 Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op, Node* a, 419 Node* b, Node* c, Node* d) { 420 RelaxControls(node); 421 node->ReplaceInput(0, a); 422 node->ReplaceInput(1, b); 423 node->ReplaceInput(2, c); 424 node->ReplaceInput(3, d); 425 node->TrimInputCount(4); 426 NodeProperties::ChangeOp(node, op); 427 return Changed(node); 428 } 429 430 431 Reduction JSIntrinsicLowering::Change(Node* node, Callable const& callable, 432 int stack_parameter_count) { 433 CallDescriptor const* const desc = Linkage::GetStubCallDescriptor( 434 isolate(), graph()->zone(), callable.descriptor(), stack_parameter_count, 435 CallDescriptor::kNeedsFrameState, node->op()->properties()); 436 node->InsertInput(graph()->zone(), 0, 437 jsgraph()->HeapConstant(callable.code())); 438 NodeProperties::ChangeOp(node, common()->Call(desc)); 439 return Changed(node); 440 } 441 442 443 Graph* JSIntrinsicLowering::graph() const { return jsgraph()->graph(); } 444 445 446 Isolate* JSIntrinsicLowering::isolate() const { return jsgraph()->isolate(); } 447 448 449 CommonOperatorBuilder* JSIntrinsicLowering::common() const { 450 return jsgraph()->common(); 451 } 452 453 JSOperatorBuilder* JSIntrinsicLowering::javascript() const { 454 return jsgraph_->javascript(); 455 } 456 457 SimplifiedOperatorBuilder* JSIntrinsicLowering::simplified() const { 458 return jsgraph()->simplified(); 459 } 460 461 } // namespace compiler 462 } // namespace internal 463 } // namespace v8 464