LCOV - code coverage report
Current view: top level - test/cctest/interpreter - bytecode-expectations-printer.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 191 194 98.5 %
Date: 2017-10-20 Functions: 24 24 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             : 
      14             : #include "src/api.h"
      15             : #include "src/base/logging.h"
      16             : #include "src/objects-inl.h"
      17             : #include "src/runtime/runtime.h"
      18             : 
      19             : #include "src/interpreter/bytecode-array-iterator.h"
      20             : #include "src/interpreter/bytecode-generator.h"
      21             : #include "src/interpreter/bytecodes.h"
      22             : #include "src/interpreter/interpreter-intrinsics.h"
      23             : #include "src/interpreter/interpreter.h"
      24             : #include "src/source-position-table.h"
      25             : 
      26             : namespace v8 {
      27             : namespace internal {
      28             : namespace interpreter {
      29             : 
      30         366 : static const char* NameForNativeContextIntrinsicIndex(uint32_t idx) {
      31         366 :   switch (idx) {
      32             : #define COMPARE_NATIVE_CONTEXT_INTRINSIC_IDX(NAME, Type, name) \
      33             :   case Context::NAME:                                          \
      34             :     return #name;
      35             : 
      36          48 :     NATIVE_CONTEXT_INTRINSIC_FUNCTIONS(COMPARE_NATIVE_CONTEXT_INTRINSIC_IDX)
      37             : 
      38             :     default:
      39             :       break;
      40             :   }
      41             : 
      42           0 :   return "UnknownIntrinsicIndex";
      43             : }
      44             : 
      45             : // static
      46             : const char* const BytecodeExpectationsPrinter::kDefaultTopFunctionName =
      47             :     "__genbckexp_wrapper__";
      48             : const char* const BytecodeExpectationsPrinter::kIndent = "  ";
      49             : 
      50        5016 : v8::Local<v8::String> BytecodeExpectationsPrinter::V8StringFromUTF8(
      51             :     const char* data) const {
      52        5016 :   return v8::String::NewFromUtf8(isolate_, data, v8::NewStringType::kNormal)
      53       10032 :       .ToLocalChecked();
      54             : }
      55             : 
      56        1638 : std::string BytecodeExpectationsPrinter::WrapCodeInFunction(
      57             :     const char* function_name, const std::string& function_body) const {
      58        1638 :   std::ostringstream program_stream;
      59        1638 :   program_stream << "function " << function_name << "() {" << function_body
      60        1638 :                  << "}\n"
      61        1638 :                  << function_name << "();";
      62             : 
      63        1638 :   return program_stream.str();
      64             : }
      65             : 
      66        2490 : v8::Local<v8::Script> BytecodeExpectationsPrinter::CompileScript(
      67             :     const char* program) const {
      68        2490 :   v8::Local<v8::String> source = V8StringFromUTF8(program);
      69        2490 :   return v8::Script::Compile(isolate_->GetCurrentContext(), source)
      70        4980 :       .ToLocalChecked();
      71             : }
      72             : 
      73          66 : v8::Local<v8::Module> BytecodeExpectationsPrinter::CompileModule(
      74             :     const char* program) const {
      75             :   ScriptOrigin origin(
      76             :       Local<v8::Value>(), Local<v8::Integer>(), Local<v8::Integer>(),
      77             :       Local<v8::Boolean>(), Local<v8::Integer>(), Local<v8::Value>(),
      78          66 :       Local<v8::Boolean>(), Local<v8::Boolean>(), True(isolate_));
      79          66 :   v8::ScriptCompiler::Source source(V8StringFromUTF8(program), origin);
      80         132 :   return v8::ScriptCompiler::CompileModule(isolate_, &source).ToLocalChecked();
      81             : }
      82             : 
      83        2460 : void BytecodeExpectationsPrinter::Run(v8::Local<v8::Script> script) const {
      84        4920 :   (void)script->Run(isolate_->GetCurrentContext());
      85        2460 : }
      86             : 
      87             : i::Handle<v8::internal::BytecodeArray>
      88        2460 : BytecodeExpectationsPrinter::GetBytecodeArrayForGlobal(
      89        2460 :     const char* global_name) const {
      90        2460 :   const v8::Local<v8::Context>& context = isolate_->GetCurrentContext();
      91        2460 :   v8::Local<v8::String> v8_global_name = V8StringFromUTF8(global_name);
      92             :   v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(
      93        7380 :       context->Global()->Get(context, v8_global_name).ToLocalChecked());
      94             :   i::Handle<i::JSFunction> js_function =
      95             :       i::Handle<i::JSFunction>::cast(v8::Utils::OpenHandle(*function));
      96             : 
      97             :   i::Handle<i::BytecodeArray> bytecodes =
      98             :       i::handle(js_function->shared()->bytecode_array(), i_isolate());
      99             : 
     100        2460 :   return bytecodes;
     101             : }
     102             : 
     103             : i::Handle<i::BytecodeArray>
     104          66 : BytecodeExpectationsPrinter::GetBytecodeArrayForModule(
     105          66 :     v8::Local<v8::Module> module) const {
     106             :   i::Handle<i::Module> i_module = v8::Utils::OpenHandle(*module);
     107             :   return i::handle(SharedFunctionInfo::cast(i_module->code())->bytecode_array(),
     108          66 :                    i_isolate());
     109             : }
     110             : 
     111             : i::Handle<i::BytecodeArray>
     112          30 : BytecodeExpectationsPrinter::GetBytecodeArrayForScript(
     113          30 :     v8::Local<v8::Script> script) const {
     114             :   i::Handle<i::JSFunction> js_function = v8::Utils::OpenHandle(*script);
     115          30 :   return i::handle(js_function->shared()->bytecode_array(), i_isolate());
     116             : }
     117             : 
     118       39276 : void BytecodeExpectationsPrinter::PrintEscapedString(
     119             :     std::ostream& stream, const std::string& string) const {
     120      600504 :   for (char c : string) {
     121      521952 :     switch (c) {
     122             :       case '"':
     123       13140 :         stream << "\\\"";
     124       13140 :         break;
     125             :       case '\\':
     126          18 :         stream << "\\\\";
     127          18 :         break;
     128             :       default:
     129             :         stream << c;
     130             :         break;
     131             :     }
     132             :   }
     133       39276 : }
     134             : 
     135      121254 : void BytecodeExpectationsPrinter::PrintBytecodeOperand(
     136             :     std::ostream& stream, const BytecodeArrayIterator& bytecode_iterator,
     137             :     const Bytecode& bytecode, int op_index, int parameter_count) const {
     138      121254 :   OperandType op_type = Bytecodes::GetOperandType(bytecode, op_index);
     139             :   OperandSize op_size = Bytecodes::GetOperandSize(
     140      121254 :       bytecode, op_index, bytecode_iterator.current_operand_scale());
     141             : 
     142             :   const char* size_tag;
     143      121254 :   switch (op_size) {
     144             :     case OperandSize::kByte:
     145             :       size_tag = "8";
     146             :       break;
     147             :     case OperandSize::kShort:
     148             :       size_tag = "16";
     149        2256 :       break;
     150             :     case OperandSize::kQuad:
     151             :       size_tag = "32";
     152           6 :       break;
     153             :     default:
     154           0 :       UNREACHABLE();
     155             :       return;
     156             :   }
     157             : 
     158      121254 :   if (Bytecodes::IsRegisterOperandType(op_type)) {
     159       57750 :     Register register_value = bytecode_iterator.GetRegisterOperand(op_index);
     160             :     stream << 'R';
     161       57750 :     if (op_size != OperandSize::kByte) stream << size_tag;
     162       57750 :     if (register_value.is_current_context()) {
     163         534 :       stream << "(context)";
     164       57216 :     } else if (register_value.is_function_closure()) {
     165         750 :       stream << "(closure)";
     166       56466 :     } else if (register_value.is_parameter()) {
     167       10986 :       int parameter_index = register_value.ToParameterIndex(parameter_count);
     168       10986 :       if (parameter_index == 0) {
     169         360 :         stream << "(this)";
     170             :       } else {
     171       10626 :         stream << "(arg" << (parameter_index - 1) << ')';
     172             :       }
     173             :     } else {
     174       45480 :       stream << '(' << register_value.index() << ')';
     175             :     }
     176             :   } else {
     177       63504 :     switch (op_type) {
     178             :       case OperandType::kFlag8:
     179        1020 :         stream << 'U' << size_tag << '(';
     180        1020 :         stream << bytecode_iterator.GetFlagOperand(op_index);
     181             :         break;
     182             :       case OperandType::kIdx: {
     183       39342 :         stream << 'U' << size_tag << '(';
     184       39342 :         stream << bytecode_iterator.GetIndexOperand(op_index);
     185             :         break;
     186             :       }
     187             :       case OperandType::kUImm:
     188        5994 :         stream << 'U' << size_tag << '(';
     189        5994 :         stream << bytecode_iterator.GetUnsignedImmediateOperand(op_index);
     190             :         break;
     191             :       case OperandType::kImm:
     192       10608 :         stream << 'I' << size_tag << '(';
     193       10608 :         stream << bytecode_iterator.GetImmediateOperand(op_index);
     194       10608 :         break;
     195             :       case OperandType::kRegCount:
     196        3600 :         stream << 'U' << size_tag << '(';
     197        3600 :         stream << bytecode_iterator.GetRegisterCountOperand(op_index);
     198             :         break;
     199             :       case OperandType::kRuntimeId: {
     200        1092 :         stream << 'U' << size_tag << '(';
     201             :         Runtime::FunctionId id =
     202        1092 :             bytecode_iterator.GetRuntimeIdOperand(op_index);
     203        1092 :         stream << "Runtime::k" << i::Runtime::FunctionForId(id)->name;
     204        1092 :         break;
     205             :       }
     206             :       case OperandType::kIntrinsicId: {
     207        1482 :         stream << 'U' << size_tag << '(';
     208             :         Runtime::FunctionId id =
     209        1482 :             bytecode_iterator.GetIntrinsicIdOperand(op_index);
     210        1482 :         stream << "Runtime::k" << i::Runtime::FunctionForId(id)->name;
     211        1482 :         break;
     212             :       }
     213             :       case OperandType::kNativeContextIndex: {
     214         366 :         stream << 'U' << size_tag << '(';
     215         366 :         uint32_t idx = bytecode_iterator.GetNativeContextIndexOperand(op_index);
     216         366 :         stream << "%" << NameForNativeContextIntrinsicIndex(idx);
     217         366 :         break;
     218             :       }
     219             :       default:
     220           0 :         UNREACHABLE();
     221             :     }
     222             : 
     223             :     stream << ')';
     224             :   }
     225      121254 : }
     226             : 
     227       99336 : void BytecodeExpectationsPrinter::PrintBytecode(
     228             :     std::ostream& stream, const BytecodeArrayIterator& bytecode_iterator,
     229             :     int parameter_count) const {
     230       99336 :   Bytecode bytecode = bytecode_iterator.current_bytecode();
     231             :   OperandScale operand_scale = bytecode_iterator.current_operand_scale();
     232       99336 :   if (Bytecodes::OperandScaleRequiresPrefixBytecode(operand_scale)) {
     233         906 :     Bytecode prefix = Bytecodes::OperandScaleToPrefixBytecode(operand_scale);
     234         906 :     stream << "B(" << Bytecodes::ToString(prefix) << "), ";
     235             :   }
     236       99336 :   stream << "B(" << Bytecodes::ToString(bytecode) << ')';
     237       99336 :   int operands_count = Bytecodes::NumberOfOperands(bytecode);
     238      220590 :   for (int op_index = 0; op_index < operands_count; ++op_index) {
     239      121254 :     stream << ", ";
     240             :     PrintBytecodeOperand(stream, bytecode_iterator, bytecode, op_index,
     241      121254 :                          parameter_count);
     242             :   }
     243       99336 : }
     244             : 
     245       99336 : void BytecodeExpectationsPrinter::PrintSourcePosition(
     246      286440 :     std::ostream& stream, SourcePositionTableIterator& source_iterator,
     247             :     int bytecode_offset) const {
     248             :   static const size_t kPositionWidth = 4;
     249      198672 :   if (!source_iterator.done() &&
     250             :       source_iterator.code_offset() == bytecode_offset) {
     251       43884 :     stream << "/* " << std::setw(kPositionWidth)
     252       43884 :            << source_iterator.source_position().ScriptOffset();
     253       43884 :     if (source_iterator.is_statement()) {
     254       32862 :       stream << " S> */ ";
     255             :     } else {
     256       11022 :       stream << " E> */ ";
     257             :     }
     258       43884 :     source_iterator.Advance();
     259             :   } else {
     260      110904 :     stream << "   " << std::setw(kPositionWidth) << ' ' << "       ";
     261             :   }
     262       99336 : }
     263             : 
     264        1776 : void BytecodeExpectationsPrinter::PrintV8String(std::ostream& stream,
     265             :                                                 i::String* string) const {
     266             :   stream << '"';
     267        8358 :   for (int i = 0, length = string->length(); i < length; ++i) {
     268        6582 :     stream << i::AsEscapedUC16ForJSON(string->Get(i));
     269             :   }
     270             :   stream << '"';
     271        1776 : }
     272             : 
     273       18474 : void BytecodeExpectationsPrinter::PrintConstant(
     274             :     std::ostream& stream, i::Handle<i::Object> constant) const {
     275       18474 :   if (constant->IsSmi()) {
     276        1056 :     stream << "Smi [";
     277        1056 :     i::Smi::cast(*constant)->SmiPrint(stream);
     278        1056 :     stream << "]";
     279             :   } else {
     280       17418 :     stream << i::HeapObject::cast(*constant)->map()->instance_type();
     281       17418 :     if (constant->IsHeapNumber()) {
     282       14202 :       stream << " [";
     283       14202 :       i::HeapNumber::cast(*constant)->HeapNumberPrint(stream);
     284       14202 :       stream << "]";
     285        3216 :     } else if (constant->IsString()) {
     286        1776 :       stream << " [";
     287        1776 :       PrintV8String(stream, i::String::cast(*constant));
     288        1776 :       stream << "]";
     289             :     }
     290             :   }
     291       18474 : }
     292             : 
     293        2556 : void BytecodeExpectationsPrinter::PrintFrameSize(
     294             :     std::ostream& stream, i::Handle<i::BytecodeArray> bytecode_array) const {
     295             :   const int kPointerSize = sizeof(void*);
     296             :   int frame_size = bytecode_array->frame_size();
     297             : 
     298             :   DCHECK_EQ(frame_size % kPointerSize, 0);
     299        2556 :   stream << "frame size: " << frame_size / kPointerSize
     300        2556 :          << "\nparameter count: " << bytecode_array->parameter_count() << '\n';
     301        2556 : }
     302             : 
     303        2556 : void BytecodeExpectationsPrinter::PrintBytecodeSequence(
     304             :     std::ostream& stream, i::Handle<i::BytecodeArray> bytecode_array) const {
     305        2556 :   stream << "bytecode array length: " << bytecode_array->length()
     306        2556 :          << "\nbytecodes: [\n";
     307             : 
     308             :   SourcePositionTableIterator source_iterator(
     309        2556 :       bytecode_array->SourcePositionTable());
     310        2556 :   BytecodeArrayIterator bytecode_iterator(bytecode_array);
     311      101892 :   for (; !bytecode_iterator.done(); bytecode_iterator.Advance()) {
     312       99336 :     stream << kIndent;
     313             :     PrintSourcePosition(stream, source_iterator,
     314       99336 :                         bytecode_iterator.current_offset());
     315       99336 :     PrintBytecode(stream, bytecode_iterator, bytecode_array->parameter_count());
     316       99336 :     stream << ",\n";
     317             :   }
     318        2556 :   stream << "]\n";
     319        2556 : }
     320             : 
     321        2556 : void BytecodeExpectationsPrinter::PrintConstantPool(
     322       18474 :     std::ostream& stream, i::FixedArray* constant_pool) const {
     323        2556 :   stream << "constant pool: [\n";
     324             :   int num_constants = constant_pool->length();
     325        2556 :   if (num_constants > 0) {
     326       18474 :     for (int i = 0; i < num_constants; ++i) {
     327       18474 :       stream << kIndent;
     328       18474 :       PrintConstant(stream, i::FixedArray::get(constant_pool, i, i_isolate()));
     329       18474 :       stream << ",\n";
     330             :     }
     331             :   }
     332        2556 :   stream << "]\n";
     333        2556 : }
     334             : 
     335        2556 : void BytecodeExpectationsPrinter::PrintCodeSnippet(
     336             :     std::ostream& stream, const std::string& body) const {
     337        2556 :   stream << "snippet: \"\n";
     338        2556 :   std::stringstream body_stream(body);
     339             :   std::string body_line;
     340       83664 :   while (std::getline(body_stream, body_line)) {
     341       39276 :     stream << kIndent;
     342       39276 :     PrintEscapedString(stream, body_line);
     343             :     stream << '\n';
     344             :   }
     345        5112 :   stream << "\"\n";
     346        2556 : }
     347             : 
     348        2556 : void BytecodeExpectationsPrinter::PrintHandlers(
     349             :     std::ostream& stream, i::Handle<i::BytecodeArray> bytecode_array) const {
     350        2556 :   stream << "handlers: [\n";
     351             :   HandlerTable* table = HandlerTable::cast(bytecode_array->handler_table());
     352        3078 :   for (int i = 0, num_entries = table->NumberOfRangeEntries(); i < num_entries;
     353             :        ++i) {
     354        1044 :     stream << "  [" << table->GetRangeStart(i) << ", " << table->GetRangeEnd(i)
     355        1044 :            << ", " << table->GetRangeHandler(i) << "],\n";
     356             :   }
     357        2556 :   stream << "]\n";
     358        2556 : }
     359             : 
     360        2556 : void BytecodeExpectationsPrinter::PrintBytecodeArray(
     361             :     std::ostream& stream, i::Handle<i::BytecodeArray> bytecode_array) const {
     362        2556 :   PrintFrameSize(stream, bytecode_array);
     363        2556 :   PrintBytecodeSequence(stream, bytecode_array);
     364        2556 :   PrintConstantPool(stream, bytecode_array->constant_pool());
     365        2556 :   PrintHandlers(stream, bytecode_array);
     366        2556 : }
     367             : 
     368        2556 : void BytecodeExpectationsPrinter::PrintExpectation(
     369             :     std::ostream& stream, const std::string& snippet) const {
     370             :   std::string source_code =
     371             :       wrap_ ? WrapCodeInFunction(test_function_name_.c_str(), snippet)
     372        4194 :             : snippet;
     373             : 
     374             :   i::Handle<i::BytecodeArray> bytecode_array;
     375        2556 :   if (module_) {
     376          66 :     CHECK(top_level_ && !wrap_);
     377          66 :     v8::Local<v8::Module> module = CompileModule(source_code.c_str());
     378          66 :     bytecode_array = GetBytecodeArrayForModule(module);
     379             :   } else {
     380        2490 :     v8::Local<v8::Script> script = CompileScript(source_code.c_str());
     381        2490 :     if (top_level_) {
     382          30 :       bytecode_array = GetBytecodeArrayForScript(script);
     383             :     } else {
     384        2460 :       Run(script);
     385        2460 :       bytecode_array = GetBytecodeArrayForGlobal(test_function_name_.c_str());
     386             :     }
     387             :   }
     388             : 
     389        2556 :   stream << "---\n";
     390        2556 :   PrintCodeSnippet(stream, snippet);
     391        2556 :   PrintBytecodeArray(stream, bytecode_array);
     392             :   stream << '\n';
     393        2556 : }
     394             : 
     395             : }  // namespace interpreter
     396             : }  // namespace internal
     397       71154 : }  // namespace v8

Generated by: LCOV version 1.10