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