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