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 |