LCOV - code coverage report
Current view: top level - src/interpreter - interpreter.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 71 94 75.5 %
Date: 2017-10-20 Functions: 13 17 76.5 %

          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 "src/ast/prettyprinter.h"
      11             : #include "src/bootstrapper.h"
      12             : #include "src/compilation-info.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/log.h"
      18             : #include "src/objects-inl.h"
      19             : #include "src/objects/shared-function-info.h"
      20             : #include "src/parsing/parse-info.h"
      21             : #include "src/setup-isolate.h"
      22             : #include "src/visitors.h"
      23             : 
      24             : namespace v8 {
      25             : namespace internal {
      26             : namespace interpreter {
      27             : 
      28     4262658 : class InterpreterCompilationJob final : public CompilationJob {
      29             :  public:
      30             :   InterpreterCompilationJob(ParseInfo* parse_info, FunctionLiteral* literal,
      31             :                             Isolate* isolate);
      32             : 
      33             :  protected:
      34             :   Status PrepareJobImpl() final;
      35             :   Status ExecuteJobImpl() final;
      36             :   Status FinalizeJobImpl() final;
      37             : 
      38             :  private:
      39             :   class TimerScope final {
      40             :    public:
      41     2131322 :     explicit TimerScope(RuntimeCallCounter* counter)
      42     2131322 :         : runtime_stats_enabled_(FLAG_runtime_stats) {
      43     2131322 :       if (V8_UNLIKELY(runtime_stats_enabled_ && counter != nullptr)) {
      44           0 :         timer_.Start(counter, nullptr);
      45             :       }
      46     2131322 :     }
      47             : 
      48             :     ~TimerScope() {
      49     2131326 :       if (V8_UNLIKELY(runtime_stats_enabled_)) {
      50           0 :         timer_.Stop();
      51             :       }
      52             :     }
      53             : 
      54             :    private:
      55             :     RuntimeCallTimer timer_;
      56             :     bool runtime_stats_enabled_;
      57             : 
      58             :     DISALLOW_COPY_AND_ASSIGN(TimerScope);
      59             :   };
      60             : 
      61             :   BytecodeGenerator* generator() { return &generator_; }
      62             : 
      63             :   Zone zone_;
      64             :   CompilationInfo compilation_info_;
      65             :   BytecodeGenerator generator_;
      66             :   RuntimeCallStats* runtime_call_stats_;
      67             :   RuntimeCallCounter background_execute_counter_;
      68             : 
      69             :   DISALLOW_COPY_AND_ASSIGN(InterpreterCompilationJob);
      70             : };
      71             : 
      72       54999 : Interpreter::Interpreter(Isolate* isolate) : isolate_(isolate) {
      73       54999 :   memset(dispatch_table_, 0, sizeof(dispatch_table_));
      74             : 
      75       54999 :   if (FLAG_trace_ignition_dispatches) {
      76             :     static const int kBytecodeCount = static_cast<int>(Bytecode::kLast) + 1;
      77             :     bytecode_dispatch_counters_table_.reset(
      78           5 :         new uintptr_t[kBytecodeCount * kBytecodeCount]);
      79             :     memset(bytecode_dispatch_counters_table_.get(), 0,
      80             :            sizeof(uintptr_t) * kBytecodeCount * kBytecodeCount);
      81             :   }
      82       54999 : }
      83             : 
      84       67866 : Code* Interpreter::GetBytecodeHandler(Bytecode bytecode,
      85             :                                       OperandScale operand_scale) {
      86             :   DCHECK(IsDispatchTableInitialized());
      87             :   DCHECK(Bytecodes::BytecodeHasHandler(bytecode, operand_scale));
      88       67866 :   size_t index = GetDispatchTableIndex(bytecode, operand_scale);
      89       67866 :   Address code_entry = dispatch_table_[index];
      90       67866 :   return Code::GetCodeFromTargetAddress(code_entry);
      91             : }
      92             : 
      93             : // static
      94       96045 : size_t Interpreter::GetDispatchTableIndex(Bytecode bytecode,
      95             :                                           OperandScale operand_scale) {
      96             :   static const size_t kEntriesPerOperandScale = 1u << kBitsPerByte;
      97       96045 :   size_t index = static_cast<size_t>(bytecode);
      98       96045 :   switch (operand_scale) {
      99             :     case OperandScale::kSingle:
     100             :       return index;
     101             :     case OperandScale::kDouble:
     102       11703 :       return index + kEntriesPerOperandScale;
     103             :     case OperandScale::kQuadruple:
     104       11703 :       return index + 2 * kEntriesPerOperandScale;
     105             :   }
     106           0 :   UNREACHABLE();
     107             : }
     108             : 
     109      202795 : void Interpreter::IterateDispatchTable(RootVisitor* v) {
     110   155929830 :   for (int i = 0; i < kDispatchTableSize; i++) {
     111   155727059 :     Address code_entry = dispatch_table_[i];
     112             :     Object* code = code_entry == nullptr
     113             :                        ? nullptr
     114   155727059 :                        : Code::GetCodeFromTargetAddress(code_entry);
     115             :     Object* old_code = code;
     116   155727059 :     v->VisitRootPointer(Root::kDispatchTable, &code);
     117   155727035 :     if (code != old_code) {
     118    42214986 :       dispatch_table_[i] = reinterpret_cast<Code*>(code)->entry();
     119             :     }
     120             :   }
     121      202771 : }
     122             : 
     123             : namespace {
     124             : 
     125             : void MaybePrintAst(ParseInfo* parse_info, CompilationInfo* compilation_info) {
     126             :   Isolate* isolate = compilation_info->isolate();
     127             :   bool print_ast = isolate->bootstrapper()->IsActive() ? FLAG_print_builtin_ast
     128             :                                                        : FLAG_print_ast;
     129             :   if (!print_ast) return;
     130             : 
     131             :   // Requires internalizing the AST, so make sure we are on the main thread and
     132             :   // allow handle dereference and allocations.
     133             :   // TODO(rmcilroy): Make ast-printer print ast raw strings instead of
     134             :   // internalized strings to avoid internalizing here.
     135             :   DCHECK(ThreadId::Current().Equals(isolate->thread_id()));
     136             :   AllowHandleDereference allow_deref;
     137             :   AllowHandleAllocation allow_handles;
     138             :   AllowHeapAllocation allow_gc;
     139             :   parse_info->ast_value_factory()->Internalize(isolate);
     140             : 
     141             :   OFStream os(stdout);
     142             :   std::unique_ptr<char[]> name = compilation_info->GetDebugName();
     143             :   os << "[generating bytecode for function: "
     144             :      << compilation_info->GetDebugName().get() << "]" << std::endl;
     145             : #ifdef DEBUG
     146             :   os << "--- AST ---" << std::endl
     147             :      << AstPrinter(isolate).PrintProgram(compilation_info->literal())
     148             :      << std::endl;
     149             : #endif  // DEBUG
     150             : }
     151             : 
     152     2131308 : bool ShouldPrintBytecode(Handle<SharedFunctionInfo> shared) {
     153     2131308 :   if (!FLAG_print_bytecode) return false;
     154             : 
     155             :   // Checks whether function passed the filter.
     156           0 :   if (shared->is_toplevel()) {
     157           0 :     Vector<const char> filter = CStrVector(FLAG_print_bytecode_filter);
     158           0 :     return (filter.length() == 0) || (filter.length() == 1 && filter[0] == '*');
     159             :   } else {
     160           0 :     return shared->PassesFilter(FLAG_print_bytecode_filter);
     161             :   }
     162             : }
     163             : 
     164             : }  // namespace
     165             : 
     166     2131327 : InterpreterCompilationJob::InterpreterCompilationJob(ParseInfo* parse_info,
     167             :                                                      FunctionLiteral* literal,
     168     2131326 :                                                      Isolate* isolate)
     169             :     : CompilationJob(isolate, parse_info, &compilation_info_, "Ignition"),
     170             :       zone_(isolate->allocator(), ZONE_NAME),
     171             :       compilation_info_(&zone_, isolate, parse_info, literal),
     172             :       generator_(&compilation_info_),
     173     2131328 :       runtime_call_stats_(isolate->counters()->runtime_call_stats()),
     174     8525309 :       background_execute_counter_("CompileBackgroundIgnition") {}
     175             : 
     176     2131325 : InterpreterCompilationJob::Status InterpreterCompilationJob::PrepareJobImpl() {
     177             :   MaybePrintAst(parse_info(), compilation_info());
     178     2131325 :   return SUCCEEDED;
     179             : }
     180             : 
     181     2131326 : InterpreterCompilationJob::Status InterpreterCompilationJob::ExecuteJobImpl() {
     182             :   TimerScope runtimeTimer(
     183     4262648 :       executed_on_background_thread() ? &background_execute_counter_ : nullptr);
     184             :   RuntimeCallTimerScope runtimeTimerScope(
     185             :       !executed_on_background_thread() ? runtime_call_stats_ : nullptr,
     186     2131325 :       &RuntimeCallStats::CompileIgnition);
     187             : 
     188             :   // TODO(lpy): add support for background compilation RCS trace.
     189     6393969 :   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.CompileIgnition");
     190             : 
     191     2131322 :   generator()->GenerateBytecode(stack_limit());
     192             : 
     193     2131325 :   if (generator()->HasStackOverflow()) {
     194             :     return FAILED;
     195             :   }
     196     2131312 :   return SUCCEEDED;
     197             : }
     198             : 
     199     2131306 : InterpreterCompilationJob::Status InterpreterCompilationJob::FinalizeJobImpl() {
     200             :   // Add background runtime call stats.
     201    14919150 :   if (V8_UNLIKELY(FLAG_runtime_stats && executed_on_background_thread())) {
     202             :     runtime_call_stats_->CompileBackgroundIgnition.Add(
     203           0 :         &background_execute_counter_);
     204             :   }
     205             : 
     206             :   RuntimeCallTimerScope runtimeTimerScope(
     207             :       !executed_on_background_thread() ? runtime_call_stats_ : nullptr,
     208     2131307 :       &RuntimeCallStats::CompileIgnitionFinalization);
     209             : 
     210             :   Handle<BytecodeArray> bytecodes =
     211     2131307 :       generator()->FinalizeBytecode(isolate(), parse_info()->script());
     212     2131308 :   if (generator()->HasStackOverflow()) {
     213             :     return FAILED;
     214             :   }
     215             : 
     216     2131308 :   if (ShouldPrintBytecode(compilation_info()->shared_info())) {
     217           0 :     OFStream os(stdout);
     218           0 :     std::unique_ptr<char[]> name = compilation_info()->GetDebugName();
     219           0 :     os << "[generated bytecode for function: "
     220           0 :        << compilation_info()->GetDebugName().get() << "]" << std::endl;
     221           0 :     bytecodes->Disassemble(os);
     222           0 :     os << std::flush;
     223             :   }
     224             : 
     225             :   compilation_info()->SetBytecodeArray(bytecodes);
     226             :   compilation_info()->SetCode(
     227     2131308 :       BUILTIN_CODE(compilation_info()->isolate(), InterpreterEntryTrampoline));
     228     2131306 :   return SUCCEEDED;
     229             : }
     230             : 
     231     2131326 : CompilationJob* Interpreter::NewCompilationJob(ParseInfo* parse_info,
     232             :                                                FunctionLiteral* literal,
     233             :                                                Isolate* isolate) {
     234     2131326 :   return new InterpreterCompilationJob(parse_info, literal, isolate);
     235             : }
     236             : 
     237           0 : bool Interpreter::IsDispatchTableInitialized() {
     238           0 :   return dispatch_table_[0] != nullptr;
     239             : }
     240             : 
     241           0 : const char* Interpreter::LookupNameOfBytecodeHandler(Code* code) {
     242             : #ifdef ENABLE_DISASSEMBLER
     243             : #define RETURN_NAME(Name, ...)                                 \
     244             :   if (dispatch_table_[Bytecodes::ToByte(Bytecode::k##Name)] == \
     245             :       code->entry()) {                                         \
     246             :     return #Name;                                              \
     247             :   }
     248             :   BYTECODE_LIST(RETURN_NAME)
     249             : #undef RETURN_NAME
     250             : #endif  // ENABLE_DISASSEMBLER
     251           0 :   return nullptr;
     252             : }
     253             : 
     254           0 : uintptr_t Interpreter::GetDispatchCounter(Bytecode from, Bytecode to) const {
     255      532512 :   int from_index = Bytecodes::ToByte(from);
     256      532512 :   int to_index = Bytecodes::ToByte(to);
     257      532512 :   return bytecode_dispatch_counters_table_[from_index * kNumberOfBytecodes +
     258     1065024 :                                            to_index];
     259             : }
     260             : 
     261          18 : Local<v8::Object> Interpreter::GetDispatchCountersObject() {
     262          18 :   v8::Isolate* isolate = reinterpret_cast<v8::Isolate*>(isolate_);
     263          18 :   Local<v8::Context> context = isolate->GetCurrentContext();
     264             : 
     265          18 :   Local<v8::Object> counters_map = v8::Object::New(isolate);
     266             : 
     267             :   // Output is a JSON-encoded object of objects.
     268             :   //
     269             :   // The keys on the top level object are source bytecodes,
     270             :   // and corresponding value are objects. Keys on these last are the
     271             :   // destinations of the dispatch and the value associated is a counter for
     272             :   // the correspondent source-destination dispatch chain.
     273             :   //
     274             :   // Only non-zero counters are written to file, but an entry in the top-level
     275             :   // object is always present, even if the value is empty because all counters
     276             :   // for that source are zero.
     277             : 
     278        3114 :   for (int from_index = 0; from_index < kNumberOfBytecodes; ++from_index) {
     279        3096 :     Bytecode from_bytecode = Bytecodes::FromByte(from_index);
     280        3096 :     Local<v8::Object> counters_row = v8::Object::New(isolate);
     281             : 
     282      535608 :     for (int to_index = 0; to_index < kNumberOfBytecodes; ++to_index) {
     283      532512 :       Bytecode to_bytecode = Bytecodes::FromByte(to_index);
     284             :       uintptr_t counter = GetDispatchCounter(from_bytecode, to_bytecode);
     285             : 
     286      532512 :       if (counter > 0) {
     287           0 :         std::string to_name = Bytecodes::ToString(to_bytecode);
     288             :         Local<v8::String> to_name_object =
     289             :             v8::String::NewFromUtf8(isolate, to_name.c_str(),
     290             :                                     NewStringType::kNormal)
     291           0 :                 .ToLocalChecked();
     292           0 :         Local<v8::Number> counter_object = v8::Number::New(isolate, counter);
     293           0 :         CHECK(counters_row
     294             :                   ->DefineOwnProperty(context, to_name_object, counter_object)
     295             :                   .IsJust());
     296             :       }
     297             :     }
     298             : 
     299        3096 :     std::string from_name = Bytecodes::ToString(from_bytecode);
     300             :     Local<v8::String> from_name_object =
     301             :         v8::String::NewFromUtf8(isolate, from_name.c_str(),
     302             :                                 NewStringType::kNormal)
     303        3096 :             .ToLocalChecked();
     304             : 
     305        3096 :     CHECK(
     306             :         counters_map->DefineOwnProperty(context, from_name_object, counters_row)
     307             :             .IsJust());
     308             :   }
     309             : 
     310          18 :   return counters_map;
     311             : }
     312             : 
     313             : }  // namespace interpreter
     314             : }  // namespace internal
     315             : }  // namespace v8

Generated by: LCOV version 1.10