Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(625)

Side by Side Diff: src/compiler/bytecode-graph-builder.cc

Issue 1291693004: [Interpreter] Bytecode graph builder (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Incorporate comments on patch set 9. Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/compiler/bytecode-graph-builder.h ('k') | src/compiler/pipeline.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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/bytecode-graph-builder.h"
6
7 #include "src/compiler/linkage.h"
8 #include "src/compiler/operator-properties.h"
9 #include "src/interpreter/bytecode-array-iterator.h"
10
11 namespace v8 {
12 namespace internal {
13 namespace compiler {
14
15 const int BytecodeGraphBuilder::Environment::kParameterStartIndex = 1;
16
17 // Issues:
18 // - Need to deal with FrameState / FrameStateBeforeAndAfter / StateValue.
19 // - Scopes - intimately tied to AST. Need to eval what is needed.
20 // - Need story for context parameter, closure parameter, this.
21 // * GetFunctionClosureForContext()
22 // * GetFunctionClosure()
23 BytecodeGraphBuilder::Environment::Environment(BytecodeGraphBuilder* builder,
24 int register_count,
25 int parameter_count,
26 Node* control_dependency,
27 Node* context)
28 : builder_(builder),
29 register_count_(register_count),
30 parameter_count_(parameter_count),
31 context_(context),
32 control_dependency_(control_dependency),
33 effect_dependency_(control_dependency),
34 values_(builder->local_zone()) {
35 // The layout of values_ is:
36 //
37 // [receiver] [parameters] [registers]
38 //
39 // parameter[0] is 'this', parameters 1..N are the parameters
40 // supplied to the method (arg0..argN-1). The accumulator is stored
41 // separately.
42
43 // Receiver
44 // TODO(oth) resolve appropriate constant for receiver rather than -1.
45 // Candidate:- Linkage::kJSFunctionCallClosureParamIndex
Michael Starzinger 2015/09/04 16:35:50 Nope, not a candidate!
46 const Operator* receiver_op = common()->Parameter(-1, nullptr);
Michael Starzinger 2015/09/04 16:46:58 Something is highly fishy here. Parameter(0) shoul
oth 2015/09/07 08:40:15 Right, I think we got confused by the wording of t
Michael Starzinger 2015/09/07 09:51:31 Looks good now.
47 Node* receiver = builder->graph()->NewNode(receiver_op, graph()->start());
48 values()->push_back(receiver);
49
50 // Parameters
51 DCHECK_EQ(values()->size(), kParameterStartIndex);
52 for (int i = 0; i < parameter_count; i++) {
53 const Operator* op = common()->Parameter(i, nullptr);
54 Node* parameter = builder->graph()->NewNode(op, graph()->start());
55 values()->push_back(parameter);
56 }
57
58 // Registers
59 register_base_ = static_cast<int>(values()->size());
60 Node* undefined_constant = builder->jsgraph()->UndefinedConstant();
61 values()->insert(values()->end(), register_count, undefined_constant);
62
63 // Accumulator
64 accumulator_ = undefined_constant;
65 }
66
67
68 int BytecodeGraphBuilder::Environment::RegisterToValuesIndex(
69 interpreter::Register the_register) const {
70 if (the_register.is_parameter()) {
71 int parameter_index = the_register.ToParameterIndex(parameter_count());
72 return kParameterStartIndex + parameter_index;
73 } else {
74 return the_register.index() + register_base();
75 }
76 }
77
78
79 void BytecodeGraphBuilder::Environment::BindRegister(
80 interpreter::Register the_register, Node* node) {
81 int values_index = RegisterToValuesIndex(the_register);
82 values()->at(values_index) = node;
83 }
84
85
86 Node* BytecodeGraphBuilder::Environment::LookupRegister(
87 interpreter::Register the_register) const {
88 int values_index = RegisterToValuesIndex(the_register);
89 return values()->at(values_index);
90 }
91
92
93 void BytecodeGraphBuilder::Environment::BindAccumulator(Node* node) {
94 accumulator_ = node;
95 }
96
97
98 Node* BytecodeGraphBuilder::Environment::LookupAccumulator() const {
99 return accumulator_;
100 }
101
102
103 bool BytecodeGraphBuilder::Environment::IsMarkedAsUnreachable() const {
104 return GetControlDependency()->opcode() == IrOpcode::kDead;
105 }
106
107
108 void BytecodeGraphBuilder::Environment::MarkAsUnreachable() {
109 UpdateControlDependency(builder()->jsgraph()->Dead());
110 }
111
112
113 BytecodeGraphBuilder::BytecodeGraphBuilder(Zone* local_zone,
114 CompilationInfo* compilation_info,
115 JSGraph* jsgraph)
116 : local_zone_(local_zone),
117 info_(compilation_info),
118 jsgraph_(jsgraph),
119 input_buffer_size_(0),
120 input_buffer_(nullptr),
121 exit_controls_(local_zone) {
122 bytecode_array_ = handle(info()->shared_info()->bytecode_array());
123 }
124
125
126 Node* BytecodeGraphBuilder::GetFunctionContext() {
127 if (!function_context_.is_set()) {
128 // Parameter (arity + 1) is special for the outer context of the function
129 const Operator* op = common()->Parameter(
130 info()->num_parameters_including_this(), "%context");
131 Node* node = NewNode(op, graph()->start());
132 function_context_.set(node);
133 }
134 return function_context_.get();
135 }
136
137
138 bool BytecodeGraphBuilder::CreateGraph(bool stack_check) {
139 // Set up the basic structure of the graph. Outputs for {Start} are
140 // the formal parameters (including the receiver) plus context and
141 // closure.
142
143 // The additional count items are for the context and closure.
144 int actual_parameter_count = bytecode_array()->parameter_count() + 2;
145 graph()->SetStart(graph()->NewNode(common()->Start(actual_parameter_count)));
146
147 int register_count = bytecode_array()->register_count();
148 Environment env(this, register_count, actual_parameter_count,
149 graph()->start(), GetFunctionContext());
150 set_environment(&env);
151
152 // Build function context only if there are context allocated variables.
153 if (info()->num_heap_slots() > 0) {
154 UNIMPLEMENTED(); // write ast-graph-builder equivalent.
155 } else {
156 // Simply use the outer function context in building the graph.
157 CreateGraphBody(stack_check);
158 }
159
160 // Finish the basic structure of the graph.
161 DCHECK_NE(0u, exit_controls_.size());
162 int const input_count = static_cast<int>(exit_controls_.size());
163 Node** const inputs = &exit_controls_.front();
164 Node* end = graph()->NewNode(common()->End(input_count), input_count, inputs);
165 graph()->SetEnd(end);
166
167 return true;
168 }
169
170
171 void BytecodeGraphBuilder::CreateGraphBody(bool stack_check) {
172 // TODO(oth): review ast-graph-builder equivalent, i.e. arguments
173 // object setup, this function variable if used, tracing hooks.
174 VisitBytecodes();
175 }
176
177
178 void BytecodeGraphBuilder::VisitBytecodes() {
179 interpreter::BytecodeArrayIterator iterator(bytecode_array());
180 while (!iterator.done()) {
181 switch (iterator.current_bytecode()) {
182 #define BYTECODE_CASE(name, ...) \
183 case interpreter::Bytecode::k##name: \
184 Visit##name(iterator); \
185 break;
186 BYTECODE_LIST(BYTECODE_CASE)
187 #undef BYTECODE_CODE
188 }
189 iterator.Advance();
190 }
191 }
192
193
194 void BytecodeGraphBuilder::VisitLdaZero(
195 const interpreter::BytecodeArrayIterator& iterator) {
196 Node* node = jsgraph()->ZeroConstant();
197 environment()->BindAccumulator(node);
198 }
199
200
201 void BytecodeGraphBuilder::VisitLdaSmi8(
202 const interpreter::BytecodeArrayIterator& iterator) {
203 Node* node = jsgraph()->Constant(iterator.GetSmi8Operand(0));
204 environment()->BindAccumulator(node);
205 }
206
207
208 void BytecodeGraphBuilder::VisitLdaConstant(
209 const interpreter::BytecodeArrayIterator& iterator) {
210 Node* node = jsgraph()->Constant(iterator.GetConstantForIndexOperand(0));
211 environment()->BindAccumulator(node);
212 }
213
214
215 void BytecodeGraphBuilder::VisitLdaUndefined(
216 const interpreter::BytecodeArrayIterator& iterator) {
217 Node* node = jsgraph()->UndefinedConstant();
218 environment()->BindAccumulator(node);
219 }
220
221
222 void BytecodeGraphBuilder::VisitLdaNull(
223 const interpreter::BytecodeArrayIterator& iterator) {
224 Node* node = jsgraph()->NullConstant();
225 environment()->BindAccumulator(node);
226 }
227
228
229 void BytecodeGraphBuilder::VisitLdaTheHole(
230 const interpreter::BytecodeArrayIterator& iterator) {
231 Node* node = jsgraph()->TheHoleConstant();
232 environment()->BindAccumulator(node);
233 }
234
235
236 void BytecodeGraphBuilder::VisitLdaTrue(
237 const interpreter::BytecodeArrayIterator& iterator) {
238 Node* node = jsgraph()->TrueConstant();
239 environment()->BindAccumulator(node);
240 }
241
242
243 void BytecodeGraphBuilder::VisitLdaFalse(
244 const interpreter::BytecodeArrayIterator& iterator) {
245 Node* node = jsgraph()->FalseConstant();
246 environment()->BindAccumulator(node);
247 }
248
249
250 void BytecodeGraphBuilder::VisitLdar(
251 const interpreter::BytecodeArrayIterator& iterator) {
252 Node* value = environment()->LookupRegister(iterator.GetRegisterOperand(0));
253 environment()->BindAccumulator(value);
254 }
255
256
257 void BytecodeGraphBuilder::VisitStar(
258 const interpreter::BytecodeArrayIterator& iterator) {
259 Node* value = environment()->LookupAccumulator();
260 environment()->BindRegister(iterator.GetRegisterOperand(0), value);
261 }
262
263
264 void BytecodeGraphBuilder::BuildBinaryOp(
265 const Operator* js_op, const interpreter::BytecodeArrayIterator& iterator) {
266 Node* left = environment()->LookupRegister(iterator.GetRegisterOperand(0));
267 Node* right = environment()->LookupAccumulator();
268 Node* node = NewNode(js_op, left, right);
269
270 // TODO(oth): Real frame state and environment check pointing.
271 int frame_state_count =
272 OperatorProperties::GetFrameStateInputCount(node->op());
273 for (int i = 0; i < frame_state_count; i++) {
274 NodeProperties::ReplaceFrameStateInput(node, i,
275 jsgraph()->EmptyFrameState());
276 }
277 environment()->BindAccumulator(node);
278 }
279
280
281 void BytecodeGraphBuilder::VisitAdd(
282 const interpreter::BytecodeArrayIterator& iterator) {
283 BuildBinaryOp(javascript()->Add(language_mode()), iterator);
284 }
285
286
287 void BytecodeGraphBuilder::VisitSub(
288 const interpreter::BytecodeArrayIterator& iterator) {
289 BuildBinaryOp(javascript()->Subtract(language_mode()), iterator);
290 }
291
292
293 void BytecodeGraphBuilder::VisitMul(
294 const interpreter::BytecodeArrayIterator& iterator) {
295 BuildBinaryOp(javascript()->Multiply(language_mode()), iterator);
296 }
297
298
299 void BytecodeGraphBuilder::VisitDiv(
300 const interpreter::BytecodeArrayIterator& iterator) {
301 BuildBinaryOp(javascript()->Divide(language_mode()), iterator);
302 }
303
304
305 void BytecodeGraphBuilder::VisitMod(
306 const interpreter::BytecodeArrayIterator& iterator) {
307 BuildBinaryOp(javascript()->Modulus(language_mode()), iterator);
308 }
309
310
311 void BytecodeGraphBuilder::VisitReturn(
312 const interpreter::BytecodeArrayIterator& iterator) {
313 Node* control =
314 NewNode(common()->Return(), environment()->LookupAccumulator());
315 UpdateControlDependencyToLeaveFunction(control);
316 }
317
318
319 void BytecodeGraphBuilder::VisitLoadIC(
320 const interpreter::BytecodeArrayIterator& iterator) {
321 UNIMPLEMENTED();
322 }
323
324
325 void BytecodeGraphBuilder::VisitKeyedLoadIC(
326 const interpreter::BytecodeArrayIterator& iterator) {
327 UNIMPLEMENTED();
328 }
329
330
331 Node** BytecodeGraphBuilder::EnsureInputBufferSize(int size) {
332 if (size > input_buffer_size_) {
333 size = size + kInputBufferSizeIncrement + input_buffer_size_;
334 input_buffer_ = local_zone()->NewArray<Node*>(size);
335 input_buffer_size_ = size;
336 }
337 return input_buffer_;
338 }
339
340
341 Node* BytecodeGraphBuilder::MakeNode(const Operator* op, int value_input_count,
342 Node** value_inputs, bool incomplete) {
343 DCHECK_EQ(op->ValueInputCount(), value_input_count);
344
345 bool has_context = OperatorProperties::HasContextInput(op);
346 int frame_state_count = OperatorProperties::GetFrameStateInputCount(op);
347 bool has_control = op->ControlInputCount() == 1;
348 bool has_effect = op->EffectInputCount() == 1;
349
350 DCHECK_LT(op->ControlInputCount(), 2);
351 DCHECK_LT(op->EffectInputCount(), 2);
352
353 Node* result = NULL;
354 if (!has_context && frame_state_count == 0 && !has_control && !has_effect) {
355 result = graph()->NewNode(op, value_input_count, value_inputs, incomplete);
356 } else {
357 int input_count_with_deps = value_input_count;
358 if (has_context) ++input_count_with_deps;
359 input_count_with_deps += frame_state_count;
360 if (has_control) ++input_count_with_deps;
361 if (has_effect) ++input_count_with_deps;
362 Node** buffer = EnsureInputBufferSize(input_count_with_deps);
363 memcpy(buffer, value_inputs, kPointerSize * value_input_count);
364 Node** current_input = buffer + value_input_count;
365 if (has_context) {
366 *current_input++ = environment()->Context();
367 }
368 for (int i = 0; i < frame_state_count; i++) {
369 // The frame state will be inserted later. Here we misuse
370 // the {Dead} node as a sentinel to be later overwritten
371 // with the real frame state.
372 *current_input++ = jsgraph()->Dead();
373 }
374 if (has_effect) {
375 *current_input++ = environment()->GetEffectDependency();
376 }
377 if (has_control) {
378 *current_input++ = environment()->GetControlDependency();
379 }
380 result = graph()->NewNode(op, input_count_with_deps, buffer, incomplete);
381 if (!environment()->IsMarkedAsUnreachable()) {
382 // Update the current control dependency for control-producing nodes.
383 if (NodeProperties::IsControl(result)) {
384 environment()->UpdateControlDependency(result);
385 }
386 // Update the current effect dependency for effect-producing nodes.
387 if (result->op()->EffectOutputCount() > 0) {
388 environment()->UpdateEffectDependency(result);
389 }
390 // Add implicit success continuation for throwing nodes.
391 if (!result->op()->HasProperty(Operator::kNoThrow)) {
392 const Operator* op = common()->IfSuccess();
393 Node* on_success = graph()->NewNode(op, result);
394 environment_->UpdateControlDependency(on_success);
395 }
396 }
397 }
398
399 return result;
400 }
401
402
403 Node* BytecodeGraphBuilder::MergeControl(Node* control, Node* other) {
404 int inputs = control->op()->ControlInputCount() + 1;
405 if (control->opcode() == IrOpcode::kLoop) {
406 // Control node for loop exists, add input.
407 const Operator* op = common()->Loop(inputs);
408 control->AppendInput(graph_zone(), other);
409 control->set_op(op);
410 } else if (control->opcode() == IrOpcode::kMerge) {
411 // Control node for merge exists, add input.
412 const Operator* op = common()->Merge(inputs);
413 control->AppendInput(graph_zone(), other);
414 control->set_op(op);
415 } else {
416 // Control node is a singleton, introduce a merge.
417 const Operator* op = common()->Merge(inputs);
418 Node* inputs[] = {control, other};
419 control = graph()->NewNode(op, arraysize(inputs), inputs, true);
420 }
421 return control;
422 }
423
424
425 void BytecodeGraphBuilder::UpdateControlDependencyToLeaveFunction(Node* exit) {
426 if (environment()->IsMarkedAsUnreachable()) return;
427 environment()->MarkAsUnreachable();
428 exit_controls_.push_back(exit);
429 }
430
431 } // namespace compiler
432 } // namespace internal
433 } // namespace v8
OLDNEW
« no previous file with comments | « src/compiler/bytecode-graph-builder.h ('k') | src/compiler/pipeline.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698