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 <iostream> | |
6 #include "include/libplatform/libplatform.h" | |
7 #include "src/base/logging.h" | |
8 #include "src/compiler.h" | |
9 #include "src/interpreter/bytecode-array-iterator.h" | |
10 #include "src/interpreter/bytecode-generator.h" | |
11 #include "src/interpreter/bytecodes.h" | |
12 #include "src/interpreter/interpreter.h" | |
13 #include "src/v8.h" | |
oth
2016/02/05 11:41:04
Is there something specific from src/v8.h? Samples
Stefano Sanfilippo
2016/02/08 13:18:34
No there's nothing specific ATM, I was just follow
| |
14 | |
15 using namespace i::interpreter; | |
16 | |
17 namespace { | |
18 | |
19 class ArrayBufferAllocator final : public v8::ArrayBuffer::Allocator { | |
20 public: | |
21 void *Allocate(size_t length) override { | |
oth
2016/02/05 11:41:05
The predominant style in v8 is
"void*" rather than
Stefano Sanfilippo
2016/02/08 13:18:34
Done.
rmcilroy
2016/02/08 13:55:31
Doesn't look like this has been done.
Stefano Sanfilippo
2016/02/09 10:09:58
It was, but cl format reverted to this style befor
rmcilroy
2016/02/09 11:58:24
Hmm that's weird (git cl format doesn't do that fo
Stefano Sanfilippo
2016/02/09 16:52:50
I finally did it on the workstation. Maybe it's a
rmcilroy
2016/02/10 09:18:00
Sounds like it - weird. thanks!
| |
22 void *data = AllocateUninitialized(length); | |
23 if (data != nullptr) memset(data, 0, length); | |
24 return data; | |
25 } | |
26 void *AllocateUninitialized(size_t length) override { return malloc(length); } | |
27 void Free(void *data, size_t) override { free(data); } | |
28 }; | |
29 | |
30 class PlatformWrapper final { | |
31 public: | |
32 PlatformWrapper(const char *program_name, const char *wrapper_function_name); | |
33 ~PlatformWrapper(); | |
34 | |
35 PlatformWrapper(PlatformWrapper &) = delete; | |
oth
2016/02/05 11:41:04
V8 code generally packages this up with (doesn't d
Stefano Sanfilippo
2016/02/08 13:18:34
Done.
| |
36 PlatformWrapper(PlatformWrapper &&) = delete; | |
37 | |
38 v8::Platform *platform() const { return platform_; } | |
39 v8::Isolate *isolate() const { return isolate_; } | |
40 i::Isolate *i_isolate() const { | |
41 return reinterpret_cast<i::Isolate *>(isolate_); | |
42 } | |
43 | |
44 private: | |
45 v8::Platform *platform_; | |
46 v8::Isolate *isolate_; | |
rmcilroy
2016/02/05 13:49:51
use base::SmartPointer<...> for both of these obje
Stefano Sanfilippo
2016/02/08 13:18:34
Done for platform_. base::SmartPointer doesn't see
| |
47 }; | |
48 | |
49 enum ConstantPoolType { | |
50 kConstantPoolTypeUnknown = 0, | |
51 kConstantPoolTypeString, | |
52 kConstantPoolTypeInteger, | |
53 kConstantPoolTypeFloat, | |
54 }; | |
rmcilroy
2016/02/05 13:49:51
Not used yet - remove for now.
Stefano Sanfilippo
2016/02/08 13:18:34
Done.
| |
55 | |
56 PlatformWrapper::PlatformWrapper(const char *program_name, | |
rmcilroy
2016/02/05 13:49:51
/s/program_name/exec_path
Stefano Sanfilippo
2016/02/08 13:18:34
Done.
| |
57 const char *wrapper_function_name) { | |
rmcilroy
2016/02/05 13:49:51
no need to pass this to the PlatformWrapper, just
Stefano Sanfilippo
2016/02/08 13:18:34
Ok, for the moment I replaced the filter with a "*
| |
58 v8::V8::InitializeICU(); | |
59 v8::V8::InitializeExternalStartupData(program_name); | |
60 platform_ = v8::platform::CreateDefaultPlatform(); | |
61 v8::V8::InitializePlatform(platform_); | |
62 v8::V8::Initialize(); | |
63 | |
64 ArrayBufferAllocator allocator; | |
65 v8::Isolate::CreateParams create_params; | |
66 create_params.array_buffer_allocator = &allocator; | |
67 | |
68 isolate_ = v8::Isolate::New(create_params); | |
69 i::FLAG_ignition = true; | |
70 i::FLAG_ignition_filter = i::StrDup(wrapper_function_name); | |
71 i::FLAG_always_opt = false; | |
72 i::FLAG_allow_natives_syntax = true; | |
73 i::FLAG_legacy_const = true; | |
rmcilroy
2016/02/05 13:49:51
just move these to the top of the function, then t
Stefano Sanfilippo
2016/02/08 13:18:34
Done.
| |
74 i_isolate()->interpreter()->Initialize(); | |
75 } | |
76 | |
77 PlatformWrapper::~PlatformWrapper() { | |
78 isolate_->Dispose(); | |
79 v8::V8::Dispose(); | |
80 v8::V8::ShutdownPlatform(); | |
81 delete platform_; | |
82 platform_ = nullptr; | |
83 } | |
84 | |
85 v8::Local<v8::String> MakeV8LocalStringFromUTF8(const PlatformWrapper &platform, | |
86 const char *data) { | |
87 return v8::String::NewFromUtf8(platform.isolate(), data, | |
88 v8::NewStringType::kNormal) | |
89 .ToLocalChecked(); | |
90 } | |
91 | |
92 static std::string WrapCodeInFunction(const char *function_name, | |
93 const std::string &body) { | |
94 std::ostringstream program_stream; | |
95 program_stream << "function " << function_name << "() {" << body << "}\n" | |
96 << function_name << "();"; | |
97 | |
98 return program_stream.str(); | |
99 } | |
100 | |
101 v8::Local<v8::Value> CompileAndRun(const PlatformWrapper &platform, | |
102 const v8::Local<v8::Context> &context, | |
103 const char *program) { | |
104 v8::Local<v8::String> source = MakeV8LocalStringFromUTF8(platform, program); | |
105 v8::Local<v8::Script> script = | |
106 v8::Script::Compile(context, source).ToLocalChecked(); | |
107 | |
108 v8::Local<v8::Value> result; | |
109 bool success = script->Run(context).ToLocal(&result); | |
110 CHECK(success); | |
111 | |
112 return result; | |
113 } | |
114 | |
115 i::Handle<v8::internal::BytecodeArray> GetBytecodeArrayForGlobal( | |
116 const PlatformWrapper &platform, const v8::Local<v8::Context> &context, | |
117 const char *global_name) { | |
118 v8::Local<v8::String> v8_global_name = | |
119 MakeV8LocalStringFromUTF8(platform, global_name); | |
120 v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast( | |
121 context->Global()->Get(context, v8_global_name).ToLocalChecked()); | |
122 i::Handle<i::JSFunction> js_function = | |
123 i::Handle<i::JSFunction>::cast(v8::Utils::OpenHandle(*function)); | |
124 | |
125 i::Handle<i::BytecodeArray> bytecodes = | |
126 i::handle(js_function->shared()->bytecode_array(), platform.i_isolate()); | |
127 | |
128 return bytecodes; | |
129 } | |
130 | |
131 void PrintBytecodeOperand(std::ostream &stream, | |
132 const BytecodeArrayIterator &bytecode_iter, | |
133 const Bytecode &bytecode, int op_index) { | |
134 OperandType op_type = Bytecodes::GetOperandType(bytecode, op_index); | |
135 | |
136 switch (op_type) { | |
137 case OperandType::kMaybeReg8: | |
138 case OperandType::kReg8: | |
139 case OperandType::kRegPair8: | |
140 case OperandType::kRegOut8: | |
141 case OperandType::kRegOutTriple8: | |
142 case OperandType::kRegOutPair8: { | |
143 Register op_value_register = bytecode_iter.GetRegisterOperand(op_index); | |
144 stream << "R(" << op_value_register.index() << ')'; | |
145 break; | |
146 } | |
147 case OperandType::kMaybeReg16: | |
148 case OperandType::kReg16: | |
149 case OperandType::kRegPair16: | |
150 case OperandType::kRegOut16: | |
151 case OperandType::kRegOutTriple16: | |
152 case OperandType::kRegOutPair16: { | |
153 Register op_value_register = bytecode_iter.GetRegisterOperand(op_index); | |
154 stream << "R16(" << op_value_register.index() << ')'; | |
155 break; | |
156 } | |
157 case OperandType::kImm8: { | |
158 int op_value_immediate = bytecode_iter.GetImmediateOperand(op_index); | |
159 stream << "U8(" << op_value_immediate << ')'; | |
160 break; | |
161 } | |
162 case OperandType::kIdx8: { | |
163 int op_value_index = bytecode_iter.GetIndexOperand(op_index); | |
164 stream << "U8(" << op_value_index << ')'; | |
165 break; | |
166 } | |
167 case OperandType::kRegCount8: { | |
168 int op_value_regcount = bytecode_iter.GetCountOperand(op_index); | |
169 stream << "U8(" << op_value_regcount << ')'; | |
170 break; | |
171 } | |
172 case OperandType::kIdx16: { | |
173 int op_value_index = bytecode_iter.GetIndexOperand(op_index); | |
174 stream << "U16(" << op_value_index << ')'; | |
175 break; | |
176 } | |
177 case OperandType::kRegCount16: { | |
178 int op_value_regcount = bytecode_iter.GetCountOperand(op_index); | |
179 stream << "U8(" << op_value_regcount << ')'; | |
rmcilroy
2016/02/05 13:49:51
This should be U16
Stefano Sanfilippo
2016/02/08 13:18:34
Silly copy and paste mistake is silly. Fixed.
| |
180 break; | |
181 } | |
rmcilroy
2016/02/05 13:49:51
Personally I would prefer that this is written usi
Stefano Sanfilippo
2016/02/08 13:18:34
Seems OK to me, as long as GetRawOperand() is guar
rmcilroy
2016/02/08 13:55:31
Yup, I think this should always be safe.
| |
182 default: | |
183 UNREACHABLE(); | |
184 return; | |
185 } | |
186 } | |
187 | |
188 void PrintBytecode(std::ostream &stream, | |
189 const BytecodeArrayIterator &bytecode_iter) { | |
190 Bytecode bytecode = bytecode_iter.current_bytecode(); | |
191 | |
192 stream << "B(" << Bytecodes::ToString(bytecode) << ')'; | |
rmcilroy
2016/02/05 13:49:51
You will need a comma after the B(..) or the final
| |
193 | |
194 int operands_count = Bytecodes::NumberOfOperands(bytecode); | |
195 for (int op_index = 0; op_index < operands_count; ++op_index) { | |
196 stream << ", "; | |
197 PrintBytecodeOperand(stream, bytecode_iter, bytecode, op_index); | |
198 } | |
199 } | |
200 | |
201 void PrintBytecodeArray(std::ostream &stream, | |
oth
2016/02/05 11:41:04
Something for you and Ross, but consider emitting
rmcilroy
2016/02/05 13:49:51
+1
Stefano Sanfilippo
2016/02/08 13:18:34
Done, I have added a boolean flag to print a banne
| |
202 i::Handle<i::BytecodeArray> bytecode_array) { | |
203 const int kPointerSize = sizeof(void *); | |
204 | |
205 int frame_size = bytecode_array->frame_size(); | |
206 if (frame_size > kPointerSize) { | |
207 stream << ' ' << frame_size / kPointerSize << " * kPointerSize,\n"; | |
rmcilroy
2016/02/05 13:49:51
Could you make these indented by the same amount a
Stefano Sanfilippo
2016/02/08 13:18:34
Done. For now the indent amount is hardcoded becau
| |
208 } else if (frame_size == kPointerSize) { | |
209 stream << " kPointerSize,\n"; | |
210 } else { | |
211 stream << " 0,\n"; | |
212 } | |
213 | |
214 stream << ' ' << bytecode_array->parameter_count() << ",\n" | |
215 << ' ' << bytecode_array->length() << ",\n {\n "; | |
216 | |
217 BytecodeArrayIterator bytecode_iter{bytecode_array}; | |
218 | |
219 bool emitting_first_instruction = true; | |
220 for (; !bytecode_iter.done(); bytecode_iter.Advance()) { | |
221 // Print separator before each instruction, except the first one | |
222 if (!emitting_first_instruction) { | |
oth
2016/02/05 11:41:04
The code can be simplified here using BytecodeIter
rmcilroy
2016/02/05 13:49:51
Also, again trailing commas are OK I think, so you
Stefano Sanfilippo
2016/02/08 13:18:34
I ended up following oth suggestion, which simplif
rmcilroy
2016/02/08 13:55:31
SGTM, thanks.
| |
223 stream << ",\n "; | |
224 } else { | |
225 emitting_first_instruction = false; | |
226 } | |
227 | |
228 PrintBytecode(stream, bytecode_iter); | |
229 } | |
230 | |
231 stream << "\n },\n"; | |
232 } | |
233 | |
234 } // namespace | |
235 | |
236 int main(int argc, char **argv) { | |
237 if (argc < 2) { | |
238 std::cerr << "Usage: " << argv[0] << " \"return null;\"\n"; | |
oth
2016/02/05 11:41:05
This usage message is cryptic.
Going forward, it
rmcilroy
2016/02/05 13:49:51
+1, I would have it read from stdin in this CL sin
Stefano Sanfilippo
2016/02/08 13:18:34
Done. 0 arguments or "-" means stdin, anything els
| |
239 return 1; | |
240 } | |
241 | |
242 const char *body = argv[1]; | |
243 const char *wrapper_function_name = "__bytecodechecker_wrapper__"; | |
244 | |
245 PlatformWrapper platform(argv[0], wrapper_function_name); | |
rmcilroy
2016/02/05 13:49:51
I'd rename PlatformWrapper as V8InitializationScop
Stefano Sanfilippo
2016/02/08 13:18:34
Done.
| |
246 { | |
247 v8::Isolate::Scope isolate_scope(platform.isolate()); | |
248 v8::HandleScope handle_scope(platform.isolate()); | |
249 v8::Local<v8::Context> context = v8::Context::New(platform.isolate()); | |
250 v8::Context::Scope context_scope(context); | |
251 | |
252 std::string source_code = WrapCodeInFunction(wrapper_function_name, body); | |
253 CompileAndRun(platform, context, source_code.c_str()); | |
254 | |
255 i::Handle<i::BytecodeArray> bytecode_array = | |
256 GetBytecodeArrayForGlobal(platform, context, wrapper_function_name); | |
257 | |
258 std::cout << "{" << '"' << body << "\",\n"; | |
rmcilroy
2016/02/05 13:49:51
nit - move this into PrintBytecodeArray (and the c
Stefano Sanfilippo
2016/02/08 13:18:34
Done.
| |
259 | |
260 PrintBytecodeArray(std::cout, bytecode_array); | |
261 | |
262 std::cout << "}\n"; | |
263 } | |
264 } | |
OLD | NEW |