OLD | NEW |
---|---|
1 // Copyright 2015 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/compiler/code-stub-assembler.h" | 5 #include "src/compiler/code-stub-assembler.h" |
6 | 6 |
7 #include <ostream> | 7 #include <ostream> |
8 | 8 |
9 #include "src/code-factory.h" | 9 #include "src/code-factory.h" |
10 #include "src/compiler/graph.h" | 10 #include "src/compiler/graph.h" |
11 #include "src/compiler/instruction-selector.h" | 11 #include "src/compiler/instruction-selector.h" |
12 #include "src/compiler/linkage.h" | 12 #include "src/compiler/linkage.h" |
13 #include "src/compiler/pipeline.h" | 13 #include "src/compiler/pipeline.h" |
14 #include "src/compiler/raw-machine-assembler.h" | 14 #include "src/compiler/raw-machine-assembler.h" |
15 #include "src/compiler/schedule.h" | 15 #include "src/compiler/schedule.h" |
16 #include "src/frames.h" | 16 #include "src/frames.h" |
17 #include "src/interface-descriptors.h" | 17 #include "src/interface-descriptors.h" |
18 #include "src/interpreter/bytecodes.h" | 18 #include "src/interpreter/bytecodes.h" |
19 #include "src/machine-type.h" | 19 #include "src/machine-type.h" |
20 #include "src/macro-assembler.h" | 20 #include "src/macro-assembler.h" |
21 #include "src/zone.h" | 21 #include "src/zone.h" |
22 | 22 |
23 namespace v8 { | 23 namespace v8 { |
24 namespace internal { | 24 namespace internal { |
25 namespace compiler { | 25 namespace compiler { |
26 | 26 |
27 | |
28 CodeStubAssembler::CodeStubAssembler(Isolate* isolate, Zone* zone, | 27 CodeStubAssembler::CodeStubAssembler(Isolate* isolate, Zone* zone, |
29 const CallInterfaceDescriptor& descriptor, | 28 const CallInterfaceDescriptor& descriptor, |
30 Code::Flags flags, const char* name) | 29 Code::Flags flags, const char* name) |
31 : raw_assembler_(new RawMachineAssembler( | 30 : raw_assembler_(new RawMachineAssembler( |
32 isolate, new (zone) Graph(zone), | 31 isolate, new (zone) Graph(zone), |
33 Linkage::GetStubCallDescriptor(isolate, zone, descriptor, 0, | 32 Linkage::GetStubCallDescriptor(isolate, zone, descriptor, 0, |
34 CallDescriptor::kNoFlags))), | 33 CallDescriptor::kNoFlags))), |
35 flags_(flags), | 34 flags_(flags), |
36 name_(name), | 35 name_(name), |
37 code_generated_(false) {} | 36 code_generated_(false), |
38 | 37 vars_(zone) {} |
39 | 38 |
40 CodeStubAssembler::~CodeStubAssembler() {} | 39 CodeStubAssembler::~CodeStubAssembler() {} |
41 | 40 |
42 | 41 |
43 Handle<Code> CodeStubAssembler::GenerateCode() { | 42 Handle<Code> CodeStubAssembler::GenerateCode() { |
44 DCHECK(!code_generated_); | 43 DCHECK(!code_generated_); |
45 | 44 |
46 Schedule* schedule = raw_assembler_->Export(); | 45 Schedule* schedule = raw_assembler_->Export(); |
47 Handle<Code> code = Pipeline::GenerateCodeForCodeStub( | 46 Handle<Code> code = Pipeline::GenerateCodeForCodeStub( |
48 isolate(), raw_assembler_->call_descriptor(), graph(), schedule, flags_, | 47 isolate(), raw_assembler_->call_descriptor(), graph(), schedule, flags_, |
(...skipping 21 matching lines...) Expand all Loading... | |
70 | 69 |
71 Node* CodeStubAssembler::HeapConstant(Handle<HeapObject> object) { | 70 Node* CodeStubAssembler::HeapConstant(Handle<HeapObject> object) { |
72 return raw_assembler_->HeapConstant(object); | 71 return raw_assembler_->HeapConstant(object); |
73 } | 72 } |
74 | 73 |
75 | 74 |
76 Node* CodeStubAssembler::BooleanConstant(bool value) { | 75 Node* CodeStubAssembler::BooleanConstant(bool value) { |
77 return raw_assembler_->BooleanConstant(value); | 76 return raw_assembler_->BooleanConstant(value); |
78 } | 77 } |
79 | 78 |
79 Node* CodeStubAssembler::ExternalConstant(ExternalReference address) { | |
80 return raw_assembler_->ExternalConstant(address); | |
81 } | |
80 | 82 |
81 Node* CodeStubAssembler::Parameter(int value) { | 83 Node* CodeStubAssembler::Parameter(int value) { |
82 return raw_assembler_->Parameter(value); | 84 return raw_assembler_->Parameter(value); |
83 } | 85 } |
84 | 86 |
85 | 87 |
86 void CodeStubAssembler::Return(Node* value) { | 88 void CodeStubAssembler::Return(Node* value) { |
87 return raw_assembler_->Return(value); | 89 return raw_assembler_->Return(value); |
88 } | 90 } |
89 | 91 |
92 void CodeStubAssembler::Bind(CodeStubAssembler::Label* label) { | |
93 return label->Bind(); | |
94 } | |
95 | |
96 Node* CodeStubAssembler::LoadFramePointer() { | |
97 return raw_assembler_->LoadFramePointer(); | |
98 } | |
90 | 99 |
91 Node* CodeStubAssembler::SmiShiftBitsConstant() { | 100 Node* CodeStubAssembler::SmiShiftBitsConstant() { |
92 return Int32Constant(kSmiShiftSize + kSmiTagSize); | 101 return Int32Constant(kSmiShiftSize + kSmiTagSize); |
93 } | 102 } |
94 | 103 |
95 | 104 |
96 Node* CodeStubAssembler::SmiTag(Node* value) { | 105 Node* CodeStubAssembler::SmiTag(Node* value) { |
97 return raw_assembler_->WordShl(value, SmiShiftBitsConstant()); | 106 return raw_assembler_->WordShl(value, SmiShiftBitsConstant()); |
98 } | 107 } |
99 | 108 |
100 | 109 |
101 Node* CodeStubAssembler::SmiUntag(Node* value) { | 110 Node* CodeStubAssembler::SmiUntag(Node* value) { |
102 return raw_assembler_->WordSar(value, SmiShiftBitsConstant()); | 111 return raw_assembler_->WordSar(value, SmiShiftBitsConstant()); |
103 } | 112 } |
104 | 113 |
105 | 114 #define DEFINE_CODE_STUB_ASSEMBER_BINARY_OP(name) \ |
106 Node* CodeStubAssembler::IntPtrAdd(Node* a, Node* b) { | 115 Node* CodeStubAssembler::name(Node* a, Node* b) { \ |
107 return raw_assembler_->IntPtrAdd(a, b); | 116 return raw_assembler_->name(a, b); \ |
108 } | 117 } |
109 | 118 CODE_STUB_ASSEMBLER_BINARY_OP_LIST(DEFINE_CODE_STUB_ASSEMBER_BINARY_OP) |
110 | 119 #undef DEFINE_CODE_STUB_ASSEMBER_BINARY_OP |
111 Node* CodeStubAssembler::IntPtrSub(Node* a, Node* b) { | |
112 return raw_assembler_->IntPtrSub(a, b); | |
113 } | |
114 | |
115 | 120 |
116 Node* CodeStubAssembler::WordShl(Node* value, int shift) { | 121 Node* CodeStubAssembler::WordShl(Node* value, int shift) { |
117 return raw_assembler_->WordShl(value, Int32Constant(shift)); | 122 return raw_assembler_->WordShl(value, Int32Constant(shift)); |
118 } | 123 } |
119 | 124 |
125 Node* CodeStubAssembler::WordIsSmi(Node* a) { | |
126 return WordEqual(raw_assembler_->WordAnd(a, Int32Constant(kSmiTagMask)), | |
127 Int32Constant(0)); | |
128 } | |
129 | |
130 Node* CodeStubAssembler::LoadBufferObject(Node* buffer, int offset) { | |
131 return raw_assembler_->Load(MachineType::AnyTagged(), buffer, | |
132 IntPtrConstant(offset)); | |
133 } | |
120 | 134 |
121 Node* CodeStubAssembler::LoadObjectField(Node* object, int offset) { | 135 Node* CodeStubAssembler::LoadObjectField(Node* object, int offset) { |
122 return raw_assembler_->Load(MachineType::AnyTagged(), object, | 136 return raw_assembler_->Load(MachineType::AnyTagged(), object, |
123 IntPtrConstant(offset - kHeapObjectTag)); | 137 IntPtrConstant(offset - kHeapObjectTag)); |
124 } | 138 } |
125 | 139 |
140 Node* CodeStubAssembler::LoadFixedArrayElementSmiIndex(Node* object, | |
141 Node* smi_index, | |
142 int additional_offset) { | |
143 Node* header_size = raw_assembler_->Int32Constant( | |
144 additional_offset + FixedArray::kHeaderSize - kHeapObjectTag); | |
145 Node* scaled_index = | |
146 (kSmiShiftSize == 0) | |
147 ? raw_assembler_->Word32Shl( | |
148 smi_index, Int32Constant(kPointerSizeLog2 - kSmiTagSize)) | |
149 : raw_assembler_->Word32Shl(SmiUntag(smi_index), | |
150 Int32Constant(kPointerSizeLog2)); | |
151 Node* offset = raw_assembler_->Int32Add(scaled_index, header_size); | |
152 return raw_assembler_->Load(MachineType::AnyTagged(), object, offset); | |
153 } | |
154 | |
155 Node* CodeStubAssembler::LoadFixedArrayElementConstantIndex(Node* object, | |
156 int index) { | |
157 Node* offset = raw_assembler_->Int32Constant( | |
158 FixedArray::kHeaderSize - kHeapObjectTag + index * kPointerSize); | |
159 return raw_assembler_->Load(MachineType::AnyTagged(), object, offset); | |
160 } | |
161 | |
162 Node* CodeStubAssembler::LoadRoot(Heap::RootListIndex root_index) { | |
163 if (isolate()->heap()->RootCanBeTreatedAsConstant(root_index)) { | |
164 Handle<Object> root = isolate()->heap()->root_handle(root_index); | |
165 if (root->IsSmi()) { | |
166 return Int32Constant(Handle<Smi>::cast(root)->value()); | |
167 } else { | |
168 return HeapConstant(Handle<HeapObject>::cast(root)); | |
169 } | |
170 } | |
171 | |
172 compiler::Node* roots_array_start = | |
173 ExternalConstant(ExternalReference::roots_array_start(isolate())); | |
174 USE(roots_array_start); | |
Michael Starzinger
2016/02/01 16:04:12
nit: Looks unimplemented, can we leave a TODO here
danno
2016/02/02 07:52:55
Done.
| |
175 | |
176 UNREACHABLE(); | |
177 return nullptr; | |
178 } | |
126 | 179 |
127 Node* CodeStubAssembler::CallN(CallDescriptor* descriptor, Node* code_target, | 180 Node* CodeStubAssembler::CallN(CallDescriptor* descriptor, Node* code_target, |
128 Node** args) { | 181 Node** args) { |
129 return raw_assembler_->CallN(descriptor, code_target, args); | 182 return raw_assembler_->CallN(descriptor, code_target, args); |
130 } | 183 } |
131 | 184 |
132 | 185 |
133 Node* CodeStubAssembler::TailCallN(CallDescriptor* descriptor, | 186 Node* CodeStubAssembler::TailCallN(CallDescriptor* descriptor, |
134 Node* code_target, Node** args) { | 187 Node* code_target, Node** args) { |
135 return raw_assembler_->TailCallN(descriptor, code_target, args); | 188 return raw_assembler_->TailCallN(descriptor, code_target, args); |
136 } | 189 } |
137 | 190 |
138 | 191 |
139 Node* CodeStubAssembler::CallRuntime(Runtime::FunctionId function_id, | 192 Node* CodeStubAssembler::CallRuntime(Runtime::FunctionId function_id, |
140 Node* context, Node* arg1) { | 193 Node* context, Node* arg1) { |
141 return raw_assembler_->CallRuntime1(function_id, arg1, context); | 194 return raw_assembler_->CallRuntime1(function_id, arg1, context); |
142 } | 195 } |
143 | 196 |
144 | 197 |
145 Node* CodeStubAssembler::CallRuntime(Runtime::FunctionId function_id, | 198 Node* CodeStubAssembler::CallRuntime(Runtime::FunctionId function_id, |
146 Node* context, Node* arg1, Node* arg2) { | 199 Node* context, Node* arg1, Node* arg2) { |
147 return raw_assembler_->CallRuntime2(function_id, arg1, arg2, context); | 200 return raw_assembler_->CallRuntime2(function_id, arg1, arg2, context); |
148 } | 201 } |
149 | 202 |
150 | |
151 Node* CodeStubAssembler::TailCallRuntime(Runtime::FunctionId function_id, | 203 Node* CodeStubAssembler::TailCallRuntime(Runtime::FunctionId function_id, |
152 Node* context, Node* arg1) { | 204 Node* arg1, Node* context) { |
153 return raw_assembler_->TailCallRuntime1(function_id, arg1, context); | 205 return raw_assembler_->TailCallRuntime1(function_id, arg1, context); |
154 } | 206 } |
155 | 207 |
156 | |
157 Node* CodeStubAssembler::TailCallRuntime(Runtime::FunctionId function_id, | 208 Node* CodeStubAssembler::TailCallRuntime(Runtime::FunctionId function_id, |
158 Node* context, Node* arg1, | 209 Node* arg1, Node* arg2, |
159 Node* arg2) { | 210 Node* context) { |
160 return raw_assembler_->TailCallRuntime2(function_id, arg1, arg2, context); | 211 return raw_assembler_->TailCallRuntime2(function_id, arg1, arg2, context); |
161 } | 212 } |
162 | 213 |
214 Node* CodeStubAssembler::TailCallRuntime(Runtime::FunctionId function_id, | |
215 Node* arg1, Node* arg2, Node* arg3, | |
216 Node* context) { | |
217 return raw_assembler_->TailCallRuntime3(function_id, arg1, arg2, arg3, | |
218 context); | |
219 } | |
220 | |
221 Node* CodeStubAssembler::TailCallRuntime(Runtime::FunctionId function_id, | |
222 Node* arg1, Node* arg2, Node* arg3, | |
223 Node* arg4, Node* context) { | |
224 return raw_assembler_->TailCallRuntime4(function_id, arg1, arg2, arg3, arg4, | |
225 context); | |
226 } | |
227 | |
228 Node* CodeStubAssembler::TailCallStub(CodeStub& stub, Node** args) { | |
229 Node* code_target = HeapConstant(stub.GetCode()); | |
230 CallDescriptor* descriptor = Linkage::GetStubCallDescriptor( | |
231 isolate(), zone(), stub.GetCallInterfaceDescriptor(), | |
232 stub.GetStackParameterCount(), CallDescriptor::kSupportsTailCalls); | |
233 return raw_assembler_->TailCallN(descriptor, code_target, args); | |
234 } | |
235 | |
236 Node* CodeStubAssembler::TailCall( | |
237 const CallInterfaceDescriptor& interface_descriptor, Node* code_target, | |
238 Node** args) { | |
239 CallDescriptor* descriptor = Linkage::GetStubCallDescriptor( | |
240 isolate(), zone(), interface_descriptor, | |
241 interface_descriptor.GetStackParameterCount(), | |
242 CallDescriptor::kSupportsTailCalls); | |
243 return raw_assembler_->TailCallN(descriptor, code_target, args); | |
244 } | |
245 | |
246 void CodeStubAssembler::Goto(CodeStubAssembler::Label* label) { | |
247 label->MergeVariables(); | |
248 raw_assembler_->Goto(label->label_); | |
249 } | |
250 | |
251 void CodeStubAssembler::Branch(Node* condition, | |
252 CodeStubAssembler::Label* true_label, | |
253 CodeStubAssembler::Label* false_label) { | |
254 true_label->MergeVariables(); | |
255 false_label->MergeVariables(); | |
256 return raw_assembler_->Branch(condition, true_label->label_, | |
257 false_label->label_); | |
258 } | |
259 | |
260 void CodeStubAssembler::Switch(Node* index, Label* default_label, | |
261 int32_t* case_values, Label** case_labels, | |
262 size_t case_count) { | |
263 RawMachineLabel** labels = | |
264 new (zone()->New(sizeof(RawMachineLabel*) * case_count)) | |
265 RawMachineLabel*[case_count]; | |
266 for (int i = 0; i < case_count; ++i) { | |
267 labels[i] = case_labels[i]->label_; | |
268 case_labels[i]->MergeVariables(); | |
269 default_label->MergeVariables(); | |
270 } | |
271 return raw_assembler_->Switch(index, default_label->label_, case_values, | |
272 labels, case_count); | |
273 } | |
163 | 274 |
164 // RawMachineAssembler delegate helpers: | 275 // RawMachineAssembler delegate helpers: |
165 Isolate* CodeStubAssembler::isolate() { return raw_assembler_->isolate(); } | 276 Isolate* CodeStubAssembler::isolate() { return raw_assembler_->isolate(); } |
166 | 277 |
167 | 278 |
168 Graph* CodeStubAssembler::graph() { return raw_assembler_->graph(); } | 279 Graph* CodeStubAssembler::graph() { return raw_assembler_->graph(); } |
169 | 280 |
170 | 281 |
171 Zone* CodeStubAssembler::zone() { return raw_assembler_->zone(); } | 282 Zone* CodeStubAssembler::zone() { return raw_assembler_->zone(); } |
172 | 283 |
284 CodeStubAssembler::Variable::Variable(CodeStubAssembler* assembler, | |
285 MachineRepresentation rep) | |
286 : impl_(new (assembler->zone()) Impl(rep)) { | |
287 assembler->vars_.push_back(impl_); | |
288 } | |
289 | |
290 CodeStubAssembler::Label::Label(CodeStubAssembler* assembler) | |
291 : bound_(false), merge_count_(0), assembler_(assembler), label_(nullptr) { | |
292 void* buffer = assembler->zone()->New(sizeof(RawMachineLabel)); | |
293 label_ = new (buffer) RawMachineLabel(); | |
294 } | |
295 | |
296 CodeStubAssembler::Label::Label(CodeStubAssembler* assembler, | |
297 int merged_value_count, | |
298 CodeStubAssembler::Variable** merged_variables) | |
299 : bound_(false), merge_count_(0), assembler_(assembler), label_(nullptr) { | |
300 void* buffer = assembler->zone()->New(sizeof(RawMachineLabel)); | |
301 label_ = new (buffer) RawMachineLabel(); | |
302 for (int i = 0; i < merged_value_count; ++i) { | |
303 variable_phis_[merged_variables[i]->impl_] = nullptr; | |
304 } | |
305 } | |
306 | |
307 CodeStubAssembler::Label::Label(CodeStubAssembler* assembler, | |
308 CodeStubAssembler::Variable* merged_variable) | |
309 : CodeStubAssembler::Label(assembler, 1, &merged_variable) {} | |
310 | |
311 void CodeStubAssembler::Label::MergeVariables() { | |
312 ++merge_count_; | |
313 for (auto var : assembler_->vars_) { | |
314 size_t count = 0; | |
315 Node* node = var->value_; | |
316 if (node != nullptr) { | |
317 auto i = variable_merges_.find(var); | |
318 if (i != variable_merges_.end()) { | |
319 DCHECK(node->id() >= 0); | |
Michael Starzinger
2016/02/01 16:04:12
nit: DCHECK_GE
danno
2016/02/02 07:52:55
Done.
| |
320 i->second.push_back(node); | |
321 count = i->second.size(); | |
322 } else { | |
323 count = 1; | |
324 variable_merges_[var] = std::vector<Node*>(1, node); | |
325 } | |
326 } | |
327 // If the following asserts, then you've jumped to a label without a bound | |
328 // variable along that path that expects to merge its value into a phi. | |
329 auto phi = variable_phis_.find(var); | |
330 DCHECK(phi == variable_phis_.end() || count == merge_count_); | |
331 | |
332 // If the label is already bound, we already know the set of variables to | |
333 // merge and phi nodes have already been created. | |
334 if (bound_) { | |
335 if (phi != variable_phis_.end()) { | |
336 DCHECK(phi->second != nullptr); | |
337 assembler_->raw_assembler_->AppendPhiInput(phi->second, node); | |
338 } else { | |
339 auto i = variable_merges_.find(var); | |
340 USE(i); | |
341 // If the following assert fires, then you've declared a variable that | |
342 // has the same bound value along all paths up until the point you bound | |
343 // this label, but then later merged a path with a new value for the | |
344 // variable after the label bind (it's not possible to add phis to the | |
345 // bound label after the fact, just make sure to list the variable in | |
346 // the label's constructor's list of merged variables). | |
347 DCHECK(find_if(i->second.begin(), i->second.end(), | |
348 [node](Node* e) -> bool { return node != e; }) == | |
349 i->second.end()); | |
350 } | |
351 } | |
352 } | |
353 } | |
354 | |
355 void CodeStubAssembler::Label::Bind() { | |
356 DCHECK(!bound_); | |
357 assembler_->raw_assembler_->Bind(label_); | |
358 | |
359 // Make sure that all variables that have changed along any path up to this | |
360 // point are marked as merge variables. | |
361 for (auto var : assembler_->vars_) { | |
362 Node* shared_value = nullptr; | |
363 auto i = variable_merges_.find(var); | |
364 if (i != variable_merges_.end()) { | |
365 for (auto value : i->second) { | |
366 DCHECK(value != nullptr); | |
Michael Starzinger
2016/02/01 16:04:12
nit: DCHECK_NOT_NULL
danno
2016/02/02 07:52:55
Done.
| |
367 if (value != shared_value) { | |
368 if (shared_value == nullptr) { | |
369 shared_value = value; | |
370 } else { | |
371 variable_phis_[var] = nullptr; | |
372 } | |
373 } | |
374 } | |
375 } | |
376 } | |
377 | |
378 for (auto var : variable_phis_) { | |
379 CodeStubAssembler::Variable::Impl* var_impl = var.first; | |
380 auto i = variable_merges_.find(var_impl); | |
381 // If the following assert fires, then a variable that has been marked as | |
382 // being merged at the label--either by explicitly marking it so in the | |
383 // label constructor or by having seen different bound values at branches | |
384 // into the label--doesn't have a bound value along all of the paths that | |
385 // have been merged into the label up to this point. | |
386 DCHECK(i != variable_merges_.end() && i->second.size() == merge_count_); | |
387 Node* phi = assembler_->raw_assembler_->Phi( | |
388 var.first->rep_, static_cast<int>(merge_count_), &(i->second[0])); | |
389 variable_phis_[var_impl] = phi; | |
390 } | |
391 | |
392 // Bind all variables to a merge phi, the common value along all paths or | |
393 // null.. | |
394 for (auto var : assembler_->vars_) { | |
395 auto i = variable_phis_.find(var); | |
396 if (i != variable_phis_.end()) { | |
397 var->value_ = i->second; | |
398 } else { | |
399 auto j = variable_merges_.find(var); | |
400 if (j != variable_merges_.end() && j->second.size() == merge_count_) { | |
401 var->value_ = j->second.back(); | |
402 } else { | |
403 var->value_ = nullptr; | |
404 } | |
405 } | |
406 } | |
407 | |
408 bound_ = true; | |
409 } | |
173 | 410 |
174 } // namespace compiler | 411 } // namespace compiler |
175 } // namespace internal | 412 } // namespace internal |
176 } // namespace v8 | 413 } // namespace v8 |
OLD | NEW |