LCOV - code coverage report
Current view: top level - src/interpreter - interpreter.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 94 115 81.7 %
Date: 2019-02-19 Functions: 18 22 81.8 %

          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             : #include "src/interpreter/interpreter.h"
       6             : 
       7             : #include <fstream>
       8             : #include <memory>
       9             : 
      10             : #include "builtins-generated/bytecodes-builtins-list.h"
      11             : #include "src/ast/prettyprinter.h"
      12             : #include "src/bootstrapper.h"
      13             : #include "src/compiler.h"
      14             : #include "src/counters-inl.h"
      15             : #include "src/interpreter/bytecode-generator.h"
      16             : #include "src/interpreter/bytecodes.h"
      17             : #include "src/objects-inl.h"
      18             : #include "src/objects/shared-function-info.h"
      19             : #include "src/objects/slots.h"
      20             : #include "src/ostreams.h"
      21             : #include "src/parsing/parse-info.h"
      22             : #include "src/setup-isolate.h"
      23             : #include "src/snapshot/snapshot.h"
      24             : #include "src/unoptimized-compilation-info.h"
      25             : #include "src/visitors.h"
      26             : 
      27             : namespace v8 {
      28             : namespace internal {
      29             : namespace interpreter {
      30             : 
      31     8348442 : class InterpreterCompilationJob final : public UnoptimizedCompilationJob {
      32             :  public:
      33             :   InterpreterCompilationJob(
      34             :       ParseInfo* parse_info, FunctionLiteral* literal,
      35             :       AccountingAllocator* allocator,
      36             :       std::vector<FunctionLiteral*>* eager_inner_literals);
      37             : 
      38             :  protected:
      39             :   Status ExecuteJobImpl() final;
      40             :   Status FinalizeJobImpl(Handle<SharedFunctionInfo> shared_info,
      41             :                          Isolate* isolate) final;
      42             : 
      43             :  private:
      44             :   BytecodeGenerator* generator() { return &generator_; }
      45             : 
      46             :   Zone zone_;
      47             :   UnoptimizedCompilationInfo compilation_info_;
      48             :   BytecodeGenerator generator_;
      49             : 
      50             :   DISALLOW_COPY_AND_ASSIGN(InterpreterCompilationJob);
      51             : };
      52             : 
      53       61048 : Interpreter::Interpreter(Isolate* isolate)
      54             :     : isolate_(isolate),
      55       61048 :       interpreter_entry_trampoline_instruction_start_(kNullAddress) {
      56       61048 :   memset(dispatch_table_, 0, sizeof(dispatch_table_));
      57             : 
      58       61048 :   if (FLAG_trace_ignition_dispatches) {
      59             :     static const int kBytecodeCount = static_cast<int>(Bytecode::kLast) + 1;
      60             :     bytecode_dispatch_counters_table_.reset(
      61           5 :         new uintptr_t[kBytecodeCount * kBytecodeCount]);
      62             :     memset(bytecode_dispatch_counters_table_.get(), 0,
      63             :            sizeof(uintptr_t) * kBytecodeCount * kBytecodeCount);
      64             :   }
      65       61048 : }
      66             : 
      67             : namespace {
      68             : 
      69             : int BuiltinIndexFromBytecode(Bytecode bytecode, OperandScale operand_scale) {
      70       66663 :   int index = BytecodeOperands::OperandScaleAsIndex(operand_scale) *
      71       66663 :                   kNumberOfBytecodeHandlers +
      72       66663 :               static_cast<int>(bytecode);
      73       66663 :   int offset = kBytecodeToBuiltinsMapping[index];
      74             :   return offset >= 0 ? Builtins::kFirstBytecodeHandler + offset
      75       66663 :                      : Builtins::kIllegalHandler;
      76             : }
      77             : 
      78             : }  // namespace
      79             : 
      80       66663 : Code Interpreter::GetBytecodeHandler(Bytecode bytecode,
      81             :                                      OperandScale operand_scale) {
      82             :   int builtin_index = BuiltinIndexFromBytecode(bytecode, operand_scale);
      83       66663 :   Builtins* builtins = isolate_->builtins();
      84       66663 :   return builtins->builtin(builtin_index);
      85             : }
      86             : 
      87    32966294 : void Interpreter::SetBytecodeHandler(Bytecode bytecode,
      88             :                                      OperandScale operand_scale, Code handler) {
      89             :   DCHECK(handler->kind() == Code::BYTECODE_HANDLER);
      90             :   size_t index = GetDispatchTableIndex(bytecode, operand_scale);
      91    32966325 :   dispatch_table_[index] = handler->InstructionStart();
      92    32966243 : }
      93             : 
      94             : // static
      95           0 : size_t Interpreter::GetDispatchTableIndex(Bytecode bytecode,
      96             :                                           OperandScale operand_scale) {
      97             :   static const size_t kEntriesPerOperandScale = 1u << kBitsPerByte;
      98    32966294 :   size_t index = static_cast<size_t>(bytecode);
      99    32966294 :   return index + BytecodeOperands::OperandScaleAsIndex(operand_scale) *
     100    32966325 :                      kEntriesPerOperandScale;
     101             : }
     102             : 
     103      196098 : void Interpreter::IterateDispatchTable(RootVisitor* v) {
     104      391172 :   if (FLAG_embedded_builtins && !isolate_->serializer_enabled() &&
     105      195074 :       isolate_->embedded_blob() != nullptr) {
     106             : // If builtins are embedded (and we're not generating a snapshot), then
     107             : // every bytecode handler will be off-heap, so there's no point iterating
     108             : // over them.
     109             : #ifdef DEBUG
     110             :     for (int i = 0; i < kDispatchTableSize; i++) {
     111             :       Address code_entry = dispatch_table_[i];
     112             :       CHECK(code_entry == kNullAddress ||
     113             :             InstructionStream::PcIsOffHeap(isolate_, code_entry));
     114             :     }
     115             : #endif  // ENABLE_SLOW_DCHECKS
     116      196098 :     return;
     117             :   }
     118             : 
     119      786432 :   for (int i = 0; i < kDispatchTableSize; i++) {
     120      786432 :     Address code_entry = dispatch_table_[i];
     121             :     // Skip over off-heap bytecode handlers since they will never move.
     122     1339392 :     if (InstructionStream::PcIsOffHeap(isolate_, code_entry)) continue;
     123             : 
     124             :     // TODO(jkummerow): Would it hurt to simply do:
     125             :     // if (code_entry == kNullAddress) continue;
     126      233472 :     Code code;
     127      233472 :     if (code_entry != kNullAddress) {
     128           0 :       code = Code::GetCodeFromTargetAddress(code_entry);
     129             :     }
     130      233472 :     Code old_code = code;
     131      466944 :     v->VisitRootPointer(Root::kDispatchTable, nullptr, FullObjectSlot(&code));
     132      233472 :     if (code != old_code) {
     133           0 :       dispatch_table_[i] = code->entry();
     134             :     }
     135             :   }
     136             : }
     137             : 
     138     2084282 : int Interpreter::InterruptBudget() {
     139     2084282 :   return FLAG_interrupt_budget;
     140             : }
     141             : 
     142             : namespace {
     143             : 
     144             : void MaybePrintAst(ParseInfo* parse_info,
     145             :                    UnoptimizedCompilationInfo* compilation_info) {
     146             :   if (!FLAG_print_ast) return;
     147             : 
     148             :   StdoutStream os;
     149             :   std::unique_ptr<char[]> name = compilation_info->literal()->GetDebugName();
     150             :   os << "[generating bytecode for function: " << name.get() << "]" << std::endl;
     151             : #ifdef DEBUG
     152             :   os << "--- AST ---" << std::endl
     153             :      << AstPrinter(parse_info->stack_limit())
     154             :             .PrintProgram(compilation_info->literal())
     155             :      << std::endl;
     156             : #endif  // DEBUG
     157             : }
     158             : 
     159     2063529 : bool ShouldPrintBytecode(Handle<SharedFunctionInfo> shared) {
     160     2063529 :   if (!FLAG_print_bytecode) return false;
     161             : 
     162             :   // Checks whether function passed the filter.
     163           0 :   if (shared->is_toplevel()) {
     164           0 :     Vector<const char> filter = CStrVector(FLAG_print_bytecode_filter);
     165           0 :     return (filter.length() == 0) || (filter.length() == 1 && filter[0] == '*');
     166             :   } else {
     167           0 :     return shared->PassesFilter(FLAG_print_bytecode_filter);
     168             :   }
     169             : }
     170             : 
     171             : }  // namespace
     172             : 
     173     2087108 : InterpreterCompilationJob::InterpreterCompilationJob(
     174     4174215 :     ParseInfo* parse_info, FunctionLiteral* literal,
     175             :     AccountingAllocator* allocator,
     176             :     std::vector<FunctionLiteral*>* eager_inner_literals)
     177             :     : UnoptimizedCompilationJob(parse_info->stack_limit(), parse_info,
     178             :                                 &compilation_info_),
     179             :       zone_(allocator, ZONE_NAME),
     180             :       compilation_info_(&zone_, parse_info, literal),
     181             :       generator_(&compilation_info_, parse_info->ast_string_constants(),
     182     6261323 :                  eager_inner_literals) {}
     183             : 
     184     2087095 : InterpreterCompilationJob::Status InterpreterCompilationJob::ExecuteJobImpl() {
     185             :   RuntimeCallTimerScope runtimeTimerScope(
     186             :       parse_info()->runtime_call_stats(),
     187     2087095 :       parse_info()->on_background_thread()
     188             :           ? RuntimeCallCounterId::kCompileBackgroundIgnition
     189     2087095 :           : RuntimeCallCounterId::kCompileIgnition);
     190             :   // TODO(lpy): add support for background compilation RCS trace.
     191     6261095 :   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.CompileIgnition");
     192             : 
     193             :   // Print AST if flag is enabled. Note, if compiling on a background thread
     194             :   // then ASTs from different functions may be intersperse when printed.
     195             :   MaybePrintAst(parse_info(), compilation_info());
     196             : 
     197     2087100 :   generator()->GenerateBytecode(stack_limit());
     198             : 
     199     2086900 :   if (generator()->HasStackOverflow()) {
     200             :     return FAILED;
     201             :   }
     202     2086978 :   return SUCCEEDED;
     203             : }
     204             : 
     205     2063526 : InterpreterCompilationJob::Status InterpreterCompilationJob::FinalizeJobImpl(
     206             :     Handle<SharedFunctionInfo> shared_info, Isolate* isolate) {
     207             :   RuntimeCallTimerScope runtimeTimerScope(
     208             :       parse_info()->runtime_call_stats(),
     209     6190580 :       RuntimeCallCounterId::kCompileIgnitionFinalization);
     210     6190577 :   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
     211             :                "V8.CompileIgnitionFinalization");
     212             : 
     213             :   Handle<BytecodeArray> bytecodes =
     214     2063525 :       generator()->FinalizeBytecode(isolate, parse_info()->script());
     215     2063528 :   if (generator()->HasStackOverflow()) {
     216             :     return FAILED;
     217             :   }
     218             : 
     219     2063530 :   if (ShouldPrintBytecode(shared_info)) {
     220           0 :     StdoutStream os;
     221             :     std::unique_ptr<char[]> name =
     222           0 :         compilation_info()->literal()->GetDebugName();
     223           0 :     os << "[generated bytecode for function: " << name.get() << "]"
     224             :        << std::endl;
     225           0 :     bytecodes->Disassemble(os);
     226           0 :     os << std::flush;
     227             :   }
     228             : 
     229             :   compilation_info()->SetBytecodeArray(bytecodes);
     230     2063529 :   return SUCCEEDED;
     231             : }
     232             : 
     233     2087102 : UnoptimizedCompilationJob* Interpreter::NewCompilationJob(
     234             :     ParseInfo* parse_info, FunctionLiteral* literal,
     235             :     AccountingAllocator* allocator,
     236             :     std::vector<FunctionLiteral*>* eager_inner_literals) {
     237             :   return new InterpreterCompilationJob(parse_info, literal, allocator,
     238     2087102 :                                        eager_inner_literals);
     239             : }
     240             : 
     241       61049 : void Interpreter::ForEachBytecode(
     242             :     const std::function<void(Bytecode, OperandScale)>& f) {
     243             :   constexpr OperandScale kOperandScales[] = {
     244             : #define VALUE(Name, _) OperandScale::k##Name,
     245             :       OPERAND_SCALE_LIST(VALUE)
     246             : #undef VALUE
     247       61049 :   };
     248             : 
     249      244196 :   for (OperandScale operand_scale : kOperandScales) {
     250    33149190 :     for (int i = 0; i < Bytecodes::kBytecodeCount; i++) {
     251    32966043 :       f(Bytecodes::FromByte(i), operand_scale);
     252             :     }
     253             :   }
     254       61049 : }
     255             : 
     256       61049 : void Interpreter::Initialize() {
     257       61049 :   Builtins* builtins = isolate_->builtins();
     258             : 
     259             :   // Set the interpreter entry trampoline entry point now that builtins are
     260             :   // initialized.
     261       61049 :   Handle<Code> code = BUILTIN_CODE(isolate_, InterpreterEntryTrampoline);
     262             :   DCHECK(builtins->is_initialized());
     263             :   DCHECK(code->is_off_heap_trampoline() ||
     264             :          isolate_->heap()->IsImmovable(*code));
     265       61049 :   interpreter_entry_trampoline_instruction_start_ = code->InstructionStart();
     266             : 
     267             :   // Initialize the dispatch table.
     268       61049 :   Code illegal = builtins->builtin(Builtins::kIllegalHandler);
     269       61049 :   int builtin_id = Builtins::kFirstBytecodeHandler;
     270             :   ForEachBytecode([=, &builtin_id](Bytecode bytecode,
     271    32966136 :                                    OperandScale operand_scale) {
     272    32966136 :     Code handler = illegal;
     273    32966136 :     if (Bytecodes::BytecodeHasHandler(bytecode, operand_scale)) {
     274             : #ifdef DEBUG
     275             :       std::string builtin_name(Builtins::name(builtin_id));
     276             :       std::string expected_name =
     277             :           Bytecodes::ToString(bytecode, operand_scale, "") + "Handler";
     278             :       DCHECK_EQ(expected_name, builtin_name);
     279             : #endif
     280    28936962 :       handler = builtins->builtin(builtin_id++);
     281             :     }
     282    32966286 :     SetBytecodeHandler(bytecode, operand_scale, handler);
     283    33149195 :   });
     284             :   DCHECK(builtin_id == Builtins::builtin_count);
     285             :   DCHECK(IsDispatchTableInitialized());
     286       61049 : }
     287             : 
     288           0 : bool Interpreter::IsDispatchTableInitialized() const {
     289           0 :   return dispatch_table_[0] != kNullAddress;
     290             : }
     291             : 
     292           0 : const char* Interpreter::LookupNameOfBytecodeHandler(const Code code) {
     293             : #ifdef ENABLE_DISASSEMBLER
     294             : #define RETURN_NAME(Name, ...)                                 \
     295             :   if (dispatch_table_[Bytecodes::ToByte(Bytecode::k##Name)] == \
     296             :       code->entry()) {                                         \
     297             :     return #Name;                                              \
     298             :   }
     299             :   BYTECODE_LIST(RETURN_NAME)
     300             : #undef RETURN_NAME
     301             : #endif  // ENABLE_DISASSEMBLER
     302           0 :   return nullptr;
     303             : }
     304             : 
     305           0 : uintptr_t Interpreter::GetDispatchCounter(Bytecode from, Bytecode to) const {
     306      583200 :   int from_index = Bytecodes::ToByte(from);
     307      583200 :   int to_index = Bytecodes::ToByte(to);
     308      583200 :   return bytecode_dispatch_counters_table_[from_index * kNumberOfBytecodes +
     309     1166400 :                                            to_index];
     310             : }
     311             : 
     312          18 : Local<v8::Object> Interpreter::GetDispatchCountersObject() {
     313          18 :   v8::Isolate* isolate = reinterpret_cast<v8::Isolate*>(isolate_);
     314          18 :   Local<v8::Context> context = isolate->GetCurrentContext();
     315             : 
     316          18 :   Local<v8::Object> counters_map = v8::Object::New(isolate);
     317             : 
     318             :   // Output is a JSON-encoded object of objects.
     319             :   //
     320             :   // The keys on the top level object are source bytecodes,
     321             :   // and corresponding value are objects. Keys on these last are the
     322             :   // destinations of the dispatch and the value associated is a counter for
     323             :   // the correspondent source-destination dispatch chain.
     324             :   //
     325             :   // Only non-zero counters are written to file, but an entry in the top-level
     326             :   // object is always present, even if the value is empty because all counters
     327             :   // for that source are zero.
     328             : 
     329        3258 :   for (int from_index = 0; from_index < kNumberOfBytecodes; ++from_index) {
     330        3240 :     Bytecode from_bytecode = Bytecodes::FromByte(from_index);
     331        3240 :     Local<v8::Object> counters_row = v8::Object::New(isolate);
     332             : 
     333      586440 :     for (int to_index = 0; to_index < kNumberOfBytecodes; ++to_index) {
     334      583200 :       Bytecode to_bytecode = Bytecodes::FromByte(to_index);
     335             :       uintptr_t counter = GetDispatchCounter(from_bytecode, to_bytecode);
     336             : 
     337      583200 :       if (counter > 0) {
     338           0 :         std::string to_name = Bytecodes::ToString(to_bytecode);
     339             :         Local<v8::String> to_name_object =
     340             :             v8::String::NewFromUtf8(isolate, to_name.c_str(),
     341             :                                     NewStringType::kNormal)
     342           0 :                 .ToLocalChecked();
     343           0 :         Local<v8::Number> counter_object = v8::Number::New(isolate, counter);
     344           0 :         CHECK(counters_row
     345             :                   ->DefineOwnProperty(context, to_name_object, counter_object)
     346             :                   .IsJust());
     347             :       }
     348             :     }
     349             : 
     350        3240 :     std::string from_name = Bytecodes::ToString(from_bytecode);
     351             :     Local<v8::String> from_name_object =
     352             :         v8::String::NewFromUtf8(isolate, from_name.c_str(),
     353             :                                 NewStringType::kNormal)
     354        3240 :             .ToLocalChecked();
     355             : 
     356        3240 :     CHECK(
     357             :         counters_map->DefineOwnProperty(context, from_name_object, counters_row)
     358             :             .IsJust());
     359             :   }
     360             : 
     361          18 :   return counters_map;
     362             : }
     363             : 
     364             : }  // namespace interpreter
     365             : }  // namespace internal
     366      178779 : }  // namespace v8

Generated by: LCOV version 1.10