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

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

Powered by Google App Engine
This is Rietveld 408576698