bytecode-generator.h 20.5 KB
Newer Older
1 2 3 4 5 6 7
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef V8_INTERPRETER_BYTECODE_GENERATOR_H_
#define V8_INTERPRETER_BYTECODE_GENERATOR_H_

8
#include "src/ast/ast.h"
9
#include "src/interpreter/bytecode-array-builder.h"
10
#include "src/interpreter/bytecode-label.h"
11
#include "src/interpreter/bytecode-register.h"
12
#include "src/interpreter/bytecodes.h"
13 14
#include "src/objects/feedback-vector.h"
#include "src/objects/function-kind.h"
15 16 17

namespace v8 {
namespace internal {
18

19
class AstNodeSourceRanges;
20
class AstStringConstants;
21
class UnoptimizedCompilationInfo;
22
enum class SourceRangeKind;
23

24 25
namespace interpreter {

26
class GlobalDeclarationsBuilder;
27
class LoopBuilder;
28
class BlockCoverageBuilder;
29
class BytecodeJumpTable;
30

31
class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
32
 public:
33
  explicit BytecodeGenerator(
34 35
      UnoptimizedCompilationInfo* info,
      const AstStringConstants* ast_string_constants,
36
      std::vector<FunctionLiteral*>* eager_inner_literals);
37

38
  void GenerateBytecode(uintptr_t stack_limit);
39 40
  Handle<BytecodeArray> FinalizeBytecode(Isolate* isolate,
                                         Handle<Script> script);
41

42
#define DECLARE_VISIT(type) void Visit##type(type* node);
43 44 45
  AST_NODE_LIST(DECLARE_VISIT)
#undef DECLARE_VISIT

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 56 57
  class ControlScopeForTopLevel;
  class ControlScopeForTryCatch;
  class ControlScopeForTryFinally;
58
  class CurrentScope;
59 60
  class ExpressionResultScope;
  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 71
  using ToBooleanMode = BytecodeArrayBuilder::ToBooleanMode;

72
  enum class TestFallthrough { kThen, kElse, kNone };
73
  enum class TypeHint { kAny, kBoolean, kString };
74
  enum class AccumulatorPreservingMode { kNone, kPreserve };
75

76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
  // An assignment has to evaluate its LHS before its RHS, but has to assign to
  // the LHS after both evaluations are done. This class stores the data
  // computed in the LHS evaulation that has to live across the RHS evaluation,
  // and is used in the actual LHS assignment.
  class AssignmentLhsData {
   public:
    static AssignmentLhsData NonProperty(Expression* expr);
    static AssignmentLhsData NamedProperty(Expression* object_expr,
                                           Register object,
                                           const AstRawString* name);
    static AssignmentLhsData KeyedProperty(Register object, Register key);
    static AssignmentLhsData NamedSuperProperty(
        RegisterList super_property_args);
    static AssignmentLhsData KeyedSuperProperty(
        RegisterList super_property_args);

    AssignType assign_type() const { return assign_type_; }
    Expression* expr() const {
      DCHECK_EQ(assign_type_, NON_PROPERTY);
      return expr_;
    }
    Expression* object_expr() const {
      DCHECK_EQ(assign_type_, NAMED_PROPERTY);
      return object_expr_;
    }
    Register object() const {
      DCHECK(assign_type_ == NAMED_PROPERTY || assign_type_ == KEYED_PROPERTY);
      return object_;
    }
    Register key() const {
      DCHECK_EQ(assign_type_, KEYED_PROPERTY);
      return key_;
    }
    const AstRawString* name() const {
      DCHECK_EQ(assign_type_, NAMED_PROPERTY);
      return name_;
    }
    RegisterList super_property_args() const {
      DCHECK(assign_type_ == NAMED_SUPER_PROPERTY ||
             assign_type_ == KEYED_SUPER_PROPERTY);
      return super_property_args_;
    }

   private:
    AssignmentLhsData(AssignType assign_type, Expression* expr,
                      RegisterList super_property_args, Register object,
                      Register key, Expression* object_expr,
                      const AstRawString* name)
        : assign_type_(assign_type),
          expr_(expr),
          super_property_args_(super_property_args),
          object_(object),
          key_(key),
          object_expr_(object_expr),
          name_(name) {}

    AssignType assign_type_;

    // Different assignment types use different fields:
    //
    // NON_PROPERTY: expr
    // NAMED_PROPERTY: object_expr, object, name
    // KEYED_PROPERTY: object, key
    // NAMED_SUPER_PROPERTY: super_property_args
    // KEYED_SUPER_PROPERT:  super_property_args
    Expression* expr_;
    RegisterList super_property_args_;
    Register object_;
    Register key_;
    Expression* object_expr_;
    const AstRawString* name_;
  };

149
  void GenerateBytecodeBody();
150
  void AllocateDeferredConstants(Isolate* isolate, Handle<Script> script);
151

152 153
  DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();

154
  // Dispatched from VisitBinaryOperation.
155
  void VisitArithmeticExpression(BinaryOperation* binop);
156 157 158
  void VisitCommaExpression(BinaryOperation* binop);
  void VisitLogicalOrExpression(BinaryOperation* binop);
  void VisitLogicalAndExpression(BinaryOperation* binop);
159

160 161 162 163 164 165
  // Dispatched from VisitNaryOperation.
  void VisitNaryArithmeticExpression(NaryOperation* expr);
  void VisitNaryCommaExpression(NaryOperation* expr);
  void VisitNaryLogicalOrExpression(NaryOperation* expr);
  void VisitNaryLogicalAndExpression(NaryOperation* expr);

166 167 168 169
  // Dispatched from VisitUnaryOperation.
  void VisitVoid(UnaryOperation* expr);
  void VisitTypeOf(UnaryOperation* expr);
  void VisitNot(UnaryOperation* expr);
170
  void VisitDelete(UnaryOperation* expr);
171

172 173 174
  // Visits a typeof expression for the value on which to perform the typeof.
  void VisitForTypeOfValue(Expression* expr);

175 176 177
  // Used by flow control routines to evaluate loop condition.
  void VisitCondition(Expression* expr);

178 179
  // Visit the arguments expressions in |args| and store them in |args_regs|,
  // growing |args_regs| for each argument visited.
180 181
  void VisitArguments(const ZonePtrList<Expression>* args,
                      RegisterList* arg_regs);
182

183 184 185 186 187 188 189 190 191 192 193 194 195 196
  // Visit a keyed super property load. The optional
  // |opt_receiver_out| register will have the receiver stored to it
  // if it's a valid register. The loaded value is placed in the
  // accumulator.
  void VisitKeyedSuperPropertyLoad(Property* property,
                                   Register opt_receiver_out);

  // Visit a named super property load. The optional
  // |opt_receiver_out| register will have the receiver stored to it
  // if it's a valid register. The loaded value is placed in the
  // accumulator.
  void VisitNamedSuperPropertyLoad(Property* property,
                                   Register opt_receiver_out);

197
  void VisitPropertyLoad(Register obj, Property* expr);
198 199
  void VisitPropertyLoadForRegister(Register obj, Property* expr,
                                    Register destination);
200

201 202 203
  AssignmentLhsData PrepareAssignmentLhs(
      Expression* lhs, AccumulatorPreservingMode accumulator_preserving_mode =
                           AccumulatorPreservingMode::kNone);
204 205 206
  void BuildAssignment(const AssignmentLhsData& data, Token::Value op,
                       LookupHoistingMode lookup_hoisting_mode);

207
  void BuildThisVariableLoad();
208

209
  Expression* GetDestructuringDefaultValue(Expression** target);
210 211 212 213 214 215
  void BuildDestructuringArrayAssignment(
      ArrayLiteral* pattern, Token::Value op,
      LookupHoistingMode lookup_hoisting_mode);
  void BuildDestructuringObjectAssignment(
      ObjectLiteral* pattern, Token::Value op,
      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 221
                               const AstRawString* name);

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 231
  void BuildLiteralCompareNil(Token::Value compare_op,
                              BytecodeArrayBuilder::NilValue nil);
232 233
  void BuildReturn(int source_position = kNoSourcePosition);
  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 240 241 242 243
  // Build jump to targets[value], where
  // start_index <= value < start_index + size.
  void BuildIndexedJump(Register value, size_t start_index, size_t size,
                        ZoneVector<BytecodeLabel>& targets);

244 245 246
  void BuildNewLocalActivationContext();
  void BuildLocalActivationContextInitialization();
  void BuildNewLocalBlockContext(Scope* scope);
247
  void BuildNewLocalCatchContext(Scope* scope);
248 249
  void BuildNewLocalWithContext(Scope* scope);

250
  void BuildGeneratorPrologue();
251
  void BuildSuspendPoint(int position);
252

253
  void BuildAwait(int position = kNoSourcePosition);
254
  void BuildAwait(Expression* await_expr);
255

256 257 258 259
  void BuildFinalizeIteration(IteratorRecord iterator, Register done,
                              Register iteration_continuation_token);

  void BuildGetIterator(IteratorType hint);
260 261 262

  // Create an IteratorRecord with pre-allocated registers holding the next
  // method and iterator object.
263
  IteratorRecord BuildGetIteratorRecord(Register iterator_next,
264 265 266 267 268
                                        Register iterator_object,
                                        IteratorType hint);

  // Create an IteratorRecord allocating new registers to hold the next method
  // 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 274 275 276
  void BuildCallIteratorMethod(Register iterator, const AstRawString* method,
                               RegisterList receiver_and_args,
                               BytecodeLabel* if_called,
                               BytecodeLabels* if_notcalled);
277

278
  void BuildFillArrayWithIterator(IteratorRecord iterator, Register array,
279
                                  Register index, Register value,
280 281 282 283
                                  FeedbackSlot next_value_slot,
                                  FeedbackSlot next_done_slot,
                                  FeedbackSlot index_slot,
                                  FeedbackSlot element_slot);
284 285 286
  // Create Array literals. |expr| can be nullptr, but if provided,
  // a boilerplate will be used to create an initial array for elements
  // 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 BuildPrivateClassMemberNameAssignment(ClassLiteral::Property* property);
295 296
  void BuildClassLiteral(ClassLiteral* expr, Register name);
  void VisitClassLiteral(ClassLiteral* expr, Register name);
297
  void VisitNewTargetVariable(Variable* variable);
298
  void VisitThisFunctionVariable(Variable* variable);
299
  void BuildPrivateBrandInitialization(Register receiver);
300 301
  void BuildInstanceMemberInitialization(Register constructor,
                                         Register instance);
302
  void BuildGeneratorObjectVariableInitialization();
303
  void VisitBlockDeclarationsAndStatements(Block* stmt);
304
  void VisitSetHomeObject(Register value, Register home_object,
305
                          LiteralProperty* property);
306 307 308
  void VisitObjectLiteralAccessor(Register home_object,
                                  ObjectLiteralProperty* property,
                                  Register value_out);
309
  void VisitForInAssignment(Expression* expr);
310
  void VisitModuleNamespaceImports();
311

312
  // Visit a logical OR/AND within a test context, rewiring the jumps based
313
  // on the expression values.
314 315 316 317
  void VisitLogicalTest(Token::Value token, Expression* left, Expression* right,
                        int right_coverage_slot);
  void VisitNaryLogicalTest(Token::Value token, NaryOperation* expr,
                            const NaryCodeCoverageSlots* coverage_slots);
318 319 320 321
  // Visit a (non-RHS) test for a logical op, which falls through if the test
  // fails or jumps to the appropriate labels if it succeeds.
  void VisitLogicalTestSubExpression(Token::Value token, Expression* expr,
                                     BytecodeLabels* then_labels,
322 323
                                     BytecodeLabels* else_labels,
                                     int coverage_slot);
324 325

  // Helpers for binary and nary logical op value expressions.
326 327
  bool VisitLogicalOrSubExpression(Expression* expr, BytecodeLabels* end_labels,
                                   int coverage_slot);
328
  bool VisitLogicalAndSubExpression(Expression* expr,
329 330
                                    BytecodeLabels* end_labels,
                                    int coverage_slot);
331

332
  // Visit the body of a loop iteration.
333 334
  void VisitIterationBody(IterationStatement* stmt, LoopBuilder* loop_builder);

335 336 337
  // Visit a statement and switch scopes, the context is in the accumulator.
  void VisitInScope(Statement* stmt, Scope* scope);

338 339
  void BuildPushUndefinedIntoRegisterList(RegisterList* reg_list);

340 341
  void BuildLoadPropertyKey(LiteralProperty* property, Register out_reg);

342
  int AllocateBlockCoverageSlotIfEnabled(AstNode* node, SourceRangeKind kind);
343 344
  int AllocateNaryBlockCoverageSlotIfEnabled(NaryOperation* node, size_t index);

345 346
  void BuildIncrementBlockCoverageCounterIfEnabled(AstNode* node,
                                                   SourceRangeKind kind);
347 348
  void BuildIncrementBlockCoverageCounterIfEnabled(int coverage_array_slot);

349 350 351
  void BuildTest(ToBooleanMode mode, BytecodeLabels* then_labels,
                 BytecodeLabels* else_labels, TestFallthrough fallthrough);

352 353 354 355
  template <typename TryBodyFunc, typename CatchBodyFunc>
  void BuildTryCatch(TryBodyFunc try_body_func, CatchBodyFunc catch_body_func,
                     HandlerTable::CatchPrediction catch_prediction,
                     TryCatchStatement* stmt_for_coverage = nullptr);
356 357 358 359 360 361
  template <typename TryBodyFunc, typename FinallyBodyFunc>
  void BuildTryFinally(TryBodyFunc try_body_func,
                       FinallyBodyFunc finally_body_func,
                       HandlerTable::CatchPrediction catch_prediction,
                       TryFinallyStatement* stmt_for_coverage = nullptr);

362
  // Visitors for obtaining expression result in the accumulator, in a
363 364 365
  // register, or just getting the effect. Some visitors return a TypeHint which
  // specifies the type of the result of the visited expression.
  TypeHint VisitForAccumulatorValue(Expression* expr);
366
  void VisitForAccumulatorValueOrTheHole(Expression* expr);
367
  V8_WARN_UNUSED_RESULT Register VisitForRegisterValue(Expression* expr);
368
  V8_INLINE void VisitForRegisterValue(Expression* expr, Register destination);
369
  void VisitAndPushIntoRegisterList(Expression* expr, RegisterList* reg_list);
370
  void VisitForEffect(Expression* expr);
371 372
  void VisitForTest(Expression* expr, BytecodeLabels* then_labels,
                    BytecodeLabels* else_labels, TestFallthrough fallthrough);
373

374
  void VisitInSameTestExecutionScope(Expression* expr);
375

376 377
  Register GetRegisterForLocalVariable(Variable* variable);

378 379 380 381
  // Returns the runtime function id for a store to super for the function's
  // language mode.
  inline Runtime::FunctionId StoreToSuperRuntimeId();
  inline Runtime::FunctionId StoreKeyedToSuperRuntimeId();
382

383 384 385 386
  // Returns a cached slot, or create and cache a new slot if one doesn't
  // already exists.
  FeedbackSlot GetCachedLoadGlobalICSlot(TypeofMode typeof_mode,
                                         Variable* variable);
387 388
  FeedbackSlot GetCachedStoreGlobalICSlot(LanguageMode language_mode,
                                          Variable* variable);
389 390 391 392
  FeedbackSlot GetCachedLoadICSlot(const Expression* expr,
                                   const AstRawString* name);
  FeedbackSlot GetCachedStoreICSlot(const Expression* expr,
                                    const AstRawString* name);
393
  FeedbackSlot GetDummyCompareICSlot();
394

395 396
  int GetCachedCreateClosureSlot(FunctionLiteral* literal);

397 398
  void AddToEagerLiteralsIfEager(FunctionLiteral* literal);

399 400 401 402 403
  // Checks if the visited expression is one shot, i.e executed only once. Any
  // expression either in a top level code or an IIFE that is not within a loop
  // is eligible for one shot optimizations.
  inline bool ShouldOptimizeAsOneShot() const;

404 405 406 407
  static constexpr ToBooleanMode ToBooleanModeFromTypeHint(TypeHint type_hint) {
    return type_hint == TypeHint::kBoolean ? ToBooleanMode::kAlreadyBoolean
                                           : ToBooleanMode::kConvertToBoolean;
  }
408

409 410
  inline Register generator_object() const;

411
  inline BytecodeArrayBuilder* builder() { return &builder_; }
412
  inline Zone* zone() const { return zone_; }
413
  inline DeclarationScope* closure_scope() const { return closure_scope_; }
414
  inline UnoptimizedCompilationInfo* info() const { return info_; }
415 416 417
  inline const AstStringConstants* ast_string_constants() const {
    return ast_string_constants_;
  }
418

419 420 421
  inline Scope* current_scope() const { return current_scope_; }
  inline void set_current_scope(Scope* scope) { current_scope_ = scope; }

422 423 424 425 426 427 428
  inline ControlScope* execution_control() const { return execution_control_; }
  inline void set_execution_control(ControlScope* scope) {
    execution_control_ = scope;
  }
  inline ContextScope* execution_context() const { return execution_context_; }
  inline void set_execution_context(ContextScope* context) {
    execution_context_ = context;
429
  }
430 431 432 433
  inline void set_execution_result(ExpressionResultScope* execution_result) {
    execution_result_ = execution_result;
  }
  ExpressionResultScope* execution_result() const { return execution_result_; }
434
  BytecodeRegisterAllocator* register_allocator() {
435
    return builder()->register_allocator();
436
  }
437

438 439 440 441
  GlobalDeclarationsBuilder* globals_builder() {
    DCHECK_NOT_NULL(globals_builder_);
    return globals_builder_;
  }
442
  inline LanguageMode language_mode() const;
443
  inline FunctionKind function_kind() const;
444 445 446 447 448 449
  inline FeedbackVectorSpec* feedback_spec();
  inline int feedback_index(FeedbackSlot slot) const;

  inline FeedbackSlotCache* feedback_slot_cache() {
    return feedback_slot_cache_;
  }
450

451 452 453 454 455 456 457
  inline HandlerTable::CatchPrediction catch_prediction() const {
    return catch_prediction_;
  }
  inline void set_catch_prediction(HandlerTable::CatchPrediction value) {
    catch_prediction_ = value;
  }

458
  Zone* zone_;
459
  BytecodeArrayBuilder builder_;
460
  UnoptimizedCompilationInfo* info_;
461
  const AstStringConstants* ast_string_constants_;
462 463
  DeclarationScope* closure_scope_;
  Scope* current_scope_;
464

465
  // External vector of literals to be eagerly compiled.
466
  std::vector<FunctionLiteral*>* eager_inner_literals_;
467

468 469
  FeedbackSlotCache* feedback_slot_cache_;

470
  GlobalDeclarationsBuilder* globals_builder_;
471
  BlockCoverageBuilder* block_coverage_builder_;
472
  ZoneVector<GlobalDeclarationsBuilder*> global_declarations_;
473 474 475
  ZoneVector<std::pair<FunctionLiteral*, size_t>> function_literals_;
  ZoneVector<std::pair<NativeFunctionLiteral*, size_t>>
      native_function_literals_;
476 477
  ZoneVector<std::pair<ObjectLiteral*, size_t>> object_literals_;
  ZoneVector<std::pair<ArrayLiteral*, size_t>> array_literals_;
478
  ZoneVector<std::pair<ClassLiteral*, size_t>> class_literals_;
479
  ZoneVector<std::pair<GetTemplateObject*, size_t>> template_objects_;
480

481 482
  ControlScope* execution_control_;
  ContextScope* execution_context_;
483
  ExpressionResultScope* execution_result_;
484

485 486
  Register incoming_new_target_or_generator_;

487 488
  // Dummy feedback slot for compare operations, where we don't care about
  // feedback
489
  SharedFeedbackSlot dummy_feedback_slot_;
490

491
  BytecodeJumpTable* generator_jump_table_;
492
  int suspend_count_;
493
  int loop_depth_;
494 495

  HandlerTable::CatchPrediction catch_prediction_;
496 497 498 499 500 501 502
};

}  // namespace interpreter
}  // namespace internal
}  // namespace v8

#endif  // V8_INTERPRETER_BYTECODE_GENERATOR_H_