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