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

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

Powered by Google App Engine
This is Rietveld 408576698