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

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: Remove dead code. 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
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/operator-properties.h"
8
9 namespace v8 {
10 namespace internal {
11 namespace compiler {
12
13 // Issues:
14 // - Need to deal with FrameState / FrameStateBeforeAndAfter / StateValue.
15 // - Scopes - intimately tied to AST. Need to eval what is needed.
16 // - Need story for context parameter, closure parameter, this.
17 // * GetFunctionClosureForContext()
18 // * GetFunctionClosure()
19 // * GetFunctionContext()
20 //
21 // NB Nodes talk slides: http://shortn/_fmVf0TjCC4
rmcilroy 2015/09/01 14:00:06 nit - probably remove the internal talk link
oth 2015/09/01 15:25:57 Done.
22
23 BytecodeGraphBuilder::Environment::Environment(BytecodeGraphBuilder* builder,
24 int locals_count,
25 Node* control_dependency)
26 : builder_(builder),
27 locals_count_(locals_count),
28 control_dependency_(control_dependency),
29 effect_dependency_(control_dependency),
30 values_(builder->local_zone()) {
31 //
32 // values_ layout
33 //
34 // [parameters] [receiver] [registers] [accumulator] [old registers]
35 //
36 // The accumulator is treated as a bytecode register. As values are
37 // overwritten, the old values are pushed to the back of the values
38 // array.
39 //
40 // TODO(oth): add support for parameters
41 //
42 register_base_ = values()->size();
43 Node* undefined_constant = builder->jsgraph()->UndefinedConstant();
44
45 values()->insert(values()->end(), locals_count, undefined_constant);
46 values()->push_back(undefined_constant);
rmcilroy 2015/09/01 14:00:06 nit - comment that this is the accumulator
oth 2015/09/01 15:25:57 Moved accumulator out of values per later review c
47 }
48
49
50 void BytecodeGraphBuilder::Environment::BindRegister(size_t register_index,
51 Node* node) {
52 size_t values_index = register_index + register_base();
53 values()->push_back(values()->at(values_index));
rmcilroy 2015/09/01 14:00:06 Do we need to keep the old register values around
oth 2015/09/01 15:25:57 Done.
54 values()->at(values_index) = node;
55 }
56
57
58 Node* BytecodeGraphBuilder::Environment::LookupRegister(
59 size_t register_index) const {
60 size_t values_index = register_index + register_base();
61 return values()->at(values_index);
62 }
63
64
65 void BytecodeGraphBuilder::Environment::BindAccumulator(Node* node) {
66 BindRegister(accumulator_pseudo_register(), node);
rmcilroy 2015/09/01 14:00:06 nit - could we just have a separate Node* accumula
oth 2015/09/01 15:25:57 Done.
67 }
68
69
70 Node* BytecodeGraphBuilder::Environment::LookupAccumulator() const {
71 return LookupRegister(accumulator_pseudo_register());
72 }
73
74
75 bool BytecodeGraphBuilder::Environment::IsMarkedAsUnreachable() const {
76 return GetControlDependency()->opcode() == IrOpcode::kDead;
77 }
78
79
80 void BytecodeGraphBuilder::Environment::MarkAsUnreachable() {
81 UpdateControlDependency(builder()->jsgraph()->Dead());
82 }
83
84
85 BytecodeGraphBuilder::BytecodeGraphBuilder(Zone* local_zone,
86 CompilationInfo* compilation_info,
87 JSGraph* jsgraph)
88 : local_zone_(local_zone),
89 info_(compilation_info),
90 jsgraph_(jsgraph),
91 exit_controls_(local_zone) {
92 bytecode_array_ = handle(info()->shared_info()->bytecode_array());
93 }
94
95
96 BytecodeGraphBuilder::BytecodeGraphBuilder(Zone* local_zone,
97 Handle<BytecodeArray> bytecode_array,
98 JSGraph* jsgraph)
99 : local_zone_(local_zone),
100 info_(nullptr),
101 jsgraph_(jsgraph),
102 bytecode_array_(bytecode_array),
103 input_buffer_size_(0),
104 input_buffer_(nullptr),
105 exit_controls_(local_zone) {}
106
107
108 bool BytecodeGraphBuilder::CreateGraph(bool stack_check) {
109 // Set up the basic structure of the graph. Outputs for {Start} are
110 // the formal parameters (including the receiver) plus context and
111 // closure.
112
113 int actual_parameter_count = info()->num_parameters_including_this() + 2;
114 graph()->SetStart(graph()->NewNode(common()->Start(actual_parameter_count)));
115
116 // Locals count are the explicitly named interpreter registers.
117 int locals_count = bytecode_array()->frame_size() / kPointerSize;
rmcilroy 2015/09/01 14:00:06 optional nit - you could add a locals_count() help
oth 2015/09/01 15:25:57 Done.
118 Environment env(this, locals_count, graph()->start());
119 set_environment(&env);
120
121 // Build function context only if there are context allocated variables.
122 if (info()->num_heap_slots() > 0) {
123 UNIMPLEMENTED(); // write ast-graph-builder equivalent.
124 } else {
125 // Simply use the outer function context in building the graph.
126 CreateGraphBody(stack_check);
127 }
128
129 // Finish the basic structure of the graph.
130 DCHECK_NE(0u, exit_controls_.size());
131 int const input_count = static_cast<int>(exit_controls_.size());
132 Node** const inputs = &exit_controls_.front();
133 Node* end = graph()->NewNode(common()->End(input_count), input_count, inputs);
134 graph()->SetEnd(end);
135
136 return true;
137 }
138
139
140 bool BytecodeGraphBuilder::CreateGraphForTest(bool stack_check) {
141 // Set up the basic structure of the graph. Outputs for {Start} are
142 // the formal parameters (including the receiver) plus context and
143 // closure.
144 int actual_parameter_count =
145 /* info()->num_parameters_including_this() */ 0 + 2;
146 graph()->SetStart(graph()->NewNode(common()->Start(actual_parameter_count)));
147
148 // Locals count are the explicitly named interpreter registers.
149 int locals_count = bytecode_array()->frame_size() / kPointerSize;
150 Environment env(this, locals_count, graph()->start());
151 set_environment(&env);
152
153 // Build function context only if there are context allocated variables.
154 // - Assume no context allocated variables.
155 // Simply use the outer function context in building the graph.
156 CreateGraphBody(stack_check);
157
158 // Finish the basic structure of the graph.
159 DCHECK_NE(0u, exit_controls_.size());
160 int const input_count = static_cast<int>(exit_controls_.size());
161 Node** const inputs = &exit_controls_.front();
162 Node* end = graph()->NewNode(common()->End(input_count), input_count, inputs);
163 graph()->SetEnd(end);
164
165 return true;
166 }
167
168
169 void BytecodeGraphBuilder::CreateGraphBody(bool stack_check) {
170 // TODO(oth): write ast-graph-builder equivalent.
rmcilroy 2015/09/01 14:00:06 not sure what this TODO means, could you add more
oth 2015/09/01 15:25:57 Done.
171 VisitBytecodes();
172 }
173
174
175 void BytecodeGraphBuilder::VisitBytecodes() {
176 int last_bytecode_length = 0;
177 for (int i = 0; i < bytecode_array()->length(); i += last_bytecode_length) {
178 interpreter::Bytecode bytecode = bytecode_at(i);
179 int operand_offset = i + 1;
180 switch (bytecode) {
181 #define BYTECODE_CASE(name, ...) \
182 case interpreter::Bytecode::k##name: \
183 Visit##name(operand_offset); \
184 break;
185 BYTECODE_LIST(BYTECODE_CASE)
186 #undef BYTECODE_CODE
187 }
188 last_bytecode_length = interpreter::Bytecodes::Size(bytecode);
189 }
190 }
191
192
193 void BytecodeGraphBuilder::VisitLdaZero(int operand_offset) {
194 Node* node = jsgraph()->ZeroConstant();
195 environment()->BindAccumulator(node);
196 }
197
198
199 void BytecodeGraphBuilder::VisitLdaSmi8(int operand_offset) {
200 Node* node = jsgraph()->Int32Constant(smi8_at(operand_offset));
201 environment()->BindAccumulator(node);
202 }
203
204
205 void BytecodeGraphBuilder::VisitLdaConstant(int operand_offset) {
206 Handle<FixedArray> constants = handle(bytecode_array()->constant_pool());
207 Handle<Object> constant = FixedArray::get(constants, operand_offset);
rmcilroy 2015/09/01 14:00:06 nit - create a helper for getting a given constant
oth 2015/09/01 15:25:57 Done. Noticed this code is broken anyway - it need
208 Node* node = jsgraph()->Constant(constant);
209 environment()->BindAccumulator(node);
210 }
211
212
213 void BytecodeGraphBuilder::VisitLdaUndefined(int operand_offset) {
214 Node* node = jsgraph()->UndefinedConstant();
215 environment()->BindAccumulator(node);
216 }
217
218
219 void BytecodeGraphBuilder::VisitLdaNull(int operand_offset) {
220 Node* node = jsgraph()->NullConstant();
221 environment()->BindAccumulator(node);
222 }
223
224
225 void BytecodeGraphBuilder::VisitLdaTheHole(int operand_offset) {
226 Node* node = jsgraph()->TheHoleConstant();
227 environment()->BindAccumulator(node);
228 }
229
230
231 void BytecodeGraphBuilder::VisitLdaTrue(int operand_offset) {
232 Node* node = jsgraph()->TrueConstant();
233 environment()->BindAccumulator(node);
234 }
235
236
237 void BytecodeGraphBuilder::VisitLdaFalse(int operand_offset) {
238 Node* node = jsgraph()->FalseConstant();
239 environment()->BindAccumulator(node);
240 }
241
242
243 void BytecodeGraphBuilder::VisitLdar(int operand_offset) {
244 Node* value = environment()->LookupRegister(register_at(operand_offset));
245 environment()->BindAccumulator(value);
246 }
247
248
249 void BytecodeGraphBuilder::VisitStar(int operand_offset) {
250 Node* value = environment()->LookupAccumulator();
251 environment()->BindRegister(register_at(operand_offset), value);
252 }
253
254
255 void BytecodeGraphBuilder::FinishBinaryOperation(Node* node) {
256 // What is the minimal work here?
257 // In the initial absence of:
258 // - FrameStateBeforeAndAfter / BailOutId
259 // - Environment check pointing
260 environment()->BindAccumulator(node);
261 }
262
263
264 void BytecodeGraphBuilder::VisitAdd(int operand_offset) {
265 const Operator* js_op = javascript()->Add(language_mode());
266 Node* left = environment()->LookupRegister(register_at(operand_offset));
267 Node* right = environment()->LookupAccumulator();
268 Node* node = NewNode(js_op, left, right);
269 FinishBinaryOperation(node);
270 }
271
272
273 void BytecodeGraphBuilder::VisitSub(int operand_offset) {
274 const Operator* js_op = javascript()->Subtract(language_mode());
275 Node* left = environment()->LookupRegister(register_at(operand_offset));
276 Node* right = environment()->LookupAccumulator();
277 Node* node = NewNode(js_op, left, right);
278 FinishBinaryOperation(node);
279 }
280
281
282 void BytecodeGraphBuilder::VisitMul(int operand_offset) {
283 const Operator* js_op = javascript()->Multiply(language_mode());
284 Node* left = environment()->LookupRegister(register_at(operand_offset));
285 Node* right = environment()->LookupAccumulator();
286 Node* node = NewNode(js_op, left, right);
287 FinishBinaryOperation(node);
288 }
289
290
291 void BytecodeGraphBuilder::VisitDiv(int operand_offset) {
292 const Operator* js_op = javascript()->Divide(language_mode());
293 Node* left = environment()->LookupRegister(register_at(operand_offset));
294 Node* right = environment()->LookupAccumulator();
295 Node* node = NewNode(js_op, left, right);
296 FinishBinaryOperation(node);
297 }
298
299
300 void BytecodeGraphBuilder::VisitMod(int operand_offset) {
301 const Operator* js_op = javascript()->Modulus(language_mode());
302 Node* left = environment()->LookupRegister(register_at(operand_offset));
303 Node* right = environment()->LookupAccumulator();
304 Node* node = NewNode(js_op, left, right);
305 FinishBinaryOperation(node);
306 }
307
308
309 void BytecodeGraphBuilder::VisitReturn(int operand_offset) {
310 Node* control =
311 NewNode(common()->Return(), environment()->LookupAccumulator());
312 UpdateControlDependencyToLeaveFunction(control);
313 }
314
315
316 Node** BytecodeGraphBuilder::EnsureInputBufferSize(int size) {
317 if (size > input_buffer_size_) {
318 size = size + kInputBufferSizeIncrement + input_buffer_size_;
319 input_buffer_ = local_zone()->NewArray<Node*>(size);
320 input_buffer_size_ = size;
321 }
322 return input_buffer_;
323 }
324
325
326 Node* BytecodeGraphBuilder::MakeNode(const Operator* op, int value_input_count,
327 Node** value_inputs, bool incomplete) {
328 DCHECK_EQ(op->ValueInputCount(), value_input_count);
329
330 bool has_context = OperatorProperties::HasContextInput(op);
331 int frame_state_count = OperatorProperties::GetFrameStateInputCount(op);
332 bool has_control = op->ControlInputCount() == 1;
333 bool has_effect = op->EffectInputCount() == 1;
334
335 DCHECK_LT(op->ControlInputCount(), 2);
336 DCHECK_LT(op->EffectInputCount(), 2);
337
338 Node* result = NULL;
339 if (!has_context && frame_state_count == 0 && !has_control && !has_effect) {
340 result = graph()->NewNode(op, value_input_count, value_inputs, incomplete);
341 } else {
342 int input_count_with_deps = value_input_count;
343 if (has_context) ++input_count_with_deps;
344 input_count_with_deps += frame_state_count;
345 if (has_control) ++input_count_with_deps;
346 if (has_effect) ++input_count_with_deps;
347 Node** buffer = EnsureInputBufferSize(input_count_with_deps);
348 memcpy(buffer, value_inputs, kPointerSize * value_input_count);
349 Node** current_input = buffer + value_input_count;
350 if (has_context) {
351 // TODO(oth): need context.
352 *current_input++ = jsgraph()->Dead();
353 }
354 for (int i = 0; i < frame_state_count; i++) {
355 // The frame state will be inserted later. Here we misuse
356 // the {Dead} node as a sentinel to be later overwritten
357 // with the real frame state.
358 *current_input++ = jsgraph()->Dead();
359 }
360 if (has_effect) {
361 *current_input++ = environment()->GetEffectDependency();
362 }
363 if (has_control) {
364 *current_input++ = environment()->GetControlDependency();
365 }
366 result = graph()->NewNode(op, input_count_with_deps, buffer, incomplete);
367 if (!environment()->IsMarkedAsUnreachable()) {
368 // Update the current control dependency for control-producing nodes.
369 if (NodeProperties::IsControl(result)) {
370 environment()->UpdateControlDependency(result);
371 }
372 // Update the current effect dependency for effect-producing nodes.
373 if (result->op()->EffectOutputCount() > 0) {
374 environment()->UpdateEffectDependency(result);
375 }
376 // Add implicit success continuation for throwing nodes.
377 if (!result->op()->HasProperty(Operator::kNoThrow)) {
378 const Operator* op = common()->IfSuccess();
379 Node* on_success = graph()->NewNode(op, result);
380 environment_->UpdateControlDependency(on_success);
381 }
382 }
383 }
384
385 return result;
386 }
387
388
389 Node* BytecodeGraphBuilder::MergeControl(Node* control, Node* other) {
390 int inputs = control->op()->ControlInputCount() + 1;
391 if (control->opcode() == IrOpcode::kLoop) {
392 // Control node for loop exists, add input.
393 const Operator* op = common()->Loop(inputs);
394 control->AppendInput(graph_zone(), other);
395 control->set_op(op);
396 } else if (control->opcode() == IrOpcode::kMerge) {
397 // Control node for merge exists, add input.
398 const Operator* op = common()->Merge(inputs);
399 control->AppendInput(graph_zone(), other);
400 control->set_op(op);
401 } else {
402 // Control node is a singleton, introduce a merge.
403 const Operator* op = common()->Merge(inputs);
404 Node* inputs[] = {control, other};
405 control = graph()->NewNode(op, arraysize(inputs), inputs, true);
406 }
407 return control;
408 }
409
410
411 void BytecodeGraphBuilder::UpdateControlDependencyToLeaveFunction(Node* exit) {
412 if (environment()->IsMarkedAsUnreachable()) return;
413 environment()->MarkAsUnreachable();
414 exit_controls_.push_back(exit);
415 }
416
417
418 interpreter::Bytecode BytecodeGraphBuilder::bytecode_at(int offset) const {
419 return interpreter::Bytecodes::FromByte(bytecode_array()->get(offset));
420 }
421
422
423 int8_t BytecodeGraphBuilder::smi8_at(int offset) const {
424 return static_cast<int8_t>(bytecode_array()->get(offset));
425 }
426
427
428 int8_t BytecodeGraphBuilder::register_at(int offset) const {
429 return static_cast<int8_t>(-bytecode_array()->get(offset));
430 }
431
432 } // namespace compiler
433 } // namespace internal
434 } // namespace v8
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698