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/code-factory.h" 8 #include "src/compiler/access-builder.h" 9 #include "src/compiler/allocation-builder.h" 10 #include "src/compiler/common-operator.h" 11 #include "src/compiler/compilation-dependencies.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-matchers.h" 16 #include "src/compiler/node-properties.h" 17 #include "src/compiler/node.h" 18 #include "src/compiler/operator-properties.h" 19 #include "src/compiler/simplified-operator.h" 20 #include "src/compiler/state-values-utils.h" 21 #include "src/objects-inl.h" 22 #include "src/objects/arguments.h" 23 #include "src/objects/hash-table-inl.h" 24 #include "src/objects/js-generator.h" 25 #include "src/objects/js-promise.h" 26 #include "src/objects/js-regexp-inl.h" 27 28 namespace v8 { 29 namespace internal { 30 namespace compiler { 31 32 namespace { 33 34 // Retrieves the frame state holding actual argument values. 35 Node* GetArgumentsFrameState(Node* frame_state) { 36 Node* const outer_state = NodeProperties::GetFrameStateInput(frame_state); 37 FrameStateInfo outer_state_info = FrameStateInfoOf(outer_state->op()); 38 return outer_state_info.type() == FrameStateType::kArgumentsAdaptor 39 ? outer_state 40 : frame_state; 41 } 42 43 // Checks whether allocation using the given target and new.target can be 44 // inlined. 45 bool IsAllocationInlineable(const JSFunctionRef& target, 46 const JSFunctionRef& new_target) { 47 CHECK_IMPLIES(new_target.has_initial_map(), 48 !new_target.initial_map().is_dictionary_map()); 49 return new_target.has_initial_map() && 50 new_target.initial_map().constructor_or_backpointer().equals(target); 51 } 52 53 // When initializing arrays, we'll unfold the loop if the number of 54 // elements is known to be of this type. 55 const int kElementLoopUnrollLimit = 16; 56 57 // Limits up to which context allocations are inlined. 58 const int kFunctionContextAllocationLimit = 16; 59 const int kBlockContextAllocationLimit = 16; 60 61 } // namespace 62 63 Reduction JSCreateLowering::Reduce(Node* node) { 64 DisallowHeapAccess disallow_heap_access; 65 switch (node->opcode()) { 66 case IrOpcode::kJSCreate: 67 return ReduceJSCreate(node); 68 case IrOpcode::kJSCreateArguments: 69 return ReduceJSCreateArguments(node); 70 case IrOpcode::kJSCreateArray: 71 return ReduceJSCreateArray(node); 72 case IrOpcode::kJSCreateArrayIterator: 73 return ReduceJSCreateArrayIterator(node); 74 case IrOpcode::kJSCreateBoundFunction: 75 return ReduceJSCreateBoundFunction(node); 76 case IrOpcode::kJSCreateClosure: 77 return ReduceJSCreateClosure(node); 78 case IrOpcode::kJSCreateCollectionIterator: 79 return ReduceJSCreateCollectionIterator(node); 80 case IrOpcode::kJSCreateIterResultObject: 81 return ReduceJSCreateIterResultObject(node); 82 case IrOpcode::kJSCreateStringIterator: 83 return ReduceJSCreateStringIterator(node); 84 case IrOpcode::kJSCreateKeyValueArray: 85 return ReduceJSCreateKeyValueArray(node); 86 case IrOpcode::kJSCreatePromise: 87 return ReduceJSCreatePromise(node); 88 case IrOpcode::kJSCreateLiteralArray: 89 case IrOpcode::kJSCreateLiteralObject: 90 return ReduceJSCreateLiteralArrayOrObject(node); 91 case IrOpcode::kJSCreateLiteralRegExp: 92 return ReduceJSCreateLiteralRegExp(node); 93 case IrOpcode::kJSCreateEmptyLiteralArray: 94 return ReduceJSCreateEmptyLiteralArray(node); 95 case IrOpcode::kJSCreateEmptyLiteralObject: 96 return ReduceJSCreateEmptyLiteralObject(node); 97 case IrOpcode::kJSCreateFunctionContext: 98 return ReduceJSCreateFunctionContext(node); 99 case IrOpcode::kJSCreateWithContext: 100 return ReduceJSCreateWithContext(node); 101 case IrOpcode::kJSCreateCatchContext: 102 return ReduceJSCreateCatchContext(node); 103 case IrOpcode::kJSCreateBlockContext: 104 return ReduceJSCreateBlockContext(node); 105 case IrOpcode::kJSCreateGeneratorObject: 106 return ReduceJSCreateGeneratorObject(node); 107 case IrOpcode::kJSCreateObject: 108 return ReduceJSCreateObject(node); 109 default: 110 break; 111 } 112 return NoChange(); 113 } 114 115 Reduction JSCreateLowering::ReduceJSCreate(Node* node) { 116 DCHECK_EQ(IrOpcode::kJSCreate, node->opcode()); 117 Node* const target = NodeProperties::GetValueInput(node, 0); 118 Type const target_type = NodeProperties::GetType(target); 119 Node* const new_target = NodeProperties::GetValueInput(node, 1); 120 Type const new_target_type = NodeProperties::GetType(new_target); 121 Node* const effect = NodeProperties::GetEffectInput(node); 122 Node* const control = NodeProperties::GetControlInput(node); 123 // Extract constructor and original constructor function. 124 if (!target_type.IsHeapConstant() || !new_target_type.IsHeapConstant() || 125 !target_type.AsHeapConstant()->Ref().IsJSFunction() || 126 !new_target_type.AsHeapConstant()->Ref().IsJSFunction()) { 127 return NoChange(); 128 } 129 130 JSFunctionRef constructor = 131 target_type.AsHeapConstant()->Ref().AsJSFunction(); 132 if (!constructor.IsConstructor()) return NoChange(); 133 JSFunctionRef original_constructor = 134 new_target_type.AsHeapConstant()->Ref().AsJSFunction(); 135 if (!original_constructor.IsConstructor()) return NoChange(); 136 137 // Check if we can inline the allocation. 138 if (!IsAllocationInlineable(constructor, original_constructor)) { 139 return NoChange(); 140 } 141 142 SlackTrackingPrediction slack_tracking_prediction = 143 dependencies()->DependOnInitialMapInstanceSizePrediction( 144 original_constructor); 145 MapRef initial_map = original_constructor.initial_map(); 146 147 // Emit code to allocate the JSObject instance for the 148 // {original_constructor}. 149 AllocationBuilder a(jsgraph(), effect, control); 150 a.Allocate(slack_tracking_prediction.instance_size()); 151 a.Store(AccessBuilder::ForMap(), initial_map); 152 a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), 153 jsgraph()->EmptyFixedArrayConstant()); 154 a.Store(AccessBuilder::ForJSObjectElements(), 155 jsgraph()->EmptyFixedArrayConstant()); 156 for (int i = 0; i < slack_tracking_prediction.inobject_property_count(); 157 ++i) { 158 a.Store(AccessBuilder::ForJSObjectInObjectProperty(initial_map, i), 159 jsgraph()->UndefinedConstant()); 160 } 161 162 RelaxControls(node); 163 a.FinishAndChange(node); 164 return Changed(node); 165 } 166 167 Reduction JSCreateLowering::ReduceJSCreateArguments(Node* node) { 168 DCHECK_EQ(IrOpcode::kJSCreateArguments, node->opcode()); 169 CreateArgumentsType type = CreateArgumentsTypeOf(node->op()); 170 Node* const frame_state = NodeProperties::GetFrameStateInput(node); 171 Node* const outer_state = frame_state->InputAt(kFrameStateOuterStateInput); 172 Node* const control = graph()->start(); 173 FrameStateInfo state_info = FrameStateInfoOf(frame_state->op()); 174 SharedFunctionInfoRef shared(js_heap_broker(), 175 state_info.shared_info().ToHandleChecked()); 176 177 // Use the ArgumentsAccessStub for materializing both mapped and unmapped 178 // arguments object, but only for non-inlined (i.e. outermost) frames. 179 if (outer_state->opcode() != IrOpcode::kFrameState) { 180 switch (type) { 181 case CreateArgumentsType::kMappedArguments: { 182 // TODO(mstarzinger): Duplicate parameters are not handled yet. 183 if (shared.has_duplicate_parameters()) return NoChange(); 184 Node* const callee = NodeProperties::GetValueInput(node, 0); 185 Node* const context = NodeProperties::GetContextInput(node); 186 Node* effect = NodeProperties::GetEffectInput(node); 187 Node* const arguments_frame = 188 graph()->NewNode(simplified()->ArgumentsFrame()); 189 Node* const arguments_length = graph()->NewNode( 190 simplified()->ArgumentsLength( 191 shared.internal_formal_parameter_count(), false), 192 arguments_frame); 193 // Allocate the elements backing store. 194 bool has_aliased_arguments = false; 195 Node* const elements = effect = AllocateAliasedArguments( 196 effect, control, context, arguments_frame, arguments_length, shared, 197 &has_aliased_arguments); 198 // Load the arguments object map. 199 Node* const arguments_map = jsgraph()->Constant( 200 has_aliased_arguments 201 ? native_context_ref().fast_aliased_arguments_map() 202 : native_context_ref().sloppy_arguments_map()); 203 // Actually allocate and initialize the arguments object. 204 AllocationBuilder a(jsgraph(), effect, control); 205 Node* properties = jsgraph()->EmptyFixedArrayConstant(); 206 STATIC_ASSERT(JSSloppyArgumentsObject::kSize == 5 * kPointerSize); 207 a.Allocate(JSSloppyArgumentsObject::kSize); 208 a.Store(AccessBuilder::ForMap(), arguments_map); 209 a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties); 210 a.Store(AccessBuilder::ForJSObjectElements(), elements); 211 a.Store(AccessBuilder::ForArgumentsLength(), arguments_length); 212 a.Store(AccessBuilder::ForArgumentsCallee(), callee); 213 RelaxControls(node); 214 a.FinishAndChange(node); 215 return Changed(node); 216 } 217 case CreateArgumentsType::kUnmappedArguments: { 218 Node* effect = NodeProperties::GetEffectInput(node); 219 Node* const arguments_frame = 220 graph()->NewNode(simplified()->ArgumentsFrame()); 221 Node* const arguments_length = graph()->NewNode( 222 simplified()->ArgumentsLength( 223 shared.internal_formal_parameter_count(), false), 224 arguments_frame); 225 // Allocate the elements backing store. 226 Node* const elements = effect = 227 graph()->NewNode(simplified()->NewArgumentsElements(0), 228 arguments_frame, arguments_length, effect); 229 // Load the arguments object map. 230 Node* const arguments_map = 231 jsgraph()->Constant(native_context_ref().strict_arguments_map()); 232 // Actually allocate and initialize the arguments object. 233 AllocationBuilder a(jsgraph(), effect, control); 234 Node* properties = jsgraph()->EmptyFixedArrayConstant(); 235 STATIC_ASSERT(JSStrictArgumentsObject::kSize == 4 * kPointerSize); 236 a.Allocate(JSStrictArgumentsObject::kSize); 237 a.Store(AccessBuilder::ForMap(), arguments_map); 238 a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties); 239 a.Store(AccessBuilder::ForJSObjectElements(), elements); 240 a.Store(AccessBuilder::ForArgumentsLength(), arguments_length); 241 RelaxControls(node); 242 a.FinishAndChange(node); 243 return Changed(node); 244 } 245 case CreateArgumentsType::kRestParameter: { 246 Node* effect = NodeProperties::GetEffectInput(node); 247 Node* const arguments_frame = 248 graph()->NewNode(simplified()->ArgumentsFrame()); 249 Node* const rest_length = graph()->NewNode( 250 simplified()->ArgumentsLength( 251 shared.internal_formal_parameter_count(), true), 252 arguments_frame); 253 // Allocate the elements backing store. Since NewArgumentsElements 254 // copies from the end of the arguments adapter frame, this is a suffix 255 // of the actual arguments. 256 Node* const elements = effect = 257 graph()->NewNode(simplified()->NewArgumentsElements(0), 258 arguments_frame, rest_length, effect); 259 // Load the JSArray object map. 260 Node* const jsarray_map = jsgraph()->Constant( 261 native_context_ref().js_array_packed_elements_map()); 262 // Actually allocate and initialize the jsarray. 263 AllocationBuilder a(jsgraph(), effect, control); 264 Node* properties = jsgraph()->EmptyFixedArrayConstant(); 265 STATIC_ASSERT(JSArray::kSize == 4 * kPointerSize); 266 a.Allocate(JSArray::kSize); 267 a.Store(AccessBuilder::ForMap(), jsarray_map); 268 a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties); 269 a.Store(AccessBuilder::ForJSObjectElements(), elements); 270 a.Store(AccessBuilder::ForJSArrayLength(PACKED_ELEMENTS), rest_length); 271 RelaxControls(node); 272 a.FinishAndChange(node); 273 return Changed(node); 274 } 275 } 276 UNREACHABLE(); 277 } else if (outer_state->opcode() == IrOpcode::kFrameState) { 278 // Use inline allocation for all mapped arguments objects within inlined 279 // (i.e. non-outermost) frames, independent of the object size. 280 if (type == CreateArgumentsType::kMappedArguments) { 281 Node* const callee = NodeProperties::GetValueInput(node, 0); 282 Node* const context = NodeProperties::GetContextInput(node); 283 Node* effect = NodeProperties::GetEffectInput(node); 284 // TODO(mstarzinger): Duplicate parameters are not handled yet. 285 if (shared.has_duplicate_parameters()) return NoChange(); 286 // Choose the correct frame state and frame state info depending on 287 // whether there conceptually is an arguments adaptor frame in the call 288 // chain. 289 Node* const args_state = GetArgumentsFrameState(frame_state); 290 if (args_state->InputAt(kFrameStateParametersInput)->opcode() == 291 IrOpcode::kDeadValue) { 292 // This protects against an incompletely propagated DeadValue node. 293 // If the FrameState has a DeadValue input, then this node will be 294 // pruned anyway. 295 return NoChange(); 296 } 297 FrameStateInfo args_state_info = FrameStateInfoOf(args_state->op()); 298 // Prepare element backing store to be used by arguments object. 299 bool has_aliased_arguments = false; 300 Node* const elements = AllocateAliasedArguments( 301 effect, control, args_state, context, shared, &has_aliased_arguments); 302 effect = elements->op()->EffectOutputCount() > 0 ? elements : effect; 303 // Load the arguments object map. 304 Node* const arguments_map = jsgraph()->Constant( 305 has_aliased_arguments 306 ? native_context_ref().fast_aliased_arguments_map() 307 : native_context_ref().sloppy_arguments_map()); 308 // Actually allocate and initialize the arguments object. 309 AllocationBuilder a(jsgraph(), effect, control); 310 Node* properties = jsgraph()->EmptyFixedArrayConstant(); 311 int length = args_state_info.parameter_count() - 1; // Minus receiver. 312 STATIC_ASSERT(JSSloppyArgumentsObject::kSize == 5 * kPointerSize); 313 a.Allocate(JSSloppyArgumentsObject::kSize); 314 a.Store(AccessBuilder::ForMap(), arguments_map); 315 a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties); 316 a.Store(AccessBuilder::ForJSObjectElements(), elements); 317 a.Store(AccessBuilder::ForArgumentsLength(), jsgraph()->Constant(length)); 318 a.Store(AccessBuilder::ForArgumentsCallee(), callee); 319 RelaxControls(node); 320 a.FinishAndChange(node); 321 return Changed(node); 322 } else if (type == CreateArgumentsType::kUnmappedArguments) { 323 // Use inline allocation for all unmapped arguments objects within inlined 324 // (i.e. non-outermost) frames, independent of the object size. 325 Node* effect = NodeProperties::GetEffectInput(node); 326 // Choose the correct frame state and frame state info depending on 327 // whether there conceptually is an arguments adaptor frame in the call 328 // chain. 329 Node* const args_state = GetArgumentsFrameState(frame_state); 330 if (args_state->InputAt(kFrameStateParametersInput)->opcode() == 331 IrOpcode::kDeadValue) { 332 // This protects against an incompletely propagated DeadValue node. 333 // If the FrameState has a DeadValue input, then this node will be 334 // pruned anyway. 335 return NoChange(); 336 } 337 FrameStateInfo args_state_info = FrameStateInfoOf(args_state->op()); 338 // Prepare element backing store to be used by arguments object. 339 Node* const elements = AllocateArguments(effect, control, args_state); 340 effect = elements->op()->EffectOutputCount() > 0 ? elements : effect; 341 // Load the arguments object map. 342 Node* const arguments_map = 343 jsgraph()->Constant(native_context_ref().strict_arguments_map()); 344 // Actually allocate and initialize the arguments object. 345 AllocationBuilder a(jsgraph(), effect, control); 346 Node* properties = jsgraph()->EmptyFixedArrayConstant(); 347 int length = args_state_info.parameter_count() - 1; // Minus receiver. 348 STATIC_ASSERT(JSStrictArgumentsObject::kSize == 4 * kPointerSize); 349 a.Allocate(JSStrictArgumentsObject::kSize); 350 a.Store(AccessBuilder::ForMap(), arguments_map); 351 a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties); 352 a.Store(AccessBuilder::ForJSObjectElements(), elements); 353 a.Store(AccessBuilder::ForArgumentsLength(), jsgraph()->Constant(length)); 354 RelaxControls(node); 355 a.FinishAndChange(node); 356 return Changed(node); 357 } else if (type == CreateArgumentsType::kRestParameter) { 358 int start_index = shared.internal_formal_parameter_count(); 359 // Use inline allocation for all unmapped arguments objects within inlined 360 // (i.e. non-outermost) frames, independent of the object size. 361 Node* effect = NodeProperties::GetEffectInput(node); 362 // Choose the correct frame state and frame state info depending on 363 // whether there conceptually is an arguments adaptor frame in the call 364 // chain. 365 Node* const args_state = GetArgumentsFrameState(frame_state); 366 if (args_state->InputAt(kFrameStateParametersInput)->opcode() == 367 IrOpcode::kDeadValue) { 368 // This protects against an incompletely propagated DeadValue node. 369 // If the FrameState has a DeadValue input, then this node will be 370 // pruned anyway. 371 return NoChange(); 372 } 373 FrameStateInfo args_state_info = FrameStateInfoOf(args_state->op()); 374 // Prepare element backing store to be used by the rest array. 375 Node* const elements = 376 AllocateRestArguments(effect, control, args_state, start_index); 377 effect = elements->op()->EffectOutputCount() > 0 ? elements : effect; 378 // Load the JSArray object map. 379 Node* const jsarray_map = jsgraph()->Constant( 380 native_context_ref().js_array_packed_elements_map()); 381 // Actually allocate and initialize the jsarray. 382 AllocationBuilder a(jsgraph(), effect, control); 383 Node* properties = jsgraph()->EmptyFixedArrayConstant(); 384 385 // -1 to minus receiver 386 int argument_count = args_state_info.parameter_count() - 1; 387 int length = std::max(0, argument_count - start_index); 388 STATIC_ASSERT(JSArray::kSize == 4 * kPointerSize); 389 a.Allocate(JSArray::kSize); 390 a.Store(AccessBuilder::ForMap(), jsarray_map); 391 a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties); 392 a.Store(AccessBuilder::ForJSObjectElements(), elements); 393 a.Store(AccessBuilder::ForJSArrayLength(PACKED_ELEMENTS), 394 jsgraph()->Constant(length)); 395 RelaxControls(node); 396 a.FinishAndChange(node); 397 return Changed(node); 398 } 399 } 400 401 return NoChange(); 402 } 403 404 Reduction JSCreateLowering::ReduceJSCreateGeneratorObject(Node* node) { 405 DCHECK_EQ(IrOpcode::kJSCreateGeneratorObject, node->opcode()); 406 Node* const closure = NodeProperties::GetValueInput(node, 0); 407 Node* const receiver = NodeProperties::GetValueInput(node, 1); 408 Node* const context = NodeProperties::GetContextInput(node); 409 Type const closure_type = NodeProperties::GetType(closure); 410 Node* effect = NodeProperties::GetEffectInput(node); 411 Node* const control = NodeProperties::GetControlInput(node); 412 if (closure_type.IsHeapConstant()) { 413 DCHECK(closure_type.AsHeapConstant()->Ref().IsJSFunction()); 414 JSFunctionRef js_function = 415 closure_type.AsHeapConstant()->Ref().AsJSFunction(); 416 if (!js_function.has_initial_map()) return NoChange(); 417 418 SlackTrackingPrediction slack_tracking_prediction = 419 dependencies()->DependOnInitialMapInstanceSizePrediction(js_function); 420 421 MapRef initial_map = js_function.initial_map(); 422 DCHECK(initial_map.instance_type() == JS_GENERATOR_OBJECT_TYPE || 423 initial_map.instance_type() == JS_ASYNC_GENERATOR_OBJECT_TYPE); 424 425 // Allocate a register file. 426 SharedFunctionInfoRef shared = js_function.shared(); 427 DCHECK(shared.HasBytecodeArray()); 428 int parameter_count_no_receiver = shared.internal_formal_parameter_count(); 429 int size = parameter_count_no_receiver + 430 shared.GetBytecodeArray().register_count(); 431 AllocationBuilder ab(jsgraph(), effect, control); 432 ab.AllocateArray(size, factory()->fixed_array_map()); 433 for (int i = 0; i < size; ++i) { 434 ab.Store(AccessBuilder::ForFixedArraySlot(i), 435 jsgraph()->UndefinedConstant()); 436 } 437 Node* parameters_and_registers = effect = ab.Finish(); 438 439 // Emit code to allocate the JS[Async]GeneratorObject instance. 440 AllocationBuilder a(jsgraph(), effect, control); 441 a.Allocate(slack_tracking_prediction.instance_size()); 442 Node* empty_fixed_array = jsgraph()->EmptyFixedArrayConstant(); 443 Node* undefined = jsgraph()->UndefinedConstant(); 444 a.Store(AccessBuilder::ForMap(), initial_map); 445 a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), empty_fixed_array); 446 a.Store(AccessBuilder::ForJSObjectElements(), empty_fixed_array); 447 a.Store(AccessBuilder::ForJSGeneratorObjectContext(), context); 448 a.Store(AccessBuilder::ForJSGeneratorObjectFunction(), closure); 449 a.Store(AccessBuilder::ForJSGeneratorObjectReceiver(), receiver); 450 a.Store(AccessBuilder::ForJSGeneratorObjectInputOrDebugPos(), undefined); 451 a.Store(AccessBuilder::ForJSGeneratorObjectResumeMode(), 452 jsgraph()->Constant(JSGeneratorObject::kNext)); 453 a.Store(AccessBuilder::ForJSGeneratorObjectContinuation(), 454 jsgraph()->Constant(JSGeneratorObject::kGeneratorExecuting)); 455 a.Store(AccessBuilder::ForJSGeneratorObjectParametersAndRegisters(), 456 parameters_and_registers); 457 458 if (initial_map.instance_type() == JS_ASYNC_GENERATOR_OBJECT_TYPE) { 459 a.Store(AccessBuilder::ForJSAsyncGeneratorObjectQueue(), undefined); 460 a.Store(AccessBuilder::ForJSAsyncGeneratorObjectIsAwaiting(), 461 jsgraph()->ZeroConstant()); 462 } 463 464 // Handle in-object properties, too. 465 for (int i = 0; i < slack_tracking_prediction.inobject_property_count(); 466 ++i) { 467 a.Store(AccessBuilder::ForJSObjectInObjectProperty(initial_map, i), 468 undefined); 469 } 470 a.FinishAndChange(node); 471 return Changed(node); 472 } 473 return NoChange(); 474 } 475 476 // Constructs an array with a variable {length} when no upper bound 477 // is known for the capacity. 478 Reduction JSCreateLowering::ReduceNewArray( 479 Node* node, Node* length, MapRef initial_map, PretenureFlag pretenure, 480 const SlackTrackingPrediction& slack_tracking_prediction) { 481 DCHECK_EQ(IrOpcode::kJSCreateArray, node->opcode()); 482 Node* effect = NodeProperties::GetEffectInput(node); 483 Node* control = NodeProperties::GetControlInput(node); 484 485 // Constructing an Array via new Array(N) where N is an unsigned 486 // integer, always creates a holey backing store. 487 ASSIGN_RETURN_NO_CHANGE_IF_DATA_MISSING( 488 initial_map, initial_map.AsElementsKind( 489 GetHoleyElementsKind(initial_map.elements_kind()))); 490 491 // Check that the {limit} is an unsigned integer in the valid range. 492 // This has to be kept in sync with src/runtime/runtime-array.cc, 493 // where this limit is protected. 494 length = effect = graph()->NewNode( 495 simplified()->CheckBounds(VectorSlotPair()), length, 496 jsgraph()->Constant(JSArray::kInitialMaxFastElementArray), effect, 497 control); 498 499 // Construct elements and properties for the resulting JSArray. 500 Node* elements = effect = 501 graph()->NewNode(IsDoubleElementsKind(initial_map.elements_kind()) 502 ? simplified()->NewDoubleElements(pretenure) 503 : simplified()->NewSmiOrObjectElements(pretenure), 504 length, effect, control); 505 Node* properties = jsgraph()->EmptyFixedArrayConstant(); 506 507 // Perform the allocation of the actual JSArray object. 508 AllocationBuilder a(jsgraph(), effect, control); 509 a.Allocate(slack_tracking_prediction.instance_size(), pretenure); 510 a.Store(AccessBuilder::ForMap(), initial_map); 511 a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties); 512 a.Store(AccessBuilder::ForJSObjectElements(), elements); 513 a.Store(AccessBuilder::ForJSArrayLength(initial_map.elements_kind()), length); 514 for (int i = 0; i < slack_tracking_prediction.inobject_property_count(); 515 ++i) { 516 a.Store(AccessBuilder::ForJSObjectInObjectProperty(initial_map, i), 517 jsgraph()->UndefinedConstant()); 518 } 519 RelaxControls(node); 520 a.FinishAndChange(node); 521 return Changed(node); 522 } 523 524 // Constructs an array with a variable {length} when an actual 525 // upper bound is known for the {capacity}. 526 Reduction JSCreateLowering::ReduceNewArray( 527 Node* node, Node* length, int capacity, MapRef initial_map, 528 PretenureFlag pretenure, 529 const SlackTrackingPrediction& slack_tracking_prediction) { 530 DCHECK(node->opcode() == IrOpcode::kJSCreateArray || 531 node->opcode() == IrOpcode::kJSCreateEmptyLiteralArray); 532 Node* effect = NodeProperties::GetEffectInput(node); 533 Node* control = NodeProperties::GetControlInput(node); 534 535 // Determine the appropriate elements kind. 536 ElementsKind elements_kind = initial_map.elements_kind(); 537 if (NodeProperties::GetType(length).Max() > 0.0) { 538 elements_kind = GetHoleyElementsKind(elements_kind); 539 ASSIGN_RETURN_NO_CHANGE_IF_DATA_MISSING( 540 initial_map, initial_map.AsElementsKind(elements_kind)); 541 } 542 DCHECK(IsFastElementsKind(elements_kind)); 543 544 // Setup elements and properties. 545 Node* elements; 546 if (capacity == 0) { 547 elements = jsgraph()->EmptyFixedArrayConstant(); 548 } else { 549 elements = effect = 550 AllocateElements(effect, control, elements_kind, capacity, pretenure); 551 } 552 Node* properties = jsgraph()->EmptyFixedArrayConstant(); 553 554 // Perform the allocation of the actual JSArray object. 555 AllocationBuilder a(jsgraph(), effect, control); 556 a.Allocate(slack_tracking_prediction.instance_size(), pretenure); 557 a.Store(AccessBuilder::ForMap(), initial_map); 558 a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties); 559 a.Store(AccessBuilder::ForJSObjectElements(), elements); 560 a.Store(AccessBuilder::ForJSArrayLength(elements_kind), length); 561 for (int i = 0; i < slack_tracking_prediction.inobject_property_count(); 562 ++i) { 563 a.Store(AccessBuilder::ForJSObjectInObjectProperty(initial_map, i), 564 jsgraph()->UndefinedConstant()); 565 } 566 RelaxControls(node); 567 a.FinishAndChange(node); 568 return Changed(node); 569 } 570 571 Reduction JSCreateLowering::ReduceNewArray( 572 Node* node, std::vector<Node*> values, MapRef initial_map, 573 PretenureFlag pretenure, 574 const SlackTrackingPrediction& slack_tracking_prediction) { 575 DCHECK_EQ(IrOpcode::kJSCreateArray, node->opcode()); 576 Node* effect = NodeProperties::GetEffectInput(node); 577 Node* control = NodeProperties::GetControlInput(node); 578 579 // Determine the appropriate elements kind. 580 ElementsKind elements_kind = initial_map.elements_kind(); 581 DCHECK(IsFastElementsKind(elements_kind)); 582 583 // Check {values} based on the {elements_kind}. These checks are guarded 584 // by the {elements_kind} feedback on the {site}, so it's safe to just 585 // deoptimize in this case. 586 if (IsSmiElementsKind(elements_kind)) { 587 for (auto& value : values) { 588 if (!NodeProperties::GetType(value).Is(Type::SignedSmall())) { 589 value = effect = graph()->NewNode( 590 simplified()->CheckSmi(VectorSlotPair()), value, effect, control); 591 } 592 } 593 } else if (IsDoubleElementsKind(elements_kind)) { 594 for (auto& value : values) { 595 if (!NodeProperties::GetType(value).Is(Type::Number())) { 596 value = effect = 597 graph()->NewNode(simplified()->CheckNumber(VectorSlotPair()), value, 598 effect, control); 599 } 600 // Make sure we do not store signaling NaNs into double arrays. 601 value = graph()->NewNode(simplified()->NumberSilenceNaN(), value); 602 } 603 } 604 605 // Setup elements, properties and length. 606 Node* elements = effect = 607 AllocateElements(effect, control, elements_kind, values, pretenure); 608 Node* properties = jsgraph()->EmptyFixedArrayConstant(); 609 Node* length = jsgraph()->Constant(static_cast<int>(values.size())); 610 611 // Perform the allocation of the actual JSArray object. 612 AllocationBuilder a(jsgraph(), effect, control); 613 a.Allocate(slack_tracking_prediction.instance_size(), pretenure); 614 a.Store(AccessBuilder::ForMap(), initial_map); 615 a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties); 616 a.Store(AccessBuilder::ForJSObjectElements(), elements); 617 a.Store(AccessBuilder::ForJSArrayLength(elements_kind), length); 618 for (int i = 0; i < slack_tracking_prediction.inobject_property_count(); 619 ++i) { 620 a.Store(AccessBuilder::ForJSObjectInObjectProperty(initial_map, i), 621 jsgraph()->UndefinedConstant()); 622 } 623 RelaxControls(node); 624 a.FinishAndChange(node); 625 return Changed(node); 626 } 627 628 Reduction JSCreateLowering::ReduceNewArrayToStubCall( 629 Node* node, base::Optional<AllocationSiteRef> site) { 630 CreateArrayParameters const& p = CreateArrayParametersOf(node->op()); 631 int const arity = static_cast<int>(p.arity()); 632 Node* target = NodeProperties::GetValueInput(node, 0); 633 Node* new_target = NodeProperties::GetValueInput(node, 1); 634 Type new_target_type = NodeProperties::GetType(new_target); 635 Node* type_info = 636 site ? jsgraph()->Constant(*site) : jsgraph()->UndefinedConstant(); 637 638 ElementsKind elements_kind = 639 site ? site->GetElementsKind() : GetInitialFastElementsKind(); 640 AllocationSiteOverrideMode override_mode = 641 (!site || AllocationSite::ShouldTrack(elements_kind)) 642 ? DISABLE_ALLOCATION_SITES 643 : DONT_OVERRIDE; 644 645 // The Array constructor can only trigger an observable side-effect 646 // if the new.target may be a proxy. 647 Operator::Properties const properties = 648 (new_target != target || new_target_type.Maybe(Type::Proxy())) 649 ? Operator::kNoDeopt 650 : Operator::kNoDeopt | Operator::kNoWrite; 651 652 if (arity == 0) { 653 Callable callable = CodeFactory::ArrayNoArgumentConstructor( 654 isolate(), elements_kind, override_mode); 655 auto call_descriptor = Linkage::GetStubCallDescriptor( 656 graph()->zone(), callable.descriptor(), arity + 1, 657 CallDescriptor::kNeedsFrameState, properties); 658 node->ReplaceInput(0, jsgraph()->HeapConstant(callable.code())); 659 node->InsertInput(graph()->zone(), 2, type_info); 660 node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(arity)); 661 node->InsertInput(graph()->zone(), 4, jsgraph()->UndefinedConstant()); 662 NodeProperties::ChangeOp(node, common()->Call(call_descriptor)); 663 } else if (arity == 1) { 664 // Require elements kind to "go holey". 665 Callable callable = CodeFactory::ArraySingleArgumentConstructor( 666 isolate(), GetHoleyElementsKind(elements_kind), override_mode); 667 auto call_descriptor = Linkage::GetStubCallDescriptor( 668 graph()->zone(), callable.descriptor(), arity + 1, 669 CallDescriptor::kNeedsFrameState, properties); 670 node->ReplaceInput(0, jsgraph()->HeapConstant(callable.code())); 671 node->InsertInput(graph()->zone(), 2, type_info); 672 node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(arity)); 673 node->InsertInput(graph()->zone(), 4, jsgraph()->UndefinedConstant()); 674 NodeProperties::ChangeOp(node, common()->Call(call_descriptor)); 675 } else { 676 DCHECK_GT(arity, 1); 677 Handle<Code> code = BUILTIN_CODE(isolate(), ArrayNArgumentsConstructor); 678 auto call_descriptor = Linkage::GetStubCallDescriptor( 679 graph()->zone(), ArrayNArgumentsConstructorDescriptor{}, arity + 1, 680 CallDescriptor::kNeedsFrameState); 681 node->ReplaceInput(0, jsgraph()->HeapConstant(code)); 682 node->InsertInput(graph()->zone(), 2, type_info); 683 node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(arity)); 684 node->InsertInput(graph()->zone(), 4, jsgraph()->UndefinedConstant()); 685 NodeProperties::ChangeOp(node, common()->Call(call_descriptor)); 686 } 687 return Changed(node); 688 } 689 690 Reduction JSCreateLowering::ReduceJSCreateArray(Node* node) { 691 DCHECK_EQ(IrOpcode::kJSCreateArray, node->opcode()); 692 CreateArrayParameters const& p = CreateArrayParametersOf(node->op()); 693 int const arity = static_cast<int>(p.arity()); 694 base::Optional<AllocationSiteRef> site_ref; 695 { 696 Handle<AllocationSite> site; 697 if (p.site().ToHandle(&site)) { 698 site_ref = AllocationSiteRef(js_heap_broker(), site); 699 } 700 } 701 PretenureFlag pretenure = NOT_TENURED; 702 JSFunctionRef constructor = native_context_ref().array_function(); 703 Node* target = NodeProperties::GetValueInput(node, 0); 704 Node* new_target = NodeProperties::GetValueInput(node, 1); 705 Type new_target_type = (target == new_target) 706 ? Type::HeapConstant(constructor, zone()) 707 : NodeProperties::GetType(new_target); 708 709 // Extract original constructor function. 710 if (new_target_type.IsHeapConstant() && 711 new_target_type.AsHeapConstant()->Ref().IsJSFunction()) { 712 JSFunctionRef original_constructor = 713 new_target_type.AsHeapConstant()->Ref().AsJSFunction(); 714 DCHECK(constructor.IsConstructor()); 715 DCHECK(original_constructor.IsConstructor()); 716 717 // Check if we can inline the allocation. 718 if (IsAllocationInlineable(constructor, original_constructor)) { 719 SlackTrackingPrediction slack_tracking_prediction = 720 dependencies()->DependOnInitialMapInstanceSizePrediction( 721 original_constructor); 722 MapRef initial_map = original_constructor.initial_map(); 723 724 // Tells whether we are protected by either the {site} or a 725 // protector cell to do certain speculative optimizations. 726 bool can_inline_call = false; 727 728 // Check if we have a feedback {site} on the {node}. 729 if (site_ref) { 730 ElementsKind elements_kind = site_ref->GetElementsKind(); 731 ASSIGN_RETURN_NO_CHANGE_IF_DATA_MISSING( 732 initial_map, initial_map.AsElementsKind(elements_kind)); 733 can_inline_call = site_ref->CanInlineCall(); 734 pretenure = dependencies()->DependOnPretenureMode(*site_ref); 735 dependencies()->DependOnElementsKind(*site_ref); 736 } else { 737 can_inline_call = isolate()->IsArrayConstructorIntact(); 738 } 739 740 if (arity == 0) { 741 Node* length = jsgraph()->ZeroConstant(); 742 int capacity = JSArray::kPreallocatedArrayElements; 743 return ReduceNewArray(node, length, capacity, initial_map, pretenure, 744 slack_tracking_prediction); 745 } else if (arity == 1) { 746 Node* length = NodeProperties::GetValueInput(node, 2); 747 Type length_type = NodeProperties::GetType(length); 748 if (!length_type.Maybe(Type::Number())) { 749 // Handle the single argument case, where we know that the value 750 // cannot be a valid Array length. 751 ElementsKind elements_kind = initial_map.elements_kind(); 752 elements_kind = GetMoreGeneralElementsKind( 753 elements_kind, IsHoleyElementsKind(elements_kind) 754 ? HOLEY_ELEMENTS 755 : PACKED_ELEMENTS); 756 ASSIGN_RETURN_NO_CHANGE_IF_DATA_MISSING( 757 initial_map, initial_map.AsElementsKind(elements_kind)); 758 return ReduceNewArray(node, std::vector<Node*>{length}, initial_map, 759 pretenure, slack_tracking_prediction); 760 } 761 if (length_type.Is(Type::SignedSmall()) && length_type.Min() >= 0 && 762 length_type.Max() <= kElementLoopUnrollLimit && 763 length_type.Min() == length_type.Max()) { 764 int capacity = static_cast<int>(length_type.Max()); 765 return ReduceNewArray(node, length, capacity, initial_map, pretenure, 766 slack_tracking_prediction); 767 } 768 if (length_type.Maybe(Type::UnsignedSmall()) && can_inline_call) { 769 return ReduceNewArray(node, length, initial_map, pretenure, 770 slack_tracking_prediction); 771 } 772 } else if (arity <= JSArray::kInitialMaxFastElementArray) { 773 // Gather the values to store into the newly created array. 774 bool values_all_smis = true, values_all_numbers = true, 775 values_any_nonnumber = false; 776 std::vector<Node*> values; 777 values.reserve(p.arity()); 778 for (int i = 0; i < arity; ++i) { 779 Node* value = NodeProperties::GetValueInput(node, 2 + i); 780 Type value_type = NodeProperties::GetType(value); 781 if (!value_type.Is(Type::SignedSmall())) { 782 values_all_smis = false; 783 } 784 if (!value_type.Is(Type::Number())) { 785 values_all_numbers = false; 786 } 787 if (!value_type.Maybe(Type::Number())) { 788 values_any_nonnumber = true; 789 } 790 values.push_back(value); 791 } 792 793 // Try to figure out the ideal elements kind statically. 794 ElementsKind elements_kind = initial_map.elements_kind(); 795 if (values_all_smis) { 796 // Smis can be stored with any elements kind. 797 } else if (values_all_numbers) { 798 elements_kind = GetMoreGeneralElementsKind( 799 elements_kind, IsHoleyElementsKind(elements_kind) 800 ? HOLEY_DOUBLE_ELEMENTS 801 : PACKED_DOUBLE_ELEMENTS); 802 } else if (values_any_nonnumber) { 803 elements_kind = GetMoreGeneralElementsKind( 804 elements_kind, IsHoleyElementsKind(elements_kind) 805 ? HOLEY_ELEMENTS 806 : PACKED_ELEMENTS); 807 } else if (!can_inline_call) { 808 // We have some crazy combination of types for the {values} where 809 // there's no clear decision on the elements kind statically. And 810 // we don't have a protection against deoptimization loops for the 811 // checks that are introduced in the call to ReduceNewArray, so 812 // we cannot inline this invocation of the Array constructor here. 813 return NoChange(); 814 } 815 ASSIGN_RETURN_NO_CHANGE_IF_DATA_MISSING( 816 initial_map, initial_map.AsElementsKind(elements_kind)); 817 return ReduceNewArray(node, values, initial_map, pretenure, 818 slack_tracking_prediction); 819 } 820 } 821 } 822 823 // TODO(bmeurer): Optimize the subclassing case. 824 if (target != new_target) return NoChange(); 825 826 return ReduceNewArrayToStubCall(node, site_ref); 827 } 828 829 Reduction JSCreateLowering::ReduceJSCreateArrayIterator(Node* node) { 830 DCHECK_EQ(IrOpcode::kJSCreateArrayIterator, node->opcode()); 831 CreateArrayIteratorParameters const& p = 832 CreateArrayIteratorParametersOf(node->op()); 833 Node* iterated_object = NodeProperties::GetValueInput(node, 0); 834 Node* effect = NodeProperties::GetEffectInput(node); 835 Node* control = NodeProperties::GetControlInput(node); 836 837 // Create the JSArrayIterator result. 838 AllocationBuilder a(jsgraph(), effect, control); 839 a.Allocate(JSArrayIterator::kSize, NOT_TENURED, Type::OtherObject()); 840 a.Store(AccessBuilder::ForMap(), 841 native_context_ref().initial_array_iterator_map()); 842 a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), 843 jsgraph()->EmptyFixedArrayConstant()); 844 a.Store(AccessBuilder::ForJSObjectElements(), 845 jsgraph()->EmptyFixedArrayConstant()); 846 a.Store(AccessBuilder::ForJSArrayIteratorIteratedObject(), iterated_object); 847 a.Store(AccessBuilder::ForJSArrayIteratorNextIndex(), 848 jsgraph()->ZeroConstant()); 849 a.Store(AccessBuilder::ForJSArrayIteratorKind(), 850 jsgraph()->Constant(static_cast<int>(p.kind()))); 851 RelaxControls(node); 852 a.FinishAndChange(node); 853 return Changed(node); 854 } 855 856 namespace { 857 858 MapRef MapForCollectionIterationKind(const NativeContextRef& native_context, 859 CollectionKind collection_kind, 860 IterationKind iteration_kind) { 861 switch (collection_kind) { 862 case CollectionKind::kSet: 863 switch (iteration_kind) { 864 case IterationKind::kKeys: 865 UNREACHABLE(); 866 case IterationKind::kValues: 867 return native_context.set_value_iterator_map(); 868 case IterationKind::kEntries: 869 return native_context.set_key_value_iterator_map(); 870 } 871 break; 872 case CollectionKind::kMap: 873 switch (iteration_kind) { 874 case IterationKind::kKeys: 875 return native_context.map_key_iterator_map(); 876 case IterationKind::kValues: 877 return native_context.map_value_iterator_map(); 878 case IterationKind::kEntries: 879 return native_context.map_key_value_iterator_map(); 880 } 881 break; 882 } 883 UNREACHABLE(); 884 } 885 886 } // namespace 887 888 Reduction JSCreateLowering::ReduceJSCreateCollectionIterator(Node* node) { 889 DCHECK_EQ(IrOpcode::kJSCreateCollectionIterator, node->opcode()); 890 CreateCollectionIteratorParameters const& p = 891 CreateCollectionIteratorParametersOf(node->op()); 892 Node* iterated_object = NodeProperties::GetValueInput(node, 0); 893 Node* effect = NodeProperties::GetEffectInput(node); 894 Node* control = NodeProperties::GetControlInput(node); 895 896 // Load the OrderedHashTable from the {receiver}. 897 Node* table = effect = graph()->NewNode( 898 simplified()->LoadField(AccessBuilder::ForJSCollectionTable()), 899 iterated_object, effect, control); 900 901 // Create the JSArrayIterator result. 902 AllocationBuilder a(jsgraph(), effect, control); 903 a.Allocate(JSCollectionIterator::kSize, NOT_TENURED, Type::OtherObject()); 904 a.Store(AccessBuilder::ForMap(), 905 MapForCollectionIterationKind( 906 native_context_ref(), p.collection_kind(), p.iteration_kind())); 907 a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), 908 jsgraph()->EmptyFixedArrayConstant()); 909 a.Store(AccessBuilder::ForJSObjectElements(), 910 jsgraph()->EmptyFixedArrayConstant()); 911 a.Store(AccessBuilder::ForJSCollectionIteratorTable(), table); 912 a.Store(AccessBuilder::ForJSCollectionIteratorIndex(), 913 jsgraph()->ZeroConstant()); 914 RelaxControls(node); 915 a.FinishAndChange(node); 916 return Changed(node); 917 } 918 919 Reduction JSCreateLowering::ReduceJSCreateBoundFunction(Node* node) { 920 DCHECK_EQ(IrOpcode::kJSCreateBoundFunction, node->opcode()); 921 CreateBoundFunctionParameters const& p = 922 CreateBoundFunctionParametersOf(node->op()); 923 int const arity = static_cast<int>(p.arity()); 924 MapRef const map(js_heap_broker(), p.map()); 925 Node* bound_target_function = NodeProperties::GetValueInput(node, 0); 926 Node* bound_this = NodeProperties::GetValueInput(node, 1); 927 Node* effect = NodeProperties::GetEffectInput(node); 928 Node* control = NodeProperties::GetControlInput(node); 929 930 // Create the [[BoundArguments]] for the result. 931 Node* bound_arguments = jsgraph()->EmptyFixedArrayConstant(); 932 if (arity > 0) { 933 AllocationBuilder a(jsgraph(), effect, control); 934 a.AllocateArray(arity, factory()->fixed_array_map()); 935 for (int i = 0; i < arity; ++i) { 936 a.Store(AccessBuilder::ForFixedArraySlot(i), 937 NodeProperties::GetValueInput(node, 2 + i)); 938 } 939 bound_arguments = effect = a.Finish(); 940 } 941 942 // Create the JSBoundFunction result. 943 AllocationBuilder a(jsgraph(), effect, control); 944 a.Allocate(JSBoundFunction::kSize, NOT_TENURED, Type::BoundFunction()); 945 a.Store(AccessBuilder::ForMap(), map); 946 a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), 947 jsgraph()->EmptyFixedArrayConstant()); 948 a.Store(AccessBuilder::ForJSObjectElements(), 949 jsgraph()->EmptyFixedArrayConstant()); 950 a.Store(AccessBuilder::ForJSBoundFunctionBoundTargetFunction(), 951 bound_target_function); 952 a.Store(AccessBuilder::ForJSBoundFunctionBoundThis(), bound_this); 953 a.Store(AccessBuilder::ForJSBoundFunctionBoundArguments(), bound_arguments); 954 RelaxControls(node); 955 a.FinishAndChange(node); 956 return Changed(node); 957 } 958 959 Reduction JSCreateLowering::ReduceJSCreateClosure(Node* node) { 960 DCHECK_EQ(IrOpcode::kJSCreateClosure, node->opcode()); 961 CreateClosureParameters const& p = CreateClosureParametersOf(node->op()); 962 SharedFunctionInfoRef shared(js_heap_broker(), p.shared_info()); 963 HeapObjectRef feedback_cell(js_heap_broker(), p.feedback_cell()); 964 HeapObjectRef code(js_heap_broker(), p.code()); 965 Node* effect = NodeProperties::GetEffectInput(node); 966 Node* control = NodeProperties::GetControlInput(node); 967 Node* context = NodeProperties::GetContextInput(node); 968 969 // Use inline allocation of closures only for instantiation sites that have 970 // seen more than one instantiation, this simplifies the generated code and 971 // also serves as a heuristic of which allocation sites benefit from it. 972 if (!feedback_cell.map().equals( 973 MapRef(js_heap_broker(), factory()->many_closures_cell_map()))) { 974 return NoChange(); 975 } 976 977 MapRef function_map = 978 native_context_ref().GetFunctionMapFromIndex(shared.function_map_index()); 979 DCHECK(!function_map.IsInobjectSlackTrackingInProgress()); 980 DCHECK(!function_map.is_dictionary_map()); 981 982 // TODO(turbofan): We should use the pretenure flag from {p} here, 983 // but currently the heuristic in the parser works against us, as 984 // it marks closures like 985 // 986 // args[l] = function(...) { ... } 987 // 988 // for old-space allocation, which doesn't always make sense. For 989 // example in case of the bluebird-parallel benchmark, where this 990 // is a core part of the *promisify* logic (see crbug.com/810132). 991 PretenureFlag pretenure = NOT_TENURED; 992 993 // Emit code to allocate the JSFunction instance. 994 STATIC_ASSERT(JSFunction::kSizeWithoutPrototype == 7 * kPointerSize); 995 AllocationBuilder a(jsgraph(), effect, control); 996 a.Allocate(function_map.instance_size(), pretenure, Type::Function()); 997 a.Store(AccessBuilder::ForMap(), function_map); 998 a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), 999 jsgraph()->EmptyFixedArrayConstant()); 1000 a.Store(AccessBuilder::ForJSObjectElements(), 1001 jsgraph()->EmptyFixedArrayConstant()); 1002 a.Store(AccessBuilder::ForJSFunctionSharedFunctionInfo(), shared); 1003 a.Store(AccessBuilder::ForJSFunctionContext(), context); 1004 a.Store(AccessBuilder::ForJSFunctionFeedbackCell(), feedback_cell); 1005 a.Store(AccessBuilder::ForJSFunctionCode(), code); 1006 STATIC_ASSERT(JSFunction::kSizeWithoutPrototype == 7 * kPointerSize); 1007 if (function_map.has_prototype_slot()) { 1008 a.Store(AccessBuilder::ForJSFunctionPrototypeOrInitialMap(), 1009 jsgraph()->TheHoleConstant()); 1010 STATIC_ASSERT(JSFunction::kSizeWithPrototype == 8 * kPointerSize); 1011 } 1012 for (int i = 0; i < function_map.GetInObjectProperties(); i++) { 1013 a.Store(AccessBuilder::ForJSObjectInObjectProperty(function_map, i), 1014 jsgraph()->UndefinedConstant()); 1015 } 1016 RelaxControls(node); 1017 a.FinishAndChange(node); 1018 return Changed(node); 1019 } 1020 1021 Reduction JSCreateLowering::ReduceJSCreateIterResultObject(Node* node) { 1022 DCHECK_EQ(IrOpcode::kJSCreateIterResultObject, node->opcode()); 1023 Node* value = NodeProperties::GetValueInput(node, 0); 1024 Node* done = NodeProperties::GetValueInput(node, 1); 1025 Node* effect = NodeProperties::GetEffectInput(node); 1026 1027 Node* iterator_result_map = 1028 jsgraph()->Constant(native_context_ref().iterator_result_map()); 1029 1030 // Emit code to allocate the JSIteratorResult instance. 1031 AllocationBuilder a(jsgraph(), effect, graph()->start()); 1032 a.Allocate(JSIteratorResult::kSize); 1033 a.Store(AccessBuilder::ForMap(), iterator_result_map); 1034 a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), 1035 jsgraph()->EmptyFixedArrayConstant()); 1036 a.Store(AccessBuilder::ForJSObjectElements(), 1037 jsgraph()->EmptyFixedArrayConstant()); 1038 a.Store(AccessBuilder::ForJSIteratorResultValue(), value); 1039 a.Store(AccessBuilder::ForJSIteratorResultDone(), done); 1040 STATIC_ASSERT(JSIteratorResult::kSize == 5 * kPointerSize); 1041 a.FinishAndChange(node); 1042 return Changed(node); 1043 } 1044 1045 Reduction JSCreateLowering::ReduceJSCreateStringIterator(Node* node) { 1046 DCHECK_EQ(IrOpcode::kJSCreateStringIterator, node->opcode()); 1047 Node* string = NodeProperties::GetValueInput(node, 0); 1048 Node* effect = NodeProperties::GetEffectInput(node); 1049 1050 Node* map = jsgraph()->Constant(native_context_ref().string_iterator_map()); 1051 // Allocate new iterator and attach the iterator to this string. 1052 AllocationBuilder a(jsgraph(), effect, graph()->start()); 1053 a.Allocate(JSStringIterator::kSize, NOT_TENURED, Type::OtherObject()); 1054 a.Store(AccessBuilder::ForMap(), map); 1055 a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), 1056 jsgraph()->EmptyFixedArrayConstant()); 1057 a.Store(AccessBuilder::ForJSObjectElements(), 1058 jsgraph()->EmptyFixedArrayConstant()); 1059 a.Store(AccessBuilder::ForJSStringIteratorString(), string); 1060 a.Store(AccessBuilder::ForJSStringIteratorIndex(), jsgraph()->SmiConstant(0)); 1061 STATIC_ASSERT(JSIteratorResult::kSize == 5 * kPointerSize); 1062 a.FinishAndChange(node); 1063 return Changed(node); 1064 } 1065 1066 Reduction JSCreateLowering::ReduceJSCreateKeyValueArray(Node* node) { 1067 DCHECK_EQ(IrOpcode::kJSCreateKeyValueArray, node->opcode()); 1068 Node* key = NodeProperties::GetValueInput(node, 0); 1069 Node* value = NodeProperties::GetValueInput(node, 1); 1070 Node* effect = NodeProperties::GetEffectInput(node); 1071 1072 Node* array_map = 1073 jsgraph()->Constant(native_context_ref().js_array_packed_elements_map()); 1074 Node* properties = jsgraph()->EmptyFixedArrayConstant(); 1075 Node* length = jsgraph()->Constant(2); 1076 1077 AllocationBuilder aa(jsgraph(), effect, graph()->start()); 1078 aa.AllocateArray(2, factory()->fixed_array_map()); 1079 aa.Store(AccessBuilder::ForFixedArrayElement(PACKED_ELEMENTS), 1080 jsgraph()->ZeroConstant(), key); 1081 aa.Store(AccessBuilder::ForFixedArrayElement(PACKED_ELEMENTS), 1082 jsgraph()->OneConstant(), value); 1083 Node* elements = aa.Finish(); 1084 1085 AllocationBuilder a(jsgraph(), elements, graph()->start()); 1086 a.Allocate(JSArray::kSize); 1087 a.Store(AccessBuilder::ForMap(), array_map); 1088 a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties); 1089 a.Store(AccessBuilder::ForJSObjectElements(), elements); 1090 a.Store(AccessBuilder::ForJSArrayLength(PACKED_ELEMENTS), length); 1091 STATIC_ASSERT(JSArray::kSize == 4 * kPointerSize); 1092 a.FinishAndChange(node); 1093 return Changed(node); 1094 } 1095 1096 Reduction JSCreateLowering::ReduceJSCreatePromise(Node* node) { 1097 DCHECK_EQ(IrOpcode::kJSCreatePromise, node->opcode()); 1098 Node* effect = NodeProperties::GetEffectInput(node); 1099 1100 MapRef promise_map = native_context_ref().promise_function().initial_map(); 1101 1102 AllocationBuilder a(jsgraph(), effect, graph()->start()); 1103 a.Allocate(promise_map.instance_size()); 1104 a.Store(AccessBuilder::ForMap(), promise_map); 1105 a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), 1106 jsgraph()->EmptyFixedArrayConstant()); 1107 a.Store(AccessBuilder::ForJSObjectElements(), 1108 jsgraph()->EmptyFixedArrayConstant()); 1109 a.Store(AccessBuilder::ForJSObjectOffset(JSPromise::kReactionsOrResultOffset), 1110 jsgraph()->ZeroConstant()); 1111 STATIC_ASSERT(v8::Promise::kPending == 0); 1112 a.Store(AccessBuilder::ForJSObjectOffset(JSPromise::kFlagsOffset), 1113 jsgraph()->ZeroConstant()); 1114 STATIC_ASSERT(JSPromise::kSize == 5 * kPointerSize); 1115 for (int i = 0; i < v8::Promise::kEmbedderFieldCount; ++i) { 1116 a.Store( 1117 AccessBuilder::ForJSObjectOffset(JSPromise::kSize + i * kPointerSize), 1118 jsgraph()->ZeroConstant()); 1119 } 1120 a.FinishAndChange(node); 1121 return Changed(node); 1122 } 1123 1124 Reduction JSCreateLowering::ReduceJSCreateLiteralArrayOrObject(Node* node) { 1125 DCHECK(node->opcode() == IrOpcode::kJSCreateLiteralArray || 1126 node->opcode() == IrOpcode::kJSCreateLiteralObject); 1127 CreateLiteralParameters const& p = CreateLiteralParametersOf(node->op()); 1128 Node* effect = NodeProperties::GetEffectInput(node); 1129 Node* control = NodeProperties::GetControlInput(node); 1130 1131 FeedbackVectorRef feedback_vector(js_heap_broker(), p.feedback().vector()); 1132 ObjectRef feedback = feedback_vector.get(p.feedback().slot()); 1133 if (feedback.IsAllocationSite()) { 1134 AllocationSiteRef site = feedback.AsAllocationSite(); 1135 if (site.IsFastLiteral()) { 1136 PretenureFlag pretenure = NOT_TENURED; 1137 if (FLAG_allocation_site_pretenuring) { 1138 pretenure = dependencies()->DependOnPretenureMode(site); 1139 } 1140 dependencies()->DependOnElementsKinds(site); 1141 JSObjectRef boilerplate = site.boilerplate().value(); 1142 Node* value = effect = 1143 AllocateFastLiteral(effect, control, boilerplate, pretenure); 1144 ReplaceWithValue(node, value, effect, control); 1145 return Replace(value); 1146 } 1147 } 1148 return NoChange(); 1149 } 1150 1151 Reduction JSCreateLowering::ReduceJSCreateEmptyLiteralArray(Node* node) { 1152 DCHECK_EQ(IrOpcode::kJSCreateEmptyLiteralArray, node->opcode()); 1153 FeedbackParameter const& p = FeedbackParameterOf(node->op()); 1154 FeedbackVectorRef fv(js_heap_broker(), p.feedback().vector()); 1155 ObjectRef feedback = fv.get(p.feedback().slot()); 1156 if (feedback.IsAllocationSite()) { 1157 AllocationSiteRef site = feedback.AsAllocationSite(); 1158 DCHECK(!site.PointsToLiteral()); 1159 MapRef initial_map = 1160 native_context_ref().GetInitialJSArrayMap(site.GetElementsKind()); 1161 PretenureFlag const pretenure = dependencies()->DependOnPretenureMode(site); 1162 dependencies()->DependOnElementsKind(site); 1163 Node* length = jsgraph()->ZeroConstant(); 1164 DCHECK(!initial_map.IsInobjectSlackTrackingInProgress()); 1165 SlackTrackingPrediction slack_tracking_prediction( 1166 initial_map, initial_map.instance_size()); 1167 return ReduceNewArray(node, length, 0, initial_map, pretenure, 1168 slack_tracking_prediction); 1169 } 1170 return NoChange(); 1171 } 1172 1173 Reduction JSCreateLowering::ReduceJSCreateEmptyLiteralObject(Node* node) { 1174 DCHECK_EQ(IrOpcode::kJSCreateEmptyLiteralObject, node->opcode()); 1175 Node* effect = NodeProperties::GetEffectInput(node); 1176 Node* control = NodeProperties::GetControlInput(node); 1177 1178 // Retrieve the initial map for the object. 1179 MapRef map = native_context_ref().object_function().initial_map(); 1180 DCHECK(!map.is_dictionary_map()); 1181 DCHECK(!map.IsInobjectSlackTrackingInProgress()); 1182 Node* js_object_map = jsgraph()->Constant(map); 1183 1184 // Setup elements and properties. 1185 Node* elements = jsgraph()->EmptyFixedArrayConstant(); 1186 Node* properties = jsgraph()->EmptyFixedArrayConstant(); 1187 1188 // Perform the allocation of the actual JSArray object. 1189 AllocationBuilder a(jsgraph(), effect, control); 1190 a.Allocate(map.instance_size()); 1191 a.Store(AccessBuilder::ForMap(), js_object_map); 1192 a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties); 1193 a.Store(AccessBuilder::ForJSObjectElements(), elements); 1194 for (int i = 0; i < map.GetInObjectProperties(); i++) { 1195 a.Store(AccessBuilder::ForJSObjectInObjectProperty(map, i), 1196 jsgraph()->UndefinedConstant()); 1197 } 1198 1199 RelaxControls(node); 1200 a.FinishAndChange(node); 1201 return Changed(node); 1202 } 1203 1204 Reduction JSCreateLowering::ReduceJSCreateLiteralRegExp(Node* node) { 1205 DCHECK_EQ(IrOpcode::kJSCreateLiteralRegExp, node->opcode()); 1206 CreateLiteralParameters const& p = CreateLiteralParametersOf(node->op()); 1207 Node* effect = NodeProperties::GetEffectInput(node); 1208 Node* control = NodeProperties::GetControlInput(node); 1209 1210 FeedbackVectorRef feedback_vector(js_heap_broker(), p.feedback().vector()); 1211 ObjectRef feedback = feedback_vector.get(p.feedback().slot()); 1212 if (feedback.IsJSRegExp()) { 1213 JSRegExpRef boilerplate = feedback.AsJSRegExp(); 1214 Node* value = effect = AllocateLiteralRegExp(effect, control, boilerplate); 1215 ReplaceWithValue(node, value, effect, control); 1216 return Replace(value); 1217 } 1218 return NoChange(); 1219 } 1220 1221 Reduction JSCreateLowering::ReduceJSCreateFunctionContext(Node* node) { 1222 DCHECK_EQ(IrOpcode::kJSCreateFunctionContext, node->opcode()); 1223 const CreateFunctionContextParameters& parameters = 1224 CreateFunctionContextParametersOf(node->op()); 1225 ScopeInfoRef scope_info(js_heap_broker(), parameters.scope_info()); 1226 int slot_count = parameters.slot_count(); 1227 ScopeType scope_type = parameters.scope_type(); 1228 1229 // Use inline allocation for function contexts up to a size limit. 1230 if (slot_count < kFunctionContextAllocationLimit) { 1231 // JSCreateFunctionContext[slot_count < limit]](fun) 1232 Node* effect = NodeProperties::GetEffectInput(node); 1233 Node* control = NodeProperties::GetControlInput(node); 1234 Node* context = NodeProperties::GetContextInput(node); 1235 Node* extension = jsgraph()->TheHoleConstant(); 1236 AllocationBuilder a(jsgraph(), effect, control); 1237 STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == 4); // Ensure fully covered. 1238 int context_length = slot_count + Context::MIN_CONTEXT_SLOTS; 1239 Handle<Map> map; 1240 switch (scope_type) { 1241 case EVAL_SCOPE: 1242 map = factory()->eval_context_map(); 1243 break; 1244 case FUNCTION_SCOPE: 1245 map = factory()->function_context_map(); 1246 break; 1247 default: 1248 UNREACHABLE(); 1249 } 1250 a.AllocateContext(context_length, map); 1251 a.Store(AccessBuilder::ForContextSlot(Context::SCOPE_INFO_INDEX), 1252 scope_info); 1253 a.Store(AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX), context); 1254 a.Store(AccessBuilder::ForContextSlot(Context::EXTENSION_INDEX), extension); 1255 a.Store(AccessBuilder::ForContextSlot(Context::NATIVE_CONTEXT_INDEX), 1256 jsgraph()->HeapConstant(native_context())); 1257 for (int i = Context::MIN_CONTEXT_SLOTS; i < context_length; ++i) { 1258 a.Store(AccessBuilder::ForContextSlot(i), jsgraph()->UndefinedConstant()); 1259 } 1260 RelaxControls(node); 1261 a.FinishAndChange(node); 1262 return Changed(node); 1263 } 1264 1265 return NoChange(); 1266 } 1267 1268 Reduction JSCreateLowering::ReduceJSCreateWithContext(Node* node) { 1269 DCHECK_EQ(IrOpcode::kJSCreateWithContext, node->opcode()); 1270 ScopeInfoRef scope_info(js_heap_broker(), ScopeInfoOf(node->op())); 1271 Node* extension = NodeProperties::GetValueInput(node, 0); 1272 Node* effect = NodeProperties::GetEffectInput(node); 1273 Node* control = NodeProperties::GetControlInput(node); 1274 Node* context = NodeProperties::GetContextInput(node); 1275 1276 AllocationBuilder a(jsgraph(), effect, control); 1277 STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == 4); // Ensure fully covered. 1278 a.AllocateContext(Context::MIN_CONTEXT_SLOTS, factory()->with_context_map()); 1279 a.Store(AccessBuilder::ForContextSlot(Context::SCOPE_INFO_INDEX), scope_info); 1280 a.Store(AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX), context); 1281 a.Store(AccessBuilder::ForContextSlot(Context::EXTENSION_INDEX), extension); 1282 a.Store(AccessBuilder::ForContextSlot(Context::NATIVE_CONTEXT_INDEX), 1283 jsgraph()->HeapConstant(native_context())); 1284 RelaxControls(node); 1285 a.FinishAndChange(node); 1286 return Changed(node); 1287 } 1288 1289 Reduction JSCreateLowering::ReduceJSCreateCatchContext(Node* node) { 1290 DCHECK_EQ(IrOpcode::kJSCreateCatchContext, node->opcode()); 1291 ScopeInfoRef scope_info(js_heap_broker(), ScopeInfoOf(node->op())); 1292 Node* exception = NodeProperties::GetValueInput(node, 0); 1293 Node* effect = NodeProperties::GetEffectInput(node); 1294 Node* control = NodeProperties::GetControlInput(node); 1295 Node* context = NodeProperties::GetContextInput(node); 1296 Node* extension = jsgraph()->TheHoleConstant(); 1297 1298 AllocationBuilder a(jsgraph(), effect, control); 1299 STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == 4); // Ensure fully covered. 1300 a.AllocateContext(Context::MIN_CONTEXT_SLOTS + 1, 1301 factory()->catch_context_map()); 1302 a.Store(AccessBuilder::ForContextSlot(Context::SCOPE_INFO_INDEX), scope_info); 1303 a.Store(AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX), context); 1304 a.Store(AccessBuilder::ForContextSlot(Context::EXTENSION_INDEX), extension); 1305 a.Store(AccessBuilder::ForContextSlot(Context::NATIVE_CONTEXT_INDEX), 1306 jsgraph()->HeapConstant(native_context())); 1307 a.Store(AccessBuilder::ForContextSlot(Context::THROWN_OBJECT_INDEX), 1308 exception); 1309 RelaxControls(node); 1310 a.FinishAndChange(node); 1311 return Changed(node); 1312 } 1313 1314 Reduction JSCreateLowering::ReduceJSCreateBlockContext(Node* node) { 1315 DCHECK_EQ(IrOpcode::kJSCreateBlockContext, node->opcode()); 1316 ScopeInfoRef scope_info(js_heap_broker(), ScopeInfoOf(node->op())); 1317 int const context_length = scope_info.ContextLength(); 1318 1319 // Use inline allocation for block contexts up to a size limit. 1320 if (context_length < kBlockContextAllocationLimit) { 1321 // JSCreateBlockContext[scope[length < limit]](fun) 1322 Node* effect = NodeProperties::GetEffectInput(node); 1323 Node* control = NodeProperties::GetControlInput(node); 1324 Node* context = NodeProperties::GetContextInput(node); 1325 Node* extension = jsgraph()->TheHoleConstant(); 1326 1327 AllocationBuilder a(jsgraph(), effect, control); 1328 STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == 4); // Ensure fully covered. 1329 a.AllocateContext(context_length, factory()->block_context_map()); 1330 a.Store(AccessBuilder::ForContextSlot(Context::SCOPE_INFO_INDEX), 1331 scope_info); 1332 a.Store(AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX), context); 1333 a.Store(AccessBuilder::ForContextSlot(Context::EXTENSION_INDEX), extension); 1334 a.Store(AccessBuilder::ForContextSlot(Context::NATIVE_CONTEXT_INDEX), 1335 jsgraph()->HeapConstant(native_context())); 1336 for (int i = Context::MIN_CONTEXT_SLOTS; i < context_length; ++i) { 1337 a.Store(AccessBuilder::ForContextSlot(i), jsgraph()->UndefinedConstant()); 1338 } 1339 RelaxControls(node); 1340 a.FinishAndChange(node); 1341 return Changed(node); 1342 } 1343 1344 return NoChange(); 1345 } 1346 1347 Reduction JSCreateLowering::ReduceJSCreateObject(Node* node) { 1348 DCHECK_EQ(IrOpcode::kJSCreateObject, node->opcode()); 1349 Node* effect = NodeProperties::GetEffectInput(node); 1350 Node* control = NodeProperties::GetControlInput(node); 1351 Node* prototype = NodeProperties::GetValueInput(node, 0); 1352 Type prototype_type = NodeProperties::GetType(prototype); 1353 if (!prototype_type.IsHeapConstant()) return NoChange(); 1354 1355 HeapObjectRef prototype_const = prototype_type.AsHeapConstant()->Ref(); 1356 auto maybe_instance_map = prototype_const.TryGetObjectCreateMap(); 1357 if (!maybe_instance_map) return NoChange(); 1358 MapRef instance_map = maybe_instance_map.value(); 1359 1360 Node* properties = jsgraph()->EmptyFixedArrayConstant(); 1361 if (instance_map.is_dictionary_map()) { 1362 DCHECK_EQ(prototype_const.type().oddball_type(), OddballType::kNull); 1363 // Allocate an empty NameDictionary as backing store for the properties. 1364 Handle<Map> map = isolate()->factory()->name_dictionary_map(); 1365 int capacity = 1366 NameDictionary::ComputeCapacity(NameDictionary::kInitialCapacity); 1367 DCHECK(base::bits::IsPowerOfTwo(capacity)); 1368 int length = NameDictionary::EntryToIndex(capacity); 1369 int size = NameDictionary::SizeFor(length); 1370 1371 AllocationBuilder a(jsgraph(), effect, control); 1372 a.Allocate(size, NOT_TENURED, Type::Any()); 1373 a.Store(AccessBuilder::ForMap(), map); 1374 // Initialize FixedArray fields. 1375 a.Store(AccessBuilder::ForFixedArrayLength(), 1376 jsgraph()->SmiConstant(length)); 1377 // Initialize HashTable fields. 1378 a.Store(AccessBuilder::ForHashTableBaseNumberOfElements(), 1379 jsgraph()->SmiConstant(0)); 1380 a.Store(AccessBuilder::ForHashTableBaseNumberOfDeletedElement(), 1381 jsgraph()->SmiConstant(0)); 1382 a.Store(AccessBuilder::ForHashTableBaseCapacity(), 1383 jsgraph()->SmiConstant(capacity)); 1384 // Initialize Dictionary fields. 1385 a.Store(AccessBuilder::ForDictionaryNextEnumerationIndex(), 1386 jsgraph()->SmiConstant(PropertyDetails::kInitialIndex)); 1387 a.Store(AccessBuilder::ForDictionaryObjectHashIndex(), 1388 jsgraph()->SmiConstant(PropertyArray::kNoHashSentinel)); 1389 // Initialize the Properties fields. 1390 Node* undefined = jsgraph()->UndefinedConstant(); 1391 STATIC_ASSERT(NameDictionary::kElementsStartIndex == 1392 NameDictionary::kObjectHashIndex + 1); 1393 for (int index = NameDictionary::kElementsStartIndex; index < length; 1394 index++) { 1395 a.Store(AccessBuilder::ForFixedArraySlot(index, kNoWriteBarrier), 1396 undefined); 1397 } 1398 properties = effect = a.Finish(); 1399 } 1400 1401 int const instance_size = instance_map.instance_size(); 1402 if (instance_size > kMaxRegularHeapObjectSize) return NoChange(); 1403 CHECK(!instance_map.IsInobjectSlackTrackingInProgress()); 1404 1405 // Emit code to allocate the JSObject instance for the given 1406 // {instance_map}. 1407 AllocationBuilder a(jsgraph(), effect, control); 1408 a.Allocate(instance_size, NOT_TENURED, Type::Any()); 1409 a.Store(AccessBuilder::ForMap(), instance_map); 1410 a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties); 1411 a.Store(AccessBuilder::ForJSObjectElements(), 1412 jsgraph()->EmptyFixedArrayConstant()); 1413 // Initialize Object fields. 1414 Node* undefined = jsgraph()->UndefinedConstant(); 1415 for (int offset = JSObject::kHeaderSize; offset < instance_size; 1416 offset += kPointerSize) { 1417 a.Store(AccessBuilder::ForJSObjectOffset(offset, kNoWriteBarrier), 1418 undefined); 1419 } 1420 Node* value = effect = a.Finish(); 1421 1422 ReplaceWithValue(node, value, effect, control); 1423 return Replace(value); 1424 } 1425 1426 // Helper that allocates a FixedArray holding argument values recorded in the 1427 // given {frame_state}. Serves as backing store for JSCreateArguments nodes. 1428 Node* JSCreateLowering::AllocateArguments(Node* effect, Node* control, 1429 Node* frame_state) { 1430 FrameStateInfo state_info = FrameStateInfoOf(frame_state->op()); 1431 int argument_count = state_info.parameter_count() - 1; // Minus receiver. 1432 if (argument_count == 0) return jsgraph()->EmptyFixedArrayConstant(); 1433 1434 // Prepare an iterator over argument values recorded in the frame state. 1435 Node* const parameters = frame_state->InputAt(kFrameStateParametersInput); 1436 StateValuesAccess parameters_access(parameters); 1437 auto parameters_it = ++parameters_access.begin(); 1438 1439 // Actually allocate the backing store. 1440 AllocationBuilder a(jsgraph(), effect, control); 1441 a.AllocateArray(argument_count, factory()->fixed_array_map()); 1442 for (int i = 0; i < argument_count; ++i, ++parameters_it) { 1443 DCHECK_NOT_NULL((*parameters_it).node); 1444 a.Store(AccessBuilder::ForFixedArraySlot(i), (*parameters_it).node); 1445 } 1446 return a.Finish(); 1447 } 1448 1449 // Helper that allocates a FixedArray holding argument values recorded in the 1450 // given {frame_state}. Serves as backing store for JSCreateArguments nodes. 1451 Node* JSCreateLowering::AllocateRestArguments(Node* effect, Node* control, 1452 Node* frame_state, 1453 int start_index) { 1454 FrameStateInfo state_info = FrameStateInfoOf(frame_state->op()); 1455 int argument_count = state_info.parameter_count() - 1; // Minus receiver. 1456 int num_elements = std::max(0, argument_count - start_index); 1457 if (num_elements == 0) return jsgraph()->EmptyFixedArrayConstant(); 1458 1459 // Prepare an iterator over argument values recorded in the frame state. 1460 Node* const parameters = frame_state->InputAt(kFrameStateParametersInput); 1461 StateValuesAccess parameters_access(parameters); 1462 auto parameters_it = ++parameters_access.begin(); 1463 1464 // Skip unused arguments. 1465 for (int i = 0; i < start_index; i++) { 1466 ++parameters_it; 1467 } 1468 1469 // Actually allocate the backing store. 1470 AllocationBuilder a(jsgraph(), effect, control); 1471 a.AllocateArray(num_elements, factory()->fixed_array_map()); 1472 for (int i = 0; i < num_elements; ++i, ++parameters_it) { 1473 DCHECK_NOT_NULL((*parameters_it).node); 1474 a.Store(AccessBuilder::ForFixedArraySlot(i), (*parameters_it).node); 1475 } 1476 return a.Finish(); 1477 } 1478 1479 // Helper that allocates a FixedArray serving as a parameter map for values 1480 // recorded in the given {frame_state}. Some elements map to slots within the 1481 // given {context}. Serves as backing store for JSCreateArguments nodes. 1482 Node* JSCreateLowering::AllocateAliasedArguments( 1483 Node* effect, Node* control, Node* frame_state, Node* context, 1484 const SharedFunctionInfoRef& shared, bool* has_aliased_arguments) { 1485 FrameStateInfo state_info = FrameStateInfoOf(frame_state->op()); 1486 int argument_count = state_info.parameter_count() - 1; // Minus receiver. 1487 if (argument_count == 0) return jsgraph()->EmptyFixedArrayConstant(); 1488 1489 // If there is no aliasing, the arguments object elements are not special in 1490 // any way, we can just return an unmapped backing store instead. 1491 int parameter_count = shared.internal_formal_parameter_count(); 1492 if (parameter_count == 0) { 1493 return AllocateArguments(effect, control, frame_state); 1494 } 1495 1496 // Calculate number of argument values being aliased/mapped. 1497 int mapped_count = Min(argument_count, parameter_count); 1498 *has_aliased_arguments = true; 1499 1500 // Prepare an iterator over argument values recorded in the frame state. 1501 Node* const parameters = frame_state->InputAt(kFrameStateParametersInput); 1502 StateValuesAccess parameters_access(parameters); 1503 auto parameters_it = ++parameters_access.begin(); 1504 1505 // The unmapped argument values recorded in the frame state are stored yet 1506 // another indirection away and then linked into the parameter map below, 1507 // whereas mapped argument values are replaced with a hole instead. 1508 AllocationBuilder aa(jsgraph(), effect, control); 1509 aa.AllocateArray(argument_count, factory()->fixed_array_map()); 1510 for (int i = 0; i < mapped_count; ++i, ++parameters_it) { 1511 aa.Store(AccessBuilder::ForFixedArraySlot(i), jsgraph()->TheHoleConstant()); 1512 } 1513 for (int i = mapped_count; i < argument_count; ++i, ++parameters_it) { 1514 DCHECK_NOT_NULL((*parameters_it).node); 1515 aa.Store(AccessBuilder::ForFixedArraySlot(i), (*parameters_it).node); 1516 } 1517 Node* arguments = aa.Finish(); 1518 1519 // Actually allocate the backing store. 1520 AllocationBuilder a(jsgraph(), arguments, control); 1521 a.AllocateArray(mapped_count + 2, factory()->sloppy_arguments_elements_map()); 1522 a.Store(AccessBuilder::ForFixedArraySlot(0), context); 1523 a.Store(AccessBuilder::ForFixedArraySlot(1), arguments); 1524 for (int i = 0; i < mapped_count; ++i) { 1525 int idx = Context::MIN_CONTEXT_SLOTS + parameter_count - 1 - i; 1526 a.Store(AccessBuilder::ForFixedArraySlot(i + 2), jsgraph()->Constant(idx)); 1527 } 1528 return a.Finish(); 1529 } 1530 1531 // Helper that allocates a FixedArray serving as a parameter map for values 1532 // unknown at compile-time, the true {arguments_length} and {arguments_frame} 1533 // values can only be determined dynamically at run-time and are provided. 1534 // Serves as backing store for JSCreateArguments nodes. 1535 Node* JSCreateLowering::AllocateAliasedArguments( 1536 Node* effect, Node* control, Node* context, Node* arguments_frame, 1537 Node* arguments_length, const SharedFunctionInfoRef& shared, 1538 bool* has_aliased_arguments) { 1539 // If there is no aliasing, the arguments object elements are not 1540 // special in any way, we can just return an unmapped backing store. 1541 int parameter_count = shared.internal_formal_parameter_count(); 1542 if (parameter_count == 0) { 1543 return graph()->NewNode(simplified()->NewArgumentsElements(0), 1544 arguments_frame, arguments_length, effect); 1545 } 1546 1547 // From here on we are going to allocate a mapped (aka. aliased) elements 1548 // backing store. We do not statically know how many arguments exist, but 1549 // dynamically selecting the hole for some of the "mapped" elements allows 1550 // using a static shape for the parameter map. 1551 int mapped_count = parameter_count; 1552 *has_aliased_arguments = true; 1553 1554 // The unmapped argument values are stored yet another indirection away and 1555 // then linked into the parameter map below, whereas mapped argument values 1556 // (i.e. the first {mapped_count} elements) are replaced with a hole instead. 1557 Node* arguments = 1558 graph()->NewNode(simplified()->NewArgumentsElements(mapped_count), 1559 arguments_frame, arguments_length, effect); 1560 1561 // Actually allocate the backing store. 1562 AllocationBuilder a(jsgraph(), arguments, control); 1563 a.AllocateArray(mapped_count + 2, factory()->sloppy_arguments_elements_map()); 1564 a.Store(AccessBuilder::ForFixedArraySlot(0), context); 1565 a.Store(AccessBuilder::ForFixedArraySlot(1), arguments); 1566 for (int i = 0; i < mapped_count; ++i) { 1567 int idx = Context::MIN_CONTEXT_SLOTS + parameter_count - 1 - i; 1568 Node* value = graph()->NewNode( 1569 common()->Select(MachineRepresentation::kTagged), 1570 graph()->NewNode(simplified()->NumberLessThan(), jsgraph()->Constant(i), 1571 arguments_length), 1572 jsgraph()->Constant(idx), jsgraph()->TheHoleConstant()); 1573 a.Store(AccessBuilder::ForFixedArraySlot(i + 2), value); 1574 } 1575 return a.Finish(); 1576 } 1577 1578 Node* JSCreateLowering::AllocateElements(Node* effect, Node* control, 1579 ElementsKind elements_kind, 1580 int capacity, 1581 PretenureFlag pretenure) { 1582 DCHECK_LE(1, capacity); 1583 DCHECK_LE(capacity, JSArray::kInitialMaxFastElementArray); 1584 1585 Handle<Map> elements_map = IsDoubleElementsKind(elements_kind) 1586 ? factory()->fixed_double_array_map() 1587 : factory()->fixed_array_map(); 1588 ElementAccess access = IsDoubleElementsKind(elements_kind) 1589 ? AccessBuilder::ForFixedDoubleArrayElement() 1590 : AccessBuilder::ForFixedArrayElement(); 1591 Node* value = jsgraph()->TheHoleConstant(); 1592 1593 // Actually allocate the backing store. 1594 AllocationBuilder a(jsgraph(), effect, control); 1595 a.AllocateArray(capacity, elements_map, pretenure); 1596 for (int i = 0; i < capacity; ++i) { 1597 Node* index = jsgraph()->Constant(i); 1598 a.Store(access, index, value); 1599 } 1600 return a.Finish(); 1601 } 1602 1603 Node* JSCreateLowering::AllocateElements(Node* effect, Node* control, 1604 ElementsKind elements_kind, 1605 std::vector<Node*> const& values, 1606 PretenureFlag pretenure) { 1607 int const capacity = static_cast<int>(values.size()); 1608 DCHECK_LE(1, capacity); 1609 DCHECK_LE(capacity, JSArray::kInitialMaxFastElementArray); 1610 1611 Handle<Map> elements_map = IsDoubleElementsKind(elements_kind) 1612 ? factory()->fixed_double_array_map() 1613 : factory()->fixed_array_map(); 1614 ElementAccess access = IsDoubleElementsKind(elements_kind) 1615 ? AccessBuilder::ForFixedDoubleArrayElement() 1616 : AccessBuilder::ForFixedArrayElement(); 1617 1618 // Actually allocate the backing store. 1619 AllocationBuilder a(jsgraph(), effect, control); 1620 a.AllocateArray(capacity, elements_map, pretenure); 1621 for (int i = 0; i < capacity; ++i) { 1622 Node* index = jsgraph()->Constant(i); 1623 a.Store(access, index, values[i]); 1624 } 1625 return a.Finish(); 1626 } 1627 1628 Node* JSCreateLowering::AllocateFastLiteral(Node* effect, Node* control, 1629 JSObjectRef boilerplate, 1630 PretenureFlag pretenure) { 1631 // Setup the properties backing store. 1632 Node* properties = jsgraph()->EmptyFixedArrayConstant(); 1633 1634 // Compute the in-object properties to store first (might have effects). 1635 MapRef boilerplate_map = boilerplate.map(); 1636 ZoneVector<std::pair<FieldAccess, Node*>> inobject_fields(zone()); 1637 inobject_fields.reserve(boilerplate_map.GetInObjectProperties()); 1638 int const boilerplate_nof = boilerplate_map.NumberOfOwnDescriptors(); 1639 for (int i = 0; i < boilerplate_nof; ++i) { 1640 PropertyDetails const property_details = 1641 boilerplate_map.GetPropertyDetails(i); 1642 if (property_details.location() != kField) continue; 1643 DCHECK_EQ(kData, property_details.kind()); 1644 NameRef property_name = boilerplate_map.GetPropertyKey(i); 1645 FieldIndex index = boilerplate_map.GetFieldIndexFor(i); 1646 FieldAccess access = { 1647 kTaggedBase, index.offset(), property_name.object<Name>(), 1648 MaybeHandle<Map>(), Type::Any(), MachineType::AnyTagged(), 1649 kFullWriteBarrier}; 1650 Node* value; 1651 if (boilerplate.IsUnboxedDoubleField(index)) { 1652 access.machine_type = MachineType::Float64(); 1653 access.type = Type::Number(); 1654 value = jsgraph()->Constant(boilerplate.RawFastDoublePropertyAt(index)); 1655 } else { 1656 ObjectRef boilerplate_value = boilerplate.RawFastPropertyAt(index); 1657 if (boilerplate_value.IsJSObject()) { 1658 JSObjectRef boilerplate_object = boilerplate_value.AsJSObject(); 1659 value = effect = 1660 AllocateFastLiteral(effect, control, boilerplate_object, pretenure); 1661 } else if (property_details.representation().IsDouble()) { 1662 double number = boilerplate_value.AsMutableHeapNumber().value(); 1663 // Allocate a mutable HeapNumber box and store the value into it. 1664 AllocationBuilder builder(jsgraph(), effect, control); 1665 builder.Allocate(HeapNumber::kSize, pretenure); 1666 builder.Store(AccessBuilder::ForMap(), 1667 factory()->mutable_heap_number_map()); 1668 builder.Store(AccessBuilder::ForHeapNumberValue(), 1669 jsgraph()->Constant(number)); 1670 value = effect = builder.Finish(); 1671 } else if (property_details.representation().IsSmi()) { 1672 // Ensure that value is stored as smi. 1673 value = boilerplate_value.oddball_type() == OddballType::kUninitialized 1674 ? jsgraph()->ZeroConstant() 1675 : jsgraph()->Constant(boilerplate_value.AsSmi()); 1676 } else { 1677 value = jsgraph()->Constant(boilerplate_value); 1678 } 1679 } 1680 inobject_fields.push_back(std::make_pair(access, value)); 1681 } 1682 1683 // Fill slack at the end of the boilerplate object with filler maps. 1684 int const boilerplate_length = boilerplate_map.GetInObjectProperties(); 1685 for (int index = static_cast<int>(inobject_fields.size()); 1686 index < boilerplate_length; ++index) { 1687 FieldAccess access = 1688 AccessBuilder::ForJSObjectInObjectProperty(boilerplate_map, index); 1689 Node* value = jsgraph()->HeapConstant(factory()->one_pointer_filler_map()); 1690 inobject_fields.push_back(std::make_pair(access, value)); 1691 } 1692 1693 // Setup the elements backing store. 1694 Node* elements = 1695 AllocateFastLiteralElements(effect, control, boilerplate, pretenure); 1696 if (elements->op()->EffectOutputCount() > 0) effect = elements; 1697 1698 // Actually allocate and initialize the object. 1699 AllocationBuilder builder(jsgraph(), effect, control); 1700 builder.Allocate(boilerplate_map.instance_size(), pretenure, 1701 Type::For(js_heap_broker(), boilerplate_map.object<Map>())); 1702 builder.Store(AccessBuilder::ForMap(), boilerplate_map); 1703 builder.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties); 1704 builder.Store(AccessBuilder::ForJSObjectElements(), elements); 1705 if (boilerplate_map.IsJSArrayMap()) { 1706 JSArrayRef boilerplate_array = boilerplate.AsJSArray(); 1707 builder.Store( 1708 AccessBuilder::ForJSArrayLength(boilerplate_array.GetElementsKind()), 1709 boilerplate_array.length()); 1710 } 1711 for (auto const& inobject_field : inobject_fields) { 1712 builder.Store(inobject_field.first, inobject_field.second); 1713 } 1714 return builder.Finish(); 1715 } 1716 1717 Node* JSCreateLowering::AllocateFastLiteralElements(Node* effect, Node* control, 1718 JSObjectRef boilerplate, 1719 PretenureFlag pretenure) { 1720 FixedArrayBaseRef boilerplate_elements = boilerplate.elements(); 1721 1722 // Empty or copy-on-write elements just store a constant. 1723 int const elements_length = boilerplate_elements.length(); 1724 MapRef elements_map = boilerplate_elements.map(); 1725 if (boilerplate_elements.length() == 0 || elements_map.IsFixedCowArrayMap()) { 1726 if (pretenure == TENURED) { 1727 boilerplate.EnsureElementsTenured(); 1728 boilerplate_elements = boilerplate.elements(); 1729 } 1730 return jsgraph()->HeapConstant(boilerplate_elements.object<HeapObject>()); 1731 } 1732 1733 // Compute the elements to store first (might have effects). 1734 ZoneVector<Node*> elements_values(elements_length, zone()); 1735 if (elements_map.instance_type() == FIXED_DOUBLE_ARRAY_TYPE) { 1736 FixedDoubleArrayRef elements = boilerplate_elements.AsFixedDoubleArray(); 1737 for (int i = 0; i < elements_length; ++i) { 1738 if (elements.is_the_hole(i)) { 1739 elements_values[i] = jsgraph()->TheHoleConstant(); 1740 } else { 1741 elements_values[i] = jsgraph()->Constant(elements.get_scalar(i)); 1742 } 1743 } 1744 } else { 1745 FixedArrayRef elements = boilerplate_elements.AsFixedArray(); 1746 for (int i = 0; i < elements_length; ++i) { 1747 if (elements.is_the_hole(i)) { 1748 elements_values[i] = jsgraph()->TheHoleConstant(); 1749 } else { 1750 ObjectRef element_value = elements.get(i); 1751 if (element_value.IsJSObject()) { 1752 elements_values[i] = effect = AllocateFastLiteral( 1753 effect, control, element_value.AsJSObject(), pretenure); 1754 } else { 1755 elements_values[i] = jsgraph()->Constant(element_value); 1756 } 1757 } 1758 } 1759 } 1760 1761 // Allocate the backing store array and store the elements. 1762 AllocationBuilder builder(jsgraph(), effect, control); 1763 builder.AllocateArray(elements_length, elements_map.object<Map>(), pretenure); 1764 ElementAccess const access = 1765 (elements_map.instance_type() == FIXED_DOUBLE_ARRAY_TYPE) 1766 ? AccessBuilder::ForFixedDoubleArrayElement() 1767 : AccessBuilder::ForFixedArrayElement(); 1768 for (int i = 0; i < elements_length; ++i) { 1769 builder.Store(access, jsgraph()->Constant(i), elements_values[i]); 1770 } 1771 return builder.Finish(); 1772 } 1773 1774 Node* JSCreateLowering::AllocateLiteralRegExp(Node* effect, Node* control, 1775 JSRegExpRef boilerplate) { 1776 MapRef boilerplate_map = boilerplate.map(); 1777 1778 // Sanity check that JSRegExp object layout hasn't changed. 1779 STATIC_ASSERT(JSRegExp::kDataOffset == JSObject::kHeaderSize); 1780 STATIC_ASSERT(JSRegExp::kSourceOffset == 1781 JSRegExp::kDataOffset + kPointerSize); 1782 STATIC_ASSERT(JSRegExp::kFlagsOffset == 1783 JSRegExp::kSourceOffset + kPointerSize); 1784 STATIC_ASSERT(JSRegExp::kSize == JSRegExp::kFlagsOffset + kPointerSize); 1785 STATIC_ASSERT(JSRegExp::kLastIndexOffset == JSRegExp::kSize); 1786 STATIC_ASSERT(JSRegExp::kInObjectFieldCount == 1); // LastIndex. 1787 1788 const PretenureFlag pretenure = NOT_TENURED; 1789 const int size = 1790 JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize; 1791 1792 AllocationBuilder builder(jsgraph(), effect, control); 1793 builder.Allocate(size, pretenure, 1794 Type::For(js_heap_broker(), boilerplate_map.object<Map>())); 1795 builder.Store(AccessBuilder::ForMap(), boilerplate_map); 1796 builder.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), 1797 boilerplate.raw_properties_or_hash()); 1798 builder.Store(AccessBuilder::ForJSObjectElements(), boilerplate.elements()); 1799 1800 builder.Store(AccessBuilder::ForJSRegExpData(), boilerplate.data()); 1801 builder.Store(AccessBuilder::ForJSRegExpSource(), boilerplate.source()); 1802 builder.Store(AccessBuilder::ForJSRegExpFlags(), boilerplate.flags()); 1803 builder.Store(AccessBuilder::ForJSRegExpLastIndex(), 1804 boilerplate.last_index()); 1805 1806 return builder.Finish(); 1807 } 1808 1809 Factory* JSCreateLowering::factory() const { return isolate()->factory(); } 1810 1811 Graph* JSCreateLowering::graph() const { return jsgraph()->graph(); } 1812 1813 Isolate* JSCreateLowering::isolate() const { return jsgraph()->isolate(); } 1814 1815 CommonOperatorBuilder* JSCreateLowering::common() const { 1816 return jsgraph()->common(); 1817 } 1818 1819 SimplifiedOperatorBuilder* JSCreateLowering::simplified() const { 1820 return jsgraph()->simplified(); 1821 } 1822 1823 NativeContextRef JSCreateLowering::native_context_ref() const { 1824 return NativeContextRef(js_heap_broker(), native_context()); 1825 } 1826 1827 } // namespace compiler 1828 } // namespace internal 1829 } // namespace v8 1830