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

Generated by: LCOV version 1.10