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