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

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