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

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