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/base/bits.h"
10 #include "src/codegen/code-factory.h"
11 #include "src/codegen/interface-descriptors-inl.h"
12 #include "src/codegen/machine-type.h"
13 #include "src/codegen/macro-assembler.h"
14 #include "src/compiler/backend/instruction-selector.h"
15 #include "src/compiler/graph.h"
16 #include "src/compiler/js-graph.h"
17 #include "src/compiler/linkage.h"
18 #include "src/compiler/node-matchers.h"
19 #include "src/compiler/pipeline.h"
20 #include "src/compiler/raw-machine-assembler.h"
21 #include "src/compiler/schedule.h"
22 #include "src/execution/frames.h"
23 #include "src/handles/handles-inl.h"
24 #include "src/heap/factory-inl.h"
25 #include "src/interpreter/bytecodes.h"
26 #include "src/numbers/conversions-inl.h"
27 #include "src/objects/smi.h"
28 #include "src/utils/memcopy.h"
29 #include "src/zone/zone.h"
30 
31 namespace v8 {
32 namespace internal {
33 
34 constexpr MachineType MachineTypeOf<Smi>::value;
35 constexpr MachineType MachineTypeOf<Object>::value;
36 constexpr MachineType MachineTypeOf<MaybeObject>::value;
37 
38 namespace compiler {
39 
40 static_assert(std::is_convertible<TNode<Number>, TNode<Object>>::value,
41               "test subtyping");
42 static_assert(
43     std::is_convertible<TNode<Number>, TNode<UnionT<Smi, HeapObject>>>::value,
44     "test subtyping");
45 static_assert(
46     !std::is_convertible<TNode<UnionT<Smi, HeapObject>>, TNode<Number>>::value,
47     "test subtyping");
48 
CodeAssemblerState(Isolate * isolate,Zone * zone,const CallInterfaceDescriptor & descriptor,CodeKind kind,const char * name,Builtin builtin)49 CodeAssemblerState::CodeAssemblerState(
50     Isolate* isolate, Zone* zone, const CallInterfaceDescriptor& descriptor,
51     CodeKind kind, const char* name, Builtin builtin)
52     // TODO(rmcilroy): Should we use Linkage::GetBytecodeDispatchDescriptor for
53     // bytecode handlers?
54     : CodeAssemblerState(
55           isolate, zone,
56           Linkage::GetStubCallDescriptor(
57               zone, descriptor, descriptor.GetStackParameterCount(),
58               CallDescriptor::kNoFlags, Operator::kNoProperties),
59           kind, name, builtin) {}
60 
CodeAssemblerState(Isolate * isolate,Zone * zone,int parameter_count,CodeKind kind,const char * name,Builtin builtin)61 CodeAssemblerState::CodeAssemblerState(Isolate* isolate, Zone* zone,
62                                        int parameter_count, CodeKind kind,
63                                        const char* name, Builtin builtin)
64     : CodeAssemblerState(
65           isolate, zone,
66           Linkage::GetJSCallDescriptor(zone, false, parameter_count,
67                                        CallDescriptor::kCanUseRoots),
68           kind, name, builtin) {}
69 
CodeAssemblerState(Isolate * isolate,Zone * zone,CallDescriptor * call_descriptor,CodeKind kind,const char * name,Builtin builtin)70 CodeAssemblerState::CodeAssemblerState(Isolate* isolate, Zone* zone,
71                                        CallDescriptor* call_descriptor,
72                                        CodeKind kind, const char* name,
73                                        Builtin builtin)
74     : raw_assembler_(new RawMachineAssembler(
75           isolate, zone->New<Graph>(zone), call_descriptor,
76           MachineType::PointerRepresentation(),
77           InstructionSelector::SupportedMachineOperatorFlags(),
78           InstructionSelector::AlignmentRequirements())),
79       kind_(kind),
80       name_(name),
81       builtin_(builtin),
82       code_generated_(false),
83       variables_(zone),
84       jsgraph_(zone->New<JSGraph>(
85           isolate, raw_assembler_->graph(), raw_assembler_->common(),
86           zone->New<JSOperatorBuilder>(zone), raw_assembler_->simplified(),
87           raw_assembler_->machine())) {}
88 
89 CodeAssemblerState::~CodeAssemblerState() = default;
90 
parameter_count() const91 int CodeAssemblerState::parameter_count() const {
92   return static_cast<int>(raw_assembler_->call_descriptor()->ParameterCount());
93 }
94 
95 CodeAssembler::~CodeAssembler() = default;
96 
97 #if DEBUG
PrintCurrentBlock(std::ostream & os)98 void CodeAssemblerState::PrintCurrentBlock(std::ostream& os) {
99   raw_assembler_->PrintCurrentBlock(os);
100 }
101 #endif
102 
InsideBlock()103 bool CodeAssemblerState::InsideBlock() { return raw_assembler_->InsideBlock(); }
104 
SetInitialDebugInformation(const char * msg,const char * file,int line)105 void CodeAssemblerState::SetInitialDebugInformation(const char* msg,
106                                                     const char* file,
107                                                     int line) {
108 #if DEBUG
109   AssemblerDebugInfo debug_info = {msg, file, line};
110   raw_assembler_->SetCurrentExternalSourcePosition({file, line});
111   raw_assembler_->SetInitialDebugInformation(debug_info);
112 #endif  // DEBUG
113 }
114 
115 class BreakOnNodeDecorator final : public GraphDecorator {
116  public:
BreakOnNodeDecorator(NodeId node_id)117   explicit BreakOnNodeDecorator(NodeId node_id) : node_id_(node_id) {}
118 
Decorate(Node * node)119   void Decorate(Node* node) final {
120     if (node->id() == node_id_) {
121       base::OS::DebugBreak();
122     }
123   }
124 
125  private:
126   NodeId node_id_;
127 };
128 
BreakOnNode(int node_id)129 void CodeAssembler::BreakOnNode(int node_id) {
130   Graph* graph = raw_assembler()->graph();
131   Zone* zone = graph->zone();
132   GraphDecorator* decorator =
133       zone->New<BreakOnNodeDecorator>(static_cast<NodeId>(node_id));
134   graph->AddDecorator(decorator);
135 }
136 
RegisterCallGenerationCallbacks(const CodeAssemblerCallback & call_prologue,const CodeAssemblerCallback & call_epilogue)137 void CodeAssembler::RegisterCallGenerationCallbacks(
138     const CodeAssemblerCallback& call_prologue,
139     const CodeAssemblerCallback& call_epilogue) {
140   // The callback can be registered only once.
141   DCHECK(!state_->call_prologue_);
142   DCHECK(!state_->call_epilogue_);
143   state_->call_prologue_ = call_prologue;
144   state_->call_epilogue_ = call_epilogue;
145 }
146 
UnregisterCallGenerationCallbacks()147 void CodeAssembler::UnregisterCallGenerationCallbacks() {
148   state_->call_prologue_ = nullptr;
149   state_->call_epilogue_ = nullptr;
150 }
151 
CallPrologue()152 void CodeAssembler::CallPrologue() {
153   if (state_->call_prologue_) {
154     state_->call_prologue_();
155   }
156 }
157 
CallEpilogue()158 void CodeAssembler::CallEpilogue() {
159   if (state_->call_epilogue_) {
160     state_->call_epilogue_();
161   }
162 }
163 
Word32ShiftIsSafe() const164 bool CodeAssembler::Word32ShiftIsSafe() const {
165   return raw_assembler()->machine()->Word32ShiftIsSafe();
166 }
167 
168 // static
GenerateCode(CodeAssemblerState * state,const AssemblerOptions & options,const ProfileDataFromFile * profile_data)169 Handle<Code> CodeAssembler::GenerateCode(
170     CodeAssemblerState* state, const AssemblerOptions& options,
171     const ProfileDataFromFile* profile_data) {
172   DCHECK(!state->code_generated_);
173 
174   RawMachineAssembler* rasm = state->raw_assembler_.get();
175 
176   Handle<Code> code;
177   Graph* graph = rasm->ExportForOptimization();
178 
179   code = Pipeline::GenerateCodeForCodeStub(
180              rasm->isolate(), rasm->call_descriptor(), graph, state->jsgraph_,
181              rasm->source_positions(), state->kind_, state->name_,
182              state->builtin_, options, profile_data)
183              .ToHandleChecked();
184 
185   state->code_generated_ = true;
186   return code;
187 }
188 
Is64() const189 bool CodeAssembler::Is64() const { return raw_assembler()->machine()->Is64(); }
Is32() const190 bool CodeAssembler::Is32() const { return raw_assembler()->machine()->Is32(); }
191 
IsFloat64RoundUpSupported() const192 bool CodeAssembler::IsFloat64RoundUpSupported() const {
193   return raw_assembler()->machine()->Float64RoundUp().IsSupported();
194 }
195 
IsFloat64RoundDownSupported() const196 bool CodeAssembler::IsFloat64RoundDownSupported() const {
197   return raw_assembler()->machine()->Float64RoundDown().IsSupported();
198 }
199 
IsFloat64RoundTiesEvenSupported() const200 bool CodeAssembler::IsFloat64RoundTiesEvenSupported() const {
201   return raw_assembler()->machine()->Float64RoundTiesEven().IsSupported();
202 }
203 
IsFloat64RoundTruncateSupported() const204 bool CodeAssembler::IsFloat64RoundTruncateSupported() const {
205   return raw_assembler()->machine()->Float64RoundTruncate().IsSupported();
206 }
207 
IsInt32AbsWithOverflowSupported() const208 bool CodeAssembler::IsInt32AbsWithOverflowSupported() const {
209   return raw_assembler()->machine()->Int32AbsWithOverflow().IsSupported();
210 }
211 
IsInt64AbsWithOverflowSupported() const212 bool CodeAssembler::IsInt64AbsWithOverflowSupported() const {
213   return raw_assembler()->machine()->Int64AbsWithOverflow().IsSupported();
214 }
215 
IsIntPtrAbsWithOverflowSupported() const216 bool CodeAssembler::IsIntPtrAbsWithOverflowSupported() const {
217   return Is64() ? IsInt64AbsWithOverflowSupported()
218                 : IsInt32AbsWithOverflowSupported();
219 }
220 
IsWord32PopcntSupported() const221 bool CodeAssembler::IsWord32PopcntSupported() const {
222   return raw_assembler()->machine()->Word32Popcnt().IsSupported();
223 }
224 
IsWord64PopcntSupported() const225 bool CodeAssembler::IsWord64PopcntSupported() const {
226   return raw_assembler()->machine()->Word64Popcnt().IsSupported();
227 }
228 
IsWord32CtzSupported() const229 bool CodeAssembler::IsWord32CtzSupported() const {
230   return raw_assembler()->machine()->Word32Ctz().IsSupported();
231 }
232 
IsWord64CtzSupported() const233 bool CodeAssembler::IsWord64CtzSupported() const {
234   return raw_assembler()->machine()->Word64Ctz().IsSupported();
235 }
236 
237 #ifdef DEBUG
GenerateCheckMaybeObjectIsObject(TNode<MaybeObject> node,const char * location)238 void CodeAssembler::GenerateCheckMaybeObjectIsObject(TNode<MaybeObject> node,
239                                                      const char* location) {
240   Label ok(this);
241   GotoIf(WordNotEqual(WordAnd(BitcastMaybeObjectToWord(node),
242                               IntPtrConstant(kHeapObjectTagMask)),
243                       IntPtrConstant(kWeakHeapObjectTag)),
244          &ok);
245   base::EmbeddedVector<char, 1024> message;
246   SNPrintF(message, "no Object: %s", location);
247   TNode<String> message_node = StringConstant(message.begin());
248   // This somewhat misuses the AbortCSADcheck runtime function. This will print
249   // "abort: CSA_DCHECK failed: <message>", which is good enough.
250   AbortCSADcheck(message_node);
251   Unreachable();
252   Bind(&ok);
253 }
254 #endif
255 
Int32Constant(int32_t value)256 TNode<Int32T> CodeAssembler::Int32Constant(int32_t value) {
257   return UncheckedCast<Int32T>(jsgraph()->Int32Constant(value));
258 }
259 
Int64Constant(int64_t value)260 TNode<Int64T> CodeAssembler::Int64Constant(int64_t value) {
261   return UncheckedCast<Int64T>(jsgraph()->Int64Constant(value));
262 }
263 
IntPtrConstant(intptr_t value)264 TNode<IntPtrT> CodeAssembler::IntPtrConstant(intptr_t value) {
265   return UncheckedCast<IntPtrT>(jsgraph()->IntPtrConstant(value));
266 }
267 
TaggedIndexConstant(intptr_t value)268 TNode<TaggedIndex> CodeAssembler::TaggedIndexConstant(intptr_t value) {
269   DCHECK(TaggedIndex::IsValid(value));
270   return UncheckedCast<TaggedIndex>(raw_assembler()->IntPtrConstant(value));
271 }
272 
NumberConstant(double value)273 TNode<Number> CodeAssembler::NumberConstant(double value) {
274   int smi_value;
275   if (DoubleToSmiInteger(value, &smi_value)) {
276     return UncheckedCast<Number>(SmiConstant(smi_value));
277   } else {
278     // We allocate the heap number constant eagerly at this point instead of
279     // deferring allocation to code generation
280     // (see AllocateAndInstallRequestedHeapObjects) since that makes it easier
281     // to generate constant lookups for embedded builtins.
282     return UncheckedCast<Number>(HeapConstant(
283         isolate()->factory()->NewHeapNumberForCodeAssembler(value)));
284   }
285 }
286 
SmiConstant(Smi value)287 TNode<Smi> CodeAssembler::SmiConstant(Smi value) {
288   return UncheckedCast<Smi>(BitcastWordToTaggedSigned(
289       IntPtrConstant(static_cast<intptr_t>(value.ptr()))));
290 }
291 
SmiConstant(int value)292 TNode<Smi> CodeAssembler::SmiConstant(int value) {
293   return SmiConstant(Smi::FromInt(value));
294 }
295 
UntypedHeapConstant(Handle<HeapObject> object)296 TNode<HeapObject> CodeAssembler::UntypedHeapConstant(
297     Handle<HeapObject> object) {
298   return UncheckedCast<HeapObject>(jsgraph()->HeapConstant(object));
299 }
300 
StringConstant(const char * str)301 TNode<String> CodeAssembler::StringConstant(const char* str) {
302   Handle<String> internalized_string =
303       factory()->InternalizeString(base::OneByteVector(str));
304   return UncheckedCast<String>(HeapConstant(internalized_string));
305 }
306 
BooleanConstant(bool value)307 TNode<Oddball> CodeAssembler::BooleanConstant(bool value) {
308   Handle<Object> object = isolate()->factory()->ToBoolean(value);
309   return UncheckedCast<Oddball>(
310       jsgraph()->HeapConstant(Handle<HeapObject>::cast(object)));
311 }
312 
ExternalConstant(ExternalReference address)313 TNode<ExternalReference> CodeAssembler::ExternalConstant(
314     ExternalReference address) {
315   return UncheckedCast<ExternalReference>(
316       raw_assembler()->ExternalConstant(address));
317 }
318 
Float32Constant(double value)319 TNode<Float32T> CodeAssembler::Float32Constant(double value) {
320   return UncheckedCast<Float32T>(jsgraph()->Float32Constant(value));
321 }
322 
Float64Constant(double value)323 TNode<Float64T> CodeAssembler::Float64Constant(double value) {
324   return UncheckedCast<Float64T>(jsgraph()->Float64Constant(value));
325 }
326 
IsMapOffsetConstant(Node * node)327 bool CodeAssembler::IsMapOffsetConstant(Node* node) {
328   return raw_assembler()->IsMapOffsetConstant(node);
329 }
330 
TryToInt32Constant(TNode<IntegralT> node,int32_t * out_value)331 bool CodeAssembler::TryToInt32Constant(TNode<IntegralT> node,
332                                        int32_t* out_value) {
333   {
334     Int64Matcher m(node);
335     if (m.HasResolvedValue() &&
336         m.IsInRange(std::numeric_limits<int32_t>::min(),
337                     std::numeric_limits<int32_t>::max())) {
338       *out_value = static_cast<int32_t>(m.ResolvedValue());
339       return true;
340     }
341   }
342 
343   {
344     Int32Matcher m(node);
345     if (m.HasResolvedValue()) {
346       *out_value = m.ResolvedValue();
347       return true;
348     }
349   }
350 
351   return false;
352 }
353 
TryToInt64Constant(TNode<IntegralT> node,int64_t * out_value)354 bool CodeAssembler::TryToInt64Constant(TNode<IntegralT> node,
355                                        int64_t* out_value) {
356   Int64Matcher m(node);
357   if (m.HasResolvedValue()) *out_value = m.ResolvedValue();
358   return m.HasResolvedValue();
359 }
360 
TryToSmiConstant(TNode<Smi> tnode,Smi * out_value)361 bool CodeAssembler::TryToSmiConstant(TNode<Smi> tnode, Smi* out_value) {
362   Node* node = tnode;
363   if (node->opcode() == IrOpcode::kBitcastWordToTaggedSigned) {
364     node = node->InputAt(0);
365   }
366   return TryToSmiConstant(ReinterpretCast<IntPtrT>(tnode), out_value);
367 }
368 
TryToSmiConstant(TNode<IntegralT> node,Smi * out_value)369 bool CodeAssembler::TryToSmiConstant(TNode<IntegralT> node, Smi* out_value) {
370   IntPtrMatcher m(node);
371   if (m.HasResolvedValue()) {
372     intptr_t value = m.ResolvedValue();
373     // Make sure that the value is actually a smi
374     CHECK_EQ(0, value & ((static_cast<intptr_t>(1) << kSmiShiftSize) - 1));
375     *out_value = Smi(static_cast<Address>(value));
376     return true;
377   }
378   return false;
379 }
380 
TryToIntPtrConstant(TNode<Smi> tnode,intptr_t * out_value)381 bool CodeAssembler::TryToIntPtrConstant(TNode<Smi> tnode, intptr_t* out_value) {
382   Node* node = tnode;
383   if (node->opcode() == IrOpcode::kBitcastWordToTaggedSigned ||
384       node->opcode() == IrOpcode::kBitcastWordToTagged) {
385     node = node->InputAt(0);
386   }
387   return TryToIntPtrConstant(ReinterpretCast<IntPtrT>(tnode), out_value);
388 }
389 
TryToIntPtrConstant(TNode<IntegralT> node,intptr_t * out_value)390 bool CodeAssembler::TryToIntPtrConstant(TNode<IntegralT> node,
391                                         intptr_t* out_value) {
392   IntPtrMatcher m(node);
393   if (m.HasResolvedValue()) *out_value = m.ResolvedValue();
394   return m.HasResolvedValue();
395 }
396 
IsUndefinedConstant(TNode<Object> node)397 bool CodeAssembler::IsUndefinedConstant(TNode<Object> node) {
398   compiler::HeapObjectMatcher m(node);
399   return m.Is(isolate()->factory()->undefined_value());
400 }
401 
IsNullConstant(TNode<Object> node)402 bool CodeAssembler::IsNullConstant(TNode<Object> node) {
403   compiler::HeapObjectMatcher m(node);
404   return m.Is(isolate()->factory()->null_value());
405 }
406 
UntypedParameter(int index)407 Node* CodeAssembler::UntypedParameter(int index) {
408   if (index == kTargetParameterIndex) return raw_assembler()->TargetParameter();
409   return raw_assembler()->Parameter(index);
410 }
411 
IsJSFunctionCall() const412 bool CodeAssembler::IsJSFunctionCall() const {
413   auto call_descriptor = raw_assembler()->call_descriptor();
414   return call_descriptor->IsJSFunctionCall();
415 }
416 
GetJSContextParameter()417 TNode<Context> CodeAssembler::GetJSContextParameter() {
418   auto call_descriptor = raw_assembler()->call_descriptor();
419   DCHECK(call_descriptor->IsJSFunctionCall());
420   return Parameter<Context>(Linkage::GetJSCallContextParamIndex(
421       static_cast<int>(call_descriptor->JSParameterCount())));
422 }
423 
Return(TNode<Object> value)424 void CodeAssembler::Return(TNode<Object> value) {
425   DCHECK_EQ(1, raw_assembler()->call_descriptor()->ReturnCount());
426   DCHECK(raw_assembler()->call_descriptor()->GetReturnType(0).IsTagged());
427   return raw_assembler()->Return(value);
428 }
429 
Return(TNode<Object> value1,TNode<Object> value2)430 void CodeAssembler::Return(TNode<Object> value1, TNode<Object> value2) {
431   DCHECK_EQ(2, raw_assembler()->call_descriptor()->ReturnCount());
432   DCHECK(raw_assembler()->call_descriptor()->GetReturnType(0).IsTagged());
433   DCHECK(raw_assembler()->call_descriptor()->GetReturnType(1).IsTagged());
434   return raw_assembler()->Return(value1, value2);
435 }
436 
Return(TNode<Object> value1,TNode<Object> value2,TNode<Object> value3)437 void CodeAssembler::Return(TNode<Object> value1, TNode<Object> value2,
438                            TNode<Object> value3) {
439   DCHECK_EQ(3, raw_assembler()->call_descriptor()->ReturnCount());
440   DCHECK(raw_assembler()->call_descriptor()->GetReturnType(0).IsTagged());
441   DCHECK(raw_assembler()->call_descriptor()->GetReturnType(1).IsTagged());
442   DCHECK(raw_assembler()->call_descriptor()->GetReturnType(2).IsTagged());
443   return raw_assembler()->Return(value1, value2, value3);
444 }
445 
Return(TNode<Int32T> value)446 void CodeAssembler::Return(TNode<Int32T> value) {
447   DCHECK_EQ(1, raw_assembler()->call_descriptor()->ReturnCount());
448   DCHECK_EQ(MachineType::Int32(),
449             raw_assembler()->call_descriptor()->GetReturnType(0));
450   return raw_assembler()->Return(value);
451 }
452 
Return(TNode<Uint32T> value)453 void CodeAssembler::Return(TNode<Uint32T> value) {
454   DCHECK_EQ(1, raw_assembler()->call_descriptor()->ReturnCount());
455   DCHECK_EQ(MachineType::Uint32(),
456             raw_assembler()->call_descriptor()->GetReturnType(0));
457   return raw_assembler()->Return(value);
458 }
459 
Return(TNode<WordT> value)460 void CodeAssembler::Return(TNode<WordT> value) {
461   DCHECK_EQ(1, raw_assembler()->call_descriptor()->ReturnCount());
462   DCHECK_EQ(
463       MachineType::PointerRepresentation(),
464       raw_assembler()->call_descriptor()->GetReturnType(0).representation());
465   return raw_assembler()->Return(value);
466 }
467 
Return(TNode<Float32T> value)468 void CodeAssembler::Return(TNode<Float32T> value) {
469   DCHECK_EQ(1, raw_assembler()->call_descriptor()->ReturnCount());
470   DCHECK_EQ(MachineType::Float32(),
471             raw_assembler()->call_descriptor()->GetReturnType(0));
472   return raw_assembler()->Return(value);
473 }
474 
Return(TNode<Float64T> value)475 void CodeAssembler::Return(TNode<Float64T> value) {
476   DCHECK_EQ(1, raw_assembler()->call_descriptor()->ReturnCount());
477   DCHECK_EQ(MachineType::Float64(),
478             raw_assembler()->call_descriptor()->GetReturnType(0));
479   return raw_assembler()->Return(value);
480 }
481 
Return(TNode<WordT> value1,TNode<WordT> value2)482 void CodeAssembler::Return(TNode<WordT> value1, TNode<WordT> value2) {
483   DCHECK_EQ(2, raw_assembler()->call_descriptor()->ReturnCount());
484   DCHECK_EQ(
485       MachineType::PointerRepresentation(),
486       raw_assembler()->call_descriptor()->GetReturnType(0).representation());
487   DCHECK_EQ(
488       MachineType::PointerRepresentation(),
489       raw_assembler()->call_descriptor()->GetReturnType(1).representation());
490   return raw_assembler()->Return(value1, value2);
491 }
492 
PopAndReturn(Node * pop,Node * value)493 void CodeAssembler::PopAndReturn(Node* pop, Node* value) {
494   DCHECK_EQ(1, raw_assembler()->call_descriptor()->ReturnCount());
495   return raw_assembler()->PopAndReturn(pop, value);
496 }
497 
ReturnIf(TNode<BoolT> condition,TNode<Object> value)498 void CodeAssembler::ReturnIf(TNode<BoolT> condition, TNode<Object> value) {
499   Label if_return(this), if_continue(this);
500   Branch(condition, &if_return, &if_continue);
501   Bind(&if_return);
502   Return(value);
503   Bind(&if_continue);
504 }
505 
AbortCSADcheck(Node * message)506 void CodeAssembler::AbortCSADcheck(Node* message) {
507   raw_assembler()->AbortCSADcheck(message);
508 }
509 
DebugBreak()510 void CodeAssembler::DebugBreak() { raw_assembler()->DebugBreak(); }
511 
Unreachable()512 void CodeAssembler::Unreachable() {
513   DebugBreak();
514   raw_assembler()->Unreachable();
515 }
516 
Comment(std::string str)517 void CodeAssembler::Comment(std::string str) {
518   if (!FLAG_code_comments) return;
519   raw_assembler()->Comment(str);
520 }
521 
StaticAssert(TNode<BoolT> value,const char * source)522 void CodeAssembler::StaticAssert(TNode<BoolT> value, const char* source) {
523   raw_assembler()->StaticAssert(value, source);
524 }
525 
SetSourcePosition(const char * file,int line)526 void CodeAssembler::SetSourcePosition(const char* file, int line) {
527   raw_assembler()->SetCurrentExternalSourcePosition({file, line});
528 }
529 
PushSourcePosition()530 void CodeAssembler::PushSourcePosition() {
531   auto position = raw_assembler()->GetCurrentExternalSourcePosition();
532   state_->macro_call_stack_.push_back(position);
533 }
534 
PopSourcePosition()535 void CodeAssembler::PopSourcePosition() {
536   state_->macro_call_stack_.pop_back();
537 }
538 
GetMacroSourcePositionStack() const539 const std::vector<FileAndLine>& CodeAssembler::GetMacroSourcePositionStack()
540     const {
541   return state_->macro_call_stack_;
542 }
543 
Bind(Label * label)544 void CodeAssembler::Bind(Label* label) { return label->Bind(); }
545 
546 #if DEBUG
Bind(Label * label,AssemblerDebugInfo debug_info)547 void CodeAssembler::Bind(Label* label, AssemblerDebugInfo debug_info) {
548   return label->Bind(debug_info);
549 }
550 #endif  // DEBUG
551 
LoadFramePointer()552 TNode<RawPtrT> CodeAssembler::LoadFramePointer() {
553   return UncheckedCast<RawPtrT>(raw_assembler()->LoadFramePointer());
554 }
555 
LoadParentFramePointer()556 TNode<RawPtrT> CodeAssembler::LoadParentFramePointer() {
557   return UncheckedCast<RawPtrT>(raw_assembler()->LoadParentFramePointer());
558 }
559 
560 #define DEFINE_CODE_ASSEMBLER_BINARY_OP(name, ResType, Arg1Type, Arg2Type)   \
561   TNode<ResType> CodeAssembler::name(TNode<Arg1Type> a, TNode<Arg2Type> b) { \
562     return UncheckedCast<ResType>(raw_assembler()->name(a, b));              \
563   }
CODE_ASSEMBLER_BINARY_OP_LIST(DEFINE_CODE_ASSEMBLER_BINARY_OP)564 CODE_ASSEMBLER_BINARY_OP_LIST(DEFINE_CODE_ASSEMBLER_BINARY_OP)
565 #undef DEFINE_CODE_ASSEMBLER_BINARY_OP
566 
567 TNode<WordT> CodeAssembler::WordShl(TNode<WordT> value, int shift) {
568   return (shift != 0) ? WordShl(value, IntPtrConstant(shift)) : value;
569 }
570 
WordShr(TNode<WordT> value,int shift)571 TNode<WordT> CodeAssembler::WordShr(TNode<WordT> value, int shift) {
572   return (shift != 0) ? WordShr(value, IntPtrConstant(shift)) : value;
573 }
574 
WordSar(TNode<WordT> value,int shift)575 TNode<WordT> CodeAssembler::WordSar(TNode<WordT> value, int shift) {
576   return (shift != 0) ? WordSar(value, IntPtrConstant(shift)) : value;
577 }
578 
Word32Shr(TNode<Word32T> value,int shift)579 TNode<Word32T> CodeAssembler::Word32Shr(TNode<Word32T> value, int shift) {
580   return (shift != 0) ? Word32Shr(value, Int32Constant(shift)) : value;
581 }
582 
Word32Sar(TNode<Word32T> value,int shift)583 TNode<Word32T> CodeAssembler::Word32Sar(TNode<Word32T> value, int shift) {
584   return (shift != 0) ? Word32Sar(value, Int32Constant(shift)) : value;
585 }
586 
587 #define CODE_ASSEMBLER_COMPARE(Name, ArgT, VarT, ToConstant, op)          \
588   TNode<BoolT> CodeAssembler::Name(TNode<ArgT> left, TNode<ArgT> right) { \
589     VarT lhs, rhs;                                                        \
590     if (ToConstant(left, &lhs) && ToConstant(right, &rhs)) {              \
591       return BoolConstant(lhs op rhs);                                    \
592     }                                                                     \
593     return UncheckedCast<BoolT>(raw_assembler()->Name(left, right));      \
594   }
595 
596 CODE_ASSEMBLER_COMPARE(IntPtrEqual, WordT, intptr_t, TryToIntPtrConstant, ==)
597 CODE_ASSEMBLER_COMPARE(WordEqual, WordT, intptr_t, TryToIntPtrConstant, ==)
598 CODE_ASSEMBLER_COMPARE(WordNotEqual, WordT, intptr_t, TryToIntPtrConstant, !=)
599 CODE_ASSEMBLER_COMPARE(Word32Equal, Word32T, int32_t, TryToInt32Constant, ==)
600 CODE_ASSEMBLER_COMPARE(Word32NotEqual, Word32T, int32_t, TryToInt32Constant, !=)
601 CODE_ASSEMBLER_COMPARE(Word64Equal, Word64T, int64_t, TryToInt64Constant, ==)
602 CODE_ASSEMBLER_COMPARE(Word64NotEqual, Word64T, int64_t, TryToInt64Constant, !=)
603 #undef CODE_ASSEMBLER_COMPARE
604 
ChangeUint32ToWord(TNode<Word32T> value)605 TNode<UintPtrT> CodeAssembler::ChangeUint32ToWord(TNode<Word32T> value) {
606   if (raw_assembler()->machine()->Is64()) {
607     return UncheckedCast<UintPtrT>(
608         raw_assembler()->ChangeUint32ToUint64(value));
609   }
610   return ReinterpretCast<UintPtrT>(value);
611 }
612 
ChangeInt32ToIntPtr(TNode<Word32T> value)613 TNode<IntPtrT> CodeAssembler::ChangeInt32ToIntPtr(TNode<Word32T> value) {
614   if (raw_assembler()->machine()->Is64()) {
615     return UncheckedCast<IntPtrT>(raw_assembler()->ChangeInt32ToInt64(value));
616   }
617   return ReinterpretCast<IntPtrT>(value);
618 }
619 
ChangeFloat64ToIntPtr(TNode<Float64T> value)620 TNode<IntPtrT> CodeAssembler::ChangeFloat64ToIntPtr(TNode<Float64T> value) {
621   if (raw_assembler()->machine()->Is64()) {
622     return UncheckedCast<IntPtrT>(raw_assembler()->ChangeFloat64ToInt64(value));
623   }
624   return UncheckedCast<IntPtrT>(raw_assembler()->ChangeFloat64ToInt32(value));
625 }
626 
ChangeFloat64ToUintPtr(TNode<Float64T> value)627 TNode<UintPtrT> CodeAssembler::ChangeFloat64ToUintPtr(TNode<Float64T> value) {
628   if (raw_assembler()->machine()->Is64()) {
629     return UncheckedCast<UintPtrT>(
630         raw_assembler()->ChangeFloat64ToUint64(value));
631   }
632   return UncheckedCast<UintPtrT>(raw_assembler()->ChangeFloat64ToUint32(value));
633 }
634 
ChangeUintPtrToFloat64(TNode<UintPtrT> value)635 TNode<Float64T> CodeAssembler::ChangeUintPtrToFloat64(TNode<UintPtrT> value) {
636   if (raw_assembler()->machine()->Is64()) {
637     // TODO(turbofan): Maybe we should introduce a ChangeUint64ToFloat64
638     // machine operator to TurboFan here?
639     return UncheckedCast<Float64T>(
640         raw_assembler()->RoundUint64ToFloat64(value));
641   }
642   return UncheckedCast<Float64T>(raw_assembler()->ChangeUint32ToFloat64(value));
643 }
644 
RoundIntPtrToFloat64(Node * value)645 TNode<Float64T> CodeAssembler::RoundIntPtrToFloat64(Node* value) {
646   if (raw_assembler()->machine()->Is64()) {
647     return UncheckedCast<Float64T>(raw_assembler()->RoundInt64ToFloat64(value));
648   }
649   return UncheckedCast<Float64T>(raw_assembler()->ChangeInt32ToFloat64(value));
650 }
651 
TruncateFloat32ToInt32(TNode<Float32T> value)652 TNode<Int32T> CodeAssembler::TruncateFloat32ToInt32(TNode<Float32T> value) {
653   return UncheckedCast<Int32T>(raw_assembler()->TruncateFloat32ToInt32(
654       value, TruncateKind::kSetOverflowToMin));
655 }
656 #define DEFINE_CODE_ASSEMBLER_UNARY_OP(name, ResType, ArgType) \
657   TNode<ResType> CodeAssembler::name(TNode<ArgType> a) {       \
658     return UncheckedCast<ResType>(raw_assembler()->name(a));   \
659   }
CODE_ASSEMBLER_UNARY_OP_LIST(DEFINE_CODE_ASSEMBLER_UNARY_OP)660 CODE_ASSEMBLER_UNARY_OP_LIST(DEFINE_CODE_ASSEMBLER_UNARY_OP)
661 #undef DEFINE_CODE_ASSEMBLER_UNARY_OP
662 
663 Node* CodeAssembler::Load(MachineType type, Node* base) {
664   return raw_assembler()->Load(type, base);
665 }
666 
Load(MachineType type,Node * base,Node * offset)667 Node* CodeAssembler::Load(MachineType type, Node* base, Node* offset) {
668   return raw_assembler()->Load(type, base, offset);
669 }
670 
LoadFullTagged(Node * base)671 TNode<Object> CodeAssembler::LoadFullTagged(Node* base) {
672   return BitcastWordToTagged(Load<RawPtrT>(base));
673 }
674 
LoadFullTagged(Node * base,TNode<IntPtrT> offset)675 TNode<Object> CodeAssembler::LoadFullTagged(Node* base, TNode<IntPtrT> offset) {
676   // Please use LoadFromObject(MachineType::MapInHeader(), object,
677   // IntPtrConstant(-kHeapObjectTag)) instead.
678   DCHECK(!raw_assembler()->IsMapOffsetConstantMinusTag(offset));
679   return BitcastWordToTagged(Load<RawPtrT>(base, offset));
680 }
681 
AtomicLoad(MachineType type,AtomicMemoryOrder order,TNode<RawPtrT> base,TNode<WordT> offset)682 Node* CodeAssembler::AtomicLoad(MachineType type, AtomicMemoryOrder order,
683                                 TNode<RawPtrT> base, TNode<WordT> offset) {
684   DCHECK(!raw_assembler()->IsMapOffsetConstantMinusTag(offset));
685   return raw_assembler()->AtomicLoad(AtomicLoadParameters(type, order), base,
686                                      offset);
687 }
688 
689 template <class Type>
AtomicLoad64(AtomicMemoryOrder order,TNode<RawPtrT> base,TNode<WordT> offset)690 TNode<Type> CodeAssembler::AtomicLoad64(AtomicMemoryOrder order,
691                                         TNode<RawPtrT> base,
692                                         TNode<WordT> offset) {
693   return UncheckedCast<Type>(raw_assembler()->AtomicLoad64(
694       AtomicLoadParameters(MachineType::Uint64(), order), base, offset));
695 }
696 
697 template TNode<AtomicInt64> CodeAssembler::AtomicLoad64<AtomicInt64>(
698     AtomicMemoryOrder order, TNode<RawPtrT> base, TNode<WordT> offset);
699 template TNode<AtomicUint64> CodeAssembler::AtomicLoad64<AtomicUint64>(
700     AtomicMemoryOrder order, TNode<RawPtrT> base, TNode<WordT> offset);
701 
LoadFromObject(MachineType type,TNode<Object> object,TNode<IntPtrT> offset)702 Node* CodeAssembler::LoadFromObject(MachineType type, TNode<Object> object,
703                                     TNode<IntPtrT> offset) {
704   return raw_assembler()->LoadFromObject(type, object, offset);
705 }
706 
707 #ifdef V8_MAP_PACKING
PackMapWord(Node * value)708 Node* CodeAssembler::PackMapWord(Node* value) {
709   TNode<IntPtrT> map_word =
710       BitcastTaggedToWordForTagAndSmiBits(UncheckedCast<AnyTaggedT>(value));
711   TNode<WordT> packed = WordXor(UncheckedCast<WordT>(map_word),
712                                 IntPtrConstant(Internals::kMapWordXorMask));
713   return BitcastWordToTaggedSigned(packed);
714 }
715 #endif
716 
LoadRootMapWord(RootIndex root_index)717 TNode<AnyTaggedT> CodeAssembler::LoadRootMapWord(RootIndex root_index) {
718 #ifdef V8_MAP_PACKING
719   Handle<Object> root = isolate()->root_handle(root_index);
720   Node* map = HeapConstant(Handle<Map>::cast(root));
721   map = PackMapWord(map);
722   return ReinterpretCast<AnyTaggedT>(map);
723 #else
724   return LoadRoot(root_index);
725 #endif
726 }
727 
LoadRoot(RootIndex root_index)728 TNode<Object> CodeAssembler::LoadRoot(RootIndex root_index) {
729   if (RootsTable::IsImmortalImmovable(root_index)) {
730     Handle<Object> root = isolate()->root_handle(root_index);
731     if (root->IsSmi()) {
732       return SmiConstant(Smi::cast(*root));
733     } else {
734       return HeapConstant(Handle<HeapObject>::cast(root));
735     }
736   }
737 
738   // TODO(jgruber): In theory we could generate better code for this by
739   // letting the macro assembler decide how to load from the roots list. In most
740   // cases, it would boil down to loading from a fixed kRootRegister offset.
741   TNode<ExternalReference> isolate_root =
742       ExternalConstant(ExternalReference::isolate_root(isolate()));
743   int offset = IsolateData::root_slot_offset(root_index);
744   return UncheckedCast<Object>(
745       LoadFullTagged(isolate_root, IntPtrConstant(offset)));
746 }
747 
UnalignedLoad(MachineType type,TNode<RawPtrT> base,TNode<WordT> offset)748 Node* CodeAssembler::UnalignedLoad(MachineType type, TNode<RawPtrT> base,
749                                    TNode<WordT> offset) {
750   return raw_assembler()->UnalignedLoad(type, static_cast<Node*>(base), offset);
751 }
752 
Store(Node * base,Node * value)753 void CodeAssembler::Store(Node* base, Node* value) {
754   raw_assembler()->Store(MachineRepresentation::kTagged, base, value,
755                          kFullWriteBarrier);
756 }
757 
StoreToObject(MachineRepresentation rep,TNode<Object> object,TNode<IntPtrT> offset,Node * value,StoreToObjectWriteBarrier write_barrier)758 void CodeAssembler::StoreToObject(MachineRepresentation rep,
759                                   TNode<Object> object, TNode<IntPtrT> offset,
760                                   Node* value,
761                                   StoreToObjectWriteBarrier write_barrier) {
762   WriteBarrierKind write_barrier_kind;
763   switch (write_barrier) {
764     case StoreToObjectWriteBarrier::kFull:
765       write_barrier_kind = WriteBarrierKind::kFullWriteBarrier;
766       break;
767     case StoreToObjectWriteBarrier::kMap:
768       write_barrier_kind = WriteBarrierKind::kMapWriteBarrier;
769       break;
770     case StoreToObjectWriteBarrier::kNone:
771       if (CanBeTaggedPointer(rep)) {
772         write_barrier_kind = WriteBarrierKind::kAssertNoWriteBarrier;
773       } else {
774         write_barrier_kind = WriteBarrierKind::kNoWriteBarrier;
775       }
776       break;
777   }
778   raw_assembler()->StoreToObject(rep, object, offset, value,
779                                  write_barrier_kind);
780 }
781 
OptimizedStoreField(MachineRepresentation rep,TNode<HeapObject> object,int offset,Node * value)782 void CodeAssembler::OptimizedStoreField(MachineRepresentation rep,
783                                         TNode<HeapObject> object, int offset,
784                                         Node* value) {
785   raw_assembler()->OptimizedStoreField(rep, object, offset, value,
786                                        WriteBarrierKind::kFullWriteBarrier);
787 }
788 
OptimizedStoreFieldAssertNoWriteBarrier(MachineRepresentation rep,TNode<HeapObject> object,int offset,Node * value)789 void CodeAssembler::OptimizedStoreFieldAssertNoWriteBarrier(
790     MachineRepresentation rep, TNode<HeapObject> object, int offset,
791     Node* value) {
792   raw_assembler()->OptimizedStoreField(rep, object, offset, value,
793                                        WriteBarrierKind::kAssertNoWriteBarrier);
794 }
795 
OptimizedStoreFieldUnsafeNoWriteBarrier(MachineRepresentation rep,TNode<HeapObject> object,int offset,Node * value)796 void CodeAssembler::OptimizedStoreFieldUnsafeNoWriteBarrier(
797     MachineRepresentation rep, TNode<HeapObject> object, int offset,
798     Node* value) {
799   raw_assembler()->OptimizedStoreField(rep, object, offset, value,
800                                        WriteBarrierKind::kNoWriteBarrier);
801 }
802 
OptimizedStoreMap(TNode<HeapObject> object,TNode<Map> map)803 void CodeAssembler::OptimizedStoreMap(TNode<HeapObject> object,
804                                       TNode<Map> map) {
805   raw_assembler()->OptimizedStoreMap(object, map);
806 }
807 
Store(Node * base,Node * offset,Node * value)808 void CodeAssembler::Store(Node* base, Node* offset, Node* value) {
809   // Please use OptimizedStoreMap(base, value) instead.
810   DCHECK(!raw_assembler()->IsMapOffsetConstantMinusTag(offset));
811   raw_assembler()->Store(MachineRepresentation::kTagged, base, offset, value,
812                          kFullWriteBarrier);
813 }
814 
StoreEphemeronKey(Node * base,Node * offset,Node * value)815 void CodeAssembler::StoreEphemeronKey(Node* base, Node* offset, Node* value) {
816   DCHECK(!raw_assembler()->IsMapOffsetConstantMinusTag(offset));
817   raw_assembler()->Store(MachineRepresentation::kTagged, base, offset, value,
818                          kEphemeronKeyWriteBarrier);
819 }
820 
StoreNoWriteBarrier(MachineRepresentation rep,Node * base,Node * value)821 void CodeAssembler::StoreNoWriteBarrier(MachineRepresentation rep, Node* base,
822                                         Node* value) {
823   raw_assembler()->Store(
824       rep, base, value,
825       CanBeTaggedPointer(rep) ? kAssertNoWriteBarrier : kNoWriteBarrier);
826 }
827 
StoreNoWriteBarrier(MachineRepresentation rep,Node * base,Node * offset,Node * value)828 void CodeAssembler::StoreNoWriteBarrier(MachineRepresentation rep, Node* base,
829                                         Node* offset, Node* value) {
830   // Please use OptimizedStoreMap(base, value) instead.
831   DCHECK(!raw_assembler()->IsMapOffsetConstantMinusTag(offset));
832   raw_assembler()->Store(
833       rep, base, offset, value,
834       CanBeTaggedPointer(rep) ? kAssertNoWriteBarrier : kNoWriteBarrier);
835 }
836 
UnsafeStoreNoWriteBarrier(MachineRepresentation rep,Node * base,Node * value)837 void CodeAssembler::UnsafeStoreNoWriteBarrier(MachineRepresentation rep,
838                                               Node* base, Node* value) {
839   raw_assembler()->Store(rep, base, value, kNoWriteBarrier);
840 }
841 
UnsafeStoreNoWriteBarrier(MachineRepresentation rep,Node * base,Node * offset,Node * value)842 void CodeAssembler::UnsafeStoreNoWriteBarrier(MachineRepresentation rep,
843                                               Node* base, Node* offset,
844                                               Node* value) {
845   // Please use OptimizedStoreMap(base, value) instead.
846   DCHECK(!raw_assembler()->IsMapOffsetConstantMinusTag(offset));
847   raw_assembler()->Store(rep, base, offset, value, kNoWriteBarrier);
848 }
849 
StoreFullTaggedNoWriteBarrier(TNode<RawPtrT> base,TNode<Object> tagged_value)850 void CodeAssembler::StoreFullTaggedNoWriteBarrier(TNode<RawPtrT> base,
851                                                   TNode<Object> tagged_value) {
852   StoreNoWriteBarrier(MachineType::PointerRepresentation(), base,
853                       BitcastTaggedToWord(tagged_value));
854 }
855 
StoreFullTaggedNoWriteBarrier(TNode<RawPtrT> base,TNode<IntPtrT> offset,TNode<Object> tagged_value)856 void CodeAssembler::StoreFullTaggedNoWriteBarrier(TNode<RawPtrT> base,
857                                                   TNode<IntPtrT> offset,
858                                                   TNode<Object> tagged_value) {
859   // Please use OptimizedStoreMap(base, tagged_value) instead.
860   DCHECK(!raw_assembler()->IsMapOffsetConstantMinusTag(offset));
861   StoreNoWriteBarrier(MachineType::PointerRepresentation(), base, offset,
862                       BitcastTaggedToWord(tagged_value));
863 }
864 
AtomicStore(MachineRepresentation rep,AtomicMemoryOrder order,TNode<RawPtrT> base,TNode<WordT> offset,TNode<Word32T> value)865 void CodeAssembler::AtomicStore(MachineRepresentation rep,
866                                 AtomicMemoryOrder order, TNode<RawPtrT> base,
867                                 TNode<WordT> offset, TNode<Word32T> value) {
868   DCHECK(!raw_assembler()->IsMapOffsetConstantMinusTag(offset));
869   raw_assembler()->AtomicStore(
870       AtomicStoreParameters(rep, WriteBarrierKind::kNoWriteBarrier, order),
871       base, offset, value);
872 }
873 
AtomicStore64(AtomicMemoryOrder order,TNode<RawPtrT> base,TNode<WordT> offset,TNode<UintPtrT> value,TNode<UintPtrT> value_high)874 void CodeAssembler::AtomicStore64(AtomicMemoryOrder order, TNode<RawPtrT> base,
875                                   TNode<WordT> offset, TNode<UintPtrT> value,
876                                   TNode<UintPtrT> value_high) {
877   raw_assembler()->AtomicStore64(
878       AtomicStoreParameters(MachineRepresentation::kWord64,
879                             WriteBarrierKind::kNoWriteBarrier, order),
880       base, offset, value, value_high);
881 }
882 
883 #define ATOMIC_FUNCTION(name)                                                 \
884   TNode<Word32T> CodeAssembler::Atomic##name(                                 \
885       MachineType type, TNode<RawPtrT> base, TNode<UintPtrT> offset,          \
886       TNode<Word32T> value) {                                                 \
887     return UncheckedCast<Word32T>(                                            \
888         raw_assembler()->Atomic##name(type, base, offset, value));            \
889   }                                                                           \
890   template <class Type>                                                       \
891   TNode<Type> CodeAssembler::Atomic##name##64(                                \
892       TNode<RawPtrT> base, TNode<UintPtrT> offset, TNode<UintPtrT> value,     \
893       TNode<UintPtrT> value_high) {                                           \
894     return UncheckedCast<Type>(                                               \
895         raw_assembler()->Atomic##name##64(base, offset, value, value_high));  \
896   }                                                                           \
897   template TNode<AtomicInt64> CodeAssembler::Atomic##name##64 < AtomicInt64 > \
898       (TNode<RawPtrT> base, TNode<UintPtrT> offset, TNode<UintPtrT> value,    \
899        TNode<UintPtrT> value_high);                                           \
900   template TNode<AtomicUint64> CodeAssembler::Atomic##name##64 <              \
901       AtomicUint64 > (TNode<RawPtrT> base, TNode<UintPtrT> offset,            \
902                       TNode<UintPtrT> value, TNode<UintPtrT> value_high);
903 ATOMIC_FUNCTION(Add)
ATOMIC_FUNCTION(Sub)904 ATOMIC_FUNCTION(Sub)
905 ATOMIC_FUNCTION(And)
906 ATOMIC_FUNCTION(Or)
907 ATOMIC_FUNCTION(Xor)
908 ATOMIC_FUNCTION(Exchange)
909 #undef ATOMIC_FUNCTION
910 
911 TNode<Word32T> CodeAssembler::AtomicCompareExchange(MachineType type,
912                                                     TNode<RawPtrT> base,
913                                                     TNode<WordT> offset,
914                                                     TNode<Word32T> old_value,
915                                                     TNode<Word32T> new_value) {
916   return UncheckedCast<Word32T>(raw_assembler()->AtomicCompareExchange(
917       type, base, offset, old_value, new_value));
918 }
919 
920 template <class Type>
AtomicCompareExchange64(TNode<RawPtrT> base,TNode<WordT> offset,TNode<UintPtrT> old_value,TNode<UintPtrT> new_value,TNode<UintPtrT> old_value_high,TNode<UintPtrT> new_value_high)921 TNode<Type> CodeAssembler::AtomicCompareExchange64(
922     TNode<RawPtrT> base, TNode<WordT> offset, TNode<UintPtrT> old_value,
923     TNode<UintPtrT> new_value, TNode<UintPtrT> old_value_high,
924     TNode<UintPtrT> new_value_high) {
925   // This uses Uint64() intentionally: AtomicCompareExchange is not implemented
926   // for Int64(), which is fine because the machine instruction only cares
927   // about words.
928   return UncheckedCast<Type>(raw_assembler()->AtomicCompareExchange64(
929       base, offset, old_value, old_value_high, new_value, new_value_high));
930 }
931 
932 template TNode<AtomicInt64> CodeAssembler::AtomicCompareExchange64<AtomicInt64>(
933     TNode<RawPtrT> base, TNode<WordT> offset, TNode<UintPtrT> old_value,
934     TNode<UintPtrT> new_value, TNode<UintPtrT> old_value_high,
935     TNode<UintPtrT> new_value_high);
936 template TNode<AtomicUint64>
937 CodeAssembler::AtomicCompareExchange64<AtomicUint64>(
938     TNode<RawPtrT> base, TNode<WordT> offset, TNode<UintPtrT> old_value,
939     TNode<UintPtrT> new_value, TNode<UintPtrT> old_value_high,
940     TNode<UintPtrT> new_value_high);
941 
StoreRoot(RootIndex root_index,TNode<Object> value)942 void CodeAssembler::StoreRoot(RootIndex root_index, TNode<Object> value) {
943   DCHECK(!RootsTable::IsImmortalImmovable(root_index));
944   TNode<ExternalReference> isolate_root =
945       ExternalConstant(ExternalReference::isolate_root(isolate()));
946   int offset = IsolateData::root_slot_offset(root_index);
947   StoreFullTaggedNoWriteBarrier(isolate_root, IntPtrConstant(offset), value);
948 }
949 
Projection(int index,Node * value)950 Node* CodeAssembler::Projection(int index, Node* value) {
951   DCHECK_LT(index, value->op()->ValueOutputCount());
952   return raw_assembler()->Projection(index, value);
953 }
954 
OptimizedAllocate(TNode<IntPtrT> size,AllocationType allocation,AllowLargeObjects allow_large_objects)955 TNode<HeapObject> CodeAssembler::OptimizedAllocate(
956     TNode<IntPtrT> size, AllocationType allocation,
957     AllowLargeObjects allow_large_objects) {
958   return UncheckedCast<HeapObject>(raw_assembler()->OptimizedAllocate(
959       size, allocation, allow_large_objects));
960 }
961 
HandleException(Node * node)962 void CodeAssembler::HandleException(Node* node) {
963   if (state_->exception_handler_labels_.size() == 0) return;
964   CodeAssemblerExceptionHandlerLabel* label =
965       state_->exception_handler_labels_.back();
966 
967   if (node->op()->HasProperty(Operator::kNoThrow)) {
968     return;
969   }
970 
971   Label success(this), exception(this, Label::kDeferred);
972   success.MergeVariables();
973   exception.MergeVariables();
974 
975   raw_assembler()->Continuations(node, success.label_, exception.label_);
976 
977   Bind(&exception);
978   const Operator* op = raw_assembler()->common()->IfException();
979   Node* exception_value = raw_assembler()->AddNode(op, node, node);
980   label->AddInputs({UncheckedCast<Object>(exception_value)});
981   Goto(label->plain_label());
982 
983   Bind(&success);
984   raw_assembler()->AddNode(raw_assembler()->common()->IfSuccess(), node);
985 }
986 
987 namespace {
988 template <size_t kMaxSize>
989 class NodeArray {
990  public:
Add(Node * node)991   void Add(Node* node) {
992     DCHECK_GT(kMaxSize, size());
993     *ptr_++ = node;
994   }
995 
data() const996   Node* const* data() const { return arr_; }
size() const997   int size() const { return static_cast<int>(ptr_ - arr_); }
998 
999  private:
1000   Node* arr_[kMaxSize];
1001   Node** ptr_ = arr_;
1002 };
1003 }  // namespace
1004 
CallRuntimeImpl(Runtime::FunctionId function,TNode<Object> context,std::initializer_list<TNode<Object>> args)1005 Node* CodeAssembler::CallRuntimeImpl(
1006     Runtime::FunctionId function, TNode<Object> context,
1007     std::initializer_list<TNode<Object>> args) {
1008   int result_size = Runtime::FunctionForId(function)->result_size;
1009   TNode<Code> centry =
1010       HeapConstant(CodeFactory::RuntimeCEntry(isolate(), result_size));
1011   constexpr size_t kMaxNumArgs = 6;
1012   DCHECK_GE(kMaxNumArgs, args.size());
1013   int argc = static_cast<int>(args.size());
1014   auto call_descriptor = Linkage::GetRuntimeCallDescriptor(
1015       zone(), function, argc, Operator::kNoProperties,
1016       Runtime::MayAllocate(function) ? CallDescriptor::kNoFlags
1017                                      : CallDescriptor::kNoAllocate);
1018 
1019   TNode<ExternalReference> ref =
1020       ExternalConstant(ExternalReference::Create(function));
1021   TNode<Int32T> arity = Int32Constant(argc);
1022 
1023   NodeArray<kMaxNumArgs + 4> inputs;
1024   inputs.Add(centry);
1025   for (auto arg : args) inputs.Add(arg);
1026   inputs.Add(ref);
1027   inputs.Add(arity);
1028   inputs.Add(context);
1029 
1030   CallPrologue();
1031   Node* return_value =
1032       raw_assembler()->CallN(call_descriptor, inputs.size(), inputs.data());
1033   HandleException(return_value);
1034   CallEpilogue();
1035   return return_value;
1036 }
1037 
TailCallRuntimeImpl(Runtime::FunctionId function,TNode<Int32T> arity,TNode<Object> context,std::initializer_list<TNode<Object>> args)1038 void CodeAssembler::TailCallRuntimeImpl(
1039     Runtime::FunctionId function, TNode<Int32T> arity, TNode<Object> context,
1040     std::initializer_list<TNode<Object>> args) {
1041   int result_size = Runtime::FunctionForId(function)->result_size;
1042   TNode<Code> centry =
1043       HeapConstant(CodeFactory::RuntimeCEntry(isolate(), result_size));
1044   constexpr size_t kMaxNumArgs = 6;
1045   DCHECK_GE(kMaxNumArgs, args.size());
1046   int argc = static_cast<int>(args.size());
1047   auto call_descriptor = Linkage::GetRuntimeCallDescriptor(
1048       zone(), function, argc, Operator::kNoProperties,
1049       CallDescriptor::kNoFlags);
1050 
1051   TNode<ExternalReference> ref =
1052       ExternalConstant(ExternalReference::Create(function));
1053 
1054   NodeArray<kMaxNumArgs + 4> inputs;
1055   inputs.Add(centry);
1056   for (auto arg : args) inputs.Add(arg);
1057   inputs.Add(ref);
1058   inputs.Add(arity);
1059   inputs.Add(context);
1060 
1061   raw_assembler()->TailCallN(call_descriptor, inputs.size(), inputs.data());
1062 }
1063 
CallStubN(StubCallMode call_mode,const CallInterfaceDescriptor & descriptor,int input_count,Node * const * inputs)1064 Node* CodeAssembler::CallStubN(StubCallMode call_mode,
1065                                const CallInterfaceDescriptor& descriptor,
1066                                int input_count, Node* const* inputs) {
1067   DCHECK(call_mode == StubCallMode::kCallCodeObject ||
1068          call_mode == StubCallMode::kCallBuiltinPointer);
1069 
1070   // implicit nodes are target and optionally context.
1071   int implicit_nodes = descriptor.HasContextParameter() ? 2 : 1;
1072   DCHECK_LE(implicit_nodes, input_count);
1073   int argc = input_count - implicit_nodes;
1074 #ifdef DEBUG
1075   if (descriptor.AllowVarArgs()) {
1076     DCHECK_LE(descriptor.GetParameterCount(), argc);
1077   } else {
1078     DCHECK_EQ(descriptor.GetParameterCount(), argc);
1079   }
1080 #endif
1081   // Extra arguments not mentioned in the descriptor are passed on the stack.
1082   int stack_parameter_count = argc - descriptor.GetRegisterParameterCount();
1083   DCHECK_LE(descriptor.GetStackParameterCount(), stack_parameter_count);
1084 
1085   auto call_descriptor = Linkage::GetStubCallDescriptor(
1086       zone(), descriptor, stack_parameter_count, CallDescriptor::kNoFlags,
1087       Operator::kNoProperties, call_mode);
1088 
1089   CallPrologue();
1090   Node* return_value =
1091       raw_assembler()->CallN(call_descriptor, input_count, inputs);
1092   HandleException(return_value);
1093   CallEpilogue();
1094   return return_value;
1095 }
1096 
TailCallStubImpl(const CallInterfaceDescriptor & descriptor,TNode<Code> target,TNode<Object> context,std::initializer_list<Node * > args)1097 void CodeAssembler::TailCallStubImpl(const CallInterfaceDescriptor& descriptor,
1098                                      TNode<Code> target, TNode<Object> context,
1099                                      std::initializer_list<Node*> args) {
1100   constexpr size_t kMaxNumArgs = 11;
1101   DCHECK_GE(kMaxNumArgs, args.size());
1102   DCHECK_EQ(descriptor.GetParameterCount(), args.size());
1103   auto call_descriptor = Linkage::GetStubCallDescriptor(
1104       zone(), descriptor, descriptor.GetStackParameterCount(),
1105       CallDescriptor::kNoFlags, Operator::kNoProperties);
1106 
1107   NodeArray<kMaxNumArgs + 2> inputs;
1108   inputs.Add(target);
1109   for (auto arg : args) inputs.Add(arg);
1110   if (descriptor.HasContextParameter()) {
1111     inputs.Add(context);
1112   }
1113 
1114   raw_assembler()->TailCallN(call_descriptor, inputs.size(), inputs.data());
1115 }
1116 
CallStubRImpl(StubCallMode call_mode,const CallInterfaceDescriptor & descriptor,TNode<Object> target,TNode<Object> context,std::initializer_list<Node * > args)1117 Node* CodeAssembler::CallStubRImpl(StubCallMode call_mode,
1118                                    const CallInterfaceDescriptor& descriptor,
1119                                    TNode<Object> target, TNode<Object> context,
1120                                    std::initializer_list<Node*> args) {
1121   DCHECK(call_mode == StubCallMode::kCallCodeObject ||
1122          call_mode == StubCallMode::kCallBuiltinPointer);
1123 
1124   constexpr size_t kMaxNumArgs = 10;
1125   DCHECK_GE(kMaxNumArgs, args.size());
1126 
1127   NodeArray<kMaxNumArgs + 2> inputs;
1128   inputs.Add(target);
1129   for (auto arg : args) inputs.Add(arg);
1130   if (descriptor.HasContextParameter()) {
1131     inputs.Add(context);
1132   }
1133 
1134   return CallStubN(call_mode, descriptor, inputs.size(), inputs.data());
1135 }
1136 
CallJSStubImpl(const CallInterfaceDescriptor & descriptor,TNode<Object> target,TNode<Object> context,TNode<Object> function,base::Optional<TNode<Object>> new_target,TNode<Int32T> arity,std::initializer_list<Node * > args)1137 Node* CodeAssembler::CallJSStubImpl(const CallInterfaceDescriptor& descriptor,
1138                                     TNode<Object> target, TNode<Object> context,
1139                                     TNode<Object> function,
1140                                     base::Optional<TNode<Object>> new_target,
1141                                     TNode<Int32T> arity,
1142                                     std::initializer_list<Node*> args) {
1143   constexpr size_t kMaxNumArgs = 10;
1144   DCHECK_GE(kMaxNumArgs, args.size());
1145   NodeArray<kMaxNumArgs + 5> inputs;
1146   inputs.Add(target);
1147   inputs.Add(function);
1148   if (new_target) {
1149     inputs.Add(*new_target);
1150   }
1151   inputs.Add(arity);
1152   for (auto arg : args) inputs.Add(arg);
1153   if (descriptor.HasContextParameter()) {
1154     inputs.Add(context);
1155   }
1156   return CallStubN(StubCallMode::kCallCodeObject, descriptor, inputs.size(),
1157                    inputs.data());
1158 }
1159 
TailCallStubThenBytecodeDispatchImpl(const CallInterfaceDescriptor & descriptor,Node * target,Node * context,std::initializer_list<Node * > args)1160 void CodeAssembler::TailCallStubThenBytecodeDispatchImpl(
1161     const CallInterfaceDescriptor& descriptor, Node* target, Node* context,
1162     std::initializer_list<Node*> args) {
1163   constexpr size_t kMaxNumArgs = 6;
1164   DCHECK_GE(kMaxNumArgs, args.size());
1165 
1166   DCHECK_LE(descriptor.GetParameterCount(), args.size());
1167   int argc = static_cast<int>(args.size());
1168   // Extra arguments not mentioned in the descriptor are passed on the stack.
1169   int stack_parameter_count = argc - descriptor.GetRegisterParameterCount();
1170   DCHECK_LE(descriptor.GetStackParameterCount(), stack_parameter_count);
1171   auto call_descriptor = Linkage::GetStubCallDescriptor(
1172       zone(), descriptor, stack_parameter_count, CallDescriptor::kNoFlags,
1173       Operator::kNoProperties);
1174 
1175   NodeArray<kMaxNumArgs + 2> inputs;
1176   inputs.Add(target);
1177   for (auto arg : args) inputs.Add(arg);
1178   inputs.Add(context);
1179 
1180   raw_assembler()->TailCallN(call_descriptor, inputs.size(), inputs.data());
1181 }
1182 
1183 template <class... TArgs>
TailCallBytecodeDispatch(const CallInterfaceDescriptor & descriptor,TNode<RawPtrT> target,TArgs...args)1184 void CodeAssembler::TailCallBytecodeDispatch(
1185     const CallInterfaceDescriptor& descriptor, TNode<RawPtrT> target,
1186     TArgs... args) {
1187   DCHECK_EQ(descriptor.GetParameterCount(), sizeof...(args));
1188   auto call_descriptor = Linkage::GetBytecodeDispatchCallDescriptor(
1189       zone(), descriptor, descriptor.GetStackParameterCount());
1190 
1191   Node* nodes[] = {target, args...};
1192   CHECK_EQ(descriptor.GetParameterCount() + 1, arraysize(nodes));
1193   raw_assembler()->TailCallN(call_descriptor, arraysize(nodes), nodes);
1194 }
1195 
1196 // Instantiate TailCallBytecodeDispatch() for argument counts used by
1197 // CSA-generated code
1198 template V8_EXPORT_PRIVATE void CodeAssembler::TailCallBytecodeDispatch(
1199     const CallInterfaceDescriptor& descriptor, TNode<RawPtrT> target,
1200     TNode<Object>, TNode<IntPtrT>, TNode<BytecodeArray>,
1201     TNode<ExternalReference>);
1202 
TailCallJSCode(TNode<Code> code,TNode<Context> context,TNode<JSFunction> function,TNode<Object> new_target,TNode<Int32T> arg_count)1203 void CodeAssembler::TailCallJSCode(TNode<Code> code, TNode<Context> context,
1204                                    TNode<JSFunction> function,
1205                                    TNode<Object> new_target,
1206                                    TNode<Int32T> arg_count) {
1207   JSTrampolineDescriptor descriptor;
1208   auto call_descriptor = Linkage::GetStubCallDescriptor(
1209       zone(), descriptor, descriptor.GetStackParameterCount(),
1210       CallDescriptor::kFixedTargetRegister, Operator::kNoProperties);
1211 
1212   Node* nodes[] = {code, function, new_target, arg_count, context};
1213   CHECK_EQ(descriptor.GetParameterCount() + 2, arraysize(nodes));
1214   raw_assembler()->TailCallN(call_descriptor, arraysize(nodes), nodes);
1215 }
1216 
CallCFunctionN(Signature<MachineType> * signature,int input_count,Node * const * inputs)1217 Node* CodeAssembler::CallCFunctionN(Signature<MachineType>* signature,
1218                                     int input_count, Node* const* inputs) {
1219   auto call_descriptor = Linkage::GetSimplifiedCDescriptor(zone(), signature);
1220   return raw_assembler()->CallN(call_descriptor, input_count, inputs);
1221 }
1222 
CallCFunction(Node * function,base::Optional<MachineType> return_type,std::initializer_list<CodeAssembler::CFunctionArg> args)1223 Node* CodeAssembler::CallCFunction(
1224     Node* function, base::Optional<MachineType> return_type,
1225     std::initializer_list<CodeAssembler::CFunctionArg> args) {
1226   return raw_assembler()->CallCFunction(function, return_type, args);
1227 }
1228 
CallCFunctionWithoutFunctionDescriptor(Node * function,MachineType return_type,std::initializer_list<CodeAssembler::CFunctionArg> args)1229 Node* CodeAssembler::CallCFunctionWithoutFunctionDescriptor(
1230     Node* function, MachineType return_type,
1231     std::initializer_list<CodeAssembler::CFunctionArg> args) {
1232   return raw_assembler()->CallCFunctionWithoutFunctionDescriptor(
1233       function, return_type, args);
1234 }
1235 
CallCFunctionWithCallerSavedRegisters(Node * function,MachineType return_type,SaveFPRegsMode mode,std::initializer_list<CodeAssembler::CFunctionArg> args)1236 Node* CodeAssembler::CallCFunctionWithCallerSavedRegisters(
1237     Node* function, MachineType return_type, SaveFPRegsMode mode,
1238     std::initializer_list<CodeAssembler::CFunctionArg> args) {
1239   DCHECK(return_type.LessThanOrEqualPointerSize());
1240   return raw_assembler()->CallCFunctionWithCallerSavedRegisters(
1241       function, return_type, mode, args);
1242 }
1243 
Goto(Label * label)1244 void CodeAssembler::Goto(Label* label) {
1245   label->MergeVariables();
1246   raw_assembler()->Goto(label->label_);
1247 }
1248 
GotoIf(TNode<IntegralT> condition,Label * true_label)1249 void CodeAssembler::GotoIf(TNode<IntegralT> condition, Label* true_label) {
1250   Label false_label(this);
1251   Branch(condition, true_label, &false_label);
1252   Bind(&false_label);
1253 }
1254 
GotoIfNot(TNode<IntegralT> condition,Label * false_label)1255 void CodeAssembler::GotoIfNot(TNode<IntegralT> condition, Label* false_label) {
1256   Label true_label(this);
1257   Branch(condition, &true_label, false_label);
1258   Bind(&true_label);
1259 }
1260 
Branch(TNode<IntegralT> condition,Label * true_label,Label * false_label)1261 void CodeAssembler::Branch(TNode<IntegralT> condition, Label* true_label,
1262                            Label* false_label) {
1263   int32_t constant;
1264   if (TryToInt32Constant(condition, &constant)) {
1265     if ((true_label->is_used() || true_label->is_bound()) &&
1266         (false_label->is_used() || false_label->is_bound())) {
1267       return Goto(constant ? true_label : false_label);
1268     }
1269   }
1270   true_label->MergeVariables();
1271   false_label->MergeVariables();
1272   return raw_assembler()->Branch(condition, true_label->label_,
1273                                  false_label->label_);
1274 }
1275 
Branch(TNode<BoolT> condition,const std::function<void ()> & true_body,const std::function<void ()> & false_body)1276 void CodeAssembler::Branch(TNode<BoolT> condition,
1277                            const std::function<void()>& true_body,
1278                            const std::function<void()>& false_body) {
1279   int32_t constant;
1280   if (TryToInt32Constant(condition, &constant)) {
1281     return constant ? true_body() : false_body();
1282   }
1283 
1284   Label vtrue(this), vfalse(this);
1285   Branch(condition, &vtrue, &vfalse);
1286 
1287   Bind(&vtrue);
1288   true_body();
1289 
1290   Bind(&vfalse);
1291   false_body();
1292 }
1293 
Branch(TNode<BoolT> condition,Label * true_label,const std::function<void ()> & false_body)1294 void CodeAssembler::Branch(TNode<BoolT> condition, Label* true_label,
1295                            const std::function<void()>& false_body) {
1296   int32_t constant;
1297   if (TryToInt32Constant(condition, &constant)) {
1298     return constant ? Goto(true_label) : false_body();
1299   }
1300 
1301   Label vfalse(this);
1302   Branch(condition, true_label, &vfalse);
1303   Bind(&vfalse);
1304   false_body();
1305 }
1306 
Branch(TNode<BoolT> condition,const std::function<void ()> & true_body,Label * false_label)1307 void CodeAssembler::Branch(TNode<BoolT> condition,
1308                            const std::function<void()>& true_body,
1309                            Label* false_label) {
1310   int32_t constant;
1311   if (TryToInt32Constant(condition, &constant)) {
1312     return constant ? true_body() : Goto(false_label);
1313   }
1314 
1315   Label vtrue(this);
1316   Branch(condition, &vtrue, false_label);
1317   Bind(&vtrue);
1318   true_body();
1319 }
1320 
Switch(Node * index,Label * default_label,const int32_t * case_values,Label ** case_labels,size_t case_count)1321 void CodeAssembler::Switch(Node* index, Label* default_label,
1322                            const int32_t* case_values, Label** case_labels,
1323                            size_t case_count) {
1324   RawMachineLabel** labels = zone()->NewArray<RawMachineLabel*>(case_count);
1325   for (size_t i = 0; i < case_count; ++i) {
1326     labels[i] = case_labels[i]->label_;
1327     case_labels[i]->MergeVariables();
1328   }
1329   default_label->MergeVariables();
1330   return raw_assembler()->Switch(index, default_label->label_, case_values,
1331                                  labels, case_count);
1332 }
1333 
UnalignedLoadSupported(MachineRepresentation rep) const1334 bool CodeAssembler::UnalignedLoadSupported(MachineRepresentation rep) const {
1335   return raw_assembler()->machine()->UnalignedLoadSupported(rep);
1336 }
UnalignedStoreSupported(MachineRepresentation rep) const1337 bool CodeAssembler::UnalignedStoreSupported(MachineRepresentation rep) const {
1338   return raw_assembler()->machine()->UnalignedStoreSupported(rep);
1339 }
1340 
1341 // RawMachineAssembler delegate helpers:
isolate() const1342 Isolate* CodeAssembler::isolate() const { return raw_assembler()->isolate(); }
1343 
factory() const1344 Factory* CodeAssembler::factory() const { return isolate()->factory(); }
1345 
zone() const1346 Zone* CodeAssembler::zone() const { return raw_assembler()->zone(); }
1347 
IsExceptionHandlerActive() const1348 bool CodeAssembler::IsExceptionHandlerActive() const {
1349   return state_->exception_handler_labels_.size() != 0;
1350 }
1351 
raw_assembler() const1352 RawMachineAssembler* CodeAssembler::raw_assembler() const {
1353   return state_->raw_assembler_.get();
1354 }
1355 
jsgraph() const1356 JSGraph* CodeAssembler::jsgraph() const { return state_->jsgraph_; }
1357 
1358 // The core implementation of Variable is stored through an indirection so
1359 // that it can outlive the often block-scoped Variable declarations. This is
1360 // needed to ensure that variable binding and merging through phis can
1361 // properly be verified.
1362 class CodeAssemblerVariable::Impl : public ZoneObject {
1363  public:
Impl(MachineRepresentation rep,CodeAssemblerState::VariableId id)1364   explicit Impl(MachineRepresentation rep, CodeAssemblerState::VariableId id)
1365       :
1366 #if DEBUG
1367         debug_info_(AssemblerDebugInfo(nullptr, nullptr, -1)),
1368 #endif
1369         value_(nullptr),
1370         rep_(rep),
1371         var_id_(id) {
1372   }
1373 
1374 #if DEBUG
debug_info() const1375   AssemblerDebugInfo debug_info() const { return debug_info_; }
set_debug_info(AssemblerDebugInfo debug_info)1376   void set_debug_info(AssemblerDebugInfo debug_info) {
1377     debug_info_ = debug_info;
1378   }
1379 
1380   AssemblerDebugInfo debug_info_;
1381 #endif  // DEBUG
operator <(const CodeAssemblerVariable::Impl & other) const1382   bool operator<(const CodeAssemblerVariable::Impl& other) const {
1383     return var_id_ < other.var_id_;
1384   }
1385   Node* value_;
1386   MachineRepresentation rep_;
1387   CodeAssemblerState::VariableId var_id_;
1388 };
1389 
operator ()(const CodeAssemblerVariable::Impl * a,const CodeAssemblerVariable::Impl * b) const1390 bool CodeAssemblerVariable::ImplComparator::operator()(
1391     const CodeAssemblerVariable::Impl* a,
1392     const CodeAssemblerVariable::Impl* b) const {
1393   return *a < *b;
1394 }
1395 
CodeAssemblerVariable(CodeAssembler * assembler,MachineRepresentation rep)1396 CodeAssemblerVariable::CodeAssemblerVariable(CodeAssembler* assembler,
1397                                              MachineRepresentation rep)
1398     : impl_(assembler->zone()->New<Impl>(rep,
1399                                          assembler->state()->NextVariableId())),
1400       state_(assembler->state()) {
1401   state_->variables_.insert(impl_);
1402 }
1403 
CodeAssemblerVariable(CodeAssembler * assembler,MachineRepresentation rep,Node * initial_value)1404 CodeAssemblerVariable::CodeAssemblerVariable(CodeAssembler* assembler,
1405                                              MachineRepresentation rep,
1406                                              Node* initial_value)
1407     : CodeAssemblerVariable(assembler, rep) {
1408   Bind(initial_value);
1409 }
1410 
1411 #if DEBUG
CodeAssemblerVariable(CodeAssembler * assembler,AssemblerDebugInfo debug_info,MachineRepresentation rep)1412 CodeAssemblerVariable::CodeAssemblerVariable(CodeAssembler* assembler,
1413                                              AssemblerDebugInfo debug_info,
1414                                              MachineRepresentation rep)
1415     : impl_(assembler->zone()->New<Impl>(rep,
1416                                          assembler->state()->NextVariableId())),
1417       state_(assembler->state()) {
1418   impl_->set_debug_info(debug_info);
1419   state_->variables_.insert(impl_);
1420 }
1421 
CodeAssemblerVariable(CodeAssembler * assembler,AssemblerDebugInfo debug_info,MachineRepresentation rep,Node * initial_value)1422 CodeAssemblerVariable::CodeAssemblerVariable(CodeAssembler* assembler,
1423                                              AssemblerDebugInfo debug_info,
1424                                              MachineRepresentation rep,
1425                                              Node* initial_value)
1426     : CodeAssemblerVariable(assembler, debug_info, rep) {
1427   impl_->set_debug_info(debug_info);
1428   Bind(initial_value);
1429 }
1430 #endif  // DEBUG
1431 
~CodeAssemblerVariable()1432 CodeAssemblerVariable::~CodeAssemblerVariable() {
1433   state_->variables_.erase(impl_);
1434 }
1435 
Bind(Node * value)1436 void CodeAssemblerVariable::Bind(Node* value) { impl_->value_ = value; }
1437 
value() const1438 Node* CodeAssemblerVariable::value() const {
1439 #if DEBUG
1440   if (!IsBound()) {
1441     std::stringstream str;
1442     str << "#Use of unbound variable:"
1443         << "#\n    Variable:      " << *this << "#\n    Current Block: ";
1444     state_->PrintCurrentBlock(str);
1445     FATAL("%s", str.str().c_str());
1446   }
1447   if (!state_->InsideBlock()) {
1448     std::stringstream str;
1449     str << "#Accessing variable value outside a block:"
1450         << "#\n    Variable:      " << *this;
1451     FATAL("%s", str.str().c_str());
1452   }
1453 #endif  // DEBUG
1454   return impl_->value_;
1455 }
1456 
rep() const1457 MachineRepresentation CodeAssemblerVariable::rep() const { return impl_->rep_; }
1458 
IsBound() const1459 bool CodeAssemblerVariable::IsBound() const { return impl_->value_ != nullptr; }
1460 
operator <<(std::ostream & os,const CodeAssemblerVariable::Impl & impl)1461 std::ostream& operator<<(std::ostream& os,
1462                          const CodeAssemblerVariable::Impl& impl) {
1463 #if DEBUG
1464   AssemblerDebugInfo info = impl.debug_info();
1465   if (info.name) os << "V" << info;
1466 #endif  // DEBUG
1467   return os;
1468 }
1469 
operator <<(std::ostream & os,const CodeAssemblerVariable & variable)1470 std::ostream& operator<<(std::ostream& os,
1471                          const CodeAssemblerVariable& variable) {
1472   os << *variable.impl_;
1473   return os;
1474 }
1475 
CodeAssemblerLabel(CodeAssembler * assembler,size_t vars_count,CodeAssemblerVariable * const * vars,CodeAssemblerLabel::Type type)1476 CodeAssemblerLabel::CodeAssemblerLabel(CodeAssembler* assembler,
1477                                        size_t vars_count,
1478                                        CodeAssemblerVariable* const* vars,
1479                                        CodeAssemblerLabel::Type type)
1480     : bound_(false),
1481       merge_count_(0),
1482       state_(assembler->state()),
1483       label_(nullptr) {
1484   label_ = assembler->zone()->New<RawMachineLabel>(
1485       type == kDeferred ? RawMachineLabel::kDeferred
1486                         : RawMachineLabel::kNonDeferred);
1487   for (size_t i = 0; i < vars_count; ++i) {
1488     variable_phis_[vars[i]->impl_] = nullptr;
1489   }
1490 }
1491 
~CodeAssemblerLabel()1492 CodeAssemblerLabel::~CodeAssemblerLabel() { label_->~RawMachineLabel(); }
1493 
MergeVariables()1494 void CodeAssemblerLabel::MergeVariables() {
1495   ++merge_count_;
1496   for (CodeAssemblerVariable::Impl* var : state_->variables_) {
1497     size_t count = 0;
1498     Node* node = var->value_;
1499     if (node != nullptr) {
1500       auto i = variable_merges_.find(var);
1501       if (i != variable_merges_.end()) {
1502         i->second.push_back(node);
1503         count = i->second.size();
1504       } else {
1505         count = 1;
1506         variable_merges_[var] = std::vector<Node*>(1, node);
1507       }
1508     }
1509     // If the following asserts, then you've jumped to a label without a bound
1510     // variable along that path that expects to merge its value into a phi.
1511     // This can also occur if a label is bound that is never jumped to.
1512     DCHECK(variable_phis_.find(var) == variable_phis_.end() ||
1513            count == merge_count_);
1514     USE(count);
1515 
1516     // If the label is already bound, we already know the set of variables to
1517     // merge and phi nodes have already been created.
1518     if (bound_) {
1519       auto phi = variable_phis_.find(var);
1520       if (phi != variable_phis_.end()) {
1521         DCHECK_NOT_NULL(phi->second);
1522         state_->raw_assembler_->AppendPhiInput(phi->second, node);
1523       } else {
1524         auto i = variable_merges_.find(var);
1525         if (i != variable_merges_.end()) {
1526           // If the following assert fires, then you've declared a variable that
1527           // has the same bound value along all paths up until the point you
1528           // bound this label, but then later merged a path with a new value for
1529           // the variable after the label bind (it's not possible to add phis to
1530           // the bound label after the fact, just make sure to list the variable
1531           // in the label's constructor's list of merged variables).
1532 #if DEBUG
1533           if (find_if(i->second.begin(), i->second.end(),
1534                       [node](Node* e) -> bool { return node != e; }) !=
1535               i->second.end()) {
1536             std::stringstream str;
1537             str << "Unmerged variable found when jumping to block. \n"
1538                 << "#    Variable:      " << *var;
1539             if (bound_) {
1540               str << "\n#    Target block:  " << *label_->block();
1541             }
1542             str << "\n#    Current Block: ";
1543             state_->PrintCurrentBlock(str);
1544             FATAL("%s", str.str().c_str());
1545           }
1546 #endif  // DEBUG
1547         }
1548       }
1549     }
1550   }
1551 }
1552 
1553 #if DEBUG
Bind(AssemblerDebugInfo debug_info)1554 void CodeAssemblerLabel::Bind(AssemblerDebugInfo debug_info) {
1555   if (bound_) {
1556     std::stringstream str;
1557     str << "Cannot bind the same label twice:"
1558         << "\n#    current:  " << debug_info
1559         << "\n#    previous: " << *label_->block();
1560     FATAL("%s", str.str().c_str());
1561   }
1562   if (FLAG_enable_source_at_csa_bind) {
1563     state_->raw_assembler_->SetCurrentExternalSourcePosition(
1564         {debug_info.file, debug_info.line});
1565   }
1566   state_->raw_assembler_->Bind(label_, debug_info);
1567   UpdateVariablesAfterBind();
1568 }
1569 #endif  // DEBUG
1570 
Bind()1571 void CodeAssemblerLabel::Bind() {
1572   DCHECK(!bound_);
1573   state_->raw_assembler_->Bind(label_);
1574   UpdateVariablesAfterBind();
1575 }
1576 
UpdateVariablesAfterBind()1577 void CodeAssemblerLabel::UpdateVariablesAfterBind() {
1578   // Make sure that all variables that have changed along any path up to this
1579   // point are marked as merge variables.
1580   for (auto var : state_->variables_) {
1581     Node* shared_value = nullptr;
1582     auto i = variable_merges_.find(var);
1583     if (i != variable_merges_.end()) {
1584       for (auto value : i->second) {
1585         DCHECK_NOT_NULL(value);
1586         if (value != shared_value) {
1587           if (shared_value == nullptr) {
1588             shared_value = value;
1589           } else {
1590             variable_phis_[var] = nullptr;
1591           }
1592         }
1593       }
1594     }
1595   }
1596 
1597   for (auto var : variable_phis_) {
1598     CodeAssemblerVariable::Impl* var_impl = var.first;
1599     auto i = variable_merges_.find(var_impl);
1600 #if DEBUG
1601     bool not_found = i == variable_merges_.end();
1602     if (not_found || i->second.size() != merge_count_) {
1603       std::stringstream str;
1604       str << "A variable that has been marked as beeing merged at the label"
1605           << "\n# doesn't have a bound value along all of the paths that "
1606           << "\n# have been merged into the label up to this point."
1607           << "\n#"
1608           << "\n# This can happen in the following cases:"
1609           << "\n# - By explicitly marking it so in the label constructor"
1610           << "\n# - By having seen different bound values at branches"
1611           << "\n#"
1612           << "\n# Merge count:     expected=" << merge_count_
1613           << " vs. found=" << (not_found ? 0 : i->second.size())
1614           << "\n# Variable:      " << *var_impl
1615           << "\n# Current Block: " << *label_->block();
1616       FATAL("%s", str.str().c_str());
1617     }
1618 #endif  // DEBUG
1619     Node* phi = state_->raw_assembler_->Phi(
1620         var.first->rep_, static_cast<int>(merge_count_), &(i->second[0]));
1621     variable_phis_[var_impl] = phi;
1622   }
1623 
1624   // Bind all variables to a merge phi, the common value along all paths or
1625   // null.
1626   for (auto var : state_->variables_) {
1627     auto i = variable_phis_.find(var);
1628     if (i != variable_phis_.end()) {
1629       var->value_ = i->second;
1630     } else {
1631       auto j = variable_merges_.find(var);
1632       if (j != variable_merges_.end() && j->second.size() == merge_count_) {
1633         var->value_ = j->second.back();
1634       } else {
1635         var->value_ = nullptr;
1636       }
1637     }
1638   }
1639 
1640   bound_ = true;
1641 }
1642 
AddInputs(std::vector<Node * > inputs)1643 void CodeAssemblerParameterizedLabelBase::AddInputs(std::vector<Node*> inputs) {
1644   if (!phi_nodes_.empty()) {
1645     DCHECK_EQ(inputs.size(), phi_nodes_.size());
1646     for (size_t i = 0; i < inputs.size(); ++i) {
1647       // We use {nullptr} as a sentinel for an uninitialized value.
1648       if (phi_nodes_[i] == nullptr) continue;
1649       state_->raw_assembler_->AppendPhiInput(phi_nodes_[i], inputs[i]);
1650     }
1651   } else {
1652     DCHECK_EQ(inputs.size(), phi_inputs_.size());
1653     for (size_t i = 0; i < inputs.size(); ++i) {
1654       phi_inputs_[i].push_back(inputs[i]);
1655     }
1656   }
1657 }
1658 
CreatePhi(MachineRepresentation rep,const std::vector<Node * > & inputs)1659 Node* CodeAssemblerParameterizedLabelBase::CreatePhi(
1660     MachineRepresentation rep, const std::vector<Node*>& inputs) {
1661   for (Node* input : inputs) {
1662     // We use {nullptr} as a sentinel for an uninitialized value. We must not
1663     // create phi nodes for these.
1664     if (input == nullptr) return nullptr;
1665   }
1666   return state_->raw_assembler_->Phi(rep, static_cast<int>(inputs.size()),
1667                                      &inputs.front());
1668 }
1669 
CreatePhis(std::vector<MachineRepresentation> representations)1670 const std::vector<Node*>& CodeAssemblerParameterizedLabelBase::CreatePhis(
1671     std::vector<MachineRepresentation> representations) {
1672   DCHECK(is_used());
1673   DCHECK(phi_nodes_.empty());
1674   phi_nodes_.reserve(phi_inputs_.size());
1675   DCHECK_EQ(representations.size(), phi_inputs_.size());
1676   for (size_t i = 0; i < phi_inputs_.size(); ++i) {
1677     phi_nodes_.push_back(CreatePhi(representations[i], phi_inputs_[i]));
1678   }
1679   return phi_nodes_;
1680 }
1681 
PushExceptionHandler(CodeAssemblerExceptionHandlerLabel * label)1682 void CodeAssemblerState::PushExceptionHandler(
1683     CodeAssemblerExceptionHandlerLabel* label) {
1684   exception_handler_labels_.push_back(label);
1685 }
1686 
PopExceptionHandler()1687 void CodeAssemblerState::PopExceptionHandler() {
1688   exception_handler_labels_.pop_back();
1689 }
1690 
ScopedExceptionHandler(CodeAssembler * assembler,CodeAssemblerExceptionHandlerLabel * label)1691 ScopedExceptionHandler::ScopedExceptionHandler(
1692     CodeAssembler* assembler, CodeAssemblerExceptionHandlerLabel* label)
1693     : has_handler_(label != nullptr),
1694       assembler_(assembler),
1695       compatibility_label_(nullptr),
1696       exception_(nullptr) {
1697   if (has_handler_) {
1698     assembler_->state()->PushExceptionHandler(label);
1699   }
1700 }
1701 
ScopedExceptionHandler(CodeAssembler * assembler,CodeAssemblerLabel * label,TypedCodeAssemblerVariable<Object> * exception)1702 ScopedExceptionHandler::ScopedExceptionHandler(
1703     CodeAssembler* assembler, CodeAssemblerLabel* label,
1704     TypedCodeAssemblerVariable<Object>* exception)
1705     : has_handler_(label != nullptr),
1706       assembler_(assembler),
1707       compatibility_label_(label),
1708       exception_(exception) {
1709   if (has_handler_) {
1710     label_ = std::make_unique<CodeAssemblerExceptionHandlerLabel>(
1711         assembler, CodeAssemblerLabel::kDeferred);
1712     assembler_->state()->PushExceptionHandler(label_.get());
1713   }
1714 }
1715 
~ScopedExceptionHandler()1716 ScopedExceptionHandler::~ScopedExceptionHandler() {
1717   if (has_handler_) {
1718     assembler_->state()->PopExceptionHandler();
1719   }
1720   if (label_ && label_->is_used()) {
1721     CodeAssembler::Label skip(assembler_);
1722     bool inside_block = assembler_->state()->InsideBlock();
1723     if (inside_block) {
1724       assembler_->Goto(&skip);
1725     }
1726     TNode<Object> e;
1727     assembler_->Bind(label_.get(), &e);
1728     if (exception_ != nullptr) *exception_ = e;
1729     assembler_->Goto(compatibility_label_);
1730     if (inside_block) {
1731       assembler_->Bind(&skip);
1732     }
1733   }
1734 }
1735 
1736 }  // namespace compiler
1737 
1738 }  // namespace internal
1739 }  // namespace v8
1740