Line data Source code
1 : // Copyright 2015 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 "src/interpreter/interpreter.h"
6 :
7 : #include <fstream>
8 : #include <memory>
9 :
10 : #include "src/ast/prettyprinter.h"
11 : #include "src/bootstrapper.h"
12 : #include "src/compilation-info.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"
17 : #include "src/log.h"
18 : #include "src/objects-inl.h"
19 : #include "src/objects/shared-function-info.h"
20 : #include "src/parsing/parse-info.h"
21 : #include "src/setup-isolate.h"
22 : #include "src/visitors.h"
23 :
24 : namespace v8 {
25 : namespace internal {
26 : namespace interpreter {
27 :
28 4262658 : class InterpreterCompilationJob final : public CompilationJob {
29 : public:
30 : InterpreterCompilationJob(ParseInfo* parse_info, FunctionLiteral* literal,
31 : Isolate* isolate);
32 :
33 : protected:
34 : Status PrepareJobImpl() final;
35 : Status ExecuteJobImpl() final;
36 : Status FinalizeJobImpl() final;
37 :
38 : private:
39 : class TimerScope final {
40 : public:
41 2131322 : explicit TimerScope(RuntimeCallCounter* counter)
42 2131322 : : runtime_stats_enabled_(FLAG_runtime_stats) {
43 2131322 : if (V8_UNLIKELY(runtime_stats_enabled_ && counter != nullptr)) {
44 0 : timer_.Start(counter, nullptr);
45 : }
46 2131322 : }
47 :
48 : ~TimerScope() {
49 2131326 : if (V8_UNLIKELY(runtime_stats_enabled_)) {
50 0 : timer_.Stop();
51 : }
52 : }
53 :
54 : private:
55 : RuntimeCallTimer timer_;
56 : bool runtime_stats_enabled_;
57 :
58 : DISALLOW_COPY_AND_ASSIGN(TimerScope);
59 : };
60 :
61 : BytecodeGenerator* generator() { return &generator_; }
62 :
63 : Zone zone_;
64 : CompilationInfo compilation_info_;
65 : BytecodeGenerator generator_;
66 : RuntimeCallStats* runtime_call_stats_;
67 : RuntimeCallCounter background_execute_counter_;
68 :
69 : DISALLOW_COPY_AND_ASSIGN(InterpreterCompilationJob);
70 : };
71 :
72 54999 : Interpreter::Interpreter(Isolate* isolate) : isolate_(isolate) {
73 54999 : memset(dispatch_table_, 0, sizeof(dispatch_table_));
74 :
75 54999 : if (FLAG_trace_ignition_dispatches) {
76 : static const int kBytecodeCount = static_cast<int>(Bytecode::kLast) + 1;
77 : bytecode_dispatch_counters_table_.reset(
78 5 : new uintptr_t[kBytecodeCount * kBytecodeCount]);
79 : memset(bytecode_dispatch_counters_table_.get(), 0,
80 : sizeof(uintptr_t) * kBytecodeCount * kBytecodeCount);
81 : }
82 54999 : }
83 :
84 67866 : Code* Interpreter::GetBytecodeHandler(Bytecode bytecode,
85 : OperandScale operand_scale) {
86 : DCHECK(IsDispatchTableInitialized());
87 : DCHECK(Bytecodes::BytecodeHasHandler(bytecode, operand_scale));
88 67866 : size_t index = GetDispatchTableIndex(bytecode, operand_scale);
89 67866 : Address code_entry = dispatch_table_[index];
90 67866 : return Code::GetCodeFromTargetAddress(code_entry);
91 : }
92 :
93 : // static
94 96045 : size_t Interpreter::GetDispatchTableIndex(Bytecode bytecode,
95 : OperandScale operand_scale) {
96 : static const size_t kEntriesPerOperandScale = 1u << kBitsPerByte;
97 96045 : size_t index = static_cast<size_t>(bytecode);
98 96045 : switch (operand_scale) {
99 : case OperandScale::kSingle:
100 : return index;
101 : case OperandScale::kDouble:
102 11703 : return index + kEntriesPerOperandScale;
103 : case OperandScale::kQuadruple:
104 11703 : return index + 2 * kEntriesPerOperandScale;
105 : }
106 0 : UNREACHABLE();
107 : }
108 :
109 202795 : void Interpreter::IterateDispatchTable(RootVisitor* v) {
110 155929830 : for (int i = 0; i < kDispatchTableSize; i++) {
111 155727059 : Address code_entry = dispatch_table_[i];
112 : Object* code = code_entry == nullptr
113 : ? nullptr
114 155727059 : : Code::GetCodeFromTargetAddress(code_entry);
115 : Object* old_code = code;
116 155727059 : v->VisitRootPointer(Root::kDispatchTable, &code);
117 155727035 : if (code != old_code) {
118 42214986 : dispatch_table_[i] = reinterpret_cast<Code*>(code)->entry();
119 : }
120 : }
121 202771 : }
122 :
123 : namespace {
124 :
125 : void MaybePrintAst(ParseInfo* parse_info, CompilationInfo* compilation_info) {
126 : Isolate* isolate = compilation_info->isolate();
127 : bool print_ast = isolate->bootstrapper()->IsActive() ? FLAG_print_builtin_ast
128 : : FLAG_print_ast;
129 : if (!print_ast) return;
130 :
131 : // Requires internalizing the AST, so make sure we are on the main thread and
132 : // allow handle dereference and allocations.
133 : // TODO(rmcilroy): Make ast-printer print ast raw strings instead of
134 : // internalized strings to avoid internalizing here.
135 : DCHECK(ThreadId::Current().Equals(isolate->thread_id()));
136 : AllowHandleDereference allow_deref;
137 : AllowHandleAllocation allow_handles;
138 : AllowHeapAllocation allow_gc;
139 : parse_info->ast_value_factory()->Internalize(isolate);
140 :
141 : OFStream os(stdout);
142 : std::unique_ptr<char[]> name = compilation_info->GetDebugName();
143 : os << "[generating bytecode for function: "
144 : << compilation_info->GetDebugName().get() << "]" << std::endl;
145 : #ifdef DEBUG
146 : os << "--- AST ---" << std::endl
147 : << AstPrinter(isolate).PrintProgram(compilation_info->literal())
148 : << std::endl;
149 : #endif // DEBUG
150 : }
151 :
152 2131308 : bool ShouldPrintBytecode(Handle<SharedFunctionInfo> shared) {
153 2131308 : if (!FLAG_print_bytecode) return false;
154 :
155 : // Checks whether function passed the filter.
156 0 : if (shared->is_toplevel()) {
157 0 : Vector<const char> filter = CStrVector(FLAG_print_bytecode_filter);
158 0 : return (filter.length() == 0) || (filter.length() == 1 && filter[0] == '*');
159 : } else {
160 0 : return shared->PassesFilter(FLAG_print_bytecode_filter);
161 : }
162 : }
163 :
164 : } // namespace
165 :
166 2131327 : InterpreterCompilationJob::InterpreterCompilationJob(ParseInfo* parse_info,
167 : FunctionLiteral* literal,
168 2131326 : Isolate* isolate)
169 : : CompilationJob(isolate, parse_info, &compilation_info_, "Ignition"),
170 : zone_(isolate->allocator(), ZONE_NAME),
171 : compilation_info_(&zone_, isolate, parse_info, literal),
172 : generator_(&compilation_info_),
173 2131328 : runtime_call_stats_(isolate->counters()->runtime_call_stats()),
174 8525309 : background_execute_counter_("CompileBackgroundIgnition") {}
175 :
176 2131325 : InterpreterCompilationJob::Status InterpreterCompilationJob::PrepareJobImpl() {
177 : MaybePrintAst(parse_info(), compilation_info());
178 2131325 : return SUCCEEDED;
179 : }
180 :
181 2131326 : InterpreterCompilationJob::Status InterpreterCompilationJob::ExecuteJobImpl() {
182 : TimerScope runtimeTimer(
183 4262648 : executed_on_background_thread() ? &background_execute_counter_ : nullptr);
184 : RuntimeCallTimerScope runtimeTimerScope(
185 : !executed_on_background_thread() ? runtime_call_stats_ : nullptr,
186 2131325 : &RuntimeCallStats::CompileIgnition);
187 :
188 : // TODO(lpy): add support for background compilation RCS trace.
189 6393969 : TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.CompileIgnition");
190 :
191 2131322 : generator()->GenerateBytecode(stack_limit());
192 :
193 2131325 : if (generator()->HasStackOverflow()) {
194 : return FAILED;
195 : }
196 2131312 : return SUCCEEDED;
197 : }
198 :
199 2131306 : InterpreterCompilationJob::Status InterpreterCompilationJob::FinalizeJobImpl() {
200 : // Add background runtime call stats.
201 14919150 : if (V8_UNLIKELY(FLAG_runtime_stats && executed_on_background_thread())) {
202 : runtime_call_stats_->CompileBackgroundIgnition.Add(
203 0 : &background_execute_counter_);
204 : }
205 :
206 : RuntimeCallTimerScope runtimeTimerScope(
207 : !executed_on_background_thread() ? runtime_call_stats_ : nullptr,
208 2131307 : &RuntimeCallStats::CompileIgnitionFinalization);
209 :
210 : Handle<BytecodeArray> bytecodes =
211 2131307 : generator()->FinalizeBytecode(isolate(), parse_info()->script());
212 2131308 : if (generator()->HasStackOverflow()) {
213 : return FAILED;
214 : }
215 :
216 2131308 : if (ShouldPrintBytecode(compilation_info()->shared_info())) {
217 0 : OFStream os(stdout);
218 0 : std::unique_ptr<char[]> name = compilation_info()->GetDebugName();
219 0 : os << "[generated bytecode for function: "
220 0 : << compilation_info()->GetDebugName().get() << "]" << std::endl;
221 0 : bytecodes->Disassemble(os);
222 0 : os << std::flush;
223 : }
224 :
225 : compilation_info()->SetBytecodeArray(bytecodes);
226 : compilation_info()->SetCode(
227 2131308 : BUILTIN_CODE(compilation_info()->isolate(), InterpreterEntryTrampoline));
228 2131306 : return SUCCEEDED;
229 : }
230 :
231 2131326 : CompilationJob* Interpreter::NewCompilationJob(ParseInfo* parse_info,
232 : FunctionLiteral* literal,
233 : Isolate* isolate) {
234 2131326 : return new InterpreterCompilationJob(parse_info, literal, isolate);
235 : }
236 :
237 0 : bool Interpreter::IsDispatchTableInitialized() {
238 0 : return dispatch_table_[0] != nullptr;
239 : }
240 :
241 0 : const char* Interpreter::LookupNameOfBytecodeHandler(Code* code) {
242 : #ifdef ENABLE_DISASSEMBLER
243 : #define RETURN_NAME(Name, ...) \
244 : if (dispatch_table_[Bytecodes::ToByte(Bytecode::k##Name)] == \
245 : code->entry()) { \
246 : return #Name; \
247 : }
248 : BYTECODE_LIST(RETURN_NAME)
249 : #undef RETURN_NAME
250 : #endif // ENABLE_DISASSEMBLER
251 0 : return nullptr;
252 : }
253 :
254 0 : uintptr_t Interpreter::GetDispatchCounter(Bytecode from, Bytecode to) const {
255 532512 : int from_index = Bytecodes::ToByte(from);
256 532512 : int to_index = Bytecodes::ToByte(to);
257 532512 : return bytecode_dispatch_counters_table_[from_index * kNumberOfBytecodes +
258 1065024 : to_index];
259 : }
260 :
261 18 : Local<v8::Object> Interpreter::GetDispatchCountersObject() {
262 18 : v8::Isolate* isolate = reinterpret_cast<v8::Isolate*>(isolate_);
263 18 : Local<v8::Context> context = isolate->GetCurrentContext();
264 :
265 18 : Local<v8::Object> counters_map = v8::Object::New(isolate);
266 :
267 : // Output is a JSON-encoded object of objects.
268 : //
269 : // The keys on the top level object are source bytecodes,
270 : // and corresponding value are objects. Keys on these last are the
271 : // destinations of the dispatch and the value associated is a counter for
272 : // the correspondent source-destination dispatch chain.
273 : //
274 : // Only non-zero counters are written to file, but an entry in the top-level
275 : // object is always present, even if the value is empty because all counters
276 : // for that source are zero.
277 :
278 3114 : for (int from_index = 0; from_index < kNumberOfBytecodes; ++from_index) {
279 3096 : Bytecode from_bytecode = Bytecodes::FromByte(from_index);
280 3096 : Local<v8::Object> counters_row = v8::Object::New(isolate);
281 :
282 535608 : for (int to_index = 0; to_index < kNumberOfBytecodes; ++to_index) {
283 532512 : Bytecode to_bytecode = Bytecodes::FromByte(to_index);
284 : uintptr_t counter = GetDispatchCounter(from_bytecode, to_bytecode);
285 :
286 532512 : if (counter > 0) {
287 0 : std::string to_name = Bytecodes::ToString(to_bytecode);
288 : Local<v8::String> to_name_object =
289 : v8::String::NewFromUtf8(isolate, to_name.c_str(),
290 : NewStringType::kNormal)
291 0 : .ToLocalChecked();
292 0 : Local<v8::Number> counter_object = v8::Number::New(isolate, counter);
293 0 : CHECK(counters_row
294 : ->DefineOwnProperty(context, to_name_object, counter_object)
295 : .IsJust());
296 : }
297 : }
298 :
299 3096 : std::string from_name = Bytecodes::ToString(from_bytecode);
300 : Local<v8::String> from_name_object =
301 : v8::String::NewFromUtf8(isolate, from_name.c_str(),
302 : NewStringType::kNormal)
303 3096 : .ToLocalChecked();
304 :
305 3096 : CHECK(
306 : counters_map->DefineOwnProperty(context, from_name_object, counters_row)
307 : .IsJust());
308 : }
309 :
310 18 : return counters_map;
311 : }
312 :
313 : } // namespace interpreter
314 : } // namespace internal
315 : } // namespace v8
|