1 // 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/builtins/constants-table-builder.h"
10 #include "src/code-factory.h"
11 #include "src/compiler/graph.h"
12 #include "src/compiler/instruction-selector.h"
13 #include "src/compiler/linkage.h"
14 #include "src/compiler/node-matchers.h"
15 #include "src/compiler/pipeline.h"
16 #include "src/compiler/raw-machine-assembler.h"
17 #include "src/compiler/schedule.h"
18 #include "src/frames.h"
19 #include "src/interface-descriptors.h"
20 #include "src/interpreter/bytecodes.h"
21 #include "src/lsan.h"
22 #include "src/machine-type.h"
23 #include "src/macro-assembler.h"
24 #include "src/objects-inl.h"
25 #include "src/snapshot/serializer-common.h"
26 #include "src/utils.h"
27 #include "src/zone/zone.h"
28 
29 #define REPEAT_1_TO_2(V, T) V(T) V(T, T)
30 #define REPEAT_1_TO_3(V, T) REPEAT_1_TO_2(V, T) V(T, T, T)
31 #define REPEAT_1_TO_4(V, T) REPEAT_1_TO_3(V, T) V(T, T, T, T)
32 #define REPEAT_1_TO_5(V, T) REPEAT_1_TO_4(V, T) V(T, T, T, T, T)
33 #define REPEAT_1_TO_6(V, T) REPEAT_1_TO_5(V, T) V(T, T, T, T, T, T)
34 #define REPEAT_1_TO_7(V, T) REPEAT_1_TO_6(V, T) V(T, T, T, T, T, T, T)
35 #define REPEAT_1_TO_8(V, T) REPEAT_1_TO_7(V, T) V(T, T, T, T, T, T, T, T)
36 #define REPEAT_1_TO_9(V, T) REPEAT_1_TO_8(V, T) V(T, T, T, T, T, T, T, T, T)
37 #define REPEAT_1_TO_10(V, T) REPEAT_1_TO_9(V, T) V(T, T, T, T, T, T, T, T, T, T)
38 #define REPEAT_1_TO_11(V, T) \
39   REPEAT_1_TO_10(V, T) V(T, T, T, T, T, T, T, T, T, T, T)
40 #define REPEAT_1_TO_12(V, T) \
41   REPEAT_1_TO_11(V, T) V(T, T, T, T, T, T, T, T, T, T, T, T)
42 
43 namespace v8 {
44 namespace internal {
45 
46 constexpr MachineType MachineTypeOf<Smi>::value;
47 constexpr MachineType MachineTypeOf<Object>::value;
48 
49 namespace compiler {
50 
51 static_assert(std::is_convertible<TNode<Number>, TNode<Object>>::value,
52               "test subtyping");
53 static_assert(std::is_convertible<TNode<UnionT<Smi, HeapNumber>>,
54                                   TNode<UnionT<Smi, HeapObject>>>::value,
55               "test subtyping");
56 static_assert(
57     !std::is_convertible<TNode<UnionT<Smi, HeapObject>>, TNode<Number>>::value,
58     "test subtyping");
59 
CodeAssemblerState(Isolate * isolate,Zone * zone,const CallInterfaceDescriptor & descriptor,Code::Kind kind,const char * name,PoisoningMitigationLevel poisoning_level,size_t result_size,uint32_t stub_key,int32_t builtin_index)60 CodeAssemblerState::CodeAssemblerState(
61     Isolate* isolate, Zone* zone, const CallInterfaceDescriptor& descriptor,
62     Code::Kind kind, const char* name, PoisoningMitigationLevel poisoning_level,
63     size_t result_size, uint32_t stub_key, int32_t builtin_index)
64     // TODO(rmcilroy): Should we use Linkage::GetBytecodeDispatchDescriptor for
65     // bytecode handlers?
66     : CodeAssemblerState(
67           isolate, zone,
68           Linkage::GetStubCallDescriptor(
69               isolate, zone, descriptor, descriptor.GetStackParameterCount(),
70               CallDescriptor::kNoFlags, Operator::kNoProperties,
71               MachineType::AnyTagged(), result_size),
72           kind, name, poisoning_level, stub_key, builtin_index) {}
73 
CodeAssemblerState(Isolate * isolate,Zone * zone,int parameter_count,Code::Kind kind,const char * name,PoisoningMitigationLevel poisoning_level,int32_t builtin_index)74 CodeAssemblerState::CodeAssemblerState(Isolate* isolate, Zone* zone,
75                                        int parameter_count, Code::Kind kind,
76                                        const char* name,
77                                        PoisoningMitigationLevel poisoning_level,
78                                        int32_t builtin_index)
79     : CodeAssemblerState(
80           isolate, zone,
81           Linkage::GetJSCallDescriptor(zone, false, parameter_count,
82                                        kind == Code::BUILTIN
83                                            ? CallDescriptor::kPushArgumentCount
84                                            : CallDescriptor::kNoFlags),
85           kind, name, poisoning_level, 0, builtin_index) {}
86 
CodeAssemblerState(Isolate * isolate,Zone * zone,CallDescriptor * call_descriptor,Code::Kind kind,const char * name,PoisoningMitigationLevel poisoning_level,uint32_t stub_key,int32_t builtin_index)87 CodeAssemblerState::CodeAssemblerState(Isolate* isolate, Zone* zone,
88                                        CallDescriptor* call_descriptor,
89                                        Code::Kind kind, const char* name,
90                                        PoisoningMitigationLevel poisoning_level,
91                                        uint32_t stub_key, int32_t builtin_index)
92     : raw_assembler_(new RawMachineAssembler(
93           isolate, new (zone) Graph(zone), call_descriptor,
94           MachineType::PointerRepresentation(),
95           InstructionSelector::SupportedMachineOperatorFlags(),
96           InstructionSelector::AlignmentRequirements(), poisoning_level)),
97       kind_(kind),
98       name_(name),
99       stub_key_(stub_key),
100       builtin_index_(builtin_index),
101       code_generated_(false),
102       variables_(zone) {}
103 
~CodeAssemblerState()104 CodeAssemblerState::~CodeAssemblerState() {}
105 
parameter_count() const106 int CodeAssemblerState::parameter_count() const {
107   return static_cast<int>(raw_assembler_->call_descriptor()->ParameterCount());
108 }
109 
~CodeAssembler()110 CodeAssembler::~CodeAssembler() {}
111 
112 #if DEBUG
PrintCurrentBlock(std::ostream & os)113 void CodeAssemblerState::PrintCurrentBlock(std::ostream& os) {
114   raw_assembler_->PrintCurrentBlock(os);
115 }
116 
InsideBlock()117 bool CodeAssemblerState::InsideBlock() { return raw_assembler_->InsideBlock(); }
118 #endif
119 
SetInitialDebugInformation(const char * msg,const char * file,int line)120 void CodeAssemblerState::SetInitialDebugInformation(const char* msg,
121                                                     const char* file,
122                                                     int line) {
123 #if DEBUG
124   AssemblerDebugInfo debug_info = {msg, file, line};
125   raw_assembler_->SetInitialDebugInformation(debug_info);
126 #endif  // DEBUG
127 }
128 
129 class BreakOnNodeDecorator final : public GraphDecorator {
130  public:
BreakOnNodeDecorator(NodeId node_id)131   explicit BreakOnNodeDecorator(NodeId node_id) : node_id_(node_id) {}
132 
Decorate(Node * node)133   void Decorate(Node* node) final {
134     if (node->id() == node_id_) {
135       base::OS::DebugBreak();
136     }
137   }
138 
139  private:
140   NodeId node_id_;
141 };
142 
BreakOnNode(int node_id)143 void CodeAssembler::BreakOnNode(int node_id) {
144   Graph* graph = raw_assembler()->graph();
145   Zone* zone = graph->zone();
146   GraphDecorator* decorator =
147       new (zone) BreakOnNodeDecorator(static_cast<NodeId>(node_id));
148   graph->AddDecorator(decorator);
149 }
150 
RegisterCallGenerationCallbacks(const CodeAssemblerCallback & call_prologue,const CodeAssemblerCallback & call_epilogue)151 void CodeAssembler::RegisterCallGenerationCallbacks(
152     const CodeAssemblerCallback& call_prologue,
153     const CodeAssemblerCallback& call_epilogue) {
154   // The callback can be registered only once.
155   DCHECK(!state_->call_prologue_);
156   DCHECK(!state_->call_epilogue_);
157   state_->call_prologue_ = call_prologue;
158   state_->call_epilogue_ = call_epilogue;
159 }
160 
UnregisterCallGenerationCallbacks()161 void CodeAssembler::UnregisterCallGenerationCallbacks() {
162   state_->call_prologue_ = nullptr;
163   state_->call_epilogue_ = nullptr;
164 }
165 
CallPrologue()166 void CodeAssembler::CallPrologue() {
167   if (state_->call_prologue_) {
168     state_->call_prologue_();
169   }
170 }
171 
CallEpilogue()172 void CodeAssembler::CallEpilogue() {
173   if (state_->call_epilogue_) {
174     state_->call_epilogue_();
175   }
176 }
177 
Word32ShiftIsSafe() const178 bool CodeAssembler::Word32ShiftIsSafe() const {
179   return raw_assembler()->machine()->Word32ShiftIsSafe();
180 }
181 
poisoning_level() const182 PoisoningMitigationLevel CodeAssembler::poisoning_level() const {
183   return raw_assembler()->poisoning_level();
184 }
185 
186 // static
GenerateCode(CodeAssemblerState * state)187 Handle<Code> CodeAssembler::GenerateCode(CodeAssemblerState* state) {
188   DCHECK(!state->code_generated_);
189 
190   RawMachineAssembler* rasm = state->raw_assembler_.get();
191   Schedule* schedule = rasm->Export();
192 
193   JumpOptimizationInfo jump_opt;
194   bool should_optimize_jumps =
195       rasm->isolate()->serializer_enabled() && FLAG_turbo_rewrite_far_jumps;
196 
197   Handle<Code> code = Pipeline::GenerateCodeForCodeStub(
198       rasm->isolate(), rasm->call_descriptor(), rasm->graph(), schedule,
199       state->kind_, state->name_, state->stub_key_, state->builtin_index_,
200       should_optimize_jumps ? &jump_opt : nullptr, rasm->poisoning_level());
201 
202   if (jump_opt.is_optimizable()) {
203     jump_opt.set_optimizing();
204 
205     // Regenerate machine code
206     code = Pipeline::GenerateCodeForCodeStub(
207         rasm->isolate(), rasm->call_descriptor(), rasm->graph(), schedule,
208         state->kind_, state->name_, state->stub_key_, state->builtin_index_,
209         &jump_opt, rasm->poisoning_level());
210   }
211 
212   state->code_generated_ = true;
213   return code;
214 }
215 
Is64() const216 bool CodeAssembler::Is64() const { return raw_assembler()->machine()->Is64(); }
217 
IsFloat64RoundUpSupported() const218 bool CodeAssembler::IsFloat64RoundUpSupported() const {
219   return raw_assembler()->machine()->Float64RoundUp().IsSupported();
220 }
221 
IsFloat64RoundDownSupported() const222 bool CodeAssembler::IsFloat64RoundDownSupported() const {
223   return raw_assembler()->machine()->Float64RoundDown().IsSupported();
224 }
225 
IsFloat64RoundTiesEvenSupported() const226 bool CodeAssembler::IsFloat64RoundTiesEvenSupported() const {
227   return raw_assembler()->machine()->Float64RoundTiesEven().IsSupported();
228 }
229 
IsFloat64RoundTruncateSupported() const230 bool CodeAssembler::IsFloat64RoundTruncateSupported() const {
231   return raw_assembler()->machine()->Float64RoundTruncate().IsSupported();
232 }
233 
IsInt32AbsWithOverflowSupported() const234 bool CodeAssembler::IsInt32AbsWithOverflowSupported() const {
235   return raw_assembler()->machine()->Int32AbsWithOverflow().IsSupported();
236 }
237 
IsInt64AbsWithOverflowSupported() const238 bool CodeAssembler::IsInt64AbsWithOverflowSupported() const {
239   return raw_assembler()->machine()->Int64AbsWithOverflow().IsSupported();
240 }
241 
IsIntPtrAbsWithOverflowSupported() const242 bool CodeAssembler::IsIntPtrAbsWithOverflowSupported() const {
243   return Is64() ? IsInt64AbsWithOverflowSupported()
244                 : IsInt32AbsWithOverflowSupported();
245 }
246 
247 #ifdef V8_EMBEDDED_BUILTINS
LookupConstant(Handle<HeapObject> object)248 TNode<HeapObject> CodeAssembler::LookupConstant(Handle<HeapObject> object) {
249   DCHECK(isolate()->ShouldLoadConstantsFromRootList());
250 
251   // Ensure the given object is in the builtins constants table and fetch its
252   // index.
253   BuiltinsConstantsTableBuilder* builder =
254       isolate()->builtins_constants_table_builder();
255   uint32_t index = builder->AddObject(object);
256 
257   // The builtins constants table is loaded through the root register on all
258   // supported platforms. This is checked by the
259   // VerifyBuiltinsIsolateIndependence cctest, which disallows embedded objects
260   // in isolate-independent builtins.
261   DCHECK(isolate()->heap()->RootCanBeTreatedAsConstant(
262       Heap::kBuiltinsConstantsTableRootIndex));
263   TNode<FixedArray> builtins_constants_table = UncheckedCast<FixedArray>(
264       LoadRoot(Heap::kBuiltinsConstantsTableRootIndex));
265 
266   // Generate the lookup.
267   const int32_t header_size = FixedArray::kHeaderSize - kHeapObjectTag;
268   TNode<IntPtrT> offset = IntPtrConstant(header_size + kPointerSize * index);
269   return UncheckedCast<HeapObject>(
270       Load(MachineType::AnyTagged(), builtins_constants_table, offset));
271 }
272 
273 // External references are stored in the external reference table.
LookupExternalReference(ExternalReference reference)274 TNode<ExternalReference> CodeAssembler::LookupExternalReference(
275     ExternalReference reference) {
276   DCHECK(isolate()->ShouldLoadConstantsFromRootList());
277 
278   // Encode as an index into the external reference table stored on the isolate.
279 
280   ExternalReferenceEncoder encoder(isolate());
281   ExternalReferenceEncoder::Value v = encoder.Encode(reference.address());
282   CHECK(!v.is_from_api());
283   uint32_t index = v.index();
284 
285   // Generate code to load from the external reference table.
286 
287   const intptr_t roots_to_external_reference_offset =
288       Heap::roots_to_external_reference_table_offset()
289 #ifdef V8_TARGET_ARCH_X64
290       - kRootRegisterBias
291 #endif
292       + ExternalReferenceTable::OffsetOfEntry(index);
293 
294   return UncheckedCast<ExternalReference>(
295       Load(MachineType::Pointer(), LoadRootsPointer(),
296            IntPtrConstant(roots_to_external_reference_offset)));
297 }
298 #endif  // V8_EMBEDDED_BUILTINS
299 
Int32Constant(int32_t value)300 TNode<Int32T> CodeAssembler::Int32Constant(int32_t value) {
301   return UncheckedCast<Int32T>(raw_assembler()->Int32Constant(value));
302 }
303 
Int64Constant(int64_t value)304 TNode<Int64T> CodeAssembler::Int64Constant(int64_t value) {
305   return UncheckedCast<Int64T>(raw_assembler()->Int64Constant(value));
306 }
307 
IntPtrConstant(intptr_t value)308 TNode<IntPtrT> CodeAssembler::IntPtrConstant(intptr_t value) {
309   return UncheckedCast<IntPtrT>(raw_assembler()->IntPtrConstant(value));
310 }
311 
NumberConstant(double value)312 TNode<Number> CodeAssembler::NumberConstant(double value) {
313   int smi_value;
314   if (DoubleToSmiInteger(value, &smi_value)) {
315     return UncheckedCast<Number>(SmiConstant(smi_value));
316   } else {
317     // We allocate the heap number constant eagerly at this point instead of
318     // deferring allocation to code generation
319     // (see AllocateAndInstallRequestedHeapObjects) since that makes it easier
320     // to generate constant lookups for embedded builtins.
321     return UncheckedCast<Number>(HeapConstant(
322         isolate()->factory()->NewHeapNumber(value, IMMUTABLE, TENURED)));
323   }
324 }
325 
SmiConstant(Smi * value)326 TNode<Smi> CodeAssembler::SmiConstant(Smi* value) {
327   return UncheckedCast<Smi>(
328       BitcastWordToTaggedSigned(IntPtrConstant(bit_cast<intptr_t>(value))));
329 }
330 
SmiConstant(int value)331 TNode<Smi> CodeAssembler::SmiConstant(int value) {
332   return SmiConstant(Smi::FromInt(value));
333 }
334 
UntypedHeapConstant(Handle<HeapObject> object)335 TNode<HeapObject> CodeAssembler::UntypedHeapConstant(
336     Handle<HeapObject> object) {
337 #ifdef V8_EMBEDDED_BUILTINS
338   // Root constants are simply loaded from the root list, while non-root
339   // constants must be looked up from the builtins constants table.
340   if (isolate()->ShouldLoadConstantsFromRootList()) {
341     Heap::RootListIndex root_index;
342     if (!isolate()->heap()->IsRootHandle(object, &root_index)) {
343       return LookupConstant(object);
344     }
345   }
346 #endif  // V8_EMBEDDED_BUILTINS
347   return UncheckedCast<HeapObject>(raw_assembler()->HeapConstant(object));
348 }
349 
StringConstant(const char * str)350 TNode<String> CodeAssembler::StringConstant(const char* str) {
351   Handle<String> internalized_string =
352       factory()->InternalizeOneByteString(OneByteVector(str));
353   return UncheckedCast<String>(HeapConstant(internalized_string));
354 }
355 
BooleanConstant(bool value)356 TNode<Oddball> CodeAssembler::BooleanConstant(bool value) {
357   return UncheckedCast<Oddball>(raw_assembler()->BooleanConstant(value));
358 }
359 
ExternalConstant(ExternalReference address)360 TNode<ExternalReference> CodeAssembler::ExternalConstant(
361     ExternalReference address) {
362 #ifdef V8_EMBEDDED_BUILTINS
363   if (isolate()->ShouldLoadConstantsFromRootList()) {
364     return LookupExternalReference(address);
365   }
366 #endif  // V8_EMBEDDED_BUILTINS
367   return UncheckedCast<ExternalReference>(
368       raw_assembler()->ExternalConstant(address));
369 }
370 
Float64Constant(double value)371 TNode<Float64T> CodeAssembler::Float64Constant(double value) {
372   return UncheckedCast<Float64T>(raw_assembler()->Float64Constant(value));
373 }
374 
NaNConstant()375 TNode<HeapNumber> CodeAssembler::NaNConstant() {
376   return UncheckedCast<HeapNumber>(LoadRoot(Heap::kNanValueRootIndex));
377 }
378 
ToInt32Constant(Node * node,int32_t & out_value)379 bool CodeAssembler::ToInt32Constant(Node* node, int32_t& out_value) {
380   {
381     Int64Matcher m(node);
382     if (m.HasValue() && m.IsInRange(std::numeric_limits<int32_t>::min(),
383                                     std::numeric_limits<int32_t>::max())) {
384       out_value = static_cast<int32_t>(m.Value());
385       return true;
386     }
387   }
388 
389   {
390     Int32Matcher m(node);
391     if (m.HasValue()) {
392       out_value = m.Value();
393       return true;
394     }
395   }
396 
397   return false;
398 }
399 
ToInt64Constant(Node * node,int64_t & out_value)400 bool CodeAssembler::ToInt64Constant(Node* node, int64_t& out_value) {
401   Int64Matcher m(node);
402   if (m.HasValue()) out_value = m.Value();
403   return m.HasValue();
404 }
405 
ToSmiConstant(Node * node,Smi * & out_value)406 bool CodeAssembler::ToSmiConstant(Node* node, Smi*& out_value) {
407   if (node->opcode() == IrOpcode::kBitcastWordToTaggedSigned) {
408     node = node->InputAt(0);
409   }
410   IntPtrMatcher m(node);
411   if (m.HasValue()) {
412     intptr_t value = m.Value();
413     // Make sure that the value is actually a smi
414     CHECK_EQ(0, value & ((static_cast<intptr_t>(1) << kSmiShiftSize) - 1));
415     out_value = Smi::cast(bit_cast<Object*>(value));
416     return true;
417   }
418   return false;
419 }
420 
ToIntPtrConstant(Node * node,intptr_t & out_value)421 bool CodeAssembler::ToIntPtrConstant(Node* node, intptr_t& out_value) {
422   if (node->opcode() == IrOpcode::kBitcastWordToTaggedSigned ||
423       node->opcode() == IrOpcode::kBitcastWordToTagged) {
424     node = node->InputAt(0);
425   }
426   IntPtrMatcher m(node);
427   if (m.HasValue()) out_value = m.Value();
428   return m.HasValue();
429 }
430 
IsUndefinedConstant(TNode<Object> node)431 bool CodeAssembler::IsUndefinedConstant(TNode<Object> node) {
432   compiler::HeapObjectMatcher m(node);
433   return m.Is(isolate()->factory()->undefined_value());
434 }
435 
IsNullConstant(TNode<Object> node)436 bool CodeAssembler::IsNullConstant(TNode<Object> node) {
437   compiler::HeapObjectMatcher m(node);
438   return m.Is(isolate()->factory()->null_value());
439 }
440 
Parameter(int value)441 Node* CodeAssembler::Parameter(int value) {
442   return raw_assembler()->Parameter(value);
443 }
444 
GetJSContextParameter()445 TNode<Context> CodeAssembler::GetJSContextParameter() {
446   auto call_descriptor = raw_assembler()->call_descriptor();
447   DCHECK(call_descriptor->IsJSFunctionCall());
448   return CAST(Parameter(Linkage::GetJSCallContextParamIndex(
449       static_cast<int>(call_descriptor->JSParameterCount()))));
450 }
451 
Return(SloppyTNode<Object> value)452 void CodeAssembler::Return(SloppyTNode<Object> value) {
453   return raw_assembler()->Return(value);
454 }
455 
Return(SloppyTNode<Object> value1,SloppyTNode<Object> value2)456 void CodeAssembler::Return(SloppyTNode<Object> value1,
457                            SloppyTNode<Object> value2) {
458   return raw_assembler()->Return(value1, value2);
459 }
460 
Return(SloppyTNode<Object> value1,SloppyTNode<Object> value2,SloppyTNode<Object> value3)461 void CodeAssembler::Return(SloppyTNode<Object> value1,
462                            SloppyTNode<Object> value2,
463                            SloppyTNode<Object> value3) {
464   return raw_assembler()->Return(value1, value2, value3);
465 }
466 
PopAndReturn(Node * pop,Node * value)467 void CodeAssembler::PopAndReturn(Node* pop, Node* value) {
468   return raw_assembler()->PopAndReturn(pop, value);
469 }
470 
ReturnIf(Node * condition,Node * value)471 void CodeAssembler::ReturnIf(Node* condition, Node* value) {
472   Label if_return(this), if_continue(this);
473   Branch(condition, &if_return, &if_continue);
474   Bind(&if_return);
475   Return(value);
476   Bind(&if_continue);
477 }
478 
DebugAbort(Node * message)479 void CodeAssembler::DebugAbort(Node* message) {
480   raw_assembler()->DebugAbort(message);
481 }
482 
DebugBreak()483 void CodeAssembler::DebugBreak() { raw_assembler()->DebugBreak(); }
484 
Unreachable()485 void CodeAssembler::Unreachable() {
486   DebugBreak();
487   raw_assembler()->Unreachable();
488 }
489 
Comment(const char * format,...)490 void CodeAssembler::Comment(const char* format, ...) {
491   if (!FLAG_code_comments) return;
492   char buffer[4 * KB];
493   StringBuilder builder(buffer, arraysize(buffer));
494   va_list arguments;
495   va_start(arguments, format);
496   builder.AddFormattedList(format, arguments);
497   va_end(arguments);
498 
499   // Copy the string before recording it in the assembler to avoid
500   // issues when the stack allocated buffer goes out of scope.
501   const int prefix_len = 2;
502   int length = builder.position() + 1;
503   char* copy = reinterpret_cast<char*>(malloc(length + prefix_len));
504   LSAN_IGNORE_OBJECT(copy);
505   MemCopy(copy + prefix_len, builder.Finalize(), length);
506   copy[0] = ';';
507   copy[1] = ' ';
508   raw_assembler()->Comment(copy);
509 }
510 
Bind(Label * label)511 void CodeAssembler::Bind(Label* label) { return label->Bind(); }
512 
513 #if DEBUG
Bind(Label * label,AssemblerDebugInfo debug_info)514 void CodeAssembler::Bind(Label* label, AssemblerDebugInfo debug_info) {
515   return label->Bind(debug_info);
516 }
517 #endif  // DEBUG
518 
LoadFramePointer()519 Node* CodeAssembler::LoadFramePointer() {
520   return raw_assembler()->LoadFramePointer();
521 }
522 
LoadParentFramePointer()523 Node* CodeAssembler::LoadParentFramePointer() {
524   return raw_assembler()->LoadParentFramePointer();
525 }
526 
LoadRootsPointer()527 TNode<IntPtrT> CodeAssembler::LoadRootsPointer() {
528   return UncheckedCast<IntPtrT>(raw_assembler()->LoadRootsPointer());
529 }
530 
LoadStackPointer()531 Node* CodeAssembler::LoadStackPointer() {
532   return raw_assembler()->LoadStackPointer();
533 }
534 
TaggedPoisonOnSpeculation(SloppyTNode<Object> value)535 TNode<Object> CodeAssembler::TaggedPoisonOnSpeculation(
536     SloppyTNode<Object> value) {
537   return UncheckedCast<Object>(
538       raw_assembler()->TaggedPoisonOnSpeculation(value));
539 }
540 
WordPoisonOnSpeculation(SloppyTNode<WordT> value)541 TNode<WordT> CodeAssembler::WordPoisonOnSpeculation(SloppyTNode<WordT> value) {
542   return UncheckedCast<WordT>(raw_assembler()->WordPoisonOnSpeculation(value));
543 }
544 
545 #define DEFINE_CODE_ASSEMBLER_BINARY_OP(name, ResType, Arg1Type, Arg2Type) \
546   TNode<ResType> CodeAssembler::name(SloppyTNode<Arg1Type> a,              \
547                                      SloppyTNode<Arg2Type> b) {            \
548     return UncheckedCast<ResType>(raw_assembler()->name(a, b));            \
549   }
CODE_ASSEMBLER_BINARY_OP_LIST(DEFINE_CODE_ASSEMBLER_BINARY_OP)550 CODE_ASSEMBLER_BINARY_OP_LIST(DEFINE_CODE_ASSEMBLER_BINARY_OP)
551 #undef DEFINE_CODE_ASSEMBLER_BINARY_OP
552 
553 TNode<WordT> CodeAssembler::IntPtrAdd(SloppyTNode<WordT> left,
554                                       SloppyTNode<WordT> right) {
555   intptr_t left_constant;
556   bool is_left_constant = ToIntPtrConstant(left, left_constant);
557   intptr_t right_constant;
558   bool is_right_constant = ToIntPtrConstant(right, right_constant);
559   if (is_left_constant) {
560     if (is_right_constant) {
561       return IntPtrConstant(left_constant + right_constant);
562     }
563     if (left_constant == 0) {
564       return right;
565     }
566   } else if (is_right_constant) {
567     if (right_constant == 0) {
568       return left;
569     }
570   }
571   return UncheckedCast<WordT>(raw_assembler()->IntPtrAdd(left, right));
572 }
573 
IntPtrSub(SloppyTNode<WordT> left,SloppyTNode<WordT> right)574 TNode<WordT> CodeAssembler::IntPtrSub(SloppyTNode<WordT> left,
575                                       SloppyTNode<WordT> right) {
576   intptr_t left_constant;
577   bool is_left_constant = ToIntPtrConstant(left, left_constant);
578   intptr_t right_constant;
579   bool is_right_constant = ToIntPtrConstant(right, right_constant);
580   if (is_left_constant) {
581     if (is_right_constant) {
582       return IntPtrConstant(left_constant - right_constant);
583     }
584   } else if (is_right_constant) {
585     if (right_constant == 0) {
586       return left;
587     }
588   }
589   return UncheckedCast<IntPtrT>(raw_assembler()->IntPtrSub(left, right));
590 }
591 
IntPtrMul(SloppyTNode<WordT> left,SloppyTNode<WordT> right)592 TNode<WordT> CodeAssembler::IntPtrMul(SloppyTNode<WordT> left,
593                                       SloppyTNode<WordT> right) {
594   intptr_t left_constant;
595   bool is_left_constant = ToIntPtrConstant(left, left_constant);
596   intptr_t right_constant;
597   bool is_right_constant = ToIntPtrConstant(right, right_constant);
598   if (is_left_constant) {
599     if (is_right_constant) {
600       return IntPtrConstant(left_constant * right_constant);
601     }
602     if (base::bits::IsPowerOfTwo(left_constant)) {
603       return WordShl(right, WhichPowerOf2(left_constant));
604     }
605   } else if (is_right_constant) {
606     if (base::bits::IsPowerOfTwo(right_constant)) {
607       return WordShl(left, WhichPowerOf2(right_constant));
608     }
609   }
610   return UncheckedCast<IntPtrT>(raw_assembler()->IntPtrMul(left, right));
611 }
612 
WordShl(SloppyTNode<WordT> value,int shift)613 TNode<WordT> CodeAssembler::WordShl(SloppyTNode<WordT> value, int shift) {
614   return (shift != 0) ? WordShl(value, IntPtrConstant(shift)) : value;
615 }
616 
WordShr(SloppyTNode<WordT> value,int shift)617 TNode<WordT> CodeAssembler::WordShr(SloppyTNode<WordT> value, int shift) {
618   return (shift != 0) ? WordShr(value, IntPtrConstant(shift)) : value;
619 }
620 
WordSar(SloppyTNode<WordT> value,int shift)621 TNode<WordT> CodeAssembler::WordSar(SloppyTNode<WordT> value, int shift) {
622   return (shift != 0) ? WordSar(value, IntPtrConstant(shift)) : value;
623 }
624 
Word32Shr(SloppyTNode<Word32T> value,int shift)625 TNode<Word32T> CodeAssembler::Word32Shr(SloppyTNode<Word32T> value, int shift) {
626   return (shift != 0) ? Word32Shr(value, Int32Constant(shift)) : value;
627 }
628 
WordOr(SloppyTNode<WordT> left,SloppyTNode<WordT> right)629 TNode<WordT> CodeAssembler::WordOr(SloppyTNode<WordT> left,
630                                    SloppyTNode<WordT> right) {
631   intptr_t left_constant;
632   bool is_left_constant = ToIntPtrConstant(left, left_constant);
633   intptr_t right_constant;
634   bool is_right_constant = ToIntPtrConstant(right, right_constant);
635   if (is_left_constant) {
636     if (is_right_constant) {
637       return IntPtrConstant(left_constant | right_constant);
638     }
639     if (left_constant == 0) {
640       return right;
641     }
642   } else if (is_right_constant) {
643     if (right_constant == 0) {
644       return left;
645     }
646   }
647   return UncheckedCast<WordT>(raw_assembler()->WordOr(left, right));
648 }
649 
WordAnd(SloppyTNode<WordT> left,SloppyTNode<WordT> right)650 TNode<WordT> CodeAssembler::WordAnd(SloppyTNode<WordT> left,
651                                     SloppyTNode<WordT> right) {
652   intptr_t left_constant;
653   bool is_left_constant = ToIntPtrConstant(left, left_constant);
654   intptr_t right_constant;
655   bool is_right_constant = ToIntPtrConstant(right, right_constant);
656   if (is_left_constant) {
657     if (is_right_constant) {
658       return IntPtrConstant(left_constant & right_constant);
659     }
660   }
661   return UncheckedCast<WordT>(raw_assembler()->WordAnd(left, right));
662 }
663 
WordXor(SloppyTNode<WordT> left,SloppyTNode<WordT> right)664 TNode<WordT> CodeAssembler::WordXor(SloppyTNode<WordT> left,
665                                     SloppyTNode<WordT> right) {
666   intptr_t left_constant;
667   bool is_left_constant = ToIntPtrConstant(left, left_constant);
668   intptr_t right_constant;
669   bool is_right_constant = ToIntPtrConstant(right, right_constant);
670   if (is_left_constant) {
671     if (is_right_constant) {
672       return IntPtrConstant(left_constant ^ right_constant);
673     }
674   }
675   return UncheckedCast<WordT>(raw_assembler()->WordXor(left, right));
676 }
677 
WordShl(SloppyTNode<WordT> left,SloppyTNode<IntegralT> right)678 TNode<WordT> CodeAssembler::WordShl(SloppyTNode<WordT> left,
679                                     SloppyTNode<IntegralT> right) {
680   intptr_t left_constant;
681   bool is_left_constant = ToIntPtrConstant(left, left_constant);
682   intptr_t right_constant;
683   bool is_right_constant = ToIntPtrConstant(right, right_constant);
684   if (is_left_constant) {
685     if (is_right_constant) {
686       return IntPtrConstant(left_constant << right_constant);
687     }
688   } else if (is_right_constant) {
689     if (right_constant == 0) {
690       return left;
691     }
692   }
693   return UncheckedCast<WordT>(raw_assembler()->WordShl(left, right));
694 }
695 
WordShr(SloppyTNode<WordT> left,SloppyTNode<IntegralT> right)696 TNode<WordT> CodeAssembler::WordShr(SloppyTNode<WordT> left,
697                                     SloppyTNode<IntegralT> right) {
698   intptr_t left_constant;
699   bool is_left_constant = ToIntPtrConstant(left, left_constant);
700   intptr_t right_constant;
701   bool is_right_constant = ToIntPtrConstant(right, right_constant);
702   if (is_left_constant) {
703     if (is_right_constant) {
704       return IntPtrConstant(static_cast<uintptr_t>(left_constant) >>
705                             right_constant);
706     }
707   } else if (is_right_constant) {
708     if (right_constant == 0) {
709       return left;
710     }
711   }
712   return UncheckedCast<WordT>(raw_assembler()->WordShr(left, right));
713 }
714 
WordSar(SloppyTNode<WordT> left,SloppyTNode<IntegralT> right)715 TNode<WordT> CodeAssembler::WordSar(SloppyTNode<WordT> left,
716                                     SloppyTNode<IntegralT> right) {
717   intptr_t left_constant;
718   bool is_left_constant = ToIntPtrConstant(left, left_constant);
719   intptr_t right_constant;
720   bool is_right_constant = ToIntPtrConstant(right, right_constant);
721   if (is_left_constant) {
722     if (is_right_constant) {
723       return IntPtrConstant(left_constant >> right_constant);
724     }
725   } else if (is_right_constant) {
726     if (right_constant == 0) {
727       return left;
728     }
729   }
730   return UncheckedCast<WordT>(raw_assembler()->WordSar(left, right));
731 }
732 
Word32Or(SloppyTNode<Word32T> left,SloppyTNode<Word32T> right)733 TNode<Word32T> CodeAssembler::Word32Or(SloppyTNode<Word32T> left,
734                                        SloppyTNode<Word32T> right) {
735   int32_t left_constant;
736   bool is_left_constant = ToInt32Constant(left, left_constant);
737   int32_t right_constant;
738   bool is_right_constant = ToInt32Constant(right, right_constant);
739   if (is_left_constant) {
740     if (is_right_constant) {
741       return Int32Constant(left_constant | right_constant);
742     }
743     if (left_constant == 0) {
744       return right;
745     }
746   } else if (is_right_constant) {
747     if (right_constant == 0) {
748       return left;
749     }
750   }
751   return UncheckedCast<Word32T>(raw_assembler()->Word32Or(left, right));
752 }
753 
Word32And(SloppyTNode<Word32T> left,SloppyTNode<Word32T> right)754 TNode<Word32T> CodeAssembler::Word32And(SloppyTNode<Word32T> left,
755                                         SloppyTNode<Word32T> right) {
756   int32_t left_constant;
757   bool is_left_constant = ToInt32Constant(left, left_constant);
758   int32_t right_constant;
759   bool is_right_constant = ToInt32Constant(right, right_constant);
760   if (is_left_constant) {
761     if (is_right_constant) {
762       return Int32Constant(left_constant & right_constant);
763     }
764   }
765   return UncheckedCast<Word32T>(raw_assembler()->Word32And(left, right));
766 }
767 
Word32Xor(SloppyTNode<Word32T> left,SloppyTNode<Word32T> right)768 TNode<Word32T> CodeAssembler::Word32Xor(SloppyTNode<Word32T> left,
769                                         SloppyTNode<Word32T> right) {
770   int32_t left_constant;
771   bool is_left_constant = ToInt32Constant(left, left_constant);
772   int32_t right_constant;
773   bool is_right_constant = ToInt32Constant(right, right_constant);
774   if (is_left_constant) {
775     if (is_right_constant) {
776       return Int32Constant(left_constant ^ right_constant);
777     }
778   }
779   return UncheckedCast<Word32T>(raw_assembler()->Word32Xor(left, right));
780 }
781 
Word32Shl(SloppyTNode<Word32T> left,SloppyTNode<Word32T> right)782 TNode<Word32T> CodeAssembler::Word32Shl(SloppyTNode<Word32T> left,
783                                         SloppyTNode<Word32T> right) {
784   int32_t left_constant;
785   bool is_left_constant = ToInt32Constant(left, left_constant);
786   int32_t right_constant;
787   bool is_right_constant = ToInt32Constant(right, right_constant);
788   if (is_left_constant) {
789     if (is_right_constant) {
790       return Int32Constant(left_constant << right_constant);
791     }
792   } else if (is_right_constant) {
793     if (right_constant == 0) {
794       return left;
795     }
796   }
797   return UncheckedCast<Word32T>(raw_assembler()->Word32Shl(left, right));
798 }
799 
Word32Shr(SloppyTNode<Word32T> left,SloppyTNode<Word32T> right)800 TNode<Word32T> CodeAssembler::Word32Shr(SloppyTNode<Word32T> left,
801                                         SloppyTNode<Word32T> right) {
802   int32_t left_constant;
803   bool is_left_constant = ToInt32Constant(left, left_constant);
804   int32_t right_constant;
805   bool is_right_constant = ToInt32Constant(right, right_constant);
806   if (is_left_constant) {
807     if (is_right_constant) {
808       return Int32Constant(static_cast<uint32_t>(left_constant) >>
809                            right_constant);
810     }
811   } else if (is_right_constant) {
812     if (right_constant == 0) {
813       return left;
814     }
815   }
816   return UncheckedCast<Word32T>(raw_assembler()->Word32Shr(left, right));
817 }
818 
Word32Sar(SloppyTNode<Word32T> left,SloppyTNode<Word32T> right)819 TNode<Word32T> CodeAssembler::Word32Sar(SloppyTNode<Word32T> left,
820                                         SloppyTNode<Word32T> right) {
821   int32_t left_constant;
822   bool is_left_constant = ToInt32Constant(left, left_constant);
823   int32_t right_constant;
824   bool is_right_constant = ToInt32Constant(right, right_constant);
825   if (is_left_constant) {
826     if (is_right_constant) {
827       return Int32Constant(left_constant >> right_constant);
828     }
829   } else if (is_right_constant) {
830     if (right_constant == 0) {
831       return left;
832     }
833   }
834   return UncheckedCast<Word32T>(raw_assembler()->Word32Sar(left, right));
835 }
836 
Word64Or(SloppyTNode<Word64T> left,SloppyTNode<Word64T> right)837 TNode<Word64T> CodeAssembler::Word64Or(SloppyTNode<Word64T> left,
838                                        SloppyTNode<Word64T> right) {
839   int64_t left_constant;
840   bool is_left_constant = ToInt64Constant(left, left_constant);
841   int64_t right_constant;
842   bool is_right_constant = ToInt64Constant(right, right_constant);
843   if (is_left_constant) {
844     if (is_right_constant) {
845       return Int64Constant(left_constant | right_constant);
846     }
847     if (left_constant == 0) {
848       return right;
849     }
850   } else if (is_right_constant) {
851     if (right_constant == 0) {
852       return left;
853     }
854   }
855   return UncheckedCast<Word64T>(raw_assembler()->Word64Or(left, right));
856 }
857 
Word64And(SloppyTNode<Word64T> left,SloppyTNode<Word64T> right)858 TNode<Word64T> CodeAssembler::Word64And(SloppyTNode<Word64T> left,
859                                         SloppyTNode<Word64T> right) {
860   int64_t left_constant;
861   bool is_left_constant = ToInt64Constant(left, left_constant);
862   int64_t right_constant;
863   bool is_right_constant = ToInt64Constant(right, right_constant);
864   if (is_left_constant) {
865     if (is_right_constant) {
866       return Int64Constant(left_constant & right_constant);
867     }
868   }
869   return UncheckedCast<Word64T>(raw_assembler()->Word64And(left, right));
870 }
871 
Word64Xor(SloppyTNode<Word64T> left,SloppyTNode<Word64T> right)872 TNode<Word64T> CodeAssembler::Word64Xor(SloppyTNode<Word64T> left,
873                                         SloppyTNode<Word64T> right) {
874   int64_t left_constant;
875   bool is_left_constant = ToInt64Constant(left, left_constant);
876   int64_t right_constant;
877   bool is_right_constant = ToInt64Constant(right, right_constant);
878   if (is_left_constant) {
879     if (is_right_constant) {
880       return Int64Constant(left_constant ^ right_constant);
881     }
882   }
883   return UncheckedCast<Word64T>(raw_assembler()->Word64Xor(left, right));
884 }
885 
Word64Shl(SloppyTNode<Word64T> left,SloppyTNode<Word64T> right)886 TNode<Word64T> CodeAssembler::Word64Shl(SloppyTNode<Word64T> left,
887                                         SloppyTNode<Word64T> right) {
888   int64_t left_constant;
889   bool is_left_constant = ToInt64Constant(left, left_constant);
890   int64_t right_constant;
891   bool is_right_constant = ToInt64Constant(right, right_constant);
892   if (is_left_constant) {
893     if (is_right_constant) {
894       return Int64Constant(left_constant << right_constant);
895     }
896   } else if (is_right_constant) {
897     if (right_constant == 0) {
898       return left;
899     }
900   }
901   return UncheckedCast<Word64T>(raw_assembler()->Word64Shl(left, right));
902 }
903 
Word64Shr(SloppyTNode<Word64T> left,SloppyTNode<Word64T> right)904 TNode<Word64T> CodeAssembler::Word64Shr(SloppyTNode<Word64T> left,
905                                         SloppyTNode<Word64T> right) {
906   int64_t left_constant;
907   bool is_left_constant = ToInt64Constant(left, left_constant);
908   int64_t right_constant;
909   bool is_right_constant = ToInt64Constant(right, right_constant);
910   if (is_left_constant) {
911     if (is_right_constant) {
912       return Int64Constant(static_cast<uint64_t>(left_constant) >>
913                            right_constant);
914     }
915   } else if (is_right_constant) {
916     if (right_constant == 0) {
917       return left;
918     }
919   }
920   return UncheckedCast<Word64T>(raw_assembler()->Word64Shr(left, right));
921 }
922 
Word64Sar(SloppyTNode<Word64T> left,SloppyTNode<Word64T> right)923 TNode<Word64T> CodeAssembler::Word64Sar(SloppyTNode<Word64T> left,
924                                         SloppyTNode<Word64T> right) {
925   int64_t left_constant;
926   bool is_left_constant = ToInt64Constant(left, left_constant);
927   int64_t right_constant;
928   bool is_right_constant = ToInt64Constant(right, right_constant);
929   if (is_left_constant) {
930     if (is_right_constant) {
931       return Int64Constant(left_constant >> right_constant);
932     }
933   } else if (is_right_constant) {
934     if (right_constant == 0) {
935       return left;
936     }
937   }
938   return UncheckedCast<Word64T>(raw_assembler()->Word64Sar(left, right));
939 }
940 
ChangeUint32ToWord(SloppyTNode<Word32T> value)941 TNode<UintPtrT> CodeAssembler::ChangeUint32ToWord(SloppyTNode<Word32T> value) {
942   if (raw_assembler()->machine()->Is64()) {
943     return UncheckedCast<UintPtrT>(
944         raw_assembler()->ChangeUint32ToUint64(value));
945   }
946   return ReinterpretCast<UintPtrT>(value);
947 }
948 
ChangeInt32ToIntPtr(SloppyTNode<Word32T> value)949 TNode<IntPtrT> CodeAssembler::ChangeInt32ToIntPtr(SloppyTNode<Word32T> value) {
950   if (raw_assembler()->machine()->Is64()) {
951     return ReinterpretCast<IntPtrT>(raw_assembler()->ChangeInt32ToInt64(value));
952   }
953   return ReinterpretCast<IntPtrT>(value);
954 }
955 
ChangeFloat64ToUintPtr(SloppyTNode<Float64T> value)956 TNode<UintPtrT> CodeAssembler::ChangeFloat64ToUintPtr(
957     SloppyTNode<Float64T> value) {
958   if (raw_assembler()->machine()->Is64()) {
959     return ReinterpretCast<UintPtrT>(
960         raw_assembler()->ChangeFloat64ToUint64(value));
961   }
962   return ReinterpretCast<UintPtrT>(
963       raw_assembler()->ChangeFloat64ToUint32(value));
964 }
965 
RoundIntPtrToFloat64(Node * value)966 Node* CodeAssembler::RoundIntPtrToFloat64(Node* value) {
967   if (raw_assembler()->machine()->Is64()) {
968     return raw_assembler()->RoundInt64ToFloat64(value);
969   }
970   return raw_assembler()->ChangeInt32ToFloat64(value);
971 }
972 
973 #define DEFINE_CODE_ASSEMBLER_UNARY_OP(name, ResType, ArgType) \
974   TNode<ResType> CodeAssembler::name(SloppyTNode<ArgType> a) { \
975     return UncheckedCast<ResType>(raw_assembler()->name(a));   \
976   }
CODE_ASSEMBLER_UNARY_OP_LIST(DEFINE_CODE_ASSEMBLER_UNARY_OP)977 CODE_ASSEMBLER_UNARY_OP_LIST(DEFINE_CODE_ASSEMBLER_UNARY_OP)
978 #undef DEFINE_CODE_ASSEMBLER_UNARY_OP
979 
980 Node* CodeAssembler::Load(MachineType rep, Node* base,
981                           LoadSensitivity needs_poisoning) {
982   return raw_assembler()->Load(rep, base, needs_poisoning);
983 }
984 
Load(MachineType rep,Node * base,Node * offset,LoadSensitivity needs_poisoning)985 Node* CodeAssembler::Load(MachineType rep, Node* base, Node* offset,
986                           LoadSensitivity needs_poisoning) {
987   return raw_assembler()->Load(rep, base, offset, needs_poisoning);
988 }
989 
AtomicLoad(MachineType rep,Node * base,Node * offset)990 Node* CodeAssembler::AtomicLoad(MachineType rep, Node* base, Node* offset) {
991   return raw_assembler()->AtomicLoad(rep, base, offset);
992 }
993 
LoadRoot(Heap::RootListIndex root_index)994 TNode<Object> CodeAssembler::LoadRoot(Heap::RootListIndex root_index) {
995   if (isolate()->heap()->RootCanBeTreatedAsConstant(root_index)) {
996     Handle<Object> root = isolate()->heap()->root_handle(root_index);
997     if (root->IsSmi()) {
998       return SmiConstant(Smi::cast(*root));
999     } else {
1000       return HeapConstant(Handle<HeapObject>::cast(root));
1001     }
1002   }
1003 
1004   Node* roots_array_start =
1005       ExternalConstant(ExternalReference::roots_array_start(isolate()));
1006   return UncheckedCast<Object>(Load(MachineType::AnyTagged(), roots_array_start,
1007                                     IntPtrConstant(root_index * kPointerSize)));
1008 }
1009 
Store(Node * base,Node * value)1010 Node* CodeAssembler::Store(Node* base, Node* value) {
1011   return raw_assembler()->Store(MachineRepresentation::kTagged, base, value,
1012                                 kFullWriteBarrier);
1013 }
1014 
Store(Node * base,Node * offset,Node * value)1015 Node* CodeAssembler::Store(Node* base, Node* offset, Node* value) {
1016   return raw_assembler()->Store(MachineRepresentation::kTagged, base, offset,
1017                                 value, kFullWriteBarrier);
1018 }
1019 
StoreWithMapWriteBarrier(Node * base,Node * offset,Node * value)1020 Node* CodeAssembler::StoreWithMapWriteBarrier(Node* base, Node* offset,
1021                                               Node* value) {
1022   return raw_assembler()->Store(MachineRepresentation::kTagged, base, offset,
1023                                 value, kMapWriteBarrier);
1024 }
1025 
StoreNoWriteBarrier(MachineRepresentation rep,Node * base,Node * value)1026 Node* CodeAssembler::StoreNoWriteBarrier(MachineRepresentation rep, Node* base,
1027                                          Node* value) {
1028   return raw_assembler()->Store(rep, base, value, kNoWriteBarrier);
1029 }
1030 
StoreNoWriteBarrier(MachineRepresentation rep,Node * base,Node * offset,Node * value)1031 Node* CodeAssembler::StoreNoWriteBarrier(MachineRepresentation rep, Node* base,
1032                                          Node* offset, Node* value) {
1033   return raw_assembler()->Store(rep, base, offset, value, kNoWriteBarrier);
1034 }
1035 
AtomicStore(MachineRepresentation rep,Node * base,Node * offset,Node * value)1036 Node* CodeAssembler::AtomicStore(MachineRepresentation rep, Node* base,
1037                                  Node* offset, Node* value) {
1038   return raw_assembler()->AtomicStore(rep, base, offset, value);
1039 }
1040 
1041 #define ATOMIC_FUNCTION(name)                                        \
1042   Node* CodeAssembler::Atomic##name(MachineType type, Node* base,    \
1043                                     Node* offset, Node* value) {     \
1044     return raw_assembler()->Atomic##name(type, base, offset, value); \
1045   }
1046 ATOMIC_FUNCTION(Exchange);
1047 ATOMIC_FUNCTION(Add);
1048 ATOMIC_FUNCTION(Sub);
1049 ATOMIC_FUNCTION(And);
1050 ATOMIC_FUNCTION(Or);
1051 ATOMIC_FUNCTION(Xor);
1052 #undef ATOMIC_FUNCTION
1053 
AtomicCompareExchange(MachineType type,Node * base,Node * offset,Node * old_value,Node * new_value)1054 Node* CodeAssembler::AtomicCompareExchange(MachineType type, Node* base,
1055                                            Node* offset, Node* old_value,
1056                                            Node* new_value) {
1057   return raw_assembler()->AtomicCompareExchange(type, base, offset, old_value,
1058                                                 new_value);
1059 }
1060 
StoreRoot(Heap::RootListIndex root_index,Node * value)1061 Node* CodeAssembler::StoreRoot(Heap::RootListIndex root_index, Node* value) {
1062   DCHECK(Heap::RootCanBeWrittenAfterInitialization(root_index));
1063   Node* roots_array_start =
1064       ExternalConstant(ExternalReference::roots_array_start(isolate()));
1065   return StoreNoWriteBarrier(MachineRepresentation::kTagged, roots_array_start,
1066                              IntPtrConstant(root_index * kPointerSize), value);
1067 }
1068 
Retain(Node * value)1069 Node* CodeAssembler::Retain(Node* value) {
1070   return raw_assembler()->Retain(value);
1071 }
1072 
Projection(int index,Node * value)1073 Node* CodeAssembler::Projection(int index, Node* value) {
1074   return raw_assembler()->Projection(index, value);
1075 }
1076 
GotoIfException(Node * node,Label * if_exception,Variable * exception_var)1077 void CodeAssembler::GotoIfException(Node* node, Label* if_exception,
1078                                     Variable* exception_var) {
1079   if (if_exception == nullptr) {
1080     // If no handler is supplied, don't add continuations
1081     return;
1082   }
1083 
1084   DCHECK(!node->op()->HasProperty(Operator::kNoThrow));
1085 
1086   Label success(this), exception(this, Label::kDeferred);
1087   success.MergeVariables();
1088   exception.MergeVariables();
1089 
1090   raw_assembler()->Continuations(node, success.label_, exception.label_);
1091 
1092   Bind(&exception);
1093   const Operator* op = raw_assembler()->common()->IfException();
1094   Node* exception_value = raw_assembler()->AddNode(op, node, node);
1095   if (exception_var != nullptr) {
1096     exception_var->Bind(exception_value);
1097   }
1098   Goto(if_exception);
1099 
1100   Bind(&success);
1101 }
1102 
1103 template <class... TArgs>
CallRuntimeImpl(Runtime::FunctionId function,SloppyTNode<Object> context,TArgs...args)1104 TNode<Object> CodeAssembler::CallRuntimeImpl(Runtime::FunctionId function,
1105                                              SloppyTNode<Object> context,
1106                                              TArgs... args) {
1107   int argc = static_cast<int>(sizeof...(args));
1108   auto call_descriptor = Linkage::GetRuntimeCallDescriptor(
1109       zone(), function, argc, Operator::kNoProperties,
1110       CallDescriptor::kNoFlags);
1111   int return_count = static_cast<int>(call_descriptor->ReturnCount());
1112 
1113   Node* centry =
1114       HeapConstant(CodeFactory::RuntimeCEntry(isolate(), return_count));
1115   Node* ref = ExternalConstant(ExternalReference::Create(function));
1116   Node* arity = Int32Constant(argc);
1117 
1118   Node* nodes[] = {centry, args..., ref, arity, context};
1119 
1120   CallPrologue();
1121   Node* return_value =
1122       raw_assembler()->CallN(call_descriptor, arraysize(nodes), nodes);
1123   CallEpilogue();
1124   return UncheckedCast<Object>(return_value);
1125 }
1126 
1127 // Instantiate CallRuntime() for argument counts used by CSA-generated code
1128 #define INSTANTIATE(...)                                                   \
1129   template V8_EXPORT_PRIVATE TNode<Object> CodeAssembler::CallRuntimeImpl( \
1130       Runtime::FunctionId, __VA_ARGS__);
REPEAT_1_TO_7(INSTANTIATE,SloppyTNode<Object>)1131 REPEAT_1_TO_7(INSTANTIATE, SloppyTNode<Object>)
1132 #undef INSTANTIATE
1133 
1134 template <class... TArgs>
1135 TNode<Object> CodeAssembler::TailCallRuntimeImpl(Runtime::FunctionId function,
1136                                                  SloppyTNode<Object> context,
1137                                                  TArgs... args) {
1138   int argc = static_cast<int>(sizeof...(args));
1139   auto call_descriptor = Linkage::GetRuntimeCallDescriptor(
1140       zone(), function, argc, Operator::kNoProperties,
1141       CallDescriptor::kNoFlags);
1142   int return_count = static_cast<int>(call_descriptor->ReturnCount());
1143 
1144   Node* centry =
1145       HeapConstant(CodeFactory::RuntimeCEntry(isolate(), return_count));
1146   Node* ref = ExternalConstant(ExternalReference::Create(function));
1147   Node* arity = Int32Constant(argc);
1148 
1149   Node* nodes[] = {centry, args..., ref, arity, context};
1150 
1151   return UncheckedCast<Object>(
1152       raw_assembler()->TailCallN(call_descriptor, arraysize(nodes), nodes));
1153 }
1154 
1155 // Instantiate TailCallRuntime() for argument counts used by CSA-generated code
1156 #define INSTANTIATE(...)                                                       \
1157   template V8_EXPORT_PRIVATE TNode<Object> CodeAssembler::TailCallRuntimeImpl( \
1158       Runtime::FunctionId, __VA_ARGS__);
REPEAT_1_TO_7(INSTANTIATE,SloppyTNode<Object>)1159 REPEAT_1_TO_7(INSTANTIATE, SloppyTNode<Object>)
1160 #undef INSTANTIATE
1161 
1162 template <class... TArgs>
1163 Node* CodeAssembler::CallStubR(const CallInterfaceDescriptor& descriptor,
1164                                size_t result_size, Node* target, Node* context,
1165                                TArgs... args) {
1166   Node* nodes[] = {target, args..., context};
1167   int input_count = arraysize(nodes);
1168   if (context == nullptr) --input_count;
1169   return CallStubN(descriptor, result_size, input_count, nodes,
1170                    context != nullptr);
1171 }
1172 
1173 // Instantiate CallStubR() for argument counts used by CSA-generated code.
1174 #define INSTANTIATE(...)                                     \
1175   template V8_EXPORT_PRIVATE Node* CodeAssembler::CallStubR( \
1176       const CallInterfaceDescriptor& descriptor, size_t, Node*, __VA_ARGS__);
REPEAT_1_TO_11(INSTANTIATE,Node *)1177 REPEAT_1_TO_11(INSTANTIATE, Node*)
1178 #undef INSTANTIATE
1179 
1180 Node* CodeAssembler::CallStubN(const CallInterfaceDescriptor& descriptor,
1181                                size_t result_size, int input_count,
1182                                Node* const* inputs, bool pass_context) {
1183   // implicit nodes are target and optionally context.
1184   int implicit_nodes = pass_context ? 2 : 1;
1185   DCHECK_LE(implicit_nodes, input_count);
1186   int argc = input_count - implicit_nodes;
1187   DCHECK_LE(descriptor.GetParameterCount(), argc);
1188   // Extra arguments not mentioned in the descriptor are passed on the stack.
1189   int stack_parameter_count = argc - descriptor.GetRegisterParameterCount();
1190   DCHECK_LE(descriptor.GetStackParameterCount(), stack_parameter_count);
1191   auto call_descriptor = Linkage::GetStubCallDescriptor(
1192       isolate(), zone(), descriptor, stack_parameter_count,
1193       CallDescriptor::kNoFlags, Operator::kNoProperties,
1194       MachineType::AnyTagged(), result_size,
1195       pass_context ? Linkage::kPassContext : Linkage::kNoContext);
1196 
1197   CallPrologue();
1198   Node* return_value =
1199       raw_assembler()->CallN(call_descriptor, input_count, inputs);
1200   CallEpilogue();
1201   return return_value;
1202 }
1203 
1204 template <class... TArgs>
TailCallStubImpl(const CallInterfaceDescriptor & descriptor,Node * target,Node * context,TArgs...args)1205 Node* CodeAssembler::TailCallStubImpl(const CallInterfaceDescriptor& descriptor,
1206                                       Node* target, Node* context,
1207                                       TArgs... args) {
1208   DCHECK_EQ(descriptor.GetParameterCount(), sizeof...(args));
1209   size_t result_size = 1;
1210   auto call_descriptor = Linkage::GetStubCallDescriptor(
1211       isolate(), zone(), descriptor, descriptor.GetStackParameterCount(),
1212       CallDescriptor::kNoFlags, Operator::kNoProperties,
1213       MachineType::AnyTagged(), result_size);
1214 
1215   Node* nodes[] = {target, args..., context};
1216   CHECK_EQ(descriptor.GetParameterCount() + 2, arraysize(nodes));
1217   return raw_assembler()->TailCallN(call_descriptor, arraysize(nodes), nodes);
1218 }
1219 
1220 // Instantiate TailCallStub() for argument counts used by CSA-generated code
1221 #define INSTANTIATE(...)                                            \
1222   template V8_EXPORT_PRIVATE Node* CodeAssembler::TailCallStubImpl( \
1223       const CallInterfaceDescriptor& descriptor, Node*, __VA_ARGS__);
REPEAT_1_TO_12(INSTANTIATE,Node *)1224 REPEAT_1_TO_12(INSTANTIATE, Node*)
1225 #undef INSTANTIATE
1226 
1227 template <class... TArgs>
1228 Node* CodeAssembler::TailCallStubThenBytecodeDispatch(
1229     const CallInterfaceDescriptor& descriptor, Node* target, Node* context,
1230     TArgs... args) {
1231   DCHECK_LE(descriptor.GetParameterCount(), sizeof...(args));
1232   // Extra arguments not mentioned in the descriptor are passed on the stack.
1233   int stack_parameter_count =
1234       sizeof...(args) - descriptor.GetRegisterParameterCount();
1235   DCHECK_LE(descriptor.GetStackParameterCount(), stack_parameter_count);
1236   auto call_descriptor = Linkage::GetStubCallDescriptor(
1237       isolate(), zone(), descriptor, stack_parameter_count,
1238       CallDescriptor::kNoFlags, Operator::kNoProperties,
1239       MachineType::AnyTagged(), 0);
1240 
1241   Node* nodes[] = {target, args..., context};
1242   return raw_assembler()->TailCallN(call_descriptor, arraysize(nodes), nodes);
1243 }
1244 
1245 // Instantiate TailCallJSAndBytecodeDispatch() for argument counts used by
1246 // CSA-generated code
1247 #define INSTANTIATE(...)                           \
1248   template V8_EXPORT_PRIVATE Node*                 \
1249   CodeAssembler::TailCallStubThenBytecodeDispatch( \
1250       const CallInterfaceDescriptor&, Node*, Node*, Node*, __VA_ARGS__);
REPEAT_1_TO_7(INSTANTIATE,Node *)1251 REPEAT_1_TO_7(INSTANTIATE, Node*)
1252 #undef INSTANTIATE
1253 
1254 template <class... TArgs>
1255 Node* CodeAssembler::TailCallBytecodeDispatch(
1256     const CallInterfaceDescriptor& descriptor, Node* target, TArgs... args) {
1257   DCHECK_EQ(descriptor.GetParameterCount(), sizeof...(args));
1258   auto call_descriptor = Linkage::GetBytecodeDispatchCallDescriptor(
1259       isolate(), zone(), descriptor, descriptor.GetStackParameterCount());
1260 
1261   Node* nodes[] = {target, args...};
1262   CHECK_EQ(descriptor.GetParameterCount() + 1, arraysize(nodes));
1263   return raw_assembler()->TailCallN(call_descriptor, arraysize(nodes), nodes);
1264 }
1265 
1266 // Instantiate TailCallBytecodeDispatch() for argument counts used by
1267 // CSA-generated code
1268 template V8_EXPORT_PRIVATE Node* CodeAssembler::TailCallBytecodeDispatch(
1269     const CallInterfaceDescriptor& descriptor, Node* target, Node*, Node*,
1270     Node*, Node*);
1271 
CallCFunctionN(Signature<MachineType> * signature,int input_count,Node * const * inputs)1272 Node* CodeAssembler::CallCFunctionN(Signature<MachineType>* signature,
1273                                     int input_count, Node* const* inputs) {
1274   auto call_descriptor = Linkage::GetSimplifiedCDescriptor(zone(), signature);
1275   return raw_assembler()->CallN(call_descriptor, input_count, inputs);
1276 }
1277 
CallCFunction1(MachineType return_type,MachineType arg0_type,Node * function,Node * arg0)1278 Node* CodeAssembler::CallCFunction1(MachineType return_type,
1279                                     MachineType arg0_type, Node* function,
1280                                     Node* arg0) {
1281   return raw_assembler()->CallCFunction1(return_type, arg0_type, function,
1282                                          arg0);
1283 }
1284 
CallCFunction1WithCallerSavedRegisters(MachineType return_type,MachineType arg0_type,Node * function,Node * arg0,SaveFPRegsMode mode)1285 Node* CodeAssembler::CallCFunction1WithCallerSavedRegisters(
1286     MachineType return_type, MachineType arg0_type, Node* function, Node* arg0,
1287     SaveFPRegsMode mode) {
1288   DCHECK(return_type.LessThanOrEqualPointerSize());
1289   return raw_assembler()->CallCFunction1WithCallerSavedRegisters(
1290       return_type, arg0_type, function, arg0, mode);
1291 }
1292 
CallCFunction2(MachineType return_type,MachineType arg0_type,MachineType arg1_type,Node * function,Node * arg0,Node * arg1)1293 Node* CodeAssembler::CallCFunction2(MachineType return_type,
1294                                     MachineType arg0_type,
1295                                     MachineType arg1_type, Node* function,
1296                                     Node* arg0, Node* arg1) {
1297   return raw_assembler()->CallCFunction2(return_type, arg0_type, arg1_type,
1298                                          function, arg0, arg1);
1299 }
1300 
CallCFunction3(MachineType return_type,MachineType arg0_type,MachineType arg1_type,MachineType arg2_type,Node * function,Node * arg0,Node * arg1,Node * arg2)1301 Node* CodeAssembler::CallCFunction3(MachineType return_type,
1302                                     MachineType arg0_type,
1303                                     MachineType arg1_type,
1304                                     MachineType arg2_type, Node* function,
1305                                     Node* arg0, Node* arg1, Node* arg2) {
1306   return raw_assembler()->CallCFunction3(return_type, arg0_type, arg1_type,
1307                                          arg2_type, function, arg0, arg1, arg2);
1308 }
1309 
CallCFunction3WithCallerSavedRegisters(MachineType return_type,MachineType arg0_type,MachineType arg1_type,MachineType arg2_type,Node * function,Node * arg0,Node * arg1,Node * arg2,SaveFPRegsMode mode)1310 Node* CodeAssembler::CallCFunction3WithCallerSavedRegisters(
1311     MachineType return_type, MachineType arg0_type, MachineType arg1_type,
1312     MachineType arg2_type, Node* function, Node* arg0, Node* arg1, Node* arg2,
1313     SaveFPRegsMode mode) {
1314   DCHECK(return_type.LessThanOrEqualPointerSize());
1315   return raw_assembler()->CallCFunction3WithCallerSavedRegisters(
1316       return_type, arg0_type, arg1_type, arg2_type, function, arg0, arg1, arg2,
1317       mode);
1318 }
1319 
CallCFunction4(MachineType return_type,MachineType arg0_type,MachineType arg1_type,MachineType arg2_type,MachineType arg3_type,Node * function,Node * arg0,Node * arg1,Node * arg2,Node * arg3)1320 Node* CodeAssembler::CallCFunction4(
1321     MachineType return_type, MachineType arg0_type, MachineType arg1_type,
1322     MachineType arg2_type, MachineType arg3_type, Node* function, Node* arg0,
1323     Node* arg1, Node* arg2, Node* arg3) {
1324   return raw_assembler()->CallCFunction4(return_type, arg0_type, arg1_type,
1325                                          arg2_type, arg3_type, function, arg0,
1326                                          arg1, arg2, arg3);
1327 }
1328 
CallCFunction5(MachineType return_type,MachineType arg0_type,MachineType arg1_type,MachineType arg2_type,MachineType arg3_type,MachineType arg4_type,Node * function,Node * arg0,Node * arg1,Node * arg2,Node * arg3,Node * arg4)1329 Node* CodeAssembler::CallCFunction5(
1330     MachineType return_type, MachineType arg0_type, MachineType arg1_type,
1331     MachineType arg2_type, MachineType arg3_type, MachineType arg4_type,
1332     Node* function, Node* arg0, Node* arg1, Node* arg2, Node* arg3,
1333     Node* arg4) {
1334   return raw_assembler()->CallCFunction5(
1335       return_type, arg0_type, arg1_type, arg2_type, arg3_type, arg4_type,
1336       function, arg0, arg1, arg2, arg3, arg4);
1337 }
1338 
CallCFunction6(MachineType return_type,MachineType arg0_type,MachineType arg1_type,MachineType arg2_type,MachineType arg3_type,MachineType arg4_type,MachineType arg5_type,Node * function,Node * arg0,Node * arg1,Node * arg2,Node * arg3,Node * arg4,Node * arg5)1339 Node* CodeAssembler::CallCFunction6(
1340     MachineType return_type, MachineType arg0_type, MachineType arg1_type,
1341     MachineType arg2_type, MachineType arg3_type, MachineType arg4_type,
1342     MachineType arg5_type, Node* function, Node* arg0, Node* arg1, Node* arg2,
1343     Node* arg3, Node* arg4, Node* arg5) {
1344   return raw_assembler()->CallCFunction6(
1345       return_type, arg0_type, arg1_type, arg2_type, arg3_type, arg4_type,
1346       arg5_type, function, arg0, arg1, arg2, arg3, arg4, arg5);
1347 }
1348 
CallCFunction9(MachineType return_type,MachineType arg0_type,MachineType arg1_type,MachineType arg2_type,MachineType arg3_type,MachineType arg4_type,MachineType arg5_type,MachineType arg6_type,MachineType arg7_type,MachineType arg8_type,Node * function,Node * arg0,Node * arg1,Node * arg2,Node * arg3,Node * arg4,Node * arg5,Node * arg6,Node * arg7,Node * arg8)1349 Node* CodeAssembler::CallCFunction9(
1350     MachineType return_type, MachineType arg0_type, MachineType arg1_type,
1351     MachineType arg2_type, MachineType arg3_type, MachineType arg4_type,
1352     MachineType arg5_type, MachineType arg6_type, MachineType arg7_type,
1353     MachineType arg8_type, Node* function, Node* arg0, Node* arg1, Node* arg2,
1354     Node* arg3, Node* arg4, Node* arg5, Node* arg6, Node* arg7, Node* arg8) {
1355   return raw_assembler()->CallCFunction9(
1356       return_type, arg0_type, arg1_type, arg2_type, arg3_type, arg4_type,
1357       arg5_type, arg6_type, arg7_type, arg8_type, function, arg0, arg1, arg2,
1358       arg3, arg4, arg5, arg6, arg7, arg8);
1359 }
1360 
Goto(Label * label)1361 void CodeAssembler::Goto(Label* label) {
1362   label->MergeVariables();
1363   raw_assembler()->Goto(label->label_);
1364 }
1365 
GotoIf(SloppyTNode<IntegralT> condition,Label * true_label)1366 void CodeAssembler::GotoIf(SloppyTNode<IntegralT> condition,
1367                            Label* true_label) {
1368   Label false_label(this);
1369   Branch(condition, true_label, &false_label);
1370   Bind(&false_label);
1371 }
1372 
GotoIfNot(SloppyTNode<IntegralT> condition,Label * false_label)1373 void CodeAssembler::GotoIfNot(SloppyTNode<IntegralT> condition,
1374                               Label* false_label) {
1375   Label true_label(this);
1376   Branch(condition, &true_label, false_label);
1377   Bind(&true_label);
1378 }
1379 
Branch(SloppyTNode<IntegralT> condition,Label * true_label,Label * false_label)1380 void CodeAssembler::Branch(SloppyTNode<IntegralT> condition, Label* true_label,
1381                            Label* false_label) {
1382   true_label->MergeVariables();
1383   false_label->MergeVariables();
1384   return raw_assembler()->Branch(condition, true_label->label_,
1385                                  false_label->label_);
1386 }
1387 
Switch(Node * index,Label * default_label,const int32_t * case_values,Label ** case_labels,size_t case_count)1388 void CodeAssembler::Switch(Node* index, Label* default_label,
1389                            const int32_t* case_values, Label** case_labels,
1390                            size_t case_count) {
1391   RawMachineLabel** labels =
1392       new (zone()->New(sizeof(RawMachineLabel*) * case_count))
1393           RawMachineLabel*[case_count];
1394   for (size_t i = 0; i < case_count; ++i) {
1395     labels[i] = case_labels[i]->label_;
1396     case_labels[i]->MergeVariables();
1397   }
1398   default_label->MergeVariables();
1399   return raw_assembler()->Switch(index, default_label->label_, case_values,
1400                                  labels, case_count);
1401 }
1402 
UnalignedLoadSupported(MachineRepresentation rep) const1403 bool CodeAssembler::UnalignedLoadSupported(MachineRepresentation rep) const {
1404   return raw_assembler()->machine()->UnalignedLoadSupported(rep);
1405 }
UnalignedStoreSupported(MachineRepresentation rep) const1406 bool CodeAssembler::UnalignedStoreSupported(MachineRepresentation rep) const {
1407   return raw_assembler()->machine()->UnalignedStoreSupported(rep);
1408 }
1409 
1410 // RawMachineAssembler delegate helpers:
isolate() const1411 Isolate* CodeAssembler::isolate() const { return raw_assembler()->isolate(); }
1412 
factory() const1413 Factory* CodeAssembler::factory() const { return isolate()->factory(); }
1414 
zone() const1415 Zone* CodeAssembler::zone() const { return raw_assembler()->zone(); }
1416 
raw_assembler() const1417 RawMachineAssembler* CodeAssembler::raw_assembler() const {
1418   return state_->raw_assembler_.get();
1419 }
1420 
1421 // The core implementation of Variable is stored through an indirection so
1422 // that it can outlive the often block-scoped Variable declarations. This is
1423 // needed to ensure that variable binding and merging through phis can
1424 // properly be verified.
1425 class CodeAssemblerVariable::Impl : public ZoneObject {
1426  public:
Impl(MachineRepresentation rep)1427   explicit Impl(MachineRepresentation rep)
1428       :
1429 #if DEBUG
1430         debug_info_(AssemblerDebugInfo(nullptr, nullptr, -1)),
1431 #endif
1432         value_(nullptr),
1433         rep_(rep) {
1434   }
1435 
1436 #if DEBUG
debug_info() const1437   AssemblerDebugInfo debug_info() const { return debug_info_; }
set_debug_info(AssemblerDebugInfo debug_info)1438   void set_debug_info(AssemblerDebugInfo debug_info) {
1439     debug_info_ = debug_info;
1440   }
1441 
1442   AssemblerDebugInfo debug_info_;
1443 #endif  // DEBUG
1444   Node* value_;
1445   MachineRepresentation rep_;
1446 };
1447 
CodeAssemblerVariable(CodeAssembler * assembler,MachineRepresentation rep)1448 CodeAssemblerVariable::CodeAssemblerVariable(CodeAssembler* assembler,
1449                                              MachineRepresentation rep)
1450     : impl_(new (assembler->zone()) Impl(rep)), state_(assembler->state()) {
1451   state_->variables_.insert(impl_);
1452 }
1453 
CodeAssemblerVariable(CodeAssembler * assembler,MachineRepresentation rep,Node * initial_value)1454 CodeAssemblerVariable::CodeAssemblerVariable(CodeAssembler* assembler,
1455                                              MachineRepresentation rep,
1456                                              Node* initial_value)
1457     : CodeAssemblerVariable(assembler, rep) {
1458   Bind(initial_value);
1459 }
1460 
1461 #if DEBUG
CodeAssemblerVariable(CodeAssembler * assembler,AssemblerDebugInfo debug_info,MachineRepresentation rep)1462 CodeAssemblerVariable::CodeAssemblerVariable(CodeAssembler* assembler,
1463                                              AssemblerDebugInfo debug_info,
1464                                              MachineRepresentation rep)
1465     : impl_(new (assembler->zone()) Impl(rep)), state_(assembler->state()) {
1466   impl_->set_debug_info(debug_info);
1467   state_->variables_.insert(impl_);
1468 }
1469 
CodeAssemblerVariable(CodeAssembler * assembler,AssemblerDebugInfo debug_info,MachineRepresentation rep,Node * initial_value)1470 CodeAssemblerVariable::CodeAssemblerVariable(CodeAssembler* assembler,
1471                                              AssemblerDebugInfo debug_info,
1472                                              MachineRepresentation rep,
1473                                              Node* initial_value)
1474     : CodeAssemblerVariable(assembler, debug_info, rep) {
1475   impl_->set_debug_info(debug_info);
1476   Bind(initial_value);
1477 }
1478 #endif  // DEBUG
1479 
~CodeAssemblerVariable()1480 CodeAssemblerVariable::~CodeAssemblerVariable() {
1481   state_->variables_.erase(impl_);
1482 }
1483 
Bind(Node * value)1484 void CodeAssemblerVariable::Bind(Node* value) { impl_->value_ = value; }
1485 
value() const1486 Node* CodeAssemblerVariable::value() const {
1487 #if DEBUG
1488   if (!IsBound()) {
1489     std::stringstream str;
1490     str << "#Use of unbound variable:"
1491         << "#\n    Variable:      " << *this << "#\n    Current Block: ";
1492     state_->PrintCurrentBlock(str);
1493     FATAL("%s", str.str().c_str());
1494   }
1495   if (!state_->InsideBlock()) {
1496     std::stringstream str;
1497     str << "#Accessing variable value outside a block:"
1498         << "#\n    Variable:      " << *this;
1499     FATAL("%s", str.str().c_str());
1500   }
1501 #endif  // DEBUG
1502   return impl_->value_;
1503 }
1504 
rep() const1505 MachineRepresentation CodeAssemblerVariable::rep() const { return impl_->rep_; }
1506 
IsBound() const1507 bool CodeAssemblerVariable::IsBound() const { return impl_->value_ != nullptr; }
1508 
operator <<(std::ostream & os,const CodeAssemblerVariable::Impl & impl)1509 std::ostream& operator<<(std::ostream& os,
1510                          const CodeAssemblerVariable::Impl& impl) {
1511 #if DEBUG
1512   AssemblerDebugInfo info = impl.debug_info();
1513   if (info.name) os << "V" << info;
1514 #endif  // DEBUG
1515   return os;
1516 }
1517 
operator <<(std::ostream & os,const CodeAssemblerVariable & variable)1518 std::ostream& operator<<(std::ostream& os,
1519                          const CodeAssemblerVariable& variable) {
1520   os << *variable.impl_;
1521   return os;
1522 }
1523 
CodeAssemblerLabel(CodeAssembler * assembler,size_t vars_count,CodeAssemblerVariable * const * vars,CodeAssemblerLabel::Type type)1524 CodeAssemblerLabel::CodeAssemblerLabel(CodeAssembler* assembler,
1525                                        size_t vars_count,
1526                                        CodeAssemblerVariable* const* vars,
1527                                        CodeAssemblerLabel::Type type)
1528     : bound_(false),
1529       merge_count_(0),
1530       state_(assembler->state()),
1531       label_(nullptr) {
1532   void* buffer = assembler->zone()->New(sizeof(RawMachineLabel));
1533   label_ = new (buffer)
1534       RawMachineLabel(type == kDeferred ? RawMachineLabel::kDeferred
1535                                         : RawMachineLabel::kNonDeferred);
1536   for (size_t i = 0; i < vars_count; ++i) {
1537     variable_phis_[vars[i]->impl_] = nullptr;
1538   }
1539 }
1540 
~CodeAssemblerLabel()1541 CodeAssemblerLabel::~CodeAssemblerLabel() { label_->~RawMachineLabel(); }
1542 
MergeVariables()1543 void CodeAssemblerLabel::MergeVariables() {
1544   ++merge_count_;
1545   for (CodeAssemblerVariable::Impl* var : state_->variables_) {
1546     size_t count = 0;
1547     Node* node = var->value_;
1548     if (node != nullptr) {
1549       auto i = variable_merges_.find(var);
1550       if (i != variable_merges_.end()) {
1551         i->second.push_back(node);
1552         count = i->second.size();
1553       } else {
1554         count = 1;
1555         variable_merges_[var] = std::vector<Node*>(1, node);
1556       }
1557     }
1558     // If the following asserts, then you've jumped to a label without a bound
1559     // variable along that path that expects to merge its value into a phi.
1560     DCHECK(variable_phis_.find(var) == variable_phis_.end() ||
1561            count == merge_count_);
1562     USE(count);
1563 
1564     // If the label is already bound, we already know the set of variables to
1565     // merge and phi nodes have already been created.
1566     if (bound_) {
1567       auto phi = variable_phis_.find(var);
1568       if (phi != variable_phis_.end()) {
1569         DCHECK_NOT_NULL(phi->second);
1570         state_->raw_assembler_->AppendPhiInput(phi->second, node);
1571       } else {
1572         auto i = variable_merges_.find(var);
1573         if (i != variable_merges_.end()) {
1574           // If the following assert fires, then you've declared a variable that
1575           // has the same bound value along all paths up until the point you
1576           // bound this label, but then later merged a path with a new value for
1577           // the variable after the label bind (it's not possible to add phis to
1578           // the bound label after the fact, just make sure to list the variable
1579           // in the label's constructor's list of merged variables).
1580 #if DEBUG
1581           if (find_if(i->second.begin(), i->second.end(),
1582                       [node](Node* e) -> bool { return node != e; }) !=
1583               i->second.end()) {
1584             std::stringstream str;
1585             str << "Unmerged variable found when jumping to block. \n"
1586                 << "#    Variable:      " << *var;
1587             if (bound_) {
1588               str << "\n#    Target block:  " << *label_->block();
1589             }
1590             str << "\n#    Current Block: ";
1591             state_->PrintCurrentBlock(str);
1592             FATAL("%s", str.str().c_str());
1593           }
1594 #endif  // DEBUG
1595         }
1596       }
1597     }
1598   }
1599 }
1600 
1601 #if DEBUG
Bind(AssemblerDebugInfo debug_info)1602 void CodeAssemblerLabel::Bind(AssemblerDebugInfo debug_info) {
1603   if (bound_) {
1604     std::stringstream str;
1605     str << "Cannot bind the same label twice:"
1606         << "\n#    current:  " << debug_info
1607         << "\n#    previous: " << *label_->block();
1608     FATAL("%s", str.str().c_str());
1609   }
1610   state_->raw_assembler_->Bind(label_, debug_info);
1611   UpdateVariablesAfterBind();
1612 }
1613 #endif  // DEBUG
1614 
Bind()1615 void CodeAssemblerLabel::Bind() {
1616   DCHECK(!bound_);
1617   state_->raw_assembler_->Bind(label_);
1618   UpdateVariablesAfterBind();
1619 }
1620 
UpdateVariablesAfterBind()1621 void CodeAssemblerLabel::UpdateVariablesAfterBind() {
1622   // Make sure that all variables that have changed along any path up to this
1623   // point are marked as merge variables.
1624   for (auto var : state_->variables_) {
1625     Node* shared_value = nullptr;
1626     auto i = variable_merges_.find(var);
1627     if (i != variable_merges_.end()) {
1628       for (auto value : i->second) {
1629         DCHECK_NOT_NULL(value);
1630         if (value != shared_value) {
1631           if (shared_value == nullptr) {
1632             shared_value = value;
1633           } else {
1634             variable_phis_[var] = nullptr;
1635           }
1636         }
1637       }
1638     }
1639   }
1640 
1641   for (auto var : variable_phis_) {
1642     CodeAssemblerVariable::Impl* var_impl = var.first;
1643     auto i = variable_merges_.find(var_impl);
1644 #if DEBUG
1645     bool not_found = i == variable_merges_.end();
1646     if (not_found || i->second.size() != merge_count_) {
1647       std::stringstream str;
1648       str << "A variable that has been marked as beeing merged at the label"
1649           << "\n# doesn't have a bound value along all of the paths that "
1650           << "\n# have been merged into the label up to this point."
1651           << "\n#"
1652           << "\n# This can happen in the following cases:"
1653           << "\n# - By explicitly marking it so in the label constructor"
1654           << "\n# - By having seen different bound values at branches"
1655           << "\n#"
1656           << "\n# Merge count:     expected=" << merge_count_
1657           << " vs. found=" << (not_found ? 0 : i->second.size())
1658           << "\n# Variable:      " << *var_impl
1659           << "\n# Current Block: " << *label_->block();
1660       FATAL("%s", str.str().c_str());
1661     }
1662 #endif  // DEBUG
1663     Node* phi = state_->raw_assembler_->Phi(
1664         var.first->rep_, static_cast<int>(merge_count_), &(i->second[0]));
1665     variable_phis_[var_impl] = phi;
1666   }
1667 
1668   // Bind all variables to a merge phi, the common value along all paths or
1669   // null.
1670   for (auto var : state_->variables_) {
1671     auto i = variable_phis_.find(var);
1672     if (i != variable_phis_.end()) {
1673       var->value_ = i->second;
1674     } else {
1675       auto j = variable_merges_.find(var);
1676       if (j != variable_merges_.end() && j->second.size() == merge_count_) {
1677         var->value_ = j->second.back();
1678       } else {
1679         var->value_ = nullptr;
1680       }
1681     }
1682   }
1683 
1684   bound_ = true;
1685 }
1686 
1687 }  // namespace compiler
1688 
CheckObjectType(Object * value,Smi * type,String * location)1689 Smi* CheckObjectType(Object* value, Smi* type, String* location) {
1690 #ifdef DEBUG
1691   const char* expected;
1692   switch (static_cast<ObjectType>(type->value())) {
1693 #define TYPE_CASE(Name)                            \
1694   case ObjectType::k##Name:                        \
1695     if (value->Is##Name()) return Smi::FromInt(0); \
1696     expected = #Name;                              \
1697     break;
1698 #define TYPE_STRUCT_CASE(NAME, Name, name)         \
1699   case ObjectType::k##Name:                        \
1700     if (value->Is##Name()) return Smi::FromInt(0); \
1701     expected = #Name;                              \
1702     break;
1703 
1704     TYPE_CASE(Object)
1705     OBJECT_TYPE_LIST(TYPE_CASE)
1706     HEAP_OBJECT_TYPE_LIST(TYPE_CASE)
1707     STRUCT_LIST(TYPE_STRUCT_CASE)
1708 #undef TYPE_CASE
1709 #undef TYPE_STRUCT_CASE
1710   }
1711   std::stringstream value_description;
1712   value->Print(value_description);
1713   V8_Fatal(__FILE__, __LINE__,
1714            "Type cast failed in %s\n"
1715            "  Expected %s but found %s",
1716            location->ToAsciiArray(), expected, value_description.str().c_str());
1717 #else
1718   UNREACHABLE();
1719 #endif
1720 }
1721 
1722 }  // namespace internal
1723 }  // namespace v8
1724 
1725 #undef REPEAT_1_TO_2
1726 #undef REPEAT_1_TO_3
1727 #undef REPEAT_1_TO_4
1728 #undef REPEAT_1_TO_5
1729 #undef REPEAT_1_TO_6
1730 #undef REPEAT_1_TO_7
1731 #undef REPEAT_1_TO_8
1732 #undef REPEAT_1_TO_9
1733 #undef REPEAT_1_TO_10
1734 #undef REPEAT_1_TO_11
1735 #undef REPEAT_1_TO_12
1736