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/common-operator.h" 6 #include "src/compiler/graph.h" 7 #include "src/compiler/js-operator.h" 8 #include "src/compiler/linkage.h" 9 #include "src/compiler/node-properties.h" 10 #include "src/compiler/operator-properties.h" 11 #include "src/compiler/verifier.h" 12 #include "src/handles-inl.h" 13 14 namespace v8 { 15 namespace internal { 16 namespace compiler { 17 18 // static 19 int NodeProperties::PastValueIndex(Node* node) { 20 return FirstValueIndex(node) + node->op()->ValueInputCount(); 21 } 22 23 24 // static 25 int NodeProperties::PastContextIndex(Node* node) { 26 return FirstContextIndex(node) + 27 OperatorProperties::GetContextInputCount(node->op()); 28 } 29 30 31 // static 32 int NodeProperties::PastFrameStateIndex(Node* node) { 33 return FirstFrameStateIndex(node) + 34 OperatorProperties::GetFrameStateInputCount(node->op()); 35 } 36 37 38 // static 39 int NodeProperties::PastEffectIndex(Node* node) { 40 return FirstEffectIndex(node) + node->op()->EffectInputCount(); 41 } 42 43 44 // static 45 int NodeProperties::PastControlIndex(Node* node) { 46 return FirstControlIndex(node) + node->op()->ControlInputCount(); 47 } 48 49 50 // static 51 Node* NodeProperties::GetValueInput(Node* node, int index) { 52 DCHECK(0 <= index && index < node->op()->ValueInputCount()); 53 return node->InputAt(FirstValueIndex(node) + index); 54 } 55 56 57 // static 58 Node* NodeProperties::GetContextInput(Node* node) { 59 DCHECK(OperatorProperties::HasContextInput(node->op())); 60 return node->InputAt(FirstContextIndex(node)); 61 } 62 63 64 // static 65 Node* NodeProperties::GetFrameStateInput(Node* node, int index) { 66 DCHECK_LT(index, OperatorProperties::GetFrameStateInputCount(node->op())); 67 return node->InputAt(FirstFrameStateIndex(node) + index); 68 } 69 70 71 // static 72 Node* NodeProperties::GetEffectInput(Node* node, int index) { 73 DCHECK(0 <= index && index < node->op()->EffectInputCount()); 74 return node->InputAt(FirstEffectIndex(node) + index); 75 } 76 77 78 // static 79 Node* NodeProperties::GetControlInput(Node* node, int index) { 80 DCHECK(0 <= index && index < node->op()->ControlInputCount()); 81 return node->InputAt(FirstControlIndex(node) + index); 82 } 83 84 85 // static 86 bool NodeProperties::IsValueEdge(Edge edge) { 87 Node* const node = edge.from(); 88 return IsInputRange(edge, FirstValueIndex(node), 89 node->op()->ValueInputCount()); 90 } 91 92 93 // static 94 bool NodeProperties::IsContextEdge(Edge edge) { 95 Node* const node = edge.from(); 96 return IsInputRange(edge, FirstContextIndex(node), 97 OperatorProperties::GetContextInputCount(node->op())); 98 } 99 100 101 // static 102 bool NodeProperties::IsFrameStateEdge(Edge edge) { 103 Node* const node = edge.from(); 104 return IsInputRange(edge, FirstFrameStateIndex(node), 105 OperatorProperties::GetFrameStateInputCount(node->op())); 106 } 107 108 109 // static 110 bool NodeProperties::IsEffectEdge(Edge edge) { 111 Node* const node = edge.from(); 112 return IsInputRange(edge, FirstEffectIndex(node), 113 node->op()->EffectInputCount()); 114 } 115 116 117 // static 118 bool NodeProperties::IsControlEdge(Edge edge) { 119 Node* const node = edge.from(); 120 return IsInputRange(edge, FirstControlIndex(node), 121 node->op()->ControlInputCount()); 122 } 123 124 125 // static 126 bool NodeProperties::IsExceptionalCall(Node* node) { 127 if (node->op()->HasProperty(Operator::kNoThrow)) return false; 128 for (Edge const edge : node->use_edges()) { 129 if (!NodeProperties::IsControlEdge(edge)) continue; 130 if (edge.from()->opcode() == IrOpcode::kIfException) return true; 131 } 132 return false; 133 } 134 135 136 // static 137 void NodeProperties::ReplaceValueInput(Node* node, Node* value, int index) { 138 DCHECK(index < node->op()->ValueInputCount()); 139 node->ReplaceInput(FirstValueIndex(node) + index, value); 140 } 141 142 143 // static 144 void NodeProperties::ReplaceValueInputs(Node* node, Node* value) { 145 int value_input_count = node->op()->ValueInputCount(); 146 DCHECK_LE(1, value_input_count); 147 node->ReplaceInput(0, value); 148 while (--value_input_count > 0) { 149 node->RemoveInput(value_input_count); 150 } 151 } 152 153 154 // static 155 void NodeProperties::ReplaceContextInput(Node* node, Node* context) { 156 node->ReplaceInput(FirstContextIndex(node), context); 157 } 158 159 160 // static 161 void NodeProperties::ReplaceControlInput(Node* node, Node* control, int index) { 162 DCHECK(index < node->op()->ControlInputCount()); 163 node->ReplaceInput(FirstControlIndex(node) + index, control); 164 } 165 166 167 // static 168 void NodeProperties::ReplaceEffectInput(Node* node, Node* effect, int index) { 169 DCHECK(index < node->op()->EffectInputCount()); 170 return node->ReplaceInput(FirstEffectIndex(node) + index, effect); 171 } 172 173 174 // static 175 void NodeProperties::ReplaceFrameStateInput(Node* node, int index, 176 Node* frame_state) { 177 DCHECK_LT(index, OperatorProperties::GetFrameStateInputCount(node->op())); 178 node->ReplaceInput(FirstFrameStateIndex(node) + index, frame_state); 179 } 180 181 182 // static 183 void NodeProperties::RemoveNonValueInputs(Node* node) { 184 node->TrimInputCount(node->op()->ValueInputCount()); 185 } 186 187 188 // static 189 void NodeProperties::RemoveValueInputs(Node* node) { 190 int value_input_count = node->op()->ValueInputCount(); 191 while (--value_input_count >= 0) { 192 node->RemoveInput(value_input_count); 193 } 194 } 195 196 197 void NodeProperties::MergeControlToEnd(Graph* graph, 198 CommonOperatorBuilder* common, 199 Node* node) { 200 graph->end()->AppendInput(graph->zone(), node); 201 graph->end()->set_op(common->End(graph->end()->InputCount())); 202 } 203 204 205 // static 206 void NodeProperties::ReplaceUses(Node* node, Node* value, Node* effect, 207 Node* success, Node* exception) { 208 // Requires distinguishing between value, effect and control edges. 209 for (Edge edge : node->use_edges()) { 210 if (IsControlEdge(edge)) { 211 if (edge.from()->opcode() == IrOpcode::kIfSuccess) { 212 DCHECK_NOT_NULL(success); 213 edge.UpdateTo(success); 214 } else if (edge.from()->opcode() == IrOpcode::kIfException) { 215 DCHECK_NOT_NULL(exception); 216 edge.UpdateTo(exception); 217 } else { 218 DCHECK_NOT_NULL(success); 219 edge.UpdateTo(success); 220 } 221 } else if (IsEffectEdge(edge)) { 222 DCHECK_NOT_NULL(effect); 223 edge.UpdateTo(effect); 224 } else { 225 DCHECK_NOT_NULL(value); 226 edge.UpdateTo(value); 227 } 228 } 229 } 230 231 232 // static 233 void NodeProperties::ChangeOp(Node* node, const Operator* new_op) { 234 node->set_op(new_op); 235 Verifier::VerifyNode(node); 236 } 237 238 239 // static 240 Node* NodeProperties::FindFrameStateBefore(Node* node) { 241 Node* effect = NodeProperties::GetEffectInput(node); 242 while (effect->opcode() != IrOpcode::kCheckpoint) { 243 if (effect->opcode() == IrOpcode::kDead) return effect; 244 DCHECK_EQ(1, effect->op()->EffectInputCount()); 245 effect = NodeProperties::GetEffectInput(effect); 246 } 247 Node* frame_state = GetFrameStateInput(effect, 0); 248 return frame_state; 249 } 250 251 // static 252 Node* NodeProperties::FindProjection(Node* node, size_t projection_index) { 253 for (auto use : node->uses()) { 254 if (use->opcode() == IrOpcode::kProjection && 255 ProjectionIndexOf(use->op()) == projection_index) { 256 return use; 257 } 258 } 259 return nullptr; 260 } 261 262 263 // static 264 void NodeProperties::CollectControlProjections(Node* node, Node** projections, 265 size_t projection_count) { 266 #ifdef DEBUG 267 DCHECK_LE(static_cast<int>(projection_count), node->UseCount()); 268 std::memset(projections, 0, sizeof(*projections) * projection_count); 269 #endif 270 size_t if_value_index = 0; 271 for (Edge const edge : node->use_edges()) { 272 if (!IsControlEdge(edge)) continue; 273 Node* use = edge.from(); 274 size_t index; 275 switch (use->opcode()) { 276 case IrOpcode::kIfTrue: 277 DCHECK_EQ(IrOpcode::kBranch, node->opcode()); 278 index = 0; 279 break; 280 case IrOpcode::kIfFalse: 281 DCHECK_EQ(IrOpcode::kBranch, node->opcode()); 282 index = 1; 283 break; 284 case IrOpcode::kIfSuccess: 285 DCHECK(!node->op()->HasProperty(Operator::kNoThrow)); 286 index = 0; 287 break; 288 case IrOpcode::kIfException: 289 DCHECK(!node->op()->HasProperty(Operator::kNoThrow)); 290 index = 1; 291 break; 292 case IrOpcode::kIfValue: 293 DCHECK_EQ(IrOpcode::kSwitch, node->opcode()); 294 index = if_value_index++; 295 break; 296 case IrOpcode::kIfDefault: 297 DCHECK_EQ(IrOpcode::kSwitch, node->opcode()); 298 index = projection_count - 1; 299 break; 300 default: 301 continue; 302 } 303 DCHECK_LT(if_value_index, projection_count); 304 DCHECK_LT(index, projection_count); 305 DCHECK_NULL(projections[index]); 306 projections[index] = use; 307 } 308 #ifdef DEBUG 309 for (size_t index = 0; index < projection_count; ++index) { 310 DCHECK_NOT_NULL(projections[index]); 311 } 312 #endif 313 } 314 315 316 // static 317 MaybeHandle<Context> NodeProperties::GetSpecializationContext( 318 Node* node, MaybeHandle<Context> context) { 319 switch (node->opcode()) { 320 case IrOpcode::kHeapConstant: 321 return Handle<Context>::cast(OpParameter<Handle<HeapObject>>(node)); 322 case IrOpcode::kParameter: { 323 Node* const start = NodeProperties::GetValueInput(node, 0); 324 DCHECK_EQ(IrOpcode::kStart, start->opcode()); 325 int const index = ParameterIndexOf(node->op()); 326 // The context is always the last parameter to a JavaScript function, and 327 // {Parameter} indices start at -1, so value outputs of {Start} look like 328 // this: closure, receiver, param0, ..., paramN, context. 329 if (index == start->op()->ValueOutputCount() - 2) { 330 return context; 331 } 332 break; 333 } 334 default: 335 break; 336 } 337 return MaybeHandle<Context>(); 338 } 339 340 341 // static 342 MaybeHandle<Context> NodeProperties::GetSpecializationNativeContext( 343 Node* node, MaybeHandle<Context> native_context) { 344 while (true) { 345 switch (node->opcode()) { 346 case IrOpcode::kJSLoadContext: { 347 ContextAccess const& access = ContextAccessOf(node->op()); 348 if (access.index() != Context::NATIVE_CONTEXT_INDEX) { 349 return MaybeHandle<Context>(); 350 } 351 // Skip over the intermediate contexts, we're only interested in the 352 // very last context in the context chain anyway. 353 node = NodeProperties::GetContextInput(node); 354 break; 355 } 356 case IrOpcode::kJSCreateBlockContext: 357 case IrOpcode::kJSCreateCatchContext: 358 case IrOpcode::kJSCreateFunctionContext: 359 case IrOpcode::kJSCreateModuleContext: 360 case IrOpcode::kJSCreateScriptContext: 361 case IrOpcode::kJSCreateWithContext: { 362 // Skip over the intermediate contexts, we're only interested in the 363 // very last context in the context chain anyway. 364 node = NodeProperties::GetContextInput(node); 365 break; 366 } 367 case IrOpcode::kHeapConstant: { 368 // Extract the native context from the actual {context}. 369 Handle<Context> context = 370 Handle<Context>::cast(OpParameter<Handle<HeapObject>>(node)); 371 return handle(context->native_context()); 372 } 373 case IrOpcode::kOsrValue: { 374 int const index = OpParameter<int>(node); 375 if (index == Linkage::kOsrContextSpillSlotIndex) { 376 return native_context; 377 } 378 return MaybeHandle<Context>(); 379 } 380 case IrOpcode::kParameter: { 381 Node* const start = NodeProperties::GetValueInput(node, 0); 382 DCHECK_EQ(IrOpcode::kStart, start->opcode()); 383 int const index = ParameterIndexOf(node->op()); 384 // The context is always the last parameter to a JavaScript function, 385 // and {Parameter} indices start at -1, so value outputs of {Start} 386 // look like this: closure, receiver, param0, ..., paramN, context. 387 if (index == start->op()->ValueOutputCount() - 2) { 388 return native_context; 389 } 390 return MaybeHandle<Context>(); 391 } 392 default: 393 return MaybeHandle<Context>(); 394 } 395 } 396 } 397 398 399 // static 400 MaybeHandle<JSGlobalObject> NodeProperties::GetSpecializationGlobalObject( 401 Node* node, MaybeHandle<Context> native_context) { 402 Handle<Context> context; 403 if (GetSpecializationNativeContext(node, native_context).ToHandle(&context)) { 404 return handle(context->global_object()); 405 } 406 return MaybeHandle<JSGlobalObject>(); 407 } 408 409 410 // static 411 Type* NodeProperties::GetTypeOrAny(Node* node) { 412 return IsTyped(node) ? node->type() : Type::Any(); 413 } 414 415 416 // static 417 bool NodeProperties::AllValueInputsAreTyped(Node* node) { 418 int input_count = node->op()->ValueInputCount(); 419 for (int index = 0; index < input_count; ++index) { 420 if (!IsTyped(GetValueInput(node, index))) return false; 421 } 422 return true; 423 } 424 425 426 // static 427 bool NodeProperties::IsInputRange(Edge edge, int first, int num) { 428 if (num == 0) return false; 429 int const index = edge.index(); 430 return first <= index && index < first + num; 431 } 432 433 } // namespace compiler 434 } // namespace internal 435 } // namespace v8 436