LCOV - code coverage report
Current view: top level - src/interpreter - interpreter.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 84 110 76.4 %
Date: 2019-04-18 Functions: 14 21 66.7 %

          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     4237346 : 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     4213057 :   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       62442 : Interpreter::Interpreter(Isolate* isolate)
      54             :     : isolate_(isolate),
      55      124884 :       interpreter_entry_trampoline_instruction_start_(kNullAddress) {
      56       62442 :   memset(dispatch_table_, 0, sizeof(dispatch_table_));
      57             : 
      58       62442 :   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       62442 : }
      66             : 
      67             : namespace {
      68             : 
      69             : int BuiltinIndexFromBytecode(Bytecode bytecode, OperandScale operand_scale) {
      70       66691 :   int index = BytecodeOperands::OperandScaleAsIndex(operand_scale) *
      71       66691 :                   kNumberOfBytecodeHandlers +
      72       66691 :               static_cast<int>(bytecode);
      73       66691 :   int offset = kBytecodeToBuiltinsMapping[index];
      74             :   return offset >= 0 ? Builtins::kFirstBytecodeHandler + offset
      75       66691 :                      : Builtins::kIllegalHandler;
      76             : }
      77             : 
      78             : }  // namespace
      79             : 
      80       66691 : Code Interpreter::GetBytecodeHandler(Bytecode bytecode,
      81             :                                      OperandScale operand_scale) {
      82             :   int builtin_index = BuiltinIndexFromBytecode(bytecode, operand_scale);
      83       66691 :   Builtins* builtins = isolate_->builtins();
      84       66691 :   return builtins->builtin(builtin_index);
      85             : }
      86             : 
      87           0 : 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    33718180 :   dispatch_table_[index] = handler->InstructionStart();
      92           0 : }
      93             : 
      94             : // static
      95           0 : size_t Interpreter::GetDispatchTableIndex(Bytecode bytecode,
      96             :                                           OperandScale operand_scale) {
      97             :   static const size_t kEntriesPerOperandScale = 1u << kBitsPerByte;
      98    33718084 :   size_t index = static_cast<size_t>(bytecode);
      99    33718084 :   return index + BytecodeOperands::OperandScaleAsIndex(operand_scale) *
     100    33718084 :                      kEntriesPerOperandScale;
     101             : }
     102             : 
     103      186335 : void Interpreter::IterateDispatchTable(RootVisitor* v) {
     104      371623 :   if (FLAG_embedded_builtins && !isolate_->serializer_enabled() &&
     105      185288 :       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             :     return;
     117             :   }
     118             : 
     119     1609239 :   for (int i = 0; i < kDispatchTableSize; i++) {
     120      804096 :     Address code_entry = dispatch_table_[i];
     121             :     // Skip over off-heap bytecode handlers since they will never move.
     122     1369476 :     if (InstructionStream::PcIsOffHeap(isolate_, code_entry)) continue;
     123             : 
     124             :     // TODO(jkummerow): Would it hurt to simply do:
     125             :     // if (code_entry == kNullAddress) continue;
     126      238716 :     Code code;
     127      238716 :     if (code_entry != kNullAddress) {
     128           0 :       code = Code::GetCodeFromTargetAddress(code_entry);
     129             :     }
     130      238716 :     Code old_code = code;
     131      477432 :     v->VisitRootPointer(Root::kDispatchTable, nullptr, FullObjectSlot(&code));
     132      238716 :     if (code != old_code) {
     133           0 :       dispatch_table_[i] = code->entry();
     134             :     }
     135             :   }
     136             : }
     137             : 
     138           0 : int Interpreter::InterruptBudget() {
     139           0 :   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     2094397 : bool ShouldPrintBytecode(Handle<SharedFunctionInfo> shared) {
     160     2094397 :   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     2118665 : InterpreterCompilationJob::InterpreterCompilationJob(
     174             :     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     4237339 :                  eager_inner_literals) {}
     183             : 
     184     2118654 : InterpreterCompilationJob::Status InterpreterCompilationJob::ExecuteJobImpl() {
     185             :   RuntimeCallTimerScope runtimeTimerScope(
     186             :       parse_info()->runtime_call_stats(),
     187             :       parse_info()->on_background_thread()
     188             :           ? RuntimeCallCounterId::kCompileBackgroundIgnition
     189     2118654 :           : RuntimeCallCounterId::kCompileIgnition);
     190             :   // TODO(lpy): add support for background compilation RCS trace.
     191     6355911 :   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     2118653 :   generator()->GenerateBytecode(stack_limit());
     198             : 
     199     2118606 :   if (generator()->HasStackOverflow()) {
     200             :     return FAILED;
     201             :   }
     202     2118592 :   return SUCCEEDED;
     203             : }
     204             : 
     205     2094405 : InterpreterCompilationJob::Status InterpreterCompilationJob::FinalizeJobImpl(
     206             :     Handle<SharedFunctionInfo> shared_info, Isolate* isolate) {
     207             :   RuntimeCallTimerScope runtimeTimerScope(
     208             :       parse_info()->runtime_call_stats(),
     209     2094405 :       RuntimeCallCounterId::kCompileIgnitionFinalization);
     210     6283205 :   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
     211             :                "V8.CompileIgnitionFinalization");
     212             : 
     213             :   Handle<BytecodeArray> bytecodes =
     214     2094404 :       generator()->FinalizeBytecode(isolate, parse_info()->script());
     215     2094399 :   if (generator()->HasStackOverflow()) {
     216             :     return FAILED;
     217             :   }
     218             : 
     219     2094400 :   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             :     os << std::flush;
     227             :   }
     228             : 
     229             :   compilation_info()->SetBytecodeArray(bytecodes);
     230     2094398 :   return SUCCEEDED;
     231             : }
     232             : 
     233     2118669 : 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     2118669 :                                        eager_inner_literals);
     239             : }
     240             : 
     241       62456 : 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       62456 :   };
     248             : 
     249      437108 :   for (OperandScale operand_scale : kOperandScales) {
     250    67623136 :     for (int i = 0; i < Bytecodes::kBytecodeCount; i++) {
     251             :       f(Bytecodes::FromByte(i), operand_scale);
     252             :     }
     253             :   }
     254       62442 : }
     255             : 
     256       62442 : void Interpreter::Initialize() {
     257       62442 :   Builtins* builtins = isolate_->builtins();
     258             : 
     259             :   // Set the interpreter entry trampoline entry point now that builtins are
     260             :   // initialized.
     261       62442 :   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      124884 :   interpreter_entry_trampoline_instruction_start_ = code->InstructionStart();
     266             : 
     267             :   // Initialize the dispatch table.
     268       62442 :   Code illegal = builtins->builtin(Builtins::kIllegalHandler);
     269       62442 :   int builtin_id = Builtins::kFirstBytecodeHandler;
     270      124884 :   ForEachBytecode([=, &builtin_id](Bytecode bytecode,
     271    63314884 :                                    OperandScale operand_scale) {
     272    33717941 :     Code handler = illegal;
     273    33717941 :     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    29596943 :       handler = builtins->builtin(builtin_id++);
     281             :     }
     282    33718084 :     SetBytecodeHandler(bytecode, operand_scale, handler);
     283    33780622 :   });
     284             :   DCHECK(builtin_id == Builtins::builtin_count);
     285             :   DCHECK(IsDispatchTableInitialized());
     286       62442 : }
     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           0 :   int from_index = Bytecodes::ToByte(from);
     307           0 :   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        6498 :   for (int from_index = 0; from_index < kNumberOfBytecodes; ++from_index) {
     330             :     Bytecode from_bytecode = Bytecodes::FromByte(from_index);
     331        3240 :     Local<v8::Object> counters_row = v8::Object::New(isolate);
     332             : 
     333     1169640 :     for (int to_index = 0; to_index < kNumberOfBytecodes; ++to_index) {
     334             :       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           0 :             v8::String::NewFromUtf8(isolate, to_name.c_str(),
     341             :                                     NewStringType::kNormal)
     342             :                 .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        3240 :         v8::String::NewFromUtf8(isolate, from_name.c_str(),
     353             :                                 NewStringType::kNormal)
     354             :             .ToLocalChecked();
     355             : 
     356        6480 :     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      122036 : }  // namespace v8

Generated by: LCOV version 1.10