LCOV - code coverage report
Current view: top level - test/cctest/interpreter - bytecode-expectations-printer.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 204 208 98.1 %
Date: 2019-01-20 Functions: 25 25 100.0 %

          Line data    Source code
       1             : // Copyright 2016 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 "test/cctest/interpreter/bytecode-expectations-printer.h"
       6             : 
       7             : #include <iomanip>
       8             : #include <iostream>
       9             : #include <vector>
      10             : 
      11             : #include "include/libplatform/libplatform.h"
      12             : #include "include/v8.h"
      13             : #include "src/api-inl.h"
      14             : #include "src/base/logging.h"
      15             : #include "src/interpreter/bytecode-array-iterator.h"
      16             : #include "src/interpreter/bytecode-generator.h"
      17             : #include "src/interpreter/bytecodes.h"
      18             : #include "src/interpreter/interpreter-intrinsics.h"
      19             : #include "src/interpreter/interpreter.h"
      20             : #include "src/objects-inl.h"
      21             : #include "src/objects/heap-number-inl.h"
      22             : #include "src/objects/module-inl.h"
      23             : #include "src/runtime/runtime.h"
      24             : #include "src/source-position-table.h"
      25             : #include "test/cctest/cctest.h"
      26             : 
      27             : namespace v8 {
      28             : namespace internal {
      29             : namespace interpreter {
      30             : 
      31          15 : static const char* NameForNativeContextIntrinsicIndex(uint32_t idx) {
      32          15 :   switch (idx) {
      33             : #define COMPARE_NATIVE_CONTEXT_INTRINSIC_IDX(NAME, Type, name) \
      34             :   case Context::NAME:                                          \
      35             :     return #name;
      36             : 
      37           0 :     NATIVE_CONTEXT_INTRINSIC_FUNCTIONS(COMPARE_NATIVE_CONTEXT_INTRINSIC_IDX)
      38             : 
      39             :     default:
      40             :       break;
      41             :   }
      42             : 
      43           0 :   return "UnknownIntrinsicIndex";
      44             : }
      45             : 
      46             : // static
      47             : const char* const BytecodeExpectationsPrinter::kDefaultTopFunctionName =
      48             :     "__genbckexp_wrapper__";
      49             : const char* const BytecodeExpectationsPrinter::kIndent = "  ";
      50             : 
      51        4305 : v8::Local<v8::String> BytecodeExpectationsPrinter::V8StringFromUTF8(
      52             :     const char* data) const {
      53        4305 :   return v8::String::NewFromUtf8(isolate_, data, v8::NewStringType::kNormal)
      54        8610 :       .ToLocalChecked();
      55             : }
      56             : 
      57        1430 : std::string BytecodeExpectationsPrinter::WrapCodeInFunction(
      58             :     const char* function_name, const std::string& function_body) const {
      59        1430 :   std::ostringstream program_stream;
      60        1430 :   program_stream << "function " << function_name << "() {" << function_body
      61        1430 :                  << "}\n"
      62        1430 :                  << function_name << "();";
      63             : 
      64        1430 :   return program_stream.str();
      65             : }
      66             : 
      67        2160 : v8::Local<v8::Script> BytecodeExpectationsPrinter::CompileScript(
      68             :     const char* program) const {
      69        2160 :   v8::Local<v8::String> source = V8StringFromUTF8(program);
      70        2160 :   return v8::Script::Compile(isolate_->GetCurrentContext(), source)
      71        4320 :       .ToLocalChecked();
      72             : }
      73             : 
      74          55 : v8::Local<v8::Module> BytecodeExpectationsPrinter::CompileModule(
      75             :     const char* program) const {
      76             :   ScriptOrigin origin(
      77             :       Local<v8::Value>(), Local<v8::Integer>(), Local<v8::Integer>(),
      78             :       Local<v8::Boolean>(), Local<v8::Integer>(), Local<v8::Value>(),
      79          55 :       Local<v8::Boolean>(), Local<v8::Boolean>(), True(isolate_));
      80          55 :   v8::ScriptCompiler::Source source(V8StringFromUTF8(program), origin);
      81         110 :   return v8::ScriptCompiler::CompileModule(isolate_, &source).ToLocalChecked();
      82             : }
      83             : 
      84        2090 : void BytecodeExpectationsPrinter::Run(v8::Local<v8::Script> script) const {
      85        4180 :   MaybeLocal<Value> result = script->Run(isolate_->GetCurrentContext());
      86             :   USE(result);
      87        2090 : }
      88             : 
      89             : i::Handle<v8::internal::BytecodeArray>
      90        2090 : BytecodeExpectationsPrinter::GetBytecodeArrayForGlobal(
      91        2090 :     const char* global_name) const {
      92        2090 :   const v8::Local<v8::Context>& context = isolate_->GetCurrentContext();
      93        2090 :   v8::Local<v8::String> v8_global_name = V8StringFromUTF8(global_name);
      94             :   v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(
      95        6270 :       context->Global()->Get(context, v8_global_name).ToLocalChecked());
      96             :   i::Handle<i::JSFunction> js_function =
      97        2090 :       i::Handle<i::JSFunction>::cast(v8::Utils::OpenHandle(*function));
      98             : 
      99             :   i::Handle<i::BytecodeArray> bytecodes =
     100        4180 :       i::handle(js_function->shared()->GetBytecodeArray(), i_isolate());
     101             : 
     102        2090 :   return bytecodes;
     103             : }
     104             : 
     105             : i::Handle<i::BytecodeArray>
     106          55 : BytecodeExpectationsPrinter::GetBytecodeArrayForModule(
     107          55 :     v8::Local<v8::Module> module) const {
     108             :   i::Handle<i::Module> i_module = v8::Utils::OpenHandle(*module);
     109             :   return i::handle(
     110         110 :       SharedFunctionInfo::cast(i_module->code())->GetBytecodeArray(),
     111         165 :       i_isolate());
     112             : }
     113             : 
     114             : i::Handle<i::BytecodeArray>
     115          70 : BytecodeExpectationsPrinter::GetBytecodeArrayForScript(
     116          70 :     v8::Local<v8::Script> script) const {
     117             :   i::Handle<i::JSFunction> js_function = v8::Utils::OpenHandle(*script);
     118         140 :   return i::handle(js_function->shared()->GetBytecodeArray(), i_isolate());
     119             : }
     120             : 
     121             : i::Handle<i::BytecodeArray>
     122         105 : BytecodeExpectationsPrinter::GetBytecodeArrayOfCallee(
     123         105 :     const char* source_code) const {
     124             :   i::Handle<i::Object> i_object =
     125         105 :       v8::Utils::OpenHandle(*CompileRun(source_code));
     126             :   i::Handle<i::JSFunction> js_function =
     127         105 :       i::Handle<i::JSFunction>::cast(i_object);
     128         105 :   CHECK(js_function->shared()->HasBytecodeArray());
     129         210 :   return i::handle(js_function->shared()->GetBytecodeArray(), i_isolate());
     130             : }
     131             : 
     132       22980 : void BytecodeExpectationsPrinter::PrintEscapedString(
     133             :     std::ostream& stream, const std::string& string) const {
     134      351090 :   for (char c : string) {
     135      305130 :     switch (c) {
     136             :       case '"':
     137         540 :         stream << "\\\"";
     138         540 :         break;
     139             :       case '\\':
     140          15 :         stream << "\\\\";
     141          15 :         break;
     142             :       default:
     143             :         stream << c;
     144             :         break;
     145             :     }
     146             :   }
     147       22980 : }
     148             : 
     149       77430 : void BytecodeExpectationsPrinter::PrintBytecodeOperand(
     150             :     std::ostream& stream, const BytecodeArrayIterator& bytecode_iterator,
     151             :     const Bytecode& bytecode, int op_index, int parameter_count) const {
     152       77430 :   OperandType op_type = Bytecodes::GetOperandType(bytecode, op_index);
     153             :   OperandSize op_size = Bytecodes::GetOperandSize(
     154       77430 :       bytecode, op_index, bytecode_iterator.current_operand_scale());
     155             : 
     156             :   const char* size_tag;
     157       77430 :   switch (op_size) {
     158             :     case OperandSize::kByte:
     159             :       size_tag = "8";
     160             :       break;
     161             :     case OperandSize::kShort:
     162             :       size_tag = "16";
     163        1670 :       break;
     164             :     case OperandSize::kQuad:
     165             :       size_tag = "32";
     166           5 :       break;
     167             :     default:
     168           0 :       UNREACHABLE();
     169             :       return;
     170             :   }
     171             : 
     172       77430 :   if (Bytecodes::IsRegisterOperandType(op_type)) {
     173       36495 :     Register register_value = bytecode_iterator.GetRegisterOperand(op_index);
     174             :     stream << 'R';
     175       36495 :     if (op_size != OperandSize::kByte) stream << size_tag;
     176       36495 :     if (register_value.is_current_context()) {
     177         345 :       stream << "(context)";
     178       36150 :     } else if (register_value.is_function_closure()) {
     179         290 :       stream << "(closure)";
     180       35860 :     } else if (register_value.is_parameter()) {
     181        4925 :       int parameter_index = register_value.ToParameterIndex(parameter_count);
     182        4925 :       if (parameter_index == 0) {
     183         445 :         stream << "(this)";
     184             :       } else {
     185        4480 :         stream << "(arg" << (parameter_index - 1) << ')';
     186             :       }
     187             :     } else {
     188       30935 :       stream << '(' << register_value.index() << ')';
     189             :     }
     190             :   } else {
     191       40935 :     switch (op_type) {
     192             :       case OperandType::kFlag8:
     193        1145 :         stream << 'U' << size_tag << '(';
     194        1145 :         stream << bytecode_iterator.GetFlagOperand(op_index);
     195             :         break;
     196             :       case OperandType::kIdx: {
     197       24110 :         stream << 'U' << size_tag << '(';
     198       24110 :         stream << bytecode_iterator.GetIndexOperand(op_index);
     199             :         break;
     200             :       }
     201             :       case OperandType::kUImm:
     202        4500 :         stream << 'U' << size_tag << '(';
     203        4500 :         stream << bytecode_iterator.GetUnsignedImmediateOperand(op_index);
     204             :         break;
     205             :       case OperandType::kImm:
     206        7010 :         stream << 'I' << size_tag << '(';
     207        7010 :         stream << bytecode_iterator.GetImmediateOperand(op_index);
     208        7010 :         break;
     209             :       case OperandType::kRegCount:
     210        2430 :         stream << 'U' << size_tag << '(';
     211        2430 :         stream << bytecode_iterator.GetRegisterCountOperand(op_index);
     212             :         break;
     213             :       case OperandType::kRuntimeId: {
     214        1070 :         stream << 'U' << size_tag << '(';
     215             :         Runtime::FunctionId id =
     216        1070 :             bytecode_iterator.GetRuntimeIdOperand(op_index);
     217        1070 :         stream << "Runtime::k" << i::Runtime::FunctionForId(id)->name;
     218        1070 :         break;
     219             :       }
     220             :       case OperandType::kIntrinsicId: {
     221         655 :         stream << 'U' << size_tag << '(';
     222             :         Runtime::FunctionId id =
     223         655 :             bytecode_iterator.GetIntrinsicIdOperand(op_index);
     224         655 :         stream << "Runtime::k" << i::Runtime::FunctionForId(id)->name;
     225         655 :         break;
     226             :       }
     227             :       case OperandType::kNativeContextIndex: {
     228          15 :         stream << 'U' << size_tag << '(';
     229          15 :         uint32_t idx = bytecode_iterator.GetNativeContextIndexOperand(op_index);
     230          15 :         stream << "%" << NameForNativeContextIntrinsicIndex(idx);
     231          15 :         break;
     232             :       }
     233             :       default:
     234           0 :         UNREACHABLE();
     235             :     }
     236             : 
     237             :     stream << ')';
     238             :   }
     239       77430 : }
     240             : 
     241       58425 : void BytecodeExpectationsPrinter::PrintBytecode(
     242             :     std::ostream& stream, const BytecodeArrayIterator& bytecode_iterator,
     243             :     int parameter_count) const {
     244       58425 :   Bytecode bytecode = bytecode_iterator.current_bytecode();
     245             :   OperandScale operand_scale = bytecode_iterator.current_operand_scale();
     246       58425 :   if (Bytecodes::OperandScaleRequiresPrefixBytecode(operand_scale)) {
     247         415 :     Bytecode prefix = Bytecodes::OperandScaleToPrefixBytecode(operand_scale);
     248         415 :     stream << "B(" << Bytecodes::ToString(prefix) << "), ";
     249             :   }
     250       58425 :   stream << "B(" << Bytecodes::ToString(bytecode) << ')';
     251       58425 :   int operands_count = Bytecodes::NumberOfOperands(bytecode);
     252      135855 :   for (int op_index = 0; op_index < operands_count; ++op_index) {
     253       77430 :     stream << ", ";
     254             :     PrintBytecodeOperand(stream, bytecode_iterator, bytecode, op_index,
     255       77430 :                          parameter_count);
     256             :   }
     257       58425 : }
     258             : 
     259       58425 : void BytecodeExpectationsPrinter::PrintSourcePosition(
     260      168330 :     std::ostream& stream, SourcePositionTableIterator& source_iterator,
     261             :     int bytecode_offset) const {
     262             :   static const size_t kPositionWidth = 4;
     263      116850 :   if (!source_iterator.done() &&
     264             :       source_iterator.code_offset() == bytecode_offset) {
     265       25740 :     stream << "/* " << std::setw(kPositionWidth)
     266       25740 :            << source_iterator.source_position().ScriptOffset();
     267       25740 :     if (source_iterator.is_statement()) {
     268       16700 :       stream << " S> */ ";
     269             :     } else {
     270        9040 :       stream << " E> */ ";
     271             :     }
     272       25740 :     source_iterator.Advance();
     273             :   } else {
     274       65370 :     stream << "   " << std::setw(kPositionWidth) << ' ' << "       ";
     275             :   }
     276       58425 : }
     277             : 
     278        6575 : void BytecodeExpectationsPrinter::PrintV8String(std::ostream& stream,
     279             :                                                 i::String string) const {
     280             :   stream << '"';
     281       44115 :   for (int i = 0, length = string->length(); i < length; ++i) {
     282       37540 :     stream << i::AsEscapedUC16ForJSON(string->Get(i));
     283             :   }
     284             :   stream << '"';
     285        6575 : }
     286             : 
     287        9170 : void BytecodeExpectationsPrinter::PrintConstant(
     288             :     std::ostream& stream, i::Handle<i::Object> constant) const {
     289       18340 :   if (constant->IsSmi()) {
     290         725 :     stream << "Smi [";
     291         725 :     i::Smi::cast(*constant)->SmiPrint(stream);
     292         725 :     stream << "]";
     293             :   } else {
     294        8445 :     stream << i::HeapObject::cast(*constant)->map()->instance_type();
     295       16890 :     if (constant->IsHeapNumber()) {
     296          25 :       stream << " [";
     297          25 :       i::HeapNumber::cast(*constant)->HeapNumberPrint(stream);
     298          25 :       stream << "]";
     299       16840 :     } else if (constant->IsString()) {
     300        6575 :       stream << " [";
     301        6575 :       PrintV8String(stream, i::String::cast(*constant));
     302        6575 :       stream << "]";
     303             :     }
     304             :   }
     305        9170 : }
     306             : 
     307        2320 : void BytecodeExpectationsPrinter::PrintFrameSize(
     308             :     std::ostream& stream, i::Handle<i::BytecodeArray> bytecode_array) const {
     309             :   const int kPointerSize = sizeof(void*);
     310             :   int frame_size = bytecode_array->frame_size();
     311             : 
     312             :   DCHECK_EQ(frame_size % kPointerSize, 0);
     313        2320 :   stream << "frame size: " << frame_size / kPointerSize
     314        2320 :          << "\nparameter count: " << bytecode_array->parameter_count() << '\n';
     315        2320 : }
     316             : 
     317        2320 : void BytecodeExpectationsPrinter::PrintBytecodeSequence(
     318             :     std::ostream& stream, i::Handle<i::BytecodeArray> bytecode_array) const {
     319        2320 :   stream << "bytecode array length: " << bytecode_array->length()
     320        2320 :          << "\nbytecodes: [\n";
     321             : 
     322             :   SourcePositionTableIterator source_iterator(
     323        2320 :       bytecode_array->SourcePositionTable());
     324        2320 :   BytecodeArrayIterator bytecode_iterator(bytecode_array);
     325       60745 :   for (; !bytecode_iterator.done(); bytecode_iterator.Advance()) {
     326       58425 :     stream << kIndent;
     327             :     PrintSourcePosition(stream, source_iterator,
     328       58425 :                         bytecode_iterator.current_offset());
     329       58425 :     PrintBytecode(stream, bytecode_iterator, bytecode_array->parameter_count());
     330       58425 :     stream << ",\n";
     331             :   }
     332        2320 :   stream << "]\n";
     333        2320 : }
     334             : 
     335        2320 : void BytecodeExpectationsPrinter::PrintConstantPool(
     336        9170 :     std::ostream& stream, i::FixedArray constant_pool) const {
     337        2320 :   stream << "constant pool: [\n";
     338             :   int num_constants = constant_pool->length();
     339        2320 :   if (num_constants > 0) {
     340        9170 :     for (int i = 0; i < num_constants; ++i) {
     341        9170 :       stream << kIndent;
     342        9170 :       PrintConstant(stream, i::FixedArray::get(constant_pool, i, i_isolate()));
     343        9170 :       stream << ",\n";
     344             :     }
     345             :   }
     346        2320 :   stream << "]\n";
     347        2320 : }
     348             : 
     349        2320 : void BytecodeExpectationsPrinter::PrintCodeSnippet(
     350             :     std::ostream& stream, const std::string& body) const {
     351        2320 :   stream << "snippet: \"\n";
     352        2320 :   std::stringstream body_stream(body);
     353             :   std::string body_line;
     354       50600 :   while (std::getline(body_stream, body_line)) {
     355       22980 :     stream << kIndent;
     356       22980 :     PrintEscapedString(stream, body_line);
     357             :     stream << '\n';
     358             :   }
     359        4640 :   stream << "\"\n";
     360        2320 : }
     361             : 
     362        2320 : void BytecodeExpectationsPrinter::PrintHandlers(
     363             :     std::ostream& stream, i::Handle<i::BytecodeArray> bytecode_array) const {
     364        2320 :   stream << "handlers: [\n";
     365        2320 :   HandlerTable table(*bytecode_array);
     366        2655 :   for (int i = 0, num_entries = table.NumberOfRangeEntries(); i < num_entries;
     367             :        ++i) {
     368         335 :     stream << "  [" << table.GetRangeStart(i) << ", " << table.GetRangeEnd(i)
     369         670 :            << ", " << table.GetRangeHandler(i) << "],\n";
     370             :   }
     371        2320 :   stream << "]\n";
     372        2320 : }
     373             : 
     374        2320 : void BytecodeExpectationsPrinter::PrintBytecodeArray(
     375             :     std::ostream& stream, i::Handle<i::BytecodeArray> bytecode_array) const {
     376        2320 :   PrintFrameSize(stream, bytecode_array);
     377        2320 :   PrintBytecodeSequence(stream, bytecode_array);
     378        2320 :   PrintConstantPool(stream, bytecode_array->constant_pool());
     379        2320 :   PrintHandlers(stream, bytecode_array);
     380        2320 : }
     381             : 
     382        2320 : void BytecodeExpectationsPrinter::PrintExpectation(
     383             :     std::ostream& stream, const std::string& snippet) const {
     384             :   std::string source_code =
     385             :       wrap_ ? WrapCodeInFunction(test_function_name_.c_str(), snippet)
     386        3750 :             : snippet;
     387             : 
     388        2320 :   i::FLAG_enable_one_shot_optimization = oneshot_opt_;
     389        2320 :   i::FLAG_compilation_cache = false;
     390             :   i::Handle<i::BytecodeArray> bytecode_array;
     391        2320 :   if (module_) {
     392          55 :     CHECK(top_level_ && !wrap_);
     393          55 :     v8::Local<v8::Module> module = CompileModule(source_code.c_str());
     394          55 :     bytecode_array = GetBytecodeArrayForModule(module);
     395        2265 :   } else if (print_callee_) {
     396         105 :     bytecode_array = GetBytecodeArrayOfCallee(source_code.c_str());
     397             :   } else {
     398        2160 :     v8::Local<v8::Script> script = CompileScript(source_code.c_str());
     399        2160 :     if (top_level_) {
     400          70 :       bytecode_array = GetBytecodeArrayForScript(script);
     401             :     } else {
     402        2090 :       Run(script);
     403        2090 :       bytecode_array = GetBytecodeArrayForGlobal(test_function_name_.c_str());
     404             :     }
     405             :   }
     406             : 
     407        2320 :   stream << "---\n";
     408        2320 :   PrintCodeSnippet(stream, snippet);
     409        2320 :   PrintBytecodeArray(stream, bytecode_array);
     410             :   stream << '\n';
     411        2320 : }
     412             : 
     413             : }  // namespace interpreter
     414             : }  // namespace internal
     415       85011 : }  // namespace v8

Generated by: LCOV version 1.10