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