5 #include "src/interpreter/interpreter.h" 10 #include "builtins-generated/bytecodes-builtins-list.h" 11 #include "src/ast/prettyprinter.h" 12 #include "src/bootstrapper.h" 13 #include "src/compiler.h" 14 #include "src/counters-inl.h" 15 #include "src/interpreter/bytecode-generator.h" 16 #include "src/interpreter/bytecodes.h" 18 #include "src/objects-inl.h" 19 #include "src/objects/shared-function-info.h" 20 #include "src/objects/slots.h" 21 #include "src/parsing/parse-info.h" 22 #include "src/setup-isolate.h" 23 #include "src/snapshot/snapshot.h" 24 #include "src/unoptimized-compilation-info.h" 25 #include "src/visitors.h" 29 namespace interpreter {
36 std::vector<FunctionLiteral*>* eager_inner_literals);
39 Status ExecuteJobImpl()
final;
53 Interpreter::Interpreter(
Isolate* isolate)
55 interpreter_entry_trampoline_instruction_start_(kNullAddress) {
56 memset(dispatch_table_, 0,
sizeof(dispatch_table_));
58 if (FLAG_trace_ignition_dispatches) {
59 static const int kBytecodeCount =
static_cast<int>(Bytecode::kLast) + 1;
60 bytecode_dispatch_counters_table_.reset(
61 new uintptr_t[kBytecodeCount * kBytecodeCount]);
62 memset(bytecode_dispatch_counters_table_.get(), 0,
63 sizeof(
uintptr_t) * kBytecodeCount * kBytecodeCount);
69 int BuiltinIndexFromBytecode(Bytecode bytecode, OperandScale operand_scale) {
70 int index = BytecodeOperands::OperandScaleAsIndex(operand_scale) *
71 kNumberOfBytecodeHandlers +
72 static_cast<int>(bytecode);
73 int offset = kBytecodeToBuiltinsMapping[index];
74 return offset >= 0 ? Builtins::kFirstBytecodeHandler + offset
75 : Builtins::kIllegalHandler;
80 Code Interpreter::GetBytecodeHandler(Bytecode bytecode,
81 OperandScale operand_scale) {
82 int builtin_index = BuiltinIndexFromBytecode(bytecode, operand_scale);
83 Builtins* builtins = isolate_->builtins();
84 return builtins->builtin(builtin_index);
87 void Interpreter::SetBytecodeHandler(Bytecode bytecode,
88 OperandScale operand_scale, Code handler) {
89 DCHECK(handler->kind() == Code::BYTECODE_HANDLER);
90 size_t index = GetDispatchTableIndex(bytecode, operand_scale);
91 dispatch_table_[index] = handler->InstructionStart();
95 size_t Interpreter::GetDispatchTableIndex(Bytecode bytecode,
96 OperandScale operand_scale) {
97 static const size_t kEntriesPerOperandScale = 1u << kBitsPerByte;
98 size_t index =
static_cast<size_t>(bytecode);
99 return index + BytecodeOperands::OperandScaleAsIndex(operand_scale) *
100 kEntriesPerOperandScale;
103 void Interpreter::IterateDispatchTable(RootVisitor* v) {
104 if (FLAG_embedded_builtins && !isolate_->serializer_enabled() &&
105 isolate_->embedded_blob() !=
nullptr) {
110 for (
int i = 0;
i < kDispatchTableSize;
i++) {
111 Address code_entry = dispatch_table_[
i];
112 CHECK(code_entry == kNullAddress ||
113 InstructionStream::PcIsOffHeap(isolate_, code_entry));
115 #endif // ENABLE_SLOW_DCHECKS 119 for (
int i = 0;
i < kDispatchTableSize;
i++) {
120 Address code_entry = dispatch_table_[
i];
122 if (InstructionStream::PcIsOffHeap(isolate_, code_entry))
continue;
127 if (code_entry != kNullAddress) {
128 code = Code::GetCodeFromTargetAddress(code_entry);
130 Code old_code = code;
131 v->VisitRootPointer(Root::kDispatchTable,
nullptr, ObjectSlot(&code));
132 if (code != old_code) {
133 dispatch_table_[
i] = code->entry();
138 int Interpreter::InterruptBudget() {
139 return FLAG_interrupt_budget;
144 void MaybePrintAst(ParseInfo* parse_info,
145 UnoptimizedCompilationInfo* compilation_info) {
146 if (!FLAG_print_ast)
return;
149 std::unique_ptr<char[]> name = compilation_info->literal()->GetDebugName();
150 os <<
"[generating bytecode for function: " << name.get() <<
"]" << std::endl;
152 os <<
"--- AST ---" << std::endl
153 << AstPrinter(parse_info->stack_limit())
154 .PrintProgram(compilation_info->literal())
159 bool ShouldPrintBytecode(Handle<SharedFunctionInfo> shared) {
160 if (!FLAG_print_bytecode)
return false;
163 if (shared->is_toplevel()) {
164 Vector<const char> filter = CStrVector(FLAG_print_bytecode_filter);
165 return (filter.length() == 0) || (filter.length() == 1 && filter[0] ==
'*');
167 return shared->PassesFilter(FLAG_print_bytecode_filter);
173 InterpreterCompilationJob::InterpreterCompilationJob(
174 ParseInfo* parse_info, FunctionLiteral* literal,
175 AccountingAllocator* allocator,
176 std::vector<FunctionLiteral*>* eager_inner_literals)
177 : UnoptimizedCompilationJob(parse_info->stack_limit(), parse_info,
179 zone_(allocator, ZONE_NAME),
180 compilation_info_(&zone_, parse_info, literal),
181 generator_(&compilation_info_, parse_info->ast_string_constants(),
182 eager_inner_literals) {}
184 InterpreterCompilationJob::Status InterpreterCompilationJob::ExecuteJobImpl() {
185 RuntimeCallTimerScope runtimeTimerScope(
186 parse_info()->runtime_call_stats(),
187 parse_info()->on_background_thread()
188 ? RuntimeCallCounterId::kCompileBackgroundIgnition
189 : RuntimeCallCounterId::kCompileIgnition);
191 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT(
"v8.compile"),
"V8.CompileIgnition");
195 MaybePrintAst(parse_info(), compilation_info());
197 generator()->GenerateBytecode(stack_limit());
199 if (generator()->HasStackOverflow()) {
205 InterpreterCompilationJob::Status InterpreterCompilationJob::FinalizeJobImpl(
206 Handle<SharedFunctionInfo> shared_info, Isolate* isolate) {
207 RuntimeCallTimerScope runtimeTimerScope(
208 parse_info()->runtime_call_stats(),
209 RuntimeCallCounterId::kCompileIgnitionFinalization);
210 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT(
"v8.compile"),
211 "V8.CompileIgnitionFinalization");
213 Handle<BytecodeArray> bytecodes =
214 generator()->FinalizeBytecode(isolate, parse_info()->script());
215 if (generator()->HasStackOverflow()) {
219 if (ShouldPrintBytecode(shared_info)) {
221 std::unique_ptr<char[]> name =
222 compilation_info()->literal()->GetDebugName();
223 os <<
"[generated bytecode for function: " << name.get() <<
"]" 225 bytecodes->Disassemble(os);
229 compilation_info()->SetBytecodeArray(bytecodes);
233 UnoptimizedCompilationJob* Interpreter::NewCompilationJob(
234 ParseInfo* parse_info, FunctionLiteral* literal,
235 AccountingAllocator* allocator,
236 std::vector<FunctionLiteral*>* eager_inner_literals) {
237 return new InterpreterCompilationJob(parse_info, literal, allocator,
238 eager_inner_literals);
241 void Interpreter::ForEachBytecode(
242 const std::function<
void(Bytecode, OperandScale)>& f) {
243 constexpr OperandScale kOperandScales[] = {
244 #define VALUE(Name, _) OperandScale::k##Name, 245 OPERAND_SCALE_LIST(VALUE)
249 for (OperandScale operand_scale : kOperandScales) {
250 for (
int i = 0;
i < Bytecodes::kBytecodeCount;
i++) {
251 f(Bytecodes::FromByte(
i), operand_scale);
256 void Interpreter::Initialize() {
257 Builtins* builtins = isolate_->builtins();
261 Handle<Code> code = BUILTIN_CODE(isolate_, InterpreterEntryTrampoline);
262 DCHECK(builtins->is_initialized());
263 DCHECK(code->is_off_heap_trampoline() ||
264 isolate_->heap()->IsImmovable(*code));
265 interpreter_entry_trampoline_instruction_start_ = code->InstructionStart();
268 Code illegal = builtins->builtin(Builtins::kIllegalHandler);
269 int builtin_id = Builtins::kFirstBytecodeHandler;
270 ForEachBytecode([=, &builtin_id](Bytecode bytecode,
271 OperandScale operand_scale) {
272 Code handler = illegal;
273 if (Bytecodes::BytecodeHasHandler(bytecode, operand_scale)) {
275 std::string builtin_name(Builtins::name(builtin_id));
276 std::string expected_name =
277 Bytecodes::ToString(bytecode, operand_scale,
"") +
"Handler";
278 DCHECK_EQ(expected_name, builtin_name);
280 handler = builtins->builtin(builtin_id++);
282 SetBytecodeHandler(bytecode, operand_scale, handler);
284 DCHECK(builtin_id == Builtins::builtin_count);
285 DCHECK(IsDispatchTableInitialized());
288 bool Interpreter::IsDispatchTableInitialized()
const {
289 return dispatch_table_[0] != kNullAddress;
292 const char* Interpreter::LookupNameOfBytecodeHandler(
const Code code) {
293 #ifdef ENABLE_DISASSEMBLER 294 #define RETURN_NAME(Name, ...) \ 295 if (dispatch_table_[Bytecodes::ToByte(Bytecode::k##Name)] == \ 299 BYTECODE_LIST(RETURN_NAME)
301 #endif // ENABLE_DISASSEMBLER 305 uintptr_t Interpreter::GetDispatchCounter(Bytecode from, Bytecode to)
const {
306 int from_index = Bytecodes::ToByte(from);
307 int to_index = Bytecodes::ToByte(to);
308 return bytecode_dispatch_counters_table_[from_index * kNumberOfBytecodes +
312 Local<v8::Object> Interpreter::GetDispatchCountersObject() {
313 v8::Isolate* isolate =
reinterpret_cast<v8::Isolate*
>(isolate_);
314 Local<v8::Context> context = isolate->GetCurrentContext();
316 Local<v8::Object> counters_map = v8::Object::New(isolate);
329 for (
int from_index = 0; from_index < kNumberOfBytecodes; ++from_index) {
330 Bytecode from_bytecode = Bytecodes::FromByte(from_index);
331 Local<v8::Object> counters_row = v8::Object::New(isolate);
333 for (
int to_index = 0; to_index < kNumberOfBytecodes; ++to_index) {
334 Bytecode to_bytecode = Bytecodes::FromByte(to_index);
335 uintptr_t counter = GetDispatchCounter(from_bytecode, to_bytecode);
338 std::string to_name = Bytecodes::ToString(to_bytecode);
339 Local<v8::String> to_name_object =
343 Local<v8::Number> counter_object = v8::Number::New(isolate, counter);
345 ->DefineOwnProperty(context, to_name_object, counter_object)
350 std::string from_name = Bytecodes::ToString(from_bytecode);
351 Local<v8::String> from_name_object =
357 counters_map->DefineOwnProperty(context, from_name_object, counters_row)
static V8_WARN_UNUSED_RESULT MaybeLocal< String > NewFromUtf8(Isolate *isolate, const char *data, v8::NewStringType type, int length=-1)