1 // Copyright 2014 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/raw-machine-assembler.h"
6
7 #include "src/code-factory.h"
8 #include "src/compiler/node-properties.h"
9 #include "src/compiler/pipeline.h"
10 #include "src/compiler/scheduler.h"
11
12 namespace v8 {
13 namespace internal {
14 namespace compiler {
15
RawMachineAssembler(Isolate * isolate,Graph * graph,CallDescriptor * call_descriptor,MachineRepresentation word,MachineOperatorBuilder::Flags flags)16 RawMachineAssembler::RawMachineAssembler(Isolate* isolate, Graph* graph,
17 CallDescriptor* call_descriptor,
18 MachineRepresentation word,
19 MachineOperatorBuilder::Flags flags)
20 : isolate_(isolate),
21 graph_(graph),
22 schedule_(new (zone()) Schedule(zone())),
23 machine_(zone(), word, flags),
24 common_(zone()),
25 call_descriptor_(call_descriptor),
26 parameters_(parameter_count(), zone()),
27 current_block_(schedule()->start()) {
28 int param_count = static_cast<int>(parameter_count());
29 // Add an extra input for the JSFunction parameter to the start node.
30 graph->SetStart(graph->NewNode(common_.Start(param_count + 1)));
31 for (size_t i = 0; i < parameter_count(); ++i) {
32 parameters_[i] =
33 AddNode(common()->Parameter(static_cast<int>(i)), graph->start());
34 }
35 graph->SetEnd(graph->NewNode(common_.End(0)));
36 }
37
RelocatableIntPtrConstant(intptr_t value,RelocInfo::Mode rmode)38 Node* RawMachineAssembler::RelocatableIntPtrConstant(intptr_t value,
39 RelocInfo::Mode rmode) {
40 return kPointerSize == 8
41 ? RelocatableInt64Constant(value, rmode)
42 : RelocatableInt32Constant(static_cast<int>(value), rmode);
43 }
44
Export()45 Schedule* RawMachineAssembler::Export() {
46 // Compute the correct codegen order.
47 DCHECK(schedule_->rpo_order()->empty());
48 OFStream os(stdout);
49 if (FLAG_trace_turbo_scheduler) {
50 PrintF("--- RAW SCHEDULE -------------------------------------------\n");
51 os << *schedule_;
52 }
53 schedule_->EnsureCFGWellFormedness();
54 schedule_->PropagateDeferredMark();
55 if (FLAG_trace_turbo_scheduler) {
56 PrintF("--- EDGE SPLIT AND PROPAGATED DEFERRED SCHEDULE ------------\n");
57 os << *schedule_;
58 }
59 Scheduler::ComputeSpecialRPO(zone(), schedule_);
60 // Invalidate RawMachineAssembler.
61 Schedule* schedule = schedule_;
62 schedule_ = nullptr;
63 return schedule;
64 }
65
66
Parameter(size_t index)67 Node* RawMachineAssembler::Parameter(size_t index) {
68 DCHECK(index < parameter_count());
69 return parameters_[index];
70 }
71
72
Goto(RawMachineLabel * label)73 void RawMachineAssembler::Goto(RawMachineLabel* label) {
74 DCHECK(current_block_ != schedule()->end());
75 schedule()->AddGoto(CurrentBlock(), Use(label));
76 current_block_ = nullptr;
77 }
78
79
Branch(Node * condition,RawMachineLabel * true_val,RawMachineLabel * false_val)80 void RawMachineAssembler::Branch(Node* condition, RawMachineLabel* true_val,
81 RawMachineLabel* false_val) {
82 DCHECK(current_block_ != schedule()->end());
83 Node* branch = MakeNode(common()->Branch(), 1, &condition);
84 schedule()->AddBranch(CurrentBlock(), branch, Use(true_val), Use(false_val));
85 current_block_ = nullptr;
86 }
87
88
Switch(Node * index,RawMachineLabel * default_label,int32_t * case_values,RawMachineLabel ** case_labels,size_t case_count)89 void RawMachineAssembler::Switch(Node* index, RawMachineLabel* default_label,
90 int32_t* case_values,
91 RawMachineLabel** case_labels,
92 size_t case_count) {
93 DCHECK_NE(schedule()->end(), current_block_);
94 size_t succ_count = case_count + 1;
95 Node* switch_node = AddNode(common()->Switch(succ_count), index);
96 BasicBlock** succ_blocks = zone()->NewArray<BasicBlock*>(succ_count);
97 for (size_t index = 0; index < case_count; ++index) {
98 int32_t case_value = case_values[index];
99 BasicBlock* case_block = schedule()->NewBasicBlock();
100 Node* case_node =
101 graph()->NewNode(common()->IfValue(case_value), switch_node);
102 schedule()->AddNode(case_block, case_node);
103 schedule()->AddGoto(case_block, Use(case_labels[index]));
104 succ_blocks[index] = case_block;
105 }
106 BasicBlock* default_block = schedule()->NewBasicBlock();
107 Node* default_node = graph()->NewNode(common()->IfDefault(), switch_node);
108 schedule()->AddNode(default_block, default_node);
109 schedule()->AddGoto(default_block, Use(default_label));
110 succ_blocks[case_count] = default_block;
111 schedule()->AddSwitch(CurrentBlock(), switch_node, succ_blocks, succ_count);
112 current_block_ = nullptr;
113 }
114
115
Return(Node * value)116 void RawMachineAssembler::Return(Node* value) {
117 Node* ret = MakeNode(common()->Return(), 1, &value);
118 schedule()->AddReturn(CurrentBlock(), ret);
119 current_block_ = nullptr;
120 }
121
122
Return(Node * v1,Node * v2)123 void RawMachineAssembler::Return(Node* v1, Node* v2) {
124 Node* values[] = {v1, v2};
125 Node* ret = MakeNode(common()->Return(2), 2, values);
126 schedule()->AddReturn(CurrentBlock(), ret);
127 current_block_ = nullptr;
128 }
129
130
Return(Node * v1,Node * v2,Node * v3)131 void RawMachineAssembler::Return(Node* v1, Node* v2, Node* v3) {
132 Node* values[] = {v1, v2, v3};
133 Node* ret = MakeNode(common()->Return(3), 3, values);
134 schedule()->AddReturn(CurrentBlock(), ret);
135 current_block_ = nullptr;
136 }
137
DebugBreak()138 void RawMachineAssembler::DebugBreak() { AddNode(machine()->DebugBreak()); }
139
Comment(const char * msg)140 void RawMachineAssembler::Comment(const char* msg) {
141 AddNode(machine()->Comment(msg));
142 }
143
CallN(CallDescriptor * desc,Node * function,Node ** args)144 Node* RawMachineAssembler::CallN(CallDescriptor* desc, Node* function,
145 Node** args) {
146 int param_count =
147 static_cast<int>(desc->GetMachineSignature()->parameter_count());
148 int input_count = param_count + 1;
149 Node** buffer = zone()->NewArray<Node*>(input_count);
150 int index = 0;
151 buffer[index++] = function;
152 for (int i = 0; i < param_count; i++) {
153 buffer[index++] = args[i];
154 }
155 return AddNode(common()->Call(desc), input_count, buffer);
156 }
157
158
CallNWithFrameState(CallDescriptor * desc,Node * function,Node ** args,Node * frame_state)159 Node* RawMachineAssembler::CallNWithFrameState(CallDescriptor* desc,
160 Node* function, Node** args,
161 Node* frame_state) {
162 DCHECK(desc->NeedsFrameState());
163 int param_count =
164 static_cast<int>(desc->GetMachineSignature()->parameter_count());
165 int input_count = param_count + 2;
166 Node** buffer = zone()->NewArray<Node*>(input_count);
167 int index = 0;
168 buffer[index++] = function;
169 for (int i = 0; i < param_count; i++) {
170 buffer[index++] = args[i];
171 }
172 buffer[index++] = frame_state;
173 return AddNode(common()->Call(desc), input_count, buffer);
174 }
175
CallRuntime0(Runtime::FunctionId function,Node * context)176 Node* RawMachineAssembler::CallRuntime0(Runtime::FunctionId function,
177 Node* context) {
178 CallDescriptor* descriptor = Linkage::GetRuntimeCallDescriptor(
179 zone(), function, 0, Operator::kNoProperties, CallDescriptor::kNoFlags);
180 int return_count = static_cast<int>(descriptor->ReturnCount());
181
182 Node* centry = HeapConstant(CEntryStub(isolate(), return_count).GetCode());
183 Node* ref = AddNode(
184 common()->ExternalConstant(ExternalReference(function, isolate())));
185 Node* arity = Int32Constant(0);
186
187 return AddNode(common()->Call(descriptor), centry, ref, arity, context);
188 }
189
CallRuntime1(Runtime::FunctionId function,Node * arg1,Node * context)190 Node* RawMachineAssembler::CallRuntime1(Runtime::FunctionId function,
191 Node* arg1, Node* context) {
192 CallDescriptor* descriptor = Linkage::GetRuntimeCallDescriptor(
193 zone(), function, 1, Operator::kNoProperties, CallDescriptor::kNoFlags);
194 int return_count = static_cast<int>(descriptor->ReturnCount());
195
196 Node* centry = HeapConstant(CEntryStub(isolate(), return_count).GetCode());
197 Node* ref = AddNode(
198 common()->ExternalConstant(ExternalReference(function, isolate())));
199 Node* arity = Int32Constant(1);
200
201 return AddNode(common()->Call(descriptor), centry, arg1, ref, arity, context);
202 }
203
204
CallRuntime2(Runtime::FunctionId function,Node * arg1,Node * arg2,Node * context)205 Node* RawMachineAssembler::CallRuntime2(Runtime::FunctionId function,
206 Node* arg1, Node* arg2, Node* context) {
207 CallDescriptor* descriptor = Linkage::GetRuntimeCallDescriptor(
208 zone(), function, 2, Operator::kNoProperties, CallDescriptor::kNoFlags);
209 int return_count = static_cast<int>(descriptor->ReturnCount());
210
211 Node* centry = HeapConstant(CEntryStub(isolate(), return_count).GetCode());
212 Node* ref = AddNode(
213 common()->ExternalConstant(ExternalReference(function, isolate())));
214 Node* arity = Int32Constant(2);
215
216 return AddNode(common()->Call(descriptor), centry, arg1, arg2, ref, arity,
217 context);
218 }
219
CallRuntime3(Runtime::FunctionId function,Node * arg1,Node * arg2,Node * arg3,Node * context)220 Node* RawMachineAssembler::CallRuntime3(Runtime::FunctionId function,
221 Node* arg1, Node* arg2, Node* arg3,
222 Node* context) {
223 CallDescriptor* descriptor = Linkage::GetRuntimeCallDescriptor(
224 zone(), function, 3, Operator::kNoProperties, CallDescriptor::kNoFlags);
225 int return_count = static_cast<int>(descriptor->ReturnCount());
226
227 Node* centry = HeapConstant(CEntryStub(isolate(), return_count).GetCode());
228 Node* ref = AddNode(
229 common()->ExternalConstant(ExternalReference(function, isolate())));
230 Node* arity = Int32Constant(3);
231
232 return AddNode(common()->Call(descriptor), centry, arg1, arg2, arg3, ref,
233 arity, context);
234 }
235
CallRuntime4(Runtime::FunctionId function,Node * arg1,Node * arg2,Node * arg3,Node * arg4,Node * context)236 Node* RawMachineAssembler::CallRuntime4(Runtime::FunctionId function,
237 Node* arg1, Node* arg2, Node* arg3,
238 Node* arg4, Node* context) {
239 CallDescriptor* descriptor = Linkage::GetRuntimeCallDescriptor(
240 zone(), function, 4, Operator::kNoProperties, CallDescriptor::kNoFlags);
241 int return_count = static_cast<int>(descriptor->ReturnCount());
242
243 Node* centry = HeapConstant(CEntryStub(isolate(), return_count).GetCode());
244 Node* ref = AddNode(
245 common()->ExternalConstant(ExternalReference(function, isolate())));
246 Node* arity = Int32Constant(4);
247
248 return AddNode(common()->Call(descriptor), centry, arg1, arg2, arg3, arg4,
249 ref, arity, context);
250 }
251
252
TailCallN(CallDescriptor * desc,Node * function,Node ** args)253 Node* RawMachineAssembler::TailCallN(CallDescriptor* desc, Node* function,
254 Node** args) {
255 int param_count =
256 static_cast<int>(desc->GetMachineSignature()->parameter_count());
257 int input_count = param_count + 1;
258 Node** buffer = zone()->NewArray<Node*>(input_count);
259 int index = 0;
260 buffer[index++] = function;
261 for (int i = 0; i < param_count; i++) {
262 buffer[index++] = args[i];
263 }
264 Node* tail_call = MakeNode(common()->TailCall(desc), input_count, buffer);
265 schedule()->AddTailCall(CurrentBlock(), tail_call);
266 current_block_ = nullptr;
267 return tail_call;
268 }
269
TailCallRuntime0(Runtime::FunctionId function,Node * context)270 Node* RawMachineAssembler::TailCallRuntime0(Runtime::FunctionId function,
271 Node* context) {
272 const int kArity = 0;
273 CallDescriptor* desc = Linkage::GetRuntimeCallDescriptor(
274 zone(), function, kArity, Operator::kNoProperties,
275 CallDescriptor::kSupportsTailCalls);
276 int return_count = static_cast<int>(desc->ReturnCount());
277
278 Node* centry = HeapConstant(CEntryStub(isolate(), return_count).GetCode());
279 Node* ref = AddNode(
280 common()->ExternalConstant(ExternalReference(function, isolate())));
281 Node* arity = Int32Constant(kArity);
282
283 Node* nodes[] = {centry, ref, arity, context};
284 Node* tail_call = MakeNode(common()->TailCall(desc), arraysize(nodes), nodes);
285
286 schedule()->AddTailCall(CurrentBlock(), tail_call);
287 current_block_ = nullptr;
288 return tail_call;
289 }
290
TailCallRuntime1(Runtime::FunctionId function,Node * arg1,Node * context)291 Node* RawMachineAssembler::TailCallRuntime1(Runtime::FunctionId function,
292 Node* arg1, Node* context) {
293 const int kArity = 1;
294 CallDescriptor* desc = Linkage::GetRuntimeCallDescriptor(
295 zone(), function, kArity, Operator::kNoProperties,
296 CallDescriptor::kSupportsTailCalls);
297 int return_count = static_cast<int>(desc->ReturnCount());
298
299 Node* centry = HeapConstant(CEntryStub(isolate(), return_count).GetCode());
300 Node* ref = AddNode(
301 common()->ExternalConstant(ExternalReference(function, isolate())));
302 Node* arity = Int32Constant(kArity);
303
304 Node* nodes[] = {centry, arg1, ref, arity, context};
305 Node* tail_call = MakeNode(common()->TailCall(desc), arraysize(nodes), nodes);
306
307 schedule()->AddTailCall(CurrentBlock(), tail_call);
308 current_block_ = nullptr;
309 return tail_call;
310 }
311
312
TailCallRuntime2(Runtime::FunctionId function,Node * arg1,Node * arg2,Node * context)313 Node* RawMachineAssembler::TailCallRuntime2(Runtime::FunctionId function,
314 Node* arg1, Node* arg2,
315 Node* context) {
316 const int kArity = 2;
317 CallDescriptor* desc = Linkage::GetRuntimeCallDescriptor(
318 zone(), function, kArity, Operator::kNoProperties,
319 CallDescriptor::kSupportsTailCalls);
320 int return_count = static_cast<int>(desc->ReturnCount());
321
322 Node* centry = HeapConstant(CEntryStub(isolate(), return_count).GetCode());
323 Node* ref = AddNode(
324 common()->ExternalConstant(ExternalReference(function, isolate())));
325 Node* arity = Int32Constant(kArity);
326
327 Node* nodes[] = {centry, arg1, arg2, ref, arity, context};
328 Node* tail_call = MakeNode(common()->TailCall(desc), arraysize(nodes), nodes);
329
330 schedule()->AddTailCall(CurrentBlock(), tail_call);
331 current_block_ = nullptr;
332 return tail_call;
333 }
334
TailCallRuntime3(Runtime::FunctionId function,Node * arg1,Node * arg2,Node * arg3,Node * context)335 Node* RawMachineAssembler::TailCallRuntime3(Runtime::FunctionId function,
336 Node* arg1, Node* arg2, Node* arg3,
337 Node* context) {
338 const int kArity = 3;
339 CallDescriptor* desc = Linkage::GetRuntimeCallDescriptor(
340 zone(), function, kArity, Operator::kNoProperties,
341 CallDescriptor::kSupportsTailCalls);
342 int return_count = static_cast<int>(desc->ReturnCount());
343
344 Node* centry = HeapConstant(CEntryStub(isolate(), return_count).GetCode());
345 Node* ref = AddNode(
346 common()->ExternalConstant(ExternalReference(function, isolate())));
347 Node* arity = Int32Constant(kArity);
348
349 Node* nodes[] = {centry, arg1, arg2, arg3, ref, arity, context};
350 Node* tail_call = MakeNode(common()->TailCall(desc), arraysize(nodes), nodes);
351
352 schedule()->AddTailCall(CurrentBlock(), tail_call);
353 current_block_ = nullptr;
354 return tail_call;
355 }
356
TailCallRuntime4(Runtime::FunctionId function,Node * arg1,Node * arg2,Node * arg3,Node * arg4,Node * context)357 Node* RawMachineAssembler::TailCallRuntime4(Runtime::FunctionId function,
358 Node* arg1, Node* arg2, Node* arg3,
359 Node* arg4, Node* context) {
360 const int kArity = 4;
361 CallDescriptor* desc = Linkage::GetRuntimeCallDescriptor(
362 zone(), function, kArity, Operator::kNoProperties,
363 CallDescriptor::kSupportsTailCalls);
364 int return_count = static_cast<int>(desc->ReturnCount());
365
366 Node* centry = HeapConstant(CEntryStub(isolate(), return_count).GetCode());
367 Node* ref = AddNode(
368 common()->ExternalConstant(ExternalReference(function, isolate())));
369 Node* arity = Int32Constant(kArity);
370
371 Node* nodes[] = {centry, arg1, arg2, arg3, arg4, ref, arity, context};
372 Node* tail_call = MakeNode(common()->TailCall(desc), arraysize(nodes), nodes);
373
374 schedule()->AddTailCall(CurrentBlock(), tail_call);
375 current_block_ = nullptr;
376 return tail_call;
377 }
378
CallCFunction0(MachineType return_type,Node * function)379 Node* RawMachineAssembler::CallCFunction0(MachineType return_type,
380 Node* function) {
381 MachineSignature::Builder builder(zone(), 1, 0);
382 builder.AddReturn(return_type);
383 const CallDescriptor* descriptor =
384 Linkage::GetSimplifiedCDescriptor(zone(), builder.Build());
385
386 return AddNode(common()->Call(descriptor), function);
387 }
388
389
CallCFunction1(MachineType return_type,MachineType arg0_type,Node * function,Node * arg0)390 Node* RawMachineAssembler::CallCFunction1(MachineType return_type,
391 MachineType arg0_type, Node* function,
392 Node* arg0) {
393 MachineSignature::Builder builder(zone(), 1, 1);
394 builder.AddReturn(return_type);
395 builder.AddParam(arg0_type);
396 const CallDescriptor* descriptor =
397 Linkage::GetSimplifiedCDescriptor(zone(), builder.Build());
398
399 return AddNode(common()->Call(descriptor), function, arg0);
400 }
401
402
CallCFunction2(MachineType return_type,MachineType arg0_type,MachineType arg1_type,Node * function,Node * arg0,Node * arg1)403 Node* RawMachineAssembler::CallCFunction2(MachineType return_type,
404 MachineType arg0_type,
405 MachineType arg1_type, Node* function,
406 Node* arg0, Node* arg1) {
407 MachineSignature::Builder builder(zone(), 1, 2);
408 builder.AddReturn(return_type);
409 builder.AddParam(arg0_type);
410 builder.AddParam(arg1_type);
411 const CallDescriptor* descriptor =
412 Linkage::GetSimplifiedCDescriptor(zone(), builder.Build());
413
414 return AddNode(common()->Call(descriptor), function, arg0, arg1);
415 }
416
417
CallCFunction8(MachineType return_type,MachineType arg0_type,MachineType arg1_type,MachineType arg2_type,MachineType arg3_type,MachineType arg4_type,MachineType arg5_type,MachineType arg6_type,MachineType arg7_type,Node * function,Node * arg0,Node * arg1,Node * arg2,Node * arg3,Node * arg4,Node * arg5,Node * arg6,Node * arg7)418 Node* RawMachineAssembler::CallCFunction8(
419 MachineType return_type, MachineType arg0_type, MachineType arg1_type,
420 MachineType arg2_type, MachineType arg3_type, MachineType arg4_type,
421 MachineType arg5_type, MachineType arg6_type, MachineType arg7_type,
422 Node* function, Node* arg0, Node* arg1, Node* arg2, Node* arg3, Node* arg4,
423 Node* arg5, Node* arg6, Node* arg7) {
424 MachineSignature::Builder builder(zone(), 1, 8);
425 builder.AddReturn(return_type);
426 builder.AddParam(arg0_type);
427 builder.AddParam(arg1_type);
428 builder.AddParam(arg2_type);
429 builder.AddParam(arg3_type);
430 builder.AddParam(arg4_type);
431 builder.AddParam(arg5_type);
432 builder.AddParam(arg6_type);
433 builder.AddParam(arg7_type);
434 Node* args[] = {function, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7};
435 const CallDescriptor* descriptor =
436 Linkage::GetSimplifiedCDescriptor(zone(), builder.Build());
437 return AddNode(common()->Call(descriptor), arraysize(args), args);
438 }
439
440
Bind(RawMachineLabel * label)441 void RawMachineAssembler::Bind(RawMachineLabel* label) {
442 DCHECK(current_block_ == nullptr);
443 DCHECK(!label->bound_);
444 label->bound_ = true;
445 current_block_ = EnsureBlock(label);
446 current_block_->set_deferred(label->deferred_);
447 }
448
449
Use(RawMachineLabel * label)450 BasicBlock* RawMachineAssembler::Use(RawMachineLabel* label) {
451 label->used_ = true;
452 return EnsureBlock(label);
453 }
454
455
EnsureBlock(RawMachineLabel * label)456 BasicBlock* RawMachineAssembler::EnsureBlock(RawMachineLabel* label) {
457 if (label->block_ == nullptr) label->block_ = schedule()->NewBasicBlock();
458 return label->block_;
459 }
460
461
CurrentBlock()462 BasicBlock* RawMachineAssembler::CurrentBlock() {
463 DCHECK(current_block_);
464 return current_block_;
465 }
466
Phi(MachineRepresentation rep,int input_count,Node * const * inputs)467 Node* RawMachineAssembler::Phi(MachineRepresentation rep, int input_count,
468 Node* const* inputs) {
469 Node** buffer = new (zone()->New(sizeof(Node*) * (input_count + 1)))
470 Node*[input_count + 1];
471 std::copy(inputs, inputs + input_count, buffer);
472 buffer[input_count] = graph()->start();
473 return AddNode(common()->Phi(rep, input_count), input_count + 1, buffer);
474 }
475
AppendPhiInput(Node * phi,Node * new_input)476 void RawMachineAssembler::AppendPhiInput(Node* phi, Node* new_input) {
477 const Operator* op = phi->op();
478 const Operator* new_op = common()->ResizeMergeOrPhi(op, phi->InputCount());
479 phi->InsertInput(zone(), phi->InputCount() - 1, new_input);
480 NodeProperties::ChangeOp(phi, new_op);
481 }
482
AddNode(const Operator * op,int input_count,Node * const * inputs)483 Node* RawMachineAssembler::AddNode(const Operator* op, int input_count,
484 Node* const* inputs) {
485 DCHECK_NOT_NULL(schedule_);
486 DCHECK_NOT_NULL(current_block_);
487 Node* node = MakeNode(op, input_count, inputs);
488 schedule()->AddNode(CurrentBlock(), node);
489 return node;
490 }
491
MakeNode(const Operator * op,int input_count,Node * const * inputs)492 Node* RawMachineAssembler::MakeNode(const Operator* op, int input_count,
493 Node* const* inputs) {
494 // The raw machine assembler nodes do not have effect and control inputs,
495 // so we disable checking input counts here.
496 return graph()->NewNodeUnchecked(op, input_count, inputs);
497 }
498
~RawMachineLabel()499 RawMachineLabel::~RawMachineLabel() { DCHECK(bound_ || !used_); }
500
501 } // namespace compiler
502 } // namespace internal
503 } // namespace v8
504