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