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

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

Powered by Google App Engine
This is Rietveld 408576698