Line data Source code
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 : #ifndef V8_INTERPRETER_BYTECODE_GENERATOR_H_
6 : #define V8_INTERPRETER_BYTECODE_GENERATOR_H_
7 :
8 : #include "src/ast/ast.h"
9 : #include "src/feedback-vector.h"
10 : #include "src/interpreter/bytecode-array-builder.h"
11 : #include "src/interpreter/bytecode-label.h"
12 : #include "src/interpreter/bytecode-register.h"
13 : #include "src/interpreter/bytecodes.h"
14 :
15 : namespace v8 {
16 : namespace internal {
17 :
18 : class AstNodeSourceRanges;
19 : class AstStringConstants;
20 : class UnoptimizedCompilationInfo;
21 : enum class SourceRangeKind;
22 :
23 : namespace interpreter {
24 :
25 : class GlobalDeclarationsBuilder;
26 : class LoopBuilder;
27 : class BlockCoverageBuilder;
28 : class BytecodeJumpTable;
29 :
30 2109777 : class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
31 : public:
32 : explicit BytecodeGenerator(
33 : UnoptimizedCompilationInfo* info,
34 : const AstStringConstants* ast_string_constants,
35 : std::vector<FunctionLiteral*>* eager_inner_literals);
36 :
37 : void GenerateBytecode(uintptr_t stack_limit);
38 : Handle<BytecodeArray> FinalizeBytecode(Isolate* isolate,
39 : Handle<Script> script);
40 :
41 : #define DECLARE_VISIT(type) void Visit##type(type* node);
42 : AST_NODE_LIST(DECLARE_VISIT)
43 : #undef DECLARE_VISIT
44 :
45 : // Visiting function for declarations list and statements are overridden.
46 : void VisitDeclarations(Declaration::List* declarations);
47 : void VisitStatements(const ZonePtrList<Statement>* statments);
48 :
49 : private:
50 : class ContextScope;
51 : class ControlScope;
52 : class ControlScopeForBreakable;
53 : class ControlScopeForIteration;
54 : class ControlScopeForTopLevel;
55 : class ControlScopeForTryCatch;
56 : class ControlScopeForTryFinally;
57 : class CurrentScope;
58 : class ExpressionResultScope;
59 : class EffectResultScope;
60 : class FeedbackSlotCache;
61 : class GlobalDeclarationsBuilder;
62 : class IteratorRecord;
63 : class NaryCodeCoverageSlots;
64 : class RegisterAllocationScope;
65 : class AccumulatorPreservingScope;
66 : class TestResultScope;
67 : class ValueResultScope;
68 :
69 : using ToBooleanMode = BytecodeArrayBuilder::ToBooleanMode;
70 :
71 : enum class TestFallthrough { kThen, kElse, kNone };
72 : enum class TypeHint { kAny, kBoolean, kString };
73 : enum class AccumulatorPreservingMode { kNone, kPreserve };
74 :
75 : // An assignment has to evaluate its LHS before its RHS, but has to assign to
76 : // the LHS after both evaluations are done. This class stores the data
77 : // computed in the LHS evaulation that has to live across the RHS evaluation,
78 : // and is used in the actual LHS assignment.
79 : class AssignmentLhsData {
80 : public:
81 : static AssignmentLhsData NonProperty(Expression* expr);
82 : static AssignmentLhsData NamedProperty(Expression* object_expr,
83 : Register object,
84 : const AstRawString* name);
85 : static AssignmentLhsData KeyedProperty(Register object, Register key);
86 : static AssignmentLhsData NamedSuperProperty(
87 : RegisterList super_property_args);
88 : static AssignmentLhsData KeyedSuperProperty(
89 : RegisterList super_property_args);
90 :
91 : AssignType assign_type() const { return assign_type_; }
92 : Expression* expr() const {
93 : DCHECK_EQ(assign_type_, NON_PROPERTY);
94 : return expr_;
95 : }
96 : Expression* object_expr() const {
97 : DCHECK_EQ(assign_type_, NAMED_PROPERTY);
98 : return object_expr_;
99 : }
100 : Register object() const {
101 : DCHECK(assign_type_ == NAMED_PROPERTY || assign_type_ == KEYED_PROPERTY);
102 : return object_;
103 : }
104 : Register key() const {
105 : DCHECK_EQ(assign_type_, KEYED_PROPERTY);
106 : return key_;
107 : }
108 : const AstRawString* name() const {
109 : DCHECK_EQ(assign_type_, NAMED_PROPERTY);
110 : return name_;
111 : }
112 : RegisterList super_property_args() const {
113 : DCHECK(assign_type_ == NAMED_SUPER_PROPERTY ||
114 : assign_type_ == KEYED_SUPER_PROPERTY);
115 : return super_property_args_;
116 : }
117 :
118 : private:
119 : AssignmentLhsData(AssignType assign_type, Expression* expr,
120 : RegisterList super_property_args, Register object,
121 : Register key, Expression* object_expr,
122 : const AstRawString* name)
123 : : assign_type_(assign_type),
124 : expr_(expr),
125 : super_property_args_(super_property_args),
126 : object_(object),
127 : key_(key),
128 : object_expr_(object_expr),
129 7608220 : name_(name) {}
130 :
131 : AssignType assign_type_;
132 :
133 : // Different assignment types use different fields:
134 : //
135 : // NON_PROPERTY: expr
136 : // NAMED_PROPERTY: object_expr, object, name
137 : // KEYED_PROPERTY: object, key
138 : // NAMED_SUPER_PROPERTY: super_property_args
139 : // KEYED_SUPER_PROPERT: super_property_args
140 : Expression* expr_;
141 : RegisterList super_property_args_;
142 : Register object_;
143 : Register key_;
144 : Expression* object_expr_;
145 : const AstRawString* name_;
146 : };
147 :
148 : void GenerateBytecodeBody();
149 : void AllocateDeferredConstants(Isolate* isolate, Handle<Script> script);
150 :
151 190593066 : DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
152 :
153 : // Dispatched from VisitBinaryOperation.
154 : void VisitArithmeticExpression(BinaryOperation* binop);
155 : void VisitCommaExpression(BinaryOperation* binop);
156 : void VisitLogicalOrExpression(BinaryOperation* binop);
157 : void VisitLogicalAndExpression(BinaryOperation* binop);
158 :
159 : // Dispatched from VisitNaryOperation.
160 : void VisitNaryArithmeticExpression(NaryOperation* expr);
161 : void VisitNaryCommaExpression(NaryOperation* expr);
162 : void VisitNaryLogicalOrExpression(NaryOperation* expr);
163 : void VisitNaryLogicalAndExpression(NaryOperation* expr);
164 :
165 : // Dispatched from VisitUnaryOperation.
166 : void VisitVoid(UnaryOperation* expr);
167 : void VisitTypeOf(UnaryOperation* expr);
168 : void VisitNot(UnaryOperation* expr);
169 : void VisitDelete(UnaryOperation* expr);
170 :
171 : // Visits a typeof expression for the value on which to perform the typeof.
172 : void VisitForTypeOfValue(Expression* expr);
173 :
174 : // Used by flow control routines to evaluate loop condition.
175 : void VisitCondition(Expression* expr);
176 :
177 : // Visit the arguments expressions in |args| and store them in |args_regs|,
178 : // growing |args_regs| for each argument visited.
179 : void VisitArguments(const ZonePtrList<Expression>* args,
180 : RegisterList* arg_regs);
181 :
182 : // Visit a keyed super property load. The optional
183 : // |opt_receiver_out| register will have the receiver stored to it
184 : // if it's a valid register. The loaded value is placed in the
185 : // accumulator.
186 : void VisitKeyedSuperPropertyLoad(Property* property,
187 : Register opt_receiver_out);
188 :
189 : // Visit a named super property load. The optional
190 : // |opt_receiver_out| register will have the receiver stored to it
191 : // if it's a valid register. The loaded value is placed in the
192 : // accumulator.
193 : void VisitNamedSuperPropertyLoad(Property* property,
194 : Register opt_receiver_out);
195 :
196 : void VisitPropertyLoad(Register obj, Property* expr);
197 : void VisitPropertyLoadForRegister(Register obj, Property* expr,
198 : Register destination);
199 :
200 : AssignmentLhsData PrepareAssignmentLhs(
201 : Expression* lhs, AccumulatorPreservingMode accumulator_preserving_mode =
202 : AccumulatorPreservingMode::kNone);
203 : void BuildAssignment(const AssignmentLhsData& data, Token::Value op,
204 : LookupHoistingMode lookup_hoisting_mode);
205 :
206 : Expression* GetDestructuringDefaultValue(Expression** target);
207 : void BuildDestructuringArrayAssignment(
208 : ArrayLiteral* pattern, Token::Value op,
209 : LookupHoistingMode lookup_hoisting_mode);
210 : void BuildDestructuringObjectAssignment(
211 : ObjectLiteral* pattern, Token::Value op,
212 : LookupHoistingMode lookup_hoisting_mode);
213 :
214 : void BuildLoadNamedProperty(const Expression* object_expr, Register object,
215 : const AstRawString* name);
216 : void BuildStoreNamedProperty(const Expression* object_expr, Register object,
217 : const AstRawString* name);
218 :
219 : void BuildVariableLoad(Variable* variable, HoleCheckMode hole_check_mode,
220 : TypeofMode typeof_mode = NOT_INSIDE_TYPEOF);
221 : void BuildVariableLoadForAccumulatorValue(
222 : Variable* variable, HoleCheckMode hole_check_mode,
223 : TypeofMode typeof_mode = NOT_INSIDE_TYPEOF);
224 : void BuildVariableAssignment(
225 : Variable* variable, Token::Value op, HoleCheckMode hole_check_mode,
226 : LookupHoistingMode lookup_hoisting_mode = LookupHoistingMode::kNormal);
227 : void BuildLiteralCompareNil(Token::Value compare_op,
228 : BytecodeArrayBuilder::NilValue nil);
229 : void BuildReturn(int source_position = kNoSourcePosition);
230 : void BuildAsyncReturn(int source_position = kNoSourcePosition);
231 : void BuildAsyncGeneratorReturn();
232 : void BuildReThrow();
233 : void BuildHoleCheckForVariableAssignment(Variable* variable, Token::Value op);
234 : void BuildThrowIfHole(Variable* variable);
235 :
236 : // Build jump to targets[value], where
237 : // start_index <= value < start_index + size.
238 : void BuildIndexedJump(Register value, size_t start_index, size_t size,
239 : ZoneVector<BytecodeLabel>& targets);
240 :
241 : void BuildNewLocalActivationContext();
242 : void BuildLocalActivationContextInitialization();
243 : void BuildNewLocalBlockContext(Scope* scope);
244 : void BuildNewLocalCatchContext(Scope* scope);
245 : void BuildNewLocalWithContext(Scope* scope);
246 :
247 : void BuildGeneratorPrologue();
248 : void BuildSuspendPoint(int position);
249 :
250 : void BuildAwait(int position = kNoSourcePosition);
251 : void BuildAwait(Expression* await_expr);
252 :
253 : void BuildFinalizeIteration(IteratorRecord iterator, Register done,
254 : Register iteration_continuation_token);
255 :
256 : void BuildGetIterator(IteratorType hint);
257 :
258 : // Create an IteratorRecord with pre-allocated registers holding the next
259 : // method and iterator object.
260 : IteratorRecord BuildGetIteratorRecord(Register iterator_next,
261 : Register iterator_object,
262 : IteratorType hint);
263 :
264 : // Create an IteratorRecord allocating new registers to hold the next method
265 : // and iterator object.
266 : IteratorRecord BuildGetIteratorRecord(IteratorType hint);
267 : void BuildIteratorNext(const IteratorRecord& iterator, Register next_result);
268 : void BuildIteratorClose(const IteratorRecord& iterator,
269 : Expression* expr = nullptr);
270 : void BuildCallIteratorMethod(Register iterator, const AstRawString* method,
271 : RegisterList receiver_and_args,
272 : BytecodeLabel* if_called,
273 : BytecodeLabels* if_notcalled);
274 :
275 : void BuildFillArrayWithIterator(IteratorRecord iterator, Register array,
276 : Register index, Register value,
277 : FeedbackSlot next_value_slot,
278 : FeedbackSlot next_done_slot,
279 : FeedbackSlot index_slot,
280 : FeedbackSlot element_slot);
281 : // Create Array literals. |expr| can be nullptr, but if provided,
282 : // a boilerplate will be used to create an initial array for elements
283 : // before the first spread.
284 : void BuildCreateArrayLiteral(const ZonePtrList<Expression>* elements,
285 : ArrayLiteral* expr);
286 : void BuildCreateObjectLiteral(Register literal, uint8_t flags, size_t entry);
287 : void AllocateTopLevelRegisters();
288 : void VisitArgumentsObject(Variable* variable);
289 : void VisitRestArgumentsArray(Variable* rest);
290 : void VisitCallSuper(Call* call);
291 : void BuildClassLiteral(ClassLiteral* expr, Register name);
292 : void VisitClassLiteral(ClassLiteral* expr, Register name);
293 : void VisitNewTargetVariable(Variable* variable);
294 : void VisitThisFunctionVariable(Variable* variable);
295 : void BuildInstanceMemberInitialization(Register constructor,
296 : Register instance);
297 : void BuildGeneratorObjectVariableInitialization();
298 : void VisitBlockDeclarationsAndStatements(Block* stmt);
299 : void VisitSetHomeObject(Register value, Register home_object,
300 : LiteralProperty* property);
301 : void VisitObjectLiteralAccessor(Register home_object,
302 : ObjectLiteralProperty* property,
303 : Register value_out);
304 : void VisitForInAssignment(Expression* expr);
305 : void VisitModuleNamespaceImports();
306 :
307 : // Visit a logical OR/AND within a test context, rewiring the jumps based
308 : // on the expression values.
309 : void VisitLogicalTest(Token::Value token, Expression* left, Expression* right,
310 : int right_coverage_slot);
311 : void VisitNaryLogicalTest(Token::Value token, NaryOperation* expr,
312 : const NaryCodeCoverageSlots* coverage_slots);
313 : // Visit a (non-RHS) test for a logical op, which falls through if the test
314 : // fails or jumps to the appropriate labels if it succeeds.
315 : void VisitLogicalTestSubExpression(Token::Value token, Expression* expr,
316 : BytecodeLabels* then_labels,
317 : BytecodeLabels* else_labels,
318 : int coverage_slot);
319 :
320 : // Helpers for binary and nary logical op value expressions.
321 : bool VisitLogicalOrSubExpression(Expression* expr, BytecodeLabels* end_labels,
322 : int coverage_slot);
323 : bool VisitLogicalAndSubExpression(Expression* expr,
324 : BytecodeLabels* end_labels,
325 : int coverage_slot);
326 :
327 : // Visit the body of a loop iteration.
328 : void VisitIterationBody(IterationStatement* stmt, LoopBuilder* loop_builder);
329 :
330 : // Visit a statement and switch scopes, the context is in the accumulator.
331 : void VisitInScope(Statement* stmt, Scope* scope);
332 :
333 : void BuildPushUndefinedIntoRegisterList(RegisterList* reg_list);
334 :
335 : void BuildLoadPropertyKey(LiteralProperty* property, Register out_reg);
336 :
337 : int AllocateBlockCoverageSlotIfEnabled(AstNode* node, SourceRangeKind kind);
338 : int AllocateNaryBlockCoverageSlotIfEnabled(NaryOperation* node, size_t index);
339 :
340 : void BuildIncrementBlockCoverageCounterIfEnabled(AstNode* node,
341 : SourceRangeKind kind);
342 : void BuildIncrementBlockCoverageCounterIfEnabled(int coverage_array_slot);
343 :
344 : void BuildTest(ToBooleanMode mode, BytecodeLabels* then_labels,
345 : BytecodeLabels* else_labels, TestFallthrough fallthrough);
346 :
347 : template <typename TryBodyFunc, typename CatchBodyFunc>
348 : void BuildTryCatch(TryBodyFunc try_body_func, CatchBodyFunc catch_body_func,
349 : HandlerTable::CatchPrediction catch_prediction,
350 : TryCatchStatement* stmt_for_coverage = nullptr);
351 : template <typename TryBodyFunc, typename FinallyBodyFunc>
352 : void BuildTryFinally(TryBodyFunc try_body_func,
353 : FinallyBodyFunc finally_body_func,
354 : HandlerTable::CatchPrediction catch_prediction,
355 : TryFinallyStatement* stmt_for_coverage = nullptr);
356 :
357 : // Visitors for obtaining expression result in the accumulator, in a
358 : // register, or just getting the effect. Some visitors return a TypeHint which
359 : // specifies the type of the result of the visited expression.
360 : TypeHint VisitForAccumulatorValue(Expression* expr);
361 : void VisitForAccumulatorValueOrTheHole(Expression* expr);
362 : V8_WARN_UNUSED_RESULT Register VisitForRegisterValue(Expression* expr);
363 : V8_INLINE void VisitForRegisterValue(Expression* expr, Register destination);
364 : void VisitAndPushIntoRegisterList(Expression* expr, RegisterList* reg_list);
365 : void VisitForEffect(Expression* expr);
366 : void VisitForTest(Expression* expr, BytecodeLabels* then_labels,
367 : BytecodeLabels* else_labels, TestFallthrough fallthrough);
368 :
369 : void VisitInSameTestExecutionScope(Expression* expr);
370 :
371 : Register GetRegisterForLocalVariable(Variable* variable);
372 :
373 : // Returns the runtime function id for a store to super for the function's
374 : // language mode.
375 : inline Runtime::FunctionId StoreToSuperRuntimeId();
376 : inline Runtime::FunctionId StoreKeyedToSuperRuntimeId();
377 :
378 : // Returns a cached slot, or create and cache a new slot if one doesn't
379 : // already exists.
380 : FeedbackSlot GetCachedLoadGlobalICSlot(TypeofMode typeof_mode,
381 : Variable* variable);
382 : FeedbackSlot GetCachedStoreGlobalICSlot(LanguageMode language_mode,
383 : Variable* variable);
384 : FeedbackSlot GetCachedCreateClosureSlot(FunctionLiteral* literal);
385 : FeedbackSlot GetCachedLoadICSlot(const Expression* expr,
386 : const AstRawString* name);
387 : FeedbackSlot GetCachedStoreICSlot(const Expression* expr,
388 : const AstRawString* name);
389 : FeedbackSlot GetDummyCompareICSlot();
390 :
391 : void AddToEagerLiteralsIfEager(FunctionLiteral* literal);
392 :
393 : // Checks if the visited expression is one shot, i.e executed only once. Any
394 : // expression either in a top level code or an IIFE that is not within a loop
395 : // is eligible for one shot optimizations.
396 : inline bool ShouldOptimizeAsOneShot() const;
397 :
398 : static constexpr ToBooleanMode ToBooleanModeFromTypeHint(TypeHint type_hint) {
399 : return type_hint == TypeHint::kBoolean ? ToBooleanMode::kAlreadyBoolean
400 937127 : : ToBooleanMode::kConvertToBoolean;
401 : }
402 :
403 : inline Register generator_object() const;
404 :
405 845415 : inline BytecodeArrayBuilder* builder() { return &builder_; }
406 : inline Zone* zone() const { return zone_; }
407 : inline DeclarationScope* closure_scope() const { return closure_scope_; }
408 : inline UnoptimizedCompilationInfo* info() const { return info_; }
409 : inline const AstStringConstants* ast_string_constants() const {
410 : return ast_string_constants_;
411 : }
412 :
413 : inline Scope* current_scope() const { return current_scope_; }
414 618558 : inline void set_current_scope(Scope* scope) { current_scope_ = scope; }
415 :
416 : inline ControlScope* execution_control() const { return execution_control_; }
417 : inline void set_execution_control(ControlScope* scope) {
418 15554949 : execution_control_ = scope;
419 : }
420 : inline ContextScope* execution_context() const { return execution_context_; }
421 : inline void set_execution_context(ContextScope* context) {
422 4864420 : execution_context_ = context;
423 : }
424 : inline void set_execution_result(ExpressionResultScope* execution_result) {
425 88709752 : execution_result_ = execution_result;
426 : }
427 : ExpressionResultScope* execution_result() const { return execution_result_; }
428 : BytecodeRegisterAllocator* register_allocator() {
429 : return builder()->register_allocator();
430 : }
431 :
432 : GlobalDeclarationsBuilder* globals_builder() {
433 : DCHECK_NOT_NULL(globals_builder_);
434 : return globals_builder_;
435 : }
436 : inline LanguageMode language_mode() const;
437 : inline FunctionKind function_kind() const;
438 : inline FeedbackVectorSpec* feedback_spec();
439 : inline int feedback_index(FeedbackSlot slot) const;
440 :
441 : inline FeedbackSlotCache* feedback_slot_cache() {
442 : return feedback_slot_cache_;
443 : }
444 :
445 : inline HandlerTable::CatchPrediction catch_prediction() const {
446 : return catch_prediction_;
447 : }
448 : inline void set_catch_prediction(HandlerTable::CatchPrediction value) {
449 139360 : catch_prediction_ = value;
450 : }
451 :
452 : Zone* zone_;
453 : BytecodeArrayBuilder builder_;
454 : UnoptimizedCompilationInfo* info_;
455 : const AstStringConstants* ast_string_constants_;
456 : DeclarationScope* closure_scope_;
457 : Scope* current_scope_;
458 :
459 : // External vector of literals to be eagerly compiled.
460 : std::vector<FunctionLiteral*>* eager_inner_literals_;
461 :
462 : FeedbackSlotCache* feedback_slot_cache_;
463 :
464 : GlobalDeclarationsBuilder* globals_builder_;
465 : BlockCoverageBuilder* block_coverage_builder_;
466 : ZoneVector<GlobalDeclarationsBuilder*> global_declarations_;
467 : ZoneVector<std::pair<FunctionLiteral*, size_t>> function_literals_;
468 : ZoneVector<std::pair<NativeFunctionLiteral*, size_t>>
469 : native_function_literals_;
470 : ZoneVector<std::pair<ObjectLiteral*, size_t>> object_literals_;
471 : ZoneVector<std::pair<ArrayLiteral*, size_t>> array_literals_;
472 : ZoneVector<std::pair<ClassLiteral*, size_t>> class_literals_;
473 : ZoneVector<std::pair<GetTemplateObject*, size_t>> template_objects_;
474 :
475 : ControlScope* execution_control_;
476 : ContextScope* execution_context_;
477 : ExpressionResultScope* execution_result_;
478 :
479 : Register incoming_new_target_or_generator_;
480 :
481 : // Dummy feedback slot for compare operations, where we don't care about
482 : // feedback
483 : SharedFeedbackSlot dummy_feedback_slot_;
484 :
485 : BytecodeJumpTable* generator_jump_table_;
486 : int suspend_count_;
487 : int loop_depth_;
488 :
489 : HandlerTable::CatchPrediction catch_prediction_;
490 : };
491 :
492 : } // namespace interpreter
493 : } // namespace internal
494 : } // namespace v8
495 :
496 : #endif // V8_INTERPRETER_BYTECODE_GENERATOR_H_
|