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 <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 |