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 19namespace v8 { 20namespace internal { 21namespace compiler { 22 23JSIntrinsicLowering::JSIntrinsicLowering(Editor* editor, JSGraph* jsgraph, 24 DeoptimizationMode mode) 25 : AdvancedReducer(editor), jsgraph_(jsgraph), mode_(mode) {} 26 27Reduction 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::kInlineDeoptimizeNow: 36 return ReduceDeoptimizeNow(node); 37 case Runtime::kInlineGeneratorClose: 38 return ReduceGeneratorClose(node); 39 case Runtime::kInlineGeneratorGetInputOrDebugPos: 40 return ReduceGeneratorGetInputOrDebugPos(node); 41 case Runtime::kInlineGeneratorGetResumeMode: 42 return ReduceGeneratorGetResumeMode(node); 43 case Runtime::kInlineIsArray: 44 return ReduceIsInstanceType(node, JS_ARRAY_TYPE); 45 case Runtime::kInlineIsTypedArray: 46 return ReduceIsInstanceType(node, JS_TYPED_ARRAY_TYPE); 47 case Runtime::kInlineIsRegExp: 48 return ReduceIsInstanceType(node, JS_REGEXP_TYPE); 49 case Runtime::kInlineIsJSReceiver: 50 return ReduceIsJSReceiver(node); 51 case Runtime::kInlineIsSmi: 52 return ReduceIsSmi(node); 53 case Runtime::kInlineFixedArrayGet: 54 return ReduceFixedArrayGet(node); 55 case Runtime::kInlineFixedArraySet: 56 return ReduceFixedArraySet(node); 57 case Runtime::kInlineRegExpExec: 58 return ReduceRegExpExec(node); 59 case Runtime::kInlineSubString: 60 return ReduceSubString(node); 61 case Runtime::kInlineToInteger: 62 return ReduceToInteger(node); 63 case Runtime::kInlineToLength: 64 return ReduceToLength(node); 65 case Runtime::kInlineToNumber: 66 return ReduceToNumber(node); 67 case Runtime::kInlineToObject: 68 return ReduceToObject(node); 69 case Runtime::kInlineToString: 70 return ReduceToString(node); 71 case Runtime::kInlineCall: 72 return ReduceCall(node); 73 case Runtime::kInlineNewObject: 74 return ReduceNewObject(node); 75 case Runtime::kInlineGetSuperConstructor: 76 return ReduceGetSuperConstructor(node); 77 default: 78 break; 79 } 80 return NoChange(); 81} 82 83 84Reduction JSIntrinsicLowering::ReduceCreateIterResultObject(Node* node) { 85 Node* const value = NodeProperties::GetValueInput(node, 0); 86 Node* const done = NodeProperties::GetValueInput(node, 1); 87 Node* const context = NodeProperties::GetContextInput(node); 88 Node* const effect = NodeProperties::GetEffectInput(node); 89 return Change(node, javascript()->CreateIterResultObject(), value, done, 90 context, effect); 91} 92 93 94Reduction JSIntrinsicLowering::ReduceDeoptimizeNow(Node* node) { 95 if (mode() != kDeoptimizationEnabled) return NoChange(); 96 Node* const frame_state = NodeProperties::GetFrameStateInput(node); 97 Node* const effect = NodeProperties::GetEffectInput(node); 98 Node* const control = NodeProperties::GetControlInput(node); 99 100 // TODO(bmeurer): Move MergeControlToEnd() to the AdvancedReducer. 101 Node* deoptimize = graph()->NewNode( 102 common()->Deoptimize(DeoptimizeKind::kEager, DeoptimizeReason::kNoReason), 103 frame_state, effect, control); 104 NodeProperties::MergeControlToEnd(graph(), common(), deoptimize); 105 Revisit(graph()->end()); 106 107 node->TrimInputCount(0); 108 NodeProperties::ChangeOp(node, common()->Dead()); 109 return Changed(node); 110} 111 112Reduction JSIntrinsicLowering::ReduceGeneratorClose(Node* node) { 113 Node* const generator = NodeProperties::GetValueInput(node, 0); 114 Node* const effect = NodeProperties::GetEffectInput(node); 115 Node* const control = NodeProperties::GetControlInput(node); 116 Node* const closed = jsgraph()->Constant(JSGeneratorObject::kGeneratorClosed); 117 Node* const undefined = jsgraph()->UndefinedConstant(); 118 Operator const* const op = simplified()->StoreField( 119 AccessBuilder::ForJSGeneratorObjectContinuation()); 120 121 ReplaceWithValue(node, undefined, node); 122 NodeProperties::RemoveType(node); 123 return Change(node, op, generator, closed, effect, control); 124} 125 126Reduction JSIntrinsicLowering::ReduceGeneratorGetInputOrDebugPos(Node* node) { 127 Node* const generator = NodeProperties::GetValueInput(node, 0); 128 Node* const effect = NodeProperties::GetEffectInput(node); 129 Node* const control = NodeProperties::GetControlInput(node); 130 Operator const* const op = simplified()->LoadField( 131 AccessBuilder::ForJSGeneratorObjectInputOrDebugPos()); 132 133 return Change(node, op, generator, effect, control); 134} 135 136Reduction JSIntrinsicLowering::ReduceGeneratorGetResumeMode(Node* node) { 137 Node* const generator = NodeProperties::GetValueInput(node, 0); 138 Node* const effect = NodeProperties::GetEffectInput(node); 139 Node* const control = NodeProperties::GetControlInput(node); 140 Operator const* const op = 141 simplified()->LoadField(AccessBuilder::ForJSGeneratorObjectResumeMode()); 142 143 return Change(node, op, generator, effect, control); 144} 145 146Reduction JSIntrinsicLowering::ReduceIsInstanceType( 147 Node* node, InstanceType instance_type) { 148 // if (%_IsSmi(value)) { 149 // return false; 150 // } else { 151 // return %_GetInstanceType(%_GetMap(value)) == instance_type; 152 // } 153 Node* value = NodeProperties::GetValueInput(node, 0); 154 Node* effect = NodeProperties::GetEffectInput(node); 155 Node* control = NodeProperties::GetControlInput(node); 156 157 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), value); 158 Node* branch = graph()->NewNode(common()->Branch(), check, control); 159 160 Node* if_true = graph()->NewNode(common()->IfTrue(), branch); 161 Node* etrue = effect; 162 Node* vtrue = jsgraph()->FalseConstant(); 163 164 Node* if_false = graph()->NewNode(common()->IfFalse(), branch); 165 Node* efalse = graph()->NewNode( 166 simplified()->LoadField(AccessBuilder::ForMapInstanceType()), 167 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), value, 168 effect, if_false), 169 effect, if_false); 170 Node* vfalse = graph()->NewNode(simplified()->NumberEqual(), efalse, 171 jsgraph()->Constant(instance_type)); 172 173 Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false); 174 175 // Replace all effect uses of {node} with the {ephi}. 176 Node* ephi = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, merge); 177 ReplaceWithValue(node, node, ephi); 178 179 // Turn the {node} into a Phi. 180 return Change(node, common()->Phi(MachineRepresentation::kTagged, 2), vtrue, 181 vfalse, merge); 182} 183 184 185Reduction JSIntrinsicLowering::ReduceIsJSReceiver(Node* node) { 186 return Change(node, simplified()->ObjectIsReceiver()); 187} 188 189 190Reduction JSIntrinsicLowering::ReduceIsSmi(Node* node) { 191 return Change(node, simplified()->ObjectIsSmi()); 192} 193 194 195Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op) { 196 // Replace all effect uses of {node} with the effect dependency. 197 RelaxEffectsAndControls(node); 198 // Remove the inputs corresponding to context, effect and control. 199 NodeProperties::RemoveNonValueInputs(node); 200 // Finally update the operator to the new one. 201 NodeProperties::ChangeOp(node, op); 202 return Changed(node); 203} 204 205 206Reduction JSIntrinsicLowering::ReduceFixedArrayGet(Node* node) { 207 Node* base = node->InputAt(0); 208 Node* index = node->InputAt(1); 209 Node* effect = NodeProperties::GetEffectInput(node); 210 Node* control = NodeProperties::GetControlInput(node); 211 return Change( 212 node, simplified()->LoadElement(AccessBuilder::ForFixedArrayElement()), 213 base, index, effect, control); 214} 215 216 217Reduction JSIntrinsicLowering::ReduceFixedArraySet(Node* node) { 218 Node* base = node->InputAt(0); 219 Node* index = node->InputAt(1); 220 Node* value = node->InputAt(2); 221 Node* effect = NodeProperties::GetEffectInput(node); 222 Node* control = NodeProperties::GetControlInput(node); 223 Node* store = (graph()->NewNode( 224 simplified()->StoreElement(AccessBuilder::ForFixedArrayElement()), base, 225 index, value, effect, control)); 226 ReplaceWithValue(node, value, store); 227 return Changed(store); 228} 229 230 231Reduction JSIntrinsicLowering::ReduceRegExpExec(Node* node) { 232 return Change(node, CodeFactory::RegExpExec(isolate()), 4); 233} 234 235 236Reduction JSIntrinsicLowering::ReduceSubString(Node* node) { 237 return Change(node, CodeFactory::SubString(isolate()), 3); 238} 239 240 241Reduction JSIntrinsicLowering::ReduceToInteger(Node* node) { 242 NodeProperties::ChangeOp(node, javascript()->ToInteger()); 243 return Changed(node); 244} 245 246 247Reduction JSIntrinsicLowering::ReduceToNumber(Node* node) { 248 NodeProperties::ChangeOp(node, javascript()->ToNumber()); 249 return Changed(node); 250} 251 252 253Reduction JSIntrinsicLowering::ReduceToLength(Node* node) { 254 NodeProperties::ChangeOp(node, javascript()->ToLength()); 255 return Changed(node); 256} 257 258 259Reduction JSIntrinsicLowering::ReduceToObject(Node* node) { 260 NodeProperties::ChangeOp(node, javascript()->ToObject()); 261 return Changed(node); 262} 263 264 265Reduction JSIntrinsicLowering::ReduceToString(Node* node) { 266 NodeProperties::ChangeOp(node, javascript()->ToString()); 267 return Changed(node); 268} 269 270 271Reduction JSIntrinsicLowering::ReduceCall(Node* node) { 272 size_t const arity = CallRuntimeParametersOf(node->op()).arity(); 273 NodeProperties::ChangeOp( 274 node, javascript()->CallFunction(arity, 0.0f, VectorSlotPair(), 275 ConvertReceiverMode::kAny, 276 TailCallMode::kDisallow)); 277 return Changed(node); 278} 279 280Reduction JSIntrinsicLowering::ReduceNewObject(Node* node) { 281 return Change(node, CodeFactory::FastNewObject(isolate()), 0); 282} 283 284Reduction JSIntrinsicLowering::ReduceGetSuperConstructor(Node* node) { 285 Node* active_function = NodeProperties::GetValueInput(node, 0); 286 Node* effect = NodeProperties::GetEffectInput(node); 287 Node* control = NodeProperties::GetControlInput(node); 288 Node* active_function_map = effect = 289 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), 290 active_function, effect, control); 291 return Change(node, simplified()->LoadField(AccessBuilder::ForMapPrototype()), 292 active_function_map, effect, control); 293} 294 295Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op, Node* a, 296 Node* b) { 297 RelaxControls(node); 298 node->ReplaceInput(0, a); 299 node->ReplaceInput(1, b); 300 node->TrimInputCount(2); 301 NodeProperties::ChangeOp(node, op); 302 return Changed(node); 303} 304 305 306Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op, Node* a, 307 Node* b, Node* c) { 308 RelaxControls(node); 309 node->ReplaceInput(0, a); 310 node->ReplaceInput(1, b); 311 node->ReplaceInput(2, c); 312 node->TrimInputCount(3); 313 NodeProperties::ChangeOp(node, op); 314 return Changed(node); 315} 316 317 318Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op, Node* a, 319 Node* b, Node* c, Node* d) { 320 RelaxControls(node); 321 node->ReplaceInput(0, a); 322 node->ReplaceInput(1, b); 323 node->ReplaceInput(2, c); 324 node->ReplaceInput(3, d); 325 node->TrimInputCount(4); 326 NodeProperties::ChangeOp(node, op); 327 return Changed(node); 328} 329 330 331Reduction JSIntrinsicLowering::Change(Node* node, Callable const& callable, 332 int stack_parameter_count) { 333 CallDescriptor const* const desc = Linkage::GetStubCallDescriptor( 334 isolate(), graph()->zone(), callable.descriptor(), stack_parameter_count, 335 CallDescriptor::kNeedsFrameState, node->op()->properties()); 336 node->InsertInput(graph()->zone(), 0, 337 jsgraph()->HeapConstant(callable.code())); 338 NodeProperties::ChangeOp(node, common()->Call(desc)); 339 return Changed(node); 340} 341 342 343Graph* JSIntrinsicLowering::graph() const { return jsgraph()->graph(); } 344 345 346Isolate* JSIntrinsicLowering::isolate() const { return jsgraph()->isolate(); } 347 348 349CommonOperatorBuilder* JSIntrinsicLowering::common() const { 350 return jsgraph()->common(); 351} 352 353JSOperatorBuilder* JSIntrinsicLowering::javascript() const { 354 return jsgraph_->javascript(); 355} 356 357SimplifiedOperatorBuilder* JSIntrinsicLowering::simplified() const { 358 return jsgraph()->simplified(); 359} 360 361} // namespace compiler 362} // namespace internal 363} // namespace v8 364