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/codegen.h"
11 : #include "src/compilation-info.h"
12 : #include "src/compiler.h"
13 : #include "src/counters.h"
14 : #include "src/interpreter/bytecode-generator.h"
15 : #include "src/interpreter/bytecodes.h"
16 : #include "src/log.h"
17 : #include "src/objects.h"
18 : #include "src/setup-isolate.h"
19 : #include "src/visitors.h"
20 :
21 : namespace v8 {
22 : namespace internal {
23 : namespace interpreter {
24 :
25 4154918 : class InterpreterCompilationJob final : public CompilationJob {
26 : public:
27 : explicit InterpreterCompilationJob(CompilationInfo* info);
28 :
29 : protected:
30 : Status PrepareJobImpl() final;
31 : Status ExecuteJobImpl() final;
32 : Status FinalizeJobImpl() final;
33 :
34 : private:
35 : class TimerScope final {
36 : public:
37 2077433 : TimerScope(RuntimeCallStats* stats, RuntimeCallStats::CounterId counter_id)
38 2077433 : : stats_(stats) {
39 2077433 : if (V8_UNLIKELY(FLAG_runtime_stats)) {
40 0 : RuntimeCallStats::Enter(stats_, &timer_, counter_id);
41 : }
42 2077433 : }
43 :
44 7 : explicit TimerScope(RuntimeCallCounter* counter) : stats_(nullptr) {
45 7 : if (V8_UNLIKELY(FLAG_runtime_stats)) {
46 0 : timer_.Start(counter, nullptr);
47 : }
48 7 : }
49 :
50 2077454 : ~TimerScope() {
51 2077454 : if (V8_UNLIKELY(FLAG_runtime_stats)) {
52 0 : if (stats_) {
53 0 : RuntimeCallStats::Leave(stats_, &timer_);
54 : } else {
55 0 : timer_.Stop();
56 : }
57 : }
58 2077454 : }
59 :
60 : private:
61 : RuntimeCallStats* stats_;
62 : RuntimeCallTimer timer_;
63 : };
64 :
65 : BytecodeGenerator* generator() { return &generator_; }
66 :
67 : BytecodeGenerator generator_;
68 : RuntimeCallStats* runtime_call_stats_;
69 : RuntimeCallCounter background_execute_counter_;
70 : bool print_bytecode_;
71 :
72 : DISALLOW_COPY_AND_ASSIGN(InterpreterCompilationJob);
73 : };
74 :
75 60782 : Interpreter::Interpreter(Isolate* isolate) : isolate_(isolate) {
76 60782 : memset(dispatch_table_, 0, sizeof(dispatch_table_));
77 :
78 60782 : if (FLAG_trace_ignition_dispatches) {
79 : static const int kBytecodeCount = static_cast<int>(Bytecode::kLast) + 1;
80 : bytecode_dispatch_counters_table_.reset(
81 6 : new uintptr_t[kBytecodeCount * kBytecodeCount]);
82 : memset(bytecode_dispatch_counters_table_.get(), 0,
83 : sizeof(uintptr_t) * kBytecodeCount * kBytecodeCount);
84 : }
85 60782 : }
86 :
87 76041 : Code* Interpreter::GetBytecodeHandler(Bytecode bytecode,
88 : OperandScale operand_scale) {
89 : DCHECK(IsDispatchTableInitialized());
90 : DCHECK(Bytecodes::BytecodeHasHandler(bytecode, operand_scale));
91 76041 : size_t index = GetDispatchTableIndex(bytecode, operand_scale);
92 76041 : Address code_entry = dispatch_table_[index];
93 76041 : return Code::GetCodeFromTargetAddress(code_entry);
94 : }
95 :
96 : // static
97 113666 : size_t Interpreter::GetDispatchTableIndex(Bytecode bytecode,
98 : OperandScale operand_scale) {
99 : static const size_t kEntriesPerOperandScale = 1u << kBitsPerByte;
100 113666 : size_t index = static_cast<size_t>(bytecode);
101 113666 : switch (operand_scale) {
102 : case OperandScale::kSingle:
103 : return index;
104 : case OperandScale::kDouble:
105 14960 : return index + kEntriesPerOperandScale;
106 : case OperandScale::kQuadruple:
107 14960 : return index + 2 * kEntriesPerOperandScale;
108 : }
109 0 : UNREACHABLE();
110 : return 0;
111 : }
112 :
113 172403 : void Interpreter::IterateDispatchTable(RootVisitor* v) {
114 132571807 : for (int i = 0; i < kDispatchTableSize; i++) {
115 132399411 : Address code_entry = dispatch_table_[i];
116 : Object* code = code_entry == nullptr
117 : ? nullptr
118 132399411 : : Code::GetCodeFromTargetAddress(code_entry);
119 : Object* old_code = code;
120 132399411 : v->VisitRootPointer(Root::kDispatchTable, &code);
121 132399404 : if (code != old_code) {
122 46646927 : dispatch_table_[i] = reinterpret_cast<Code*>(code)->entry();
123 : }
124 : }
125 172396 : }
126 :
127 : // static
128 2106964 : int Interpreter::InterruptBudget() {
129 2106964 : return FLAG_interrupt_budget * kCodeSizeMultiplier;
130 : }
131 :
132 : namespace {
133 :
134 2077458 : bool ShouldPrintBytecode(Handle<SharedFunctionInfo> shared) {
135 2077458 : if (!FLAG_print_bytecode) return false;
136 :
137 : // Checks whether function passed the filter.
138 0 : if (shared->is_toplevel()) {
139 0 : Vector<const char> filter = CStrVector(FLAG_print_bytecode_filter);
140 0 : return (filter.length() == 0) || (filter.length() == 1 && filter[0] == '*');
141 : } else {
142 0 : return shared->PassesFilter(FLAG_print_bytecode_filter);
143 : }
144 : }
145 :
146 : } // namespace
147 :
148 4154920 : InterpreterCompilationJob::InterpreterCompilationJob(CompilationInfo* info)
149 : : CompilationJob(info->isolate(), info, "Ignition"),
150 : generator_(info),
151 2077457 : runtime_call_stats_(info->isolate()->counters()->runtime_call_stats()),
152 : background_execute_counter_("CompileBackgroundIgnition"),
153 6232377 : print_bytecode_(ShouldPrintBytecode(info->shared_info())) {}
154 :
155 2077452 : InterpreterCompilationJob::Status InterpreterCompilationJob::PrepareJobImpl() {
156 2077452 : CodeGenerator::MakeCodePrologue(info(), "interpreter");
157 :
158 2077456 : if (print_bytecode_) {
159 0 : OFStream os(stdout);
160 0 : std::unique_ptr<char[]> name = info()->GetDebugName();
161 0 : os << "[generating bytecode for function: " << info()->GetDebugName().get()
162 0 : << "]" << std::endl
163 0 : << std::flush;
164 : }
165 :
166 2077456 : return SUCCEEDED;
167 : }
168 :
169 2077441 : InterpreterCompilationJob::Status InterpreterCompilationJob::ExecuteJobImpl() {
170 : TimerScope runtimeTimer =
171 4154891 : executed_on_background_thread()
172 : ? TimerScope(&background_execute_counter_)
173 2077441 : : TimerScope(runtime_call_stats_, &RuntimeCallStats::CompileIgnition);
174 : // TODO(lpy): add support for background compilation RCS trace.
175 6232355 : TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.CompileIgnition");
176 :
177 2077450 : generator()->GenerateBytecode(stack_limit());
178 :
179 2077455 : if (generator()->HasStackOverflow()) {
180 : return FAILED;
181 : }
182 4154878 : return SUCCEEDED;
183 : }
184 :
185 2077421 : InterpreterCompilationJob::Status InterpreterCompilationJob::FinalizeJobImpl() {
186 : // Add background runtime call stats.
187 6232264 : if (V8_UNLIKELY(FLAG_runtime_stats && executed_on_background_thread())) {
188 : runtime_call_stats_->CompileBackgroundIgnition.Add(
189 0 : &background_execute_counter_);
190 : }
191 :
192 : RuntimeCallTimerScope runtimeTimer(
193 2077421 : runtime_call_stats_, &RuntimeCallStats::CompileIgnitionFinalization);
194 :
195 2077419 : Handle<BytecodeArray> bytecodes = generator()->FinalizeBytecode(isolate());
196 2077425 : if (generator()->HasStackOverflow()) {
197 : return FAILED;
198 : }
199 :
200 2077425 : if (print_bytecode_) {
201 0 : OFStream os(stdout);
202 : bytecodes->Print(os);
203 0 : os << std::flush;
204 : }
205 :
206 : info()->SetBytecodeArray(bytecodes);
207 2077425 : info()->SetCode(info()->isolate()->builtins()->InterpreterEntryTrampoline());
208 2077418 : return SUCCEEDED;
209 : }
210 :
211 2077454 : CompilationJob* Interpreter::NewCompilationJob(CompilationInfo* info) {
212 2077454 : return new InterpreterCompilationJob(info);
213 : }
214 :
215 0 : bool Interpreter::IsDispatchTableInitialized() {
216 0 : return dispatch_table_[0] != nullptr;
217 : }
218 :
219 0 : const char* Interpreter::LookupNameOfBytecodeHandler(Code* code) {
220 : #ifdef ENABLE_DISASSEMBLER
221 : #define RETURN_NAME(Name, ...) \
222 : if (dispatch_table_[Bytecodes::ToByte(Bytecode::k##Name)] == \
223 : code->entry()) { \
224 : return #Name; \
225 : }
226 : BYTECODE_LIST(RETURN_NAME)
227 : #undef RETURN_NAME
228 : #endif // ENABLE_DISASSEMBLER
229 0 : return nullptr;
230 : }
231 :
232 0 : uintptr_t Interpreter::GetDispatchCounter(Bytecode from, Bytecode to) const {
233 762300 : int from_index = Bytecodes::ToByte(from);
234 762300 : int to_index = Bytecodes::ToByte(to);
235 762300 : return bytecode_dispatch_counters_table_[from_index * kNumberOfBytecodes +
236 1524600 : to_index];
237 : }
238 :
239 28 : Local<v8::Object> Interpreter::GetDispatchCountersObject() {
240 28 : v8::Isolate* isolate = reinterpret_cast<v8::Isolate*>(isolate_);
241 28 : Local<v8::Context> context = isolate->GetCurrentContext();
242 :
243 28 : Local<v8::Object> counters_map = v8::Object::New(isolate);
244 :
245 : // Output is a JSON-encoded object of objects.
246 : //
247 : // The keys on the top level object are source bytecodes,
248 : // and corresponding value are objects. Keys on these last are the
249 : // destinations of the dispatch and the value associated is a counter for
250 : // the correspondent source-destination dispatch chain.
251 : //
252 : // Only non-zero counters are written to file, but an entry in the top-level
253 : // object is always present, even if the value is empty because all counters
254 : // for that source are zero.
255 :
256 4648 : for (int from_index = 0; from_index < kNumberOfBytecodes; ++from_index) {
257 4620 : Bytecode from_bytecode = Bytecodes::FromByte(from_index);
258 4620 : Local<v8::Object> counters_row = v8::Object::New(isolate);
259 :
260 766920 : for (int to_index = 0; to_index < kNumberOfBytecodes; ++to_index) {
261 762300 : Bytecode to_bytecode = Bytecodes::FromByte(to_index);
262 : uintptr_t counter = GetDispatchCounter(from_bytecode, to_bytecode);
263 :
264 762300 : if (counter > 0) {
265 0 : std::string to_name = Bytecodes::ToString(to_bytecode);
266 : Local<v8::String> to_name_object =
267 : v8::String::NewFromUtf8(isolate, to_name.c_str(),
268 : NewStringType::kNormal)
269 0 : .ToLocalChecked();
270 0 : Local<v8::Number> counter_object = v8::Number::New(isolate, counter);
271 0 : CHECK(counters_row
272 : ->DefineOwnProperty(context, to_name_object, counter_object)
273 : .IsJust());
274 : }
275 : }
276 :
277 4620 : std::string from_name = Bytecodes::ToString(from_bytecode);
278 : Local<v8::String> from_name_object =
279 : v8::String::NewFromUtf8(isolate, from_name.c_str(),
280 : NewStringType::kNormal)
281 4620 : .ToLocalChecked();
282 :
283 4620 : CHECK(
284 : counters_map->DefineOwnProperty(context, from_name_object, counters_row)
285 : .IsJust());
286 : }
287 :
288 28 : return counters_map;
289 : }
290 :
291 : } // namespace interpreter
292 : } // namespace internal
293 : } // namespace v8
|