1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/compiler/code-assembler.h"
6
7 #include <ostream>
8
9 #include "src/code-factory.h"
10 #include "src/compiler/graph.h"
11 #include "src/compiler/instruction-selector.h"
12 #include "src/compiler/linkage.h"
13 #include "src/compiler/node-matchers.h"
14 #include "src/compiler/pipeline.h"
15 #include "src/compiler/raw-machine-assembler.h"
16 #include "src/compiler/schedule.h"
17 #include "src/frames.h"
18 #include "src/interface-descriptors.h"
19 #include "src/interpreter/bytecodes.h"
20 #include "src/machine-type.h"
21 #include "src/macro-assembler.h"
22 #include "src/objects-inl.h"
23 #include "src/utils.h"
24 #include "src/zone/zone.h"
25
26 #define REPEAT_1_TO_2(V, T) V(T) V(T, T)
27 #define REPEAT_1_TO_3(V, T) REPEAT_1_TO_2(V, T) V(T, T, T)
28 #define REPEAT_1_TO_4(V, T) REPEAT_1_TO_3(V, T) V(T, T, T, T)
29 #define REPEAT_1_TO_5(V, T) REPEAT_1_TO_4(V, T) V(T, T, T, T, T)
30 #define REPEAT_1_TO_6(V, T) REPEAT_1_TO_5(V, T) V(T, T, T, T, T, T)
31 #define REPEAT_1_TO_7(V, T) REPEAT_1_TO_6(V, T) V(T, T, T, T, T, T, T)
32 #define REPEAT_1_TO_8(V, T) REPEAT_1_TO_7(V, T) V(T, T, T, T, T, T, T, T)
33 #define REPEAT_1_TO_9(V, T) REPEAT_1_TO_8(V, T) V(T, T, T, T, T, T, T, T, T)
34
35 namespace v8 {
36 namespace internal {
37 namespace compiler {
38
CodeAssemblerState(Isolate * isolate,Zone * zone,const CallInterfaceDescriptor & descriptor,Code::Flags flags,const char * name,size_t result_size)39 CodeAssemblerState::CodeAssemblerState(
40 Isolate* isolate, Zone* zone, const CallInterfaceDescriptor& descriptor,
41 Code::Flags flags, const char* name, size_t result_size)
42 : CodeAssemblerState(
43 isolate, zone,
44 Linkage::GetStubCallDescriptor(
45 isolate, zone, descriptor, descriptor.GetStackParameterCount(),
46 CallDescriptor::kNoFlags, Operator::kNoProperties,
47 MachineType::AnyTagged(), result_size),
48 flags, name) {}
49
CodeAssemblerState(Isolate * isolate,Zone * zone,int parameter_count,Code::Flags flags,const char * name)50 CodeAssemblerState::CodeAssemblerState(Isolate* isolate, Zone* zone,
51 int parameter_count, Code::Flags flags,
52 const char* name)
53 : CodeAssemblerState(isolate, zone,
54 Linkage::GetJSCallDescriptor(
55 zone, false, parameter_count,
56 Code::ExtractKindFromFlags(flags) == Code::BUILTIN
57 ? CallDescriptor::kPushArgumentCount
58 : CallDescriptor::kNoFlags),
59 flags, name) {}
60
CodeAssemblerState(Isolate * isolate,Zone * zone,CallDescriptor * call_descriptor,Code::Flags flags,const char * name)61 CodeAssemblerState::CodeAssemblerState(Isolate* isolate, Zone* zone,
62 CallDescriptor* call_descriptor,
63 Code::Flags flags, const char* name)
64 : raw_assembler_(new RawMachineAssembler(
65 isolate, new (zone) Graph(zone), call_descriptor,
66 MachineType::PointerRepresentation(),
67 InstructionSelector::SupportedMachineOperatorFlags(),
68 InstructionSelector::AlignmentRequirements())),
69 flags_(flags),
70 name_(name),
71 code_generated_(false),
72 variables_(zone) {}
73
~CodeAssemblerState()74 CodeAssemblerState::~CodeAssemblerState() {}
75
parameter_count() const76 int CodeAssemblerState::parameter_count() const {
77 return static_cast<int>(raw_assembler_->call_descriptor()->ParameterCount());
78 }
79
~CodeAssembler()80 CodeAssembler::~CodeAssembler() {}
81
82 class BreakOnNodeDecorator final : public GraphDecorator {
83 public:
BreakOnNodeDecorator(NodeId node_id)84 explicit BreakOnNodeDecorator(NodeId node_id) : node_id_(node_id) {}
85
Decorate(Node * node)86 void Decorate(Node* node) final {
87 if (node->id() == node_id_) {
88 base::OS::DebugBreak();
89 }
90 }
91
92 private:
93 NodeId node_id_;
94 };
95
BreakOnNode(int node_id)96 void CodeAssembler::BreakOnNode(int node_id) {
97 Graph* graph = raw_assembler()->graph();
98 Zone* zone = graph->zone();
99 GraphDecorator* decorator =
100 new (zone) BreakOnNodeDecorator(static_cast<NodeId>(node_id));
101 graph->AddDecorator(decorator);
102 }
103
RegisterCallGenerationCallbacks(const CodeAssemblerCallback & call_prologue,const CodeAssemblerCallback & call_epilogue)104 void CodeAssembler::RegisterCallGenerationCallbacks(
105 const CodeAssemblerCallback& call_prologue,
106 const CodeAssemblerCallback& call_epilogue) {
107 // The callback can be registered only once.
108 DCHECK(!state_->call_prologue_);
109 DCHECK(!state_->call_epilogue_);
110 state_->call_prologue_ = call_prologue;
111 state_->call_epilogue_ = call_epilogue;
112 }
113
UnregisterCallGenerationCallbacks()114 void CodeAssembler::UnregisterCallGenerationCallbacks() {
115 state_->call_prologue_ = nullptr;
116 state_->call_epilogue_ = nullptr;
117 }
118
CallPrologue()119 void CodeAssembler::CallPrologue() {
120 if (state_->call_prologue_) {
121 state_->call_prologue_();
122 }
123 }
124
CallEpilogue()125 void CodeAssembler::CallEpilogue() {
126 if (state_->call_epilogue_) {
127 state_->call_epilogue_();
128 }
129 }
130
131 // static
GenerateCode(CodeAssemblerState * state)132 Handle<Code> CodeAssembler::GenerateCode(CodeAssemblerState* state) {
133 DCHECK(!state->code_generated_);
134
135 RawMachineAssembler* rasm = state->raw_assembler_.get();
136 Schedule* schedule = rasm->Export();
137 Handle<Code> code = Pipeline::GenerateCodeForCodeStub(
138 rasm->isolate(), rasm->call_descriptor(), rasm->graph(), schedule,
139 state->flags_, state->name_);
140
141 state->code_generated_ = true;
142 return code;
143 }
144
Is64() const145 bool CodeAssembler::Is64() const { return raw_assembler()->machine()->Is64(); }
146
IsFloat64RoundUpSupported() const147 bool CodeAssembler::IsFloat64RoundUpSupported() const {
148 return raw_assembler()->machine()->Float64RoundUp().IsSupported();
149 }
150
IsFloat64RoundDownSupported() const151 bool CodeAssembler::IsFloat64RoundDownSupported() const {
152 return raw_assembler()->machine()->Float64RoundDown().IsSupported();
153 }
154
IsFloat64RoundTiesEvenSupported() const155 bool CodeAssembler::IsFloat64RoundTiesEvenSupported() const {
156 return raw_assembler()->machine()->Float64RoundTiesEven().IsSupported();
157 }
158
IsFloat64RoundTruncateSupported() const159 bool CodeAssembler::IsFloat64RoundTruncateSupported() const {
160 return raw_assembler()->machine()->Float64RoundTruncate().IsSupported();
161 }
162
Int32Constant(int32_t value)163 Node* CodeAssembler::Int32Constant(int32_t value) {
164 return raw_assembler()->Int32Constant(value);
165 }
166
Int64Constant(int64_t value)167 Node* CodeAssembler::Int64Constant(int64_t value) {
168 return raw_assembler()->Int64Constant(value);
169 }
170
IntPtrConstant(intptr_t value)171 Node* CodeAssembler::IntPtrConstant(intptr_t value) {
172 return raw_assembler()->IntPtrConstant(value);
173 }
174
NumberConstant(double value)175 Node* CodeAssembler::NumberConstant(double value) {
176 return raw_assembler()->NumberConstant(value);
177 }
178
SmiConstant(Smi * value)179 Node* CodeAssembler::SmiConstant(Smi* value) {
180 return BitcastWordToTaggedSigned(IntPtrConstant(bit_cast<intptr_t>(value)));
181 }
182
SmiConstant(int value)183 Node* CodeAssembler::SmiConstant(int value) {
184 return SmiConstant(Smi::FromInt(value));
185 }
186
HeapConstant(Handle<HeapObject> object)187 Node* CodeAssembler::HeapConstant(Handle<HeapObject> object) {
188 return raw_assembler()->HeapConstant(object);
189 }
190
CStringConstant(const char * str)191 Node* CodeAssembler::CStringConstant(const char* str) {
192 return HeapConstant(factory()->NewStringFromAsciiChecked(str, TENURED));
193 }
194
BooleanConstant(bool value)195 Node* CodeAssembler::BooleanConstant(bool value) {
196 return raw_assembler()->BooleanConstant(value);
197 }
198
ExternalConstant(ExternalReference address)199 Node* CodeAssembler::ExternalConstant(ExternalReference address) {
200 return raw_assembler()->ExternalConstant(address);
201 }
202
Float64Constant(double value)203 Node* CodeAssembler::Float64Constant(double value) {
204 return raw_assembler()->Float64Constant(value);
205 }
206
NaNConstant()207 Node* CodeAssembler::NaNConstant() {
208 return LoadRoot(Heap::kNanValueRootIndex);
209 }
210
ToInt32Constant(Node * node,int32_t & out_value)211 bool CodeAssembler::ToInt32Constant(Node* node, int32_t& out_value) {
212 Int64Matcher m(node);
213 if (m.HasValue() &&
214 m.IsInRange(std::numeric_limits<int32_t>::min(),
215 std::numeric_limits<int32_t>::max())) {
216 out_value = static_cast<int32_t>(m.Value());
217 return true;
218 }
219
220 return false;
221 }
222
ToInt64Constant(Node * node,int64_t & out_value)223 bool CodeAssembler::ToInt64Constant(Node* node, int64_t& out_value) {
224 Int64Matcher m(node);
225 if (m.HasValue()) out_value = m.Value();
226 return m.HasValue();
227 }
228
ToSmiConstant(Node * node,Smi * & out_value)229 bool CodeAssembler::ToSmiConstant(Node* node, Smi*& out_value) {
230 if (node->opcode() == IrOpcode::kBitcastWordToTaggedSigned) {
231 node = node->InputAt(0);
232 } else {
233 return false;
234 }
235 IntPtrMatcher m(node);
236 if (m.HasValue()) {
237 out_value = Smi::cast(bit_cast<Object*>(m.Value()));
238 return true;
239 }
240 return false;
241 }
242
ToIntPtrConstant(Node * node,intptr_t & out_value)243 bool CodeAssembler::ToIntPtrConstant(Node* node, intptr_t& out_value) {
244 if (node->opcode() == IrOpcode::kBitcastWordToTaggedSigned ||
245 node->opcode() == IrOpcode::kBitcastWordToTagged) {
246 node = node->InputAt(0);
247 }
248 IntPtrMatcher m(node);
249 if (m.HasValue()) out_value = m.Value();
250 return m.HasValue();
251 }
252
Parameter(int value)253 Node* CodeAssembler::Parameter(int value) {
254 return raw_assembler()->Parameter(value);
255 }
256
GetJSContextParameter()257 Node* CodeAssembler::GetJSContextParameter() {
258 CallDescriptor* desc = raw_assembler()->call_descriptor();
259 DCHECK(desc->IsJSFunctionCall());
260 return Parameter(Linkage::GetJSCallContextParamIndex(
261 static_cast<int>(desc->JSParameterCount())));
262 }
263
Return(Node * value)264 void CodeAssembler::Return(Node* value) {
265 return raw_assembler()->Return(value);
266 }
267
Return(Node * value1,Node * value2)268 void CodeAssembler::Return(Node* value1, Node* value2) {
269 return raw_assembler()->Return(value1, value2);
270 }
271
Return(Node * value1,Node * value2,Node * value3)272 void CodeAssembler::Return(Node* value1, Node* value2, Node* value3) {
273 return raw_assembler()->Return(value1, value2, value3);
274 }
275
PopAndReturn(Node * pop,Node * value)276 void CodeAssembler::PopAndReturn(Node* pop, Node* value) {
277 return raw_assembler()->PopAndReturn(pop, value);
278 }
279
DebugBreak()280 void CodeAssembler::DebugBreak() { raw_assembler()->DebugBreak(); }
281
Unreachable()282 void CodeAssembler::Unreachable() {
283 DebugBreak();
284 raw_assembler()->Unreachable();
285 }
286
Comment(const char * format,...)287 void CodeAssembler::Comment(const char* format, ...) {
288 if (!FLAG_code_comments) return;
289 char buffer[4 * KB];
290 StringBuilder builder(buffer, arraysize(buffer));
291 va_list arguments;
292 va_start(arguments, format);
293 builder.AddFormattedList(format, arguments);
294 va_end(arguments);
295
296 // Copy the string before recording it in the assembler to avoid
297 // issues when the stack allocated buffer goes out of scope.
298 const int prefix_len = 2;
299 int length = builder.position() + 1;
300 char* copy = reinterpret_cast<char*>(malloc(length + prefix_len));
301 MemCopy(copy + prefix_len, builder.Finalize(), length);
302 copy[0] = ';';
303 copy[1] = ' ';
304 raw_assembler()->Comment(copy);
305 }
306
Bind(Label * label)307 void CodeAssembler::Bind(Label* label) { return label->Bind(); }
308
LoadFramePointer()309 Node* CodeAssembler::LoadFramePointer() {
310 return raw_assembler()->LoadFramePointer();
311 }
312
LoadParentFramePointer()313 Node* CodeAssembler::LoadParentFramePointer() {
314 return raw_assembler()->LoadParentFramePointer();
315 }
316
LoadStackPointer()317 Node* CodeAssembler::LoadStackPointer() {
318 return raw_assembler()->LoadStackPointer();
319 }
320
321 #define DEFINE_CODE_ASSEMBLER_BINARY_OP(name) \
322 Node* CodeAssembler::name(Node* a, Node* b) { \
323 return raw_assembler()->name(a, b); \
324 }
CODE_ASSEMBLER_BINARY_OP_LIST(DEFINE_CODE_ASSEMBLER_BINARY_OP)325 CODE_ASSEMBLER_BINARY_OP_LIST(DEFINE_CODE_ASSEMBLER_BINARY_OP)
326 #undef DEFINE_CODE_ASSEMBLER_BINARY_OP
327
328 Node* CodeAssembler::IntPtrAdd(Node* left, Node* right) {
329 intptr_t left_constant;
330 bool is_left_constant = ToIntPtrConstant(left, left_constant);
331 intptr_t right_constant;
332 bool is_right_constant = ToIntPtrConstant(right, right_constant);
333 if (is_left_constant) {
334 if (is_right_constant) {
335 return IntPtrConstant(left_constant + right_constant);
336 }
337 if (left_constant == 0) {
338 return right;
339 }
340 } else if (is_right_constant) {
341 if (right_constant == 0) {
342 return left;
343 }
344 }
345 return raw_assembler()->IntPtrAdd(left, right);
346 }
347
IntPtrSub(Node * left,Node * right)348 Node* CodeAssembler::IntPtrSub(Node* left, Node* right) {
349 intptr_t left_constant;
350 bool is_left_constant = ToIntPtrConstant(left, left_constant);
351 intptr_t right_constant;
352 bool is_right_constant = ToIntPtrConstant(right, right_constant);
353 if (is_left_constant) {
354 if (is_right_constant) {
355 return IntPtrConstant(left_constant - right_constant);
356 }
357 } else if (is_right_constant) {
358 if (right_constant == 0) {
359 return left;
360 }
361 }
362 return raw_assembler()->IntPtrSub(left, right);
363 }
364
WordShl(Node * value,int shift)365 Node* CodeAssembler::WordShl(Node* value, int shift) {
366 return (shift != 0) ? raw_assembler()->WordShl(value, IntPtrConstant(shift))
367 : value;
368 }
369
WordShr(Node * value,int shift)370 Node* CodeAssembler::WordShr(Node* value, int shift) {
371 return (shift != 0) ? raw_assembler()->WordShr(value, IntPtrConstant(shift))
372 : value;
373 }
374
Word32Shr(Node * value,int shift)375 Node* CodeAssembler::Word32Shr(Node* value, int shift) {
376 return (shift != 0) ? raw_assembler()->Word32Shr(value, Int32Constant(shift))
377 : value;
378 }
379
ChangeUint32ToWord(Node * value)380 Node* CodeAssembler::ChangeUint32ToWord(Node* value) {
381 if (raw_assembler()->machine()->Is64()) {
382 value = raw_assembler()->ChangeUint32ToUint64(value);
383 }
384 return value;
385 }
386
ChangeInt32ToIntPtr(Node * value)387 Node* CodeAssembler::ChangeInt32ToIntPtr(Node* value) {
388 if (raw_assembler()->machine()->Is64()) {
389 value = raw_assembler()->ChangeInt32ToInt64(value);
390 }
391 return value;
392 }
393
RoundIntPtrToFloat64(Node * value)394 Node* CodeAssembler::RoundIntPtrToFloat64(Node* value) {
395 if (raw_assembler()->machine()->Is64()) {
396 return raw_assembler()->RoundInt64ToFloat64(value);
397 }
398 return raw_assembler()->ChangeInt32ToFloat64(value);
399 }
400
401 #define DEFINE_CODE_ASSEMBLER_UNARY_OP(name) \
402 Node* CodeAssembler::name(Node* a) { return raw_assembler()->name(a); }
CODE_ASSEMBLER_UNARY_OP_LIST(DEFINE_CODE_ASSEMBLER_UNARY_OP)403 CODE_ASSEMBLER_UNARY_OP_LIST(DEFINE_CODE_ASSEMBLER_UNARY_OP)
404 #undef DEFINE_CODE_ASSEMBLER_UNARY_OP
405
406 Node* CodeAssembler::Load(MachineType rep, Node* base) {
407 return raw_assembler()->Load(rep, base);
408 }
409
Load(MachineType rep,Node * base,Node * offset)410 Node* CodeAssembler::Load(MachineType rep, Node* base, Node* offset) {
411 return raw_assembler()->Load(rep, base, offset);
412 }
413
AtomicLoad(MachineType rep,Node * base,Node * offset)414 Node* CodeAssembler::AtomicLoad(MachineType rep, Node* base, Node* offset) {
415 return raw_assembler()->AtomicLoad(rep, base, offset);
416 }
417
LoadRoot(Heap::RootListIndex root_index)418 Node* CodeAssembler::LoadRoot(Heap::RootListIndex root_index) {
419 if (isolate()->heap()->RootCanBeTreatedAsConstant(root_index)) {
420 Handle<Object> root = isolate()->heap()->root_handle(root_index);
421 if (root->IsSmi()) {
422 return SmiConstant(Smi::cast(*root));
423 } else {
424 return HeapConstant(Handle<HeapObject>::cast(root));
425 }
426 }
427
428 Node* roots_array_start =
429 ExternalConstant(ExternalReference::roots_array_start(isolate()));
430 return Load(MachineType::AnyTagged(), roots_array_start,
431 IntPtrConstant(root_index * kPointerSize));
432 }
433
Store(Node * base,Node * value)434 Node* CodeAssembler::Store(Node* base, Node* value) {
435 return raw_assembler()->Store(MachineRepresentation::kTagged, base, value,
436 kFullWriteBarrier);
437 }
438
Store(Node * base,Node * offset,Node * value)439 Node* CodeAssembler::Store(Node* base, Node* offset, Node* value) {
440 return raw_assembler()->Store(MachineRepresentation::kTagged, base, offset,
441 value, kFullWriteBarrier);
442 }
443
StoreWithMapWriteBarrier(Node * base,Node * offset,Node * value)444 Node* CodeAssembler::StoreWithMapWriteBarrier(Node* base, Node* offset,
445 Node* value) {
446 return raw_assembler()->Store(MachineRepresentation::kTagged, base, offset,
447 value, kMapWriteBarrier);
448 }
449
StoreNoWriteBarrier(MachineRepresentation rep,Node * base,Node * value)450 Node* CodeAssembler::StoreNoWriteBarrier(MachineRepresentation rep, Node* base,
451 Node* value) {
452 return raw_assembler()->Store(rep, base, value, kNoWriteBarrier);
453 }
454
StoreNoWriteBarrier(MachineRepresentation rep,Node * base,Node * offset,Node * value)455 Node* CodeAssembler::StoreNoWriteBarrier(MachineRepresentation rep, Node* base,
456 Node* offset, Node* value) {
457 return raw_assembler()->Store(rep, base, offset, value, kNoWriteBarrier);
458 }
459
AtomicStore(MachineRepresentation rep,Node * base,Node * offset,Node * value)460 Node* CodeAssembler::AtomicStore(MachineRepresentation rep, Node* base,
461 Node* offset, Node* value) {
462 return raw_assembler()->AtomicStore(rep, base, offset, value);
463 }
464
StoreRoot(Heap::RootListIndex root_index,Node * value)465 Node* CodeAssembler::StoreRoot(Heap::RootListIndex root_index, Node* value) {
466 DCHECK(Heap::RootCanBeWrittenAfterInitialization(root_index));
467 Node* roots_array_start =
468 ExternalConstant(ExternalReference::roots_array_start(isolate()));
469 return StoreNoWriteBarrier(MachineRepresentation::kTagged, roots_array_start,
470 IntPtrConstant(root_index * kPointerSize), value);
471 }
472
Retain(Node * value)473 Node* CodeAssembler::Retain(Node* value) {
474 return raw_assembler()->Retain(value);
475 }
476
Projection(int index,Node * value)477 Node* CodeAssembler::Projection(int index, Node* value) {
478 return raw_assembler()->Projection(index, value);
479 }
480
GotoIfException(Node * node,Label * if_exception,Variable * exception_var)481 void CodeAssembler::GotoIfException(Node* node, Label* if_exception,
482 Variable* exception_var) {
483 Label success(this), exception(this, Label::kDeferred);
484 success.MergeVariables();
485 exception.MergeVariables();
486 DCHECK(!node->op()->HasProperty(Operator::kNoThrow));
487
488 raw_assembler()->Continuations(node, success.label_, exception.label_);
489
490 Bind(&exception);
491 const Operator* op = raw_assembler()->common()->IfException();
492 Node* exception_value = raw_assembler()->AddNode(op, node, node);
493 if (exception_var != nullptr) {
494 exception_var->Bind(exception_value);
495 }
496 Goto(if_exception);
497
498 Bind(&success);
499 }
500
501 template <class... TArgs>
CallRuntime(Runtime::FunctionId function,Node * context,TArgs...args)502 Node* CodeAssembler::CallRuntime(Runtime::FunctionId function, Node* context,
503 TArgs... args) {
504 int argc = static_cast<int>(sizeof...(args));
505 CallDescriptor* desc = Linkage::GetRuntimeCallDescriptor(
506 zone(), function, argc, Operator::kNoProperties,
507 CallDescriptor::kNoFlags);
508 int return_count = static_cast<int>(desc->ReturnCount());
509
510 Node* centry =
511 HeapConstant(CodeFactory::RuntimeCEntry(isolate(), return_count));
512 Node* ref = ExternalConstant(ExternalReference(function, isolate()));
513 Node* arity = Int32Constant(argc);
514
515 Node* nodes[] = {centry, args..., ref, arity, context};
516
517 CallPrologue();
518 Node* return_value = raw_assembler()->CallN(desc, arraysize(nodes), nodes);
519 CallEpilogue();
520 return return_value;
521 }
522
523 // Instantiate CallRuntime() with up to 6 arguments.
524 #define INSTANTIATE(...) \
525 template V8_EXPORT_PRIVATE Node* CodeAssembler::CallRuntime( \
526 Runtime::FunctionId, __VA_ARGS__);
REPEAT_1_TO_7(INSTANTIATE,Node *)527 REPEAT_1_TO_7(INSTANTIATE, Node*)
528 #undef INSTANTIATE
529
530 template <class... TArgs>
531 Node* CodeAssembler::TailCallRuntime(Runtime::FunctionId function,
532 Node* context, TArgs... args) {
533 int argc = static_cast<int>(sizeof...(args));
534 CallDescriptor* desc = Linkage::GetRuntimeCallDescriptor(
535 zone(), function, argc, Operator::kNoProperties,
536 CallDescriptor::kSupportsTailCalls);
537 int return_count = static_cast<int>(desc->ReturnCount());
538
539 Node* centry =
540 HeapConstant(CodeFactory::RuntimeCEntry(isolate(), return_count));
541 Node* ref = ExternalConstant(ExternalReference(function, isolate()));
542 Node* arity = Int32Constant(argc);
543
544 Node* nodes[] = {centry, args..., ref, arity, context};
545
546 return raw_assembler()->TailCallN(desc, arraysize(nodes), nodes);
547 }
548
549 // Instantiate TailCallRuntime() with up to 6 arguments.
550 #define INSTANTIATE(...) \
551 template V8_EXPORT_PRIVATE Node* CodeAssembler::TailCallRuntime( \
552 Runtime::FunctionId, __VA_ARGS__);
REPEAT_1_TO_7(INSTANTIATE,Node *)553 REPEAT_1_TO_7(INSTANTIATE, Node*)
554 #undef INSTANTIATE
555
556 template <class... TArgs>
557 Node* CodeAssembler::CallStubR(const CallInterfaceDescriptor& descriptor,
558 size_t result_size, Node* target, Node* context,
559 TArgs... args) {
560 Node* nodes[] = {target, args..., context};
561 return CallStubN(descriptor, result_size, arraysize(nodes), nodes);
562 }
563
564 // Instantiate CallStubR() with up to 6 arguments.
565 #define INSTANTIATE(...) \
566 template V8_EXPORT_PRIVATE Node* CodeAssembler::CallStubR( \
567 const CallInterfaceDescriptor& descriptor, size_t, Node*, __VA_ARGS__);
REPEAT_1_TO_7(INSTANTIATE,Node *)568 REPEAT_1_TO_7(INSTANTIATE, Node*)
569 #undef INSTANTIATE
570
571 Node* CodeAssembler::CallStubN(const CallInterfaceDescriptor& descriptor,
572 size_t result_size, int input_count,
573 Node* const* inputs) {
574 // 2 is for target and context.
575 DCHECK_LE(2, input_count);
576 int argc = input_count - 2;
577 DCHECK_LE(descriptor.GetParameterCount(), argc);
578 // Extra arguments not mentioned in the descriptor are passed on the stack.
579 int stack_parameter_count = argc - descriptor.GetRegisterParameterCount();
580 DCHECK_LE(descriptor.GetStackParameterCount(), stack_parameter_count);
581 CallDescriptor* desc = Linkage::GetStubCallDescriptor(
582 isolate(), zone(), descriptor, stack_parameter_count,
583 CallDescriptor::kNoFlags, Operator::kNoProperties,
584 MachineType::AnyTagged(), result_size);
585
586 CallPrologue();
587 Node* return_value = raw_assembler()->CallN(desc, input_count, inputs);
588 CallEpilogue();
589 return return_value;
590 }
591
592 template <class... TArgs>
TailCallStub(const CallInterfaceDescriptor & descriptor,Node * target,Node * context,TArgs...args)593 Node* CodeAssembler::TailCallStub(const CallInterfaceDescriptor& descriptor,
594 Node* target, Node* context, TArgs... args) {
595 DCHECK_EQ(descriptor.GetParameterCount(), sizeof...(args));
596 size_t result_size = 1;
597 CallDescriptor* desc = Linkage::GetStubCallDescriptor(
598 isolate(), zone(), descriptor, descriptor.GetStackParameterCount(),
599 CallDescriptor::kSupportsTailCalls, Operator::kNoProperties,
600 MachineType::AnyTagged(), result_size);
601
602 Node* nodes[] = {target, args..., context};
603
604 return raw_assembler()->TailCallN(desc, arraysize(nodes), nodes);
605 }
606
607 // Instantiate TailCallStub() with up to 6 arguments.
608 #define INSTANTIATE(...) \
609 template V8_EXPORT_PRIVATE Node* CodeAssembler::TailCallStub( \
610 const CallInterfaceDescriptor& descriptor, Node*, __VA_ARGS__);
REPEAT_1_TO_7(INSTANTIATE,Node *)611 REPEAT_1_TO_7(INSTANTIATE, Node*)
612 #undef INSTANTIATE
613
614 template <class... TArgs>
615 Node* CodeAssembler::TailCallBytecodeDispatch(
616 const CallInterfaceDescriptor& descriptor, Node* target, TArgs... args) {
617 DCHECK_EQ(descriptor.GetParameterCount(), sizeof...(args));
618 CallDescriptor* desc = Linkage::GetBytecodeDispatchCallDescriptor(
619 isolate(), zone(), descriptor, descriptor.GetStackParameterCount());
620
621 Node* nodes[] = {target, args...};
622 return raw_assembler()->TailCallN(desc, arraysize(nodes), nodes);
623 }
624
625 // Instantiate TailCallBytecodeDispatch() with 4 arguments.
626 template V8_EXPORT_PRIVATE Node* CodeAssembler::TailCallBytecodeDispatch(
627 const CallInterfaceDescriptor& descriptor, Node* target, Node*, Node*,
628 Node*, Node*);
629
CallCFunctionN(Signature<MachineType> * signature,int input_count,Node * const * inputs)630 Node* CodeAssembler::CallCFunctionN(Signature<MachineType>* signature,
631 int input_count, Node* const* inputs) {
632 CallDescriptor* desc = Linkage::GetSimplifiedCDescriptor(zone(), signature);
633 return raw_assembler()->CallN(desc, input_count, inputs);
634 }
635
CallCFunction2(MachineType return_type,MachineType arg0_type,MachineType arg1_type,Node * function,Node * arg0,Node * arg1)636 Node* CodeAssembler::CallCFunction2(MachineType return_type,
637 MachineType arg0_type,
638 MachineType arg1_type, Node* function,
639 Node* arg0, Node* arg1) {
640 return raw_assembler()->CallCFunction2(return_type, arg0_type, arg1_type,
641 function, arg0, arg1);
642 }
643
CallCFunction3(MachineType return_type,MachineType arg0_type,MachineType arg1_type,MachineType arg2_type,Node * function,Node * arg0,Node * arg1,Node * arg2)644 Node* CodeAssembler::CallCFunction3(MachineType return_type,
645 MachineType arg0_type,
646 MachineType arg1_type,
647 MachineType arg2_type, Node* function,
648 Node* arg0, Node* arg1, Node* arg2) {
649 return raw_assembler()->CallCFunction3(return_type, arg0_type, arg1_type,
650 arg2_type, function, arg0, arg1, arg2);
651 }
652
Goto(Label * label)653 void CodeAssembler::Goto(Label* label) {
654 label->MergeVariables();
655 raw_assembler()->Goto(label->label_);
656 }
657
GotoIf(Node * condition,Label * true_label)658 void CodeAssembler::GotoIf(Node* condition, Label* true_label) {
659 Label false_label(this);
660 Branch(condition, true_label, &false_label);
661 Bind(&false_label);
662 }
663
GotoIfNot(Node * condition,Label * false_label)664 void CodeAssembler::GotoIfNot(Node* condition, Label* false_label) {
665 Label true_label(this);
666 Branch(condition, &true_label, false_label);
667 Bind(&true_label);
668 }
669
Branch(Node * condition,Label * true_label,Label * false_label)670 void CodeAssembler::Branch(Node* condition, Label* true_label,
671 Label* false_label) {
672 true_label->MergeVariables();
673 false_label->MergeVariables();
674 return raw_assembler()->Branch(condition, true_label->label_,
675 false_label->label_);
676 }
677
Switch(Node * index,Label * default_label,const int32_t * case_values,Label ** case_labels,size_t case_count)678 void CodeAssembler::Switch(Node* index, Label* default_label,
679 const int32_t* case_values, Label** case_labels,
680 size_t case_count) {
681 RawMachineLabel** labels =
682 new (zone()->New(sizeof(RawMachineLabel*) * case_count))
683 RawMachineLabel*[case_count];
684 for (size_t i = 0; i < case_count; ++i) {
685 labels[i] = case_labels[i]->label_;
686 case_labels[i]->MergeVariables();
687 default_label->MergeVariables();
688 }
689 return raw_assembler()->Switch(index, default_label->label_, case_values,
690 labels, case_count);
691 }
692
693 // RawMachineAssembler delegate helpers:
isolate() const694 Isolate* CodeAssembler::isolate() const { return raw_assembler()->isolate(); }
695
factory() const696 Factory* CodeAssembler::factory() const { return isolate()->factory(); }
697
zone() const698 Zone* CodeAssembler::zone() const { return raw_assembler()->zone(); }
699
raw_assembler() const700 RawMachineAssembler* CodeAssembler::raw_assembler() const {
701 return state_->raw_assembler_.get();
702 }
703
704 // The core implementation of Variable is stored through an indirection so
705 // that it can outlive the often block-scoped Variable declarations. This is
706 // needed to ensure that variable binding and merging through phis can
707 // properly be verified.
708 class CodeAssemblerVariable::Impl : public ZoneObject {
709 public:
Impl(MachineRepresentation rep)710 explicit Impl(MachineRepresentation rep) : value_(nullptr), rep_(rep) {}
711 Node* value_;
712 MachineRepresentation rep_;
713 };
714
CodeAssemblerVariable(CodeAssembler * assembler,MachineRepresentation rep)715 CodeAssemblerVariable::CodeAssemblerVariable(CodeAssembler* assembler,
716 MachineRepresentation rep)
717 : impl_(new (assembler->zone()) Impl(rep)), state_(assembler->state()) {
718 state_->variables_.insert(impl_);
719 }
720
CodeAssemblerVariable(CodeAssembler * assembler,MachineRepresentation rep,Node * initial_value)721 CodeAssemblerVariable::CodeAssemblerVariable(CodeAssembler* assembler,
722 MachineRepresentation rep,
723 Node* initial_value)
724 : CodeAssemblerVariable(assembler, rep) {
725 Bind(initial_value);
726 }
727
~CodeAssemblerVariable()728 CodeAssemblerVariable::~CodeAssemblerVariable() {
729 state_->variables_.erase(impl_);
730 }
731
Bind(Node * value)732 void CodeAssemblerVariable::Bind(Node* value) { impl_->value_ = value; }
733
value() const734 Node* CodeAssemblerVariable::value() const {
735 DCHECK_NOT_NULL(impl_->value_);
736 return impl_->value_;
737 }
738
rep() const739 MachineRepresentation CodeAssemblerVariable::rep() const { return impl_->rep_; }
740
IsBound() const741 bool CodeAssemblerVariable::IsBound() const { return impl_->value_ != nullptr; }
742
CodeAssemblerLabel(CodeAssembler * assembler,size_t vars_count,CodeAssemblerVariable ** vars,CodeAssemblerLabel::Type type)743 CodeAssemblerLabel::CodeAssemblerLabel(CodeAssembler* assembler,
744 size_t vars_count,
745 CodeAssemblerVariable** vars,
746 CodeAssemblerLabel::Type type)
747 : bound_(false),
748 merge_count_(0),
749 state_(assembler->state()),
750 label_(nullptr) {
751 void* buffer = assembler->zone()->New(sizeof(RawMachineLabel));
752 label_ = new (buffer)
753 RawMachineLabel(type == kDeferred ? RawMachineLabel::kDeferred
754 : RawMachineLabel::kNonDeferred);
755 for (size_t i = 0; i < vars_count; ++i) {
756 variable_phis_[vars[i]->impl_] = nullptr;
757 }
758 }
759
~CodeAssemblerLabel()760 CodeAssemblerLabel::~CodeAssemblerLabel() { label_->~RawMachineLabel(); }
761
MergeVariables()762 void CodeAssemblerLabel::MergeVariables() {
763 ++merge_count_;
764 for (auto var : state_->variables_) {
765 size_t count = 0;
766 Node* node = var->value_;
767 if (node != nullptr) {
768 auto i = variable_merges_.find(var);
769 if (i != variable_merges_.end()) {
770 i->second.push_back(node);
771 count = i->second.size();
772 } else {
773 count = 1;
774 variable_merges_[var] = std::vector<Node*>(1, node);
775 }
776 }
777 // If the following asserts, then you've jumped to a label without a bound
778 // variable along that path that expects to merge its value into a phi.
779 DCHECK(variable_phis_.find(var) == variable_phis_.end() ||
780 count == merge_count_);
781 USE(count);
782
783 // If the label is already bound, we already know the set of variables to
784 // merge and phi nodes have already been created.
785 if (bound_) {
786 auto phi = variable_phis_.find(var);
787 if (phi != variable_phis_.end()) {
788 DCHECK_NOT_NULL(phi->second);
789 state_->raw_assembler_->AppendPhiInput(phi->second, node);
790 } else {
791 auto i = variable_merges_.find(var);
792 if (i != variable_merges_.end()) {
793 // If the following assert fires, then you've declared a variable that
794 // has the same bound value along all paths up until the point you
795 // bound this label, but then later merged a path with a new value for
796 // the variable after the label bind (it's not possible to add phis to
797 // the bound label after the fact, just make sure to list the variable
798 // in the label's constructor's list of merged variables).
799 DCHECK(find_if(i->second.begin(), i->second.end(),
800 [node](Node* e) -> bool { return node != e; }) ==
801 i->second.end());
802 }
803 }
804 }
805 }
806 }
807
Bind()808 void CodeAssemblerLabel::Bind() {
809 DCHECK(!bound_);
810 state_->raw_assembler_->Bind(label_);
811
812 // Make sure that all variables that have changed along any path up to this
813 // point are marked as merge variables.
814 for (auto var : state_->variables_) {
815 Node* shared_value = nullptr;
816 auto i = variable_merges_.find(var);
817 if (i != variable_merges_.end()) {
818 for (auto value : i->second) {
819 DCHECK(value != nullptr);
820 if (value != shared_value) {
821 if (shared_value == nullptr) {
822 shared_value = value;
823 } else {
824 variable_phis_[var] = nullptr;
825 }
826 }
827 }
828 }
829 }
830
831 for (auto var : variable_phis_) {
832 CodeAssemblerVariable::Impl* var_impl = var.first;
833 auto i = variable_merges_.find(var_impl);
834 // If the following asserts fire, then a variable that has been marked as
835 // being merged at the label--either by explicitly marking it so in the
836 // label constructor or by having seen different bound values at branches
837 // into the label--doesn't have a bound value along all of the paths that
838 // have been merged into the label up to this point.
839 DCHECK(i != variable_merges_.end());
840 DCHECK_EQ(i->second.size(), merge_count_);
841 Node* phi = state_->raw_assembler_->Phi(
842 var.first->rep_, static_cast<int>(merge_count_), &(i->second[0]));
843 variable_phis_[var_impl] = phi;
844 }
845
846 // Bind all variables to a merge phi, the common value along all paths or
847 // null.
848 for (auto var : state_->variables_) {
849 auto i = variable_phis_.find(var);
850 if (i != variable_phis_.end()) {
851 var->value_ = i->second;
852 } else {
853 auto j = variable_merges_.find(var);
854 if (j != variable_merges_.end() && j->second.size() == merge_count_) {
855 var->value_ = j->second.back();
856 } else {
857 var->value_ = nullptr;
858 }
859 }
860 }
861
862 bound_ = true;
863 }
864
865 } // namespace compiler
866 } // namespace internal
867 } // namespace v8
868