1 // Copyright 2016 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-create-lowering.h" 6 7 #include "src/allocation-site-scopes.h" 8 #include "src/code-factory.h" 9 #include "src/compilation-dependencies.h" 10 #include "src/compiler/access-builder.h" 11 #include "src/compiler/common-operator.h" 12 #include "src/compiler/js-graph.h" 13 #include "src/compiler/js-operator.h" 14 #include "src/compiler/linkage.h" 15 #include "src/compiler/node-properties.h" 16 #include "src/compiler/node.h" 17 #include "src/compiler/operator-properties.h" 18 #include "src/compiler/simplified-operator.h" 19 #include "src/compiler/state-values-utils.h" 20 #include "src/objects-inl.h" 21 22 namespace v8 { 23 namespace internal { 24 namespace compiler { 25 26 namespace { 27 28 // A helper class to construct inline allocations on the simplified operator 29 // level. This keeps track of the effect chain for initial stores on a newly 30 // allocated object and also provides helpers for commonly allocated objects. 31 class AllocationBuilder final { 32 public: 33 AllocationBuilder(JSGraph* jsgraph, Node* effect, Node* control) 34 : jsgraph_(jsgraph), 35 allocation_(nullptr), 36 effect_(effect), 37 control_(control) {} 38 39 // Primitive allocation of static size. 40 void Allocate(int size, PretenureFlag pretenure = NOT_TENURED, 41 Type* type = Type::Any()) { 42 DCHECK_LE(size, kMaxRegularHeapObjectSize); 43 effect_ = graph()->NewNode( 44 common()->BeginRegion(RegionObservability::kNotObservable), effect_); 45 allocation_ = 46 graph()->NewNode(simplified()->Allocate(pretenure), 47 jsgraph()->Constant(size), effect_, control_); 48 // TODO(turbofan): Maybe we should put the Type* onto the Allocate operator 49 // at some point, or maybe we should have a completely differnt story. 50 NodeProperties::SetType(allocation_, type); 51 effect_ = allocation_; 52 } 53 54 // Primitive store into a field. 55 void Store(const FieldAccess& access, Node* value) { 56 effect_ = graph()->NewNode(simplified()->StoreField(access), allocation_, 57 value, effect_, control_); 58 } 59 60 // Primitive store into an element. 61 void Store(ElementAccess const& access, Node* index, Node* value) { 62 effect_ = graph()->NewNode(simplified()->StoreElement(access), allocation_, 63 index, value, effect_, control_); 64 } 65 66 // Compound allocation of a FixedArray. 67 void AllocateArray(int length, Handle<Map> map, 68 PretenureFlag pretenure = NOT_TENURED) { 69 DCHECK(map->instance_type() == FIXED_ARRAY_TYPE || 70 map->instance_type() == FIXED_DOUBLE_ARRAY_TYPE); 71 int size = (map->instance_type() == FIXED_ARRAY_TYPE) 72 ? FixedArray::SizeFor(length) 73 : FixedDoubleArray::SizeFor(length); 74 Allocate(size, pretenure, Type::OtherInternal()); 75 Store(AccessBuilder::ForMap(), map); 76 Store(AccessBuilder::ForFixedArrayLength(), jsgraph()->Constant(length)); 77 } 78 79 // Compound store of a constant into a field. 80 void Store(const FieldAccess& access, Handle<Object> value) { 81 Store(access, jsgraph()->Constant(value)); 82 } 83 84 void FinishAndChange(Node* node) { 85 NodeProperties::SetType(allocation_, NodeProperties::GetType(node)); 86 node->ReplaceInput(0, allocation_); 87 node->ReplaceInput(1, effect_); 88 node->TrimInputCount(2); 89 NodeProperties::ChangeOp(node, common()->FinishRegion()); 90 } 91 92 Node* Finish() { 93 return graph()->NewNode(common()->FinishRegion(), allocation_, effect_); 94 } 95 96 protected: 97 JSGraph* jsgraph() { return jsgraph_; } 98 Graph* graph() { return jsgraph_->graph(); } 99 CommonOperatorBuilder* common() { return jsgraph_->common(); } 100 SimplifiedOperatorBuilder* simplified() { return jsgraph_->simplified(); } 101 102 private: 103 JSGraph* const jsgraph_; 104 Node* allocation_; 105 Node* effect_; 106 Node* control_; 107 }; 108 109 // Retrieves the frame state holding actual argument values. 110 Node* GetArgumentsFrameState(Node* frame_state) { 111 Node* const outer_state = NodeProperties::GetFrameStateInput(frame_state); 112 FrameStateInfo outer_state_info = OpParameter<FrameStateInfo>(outer_state); 113 return outer_state_info.type() == FrameStateType::kArgumentsAdaptor 114 ? outer_state 115 : frame_state; 116 } 117 118 // Checks whether allocation using the given target and new.target can be 119 // inlined. 120 bool IsAllocationInlineable(Handle<JSFunction> target, 121 Handle<JSFunction> new_target) { 122 return new_target->has_initial_map() && 123 new_target->initial_map()->constructor_or_backpointer() == *target; 124 } 125 126 // When initializing arrays, we'll unfold the loop if the number of 127 // elements is known to be of this type. 128 const int kElementLoopUnrollLimit = 16; 129 130 // Limits up to which context allocations are inlined. 131 const int kFunctionContextAllocationLimit = 16; 132 const int kBlockContextAllocationLimit = 16; 133 134 // Determines whether the given array or object literal boilerplate satisfies 135 // all limits to be considered for fast deep-copying and computes the total 136 // size of all objects that are part of the graph. 137 bool IsFastLiteral(Handle<JSObject> boilerplate, int max_depth, 138 int* max_properties) { 139 DCHECK_GE(max_depth, 0); 140 DCHECK_GE(*max_properties, 0); 141 142 // Make sure the boilerplate map is not deprecated. 143 if (!JSObject::TryMigrateInstance(boilerplate)) return false; 144 145 // Check for too deep nesting. 146 if (max_depth == 0) return false; 147 148 // Check the elements. 149 Isolate* const isolate = boilerplate->GetIsolate(); 150 Handle<FixedArrayBase> elements(boilerplate->elements(), isolate); 151 if (elements->length() > 0 && 152 elements->map() != isolate->heap()->fixed_cow_array_map()) { 153 if (boilerplate->HasFastSmiOrObjectElements()) { 154 Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements); 155 int length = elements->length(); 156 for (int i = 0; i < length; i++) { 157 if ((*max_properties)-- == 0) return false; 158 Handle<Object> value(fast_elements->get(i), isolate); 159 if (value->IsJSObject()) { 160 Handle<JSObject> value_object = Handle<JSObject>::cast(value); 161 if (!IsFastLiteral(value_object, max_depth - 1, max_properties)) { 162 return false; 163 } 164 } 165 } 166 } else if (boilerplate->HasFastDoubleElements()) { 167 if (elements->Size() > kMaxRegularHeapObjectSize) return false; 168 } else { 169 return false; 170 } 171 } 172 173 // TODO(turbofan): Do we want to support out-of-object properties? 174 Handle<FixedArray> properties(boilerplate->properties(), isolate); 175 if (properties->length() > 0) return false; 176 177 // Check the in-object properties. 178 Handle<DescriptorArray> descriptors( 179 boilerplate->map()->instance_descriptors(), isolate); 180 int limit = boilerplate->map()->NumberOfOwnDescriptors(); 181 for (int i = 0; i < limit; i++) { 182 PropertyDetails details = descriptors->GetDetails(i); 183 if (details.location() != kField) continue; 184 DCHECK_EQ(kData, details.kind()); 185 if ((*max_properties)-- == 0) return false; 186 FieldIndex field_index = FieldIndex::ForDescriptor(boilerplate->map(), i); 187 if (boilerplate->IsUnboxedDoubleField(field_index)) continue; 188 Handle<Object> value(boilerplate->RawFastPropertyAt(field_index), isolate); 189 if (value->IsJSObject()) { 190 Handle<JSObject> value_object = Handle<JSObject>::cast(value); 191 if (!IsFastLiteral(value_object, max_depth - 1, max_properties)) { 192 return false; 193 } 194 } 195 } 196 return true; 197 } 198 199 // Maximum depth and total number of elements and properties for literal 200 // graphs to be considered for fast deep-copying. 201 const int kMaxFastLiteralDepth = 3; 202 const int kMaxFastLiteralProperties = 8; 203 204 } // namespace 205 206 Reduction JSCreateLowering::Reduce(Node* node) { 207 switch (node->opcode()) { 208 case IrOpcode::kJSCreate: 209 return ReduceJSCreate(node); 210 case IrOpcode::kJSCreateArguments: 211 return ReduceJSCreateArguments(node); 212 case IrOpcode::kJSCreateArray: 213 return ReduceJSCreateArray(node); 214 case IrOpcode::kJSCreateIterResultObject: 215 return ReduceJSCreateIterResultObject(node); 216 case IrOpcode::kJSCreateKeyValueArray: 217 return ReduceJSCreateKeyValueArray(node); 218 case IrOpcode::kJSCreateLiteralArray: 219 case IrOpcode::kJSCreateLiteralObject: 220 return ReduceJSCreateLiteral(node); 221 case IrOpcode::kJSCreateFunctionContext: 222 return ReduceJSCreateFunctionContext(node); 223 case IrOpcode::kJSCreateWithContext: 224 return ReduceJSCreateWithContext(node); 225 case IrOpcode::kJSCreateCatchContext: 226 return ReduceJSCreateCatchContext(node); 227 case IrOpcode::kJSCreateBlockContext: 228 return ReduceJSCreateBlockContext(node); 229 default: 230 break; 231 } 232 return NoChange(); 233 } 234 235 Reduction JSCreateLowering::ReduceJSCreate(Node* node) { 236 DCHECK_EQ(IrOpcode::kJSCreate, node->opcode()); 237 Node* const target = NodeProperties::GetValueInput(node, 0); 238 Type* const target_type = NodeProperties::GetType(target); 239 Node* const new_target = NodeProperties::GetValueInput(node, 1); 240 Type* const new_target_type = NodeProperties::GetType(new_target); 241 Node* const effect = NodeProperties::GetEffectInput(node); 242 Node* const control = NodeProperties::GetControlInput(node); 243 // Extract constructor and original constructor function. 244 if (target_type->IsHeapConstant() && new_target_type->IsHeapConstant() && 245 new_target_type->AsHeapConstant()->Value()->IsJSFunction()) { 246 Handle<JSFunction> constructor = 247 Handle<JSFunction>::cast(target_type->AsHeapConstant()->Value()); 248 Handle<JSFunction> original_constructor = 249 Handle<JSFunction>::cast(new_target_type->AsHeapConstant()->Value()); 250 DCHECK(constructor->IsConstructor()); 251 DCHECK(original_constructor->IsConstructor()); 252 253 // Check if we can inline the allocation. 254 if (IsAllocationInlineable(constructor, original_constructor)) { 255 // Force completion of inobject slack tracking before 256 // generating code to finalize the instance size. 257 original_constructor->CompleteInobjectSlackTrackingIfActive(); 258 259 // Compute instance size from initial map of {original_constructor}. 260 Handle<Map> initial_map(original_constructor->initial_map(), isolate()); 261 int const instance_size = initial_map->instance_size(); 262 263 // Add a dependency on the {initial_map} to make sure that this code is 264 // deoptimized whenever the {initial_map} of the {original_constructor} 265 // changes. 266 dependencies()->AssumeInitialMapCantChange(initial_map); 267 268 // Emit code to allocate the JSObject instance for the 269 // {original_constructor}. 270 AllocationBuilder a(jsgraph(), effect, control); 271 a.Allocate(instance_size); 272 a.Store(AccessBuilder::ForMap(), initial_map); 273 a.Store(AccessBuilder::ForJSObjectProperties(), 274 jsgraph()->EmptyFixedArrayConstant()); 275 a.Store(AccessBuilder::ForJSObjectElements(), 276 jsgraph()->EmptyFixedArrayConstant()); 277 for (int i = 0; i < initial_map->GetInObjectProperties(); ++i) { 278 a.Store(AccessBuilder::ForJSObjectInObjectProperty(initial_map, i), 279 jsgraph()->UndefinedConstant()); 280 } 281 RelaxControls(node); 282 a.FinishAndChange(node); 283 return Changed(node); 284 } 285 } 286 return NoChange(); 287 } 288 289 Reduction JSCreateLowering::ReduceJSCreateArguments(Node* node) { 290 DCHECK_EQ(IrOpcode::kJSCreateArguments, node->opcode()); 291 CreateArgumentsType type = CreateArgumentsTypeOf(node->op()); 292 Node* const frame_state = NodeProperties::GetFrameStateInput(node); 293 Node* const outer_state = frame_state->InputAt(kFrameStateOuterStateInput); 294 Node* const control = graph()->start(); 295 FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state); 296 297 // Use the ArgumentsAccessStub for materializing both mapped and unmapped 298 // arguments object, but only for non-inlined (i.e. outermost) frames. 299 if (outer_state->opcode() != IrOpcode::kFrameState) { 300 switch (type) { 301 case CreateArgumentsType::kMappedArguments: { 302 // TODO(bmeurer): Make deoptimization mandatory for the various 303 // arguments objects, so that we always have a shared_info here. 304 Handle<SharedFunctionInfo> shared_info; 305 if (state_info.shared_info().ToHandle(&shared_info)) { 306 // TODO(mstarzinger): Duplicate parameters are not handled yet. 307 if (shared_info->has_duplicate_parameters()) return NoChange(); 308 // If there is no aliasing, the arguments object elements are not 309 // special in any way, we can just return an unmapped backing store. 310 if (shared_info->internal_formal_parameter_count() == 0) { 311 Node* const callee = NodeProperties::GetValueInput(node, 0); 312 Node* effect = NodeProperties::GetEffectInput(node); 313 // Allocate the elements backing store. 314 Node* const elements = effect = graph()->NewNode( 315 simplified()->NewUnmappedArgumentsElements(0), effect); 316 Node* const length = effect = graph()->NewNode( 317 simplified()->LoadField(AccessBuilder::ForFixedArrayLength()), 318 elements, effect, control); 319 // Load the arguments object map. 320 Node* const arguments_map = jsgraph()->HeapConstant( 321 handle(native_context()->sloppy_arguments_map(), isolate())); 322 // Actually allocate and initialize the arguments object. 323 AllocationBuilder a(jsgraph(), effect, control); 324 Node* properties = jsgraph()->EmptyFixedArrayConstant(); 325 STATIC_ASSERT(JSSloppyArgumentsObject::kSize == 5 * kPointerSize); 326 a.Allocate(JSSloppyArgumentsObject::kSize); 327 a.Store(AccessBuilder::ForMap(), arguments_map); 328 a.Store(AccessBuilder::ForJSObjectProperties(), properties); 329 a.Store(AccessBuilder::ForJSObjectElements(), elements); 330 a.Store(AccessBuilder::ForArgumentsLength(), length); 331 a.Store(AccessBuilder::ForArgumentsCallee(), callee); 332 RelaxControls(node); 333 a.FinishAndChange(node); 334 } else { 335 Callable callable = CodeFactory::FastNewSloppyArguments(isolate()); 336 Operator::Properties properties = node->op()->properties(); 337 CallDescriptor* desc = Linkage::GetStubCallDescriptor( 338 isolate(), graph()->zone(), callable.descriptor(), 0, 339 CallDescriptor::kNoFlags, properties); 340 const Operator* new_op = common()->Call(desc); 341 Node* stub_code = jsgraph()->HeapConstant(callable.code()); 342 node->InsertInput(graph()->zone(), 0, stub_code); 343 node->RemoveInput(3); // Remove the frame state. 344 NodeProperties::ChangeOp(node, new_op); 345 } 346 return Changed(node); 347 } 348 return NoChange(); 349 } 350 case CreateArgumentsType::kUnmappedArguments: { 351 Handle<SharedFunctionInfo> shared_info; 352 if (state_info.shared_info().ToHandle(&shared_info)) { 353 Node* effect = NodeProperties::GetEffectInput(node); 354 // Allocate the elements backing store. 355 Node* const elements = effect = graph()->NewNode( 356 simplified()->NewUnmappedArgumentsElements( 357 shared_info->internal_formal_parameter_count()), 358 effect); 359 Node* const length = effect = graph()->NewNode( 360 simplified()->LoadField(AccessBuilder::ForFixedArrayLength()), 361 elements, effect, control); 362 // Load the arguments object map. 363 Node* const arguments_map = jsgraph()->HeapConstant( 364 handle(native_context()->strict_arguments_map(), isolate())); 365 // Actually allocate and initialize the arguments object. 366 AllocationBuilder a(jsgraph(), effect, control); 367 Node* properties = jsgraph()->EmptyFixedArrayConstant(); 368 STATIC_ASSERT(JSStrictArgumentsObject::kSize == 4 * kPointerSize); 369 a.Allocate(JSStrictArgumentsObject::kSize); 370 a.Store(AccessBuilder::ForMap(), arguments_map); 371 a.Store(AccessBuilder::ForJSObjectProperties(), properties); 372 a.Store(AccessBuilder::ForJSObjectElements(), elements); 373 a.Store(AccessBuilder::ForArgumentsLength(), length); 374 RelaxControls(node); 375 a.FinishAndChange(node); 376 } else { 377 Callable callable = CodeFactory::FastNewStrictArguments(isolate()); 378 Operator::Properties properties = node->op()->properties(); 379 CallDescriptor* desc = Linkage::GetStubCallDescriptor( 380 isolate(), graph()->zone(), callable.descriptor(), 0, 381 CallDescriptor::kNeedsFrameState, properties); 382 const Operator* new_op = common()->Call(desc); 383 Node* stub_code = jsgraph()->HeapConstant(callable.code()); 384 node->InsertInput(graph()->zone(), 0, stub_code); 385 NodeProperties::ChangeOp(node, new_op); 386 } 387 return Changed(node); 388 } 389 case CreateArgumentsType::kRestParameter: { 390 Handle<SharedFunctionInfo> shared_info; 391 if (state_info.shared_info().ToHandle(&shared_info)) { 392 Node* effect = NodeProperties::GetEffectInput(node); 393 // Allocate the elements backing store. 394 Node* const elements = effect = graph()->NewNode( 395 simplified()->NewRestParameterElements( 396 shared_info->internal_formal_parameter_count()), 397 effect); 398 Node* const length = effect = graph()->NewNode( 399 simplified()->LoadField(AccessBuilder::ForFixedArrayLength()), 400 elements, effect, control); 401 // Load the JSArray object map. 402 Node* const jsarray_map = jsgraph()->HeapConstant(handle( 403 native_context()->js_array_fast_elements_map_index(), isolate())); 404 // Actually allocate and initialize the jsarray. 405 AllocationBuilder a(jsgraph(), effect, control); 406 Node* properties = jsgraph()->EmptyFixedArrayConstant(); 407 STATIC_ASSERT(JSArray::kSize == 4 * kPointerSize); 408 a.Allocate(JSArray::kSize); 409 a.Store(AccessBuilder::ForMap(), jsarray_map); 410 a.Store(AccessBuilder::ForJSObjectProperties(), properties); 411 a.Store(AccessBuilder::ForJSObjectElements(), elements); 412 a.Store(AccessBuilder::ForJSArrayLength(FAST_ELEMENTS), length); 413 RelaxControls(node); 414 a.FinishAndChange(node); 415 } else { 416 Callable callable = CodeFactory::FastNewRestParameter(isolate()); 417 Operator::Properties properties = node->op()->properties(); 418 CallDescriptor* desc = Linkage::GetStubCallDescriptor( 419 isolate(), graph()->zone(), callable.descriptor(), 0, 420 CallDescriptor::kNeedsFrameState, properties); 421 const Operator* new_op = common()->Call(desc); 422 Node* stub_code = jsgraph()->HeapConstant(callable.code()); 423 node->InsertInput(graph()->zone(), 0, stub_code); 424 NodeProperties::ChangeOp(node, new_op); 425 } 426 return Changed(node); 427 } 428 } 429 UNREACHABLE(); 430 } else if (outer_state->opcode() == IrOpcode::kFrameState) { 431 // Use inline allocation for all mapped arguments objects within inlined 432 // (i.e. non-outermost) frames, independent of the object size. 433 if (type == CreateArgumentsType::kMappedArguments) { 434 Handle<SharedFunctionInfo> shared; 435 if (!state_info.shared_info().ToHandle(&shared)) return NoChange(); 436 Node* const callee = NodeProperties::GetValueInput(node, 0); 437 Node* const context = NodeProperties::GetContextInput(node); 438 Node* effect = NodeProperties::GetEffectInput(node); 439 // TODO(mstarzinger): Duplicate parameters are not handled yet. 440 if (shared->has_duplicate_parameters()) return NoChange(); 441 // Choose the correct frame state and frame state info depending on 442 // whether there conceptually is an arguments adaptor frame in the call 443 // chain. 444 Node* const args_state = GetArgumentsFrameState(frame_state); 445 FrameStateInfo args_state_info = OpParameter<FrameStateInfo>(args_state); 446 // Prepare element backing store to be used by arguments object. 447 bool has_aliased_arguments = false; 448 Node* const elements = AllocateAliasedArguments( 449 effect, control, args_state, context, shared, &has_aliased_arguments); 450 effect = elements->op()->EffectOutputCount() > 0 ? elements : effect; 451 // Load the arguments object map. 452 Node* const arguments_map = jsgraph()->HeapConstant(handle( 453 has_aliased_arguments ? native_context()->fast_aliased_arguments_map() 454 : native_context()->sloppy_arguments_map(), 455 isolate())); 456 // Actually allocate and initialize the arguments object. 457 AllocationBuilder a(jsgraph(), effect, control); 458 Node* properties = jsgraph()->EmptyFixedArrayConstant(); 459 int length = args_state_info.parameter_count() - 1; // Minus receiver. 460 STATIC_ASSERT(JSSloppyArgumentsObject::kSize == 5 * kPointerSize); 461 a.Allocate(JSSloppyArgumentsObject::kSize); 462 a.Store(AccessBuilder::ForMap(), arguments_map); 463 a.Store(AccessBuilder::ForJSObjectProperties(), properties); 464 a.Store(AccessBuilder::ForJSObjectElements(), elements); 465 a.Store(AccessBuilder::ForArgumentsLength(), jsgraph()->Constant(length)); 466 a.Store(AccessBuilder::ForArgumentsCallee(), callee); 467 RelaxControls(node); 468 a.FinishAndChange(node); 469 return Changed(node); 470 } else if (type == CreateArgumentsType::kUnmappedArguments) { 471 // Use inline allocation for all unmapped arguments objects within inlined 472 // (i.e. non-outermost) frames, independent of the object size. 473 Node* effect = NodeProperties::GetEffectInput(node); 474 // Choose the correct frame state and frame state info depending on 475 // whether there conceptually is an arguments adaptor frame in the call 476 // chain. 477 Node* const args_state = GetArgumentsFrameState(frame_state); 478 FrameStateInfo args_state_info = OpParameter<FrameStateInfo>(args_state); 479 // Prepare element backing store to be used by arguments object. 480 Node* const elements = AllocateArguments(effect, control, args_state); 481 effect = elements->op()->EffectOutputCount() > 0 ? elements : effect; 482 // Load the arguments object map. 483 Node* const arguments_map = jsgraph()->HeapConstant( 484 handle(native_context()->strict_arguments_map(), isolate())); 485 // Actually allocate and initialize the arguments object. 486 AllocationBuilder a(jsgraph(), effect, control); 487 Node* properties = jsgraph()->EmptyFixedArrayConstant(); 488 int length = args_state_info.parameter_count() - 1; // Minus receiver. 489 STATIC_ASSERT(JSStrictArgumentsObject::kSize == 4 * kPointerSize); 490 a.Allocate(JSStrictArgumentsObject::kSize); 491 a.Store(AccessBuilder::ForMap(), arguments_map); 492 a.Store(AccessBuilder::ForJSObjectProperties(), properties); 493 a.Store(AccessBuilder::ForJSObjectElements(), elements); 494 a.Store(AccessBuilder::ForArgumentsLength(), jsgraph()->Constant(length)); 495 RelaxControls(node); 496 a.FinishAndChange(node); 497 return Changed(node); 498 } else if (type == CreateArgumentsType::kRestParameter) { 499 Handle<SharedFunctionInfo> shared; 500 if (!state_info.shared_info().ToHandle(&shared)) return NoChange(); 501 int start_index = shared->internal_formal_parameter_count(); 502 // Use inline allocation for all unmapped arguments objects within inlined 503 // (i.e. non-outermost) frames, independent of the object size. 504 Node* effect = NodeProperties::GetEffectInput(node); 505 // Choose the correct frame state and frame state info depending on 506 // whether there conceptually is an arguments adaptor frame in the call 507 // chain. 508 Node* const args_state = GetArgumentsFrameState(frame_state); 509 FrameStateInfo args_state_info = OpParameter<FrameStateInfo>(args_state); 510 // Prepare element backing store to be used by the rest array. 511 Node* const elements = 512 AllocateRestArguments(effect, control, args_state, start_index); 513 effect = elements->op()->EffectOutputCount() > 0 ? elements : effect; 514 // Load the JSArray object map. 515 Node* const jsarray_map = jsgraph()->HeapConstant(handle( 516 native_context()->js_array_fast_elements_map_index(), isolate())); 517 // Actually allocate and initialize the jsarray. 518 AllocationBuilder a(jsgraph(), effect, control); 519 Node* properties = jsgraph()->EmptyFixedArrayConstant(); 520 521 // -1 to minus receiver 522 int argument_count = args_state_info.parameter_count() - 1; 523 int length = std::max(0, argument_count - start_index); 524 STATIC_ASSERT(JSArray::kSize == 4 * kPointerSize); 525 a.Allocate(JSArray::kSize); 526 a.Store(AccessBuilder::ForMap(), jsarray_map); 527 a.Store(AccessBuilder::ForJSObjectProperties(), properties); 528 a.Store(AccessBuilder::ForJSObjectElements(), elements); 529 a.Store(AccessBuilder::ForJSArrayLength(FAST_ELEMENTS), 530 jsgraph()->Constant(length)); 531 RelaxControls(node); 532 a.FinishAndChange(node); 533 return Changed(node); 534 } 535 } 536 537 return NoChange(); 538 } 539 540 Reduction JSCreateLowering::ReduceNewArray(Node* node, Node* length, 541 int capacity, 542 Handle<AllocationSite> site) { 543 DCHECK_EQ(IrOpcode::kJSCreateArray, node->opcode()); 544 Node* effect = NodeProperties::GetEffectInput(node); 545 Node* control = NodeProperties::GetControlInput(node); 546 547 // Extract transition and tenuring feedback from the {site} and add 548 // appropriate code dependencies on the {site} if deoptimization is 549 // enabled. 550 PretenureFlag pretenure = site->GetPretenureMode(); 551 ElementsKind elements_kind = site->GetElementsKind(); 552 DCHECK(IsFastElementsKind(elements_kind)); 553 if (NodeProperties::GetType(length)->Max() > 0) { 554 elements_kind = GetHoleyElementsKind(elements_kind); 555 } 556 dependencies()->AssumeTenuringDecision(site); 557 dependencies()->AssumeTransitionStable(site); 558 559 // Retrieve the initial map for the array. 560 int const array_map_index = Context::ArrayMapIndex(elements_kind); 561 Node* js_array_map = jsgraph()->HeapConstant( 562 handle(Map::cast(native_context()->get(array_map_index)), isolate())); 563 564 // Setup elements and properties. 565 Node* elements; 566 if (capacity == 0) { 567 elements = jsgraph()->EmptyFixedArrayConstant(); 568 } else { 569 elements = effect = 570 AllocateElements(effect, control, elements_kind, capacity, pretenure); 571 } 572 Node* properties = jsgraph()->EmptyFixedArrayConstant(); 573 574 // Perform the allocation of the actual JSArray object. 575 AllocationBuilder a(jsgraph(), effect, control); 576 a.Allocate(JSArray::kSize, pretenure); 577 a.Store(AccessBuilder::ForMap(), js_array_map); 578 a.Store(AccessBuilder::ForJSObjectProperties(), properties); 579 a.Store(AccessBuilder::ForJSObjectElements(), elements); 580 a.Store(AccessBuilder::ForJSArrayLength(elements_kind), length); 581 RelaxControls(node); 582 a.FinishAndChange(node); 583 return Changed(node); 584 } 585 586 Reduction JSCreateLowering::ReduceNewArrayToStubCall( 587 Node* node, Handle<AllocationSite> site) { 588 CreateArrayParameters const& p = CreateArrayParametersOf(node->op()); 589 int const arity = static_cast<int>(p.arity()); 590 591 ElementsKind elements_kind = site->GetElementsKind(); 592 AllocationSiteOverrideMode override_mode = 593 (AllocationSite::GetMode(elements_kind) == TRACK_ALLOCATION_SITE) 594 ? DISABLE_ALLOCATION_SITES 595 : DONT_OVERRIDE; 596 597 if (arity == 0) { 598 ArrayNoArgumentConstructorStub stub(isolate(), elements_kind, 599 override_mode); 600 CallDescriptor* desc = Linkage::GetStubCallDescriptor( 601 isolate(), graph()->zone(), stub.GetCallInterfaceDescriptor(), 1, 602 CallDescriptor::kNeedsFrameState); 603 node->ReplaceInput(0, jsgraph()->HeapConstant(stub.GetCode())); 604 node->InsertInput(graph()->zone(), 2, jsgraph()->HeapConstant(site)); 605 node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(0)); 606 node->InsertInput(graph()->zone(), 4, jsgraph()->UndefinedConstant()); 607 NodeProperties::ChangeOp(node, common()->Call(desc)); 608 return Changed(node); 609 } else if (arity == 1) { 610 AllocationSiteOverrideMode override_mode = 611 (AllocationSite::GetMode(elements_kind) == TRACK_ALLOCATION_SITE) 612 ? DISABLE_ALLOCATION_SITES 613 : DONT_OVERRIDE; 614 615 if (IsHoleyElementsKind(elements_kind)) { 616 ArraySingleArgumentConstructorStub stub(isolate(), elements_kind, 617 override_mode); 618 CallDescriptor* desc = Linkage::GetStubCallDescriptor( 619 isolate(), graph()->zone(), stub.GetCallInterfaceDescriptor(), 2, 620 CallDescriptor::kNeedsFrameState); 621 node->ReplaceInput(0, jsgraph()->HeapConstant(stub.GetCode())); 622 node->InsertInput(graph()->zone(), 2, jsgraph()->HeapConstant(site)); 623 node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(1)); 624 node->InsertInput(graph()->zone(), 4, jsgraph()->UndefinedConstant()); 625 NodeProperties::ChangeOp(node, common()->Call(desc)); 626 return Changed(node); 627 } 628 629 Node* effect = NodeProperties::GetEffectInput(node); 630 Node* control = NodeProperties::GetControlInput(node); 631 Node* length = NodeProperties::GetValueInput(node, 2); 632 Node* equal = graph()->NewNode(simplified()->ReferenceEqual(), length, 633 jsgraph()->ZeroConstant()); 634 635 Node* branch = 636 graph()->NewNode(common()->Branch(BranchHint::kFalse), equal, control); 637 Node* call_holey; 638 Node* call_packed; 639 Node* if_success_packed; 640 Node* if_success_holey; 641 Node* context = NodeProperties::GetContextInput(node); 642 Node* frame_state = NodeProperties::GetFrameStateInput(node); 643 Node* if_equal = graph()->NewNode(common()->IfTrue(), branch); 644 { 645 ArraySingleArgumentConstructorStub stub(isolate(), elements_kind, 646 override_mode); 647 CallDescriptor* desc = Linkage::GetStubCallDescriptor( 648 isolate(), graph()->zone(), stub.GetCallInterfaceDescriptor(), 2, 649 CallDescriptor::kNeedsFrameState); 650 651 Node* inputs[] = {jsgraph()->HeapConstant(stub.GetCode()), 652 node->InputAt(1), 653 jsgraph()->HeapConstant(site), 654 jsgraph()->Constant(1), 655 jsgraph()->UndefinedConstant(), 656 length, 657 context, 658 frame_state, 659 effect, 660 if_equal}; 661 662 call_holey = 663 graph()->NewNode(common()->Call(desc), arraysize(inputs), inputs); 664 if_success_holey = graph()->NewNode(common()->IfSuccess(), call_holey); 665 } 666 Node* if_not_equal = graph()->NewNode(common()->IfFalse(), branch); 667 { 668 // Require elements kind to "go holey." 669 ArraySingleArgumentConstructorStub stub( 670 isolate(), GetHoleyElementsKind(elements_kind), override_mode); 671 CallDescriptor* desc = Linkage::GetStubCallDescriptor( 672 isolate(), graph()->zone(), stub.GetCallInterfaceDescriptor(), 2, 673 CallDescriptor::kNeedsFrameState); 674 675 Node* inputs[] = {jsgraph()->HeapConstant(stub.GetCode()), 676 node->InputAt(1), 677 jsgraph()->HeapConstant(site), 678 jsgraph()->Constant(1), 679 jsgraph()->UndefinedConstant(), 680 length, 681 context, 682 frame_state, 683 effect, 684 if_not_equal}; 685 686 call_packed = 687 graph()->NewNode(common()->Call(desc), arraysize(inputs), inputs); 688 if_success_packed = graph()->NewNode(common()->IfSuccess(), call_packed); 689 } 690 Node* merge = graph()->NewNode(common()->Merge(2), if_success_holey, 691 if_success_packed); 692 Node* effect_phi = graph()->NewNode(common()->EffectPhi(2), call_holey, 693 call_packed, merge); 694 Node* phi = 695 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), 696 call_holey, call_packed, merge); 697 698 ReplaceWithValue(node, phi, effect_phi, merge); 699 return Changed(node); 700 } 701 702 DCHECK(arity > 1); 703 ArrayNArgumentsConstructorStub stub(isolate()); 704 CallDescriptor* desc = Linkage::GetStubCallDescriptor( 705 isolate(), graph()->zone(), stub.GetCallInterfaceDescriptor(), arity + 1, 706 CallDescriptor::kNeedsFrameState); 707 node->ReplaceInput(0, jsgraph()->HeapConstant(stub.GetCode())); 708 node->InsertInput(graph()->zone(), 2, jsgraph()->HeapConstant(site)); 709 node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(arity)); 710 node->InsertInput(graph()->zone(), 4, jsgraph()->UndefinedConstant()); 711 NodeProperties::ChangeOp(node, common()->Call(desc)); 712 return Changed(node); 713 } 714 715 Reduction JSCreateLowering::ReduceJSCreateArray(Node* node) { 716 DCHECK_EQ(IrOpcode::kJSCreateArray, node->opcode()); 717 CreateArrayParameters const& p = CreateArrayParametersOf(node->op()); 718 Node* target = NodeProperties::GetValueInput(node, 0); 719 Node* new_target = NodeProperties::GetValueInput(node, 1); 720 721 // TODO(mstarzinger): Array constructor can throw. Hook up exceptional edges. 722 if (NodeProperties::IsExceptionalCall(node)) return NoChange(); 723 724 // TODO(bmeurer): Optimize the subclassing case. 725 if (target != new_target) return NoChange(); 726 727 // Check if we have a feedback {site} on the {node}. 728 Handle<AllocationSite> site = p.site(); 729 if (p.site().is_null()) return NoChange(); 730 731 // Attempt to inline calls to the Array constructor for the relevant cases 732 // where either no arguments are provided, or exactly one unsigned number 733 // argument is given. 734 if (site->CanInlineCall()) { 735 if (p.arity() == 0) { 736 Node* length = jsgraph()->ZeroConstant(); 737 int capacity = JSArray::kPreallocatedArrayElements; 738 return ReduceNewArray(node, length, capacity, site); 739 } else if (p.arity() == 1) { 740 Node* length = NodeProperties::GetValueInput(node, 2); 741 Type* length_type = NodeProperties::GetType(length); 742 if (length_type->Is(Type::SignedSmall()) && length_type->Min() >= 0 && 743 length_type->Max() <= kElementLoopUnrollLimit && 744 length_type->Min() == length_type->Max()) { 745 int capacity = static_cast<int>(length_type->Max()); 746 return ReduceNewArray(node, length, capacity, site); 747 } 748 } 749 } 750 751 return ReduceNewArrayToStubCall(node, site); 752 } 753 754 Reduction JSCreateLowering::ReduceJSCreateIterResultObject(Node* node) { 755 DCHECK_EQ(IrOpcode::kJSCreateIterResultObject, node->opcode()); 756 Node* value = NodeProperties::GetValueInput(node, 0); 757 Node* done = NodeProperties::GetValueInput(node, 1); 758 Node* effect = NodeProperties::GetEffectInput(node); 759 760 Node* iterator_result_map = jsgraph()->HeapConstant( 761 handle(native_context()->iterator_result_map(), isolate())); 762 763 // Emit code to allocate the JSIteratorResult instance. 764 AllocationBuilder a(jsgraph(), effect, graph()->start()); 765 a.Allocate(JSIteratorResult::kSize); 766 a.Store(AccessBuilder::ForMap(), iterator_result_map); 767 a.Store(AccessBuilder::ForJSObjectProperties(), 768 jsgraph()->EmptyFixedArrayConstant()); 769 a.Store(AccessBuilder::ForJSObjectElements(), 770 jsgraph()->EmptyFixedArrayConstant()); 771 a.Store(AccessBuilder::ForJSIteratorResultValue(), value); 772 a.Store(AccessBuilder::ForJSIteratorResultDone(), done); 773 STATIC_ASSERT(JSIteratorResult::kSize == 5 * kPointerSize); 774 a.FinishAndChange(node); 775 return Changed(node); 776 } 777 778 Reduction JSCreateLowering::ReduceJSCreateKeyValueArray(Node* node) { 779 DCHECK_EQ(IrOpcode::kJSCreateKeyValueArray, node->opcode()); 780 Node* key = NodeProperties::GetValueInput(node, 0); 781 Node* value = NodeProperties::GetValueInput(node, 1); 782 Node* effect = NodeProperties::GetEffectInput(node); 783 784 Node* array_map = jsgraph()->HeapConstant( 785 handle(native_context()->js_array_fast_elements_map_index())); 786 Node* properties = jsgraph()->EmptyFixedArrayConstant(); 787 Node* length = jsgraph()->Constant(2); 788 789 AllocationBuilder aa(jsgraph(), effect, graph()->start()); 790 aa.AllocateArray(2, factory()->fixed_array_map()); 791 aa.Store(AccessBuilder::ForFixedArrayElement(FAST_ELEMENTS), 792 jsgraph()->Constant(0), key); 793 aa.Store(AccessBuilder::ForFixedArrayElement(FAST_ELEMENTS), 794 jsgraph()->Constant(1), value); 795 Node* elements = aa.Finish(); 796 797 AllocationBuilder a(jsgraph(), elements, graph()->start()); 798 a.Allocate(JSArray::kSize); 799 a.Store(AccessBuilder::ForMap(), array_map); 800 a.Store(AccessBuilder::ForJSObjectProperties(), properties); 801 a.Store(AccessBuilder::ForJSObjectElements(), elements); 802 a.Store(AccessBuilder::ForJSArrayLength(FAST_ELEMENTS), length); 803 STATIC_ASSERT(JSArray::kSize == 4 * kPointerSize); 804 a.FinishAndChange(node); 805 return Changed(node); 806 } 807 808 Reduction JSCreateLowering::ReduceJSCreateLiteral(Node* node) { 809 DCHECK(node->opcode() == IrOpcode::kJSCreateLiteralArray || 810 node->opcode() == IrOpcode::kJSCreateLiteralObject); 811 CreateLiteralParameters const& p = CreateLiteralParametersOf(node->op()); 812 Node* effect = NodeProperties::GetEffectInput(node); 813 Node* control = NodeProperties::GetControlInput(node); 814 815 Handle<FeedbackVector> feedback_vector; 816 if (GetSpecializationFeedbackVector(node).ToHandle(&feedback_vector)) { 817 FeedbackSlot slot(FeedbackVector::ToSlot(p.index())); 818 Handle<Object> literal(feedback_vector->Get(slot), isolate()); 819 if (literal->IsAllocationSite()) { 820 Handle<AllocationSite> site = Handle<AllocationSite>::cast(literal); 821 Handle<JSObject> boilerplate(JSObject::cast(site->transition_info()), 822 isolate()); 823 int max_properties = kMaxFastLiteralProperties; 824 if (IsFastLiteral(boilerplate, kMaxFastLiteralDepth, &max_properties)) { 825 AllocationSiteUsageContext site_context(isolate(), site, false); 826 site_context.EnterNewScope(); 827 Node* value = effect = 828 AllocateFastLiteral(effect, control, boilerplate, &site_context); 829 site_context.ExitScope(site, boilerplate); 830 ReplaceWithValue(node, value, effect, control); 831 return Replace(value); 832 } 833 } 834 } 835 836 return NoChange(); 837 } 838 839 Reduction JSCreateLowering::ReduceJSCreateFunctionContext(Node* node) { 840 DCHECK_EQ(IrOpcode::kJSCreateFunctionContext, node->opcode()); 841 const CreateFunctionContextParameters& parameters = 842 CreateFunctionContextParametersOf(node->op()); 843 int slot_count = parameters.slot_count(); 844 ScopeType scope_type = parameters.scope_type(); 845 Node* const closure = NodeProperties::GetValueInput(node, 0); 846 847 // Use inline allocation for function contexts up to a size limit. 848 if (slot_count < kFunctionContextAllocationLimit) { 849 // JSCreateFunctionContext[slot_count < limit]](fun) 850 Node* effect = NodeProperties::GetEffectInput(node); 851 Node* control = NodeProperties::GetControlInput(node); 852 Node* context = NodeProperties::GetContextInput(node); 853 Node* extension = jsgraph()->TheHoleConstant(); 854 AllocationBuilder a(jsgraph(), effect, control); 855 STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == 4); // Ensure fully covered. 856 int context_length = slot_count + Context::MIN_CONTEXT_SLOTS; 857 Handle<Map> map; 858 switch (scope_type) { 859 case EVAL_SCOPE: 860 map = factory()->eval_context_map(); 861 break; 862 case FUNCTION_SCOPE: 863 map = factory()->function_context_map(); 864 break; 865 default: 866 UNREACHABLE(); 867 } 868 a.AllocateArray(context_length, map); 869 a.Store(AccessBuilder::ForContextSlot(Context::CLOSURE_INDEX), closure); 870 a.Store(AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX), context); 871 a.Store(AccessBuilder::ForContextSlot(Context::EXTENSION_INDEX), extension); 872 a.Store(AccessBuilder::ForContextSlot(Context::NATIVE_CONTEXT_INDEX), 873 jsgraph()->HeapConstant(native_context())); 874 for (int i = Context::MIN_CONTEXT_SLOTS; i < context_length; ++i) { 875 a.Store(AccessBuilder::ForContextSlot(i), jsgraph()->UndefinedConstant()); 876 } 877 RelaxControls(node); 878 a.FinishAndChange(node); 879 return Changed(node); 880 } 881 882 return NoChange(); 883 } 884 885 Reduction JSCreateLowering::ReduceJSCreateWithContext(Node* node) { 886 DCHECK_EQ(IrOpcode::kJSCreateWithContext, node->opcode()); 887 Handle<ScopeInfo> scope_info = OpParameter<Handle<ScopeInfo>>(node); 888 Node* object = NodeProperties::GetValueInput(node, 0); 889 Node* closure = NodeProperties::GetValueInput(node, 1); 890 Node* effect = NodeProperties::GetEffectInput(node); 891 Node* control = NodeProperties::GetControlInput(node); 892 Node* context = NodeProperties::GetContextInput(node); 893 894 AllocationBuilder aa(jsgraph(), effect, control); 895 aa.Allocate(ContextExtension::kSize); 896 aa.Store(AccessBuilder::ForMap(), factory()->context_extension_map()); 897 aa.Store(AccessBuilder::ForContextExtensionScopeInfo(), scope_info); 898 aa.Store(AccessBuilder::ForContextExtensionExtension(), object); 899 Node* extension = aa.Finish(); 900 901 AllocationBuilder a(jsgraph(), extension, control); 902 STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == 4); // Ensure fully covered. 903 a.AllocateArray(Context::MIN_CONTEXT_SLOTS, factory()->with_context_map()); 904 a.Store(AccessBuilder::ForContextSlot(Context::CLOSURE_INDEX), closure); 905 a.Store(AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX), context); 906 a.Store(AccessBuilder::ForContextSlot(Context::EXTENSION_INDEX), extension); 907 a.Store(AccessBuilder::ForContextSlot(Context::NATIVE_CONTEXT_INDEX), 908 jsgraph()->HeapConstant(native_context())); 909 RelaxControls(node); 910 a.FinishAndChange(node); 911 return Changed(node); 912 } 913 914 Reduction JSCreateLowering::ReduceJSCreateCatchContext(Node* node) { 915 DCHECK_EQ(IrOpcode::kJSCreateCatchContext, node->opcode()); 916 const CreateCatchContextParameters& parameters = 917 CreateCatchContextParametersOf(node->op()); 918 Node* exception = NodeProperties::GetValueInput(node, 0); 919 Node* closure = NodeProperties::GetValueInput(node, 1); 920 Node* effect = NodeProperties::GetEffectInput(node); 921 Node* control = NodeProperties::GetControlInput(node); 922 Node* context = NodeProperties::GetContextInput(node); 923 924 AllocationBuilder aa(jsgraph(), effect, control); 925 aa.Allocate(ContextExtension::kSize); 926 aa.Store(AccessBuilder::ForMap(), factory()->context_extension_map()); 927 aa.Store(AccessBuilder::ForContextExtensionScopeInfo(), 928 parameters.scope_info()); 929 aa.Store(AccessBuilder::ForContextExtensionExtension(), 930 parameters.catch_name()); 931 Node* extension = aa.Finish(); 932 933 AllocationBuilder a(jsgraph(), extension, control); 934 STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == 4); // Ensure fully covered. 935 a.AllocateArray(Context::MIN_CONTEXT_SLOTS + 1, 936 factory()->catch_context_map()); 937 a.Store(AccessBuilder::ForContextSlot(Context::CLOSURE_INDEX), closure); 938 a.Store(AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX), context); 939 a.Store(AccessBuilder::ForContextSlot(Context::EXTENSION_INDEX), extension); 940 a.Store(AccessBuilder::ForContextSlot(Context::NATIVE_CONTEXT_INDEX), 941 jsgraph()->HeapConstant(native_context())); 942 a.Store(AccessBuilder::ForContextSlot(Context::THROWN_OBJECT_INDEX), 943 exception); 944 RelaxControls(node); 945 a.FinishAndChange(node); 946 return Changed(node); 947 } 948 949 Reduction JSCreateLowering::ReduceJSCreateBlockContext(Node* node) { 950 DCHECK_EQ(IrOpcode::kJSCreateBlockContext, node->opcode()); 951 Handle<ScopeInfo> scope_info = OpParameter<Handle<ScopeInfo>>(node); 952 int const context_length = scope_info->ContextLength(); 953 Node* const closure = NodeProperties::GetValueInput(node, 0); 954 955 // Use inline allocation for block contexts up to a size limit. 956 if (context_length < kBlockContextAllocationLimit) { 957 // JSCreateBlockContext[scope[length < limit]](fun) 958 Node* effect = NodeProperties::GetEffectInput(node); 959 Node* control = NodeProperties::GetControlInput(node); 960 Node* context = NodeProperties::GetContextInput(node); 961 Node* extension = jsgraph()->Constant(scope_info); 962 963 AllocationBuilder a(jsgraph(), effect, control); 964 STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == 4); // Ensure fully covered. 965 a.AllocateArray(context_length, factory()->block_context_map()); 966 a.Store(AccessBuilder::ForContextSlot(Context::CLOSURE_INDEX), closure); 967 a.Store(AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX), context); 968 a.Store(AccessBuilder::ForContextSlot(Context::EXTENSION_INDEX), extension); 969 a.Store(AccessBuilder::ForContextSlot(Context::NATIVE_CONTEXT_INDEX), 970 jsgraph()->HeapConstant(native_context())); 971 for (int i = Context::MIN_CONTEXT_SLOTS; i < context_length; ++i) { 972 a.Store(AccessBuilder::ForContextSlot(i), jsgraph()->UndefinedConstant()); 973 } 974 RelaxControls(node); 975 a.FinishAndChange(node); 976 return Changed(node); 977 } 978 979 return NoChange(); 980 } 981 982 // Helper that allocates a FixedArray holding argument values recorded in the 983 // given {frame_state}. Serves as backing store for JSCreateArguments nodes. 984 Node* JSCreateLowering::AllocateArguments(Node* effect, Node* control, 985 Node* frame_state) { 986 FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state); 987 int argument_count = state_info.parameter_count() - 1; // Minus receiver. 988 if (argument_count == 0) return jsgraph()->EmptyFixedArrayConstant(); 989 990 // Prepare an iterator over argument values recorded in the frame state. 991 Node* const parameters = frame_state->InputAt(kFrameStateParametersInput); 992 StateValuesAccess parameters_access(parameters); 993 auto parameters_it = ++parameters_access.begin(); 994 995 // Actually allocate the backing store. 996 AllocationBuilder a(jsgraph(), effect, control); 997 a.AllocateArray(argument_count, factory()->fixed_array_map()); 998 for (int i = 0; i < argument_count; ++i, ++parameters_it) { 999 DCHECK_NOT_NULL((*parameters_it).node); 1000 a.Store(AccessBuilder::ForFixedArraySlot(i), (*parameters_it).node); 1001 } 1002 return a.Finish(); 1003 } 1004 1005 // Helper that allocates a FixedArray holding argument values recorded in the 1006 // given {frame_state}. Serves as backing store for JSCreateArguments nodes. 1007 Node* JSCreateLowering::AllocateRestArguments(Node* effect, Node* control, 1008 Node* frame_state, 1009 int start_index) { 1010 FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state); 1011 int argument_count = state_info.parameter_count() - 1; // Minus receiver. 1012 int num_elements = std::max(0, argument_count - start_index); 1013 if (num_elements == 0) return jsgraph()->EmptyFixedArrayConstant(); 1014 1015 // Prepare an iterator over argument values recorded in the frame state. 1016 Node* const parameters = frame_state->InputAt(kFrameStateParametersInput); 1017 StateValuesAccess parameters_access(parameters); 1018 auto parameters_it = ++parameters_access.begin(); 1019 1020 // Skip unused arguments. 1021 for (int i = 0; i < start_index; i++) { 1022 ++parameters_it; 1023 } 1024 1025 // Actually allocate the backing store. 1026 AllocationBuilder a(jsgraph(), effect, control); 1027 a.AllocateArray(num_elements, factory()->fixed_array_map()); 1028 for (int i = 0; i < num_elements; ++i, ++parameters_it) { 1029 DCHECK_NOT_NULL((*parameters_it).node); 1030 a.Store(AccessBuilder::ForFixedArraySlot(i), (*parameters_it).node); 1031 } 1032 return a.Finish(); 1033 } 1034 1035 // Helper that allocates a FixedArray serving as a parameter map for values 1036 // recorded in the given {frame_state}. Some elements map to slots within the 1037 // given {context}. Serves as backing store for JSCreateArguments nodes. 1038 Node* JSCreateLowering::AllocateAliasedArguments( 1039 Node* effect, Node* control, Node* frame_state, Node* context, 1040 Handle<SharedFunctionInfo> shared, bool* has_aliased_arguments) { 1041 FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state); 1042 int argument_count = state_info.parameter_count() - 1; // Minus receiver. 1043 if (argument_count == 0) return jsgraph()->EmptyFixedArrayConstant(); 1044 1045 // If there is no aliasing, the arguments object elements are not special in 1046 // any way, we can just return an unmapped backing store instead. 1047 int parameter_count = shared->internal_formal_parameter_count(); 1048 if (parameter_count == 0) { 1049 return AllocateArguments(effect, control, frame_state); 1050 } 1051 1052 // Calculate number of argument values being aliased/mapped. 1053 int mapped_count = Min(argument_count, parameter_count); 1054 *has_aliased_arguments = true; 1055 1056 // Prepare an iterator over argument values recorded in the frame state. 1057 Node* const parameters = frame_state->InputAt(kFrameStateParametersInput); 1058 StateValuesAccess parameters_access(parameters); 1059 auto parameters_it = ++parameters_access.begin(); 1060 1061 // The unmapped argument values recorded in the frame state are stored yet 1062 // another indirection away and then linked into the parameter map below, 1063 // whereas mapped argument values are replaced with a hole instead. 1064 AllocationBuilder aa(jsgraph(), effect, control); 1065 aa.AllocateArray(argument_count, factory()->fixed_array_map()); 1066 for (int i = 0; i < mapped_count; ++i, ++parameters_it) { 1067 aa.Store(AccessBuilder::ForFixedArraySlot(i), jsgraph()->TheHoleConstant()); 1068 } 1069 for (int i = mapped_count; i < argument_count; ++i, ++parameters_it) { 1070 DCHECK_NOT_NULL((*parameters_it).node); 1071 aa.Store(AccessBuilder::ForFixedArraySlot(i), (*parameters_it).node); 1072 } 1073 Node* arguments = aa.Finish(); 1074 1075 // Actually allocate the backing store. 1076 AllocationBuilder a(jsgraph(), arguments, control); 1077 a.AllocateArray(mapped_count + 2, factory()->sloppy_arguments_elements_map()); 1078 a.Store(AccessBuilder::ForFixedArraySlot(0), context); 1079 a.Store(AccessBuilder::ForFixedArraySlot(1), arguments); 1080 for (int i = 0; i < mapped_count; ++i) { 1081 int idx = Context::MIN_CONTEXT_SLOTS + parameter_count - 1 - i; 1082 a.Store(AccessBuilder::ForFixedArraySlot(i + 2), jsgraph()->Constant(idx)); 1083 } 1084 return a.Finish(); 1085 } 1086 1087 Node* JSCreateLowering::AllocateElements(Node* effect, Node* control, 1088 ElementsKind elements_kind, 1089 int capacity, 1090 PretenureFlag pretenure) { 1091 DCHECK_LE(1, capacity); 1092 DCHECK_LE(capacity, JSArray::kInitialMaxFastElementArray); 1093 1094 Handle<Map> elements_map = IsFastDoubleElementsKind(elements_kind) 1095 ? factory()->fixed_double_array_map() 1096 : factory()->fixed_array_map(); 1097 ElementAccess access = IsFastDoubleElementsKind(elements_kind) 1098 ? AccessBuilder::ForFixedDoubleArrayElement() 1099 : AccessBuilder::ForFixedArrayElement(); 1100 Node* value; 1101 if (IsFastDoubleElementsKind(elements_kind)) { 1102 // Load the hole NaN pattern from the canonical location. 1103 value = effect = graph()->NewNode( 1104 simplified()->LoadField(AccessBuilder::ForExternalDoubleValue()), 1105 jsgraph()->ExternalConstant( 1106 ExternalReference::address_of_the_hole_nan()), 1107 effect, control); 1108 } else { 1109 value = jsgraph()->TheHoleConstant(); 1110 } 1111 1112 // Actually allocate the backing store. 1113 AllocationBuilder a(jsgraph(), effect, control); 1114 a.AllocateArray(capacity, elements_map, pretenure); 1115 for (int i = 0; i < capacity; ++i) { 1116 Node* index = jsgraph()->Constant(i); 1117 a.Store(access, index, value); 1118 } 1119 return a.Finish(); 1120 } 1121 1122 Node* JSCreateLowering::AllocateFastLiteral( 1123 Node* effect, Node* control, Handle<JSObject> boilerplate, 1124 AllocationSiteUsageContext* site_context) { 1125 Handle<AllocationSite> current_site(*site_context->current(), isolate()); 1126 dependencies()->AssumeTransitionStable(current_site); 1127 1128 PretenureFlag pretenure = NOT_TENURED; 1129 if (FLAG_allocation_site_pretenuring) { 1130 Handle<AllocationSite> top_site(*site_context->top(), isolate()); 1131 pretenure = top_site->GetPretenureMode(); 1132 if (current_site.is_identical_to(top_site)) { 1133 // We install a dependency for pretenuring only on the outermost literal. 1134 dependencies()->AssumeTenuringDecision(top_site); 1135 } 1136 } 1137 1138 // Setup the properties backing store. 1139 Node* properties = jsgraph()->EmptyFixedArrayConstant(); 1140 1141 // Setup the elements backing store. 1142 Node* elements = AllocateFastLiteralElements(effect, control, boilerplate, 1143 pretenure, site_context); 1144 if (elements->op()->EffectOutputCount() > 0) effect = elements; 1145 1146 // Compute the in-object properties to store first (might have effects). 1147 Handle<Map> boilerplate_map(boilerplate->map(), isolate()); 1148 ZoneVector<std::pair<FieldAccess, Node*>> inobject_fields(zone()); 1149 inobject_fields.reserve(boilerplate_map->GetInObjectProperties()); 1150 int const boilerplate_nof = boilerplate_map->NumberOfOwnDescriptors(); 1151 for (int i = 0; i < boilerplate_nof; ++i) { 1152 PropertyDetails const property_details = 1153 boilerplate_map->instance_descriptors()->GetDetails(i); 1154 if (property_details.location() != kField) continue; 1155 DCHECK_EQ(kData, property_details.kind()); 1156 Handle<Name> property_name( 1157 boilerplate_map->instance_descriptors()->GetKey(i), isolate()); 1158 FieldIndex index = FieldIndex::ForDescriptor(*boilerplate_map, i); 1159 FieldAccess access = {kTaggedBase, index.offset(), 1160 property_name, MaybeHandle<Map>(), 1161 Type::Any(), MachineType::AnyTagged(), 1162 kFullWriteBarrier}; 1163 Node* value; 1164 if (boilerplate->IsUnboxedDoubleField(index)) { 1165 access.machine_type = MachineType::Float64(); 1166 access.type = Type::Number(); 1167 value = jsgraph()->Constant(boilerplate->RawFastDoublePropertyAt(index)); 1168 } else { 1169 Handle<Object> boilerplate_value(boilerplate->RawFastPropertyAt(index), 1170 isolate()); 1171 if (boilerplate_value->IsJSObject()) { 1172 Handle<JSObject> boilerplate_object = 1173 Handle<JSObject>::cast(boilerplate_value); 1174 Handle<AllocationSite> current_site = site_context->EnterNewScope(); 1175 value = effect = AllocateFastLiteral(effect, control, 1176 boilerplate_object, site_context); 1177 site_context->ExitScope(current_site, boilerplate_object); 1178 } else if (property_details.representation().IsDouble()) { 1179 double number = Handle<HeapNumber>::cast(boilerplate_value)->value(); 1180 // Allocate a mutable HeapNumber box and store the value into it. 1181 AllocationBuilder builder(jsgraph(), effect, control); 1182 builder.Allocate(HeapNumber::kSize, pretenure); 1183 builder.Store(AccessBuilder::ForMap(), 1184 factory()->mutable_heap_number_map()); 1185 builder.Store(AccessBuilder::ForHeapNumberValue(), 1186 jsgraph()->Constant(number)); 1187 value = effect = builder.Finish(); 1188 } else if (property_details.representation().IsSmi()) { 1189 // Ensure that value is stored as smi. 1190 value = boilerplate_value->IsUninitialized(isolate()) 1191 ? jsgraph()->ZeroConstant() 1192 : jsgraph()->Constant(boilerplate_value); 1193 } else { 1194 value = jsgraph()->Constant(boilerplate_value); 1195 } 1196 } 1197 inobject_fields.push_back(std::make_pair(access, value)); 1198 } 1199 1200 // Fill slack at the end of the boilerplate object with filler maps. 1201 int const boilerplate_length = boilerplate_map->GetInObjectProperties(); 1202 for (int index = static_cast<int>(inobject_fields.size()); 1203 index < boilerplate_length; ++index) { 1204 FieldAccess access = 1205 AccessBuilder::ForJSObjectInObjectProperty(boilerplate_map, index); 1206 Node* value = jsgraph()->HeapConstant(factory()->one_pointer_filler_map()); 1207 inobject_fields.push_back(std::make_pair(access, value)); 1208 } 1209 1210 // Actually allocate and initialize the object. 1211 AllocationBuilder builder(jsgraph(), effect, control); 1212 builder.Allocate(boilerplate_map->instance_size(), pretenure, 1213 Type::OtherObject()); 1214 builder.Store(AccessBuilder::ForMap(), boilerplate_map); 1215 builder.Store(AccessBuilder::ForJSObjectProperties(), properties); 1216 builder.Store(AccessBuilder::ForJSObjectElements(), elements); 1217 if (boilerplate_map->IsJSArrayMap()) { 1218 Handle<JSArray> boilerplate_array = Handle<JSArray>::cast(boilerplate); 1219 builder.Store( 1220 AccessBuilder::ForJSArrayLength(boilerplate_array->GetElementsKind()), 1221 handle(boilerplate_array->length(), isolate())); 1222 } 1223 for (auto const& inobject_field : inobject_fields) { 1224 builder.Store(inobject_field.first, inobject_field.second); 1225 } 1226 return builder.Finish(); 1227 } 1228 1229 Node* JSCreateLowering::AllocateFastLiteralElements( 1230 Node* effect, Node* control, Handle<JSObject> boilerplate, 1231 PretenureFlag pretenure, AllocationSiteUsageContext* site_context) { 1232 Handle<FixedArrayBase> boilerplate_elements(boilerplate->elements(), 1233 isolate()); 1234 1235 // Empty or copy-on-write elements just store a constant. 1236 if (boilerplate_elements->length() == 0 || 1237 boilerplate_elements->map() == isolate()->heap()->fixed_cow_array_map()) { 1238 if (pretenure == TENURED && 1239 isolate()->heap()->InNewSpace(*boilerplate_elements)) { 1240 // If we would like to pretenure a fixed cow array, we must ensure that 1241 // the array is already in old space, otherwise we'll create too many 1242 // old-to-new-space pointers (overflowing the store buffer). 1243 boilerplate_elements = Handle<FixedArrayBase>( 1244 isolate()->factory()->CopyAndTenureFixedCOWArray( 1245 Handle<FixedArray>::cast(boilerplate_elements))); 1246 boilerplate->set_elements(*boilerplate_elements); 1247 } 1248 return jsgraph()->HeapConstant(boilerplate_elements); 1249 } 1250 1251 // Compute the elements to store first (might have effects). 1252 int const elements_length = boilerplate_elements->length(); 1253 Handle<Map> elements_map(boilerplate_elements->map(), isolate()); 1254 ZoneVector<Node*> elements_values(elements_length, zone()); 1255 if (elements_map->instance_type() == FIXED_DOUBLE_ARRAY_TYPE) { 1256 Handle<FixedDoubleArray> elements = 1257 Handle<FixedDoubleArray>::cast(boilerplate_elements); 1258 Node* the_hole_value = nullptr; 1259 for (int i = 0; i < elements_length; ++i) { 1260 if (elements->is_the_hole(i)) { 1261 if (the_hole_value == nullptr) { 1262 // Load the hole NaN pattern from the canonical location. 1263 the_hole_value = effect = graph()->NewNode( 1264 simplified()->LoadField(AccessBuilder::ForExternalDoubleValue()), 1265 jsgraph()->ExternalConstant( 1266 ExternalReference::address_of_the_hole_nan()), 1267 effect, control); 1268 } 1269 elements_values[i] = the_hole_value; 1270 } else { 1271 elements_values[i] = jsgraph()->Constant(elements->get_scalar(i)); 1272 } 1273 } 1274 } else { 1275 Handle<FixedArray> elements = 1276 Handle<FixedArray>::cast(boilerplate_elements); 1277 for (int i = 0; i < elements_length; ++i) { 1278 if (elements->is_the_hole(isolate(), i)) { 1279 elements_values[i] = jsgraph()->TheHoleConstant(); 1280 } else { 1281 Handle<Object> element_value(elements->get(i), isolate()); 1282 if (element_value->IsJSObject()) { 1283 Handle<JSObject> boilerplate_object = 1284 Handle<JSObject>::cast(element_value); 1285 Handle<AllocationSite> current_site = site_context->EnterNewScope(); 1286 elements_values[i] = effect = AllocateFastLiteral( 1287 effect, control, boilerplate_object, site_context); 1288 site_context->ExitScope(current_site, boilerplate_object); 1289 } else { 1290 elements_values[i] = jsgraph()->Constant(element_value); 1291 } 1292 } 1293 } 1294 } 1295 1296 // Allocate the backing store array and store the elements. 1297 AllocationBuilder builder(jsgraph(), effect, control); 1298 builder.AllocateArray(elements_length, elements_map, pretenure); 1299 ElementAccess const access = 1300 (elements_map->instance_type() == FIXED_DOUBLE_ARRAY_TYPE) 1301 ? AccessBuilder::ForFixedDoubleArrayElement() 1302 : AccessBuilder::ForFixedArrayElement(); 1303 for (int i = 0; i < elements_length; ++i) { 1304 builder.Store(access, jsgraph()->Constant(i), elements_values[i]); 1305 } 1306 return builder.Finish(); 1307 } 1308 1309 MaybeHandle<FeedbackVector> JSCreateLowering::GetSpecializationFeedbackVector( 1310 Node* node) { 1311 Node* const closure = NodeProperties::GetValueInput(node, 0); 1312 switch (closure->opcode()) { 1313 case IrOpcode::kHeapConstant: { 1314 Handle<HeapObject> object = OpParameter<Handle<HeapObject>>(closure); 1315 return handle(Handle<JSFunction>::cast(object)->feedback_vector()); 1316 } 1317 case IrOpcode::kParameter: { 1318 int const index = ParameterIndexOf(closure->op()); 1319 // The closure is always the last parameter to a JavaScript function, and 1320 // {Parameter} indices start at -1, so value outputs of {Start} look like 1321 // this: closure, receiver, param0, ..., paramN, context. 1322 if (index == -1) { 1323 return feedback_vector_; 1324 } 1325 break; 1326 } 1327 default: 1328 break; 1329 } 1330 return MaybeHandle<FeedbackVector>(); 1331 } 1332 1333 Factory* JSCreateLowering::factory() const { return isolate()->factory(); } 1334 1335 Graph* JSCreateLowering::graph() const { return jsgraph()->graph(); } 1336 1337 Isolate* JSCreateLowering::isolate() const { return jsgraph()->isolate(); } 1338 1339 JSOperatorBuilder* JSCreateLowering::javascript() const { 1340 return jsgraph()->javascript(); 1341 } 1342 1343 CommonOperatorBuilder* JSCreateLowering::common() const { 1344 return jsgraph()->common(); 1345 } 1346 1347 SimplifiedOperatorBuilder* JSCreateLowering::simplified() const { 1348 return jsgraph()->simplified(); 1349 } 1350 1351 MachineOperatorBuilder* JSCreateLowering::machine() const { 1352 return jsgraph()->machine(); 1353 } 1354 1355 } // namespace compiler 1356 } // namespace internal 1357 } // namespace v8 1358