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