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