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