Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(83)

Side by Side Diff: src/compiler/js-create-lowering.cc

Issue 1678833002: [turbofan] Introduce JSCreateLowering for optimizing JSCreate nodes. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Fix length_type check. Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/compiler/js-create-lowering.h"
6
7 #include "src/code-factory.h"
8 #include "src/compilation-dependencies.h"
9 #include "src/compiler/access-builder.h"
10 #include "src/compiler/common-operator.h"
11 #include "src/compiler/js-graph.h"
12 #include "src/compiler/js-operator.h"
13 #include "src/compiler/linkage.h"
14 #include "src/compiler/node.h"
15 #include "src/compiler/node-properties.h"
16 #include "src/compiler/simplified-operator.h"
17 #include "src/compiler/state-values-utils.h"
18
19 namespace v8 {
20 namespace internal {
21 namespace compiler {
22
23 namespace {
24
25 // A helper class to construct inline allocations on the simplified operator
26 // level. This keeps track of the effect chain for initial stores on a newly
27 // allocated object and also provides helpers for commonly allocated objects.
28 class AllocationBuilder final {
29 public:
30 AllocationBuilder(JSGraph* jsgraph, Node* effect, Node* control)
31 : jsgraph_(jsgraph),
32 allocation_(nullptr),
33 effect_(effect),
34 control_(control) {}
35
36 // Primitive allocation of static size.
37 void Allocate(int size, PretenureFlag pretenure = NOT_TENURED) {
38 effect_ = graph()->NewNode(common()->BeginRegion(), effect_);
39 allocation_ =
40 graph()->NewNode(simplified()->Allocate(pretenure),
41 jsgraph()->Constant(size), effect_, control_);
42 effect_ = allocation_;
43 }
44
45 // Primitive store into a field.
46 void Store(const FieldAccess& access, Node* value) {
47 effect_ = graph()->NewNode(simplified()->StoreField(access), allocation_,
48 value, effect_, control_);
49 }
50
51 // Primitive store into an element.
52 void Store(ElementAccess const& access, Node* index, Node* value) {
53 effect_ = graph()->NewNode(simplified()->StoreElement(access), allocation_,
54 index, value, effect_, control_);
55 }
56
57 // Compound allocation of a FixedArray.
58 void AllocateArray(int length, Handle<Map> map,
59 PretenureFlag pretenure = NOT_TENURED) {
60 DCHECK(map->instance_type() == FIXED_ARRAY_TYPE ||
61 map->instance_type() == FIXED_DOUBLE_ARRAY_TYPE);
62 int size = (map->instance_type() == FIXED_ARRAY_TYPE)
63 ? FixedArray::SizeFor(length)
64 : FixedDoubleArray::SizeFor(length);
65 Allocate(size, pretenure);
66 Store(AccessBuilder::ForMap(), map);
67 Store(AccessBuilder::ForFixedArrayLength(), jsgraph()->Constant(length));
68 }
69
70 // Compound store of a constant into a field.
71 void Store(const FieldAccess& access, Handle<Object> value) {
72 Store(access, jsgraph()->Constant(value));
73 }
74
75 void FinishAndChange(Node* node) {
76 NodeProperties::SetType(allocation_, NodeProperties::GetType(node));
77 node->ReplaceInput(0, allocation_);
78 node->ReplaceInput(1, effect_);
79 node->TrimInputCount(2);
80 NodeProperties::ChangeOp(node, common()->FinishRegion());
81 }
82
83 Node* Finish() {
84 return graph()->NewNode(common()->FinishRegion(), allocation_, effect_);
85 }
86
87 protected:
88 JSGraph* jsgraph() { return jsgraph_; }
89 Graph* graph() { return jsgraph_->graph(); }
90 CommonOperatorBuilder* common() { return jsgraph_->common(); }
91 SimplifiedOperatorBuilder* simplified() { return jsgraph_->simplified(); }
92
93 private:
94 JSGraph* const jsgraph_;
95 Node* allocation_;
96 Node* effect_;
97 Node* control_;
98 };
99
100 // Retrieves the frame state holding actual argument values.
101 Node* GetArgumentsFrameState(Node* frame_state) {
102 Node* const outer_state = NodeProperties::GetFrameStateInput(frame_state, 0);
103 FrameStateInfo outer_state_info = OpParameter<FrameStateInfo>(outer_state);
104 return outer_state_info.type() == FrameStateType::kArgumentsAdaptor
105 ? outer_state
106 : frame_state;
107 }
108
109 // Maximum instance size for which allocations will be inlined.
110 const int kMaxInlineInstanceSize = 64 * kPointerSize;
111
112 // Checks whether allocation using the given constructor can be inlined.
113 bool IsAllocationInlineable(Handle<JSFunction> constructor) {
114 // TODO(bmeurer): Further relax restrictions on inlining, i.e.
115 // instance type and maybe instance size (inobject properties
116 // are limited anyways by the runtime).
117 return constructor->has_initial_map() &&
118 constructor->initial_map()->instance_type() == JS_OBJECT_TYPE &&
119 constructor->initial_map()->instance_size() < kMaxInlineInstanceSize;
120 }
121
122 // When initializing arrays, we'll unfold the loop if the number of
123 // elements is known to be of this type.
124 const int kElementLoopUnrollLimit = 16;
125
126 // Limits up to which context allocations are inlined.
127 const int kFunctionContextAllocationLimit = 16;
128 const int kBlockContextAllocationLimit = 16;
129
130 } // namespace
131
132 Reduction JSCreateLowering::Reduce(Node* node) {
133 switch (node->opcode()) {
134 case IrOpcode::kJSCreate:
135 return ReduceJSCreate(node);
136 case IrOpcode::kJSCreateArguments:
137 return ReduceJSCreateArguments(node);
138 case IrOpcode::kJSCreateArray:
139 return ReduceJSCreateArray(node);
140 case IrOpcode::kJSCreateIterResultObject:
141 return ReduceJSCreateIterResultObject(node);
142 case IrOpcode::kJSCreateFunctionContext:
143 return ReduceJSCreateFunctionContext(node);
144 case IrOpcode::kJSCreateWithContext:
145 return ReduceJSCreateWithContext(node);
146 case IrOpcode::kJSCreateCatchContext:
147 return ReduceJSCreateCatchContext(node);
148 case IrOpcode::kJSCreateBlockContext:
149 return ReduceJSCreateBlockContext(node);
150 default:
151 break;
152 }
153 return NoChange();
154 }
155
156 Reduction JSCreateLowering::ReduceJSCreate(Node* node) {
157 DCHECK_EQ(IrOpcode::kJSCreate, node->opcode());
158 Node* const target = NodeProperties::GetValueInput(node, 0);
159 Type* const target_type = NodeProperties::GetType(target);
160 Node* const new_target = NodeProperties::GetValueInput(node, 1);
161 Node* const effect = NodeProperties::GetEffectInput(node);
162 // TODO(turbofan): Add support for NewTarget passed to JSCreate.
163 if (target != new_target) return NoChange();
164 // Extract constructor function.
165 if (target_type->IsConstant() &&
166 target_type->AsConstant()->Value()->IsJSFunction()) {
167 Handle<JSFunction> constructor =
168 Handle<JSFunction>::cast(target_type->AsConstant()->Value());
169 DCHECK(constructor->IsConstructor());
170 // Force completion of inobject slack tracking before
171 // generating code to finalize the instance size.
172 constructor->CompleteInobjectSlackTrackingIfActive();
173
174 // TODO(bmeurer): We fall back to the runtime in case we cannot inline
175 // the allocation here, which is sort of expensive. We should think about
176 // a soft fallback to some NewObjectCodeStub.
177 if (IsAllocationInlineable(constructor)) {
178 // Compute instance size from initial map of {constructor}.
179 Handle<Map> initial_map(constructor->initial_map(), isolate());
180 int const instance_size = initial_map->instance_size();
181
182 // Add a dependency on the {initial_map} to make sure that this code is
183 // deoptimized whenever the {initial_map} of the {constructor} changes.
184 dependencies()->AssumeInitialMapCantChange(initial_map);
185
186 // Emit code to allocate the JSObject instance for the {constructor}.
187 AllocationBuilder a(jsgraph(), effect, graph()->start());
188 a.Allocate(instance_size);
189 a.Store(AccessBuilder::ForMap(), initial_map);
190 a.Store(AccessBuilder::ForJSObjectProperties(),
191 jsgraph()->EmptyFixedArrayConstant());
192 a.Store(AccessBuilder::ForJSObjectElements(),
193 jsgraph()->EmptyFixedArrayConstant());
194 for (int i = 0; i < initial_map->GetInObjectProperties(); ++i) {
195 a.Store(AccessBuilder::ForJSObjectInObjectProperty(initial_map, i),
196 jsgraph()->UndefinedConstant());
197 }
198 a.FinishAndChange(node);
199 return Changed(node);
200 }
201 }
202 return NoChange();
203 }
204
205 Reduction JSCreateLowering::ReduceJSCreateArguments(Node* node) {
206 DCHECK_EQ(IrOpcode::kJSCreateArguments, node->opcode());
207 CreateArgumentsType type = CreateArgumentsTypeOf(node->op());
208 Node* const frame_state = NodeProperties::GetFrameStateInput(node, 0);
209 Node* const outer_state = frame_state->InputAt(kFrameStateOuterStateInput);
210 FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state);
211
212 // Use the ArgumentsAccessStub for materializing both mapped and unmapped
213 // arguments object, but only for non-inlined (i.e. outermost) frames.
214 if (outer_state->opcode() != IrOpcode::kFrameState) {
215 if (type != CreateArgumentsType::kRestParameter) {
216 // TODO(bmeurer): Cleanup this mess at some point.
217 int parameter_count = state_info.parameter_count() - 1;
218 int parameter_offset = parameter_count * kPointerSize;
219 int offset = StandardFrameConstants::kCallerSPOffset + parameter_offset;
220 Node* parameter_pointer = graph()->NewNode(
221 machine()->IntAdd(), graph()->NewNode(machine()->LoadFramePointer()),
222 jsgraph()->IntPtrConstant(offset));
223 Handle<SharedFunctionInfo> shared;
224 if (!state_info.shared_info().ToHandle(&shared)) return NoChange();
225 bool unmapped = type == CreateArgumentsType::kUnmappedArguments;
226 Callable callable = CodeFactory::ArgumentsAccess(
227 isolate(), unmapped, shared->has_duplicate_parameters());
228 CallDescriptor* desc = Linkage::GetStubCallDescriptor(
229 isolate(), graph()->zone(), callable.descriptor(), 0,
230 CallDescriptor::kNeedsFrameState);
231 const Operator* new_op = common()->Call(desc);
232 Node* stub_code = jsgraph()->HeapConstant(callable.code());
233 node->InsertInput(graph()->zone(), 0, stub_code);
234 node->InsertInput(graph()->zone(), 2,
235 jsgraph()->Constant(parameter_count));
236 node->InsertInput(graph()->zone(), 3, parameter_pointer);
237 NodeProperties::ChangeOp(node, new_op);
238 return Changed(node);
239 } else {
240 Callable callable = CodeFactory::FastNewRestParameter(isolate());
241 CallDescriptor* desc = Linkage::GetStubCallDescriptor(
242 isolate(), graph()->zone(), callable.descriptor(), 0,
243 CallDescriptor::kNeedsFrameState);
244 const Operator* new_op = common()->Call(desc);
245 Node* stub_code = jsgraph()->HeapConstant(callable.code());
246 node->InsertInput(graph()->zone(), 0, stub_code);
247 NodeProperties::ChangeOp(node, new_op);
248 return Changed(node);
249 }
250 } else if (outer_state->opcode() == IrOpcode::kFrameState) {
251 // Use inline allocation for all mapped arguments objects within inlined
252 // (i.e. non-outermost) frames, independent of the object size.
253 if (type == CreateArgumentsType::kMappedArguments) {
254 Handle<SharedFunctionInfo> shared;
255 if (!state_info.shared_info().ToHandle(&shared)) return NoChange();
256 Node* const callee = NodeProperties::GetValueInput(node, 0);
257 Node* const control = NodeProperties::GetControlInput(node);
258 Node* const context = NodeProperties::GetContextInput(node);
259 Node* effect = NodeProperties::GetEffectInput(node);
260 // TODO(mstarzinger): Duplicate parameters are not handled yet.
261 if (shared->has_duplicate_parameters()) return NoChange();
262 // Choose the correct frame state and frame state info depending on
263 // whether there conceptually is an arguments adaptor frame in the call
264 // chain.
265 Node* const args_state = GetArgumentsFrameState(frame_state);
266 FrameStateInfo args_state_info = OpParameter<FrameStateInfo>(args_state);
267 // Prepare element backing store to be used by arguments object.
268 bool has_aliased_arguments = false;
269 Node* const elements = AllocateAliasedArguments(
270 effect, control, args_state, context, shared, &has_aliased_arguments);
271 effect = elements->op()->EffectOutputCount() > 0 ? elements : effect;
272 // Load the arguments object map from the current native context.
273 Node* const load_native_context = effect = graph()->NewNode(
274 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
275 context, context, effect);
276 Node* const load_arguments_map = effect = graph()->NewNode(
277 simplified()->LoadField(AccessBuilder::ForContextSlot(
278 has_aliased_arguments ? Context::FAST_ALIASED_ARGUMENTS_MAP_INDEX
279 : Context::SLOPPY_ARGUMENTS_MAP_INDEX)),
280 load_native_context, effect, control);
281 // Actually allocate and initialize the arguments object.
282 AllocationBuilder a(jsgraph(), effect, control);
283 Node* properties = jsgraph()->EmptyFixedArrayConstant();
284 int length = args_state_info.parameter_count() - 1; // Minus receiver.
285 STATIC_ASSERT(Heap::kSloppyArgumentsObjectSize == 5 * kPointerSize);
286 a.Allocate(Heap::kSloppyArgumentsObjectSize);
287 a.Store(AccessBuilder::ForMap(), load_arguments_map);
288 a.Store(AccessBuilder::ForJSObjectProperties(), properties);
289 a.Store(AccessBuilder::ForJSObjectElements(), elements);
290 a.Store(AccessBuilder::ForArgumentsLength(), jsgraph()->Constant(length));
291 a.Store(AccessBuilder::ForArgumentsCallee(), callee);
292 RelaxControls(node);
293 a.FinishAndChange(node);
294 return Changed(node);
295 } else if (type == CreateArgumentsType::kUnmappedArguments) {
296 // Use inline allocation for all unmapped arguments objects within inlined
297 // (i.e. non-outermost) frames, independent of the object size.
298 Node* const control = NodeProperties::GetControlInput(node);
299 Node* const context = NodeProperties::GetContextInput(node);
300 Node* effect = NodeProperties::GetEffectInput(node);
301 // Choose the correct frame state and frame state info depending on
302 // whether there conceptually is an arguments adaptor frame in the call
303 // chain.
304 Node* const args_state = GetArgumentsFrameState(frame_state);
305 FrameStateInfo args_state_info = OpParameter<FrameStateInfo>(args_state);
306 // Prepare element backing store to be used by arguments object.
307 Node* const elements = AllocateArguments(effect, control, args_state);
308 effect = elements->op()->EffectOutputCount() > 0 ? elements : effect;
309 // Load the arguments object map from the current native context.
310 Node* const load_native_context = effect = graph()->NewNode(
311 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
312 context, context, effect);
313 Node* const load_arguments_map = effect = graph()->NewNode(
314 simplified()->LoadField(AccessBuilder::ForContextSlot(
315 Context::STRICT_ARGUMENTS_MAP_INDEX)),
316 load_native_context, effect, control);
317 // Actually allocate and initialize the arguments object.
318 AllocationBuilder a(jsgraph(), effect, control);
319 Node* properties = jsgraph()->EmptyFixedArrayConstant();
320 int length = args_state_info.parameter_count() - 1; // Minus receiver.
321 STATIC_ASSERT(Heap::kStrictArgumentsObjectSize == 4 * kPointerSize);
322 a.Allocate(Heap::kStrictArgumentsObjectSize);
323 a.Store(AccessBuilder::ForMap(), load_arguments_map);
324 a.Store(AccessBuilder::ForJSObjectProperties(), properties);
325 a.Store(AccessBuilder::ForJSObjectElements(), elements);
326 a.Store(AccessBuilder::ForArgumentsLength(), jsgraph()->Constant(length));
327 RelaxControls(node);
328 a.FinishAndChange(node);
329 return Changed(node);
330 } else if (type == CreateArgumentsType::kRestParameter) {
331 Handle<SharedFunctionInfo> shared;
332 if (!state_info.shared_info().ToHandle(&shared)) return NoChange();
333 int start_index = shared->internal_formal_parameter_count();
334 // Use inline allocation for all unmapped arguments objects within inlined
335 // (i.e. non-outermost) frames, independent of the object size.
336 Node* const control = NodeProperties::GetControlInput(node);
337 Node* const context = NodeProperties::GetContextInput(node);
338 Node* effect = NodeProperties::GetEffectInput(node);
339 // Choose the correct frame state and frame state info depending on
340 // whether there conceptually is an arguments adaptor frame in the call
341 // chain.
342 Node* const args_state = GetArgumentsFrameState(frame_state);
343 FrameStateInfo args_state_info = OpParameter<FrameStateInfo>(args_state);
344 // Prepare element backing store to be used by the rest array.
345 Node* const elements =
346 AllocateRestArguments(effect, control, args_state, start_index);
347 effect = elements->op()->EffectOutputCount() > 0 ? elements : effect;
348 // Load the JSArray object map from the current native context.
349 Node* const load_native_context = effect = graph()->NewNode(
350 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
351 context, context, effect);
352 Node* const load_jsarray_map = effect = graph()->NewNode(
353 simplified()->LoadField(AccessBuilder::ForContextSlot(
354 Context::JS_ARRAY_FAST_ELEMENTS_MAP_INDEX)),
355 load_native_context, effect, control);
356 // Actually allocate and initialize the jsarray.
357 AllocationBuilder a(jsgraph(), effect, control);
358 Node* properties = jsgraph()->EmptyFixedArrayConstant();
359
360 // -1 to minus receiver
361 int argument_count = args_state_info.parameter_count() - 1;
362 int length = std::max(0, argument_count - start_index);
363 STATIC_ASSERT(JSArray::kSize == 4 * kPointerSize);
364 a.Allocate(JSArray::kSize);
365 a.Store(AccessBuilder::ForMap(), load_jsarray_map);
366 a.Store(AccessBuilder::ForJSObjectProperties(), properties);
367 a.Store(AccessBuilder::ForJSObjectElements(), elements);
368 a.Store(AccessBuilder::ForJSArrayLength(FAST_ELEMENTS),
369 jsgraph()->Constant(length));
370 RelaxControls(node);
371 a.FinishAndChange(node);
372 return Changed(node);
373 }
374 }
375
376 return NoChange();
377 }
378
379 Reduction JSCreateLowering::ReduceNewArray(Node* node, Node* length,
380 int capacity,
381 Handle<AllocationSite> site) {
382 DCHECK_EQ(IrOpcode::kJSCreateArray, node->opcode());
383 Node* context = NodeProperties::GetContextInput(node);
384 Node* effect = NodeProperties::GetEffectInput(node);
385 Node* control = NodeProperties::GetControlInput(node);
386
387 // Extract transition and tenuring feedback from the {site} and add
388 // appropriate code dependencies on the {site} if deoptimization is
389 // enabled.
390 PretenureFlag pretenure = site->GetPretenureMode();
391 ElementsKind elements_kind = site->GetElementsKind();
392 DCHECK(IsFastElementsKind(elements_kind));
393 dependencies()->AssumeTenuringDecision(site);
394 dependencies()->AssumeTransitionStable(site);
395
396 // Retrieve the initial map for the array from the appropriate native context.
397 Node* native_context = effect = graph()->NewNode(
398 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
399 context, context, effect);
400 Node* js_array_map = effect = graph()->NewNode(
401 javascript()->LoadContext(0, Context::ArrayMapIndex(elements_kind), true),
402 native_context, native_context, effect);
403
404 // Setup elements and properties.
405 Node* elements;
406 if (capacity == 0) {
407 elements = jsgraph()->EmptyFixedArrayConstant();
408 } else {
409 elements = effect =
410 AllocateElements(effect, control, elements_kind, capacity, pretenure);
411 }
412 Node* properties = jsgraph()->EmptyFixedArrayConstant();
413
414 // Perform the allocation of the actual JSArray object.
415 AllocationBuilder a(jsgraph(), effect, control);
416 a.Allocate(JSArray::kSize, pretenure);
417 a.Store(AccessBuilder::ForMap(), js_array_map);
418 a.Store(AccessBuilder::ForJSObjectProperties(), properties);
419 a.Store(AccessBuilder::ForJSObjectElements(), elements);
420 a.Store(AccessBuilder::ForJSArrayLength(elements_kind), length);
421 RelaxControls(node);
422 a.FinishAndChange(node);
423 return Changed(node);
424 }
425
426 Reduction JSCreateLowering::ReduceJSCreateArray(Node* node) {
427 DCHECK_EQ(IrOpcode::kJSCreateArray, node->opcode());
428 CreateArrayParameters const& p = CreateArrayParametersOf(node->op());
429 Node* target = NodeProperties::GetValueInput(node, 0);
430 Node* new_target = NodeProperties::GetValueInput(node, 1);
431
432 // TODO(bmeurer): Optimize the subclassing case.
433 if (target != new_target) return NoChange();
434
435 // Check if we have a feedback {site} on the {node}.
436 Handle<AllocationSite> site = p.site();
437 if (p.site().is_null()) return NoChange();
438
439 // Attempt to inline calls to the Array constructor for the relevant cases
440 // where either no arguments are provided, or exactly one unsigned number
441 // argument is given.
442 if (site->CanInlineCall()) {
443 if (p.arity() == 0) {
444 Node* length = jsgraph()->ZeroConstant();
445 int capacity = JSArray::kPreallocatedArrayElements;
446 return ReduceNewArray(node, length, capacity, site);
447 } else if (p.arity() == 1) {
448 Node* length = NodeProperties::GetValueInput(node, 2);
449 Type* length_type = NodeProperties::GetType(length);
450 if (length_type->Is(Type::SignedSmall()) &&
451 length_type->Min() >= 0 &&
452 length_type->Max() <= kElementLoopUnrollLimit) {
453 int capacity = static_cast<int>(length_type->Max());
454 return ReduceNewArray(node, length, capacity, site);
455 }
456 }
457 }
458
459 return NoChange();
460 }
461
462 Reduction JSCreateLowering::ReduceJSCreateIterResultObject(Node* node) {
463 DCHECK_EQ(IrOpcode::kJSCreateIterResultObject, node->opcode());
464 Node* value = NodeProperties::GetValueInput(node, 0);
465 Node* done = NodeProperties::GetValueInput(node, 1);
466 Node* context = NodeProperties::GetContextInput(node);
467 Node* effect = NodeProperties::GetEffectInput(node);
468
469 // Load the JSIteratorResult map for the {context}.
470 Node* native_context = effect = graph()->NewNode(
471 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
472 context, context, effect);
473 Node* iterator_result_map = effect = graph()->NewNode(
474 javascript()->LoadContext(0, Context::ITERATOR_RESULT_MAP_INDEX, true),
475 native_context, native_context, effect);
476
477 // Emit code to allocate the JSIteratorResult instance.
478 AllocationBuilder a(jsgraph(), effect, graph()->start());
479 a.Allocate(JSIteratorResult::kSize);
480 a.Store(AccessBuilder::ForMap(), iterator_result_map);
481 a.Store(AccessBuilder::ForJSObjectProperties(),
482 jsgraph()->EmptyFixedArrayConstant());
483 a.Store(AccessBuilder::ForJSObjectElements(),
484 jsgraph()->EmptyFixedArrayConstant());
485 a.Store(AccessBuilder::ForJSIteratorResultValue(), value);
486 a.Store(AccessBuilder::ForJSIteratorResultDone(), done);
487 STATIC_ASSERT(JSIteratorResult::kSize == 5 * kPointerSize);
488 a.FinishAndChange(node);
489 return Changed(node);
490 }
491
492 Reduction JSCreateLowering::ReduceJSCreateFunctionContext(Node* node) {
493 DCHECK_EQ(IrOpcode::kJSCreateFunctionContext, node->opcode());
494 int slot_count = OpParameter<int>(node->op());
495 Node* const closure = NodeProperties::GetValueInput(node, 0);
496
497 // Use inline allocation for function contexts up to a size limit.
498 if (slot_count < kFunctionContextAllocationLimit) {
499 // JSCreateFunctionContext[slot_count < limit]](fun)
500 Node* effect = NodeProperties::GetEffectInput(node);
501 Node* control = NodeProperties::GetControlInput(node);
502 Node* context = NodeProperties::GetContextInput(node);
503 Node* extension = jsgraph()->TheHoleConstant();
504 Node* native_context = effect = graph()->NewNode(
505 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
506 context, context, effect);
507 AllocationBuilder a(jsgraph(), effect, control);
508 STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == 4); // Ensure fully covered.
509 int context_length = slot_count + Context::MIN_CONTEXT_SLOTS;
510 a.AllocateArray(context_length, factory()->function_context_map());
511 a.Store(AccessBuilder::ForContextSlot(Context::CLOSURE_INDEX), closure);
512 a.Store(AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX), context);
513 a.Store(AccessBuilder::ForContextSlot(Context::EXTENSION_INDEX), extension);
514 a.Store(AccessBuilder::ForContextSlot(Context::NATIVE_CONTEXT_INDEX),
515 native_context);
516 for (int i = Context::MIN_CONTEXT_SLOTS; i < context_length; ++i) {
517 a.Store(AccessBuilder::ForContextSlot(i), jsgraph()->UndefinedConstant());
518 }
519 RelaxControls(node);
520 a.FinishAndChange(node);
521 return Changed(node);
522 }
523
524 return NoChange();
525 }
526
527 Reduction JSCreateLowering::ReduceJSCreateWithContext(Node* node) {
528 DCHECK_EQ(IrOpcode::kJSCreateWithContext, node->opcode());
529 Node* object = NodeProperties::GetValueInput(node, 0);
530 Node* closure = NodeProperties::GetValueInput(node, 1);
531 Node* effect = NodeProperties::GetEffectInput(node);
532 Node* control = NodeProperties::GetControlInput(node);
533 Node* context = NodeProperties::GetContextInput(node);
534 Node* native_context = effect = graph()->NewNode(
535 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
536 context, context, effect);
537 AllocationBuilder a(jsgraph(), effect, control);
538 STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == 4); // Ensure fully covered.
539 a.AllocateArray(Context::MIN_CONTEXT_SLOTS, factory()->with_context_map());
540 a.Store(AccessBuilder::ForContextSlot(Context::CLOSURE_INDEX), closure);
541 a.Store(AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX), context);
542 a.Store(AccessBuilder::ForContextSlot(Context::EXTENSION_INDEX), object);
543 a.Store(AccessBuilder::ForContextSlot(Context::NATIVE_CONTEXT_INDEX),
544 native_context);
545 RelaxControls(node);
546 a.FinishAndChange(node);
547 return Changed(node);
548 }
549
550 Reduction JSCreateLowering::ReduceJSCreateCatchContext(Node* node) {
551 DCHECK_EQ(IrOpcode::kJSCreateCatchContext, node->opcode());
552 Handle<String> name = OpParameter<Handle<String>>(node);
553 Node* exception = NodeProperties::GetValueInput(node, 0);
554 Node* closure = NodeProperties::GetValueInput(node, 1);
555 Node* effect = NodeProperties::GetEffectInput(node);
556 Node* control = NodeProperties::GetControlInput(node);
557 Node* context = NodeProperties::GetContextInput(node);
558 Node* native_context = effect = graph()->NewNode(
559 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
560 context, context, effect);
561 AllocationBuilder a(jsgraph(), effect, control);
562 STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == 4); // Ensure fully covered.
563 a.AllocateArray(Context::MIN_CONTEXT_SLOTS + 1,
564 factory()->catch_context_map());
565 a.Store(AccessBuilder::ForContextSlot(Context::CLOSURE_INDEX), closure);
566 a.Store(AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX), context);
567 a.Store(AccessBuilder::ForContextSlot(Context::EXTENSION_INDEX), name);
568 a.Store(AccessBuilder::ForContextSlot(Context::NATIVE_CONTEXT_INDEX),
569 native_context);
570 a.Store(AccessBuilder::ForContextSlot(Context::THROWN_OBJECT_INDEX),
571 exception);
572 RelaxControls(node);
573 a.FinishAndChange(node);
574 return Changed(node);
575 }
576
577 Reduction JSCreateLowering::ReduceJSCreateBlockContext(Node* node) {
578 DCHECK_EQ(IrOpcode::kJSCreateBlockContext, node->opcode());
579 Handle<ScopeInfo> scope_info = OpParameter<Handle<ScopeInfo>>(node);
580 int const context_length = scope_info->ContextLength();
581 Node* const closure = NodeProperties::GetValueInput(node, 0);
582
583 // Use inline allocation for block contexts up to a size limit.
584 if (context_length < kBlockContextAllocationLimit) {
585 // JSCreateBlockContext[scope[length < limit]](fun)
586 Node* effect = NodeProperties::GetEffectInput(node);
587 Node* control = NodeProperties::GetControlInput(node);
588 Node* context = NodeProperties::GetContextInput(node);
589 Node* extension = jsgraph()->Constant(scope_info);
590 Node* native_context = effect = graph()->NewNode(
591 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
592 context, context, effect);
593 AllocationBuilder a(jsgraph(), effect, control);
594 STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == 4); // Ensure fully covered.
595 a.AllocateArray(context_length, factory()->block_context_map());
596 a.Store(AccessBuilder::ForContextSlot(Context::CLOSURE_INDEX), closure);
597 a.Store(AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX), context);
598 a.Store(AccessBuilder::ForContextSlot(Context::EXTENSION_INDEX), extension);
599 a.Store(AccessBuilder::ForContextSlot(Context::NATIVE_CONTEXT_INDEX),
600 native_context);
601 for (int i = Context::MIN_CONTEXT_SLOTS; i < context_length; ++i) {
602 a.Store(AccessBuilder::ForContextSlot(i), jsgraph()->UndefinedConstant());
603 }
604 RelaxControls(node);
605 a.FinishAndChange(node);
606 return Changed(node);
607 }
608
609 return NoChange();
610 }
611
612 // Helper that allocates a FixedArray holding argument values recorded in the
613 // given {frame_state}. Serves as backing store for JSCreateArguments nodes.
614 Node* JSCreateLowering::AllocateArguments(Node* effect, Node* control,
615 Node* frame_state) {
616 FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state);
617 int argument_count = state_info.parameter_count() - 1; // Minus receiver.
618 if (argument_count == 0) return jsgraph()->EmptyFixedArrayConstant();
619
620 // Prepare an iterator over argument values recorded in the frame state.
621 Node* const parameters = frame_state->InputAt(kFrameStateParametersInput);
622 StateValuesAccess parameters_access(parameters);
623 auto parameters_it = ++parameters_access.begin();
624
625 // Actually allocate the backing store.
626 AllocationBuilder a(jsgraph(), effect, control);
627 a.AllocateArray(argument_count, factory()->fixed_array_map());
628 for (int i = 0; i < argument_count; ++i, ++parameters_it) {
629 a.Store(AccessBuilder::ForFixedArraySlot(i), (*parameters_it).node);
630 }
631 return a.Finish();
632 }
633
634 // Helper that allocates a FixedArray holding argument values recorded in the
635 // given {frame_state}. Serves as backing store for JSCreateArguments nodes.
636 Node* JSCreateLowering::AllocateRestArguments(Node* effect, Node* control,
637 Node* frame_state,
638 int start_index) {
639 FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state);
640 int argument_count = state_info.parameter_count() - 1; // Minus receiver.
641 int num_elements = std::max(0, argument_count - start_index);
642 if (num_elements == 0) return jsgraph()->EmptyFixedArrayConstant();
643
644 // Prepare an iterator over argument values recorded in the frame state.
645 Node* const parameters = frame_state->InputAt(kFrameStateParametersInput);
646 StateValuesAccess parameters_access(parameters);
647 auto parameters_it = ++parameters_access.begin();
648
649 // Skip unused arguments.
650 for (int i = 0; i < start_index; i++) {
651 ++parameters_it;
652 }
653
654 // Actually allocate the backing store.
655 AllocationBuilder a(jsgraph(), effect, control);
656 a.AllocateArray(num_elements, factory()->fixed_array_map());
657 for (int i = 0; i < num_elements; ++i, ++parameters_it) {
658 a.Store(AccessBuilder::ForFixedArraySlot(i), (*parameters_it).node);
659 }
660 return a.Finish();
661 }
662
663 // Helper that allocates a FixedArray serving as a parameter map for values
664 // recorded in the given {frame_state}. Some elements map to slots within the
665 // given {context}. Serves as backing store for JSCreateArguments nodes.
666 Node* JSCreateLowering::AllocateAliasedArguments(
667 Node* effect, Node* control, Node* frame_state, Node* context,
668 Handle<SharedFunctionInfo> shared, bool* has_aliased_arguments) {
669 FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state);
670 int argument_count = state_info.parameter_count() - 1; // Minus receiver.
671 if (argument_count == 0) return jsgraph()->EmptyFixedArrayConstant();
672
673 // If there is no aliasing, the arguments object elements are not special in
674 // any way, we can just return an unmapped backing store instead.
675 int parameter_count = shared->internal_formal_parameter_count();
676 if (parameter_count == 0) {
677 return AllocateArguments(effect, control, frame_state);
678 }
679
680 // Calculate number of argument values being aliased/mapped.
681 int mapped_count = Min(argument_count, parameter_count);
682 *has_aliased_arguments = true;
683
684 // Prepare an iterator over argument values recorded in the frame state.
685 Node* const parameters = frame_state->InputAt(kFrameStateParametersInput);
686 StateValuesAccess parameters_access(parameters);
687 auto paratemers_it = ++parameters_access.begin();
688
689 // The unmapped argument values recorded in the frame state are stored yet
690 // another indirection away and then linked into the parameter map below,
691 // whereas mapped argument values are replaced with a hole instead.
692 AllocationBuilder aa(jsgraph(), effect, control);
693 aa.AllocateArray(argument_count, factory()->fixed_array_map());
694 for (int i = 0; i < mapped_count; ++i, ++paratemers_it) {
695 aa.Store(AccessBuilder::ForFixedArraySlot(i), jsgraph()->TheHoleConstant());
696 }
697 for (int i = mapped_count; i < argument_count; ++i, ++paratemers_it) {
698 aa.Store(AccessBuilder::ForFixedArraySlot(i), (*paratemers_it).node);
699 }
700 Node* arguments = aa.Finish();
701
702 // Actually allocate the backing store.
703 AllocationBuilder a(jsgraph(), arguments, control);
704 a.AllocateArray(mapped_count + 2, factory()->sloppy_arguments_elements_map());
705 a.Store(AccessBuilder::ForFixedArraySlot(0), context);
706 a.Store(AccessBuilder::ForFixedArraySlot(1), arguments);
707 for (int i = 0; i < mapped_count; ++i) {
708 int idx = Context::MIN_CONTEXT_SLOTS + parameter_count - 1 - i;
709 a.Store(AccessBuilder::ForFixedArraySlot(i + 2), jsgraph()->Constant(idx));
710 }
711 return a.Finish();
712 }
713
714 Node* JSCreateLowering::AllocateElements(Node* effect, Node* control,
715 ElementsKind elements_kind,
716 int capacity,
717 PretenureFlag pretenure) {
718 DCHECK_LE(1, capacity);
719 DCHECK_LE(capacity, JSArray::kInitialMaxFastElementArray);
720
721 Handle<Map> elements_map = IsFastDoubleElementsKind(elements_kind)
722 ? factory()->fixed_double_array_map()
723 : factory()->fixed_array_map();
724 ElementAccess access = IsFastDoubleElementsKind(elements_kind)
725 ? AccessBuilder::ForFixedDoubleArrayElement()
726 : AccessBuilder::ForFixedArrayElement();
727 Node* value =
728 IsFastDoubleElementsKind(elements_kind)
729 ? jsgraph()->Float64Constant(bit_cast<double>(kHoleNanInt64))
730 : jsgraph()->TheHoleConstant();
731
732 // Actually allocate the backing store.
733 AllocationBuilder a(jsgraph(), effect, control);
734 a.AllocateArray(capacity, elements_map, pretenure);
735 for (int i = 0; i < capacity; ++i) {
736 Node* index = jsgraph()->Constant(i);
737 a.Store(access, index, value);
738 }
739 return a.Finish();
740 }
741
742 Factory* JSCreateLowering::factory() const { return isolate()->factory(); }
743
744 Graph* JSCreateLowering::graph() const { return jsgraph()->graph(); }
745
746 Isolate* JSCreateLowering::isolate() const { return jsgraph()->isolate(); }
747
748 JSOperatorBuilder* JSCreateLowering::javascript() const {
749 return jsgraph()->javascript();
750 }
751
752 CommonOperatorBuilder* JSCreateLowering::common() const {
753 return jsgraph()->common();
754 }
755
756 SimplifiedOperatorBuilder* JSCreateLowering::simplified() const {
757 return jsgraph()->simplified();
758 }
759
760 MachineOperatorBuilder* JSCreateLowering::machine() const {
761 return jsgraph()->machine();
762 }
763
764 } // namespace compiler
765 } // namespace internal
766 } // namespace v8
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698