Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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.h" | |
| 6 | |
| 7 #include <iostream> | |
| 8 | |
| 9 #include "include/libplatform/libplatform.h" | |
| 10 #include "include/v8.h" | |
| 11 | |
| 12 #include "src/base/logging.h" | |
| 13 #include "src/base/smart-pointers.h" | |
| 14 #include "src/compiler.h" | |
| 15 | |
| 16 #include "src/interpreter/bytecode-array-iterator.h" | |
| 17 #include "src/interpreter/bytecode-generator.h" | |
| 18 #include "src/interpreter/bytecodes.h" | |
| 19 #include "src/interpreter/interpreter.h" | |
| 20 | |
| 21 using namespace v8::internal::interpreter; | |
| 22 | |
| 23 namespace { | |
| 24 | |
| 25 i::Isolate* GetInternalIsolate(v8::Isolate* isolate) { | |
|
rmcilroy
2016/02/12 15:29:05
Move this to generate-bytecode-expectations.cc and
Stefano Sanfilippo
2016/02/12 18:29:40
Turns out we need the external Isolate as well, fo
rmcilroy
2016/02/15 11:15:19
What you've done here is fine (modulo the rename o
| |
| 26 return reinterpret_cast<i::Isolate*>(isolate); | |
| 27 } | |
| 28 | |
| 29 v8::Local<v8::String> V8StringFromUTF8(v8::Isolate* isolate, const char* data) { | |
| 30 return v8::String::NewFromUtf8(isolate, data, v8::NewStringType::kNormal) | |
| 31 .ToLocalChecked(); | |
| 32 } | |
| 33 | |
| 34 std::string WrapCodeInFunction(const char* function_name, | |
| 35 const std::string& function_body) { | |
| 36 std::ostringstream program_stream; | |
| 37 program_stream << "function " << function_name << "() {" << function_body | |
| 38 << "}\n" | |
| 39 << function_name << "();"; | |
| 40 | |
| 41 return program_stream.str(); | |
| 42 } | |
| 43 | |
| 44 v8::Local<v8::Value> CompileAndRun(v8::Isolate* isolate, const char* program) { | |
| 45 v8::Local<v8::String> source = V8StringFromUTF8(isolate, program); | |
| 46 v8::Local<v8::Script> script = | |
| 47 v8::Script::Compile(isolate->GetCurrentContext(), source) | |
| 48 .ToLocalChecked(); | |
| 49 | |
| 50 v8::Local<v8::Value> result; | |
| 51 CHECK(script->Run(isolate->GetCurrentContext()).ToLocal(&result)); | |
| 52 | |
| 53 return result; | |
| 54 } | |
| 55 | |
| 56 i::Handle<v8::internal::BytecodeArray> GetBytecodeArrayForGlobal( | |
| 57 v8::Isolate* isolate, const char* global_name) { | |
| 58 const v8::Local<v8::Context>& context = isolate->GetCurrentContext(); | |
| 59 v8::Local<v8::String> v8_global_name = V8StringFromUTF8(isolate, global_name); | |
| 60 v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast( | |
| 61 context->Global()->Get(context, v8_global_name).ToLocalChecked()); | |
| 62 i::Handle<i::JSFunction> js_function = | |
| 63 i::Handle<i::JSFunction>::cast(v8::Utils::OpenHandle(*function)); | |
| 64 | |
| 65 i::Handle<i::BytecodeArray> bytecodes = i::handle( | |
| 66 js_function->shared()->bytecode_array(), GetInternalIsolate(isolate)); | |
| 67 | |
| 68 return bytecodes; | |
| 69 } | |
| 70 | |
| 71 void PrintEscapedString(std::ostream& stream, const std::string& string) { | |
| 72 for (char c : string) { | |
| 73 switch (c) { | |
| 74 case '"': | |
| 75 stream << "\\\""; | |
| 76 break; | |
| 77 case '\\': | |
| 78 stream << "\\\\"; | |
| 79 break; | |
| 80 default: | |
| 81 stream << c; | |
| 82 break; | |
| 83 } | |
| 84 } | |
| 85 } | |
| 86 | |
| 87 void PrintBytecodeOperand(std::ostream& stream, | |
|
rmcilroy
2016/02/12 15:29:05
Functions from here onwards should be private func
Stefano Sanfilippo
2016/02/12 18:29:40
Done.
| |
| 88 const BytecodeArrayIterator& bytecode_iter, | |
| 89 const Bytecode& bytecode, int op_index) { | |
| 90 OperandType op_type = Bytecodes::GetOperandType(bytecode, op_index); | |
| 91 OperandSize op_size = Bytecodes::GetOperandSize(bytecode, op_index); | |
| 92 | |
| 93 const char* size_tag; | |
| 94 switch (op_size) { | |
| 95 case OperandSize::kByte: | |
| 96 size_tag = "8"; | |
| 97 break; | |
| 98 case OperandSize::kShort: | |
| 99 size_tag = "16"; | |
| 100 break; | |
| 101 default: | |
| 102 UNREACHABLE(); | |
| 103 return; | |
| 104 } | |
| 105 | |
| 106 if (Bytecodes::IsRegisterOperandType(op_type)) { | |
| 107 Register register_value = bytecode_iter.GetRegisterOperand(op_index); | |
| 108 stream << 'R'; | |
| 109 if (op_size != OperandSize::kByte) stream << size_tag; | |
| 110 stream << '(' << register_value.index() << ')'; | |
| 111 } else { | |
| 112 stream << 'U' << size_tag << '('; | |
| 113 | |
| 114 if (Bytecodes::IsImmediateOperandType(op_type)) { | |
| 115 // We need a cast, otherwise the result is printed as char. | |
| 116 stream << static_cast<int>(bytecode_iter.GetImmediateOperand(op_index)); | |
| 117 } else if (Bytecodes::IsRegisterCountOperandType(op_type)) { | |
| 118 stream << bytecode_iter.GetRegisterCountOperand(op_index); | |
| 119 } else if (Bytecodes::IsIndexOperandType(op_type)) { | |
| 120 stream << bytecode_iter.GetIndexOperand(op_index); | |
| 121 } else { | |
| 122 UNREACHABLE(); | |
| 123 } | |
| 124 | |
| 125 stream << ')'; | |
| 126 } | |
| 127 } | |
| 128 | |
| 129 void PrintBytecode(std::ostream& stream, | |
| 130 const BytecodeArrayIterator& bytecode_iter) { | |
| 131 Bytecode bytecode = bytecode_iter.current_bytecode(); | |
| 132 | |
| 133 stream << "B(" << Bytecodes::ToString(bytecode) << ')'; | |
| 134 | |
| 135 int operands_count = Bytecodes::NumberOfOperands(bytecode); | |
| 136 for (int op_index = 0; op_index < operands_count; ++op_index) { | |
| 137 stream << ", "; | |
| 138 PrintBytecodeOperand(stream, bytecode_iter, bytecode, op_index); | |
| 139 } | |
| 140 } | |
| 141 | |
| 142 void PrintV8String(std::ostream& stream, i::String* string) { | |
| 143 stream << '"'; | |
| 144 for (int i = 0, length = string->length(); i < length; ++i) { | |
| 145 stream << i::AsEscapedUC16ForJSON(string->Get(i)); | |
| 146 } | |
| 147 stream << '"'; | |
| 148 } | |
| 149 | |
| 150 void PrintConstant(std::ostream& stream, | |
| 151 ConstantPoolType expected_constant_type, | |
| 152 i::Handle<i::Object> constant) { | |
| 153 switch (expected_constant_type) { | |
| 154 case kConstantPoolTypeString: | |
| 155 CHECK(constant->IsString()); | |
| 156 PrintV8String(stream, i::String::cast(*constant)); | |
| 157 break; | |
| 158 case kConstantPoolTypeInteger: | |
| 159 if (constant->IsSmi()) { | |
| 160 i::Smi::cast(*constant)->SmiPrint(stream); | |
| 161 } else if (constant->IsHeapNumber()) { | |
| 162 i::HeapNumber::cast(*constant)->HeapNumberPrint(stream); | |
| 163 } else { | |
| 164 UNREACHABLE(); | |
| 165 } | |
| 166 break; | |
| 167 case kConstantPoolTypeDouble: | |
| 168 i::HeapNumber::cast(*constant)->HeapNumberPrint(stream); | |
| 169 break; | |
| 170 case kConstantPoolTypeMixed: | |
| 171 if (constant->IsSmi()) { | |
| 172 stream << "kInstanceTypeDontCare"; | |
| 173 } else { | |
| 174 stream << "InstanceType::" | |
| 175 << i::HeapObject::cast(*constant)->map()->instance_type(); | |
| 176 } | |
| 177 break; | |
| 178 case kConstantPoolTypeUnknown: | |
| 179 default: | |
| 180 UNREACHABLE(); | |
| 181 return; | |
| 182 } | |
| 183 } | |
| 184 | |
| 185 void PrintFrameSize(std::ostream& stream, | |
| 186 i::Handle<i::BytecodeArray> bytecode_array) { | |
| 187 const int kPointerSize = sizeof(void*); | |
| 188 int frame_size = bytecode_array->frame_size(); | |
| 189 | |
| 190 DCHECK_EQ(frame_size % kPointerSize, 0); | |
| 191 stream << "frame size: " << frame_size / kPointerSize; | |
| 192 if (frame_size > 0) stream << " # in multiples of sizeof(void*)"; | |
| 193 stream << "\nparameter count: " << bytecode_array->parameter_count() << '\n'; | |
| 194 } | |
| 195 | |
| 196 void PrintBytecodeSequence(std::ostream& stream, | |
| 197 i::Handle<i::BytecodeArray> bytecode_array) { | |
| 198 stream << "bytecodes: [\n"; | |
| 199 BytecodeArrayIterator bytecode_iter{bytecode_array}; | |
| 200 for (; !bytecode_iter.done(); bytecode_iter.Advance()) { | |
| 201 stream << " "; | |
| 202 PrintBytecode(stream, bytecode_iter); | |
| 203 stream << ",\n"; | |
| 204 } | |
| 205 stream << "]\n"; | |
| 206 } | |
| 207 | |
| 208 void PrintConstantPool(std::ostream& stream, i::FixedArray* constant_pool, | |
| 209 ConstantPoolType const_pool_type, v8::Isolate* isolate) { | |
| 210 stream << "constant pool: [\n"; | |
| 211 int num_constants = constant_pool->length(); | |
| 212 if (num_constants > 0) { | |
| 213 for (int i = 0; i < num_constants; ++i) { | |
| 214 stream << " "; | |
| 215 PrintConstant( | |
| 216 stream, const_pool_type, | |
| 217 i::FixedArray::get(constant_pool, i, GetInternalIsolate(isolate))); | |
| 218 stream << ",\n"; | |
| 219 } | |
| 220 } | |
| 221 stream << "]\n"; | |
| 222 } | |
| 223 | |
| 224 void PrintCodeSnippet(std::ostream& stream, const std::string& body) { | |
| 225 stream << "snippet: \"\n"; | |
| 226 std::stringstream body_stream{body}; | |
| 227 std::string body_line; | |
| 228 while (std::getline(body_stream, body_line)) { | |
| 229 stream << " "; | |
| 230 PrintEscapedString(stream, body_line); | |
| 231 stream << '\n'; | |
| 232 } | |
| 233 stream << "\"\n"; | |
| 234 } | |
| 235 | |
| 236 void PrintBytecodeArray(std::ostream& stream, | |
| 237 i::Handle<i::BytecodeArray> bytecode_array, | |
| 238 const std::string& body, v8::Isolate* isolate, | |
| 239 ConstantPoolType constant_pool_type) { | |
| 240 stream << "---\n"; | |
| 241 PrintCodeSnippet(stream, body); | |
| 242 PrintFrameSize(stream, bytecode_array); | |
| 243 PrintBytecodeSequence(stream, bytecode_array); | |
| 244 PrintConstantPool(stream, bytecode_array->constant_pool(), constant_pool_type, | |
| 245 isolate); | |
| 246 | |
| 247 // TODO(ssanfilippo) print handlers. | |
| 248 i::HandlerTable* handlers = | |
| 249 i::HandlerTable::cast(bytecode_array->handler_table()); | |
| 250 CHECK_EQ(handlers->NumberOfRangeEntries(), 0); | |
| 251 } | |
| 252 | |
| 253 } // namespace | |
| 254 | |
| 255 namespace v8 { | |
| 256 namespace internal { | |
| 257 namespace interpreter { | |
| 258 | |
| 259 void ExpectationPrinter::PrintExpectation(std::ostream& stream, | |
| 260 const std::string& snippet) { | |
| 261 const char* wrapper_function_name = "__genbckexp_wrapper__"; | |
| 262 | |
| 263 std::string source_code = WrapCodeInFunction(wrapper_function_name, snippet); | |
| 264 CompileAndRun(isolate_, source_code.c_str()); | |
| 265 | |
| 266 i::Handle<i::BytecodeArray> bytecode_array = | |
| 267 GetBytecodeArrayForGlobal(isolate_, wrapper_function_name); | |
| 268 | |
| 269 PrintBytecodeArray(stream, bytecode_array, snippet, isolate_, | |
| 270 const_pool_type_); | |
| 271 stream << '\n'; | |
| 272 } | |
| 273 | |
| 274 } // namespace interpreter | |
| 275 } // namespace internal | |
| 276 } // namespace v8 | |
| OLD | NEW |