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