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