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