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) { 66 DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op())); 67 return node->InputAt(FirstFrameStateIndex(node)); 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, Node* frame_state) { 176 DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op())); 177 node->ReplaceInput(FirstFrameStateIndex(node), frame_state); 178 } 179 180 181 // static 182 void NodeProperties::RemoveNonValueInputs(Node* node) { 183 node->TrimInputCount(node->op()->ValueInputCount()); 184 } 185 186 187 // static 188 void NodeProperties::RemoveValueInputs(Node* node) { 189 int value_input_count = node->op()->ValueInputCount(); 190 while (--value_input_count >= 0) { 191 node->RemoveInput(value_input_count); 192 } 193 } 194 195 196 void NodeProperties::MergeControlToEnd(Graph* graph, 197 CommonOperatorBuilder* common, 198 Node* node) { 199 graph->end()->AppendInput(graph->zone(), node); 200 graph->end()->set_op(common->End(graph->end()->InputCount())); 201 } 202 203 204 // static 205 void NodeProperties::ReplaceUses(Node* node, Node* value, Node* effect, 206 Node* success, Node* exception) { 207 // Requires distinguishing between value, effect and control edges. 208 for (Edge edge : node->use_edges()) { 209 if (IsControlEdge(edge)) { 210 if (edge.from()->opcode() == IrOpcode::kIfSuccess) { 211 DCHECK_NOT_NULL(success); 212 edge.UpdateTo(success); 213 } else if (edge.from()->opcode() == IrOpcode::kIfException) { 214 DCHECK_NOT_NULL(exception); 215 edge.UpdateTo(exception); 216 } else { 217 DCHECK_NOT_NULL(success); 218 edge.UpdateTo(success); 219 } 220 } else if (IsEffectEdge(edge)) { 221 DCHECK_NOT_NULL(effect); 222 edge.UpdateTo(effect); 223 } else { 224 DCHECK_NOT_NULL(value); 225 edge.UpdateTo(value); 226 } 227 } 228 } 229 230 231 // static 232 void NodeProperties::ChangeOp(Node* node, const Operator* new_op) { 233 node->set_op(new_op); 234 Verifier::VerifyNode(node); 235 } 236 237 238 // static 239 Node* NodeProperties::FindFrameStateBefore(Node* node) { 240 Node* effect = NodeProperties::GetEffectInput(node); 241 while (effect->opcode() != IrOpcode::kCheckpoint) { 242 if (effect->opcode() == IrOpcode::kDead) return effect; 243 DCHECK_EQ(1, effect->op()->EffectInputCount()); 244 effect = NodeProperties::GetEffectInput(effect); 245 } 246 Node* frame_state = GetFrameStateInput(effect); 247 return frame_state; 248 } 249 250 // static 251 Node* NodeProperties::FindProjection(Node* node, size_t projection_index) { 252 for (auto use : node->uses()) { 253 if (use->opcode() == IrOpcode::kProjection && 254 ProjectionIndexOf(use->op()) == projection_index) { 255 return use; 256 } 257 } 258 return nullptr; 259 } 260 261 262 // static 263 void NodeProperties::CollectControlProjections(Node* node, Node** projections, 264 size_t projection_count) { 265 #ifdef DEBUG 266 DCHECK_LE(static_cast<int>(projection_count), node->UseCount()); 267 std::memset(projections, 0, sizeof(*projections) * projection_count); 268 #endif 269 size_t if_value_index = 0; 270 for (Edge const edge : node->use_edges()) { 271 if (!IsControlEdge(edge)) continue; 272 Node* use = edge.from(); 273 size_t index; 274 switch (use->opcode()) { 275 case IrOpcode::kIfTrue: 276 DCHECK_EQ(IrOpcode::kBranch, node->opcode()); 277 index = 0; 278 break; 279 case IrOpcode::kIfFalse: 280 DCHECK_EQ(IrOpcode::kBranch, node->opcode()); 281 index = 1; 282 break; 283 case IrOpcode::kIfSuccess: 284 DCHECK(!node->op()->HasProperty(Operator::kNoThrow)); 285 index = 0; 286 break; 287 case IrOpcode::kIfException: 288 DCHECK(!node->op()->HasProperty(Operator::kNoThrow)); 289 index = 1; 290 break; 291 case IrOpcode::kIfValue: 292 DCHECK_EQ(IrOpcode::kSwitch, node->opcode()); 293 index = if_value_index++; 294 break; 295 case IrOpcode::kIfDefault: 296 DCHECK_EQ(IrOpcode::kSwitch, node->opcode()); 297 index = projection_count - 1; 298 break; 299 default: 300 continue; 301 } 302 DCHECK_LT(if_value_index, projection_count); 303 DCHECK_LT(index, projection_count); 304 DCHECK_NULL(projections[index]); 305 projections[index] = use; 306 } 307 #ifdef DEBUG 308 for (size_t index = 0; index < projection_count; ++index) { 309 DCHECK_NOT_NULL(projections[index]); 310 } 311 #endif 312 } 313 314 315 // static 316 MaybeHandle<Context> NodeProperties::GetSpecializationContext( 317 Node* node, MaybeHandle<Context> context) { 318 switch (node->opcode()) { 319 case IrOpcode::kHeapConstant: 320 return Handle<Context>::cast(OpParameter<Handle<HeapObject>>(node)); 321 case IrOpcode::kParameter: { 322 Node* const start = NodeProperties::GetValueInput(node, 0); 323 DCHECK_EQ(IrOpcode::kStart, start->opcode()); 324 int const index = ParameterIndexOf(node->op()); 325 // The context is always the last parameter to a JavaScript function, and 326 // {Parameter} indices start at -1, so value outputs of {Start} look like 327 // this: closure, receiver, param0, ..., paramN, context. 328 if (index == start->op()->ValueOutputCount() - 2) { 329 return context; 330 } 331 break; 332 } 333 default: 334 break; 335 } 336 return MaybeHandle<Context>(); 337 } 338 339 340 // static 341 Type* NodeProperties::GetTypeOrAny(Node* node) { 342 return IsTyped(node) ? node->type() : Type::Any(); 343 } 344 345 346 // static 347 bool NodeProperties::AllValueInputsAreTyped(Node* node) { 348 int input_count = node->op()->ValueInputCount(); 349 for (int index = 0; index < input_count; ++index) { 350 if (!IsTyped(GetValueInput(node, index))) return false; 351 } 352 return true; 353 } 354 355 356 // static 357 bool NodeProperties::IsInputRange(Edge edge, int first, int num) { 358 if (num == 0) return false; 359 int const index = edge.index(); 360 return first <= index && index < first + num; 361 } 362 363 } // namespace compiler 364 } // namespace internal 365 } // namespace v8 366