Home | History | Annotate | Download | only in interpreter
      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/compiler.h"
     13 #include "src/counters-inl.h"
     14 #include "src/interpreter/bytecode-generator.h"
     15 #include "src/interpreter/bytecodes.h"
     16 #include "src/log.h"
     17 #include "src/objects-inl.h"
     18 #include "src/objects/shared-function-info.h"
     19 #include "src/parsing/parse-info.h"
     20 #include "src/setup-isolate.h"
     21 #include "src/snapshot/snapshot.h"
     22 #include "src/unoptimized-compilation-info.h"
     23 #include "src/visitors.h"
     24 
     25 namespace v8 {
     26 namespace internal {
     27 namespace interpreter {
     28 
     29 class InterpreterCompilationJob final : public UnoptimizedCompilationJob {
     30  public:
     31   InterpreterCompilationJob(ParseInfo* parse_info, FunctionLiteral* literal,
     32                             AccountingAllocator* allocator,
     33                             ZoneVector<FunctionLiteral*>* eager_inner_literals);
     34 
     35  protected:
     36   Status ExecuteJobImpl() final;
     37   Status FinalizeJobImpl(Handle<SharedFunctionInfo> shared_info,
     38                          Isolate* isolate) final;
     39 
     40  private:
     41   BytecodeGenerator* generator() { return &generator_; }
     42 
     43   Zone zone_;
     44   UnoptimizedCompilationInfo compilation_info_;
     45   BytecodeGenerator generator_;
     46 
     47   DISALLOW_COPY_AND_ASSIGN(InterpreterCompilationJob);
     48 };
     49 
     50 Interpreter::Interpreter(Isolate* isolate) : isolate_(isolate) {
     51   memset(dispatch_table_, 0, sizeof(dispatch_table_));
     52 
     53   if (FLAG_trace_ignition_dispatches) {
     54     static const int kBytecodeCount = static_cast<int>(Bytecode::kLast) + 1;
     55     bytecode_dispatch_counters_table_.reset(
     56         new uintptr_t[kBytecodeCount * kBytecodeCount]);
     57     memset(bytecode_dispatch_counters_table_.get(), 0,
     58            sizeof(uintptr_t) * kBytecodeCount * kBytecodeCount);
     59   }
     60 }
     61 
     62 Code* Interpreter::GetAndMaybeDeserializeBytecodeHandler(
     63     Bytecode bytecode, OperandScale operand_scale) {
     64   Code* code = GetBytecodeHandler(bytecode, operand_scale);
     65 
     66   // Already deserialized? Then just return the handler.
     67   if (!isolate_->heap()->IsDeserializeLazyHandler(code)) return code;
     68 
     69   DCHECK(FLAG_lazy_handler_deserialization);
     70   DCHECK(Bytecodes::BytecodeHasHandler(bytecode, operand_scale));
     71   code = Snapshot::DeserializeHandler(isolate_, bytecode, operand_scale);
     72 
     73   DCHECK(code->IsCode());
     74   DCHECK_EQ(code->kind(), Code::BYTECODE_HANDLER);
     75   DCHECK(!isolate_->heap()->IsDeserializeLazyHandler(code));
     76 
     77   SetBytecodeHandler(bytecode, operand_scale, code);
     78 
     79   return code;
     80 }
     81 
     82 Code* Interpreter::GetBytecodeHandler(Bytecode bytecode,
     83                                       OperandScale operand_scale) {
     84   DCHECK(IsDispatchTableInitialized());
     85   DCHECK(Bytecodes::BytecodeHasHandler(bytecode, operand_scale));
     86   size_t index = GetDispatchTableIndex(bytecode, operand_scale);
     87   Address code_entry = dispatch_table_[index];
     88   return Code::GetCodeFromTargetAddress(code_entry);
     89 }
     90 
     91 void Interpreter::SetBytecodeHandler(Bytecode bytecode,
     92                                      OperandScale operand_scale,
     93                                      Code* handler) {
     94   DCHECK(handler->kind() == Code::BYTECODE_HANDLER);
     95   size_t index = GetDispatchTableIndex(bytecode, operand_scale);
     96   dispatch_table_[index] = handler->entry();
     97 }
     98 
     99 // static
    100 size_t Interpreter::GetDispatchTableIndex(Bytecode bytecode,
    101                                           OperandScale operand_scale) {
    102   static const size_t kEntriesPerOperandScale = 1u << kBitsPerByte;
    103   size_t index = static_cast<size_t>(bytecode);
    104   switch (operand_scale) {
    105     case OperandScale::kSingle:
    106       return index;
    107     case OperandScale::kDouble:
    108       return index + kEntriesPerOperandScale;
    109     case OperandScale::kQuadruple:
    110       return index + 2 * kEntriesPerOperandScale;
    111   }
    112   UNREACHABLE();
    113 }
    114 
    115 void Interpreter::IterateDispatchTable(RootVisitor* v) {
    116   for (int i = 0; i < kDispatchTableSize; i++) {
    117     Address code_entry = dispatch_table_[i];
    118     Object* code = code_entry == kNullAddress
    119                        ? nullptr
    120                        : Code::GetCodeFromTargetAddress(code_entry);
    121     Object* old_code = code;
    122     v->VisitRootPointer(Root::kDispatchTable, nullptr, &code);
    123     if (code != old_code) {
    124       dispatch_table_[i] = reinterpret_cast<Code*>(code)->entry();
    125     }
    126   }
    127 }
    128 
    129 int Interpreter::InterruptBudget() {
    130   return FLAG_interrupt_budget;
    131 }
    132 
    133 namespace {
    134 
    135 void MaybePrintAst(ParseInfo* parse_info,
    136                    UnoptimizedCompilationInfo* compilation_info) {
    137   if (!FLAG_print_ast) return;
    138 
    139   StdoutStream os;
    140   std::unique_ptr<char[]> name = compilation_info->literal()->GetDebugName();
    141   os << "[generating bytecode for function: " << name.get() << "]" << std::endl;
    142 #ifdef DEBUG
    143   os << "--- AST ---" << std::endl
    144      << AstPrinter(parse_info->stack_limit())
    145             .PrintProgram(compilation_info->literal())
    146      << std::endl;
    147 #endif  // DEBUG
    148 }
    149 
    150 bool ShouldPrintBytecode(Handle<SharedFunctionInfo> shared) {
    151   if (!FLAG_print_bytecode) return false;
    152 
    153   // Checks whether function passed the filter.
    154   if (shared->is_toplevel()) {
    155     Vector<const char> filter = CStrVector(FLAG_print_bytecode_filter);
    156     return (filter.length() == 0) || (filter.length() == 1 && filter[0] == '*');
    157   } else {
    158     return shared->PassesFilter(FLAG_print_bytecode_filter);
    159   }
    160 }
    161 
    162 }  // namespace
    163 
    164 InterpreterCompilationJob::InterpreterCompilationJob(
    165     ParseInfo* parse_info, FunctionLiteral* literal,
    166     AccountingAllocator* allocator,
    167     ZoneVector<FunctionLiteral*>* eager_inner_literals)
    168     : UnoptimizedCompilationJob(parse_info->stack_limit(), parse_info,
    169                                 &compilation_info_),
    170       zone_(allocator, ZONE_NAME),
    171       compilation_info_(&zone_, parse_info, literal),
    172       generator_(&compilation_info_, parse_info->ast_string_constants(),
    173                  eager_inner_literals) {}
    174 
    175 InterpreterCompilationJob::Status InterpreterCompilationJob::ExecuteJobImpl() {
    176   RuntimeCallTimerScope runtimeTimerScope(
    177       parse_info()->runtime_call_stats(),
    178       parse_info()->on_background_thread()
    179           ? RuntimeCallCounterId::kCompileBackgroundIgnition
    180           : RuntimeCallCounterId::kCompileIgnition);
    181   // TODO(lpy): add support for background compilation RCS trace.
    182   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.CompileIgnition");
    183 
    184   // Print AST if flag is enabled. Note, if compiling on a background thread
    185   // then ASTs from different functions may be intersperse when printed.
    186   MaybePrintAst(parse_info(), compilation_info());
    187 
    188   generator()->GenerateBytecode(stack_limit());
    189 
    190   if (generator()->HasStackOverflow()) {
    191     return FAILED;
    192   }
    193   return SUCCEEDED;
    194 }
    195 
    196 InterpreterCompilationJob::Status InterpreterCompilationJob::FinalizeJobImpl(
    197     Handle<SharedFunctionInfo> shared_info, Isolate* isolate) {
    198   RuntimeCallTimerScope runtimeTimerScope(
    199       parse_info()->runtime_call_stats(),
    200       RuntimeCallCounterId::kCompileIgnitionFinalization);
    201   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
    202                "V8.CompileIgnitionFinalization");
    203 
    204   Handle<BytecodeArray> bytecodes =
    205       generator()->FinalizeBytecode(isolate, parse_info()->script());
    206   if (generator()->HasStackOverflow()) {
    207     return FAILED;
    208   }
    209 
    210   if (ShouldPrintBytecode(shared_info)) {
    211     StdoutStream os;
    212     std::unique_ptr<char[]> name =
    213         compilation_info()->literal()->GetDebugName();
    214     os << "[generated bytecode for function: " << name.get() << "]"
    215        << std::endl;
    216     bytecodes->Disassemble(os);
    217     os << std::flush;
    218   }
    219 
    220   compilation_info()->SetBytecodeArray(bytecodes);
    221   return SUCCEEDED;
    222 }
    223 
    224 UnoptimizedCompilationJob* Interpreter::NewCompilationJob(
    225     ParseInfo* parse_info, FunctionLiteral* literal,
    226     AccountingAllocator* allocator,
    227     ZoneVector<FunctionLiteral*>* eager_inner_literals) {
    228   return new InterpreterCompilationJob(parse_info, literal, allocator,
    229                                        eager_inner_literals);
    230 }
    231 
    232 bool Interpreter::IsDispatchTableInitialized() const {
    233   return dispatch_table_[0] != kNullAddress;
    234 }
    235 
    236 const char* Interpreter::LookupNameOfBytecodeHandler(const Code* code) {
    237 #ifdef ENABLE_DISASSEMBLER
    238 #define RETURN_NAME(Name, ...)                                 \
    239   if (dispatch_table_[Bytecodes::ToByte(Bytecode::k##Name)] == \
    240       code->entry()) {                                         \
    241     return #Name;                                              \
    242   }
    243   BYTECODE_LIST(RETURN_NAME)
    244 #undef RETURN_NAME
    245 #endif  // ENABLE_DISASSEMBLER
    246   return nullptr;
    247 }
    248 
    249 uintptr_t Interpreter::GetDispatchCounter(Bytecode from, Bytecode to) const {
    250   int from_index = Bytecodes::ToByte(from);
    251   int to_index = Bytecodes::ToByte(to);
    252   return bytecode_dispatch_counters_table_[from_index * kNumberOfBytecodes +
    253                                            to_index];
    254 }
    255 
    256 Local<v8::Object> Interpreter::GetDispatchCountersObject() {
    257   v8::Isolate* isolate = reinterpret_cast<v8::Isolate*>(isolate_);
    258   Local<v8::Context> context = isolate->GetCurrentContext();
    259 
    260   Local<v8::Object> counters_map = v8::Object::New(isolate);
    261 
    262   // Output is a JSON-encoded object of objects.
    263   //
    264   // The keys on the top level object are source bytecodes,
    265   // and corresponding value are objects. Keys on these last are the
    266   // destinations of the dispatch and the value associated is a counter for
    267   // the correspondent source-destination dispatch chain.
    268   //
    269   // Only non-zero counters are written to file, but an entry in the top-level
    270   // object is always present, even if the value is empty because all counters
    271   // for that source are zero.
    272 
    273   for (int from_index = 0; from_index < kNumberOfBytecodes; ++from_index) {
    274     Bytecode from_bytecode = Bytecodes::FromByte(from_index);
    275     Local<v8::Object> counters_row = v8::Object::New(isolate);
    276 
    277     for (int to_index = 0; to_index < kNumberOfBytecodes; ++to_index) {
    278       Bytecode to_bytecode = Bytecodes::FromByte(to_index);
    279       uintptr_t counter = GetDispatchCounter(from_bytecode, to_bytecode);
    280 
    281       if (counter > 0) {
    282         std::string to_name = Bytecodes::ToString(to_bytecode);
    283         Local<v8::String> to_name_object =
    284             v8::String::NewFromUtf8(isolate, to_name.c_str(),
    285                                     NewStringType::kNormal)
    286                 .ToLocalChecked();
    287         Local<v8::Number> counter_object = v8::Number::New(isolate, counter);
    288         CHECK(counters_row
    289                   ->DefineOwnProperty(context, to_name_object, counter_object)
    290                   .IsJust());
    291       }
    292     }
    293 
    294     std::string from_name = Bytecodes::ToString(from_bytecode);
    295     Local<v8::String> from_name_object =
    296         v8::String::NewFromUtf8(isolate, from_name.c_str(),
    297                                 NewStringType::kNormal)
    298             .ToLocalChecked();
    299 
    300     CHECK(
    301         counters_map->DefineOwnProperty(context, from_name_object, counters_row)
    302             .IsJust());
    303   }
    304 
    305   return counters_map;
    306 }
    307 
    308 }  // namespace interpreter
    309 }  // namespace internal
    310 }  // namespace v8
    311