blob: 081f28b16d4487dbd55f699c1d617a5a18b77ce1 [file] [log] [blame]
Ben Murdochc5610432016-08-08 18:44:38 +01001// Copyright 2015 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/code-assembler.h"
6
7#include <ostream>
8
9#include "src/code-factory.h"
10#include "src/compiler/graph.h"
11#include "src/compiler/instruction-selector.h"
12#include "src/compiler/linkage.h"
13#include "src/compiler/node-matchers.h"
14#include "src/compiler/pipeline.h"
15#include "src/compiler/raw-machine-assembler.h"
16#include "src/compiler/schedule.h"
17#include "src/frames.h"
18#include "src/interface-descriptors.h"
19#include "src/interpreter/bytecodes.h"
20#include "src/machine-type.h"
21#include "src/macro-assembler.h"
22#include "src/zone.h"
23
24namespace v8 {
25namespace internal {
26namespace compiler {
27
28CodeAssembler::CodeAssembler(Isolate* isolate, Zone* zone,
29 const CallInterfaceDescriptor& descriptor,
30 Code::Flags flags, const char* name,
31 size_t result_size)
32 : CodeAssembler(
33 isolate, zone,
34 Linkage::GetStubCallDescriptor(
35 isolate, zone, descriptor, descriptor.GetStackParameterCount(),
36 CallDescriptor::kNoFlags, Operator::kNoProperties,
37 MachineType::AnyTagged(), result_size),
38 flags, name) {}
39
40CodeAssembler::CodeAssembler(Isolate* isolate, Zone* zone, int parameter_count,
41 Code::Flags flags, const char* name)
42 : CodeAssembler(isolate, zone,
43 Linkage::GetJSCallDescriptor(zone, false, parameter_count,
44 CallDescriptor::kNoFlags),
45 flags, name) {}
46
47CodeAssembler::CodeAssembler(Isolate* isolate, Zone* zone,
48 CallDescriptor* call_descriptor, Code::Flags flags,
49 const char* name)
50 : raw_assembler_(new RawMachineAssembler(
51 isolate, new (zone) Graph(zone), call_descriptor,
52 MachineType::PointerRepresentation(),
53 InstructionSelector::SupportedMachineOperatorFlags())),
54 flags_(flags),
55 name_(name),
56 code_generated_(false),
57 variables_(zone) {}
58
59CodeAssembler::~CodeAssembler() {}
60
61void CodeAssembler::CallPrologue() {}
62
63void CodeAssembler::CallEpilogue() {}
64
65Handle<Code> CodeAssembler::GenerateCode() {
66 DCHECK(!code_generated_);
67
68 Schedule* schedule = raw_assembler_->Export();
69 Handle<Code> code = Pipeline::GenerateCodeForCodeStub(
70 isolate(), raw_assembler_->call_descriptor(), graph(), schedule, flags_,
71 name_);
72
73 code_generated_ = true;
74 return code;
75}
76
77bool CodeAssembler::Is64() const { return raw_assembler_->machine()->Is64(); }
78
79bool CodeAssembler::IsFloat64RoundUpSupported() const {
80 return raw_assembler_->machine()->Float64RoundUp().IsSupported();
81}
82
83bool CodeAssembler::IsFloat64RoundDownSupported() const {
84 return raw_assembler_->machine()->Float64RoundDown().IsSupported();
85}
86
87bool CodeAssembler::IsFloat64RoundTruncateSupported() const {
88 return raw_assembler_->machine()->Float64RoundTruncate().IsSupported();
89}
90
91Node* CodeAssembler::Int32Constant(int32_t value) {
92 return raw_assembler_->Int32Constant(value);
93}
94
95Node* CodeAssembler::Int64Constant(int64_t value) {
96 return raw_assembler_->Int64Constant(value);
97}
98
99Node* CodeAssembler::IntPtrConstant(intptr_t value) {
100 return raw_assembler_->IntPtrConstant(value);
101}
102
103Node* CodeAssembler::NumberConstant(double value) {
104 return raw_assembler_->NumberConstant(value);
105}
106
107Node* CodeAssembler::SmiConstant(Smi* value) {
108 return IntPtrConstant(bit_cast<intptr_t>(value));
109}
110
111Node* CodeAssembler::HeapConstant(Handle<HeapObject> object) {
112 return raw_assembler_->HeapConstant(object);
113}
114
115Node* CodeAssembler::BooleanConstant(bool value) {
116 return raw_assembler_->BooleanConstant(value);
117}
118
119Node* CodeAssembler::ExternalConstant(ExternalReference address) {
120 return raw_assembler_->ExternalConstant(address);
121}
122
123Node* CodeAssembler::Float64Constant(double value) {
124 return raw_assembler_->Float64Constant(value);
125}
126
127Node* CodeAssembler::NaNConstant() {
128 return LoadRoot(Heap::kNanValueRootIndex);
129}
130
131bool CodeAssembler::ToInt32Constant(Node* node, int32_t& out_value) {
132 Int64Matcher m(node);
133 if (m.HasValue() &&
134 m.IsInRange(std::numeric_limits<int32_t>::min(),
135 std::numeric_limits<int32_t>::max())) {
136 out_value = static_cast<int32_t>(m.Value());
137 return true;
138 }
139
140 return false;
141}
142
143bool CodeAssembler::ToInt64Constant(Node* node, int64_t& out_value) {
144 Int64Matcher m(node);
145 if (m.HasValue()) out_value = m.Value();
146 return m.HasValue();
147}
148
149bool CodeAssembler::ToIntPtrConstant(Node* node, intptr_t& out_value) {
150 IntPtrMatcher m(node);
151 if (m.HasValue()) out_value = m.Value();
152 return m.HasValue();
153}
154
155Node* CodeAssembler::Parameter(int value) {
156 return raw_assembler_->Parameter(value);
157}
158
159void CodeAssembler::Return(Node* value) {
160 return raw_assembler_->Return(value);
161}
162
163void CodeAssembler::Bind(CodeAssembler::Label* label) { return label->Bind(); }
164
165Node* CodeAssembler::LoadFramePointer() {
166 return raw_assembler_->LoadFramePointer();
167}
168
169Node* CodeAssembler::LoadParentFramePointer() {
170 return raw_assembler_->LoadParentFramePointer();
171}
172
173Node* CodeAssembler::LoadStackPointer() {
174 return raw_assembler_->LoadStackPointer();
175}
176
177Node* CodeAssembler::SmiShiftBitsConstant() {
178 return IntPtrConstant(kSmiShiftSize + kSmiTagSize);
179}
180
181#define DEFINE_CODE_ASSEMBLER_BINARY_OP(name) \
182 Node* CodeAssembler::name(Node* a, Node* b) { \
183 return raw_assembler_->name(a, b); \
184 }
185CODE_ASSEMBLER_BINARY_OP_LIST(DEFINE_CODE_ASSEMBLER_BINARY_OP)
186#undef DEFINE_CODE_ASSEMBLER_BINARY_OP
187
188Node* CodeAssembler::WordShl(Node* value, int shift) {
189 return raw_assembler_->WordShl(value, IntPtrConstant(shift));
190}
191
192Node* CodeAssembler::WordShr(Node* value, int shift) {
193 return raw_assembler_->WordShr(value, IntPtrConstant(shift));
194}
195
196Node* CodeAssembler::ChangeUint32ToWord(Node* value) {
197 if (raw_assembler_->machine()->Is64()) {
198 value = raw_assembler_->ChangeUint32ToUint64(value);
199 }
200 return value;
201}
202
203Node* CodeAssembler::ChangeInt32ToIntPtr(Node* value) {
204 if (raw_assembler_->machine()->Is64()) {
205 value = raw_assembler_->ChangeInt32ToInt64(value);
206 }
207 return value;
208}
209
210#define DEFINE_CODE_ASSEMBLER_UNARY_OP(name) \
211 Node* CodeAssembler::name(Node* a) { return raw_assembler_->name(a); }
212CODE_ASSEMBLER_UNARY_OP_LIST(DEFINE_CODE_ASSEMBLER_UNARY_OP)
213#undef DEFINE_CODE_ASSEMBLER_UNARY_OP
214
215Node* CodeAssembler::Load(MachineType rep, Node* base) {
216 return raw_assembler_->Load(rep, base);
217}
218
219Node* CodeAssembler::Load(MachineType rep, Node* base, Node* index) {
220 return raw_assembler_->Load(rep, base, index);
221}
222
223Node* CodeAssembler::AtomicLoad(MachineType rep, Node* base, Node* index) {
224 return raw_assembler_->AtomicLoad(rep, base, index);
225}
226
227Node* CodeAssembler::LoadRoot(Heap::RootListIndex root_index) {
228 if (isolate()->heap()->RootCanBeTreatedAsConstant(root_index)) {
229 Handle<Object> root = isolate()->heap()->root_handle(root_index);
230 if (root->IsSmi()) {
231 return SmiConstant(Smi::cast(*root));
232 } else {
233 return HeapConstant(Handle<HeapObject>::cast(root));
234 }
235 }
236
237 Node* roots_array_start =
238 ExternalConstant(ExternalReference::roots_array_start(isolate()));
239 return Load(MachineType::AnyTagged(), roots_array_start,
240 IntPtrConstant(root_index * kPointerSize));
241}
242
243Node* CodeAssembler::Store(MachineRepresentation rep, Node* base, Node* value) {
244 return raw_assembler_->Store(rep, base, value, kFullWriteBarrier);
245}
246
247Node* CodeAssembler::Store(MachineRepresentation rep, Node* base, Node* index,
248 Node* value) {
249 return raw_assembler_->Store(rep, base, index, value, kFullWriteBarrier);
250}
251
252Node* CodeAssembler::StoreNoWriteBarrier(MachineRepresentation rep, Node* base,
253 Node* value) {
254 return raw_assembler_->Store(rep, base, value, kNoWriteBarrier);
255}
256
257Node* CodeAssembler::StoreNoWriteBarrier(MachineRepresentation rep, Node* base,
258 Node* index, Node* value) {
259 return raw_assembler_->Store(rep, base, index, value, kNoWriteBarrier);
260}
261
262Node* CodeAssembler::AtomicStore(MachineRepresentation rep, Node* base,
263 Node* index, Node* value) {
264 return raw_assembler_->AtomicStore(rep, base, index, value);
265}
266
267Node* CodeAssembler::StoreRoot(Heap::RootListIndex root_index, Node* value) {
268 DCHECK(Heap::RootCanBeWrittenAfterInitialization(root_index));
269 Node* roots_array_start =
270 ExternalConstant(ExternalReference::roots_array_start(isolate()));
271 return StoreNoWriteBarrier(MachineRepresentation::kTagged, roots_array_start,
272 IntPtrConstant(root_index * kPointerSize), value);
273}
274
275Node* CodeAssembler::Projection(int index, Node* value) {
276 return raw_assembler_->Projection(index, value);
277}
278
279void CodeAssembler::BranchIf(Node* condition, Label* if_true, Label* if_false) {
280 Label if_condition_is_true(this), if_condition_is_false(this);
281 Branch(condition, &if_condition_is_true, &if_condition_is_false);
282 Bind(&if_condition_is_true);
283 Goto(if_true);
284 Bind(&if_condition_is_false);
285 Goto(if_false);
286}
287
288Node* CodeAssembler::CallN(CallDescriptor* descriptor, Node* code_target,
289 Node** args) {
290 CallPrologue();
291 Node* return_value = raw_assembler_->CallN(descriptor, code_target, args);
292 CallEpilogue();
293 return return_value;
294}
295
296Node* CodeAssembler::TailCallN(CallDescriptor* descriptor, Node* code_target,
297 Node** args) {
298 return raw_assembler_->TailCallN(descriptor, code_target, args);
299}
300
301Node* CodeAssembler::CallRuntime(Runtime::FunctionId function_id,
302 Node* context) {
303 CallPrologue();
304 Node* return_value = raw_assembler_->CallRuntime0(function_id, context);
305 CallEpilogue();
306 return return_value;
307}
308
309Node* CodeAssembler::CallRuntime(Runtime::FunctionId function_id, Node* context,
310 Node* arg1) {
311 CallPrologue();
312 Node* return_value = raw_assembler_->CallRuntime1(function_id, arg1, context);
313 CallEpilogue();
314 return return_value;
315}
316
317Node* CodeAssembler::CallRuntime(Runtime::FunctionId function_id, Node* context,
318 Node* arg1, Node* arg2) {
319 CallPrologue();
320 Node* return_value =
321 raw_assembler_->CallRuntime2(function_id, arg1, arg2, context);
322 CallEpilogue();
323 return return_value;
324}
325
326Node* CodeAssembler::CallRuntime(Runtime::FunctionId function_id, Node* context,
327 Node* arg1, Node* arg2, Node* arg3) {
328 CallPrologue();
329 Node* return_value =
330 raw_assembler_->CallRuntime3(function_id, arg1, arg2, arg3, context);
331 CallEpilogue();
332 return return_value;
333}
334
335Node* CodeAssembler::CallRuntime(Runtime::FunctionId function_id, Node* context,
336 Node* arg1, Node* arg2, Node* arg3,
337 Node* arg4) {
338 CallPrologue();
339 Node* return_value = raw_assembler_->CallRuntime4(function_id, arg1, arg2,
340 arg3, arg4, context);
341 CallEpilogue();
342 return return_value;
343}
344
345Node* CodeAssembler::TailCallRuntime(Runtime::FunctionId function_id,
346 Node* context) {
347 return raw_assembler_->TailCallRuntime0(function_id, context);
348}
349
350Node* CodeAssembler::TailCallRuntime(Runtime::FunctionId function_id,
351 Node* context, Node* arg1) {
352 return raw_assembler_->TailCallRuntime1(function_id, arg1, context);
353}
354
355Node* CodeAssembler::TailCallRuntime(Runtime::FunctionId function_id,
356 Node* context, Node* arg1, Node* arg2) {
357 return raw_assembler_->TailCallRuntime2(function_id, arg1, arg2, context);
358}
359
360Node* CodeAssembler::TailCallRuntime(Runtime::FunctionId function_id,
361 Node* context, Node* arg1, Node* arg2,
362 Node* arg3) {
363 return raw_assembler_->TailCallRuntime3(function_id, arg1, arg2, arg3,
364 context);
365}
366
367Node* CodeAssembler::TailCallRuntime(Runtime::FunctionId function_id,
368 Node* context, Node* arg1, Node* arg2,
369 Node* arg3, Node* arg4) {
370 return raw_assembler_->TailCallRuntime4(function_id, arg1, arg2, arg3, arg4,
371 context);
372}
373
374Node* CodeAssembler::CallStub(Callable const& callable, Node* context,
375 Node* arg1, size_t result_size) {
376 Node* target = HeapConstant(callable.code());
377 return CallStub(callable.descriptor(), target, context, arg1, result_size);
378}
379
380Node* CodeAssembler::CallStub(Callable const& callable, Node* context,
381 Node* arg1, Node* arg2, size_t result_size) {
382 Node* target = HeapConstant(callable.code());
383 return CallStub(callable.descriptor(), target, context, arg1, arg2,
384 result_size);
385}
386
387Node* CodeAssembler::CallStub(Callable const& callable, Node* context,
388 Node* arg1, Node* arg2, Node* arg3,
389 size_t result_size) {
390 Node* target = HeapConstant(callable.code());
391 return CallStub(callable.descriptor(), target, context, arg1, arg2, arg3,
392 result_size);
393}
394
395Node* CodeAssembler::CallStub(const CallInterfaceDescriptor& descriptor,
396 Node* target, Node* context, Node* arg1,
397 size_t result_size) {
398 CallDescriptor* call_descriptor = Linkage::GetStubCallDescriptor(
399 isolate(), zone(), descriptor, descriptor.GetStackParameterCount(),
400 CallDescriptor::kNoFlags, Operator::kNoProperties,
401 MachineType::AnyTagged(), result_size);
402
403 Node** args = zone()->NewArray<Node*>(2);
404 args[0] = arg1;
405 args[1] = context;
406
407 return CallN(call_descriptor, target, args);
408}
409
410Node* CodeAssembler::CallStub(const CallInterfaceDescriptor& descriptor,
411 Node* target, Node* context, Node* arg1,
412 Node* arg2, size_t result_size) {
413 CallDescriptor* call_descriptor = Linkage::GetStubCallDescriptor(
414 isolate(), zone(), descriptor, descriptor.GetStackParameterCount(),
415 CallDescriptor::kNoFlags, Operator::kNoProperties,
416 MachineType::AnyTagged(), result_size);
417
418 Node** args = zone()->NewArray<Node*>(3);
419 args[0] = arg1;
420 args[1] = arg2;
421 args[2] = context;
422
423 return CallN(call_descriptor, target, args);
424}
425
426Node* CodeAssembler::CallStub(const CallInterfaceDescriptor& descriptor,
427 Node* target, Node* context, Node* arg1,
428 Node* arg2, Node* arg3, size_t result_size) {
429 CallDescriptor* call_descriptor = Linkage::GetStubCallDescriptor(
430 isolate(), zone(), descriptor, descriptor.GetStackParameterCount(),
431 CallDescriptor::kNoFlags, Operator::kNoProperties,
432 MachineType::AnyTagged(), result_size);
433
434 Node** args = zone()->NewArray<Node*>(4);
435 args[0] = arg1;
436 args[1] = arg2;
437 args[2] = arg3;
438 args[3] = context;
439
440 return CallN(call_descriptor, target, args);
441}
442
443Node* CodeAssembler::CallStub(const CallInterfaceDescriptor& descriptor,
444 Node* target, Node* context, Node* arg1,
445 Node* arg2, Node* arg3, Node* arg4,
446 size_t result_size) {
447 CallDescriptor* call_descriptor = Linkage::GetStubCallDescriptor(
448 isolate(), zone(), descriptor, descriptor.GetStackParameterCount(),
449 CallDescriptor::kNoFlags, Operator::kNoProperties,
450 MachineType::AnyTagged(), result_size);
451
452 Node** args = zone()->NewArray<Node*>(5);
453 args[0] = arg1;
454 args[1] = arg2;
455 args[2] = arg3;
456 args[3] = arg4;
457 args[4] = context;
458
459 return CallN(call_descriptor, target, args);
460}
461
462Node* CodeAssembler::CallStub(const CallInterfaceDescriptor& descriptor,
463 Node* target, Node* context, Node* arg1,
464 Node* arg2, Node* arg3, Node* arg4, Node* arg5,
465 size_t result_size) {
466 CallDescriptor* call_descriptor = Linkage::GetStubCallDescriptor(
467 isolate(), zone(), descriptor, descriptor.GetStackParameterCount(),
468 CallDescriptor::kNoFlags, Operator::kNoProperties,
469 MachineType::AnyTagged(), result_size);
470
471 Node** args = zone()->NewArray<Node*>(6);
472 args[0] = arg1;
473 args[1] = arg2;
474 args[2] = arg3;
475 args[3] = arg4;
476 args[4] = arg5;
477 args[5] = context;
478
479 return CallN(call_descriptor, target, args);
480}
481
482Node* CodeAssembler::TailCallStub(Callable const& callable, Node* context,
483 Node* arg1, Node* arg2, size_t result_size) {
484 Node* target = HeapConstant(callable.code());
485 return TailCallStub(callable.descriptor(), target, context, arg1, arg2,
486 result_size);
487}
488
489Node* CodeAssembler::TailCallStub(Callable const& callable, Node* context,
490 Node* arg1, Node* arg2, Node* arg3,
491 size_t result_size) {
492 Node* target = HeapConstant(callable.code());
493 return TailCallStub(callable.descriptor(), target, context, arg1, arg2, arg3,
494 result_size);
495}
496
497Node* CodeAssembler::TailCallStub(const CallInterfaceDescriptor& descriptor,
498 Node* target, Node* context, Node* arg1,
499 Node* arg2, size_t result_size) {
500 CallDescriptor* call_descriptor = Linkage::GetStubCallDescriptor(
501 isolate(), zone(), descriptor, descriptor.GetStackParameterCount(),
502 CallDescriptor::kSupportsTailCalls, Operator::kNoProperties,
503 MachineType::AnyTagged(), result_size);
504
505 Node** args = zone()->NewArray<Node*>(3);
506 args[0] = arg1;
507 args[1] = arg2;
508 args[2] = context;
509
510 return raw_assembler_->TailCallN(call_descriptor, target, args);
511}
512
513Node* CodeAssembler::TailCallStub(const CallInterfaceDescriptor& descriptor,
514 Node* target, Node* context, Node* arg1,
515 Node* arg2, Node* arg3, size_t result_size) {
516 CallDescriptor* call_descriptor = Linkage::GetStubCallDescriptor(
517 isolate(), zone(), descriptor, descriptor.GetStackParameterCount(),
518 CallDescriptor::kSupportsTailCalls, Operator::kNoProperties,
519 MachineType::AnyTagged(), result_size);
520
521 Node** args = zone()->NewArray<Node*>(4);
522 args[0] = arg1;
523 args[1] = arg2;
524 args[2] = arg3;
525 args[3] = context;
526
527 return raw_assembler_->TailCallN(call_descriptor, target, args);
528}
529
530Node* CodeAssembler::TailCallBytecodeDispatch(
531 const CallInterfaceDescriptor& interface_descriptor,
532 Node* code_target_address, Node** args) {
533 CallDescriptor* descriptor = Linkage::GetBytecodeDispatchCallDescriptor(
534 isolate(), zone(), interface_descriptor,
535 interface_descriptor.GetStackParameterCount());
536 return raw_assembler_->TailCallN(descriptor, code_target_address, args);
537}
538
539void CodeAssembler::Goto(CodeAssembler::Label* label) {
540 label->MergeVariables();
541 raw_assembler_->Goto(label->label_);
542}
543
544void CodeAssembler::GotoIf(Node* condition, Label* true_label) {
545 Label false_label(this);
546 Branch(condition, true_label, &false_label);
547 Bind(&false_label);
548}
549
550void CodeAssembler::GotoUnless(Node* condition, Label* false_label) {
551 Label true_label(this);
552 Branch(condition, &true_label, false_label);
553 Bind(&true_label);
554}
555
556void CodeAssembler::Branch(Node* condition, CodeAssembler::Label* true_label,
557 CodeAssembler::Label* false_label) {
558 true_label->MergeVariables();
559 false_label->MergeVariables();
560 return raw_assembler_->Branch(condition, true_label->label_,
561 false_label->label_);
562}
563
564void CodeAssembler::Switch(Node* index, Label* default_label,
565 int32_t* case_values, Label** case_labels,
566 size_t case_count) {
567 RawMachineLabel** labels =
568 new (zone()->New(sizeof(RawMachineLabel*) * case_count))
569 RawMachineLabel*[case_count];
570 for (size_t i = 0; i < case_count; ++i) {
571 labels[i] = case_labels[i]->label_;
572 case_labels[i]->MergeVariables();
573 default_label->MergeVariables();
574 }
575 return raw_assembler_->Switch(index, default_label->label_, case_values,
576 labels, case_count);
577}
578
579// RawMachineAssembler delegate helpers:
580Isolate* CodeAssembler::isolate() const { return raw_assembler_->isolate(); }
581
582Factory* CodeAssembler::factory() const { return isolate()->factory(); }
583
584Graph* CodeAssembler::graph() const { return raw_assembler_->graph(); }
585
586Zone* CodeAssembler::zone() const { return raw_assembler_->zone(); }
587
588// The core implementation of Variable is stored through an indirection so
589// that it can outlive the often block-scoped Variable declarations. This is
590// needed to ensure that variable binding and merging through phis can
591// properly be verified.
592class CodeAssembler::Variable::Impl : public ZoneObject {
593 public:
594 explicit Impl(MachineRepresentation rep) : value_(nullptr), rep_(rep) {}
595 Node* value_;
596 MachineRepresentation rep_;
597};
598
599CodeAssembler::Variable::Variable(CodeAssembler* assembler,
600 MachineRepresentation rep)
601 : impl_(new (assembler->zone()) Impl(rep)) {
602 assembler->variables_.push_back(impl_);
603}
604
605void CodeAssembler::Variable::Bind(Node* value) { impl_->value_ = value; }
606
607Node* CodeAssembler::Variable::value() const {
608 DCHECK_NOT_NULL(impl_->value_);
609 return impl_->value_;
610}
611
612MachineRepresentation CodeAssembler::Variable::rep() const {
613 return impl_->rep_;
614}
615
616bool CodeAssembler::Variable::IsBound() const {
617 return impl_->value_ != nullptr;
618}
619
620CodeAssembler::Label::Label(CodeAssembler* assembler, int merged_value_count,
621 CodeAssembler::Variable** merged_variables,
622 CodeAssembler::Label::Type type)
623 : bound_(false), merge_count_(0), assembler_(assembler), label_(nullptr) {
624 void* buffer = assembler->zone()->New(sizeof(RawMachineLabel));
625 label_ = new (buffer)
626 RawMachineLabel(type == kDeferred ? RawMachineLabel::kDeferred
627 : RawMachineLabel::kNonDeferred);
628 for (int i = 0; i < merged_value_count; ++i) {
629 variable_phis_[merged_variables[i]->impl_] = nullptr;
630 }
631}
632
633void CodeAssembler::Label::MergeVariables() {
634 ++merge_count_;
635 for (auto var : assembler_->variables_) {
636 size_t count = 0;
637 Node* node = var->value_;
638 if (node != nullptr) {
639 auto i = variable_merges_.find(var);
640 if (i != variable_merges_.end()) {
641 i->second.push_back(node);
642 count = i->second.size();
643 } else {
644 count = 1;
645 variable_merges_[var] = std::vector<Node*>(1, node);
646 }
647 }
648 // If the following asserts, then you've jumped to a label without a bound
649 // variable along that path that expects to merge its value into a phi.
650 DCHECK(variable_phis_.find(var) == variable_phis_.end() ||
651 count == merge_count_);
652 USE(count);
653
654 // If the label is already bound, we already know the set of variables to
655 // merge and phi nodes have already been created.
656 if (bound_) {
657 auto phi = variable_phis_.find(var);
658 if (phi != variable_phis_.end()) {
659 DCHECK_NOT_NULL(phi->second);
660 assembler_->raw_assembler_->AppendPhiInput(phi->second, node);
661 } else {
662 auto i = variable_merges_.find(var);
663 if (i != variable_merges_.end()) {
664 // If the following assert fires, then you've declared a variable that
665 // has the same bound value along all paths up until the point you
666 // bound this label, but then later merged a path with a new value for
667 // the variable after the label bind (it's not possible to add phis to
668 // the bound label after the fact, just make sure to list the variable
669 // in the label's constructor's list of merged variables).
670 DCHECK(find_if(i->second.begin(), i->second.end(),
671 [node](Node* e) -> bool { return node != e; }) ==
672 i->second.end());
673 }
674 }
675 }
676 }
677}
678
679void CodeAssembler::Label::Bind() {
680 DCHECK(!bound_);
681 assembler_->raw_assembler_->Bind(label_);
682
683 // Make sure that all variables that have changed along any path up to this
684 // point are marked as merge variables.
685 for (auto var : assembler_->variables_) {
686 Node* shared_value = nullptr;
687 auto i = variable_merges_.find(var);
688 if (i != variable_merges_.end()) {
689 for (auto value : i->second) {
690 DCHECK(value != nullptr);
691 if (value != shared_value) {
692 if (shared_value == nullptr) {
693 shared_value = value;
694 } else {
695 variable_phis_[var] = nullptr;
696 }
697 }
698 }
699 }
700 }
701
702 for (auto var : variable_phis_) {
703 CodeAssembler::Variable::Impl* var_impl = var.first;
704 auto i = variable_merges_.find(var_impl);
705 // If the following assert fires, then a variable that has been marked as
706 // being merged at the label--either by explicitly marking it so in the
707 // label constructor or by having seen different bound values at branches
708 // into the label--doesn't have a bound value along all of the paths that
709 // have been merged into the label up to this point.
710 DCHECK(i != variable_merges_.end() && i->second.size() == merge_count_);
711 Node* phi = assembler_->raw_assembler_->Phi(
712 var.first->rep_, static_cast<int>(merge_count_), &(i->second[0]));
713 variable_phis_[var_impl] = phi;
714 }
715
716 // Bind all variables to a merge phi, the common value along all paths or
717 // null.
718 for (auto var : assembler_->variables_) {
719 auto i = variable_phis_.find(var);
720 if (i != variable_phis_.end()) {
721 var->value_ = i->second;
722 } else {
723 auto j = variable_merges_.find(var);
724 if (j != variable_merges_.end() && j->second.size() == merge_count_) {
725 var->value_ = j->second.back();
726 } else {
727 var->value_ = nullptr;
728 }
729 }
730 }
731
732 bound_ = true;
733}
734
735} // namespace compiler
736} // namespace internal
737} // namespace v8