Line data Source code
1 : // Copyright 2019 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 <iomanip>
6 :
7 : #include "src/objects/code.h"
8 :
9 : #include "src/assembler-inl.h"
10 : #include "src/cpu-features.h"
11 : #include "src/deoptimizer.h"
12 : #include "src/interpreter/bytecode-array-iterator.h"
13 : #include "src/interpreter/bytecode-decoder.h"
14 : #include "src/interpreter/interpreter.h"
15 : #include "src/objects/allocation-site-inl.h"
16 : #include "src/ostreams.h"
17 : #include "src/reloc-info.h"
18 : #include "src/roots-inl.h"
19 : #include "src/safepoint-table.h"
20 : #include "src/snapshot/embedded-data.h"
21 :
22 : #ifdef ENABLE_DISASSEMBLER
23 : #include "src/code-comments.h"
24 : #include "src/disasm.h"
25 : #include "src/disassembler.h"
26 : #include "src/eh-frame.h"
27 : #endif
28 :
29 : namespace v8 {
30 : namespace internal {
31 :
32 0 : int Code::safepoint_table_size() const {
33 : DCHECK_GE(handler_table_offset() - safepoint_table_offset(), 0);
34 3324 : return handler_table_offset() - safepoint_table_offset();
35 : }
36 :
37 6648 : bool Code::has_safepoint_table() const { return safepoint_table_size() > 0; }
38 :
39 0 : int Code::handler_table_size() const {
40 : DCHECK_GE(constant_pool_offset() - handler_table_offset(), 0);
41 4047883 : return constant_pool_offset() - handler_table_offset();
42 : }
43 :
44 8095766 : bool Code::has_handler_table() const { return handler_table_size() > 0; }
45 :
46 0 : int Code::constant_pool_size() const {
47 : const int size = code_comments_offset() - constant_pool_offset();
48 : DCHECK_IMPLIES(!FLAG_enable_embedded_constant_pool, size == 0);
49 : DCHECK_GE(size, 0);
50 0 : return size;
51 : }
52 :
53 214842579 : bool Code::has_constant_pool() const { return constant_pool_size() > 0; }
54 :
55 0 : int Code::code_comments_size() const {
56 : DCHECK_GE(InstructionSize() - code_comments_offset(), 0);
57 16 : return InstructionSize() - code_comments_offset();
58 : }
59 :
60 16 : bool Code::has_code_comments() const { return code_comments_size() > 0; }
61 :
62 0 : int Code::ExecutableInstructionSize() const { return safepoint_table_offset(); }
63 :
64 266 : void Code::ClearEmbeddedObjects(Heap* heap) {
65 : HeapObject undefined = ReadOnlyRoots(heap).undefined_value();
66 : int mode_mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
67 4097 : for (RelocIterator it(*this, mode_mask); !it.done(); it.next()) {
68 3831 : RelocInfo::Mode mode = it.rinfo()->rmode();
69 3831 : if (mode == RelocInfo::EMBEDDED_OBJECT) {
70 : it.rinfo()->set_target_object(heap, undefined, SKIP_WRITE_BARRIER);
71 : }
72 : }
73 266 : set_embedded_objects_cleared(true);
74 266 : }
75 :
76 1958 : void Code::Relocate(intptr_t delta) {
77 39366 : for (RelocIterator it(*this, RelocInfo::kApplyMask); !it.done(); it.next()) {
78 : it.rinfo()->apply(delta);
79 : }
80 : FlushICache();
81 1958 : }
82 :
83 1893227 : void Code::FlushICache() const {
84 1895185 : FlushInstructionCache(raw_instruction_start(), raw_instruction_size());
85 1893229 : }
86 :
87 3786457 : void Code::CopyFromNoFlush(Heap* heap, const CodeDesc& desc) {
88 : // Copy code.
89 : CopyBytes(reinterpret_cast<byte*>(raw_instruction_start()), desc.buffer,
90 3786456 : static_cast<size_t>(desc.instr_size));
91 :
92 : // Copy unwinding info, if any.
93 1893229 : if (desc.unwinding_info) {
94 : DCHECK_GT(desc.unwinding_info_size, 0);
95 27 : set_unwinding_info_size(desc.unwinding_info_size);
96 : CopyBytes(reinterpret_cast<byte*>(unwinding_info_start()),
97 : desc.unwinding_info,
98 54 : static_cast<size_t>(desc.unwinding_info_size));
99 : }
100 :
101 : // Copy reloc info.
102 : CopyRelocInfoToByteArray(unchecked_relocation_info(), desc);
103 :
104 : // Unbox handles and relocate.
105 1893229 : Assembler* origin = desc.origin;
106 : AllowDeferredHandleDereference embedding_raw_address;
107 : const int mode_mask = RelocInfo::PostCodegenRelocationMask();
108 11969018 : for (RelocIterator it(*this, mode_mask); !it.done(); it.next()) {
109 10075789 : RelocInfo::Mode mode = it.rinfo()->rmode();
110 10075789 : if (mode == RelocInfo::EMBEDDED_OBJECT) {
111 6249670 : Handle<HeapObject> p = it.rinfo()->target_object_handle(origin);
112 : it.rinfo()->set_target_object(heap, *p, UPDATE_WRITE_BARRIER,
113 : SKIP_ICACHE_FLUSH);
114 3826119 : } else if (RelocInfo::IsCodeTargetMode(mode)) {
115 : // Rewrite code handles to direct pointers to the first instruction in the
116 : // code object.
117 545561 : Handle<Object> p = it.rinfo()->target_object_handle(origin);
118 : Code code = Code::cast(*p);
119 : it.rinfo()->set_target_address(code->raw_instruction_start(),
120 545560 : UPDATE_WRITE_BARRIER, SKIP_ICACHE_FLUSH);
121 3280558 : } else if (RelocInfo::IsRuntimeEntry(mode)) {
122 3272596 : Address p = it.rinfo()->target_runtime_entry(origin);
123 : it.rinfo()->set_target_runtime_entry(p, UPDATE_WRITE_BARRIER,
124 : SKIP_ICACHE_FLUSH);
125 : } else {
126 : intptr_t delta =
127 7962 : raw_instruction_start() - reinterpret_cast<Address>(desc.buffer);
128 : it.rinfo()->apply(delta);
129 : }
130 : }
131 1893229 : }
132 :
133 2850503 : SafepointEntry Code::GetSafepointEntry(Address pc) {
134 2850503 : SafepointTable table(*this);
135 2850503 : return table.FindEntry(pc);
136 : }
137 :
138 67549 : int Code::OffHeapInstructionSize() const {
139 : DCHECK(is_off_heap_trampoline());
140 67549 : if (Isolate::CurrentEmbeddedBlob() == nullptr) return raw_instruction_size();
141 67549 : EmbeddedData d = EmbeddedData::FromBlob();
142 67549 : return d.InstructionSizeOfBuiltin(builtin_index());
143 : }
144 :
145 185706346 : Address Code::OffHeapInstructionStart() const {
146 : DCHECK(is_off_heap_trampoline());
147 185706346 : if (Isolate::CurrentEmbeddedBlob() == nullptr) return raw_instruction_start();
148 185707028 : EmbeddedData d = EmbeddedData::FromBlob();
149 185707028 : return d.InstructionStartOfBuiltin(builtin_index());
150 : }
151 :
152 95506 : Address Code::OffHeapInstructionEnd() const {
153 : DCHECK(is_off_heap_trampoline());
154 95506 : if (Isolate::CurrentEmbeddedBlob() == nullptr) return raw_instruction_end();
155 95506 : EmbeddedData d = EmbeddedData::FromBlob();
156 191012 : return d.InstructionStartOfBuiltin(builtin_index()) +
157 191012 : d.InstructionSizeOfBuiltin(builtin_index());
158 : }
159 :
160 : namespace {
161 : template <typename Code>
162 8490 : void SetStackFrameCacheCommon(Isolate* isolate, Handle<Code> code,
163 : Handle<SimpleNumberDictionary> cache) {
164 : Handle<Object> maybe_table(code->source_position_table(), isolate);
165 16980 : if (maybe_table->IsSourcePositionTableWithFrameCache()) {
166 349 : Handle<SourcePositionTableWithFrameCache>::cast(maybe_table)
167 1047 : ->set_stack_frame_cache(*cache);
168 8839 : return;
169 : }
170 : DCHECK(maybe_table->IsUndefined() || maybe_table->IsByteArray());
171 8141 : Handle<ByteArray> table(Handle<ByteArray>::cast(maybe_table));
172 : Handle<SourcePositionTableWithFrameCache> table_with_cache =
173 8141 : isolate->factory()->NewSourcePositionTableWithFrameCache(table, cache);
174 16282 : code->set_source_position_table(*table_with_cache);
175 : }
176 : } // namespace
177 :
178 : // static
179 8490 : void AbstractCode::SetStackFrameCache(Handle<AbstractCode> abstract_code,
180 : Handle<SimpleNumberDictionary> cache) {
181 16980 : if (abstract_code->IsCode()) {
182 : SetStackFrameCacheCommon(
183 : abstract_code->GetIsolate(),
184 0 : handle(abstract_code->GetCode(), abstract_code->GetIsolate()), cache);
185 : } else {
186 : SetStackFrameCacheCommon(
187 : abstract_code->GetIsolate(),
188 : handle(abstract_code->GetBytecodeArray(), abstract_code->GetIsolate()),
189 16980 : cache);
190 : }
191 8490 : }
192 :
193 : namespace {
194 : template <typename Code>
195 754570 : void DropStackFrameCacheCommon(Code code) {
196 754570 : i::Object maybe_table = code->source_position_table();
197 2263690 : if (maybe_table->IsUndefined() || maybe_table->IsByteArray()) return;
198 : DCHECK(maybe_table->IsSourcePositionTableWithFrameCache());
199 20 : code->set_source_position_table(
200 : i::SourcePositionTableWithFrameCache::cast(maybe_table)
201 40 : ->source_position_table());
202 : }
203 : } // namespace
204 :
205 754570 : void AbstractCode::DropStackFrameCache() {
206 1509140 : if (IsCode()) {
207 754187 : DropStackFrameCacheCommon(GetCode());
208 : } else {
209 383 : DropStackFrameCacheCommon(GetBytecodeArray());
210 : }
211 754570 : }
212 :
213 1424034 : int AbstractCode::SourcePosition(int offset) {
214 : int position = 0;
215 : // Subtract one because the current PC is one instruction after the call site.
216 2848068 : if (IsCode()) offset--;
217 38005350 : for (SourcePositionTableIterator iterator(source_position_table());
218 36581316 : !iterator.done() && iterator.code_offset() <= offset;
219 35157282 : iterator.Advance()) {
220 35157282 : position = iterator.source_position().ScriptOffset();
221 : }
222 1424034 : return position;
223 : }
224 :
225 107662 : int AbstractCode::SourceStatementPosition(int offset) {
226 : // First find the closest position.
227 107662 : int position = SourcePosition(offset);
228 : // Now find the closest statement position before the position.
229 : int statement_position = 0;
230 11288758 : for (SourcePositionTableIterator it(source_position_table()); !it.done();
231 11073434 : it.Advance()) {
232 11073434 : if (it.is_statement()) {
233 7017126 : int p = it.source_position().ScriptOffset();
234 7017126 : if (statement_position < p && p <= position) {
235 : statement_position = p;
236 : }
237 : }
238 : }
239 107662 : return statement_position;
240 : }
241 :
242 240 : void Code::PrintDeoptLocation(FILE* out, const char* str, Address pc) {
243 240 : Deoptimizer::DeoptInfo info = Deoptimizer::GetDeoptInfo(*this, pc);
244 240 : class SourcePosition pos = info.position;
245 240 : if (info.deopt_reason != DeoptimizeReason::kUnknown || pos.IsKnown()) {
246 240 : PrintF(out, "%s", str);
247 240 : OFStream outstr(out);
248 240 : pos.Print(outstr, *this);
249 240 : PrintF(out, ", %s\n", DeoptimizeReasonToString(info.deopt_reason));
250 : }
251 240 : }
252 :
253 9441 : bool Code::CanDeoptAt(Address pc) {
254 : DeoptimizationData deopt_data =
255 18882 : DeoptimizationData::cast(deoptimization_data());
256 9441 : Address code_start_address = InstructionStart();
257 100230 : for (int i = 0; i < deopt_data->DeoptCount(); i++) {
258 197530 : if (deopt_data->Pc(i)->value() == -1) continue;
259 137556 : Address address = code_start_address + deopt_data->Pc(i)->value();
260 76754 : if (address == pc && deopt_data->BytecodeOffset(i) != BailoutId::None()) {
261 : return true;
262 : }
263 : }
264 : return false;
265 : }
266 :
267 : // Identify kind of code.
268 19676 : const char* Code::Kind2String(Kind kind) {
269 19676 : switch (kind) {
270 : #define CASE(name) \
271 : case name: \
272 : return #name;
273 0 : CODE_KIND_LIST(CASE)
274 : #undef CASE
275 : case NUMBER_OF_KINDS:
276 : break;
277 : }
278 0 : UNREACHABLE();
279 : }
280 :
281 : // Identify kind of code.
282 0 : const char* AbstractCode::Kind2String(Kind kind) {
283 0 : if (kind < AbstractCode::INTERPRETED_FUNCTION)
284 0 : return Code::Kind2String(static_cast<Code::Kind>(kind));
285 0 : if (kind == AbstractCode::INTERPRETED_FUNCTION) return "INTERPRETED_FUNCTION";
286 0 : UNREACHABLE();
287 : }
288 :
289 84280 : bool Code::IsIsolateIndependent(Isolate* isolate) {
290 : constexpr int all_real_modes_mask =
291 : (1 << (RelocInfo::LAST_REAL_RELOC_MODE + 1)) - 1;
292 : constexpr int mode_mask = all_real_modes_mask &
293 : ~RelocInfo::ModeMask(RelocInfo::CONST_POOL) &
294 : ~RelocInfo::ModeMask(RelocInfo::OFF_HEAP_TARGET) &
295 : ~RelocInfo::ModeMask(RelocInfo::VENEER_POOL);
296 : STATIC_ASSERT(RelocInfo::LAST_REAL_RELOC_MODE == RelocInfo::VENEER_POOL);
297 : STATIC_ASSERT(mode_mask ==
298 : (RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
299 : RelocInfo::ModeMask(RelocInfo::RELATIVE_CODE_TARGET) |
300 : RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
301 : RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE) |
302 : RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE) |
303 : RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE_ENCODED) |
304 : RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY) |
305 : RelocInfo::ModeMask(RelocInfo::WASM_CALL) |
306 : RelocInfo::ModeMask(RelocInfo::WASM_STUB_CALL)));
307 :
308 : bool is_process_independent = true;
309 500472 : for (RelocIterator it(*this, mode_mask); !it.done(); it.next()) {
310 : #if defined(V8_TARGET_ARCH_X64) || defined(V8_TARGET_ARCH_ARM64) || \
311 : defined(V8_TARGET_ARCH_ARM) || defined(V8_TARGET_ARCH_MIPS) || \
312 : defined(V8_TARGET_ARCH_S390) || defined(V8_TARGET_ARCH_IA32)
313 : // On these platforms we emit relative builtin-to-builtin
314 : // jumps for isolate independent builtins in the snapshot. They are later
315 : // rewritten as pc-relative jumps to the off-heap instruction stream and are
316 : // thus process-independent. See also: FinalizeEmbeddedCodeTargets.
317 416192 : if (RelocInfo::IsCodeTargetMode(it.rinfo()->rmode())) {
318 416192 : Address target_address = it.rinfo()->target_address();
319 832384 : if (InstructionStream::PcIsOffHeap(isolate, target_address)) continue;
320 :
321 416192 : Code target = Code::GetCodeFromTargetAddress(target_address);
322 416192 : CHECK(target->IsCode());
323 416192 : if (Builtins::IsIsolateIndependentBuiltin(target)) continue;
324 : }
325 : #endif
326 : is_process_independent = false;
327 : }
328 :
329 84280 : return is_process_independent;
330 : }
331 :
332 17288 : bool Code::Inlines(SharedFunctionInfo sfi) {
333 : // We can only check for inlining for optimized code.
334 : DCHECK(is_optimized_code());
335 : DisallowHeapAllocation no_gc;
336 : DeoptimizationData const data =
337 34576 : DeoptimizationData::cast(deoptimization_data());
338 17288 : if (data->length() == 0) return false;
339 17288 : if (data->SharedFunctionInfo() == sfi) return true;
340 16981 : FixedArray const literals = data->LiteralArray();
341 33962 : int const inlined_count = data->InlinedFunctionCount()->value();
342 17064 : for (int i = 0; i < inlined_count; ++i) {
343 125 : if (SharedFunctionInfo::cast(literals->get(i)) == sfi) return true;
344 : }
345 : return false;
346 : }
347 :
348 12396 : Code::OptimizedCodeIterator::OptimizedCodeIterator(Isolate* isolate) {
349 12396 : isolate_ = isolate;
350 12396 : Object list = isolate->heap()->native_contexts_list();
351 24792 : next_context_ = list->IsUndefined(isolate_) ? Context() : Context::cast(list);
352 12396 : }
353 :
354 29684 : Code Code::OptimizedCodeIterator::Next() {
355 30458 : do {
356 42854 : Object next;
357 42854 : if (!current_code_.is_null()) {
358 : // Get next code in the linked list.
359 34576 : next = current_code_->next_code_link();
360 25566 : } else if (!next_context_.is_null()) {
361 : // Linked list of code exhausted. Get list of next context.
362 13170 : next = next_context_->OptimizedCodeListHead();
363 13170 : Object next_context = next_context_->next_context_link();
364 13170 : next_context_ = next_context->IsUndefined(isolate_)
365 : ? Context()
366 13944 : : Context::cast(next_context);
367 : } else {
368 : // Exhausted contexts.
369 12396 : return Code();
370 : }
371 78204 : current_code_ = next->IsUndefined(isolate_) ? Code() : Code::cast(next);
372 : } while (current_code_.is_null());
373 : DCHECK_EQ(Code::OPTIMIZED_FUNCTION, current_code_->kind());
374 17288 : return current_code_;
375 : }
376 :
377 456566 : Handle<DeoptimizationData> DeoptimizationData::New(Isolate* isolate,
378 : int deopt_entry_count,
379 : PretenureFlag pretenure) {
380 : return Handle<DeoptimizationData>::cast(isolate->factory()->NewFixedArray(
381 456566 : LengthFor(deopt_entry_count), pretenure));
382 : }
383 :
384 1436652 : Handle<DeoptimizationData> DeoptimizationData::Empty(Isolate* isolate) {
385 : return Handle<DeoptimizationData>::cast(
386 1436652 : isolate->factory()->empty_fixed_array());
387 : }
388 :
389 86 : SharedFunctionInfo DeoptimizationData::GetInlinedFunction(int index) {
390 86 : if (index == -1) {
391 : return SharedFunctionInfo::cast(SharedFunctionInfo());
392 : } else {
393 172 : return SharedFunctionInfo::cast(LiteralArray()->get(index));
394 : }
395 : }
396 :
397 : #ifdef ENABLE_DISASSEMBLER
398 :
399 : const char* Code::GetName(Isolate* isolate) const {
400 : if (kind() == BYTECODE_HANDLER) {
401 : return isolate->interpreter()->LookupNameOfBytecodeHandler(*this);
402 : } else {
403 : // There are some handlers and ICs that we can also find names for with
404 : // Builtins::Lookup.
405 : return isolate->builtins()->Lookup(raw_instruction_start());
406 : }
407 : }
408 :
409 : namespace {
410 : void print_pc(std::ostream& os, int pc) {
411 : if (pc == -1) {
412 : os << "NA";
413 : } else {
414 : os << std::hex << pc << std::dec;
415 : }
416 : }
417 : } // anonymous namespace
418 :
419 : void DeoptimizationData::DeoptimizationDataPrint(std::ostream& os) { // NOLINT
420 : if (length() == 0) {
421 : os << "Deoptimization Input Data invalidated by lazy deoptimization\n";
422 : return;
423 : }
424 :
425 : disasm::NameConverter converter;
426 : int const inlined_function_count = InlinedFunctionCount()->value();
427 : os << "Inlined functions (count = " << inlined_function_count << ")\n";
428 : for (int id = 0; id < inlined_function_count; ++id) {
429 : Object info = LiteralArray()->get(id);
430 : os << " " << Brief(SharedFunctionInfo::cast(info)) << "\n";
431 : }
432 : os << "\n";
433 : int deopt_count = DeoptCount();
434 : os << "Deoptimization Input Data (deopt points = " << deopt_count << ")\n";
435 : if (0 != deopt_count) {
436 : os << " index bytecode-offset pc";
437 : if (FLAG_print_code_verbose) os << " commands";
438 : os << "\n";
439 : }
440 : for (int i = 0; i < deopt_count; i++) {
441 : os << std::setw(6) << i << " " << std::setw(15)
442 : << BytecodeOffset(i).ToInt() << " " << std::setw(4);
443 : print_pc(os, Pc(i)->value());
444 : os << std::setw(2);
445 :
446 : if (!FLAG_print_code_verbose) {
447 : os << "\n";
448 : continue;
449 : }
450 :
451 : // Print details of the frame translation.
452 : int translation_index = TranslationIndex(i)->value();
453 : TranslationIterator iterator(TranslationByteArray(), translation_index);
454 : Translation::Opcode opcode =
455 : static_cast<Translation::Opcode>(iterator.Next());
456 : DCHECK(Translation::BEGIN == opcode);
457 : int frame_count = iterator.Next();
458 : int jsframe_count = iterator.Next();
459 : int update_feedback_count = iterator.Next();
460 : os << " " << Translation::StringFor(opcode)
461 : << " {frame count=" << frame_count
462 : << ", js frame count=" << jsframe_count
463 : << ", update_feedback_count=" << update_feedback_count << "}\n";
464 :
465 : while (iterator.HasNext() &&
466 : Translation::BEGIN !=
467 : (opcode = static_cast<Translation::Opcode>(iterator.Next()))) {
468 : os << std::setw(31) << " " << Translation::StringFor(opcode) << " ";
469 :
470 : switch (opcode) {
471 : case Translation::BEGIN:
472 : UNREACHABLE();
473 : break;
474 :
475 : case Translation::INTERPRETED_FRAME: {
476 : int bytecode_offset = iterator.Next();
477 : int shared_info_id = iterator.Next();
478 : unsigned height = iterator.Next();
479 : int return_value_offset = iterator.Next();
480 : int return_value_count = iterator.Next();
481 : Object shared_info = LiteralArray()->get(shared_info_id);
482 : os << "{bytecode_offset=" << bytecode_offset << ", function="
483 : << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
484 : << ", height=" << height << ", retval=@" << return_value_offset
485 : << "(#" << return_value_count << ")}";
486 : break;
487 : }
488 :
489 : case Translation::CONSTRUCT_STUB_FRAME: {
490 : int bailout_id = iterator.Next();
491 : int shared_info_id = iterator.Next();
492 : Object shared_info = LiteralArray()->get(shared_info_id);
493 : unsigned height = iterator.Next();
494 : os << "{bailout_id=" << bailout_id << ", function="
495 : << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
496 : << ", height=" << height << "}";
497 : break;
498 : }
499 :
500 : case Translation::BUILTIN_CONTINUATION_FRAME:
501 : case Translation::JAVA_SCRIPT_BUILTIN_CONTINUATION_FRAME:
502 : case Translation::JAVA_SCRIPT_BUILTIN_CONTINUATION_WITH_CATCH_FRAME: {
503 : int bailout_id = iterator.Next();
504 : int shared_info_id = iterator.Next();
505 : Object shared_info = LiteralArray()->get(shared_info_id);
506 : unsigned height = iterator.Next();
507 : os << "{bailout_id=" << bailout_id << ", function="
508 : << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
509 : << ", height=" << height << "}";
510 : break;
511 : }
512 :
513 : case Translation::ARGUMENTS_ADAPTOR_FRAME: {
514 : int shared_info_id = iterator.Next();
515 : Object shared_info = LiteralArray()->get(shared_info_id);
516 : unsigned height = iterator.Next();
517 : os << "{function="
518 : << Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
519 : << ", height=" << height << "}";
520 : break;
521 : }
522 :
523 : case Translation::REGISTER: {
524 : int reg_code = iterator.Next();
525 : os << "{input=" << converter.NameOfCPURegister(reg_code) << "}";
526 : break;
527 : }
528 :
529 : case Translation::INT32_REGISTER: {
530 : int reg_code = iterator.Next();
531 : os << "{input=" << converter.NameOfCPURegister(reg_code)
532 : << " (int32)}";
533 : break;
534 : }
535 :
536 : case Translation::INT64_REGISTER: {
537 : int reg_code = iterator.Next();
538 : os << "{input=" << converter.NameOfCPURegister(reg_code)
539 : << " (int64)}";
540 : break;
541 : }
542 :
543 : case Translation::UINT32_REGISTER: {
544 : int reg_code = iterator.Next();
545 : os << "{input=" << converter.NameOfCPURegister(reg_code)
546 : << " (uint32)}";
547 : break;
548 : }
549 :
550 : case Translation::BOOL_REGISTER: {
551 : int reg_code = iterator.Next();
552 : os << "{input=" << converter.NameOfCPURegister(reg_code)
553 : << " (bool)}";
554 : break;
555 : }
556 :
557 : case Translation::FLOAT_REGISTER: {
558 : int reg_code = iterator.Next();
559 : os << "{input=" << FloatRegister::from_code(reg_code) << "}";
560 : break;
561 : }
562 :
563 : case Translation::DOUBLE_REGISTER: {
564 : int reg_code = iterator.Next();
565 : os << "{input=" << DoubleRegister::from_code(reg_code) << "}";
566 : break;
567 : }
568 :
569 : case Translation::STACK_SLOT: {
570 : int input_slot_index = iterator.Next();
571 : os << "{input=" << input_slot_index << "}";
572 : break;
573 : }
574 :
575 : case Translation::INT32_STACK_SLOT: {
576 : int input_slot_index = iterator.Next();
577 : os << "{input=" << input_slot_index << " (int32)}";
578 : break;
579 : }
580 :
581 : case Translation::INT64_STACK_SLOT: {
582 : int input_slot_index = iterator.Next();
583 : os << "{input=" << input_slot_index << " (int64)}";
584 : break;
585 : }
586 :
587 : case Translation::UINT32_STACK_SLOT: {
588 : int input_slot_index = iterator.Next();
589 : os << "{input=" << input_slot_index << " (uint32)}";
590 : break;
591 : }
592 :
593 : case Translation::BOOL_STACK_SLOT: {
594 : int input_slot_index = iterator.Next();
595 : os << "{input=" << input_slot_index << " (bool)}";
596 : break;
597 : }
598 :
599 : case Translation::FLOAT_STACK_SLOT:
600 : case Translation::DOUBLE_STACK_SLOT: {
601 : int input_slot_index = iterator.Next();
602 : os << "{input=" << input_slot_index << "}";
603 : break;
604 : }
605 :
606 : case Translation::LITERAL: {
607 : int literal_index = iterator.Next();
608 : Object literal_value = LiteralArray()->get(literal_index);
609 : os << "{literal_id=" << literal_index << " (" << Brief(literal_value)
610 : << ")}";
611 : break;
612 : }
613 :
614 : case Translation::DUPLICATED_OBJECT: {
615 : int object_index = iterator.Next();
616 : os << "{object_index=" << object_index << "}";
617 : break;
618 : }
619 :
620 : case Translation::ARGUMENTS_ELEMENTS:
621 : case Translation::ARGUMENTS_LENGTH: {
622 : CreateArgumentsType arguments_type =
623 : static_cast<CreateArgumentsType>(iterator.Next());
624 : os << "{arguments_type=" << arguments_type << "}";
625 : break;
626 : }
627 :
628 : case Translation::CAPTURED_OBJECT: {
629 : int args_length = iterator.Next();
630 : os << "{length=" << args_length << "}";
631 : break;
632 : }
633 :
634 : case Translation::UPDATE_FEEDBACK: {
635 : int literal_index = iterator.Next();
636 : FeedbackSlot slot(iterator.Next());
637 : os << "{feedback={vector_index=" << literal_index << ", slot=" << slot
638 : << "}}";
639 : break;
640 : }
641 : }
642 : os << "\n";
643 : }
644 : }
645 : }
646 :
647 : namespace {
648 :
649 : inline void DisassembleCodeRange(Isolate* isolate, std::ostream& os, Code code,
650 : Address begin, size_t size,
651 : Address current_pc) {
652 : Address end = begin + size;
653 : // TODO(mstarzinger): Refactor CodeReference to avoid the
654 : // unhandlified->handlified transition.
655 : AllowHandleAllocation allow_handles;
656 : DisallowHeapAllocation no_gc;
657 : HandleScope handle_scope(isolate);
658 : Disassembler::Decode(isolate, &os, reinterpret_cast<byte*>(begin),
659 : reinterpret_cast<byte*>(end),
660 : CodeReference(handle(code, isolate)), current_pc);
661 : }
662 :
663 : } // namespace
664 :
665 : void Code::Disassemble(const char* name, std::ostream& os, Address current_pc) {
666 : Isolate* isolate = GetIsolate();
667 : os << "kind = " << Kind2String(kind()) << "\n";
668 : if (name == nullptr) {
669 : name = GetName(isolate);
670 : }
671 : if ((name != nullptr) && (name[0] != '\0')) {
672 : os << "name = " << name << "\n";
673 : }
674 : if (kind() == OPTIMIZED_FUNCTION) {
675 : os << "stack_slots = " << stack_slots() << "\n";
676 : }
677 : os << "compiler = " << (is_turbofanned() ? "turbofan" : "unknown") << "\n";
678 : os << "address = " << static_cast<const void*>(this) << "\n\n";
679 :
680 : if (is_off_heap_trampoline()) {
681 : int trampoline_size = raw_instruction_size();
682 : os << "Trampoline (size = " << trampoline_size << ")\n";
683 : DisassembleCodeRange(isolate, os, *this, raw_instruction_start(),
684 : trampoline_size, current_pc);
685 : os << "\n";
686 : }
687 :
688 : {
689 : // Stop before reaching any embedded tables
690 : int code_size = ExecutableInstructionSize();
691 : os << "Instructions (size = " << code_size << ")\n";
692 : DisassembleCodeRange(isolate, os, *this, InstructionStart(), code_size,
693 : current_pc);
694 :
695 : if (int pool_size = constant_pool_size()) {
696 : DCHECK_EQ(pool_size & kPointerAlignmentMask, 0);
697 : os << "\nConstant Pool (size = " << pool_size << ")\n";
698 : Vector<char> buf = Vector<char>::New(50);
699 : intptr_t* ptr = reinterpret_cast<intptr_t*>(InstructionStart() +
700 : constant_pool_offset());
701 : for (int i = 0; i < pool_size; i += kSystemPointerSize, ptr++) {
702 : SNPrintF(buf, "%4d %08" V8PRIxPTR, i, *ptr);
703 : os << static_cast<const void*>(ptr) << " " << buf.start() << "\n";
704 : }
705 : }
706 : }
707 : os << "\n";
708 :
709 : {
710 : SourcePositionTableIterator it(
711 : SourcePositionTable(), SourcePositionTableIterator::kJavaScriptOnly);
712 : if (!it.done()) {
713 : os << "Source positions:\n pc offset position\n";
714 : for (; !it.done(); it.Advance()) {
715 : os << std::setw(10) << std::hex << it.code_offset() << std::dec
716 : << std::setw(10) << it.source_position().ScriptOffset()
717 : << (it.is_statement() ? " statement" : "") << "\n";
718 : }
719 : os << "\n";
720 : }
721 : }
722 :
723 : {
724 : SourcePositionTableIterator it(SourcePositionTable(),
725 : SourcePositionTableIterator::kExternalOnly);
726 : if (!it.done()) {
727 : os << "External Source positions:\n pc offset fileid line\n";
728 : for (; !it.done(); it.Advance()) {
729 : DCHECK(it.source_position().IsExternal());
730 : os << std::setw(10) << std::hex << it.code_offset() << std::dec
731 : << std::setw(10) << it.source_position().ExternalFileId()
732 : << std::setw(10) << it.source_position().ExternalLine() << "\n";
733 : }
734 : os << "\n";
735 : }
736 : }
737 :
738 : if (kind() == OPTIMIZED_FUNCTION) {
739 : DeoptimizationData data =
740 : DeoptimizationData::cast(this->deoptimization_data());
741 : data->DeoptimizationDataPrint(os);
742 : }
743 : os << "\n";
744 :
745 : if (has_safepoint_info()) {
746 : SafepointTable table(*this);
747 : os << "Safepoints (size = " << table.size() << ")\n";
748 : for (unsigned i = 0; i < table.length(); i++) {
749 : unsigned pc_offset = table.GetPcOffset(i);
750 : os << reinterpret_cast<const void*>(InstructionStart() + pc_offset)
751 : << " ";
752 : os << std::setw(6) << std::hex << pc_offset << " " << std::setw(4);
753 : int trampoline_pc = table.GetTrampolinePcOffset(i);
754 : print_pc(os, trampoline_pc);
755 : os << std::dec << " ";
756 : table.PrintEntry(i, os);
757 : os << " (sp -> fp) ";
758 : SafepointEntry entry = table.GetEntry(i);
759 : if (entry.has_deoptimization_index()) {
760 : os << std::setw(6) << entry.deoptimization_index();
761 : } else {
762 : os << "<none>";
763 : }
764 : os << "\n";
765 : }
766 : os << "\n";
767 : }
768 :
769 : if (has_handler_table()) {
770 : HandlerTable table(*this);
771 : os << "Handler Table (size = " << table.NumberOfReturnEntries() << ")\n";
772 : if (kind() == OPTIMIZED_FUNCTION) {
773 : table.HandlerTableReturnPrint(os);
774 : }
775 : os << "\n";
776 : }
777 :
778 : os << "RelocInfo (size = " << relocation_size() << ")\n";
779 : for (RelocIterator it(*this); !it.done(); it.next()) {
780 : it.rinfo()->Print(isolate, os);
781 : }
782 : os << "\n";
783 :
784 : if (has_unwinding_info()) {
785 : os << "UnwindingInfo (size = " << unwinding_info_size() << ")\n";
786 : EhFrameDisassembler eh_frame_disassembler(
787 : reinterpret_cast<byte*>(unwinding_info_start()),
788 : reinterpret_cast<byte*>(unwinding_info_end()));
789 : eh_frame_disassembler.DisassembleToStream(os);
790 : os << "\n";
791 : }
792 :
793 : if (has_code_comments()) {
794 : PrintCodeCommentsSection(os, code_comments());
795 : }
796 : }
797 : #endif // ENABLE_DISASSEMBLER
798 :
799 0 : void BytecodeArray::Disassemble(std::ostream& os) {
800 : DisallowHeapAllocation no_gc;
801 :
802 0 : os << "Parameter count " << parameter_count() << "\n";
803 0 : os << "Register count " << register_count() << "\n";
804 0 : os << "Frame size " << frame_size() << "\n";
805 :
806 : Address base_address = GetFirstBytecodeAddress();
807 0 : SourcePositionTableIterator source_positions(SourcePositionTable());
808 :
809 : // Storage for backing the handle passed to the iterator. This handle won't be
810 : // updated by the gc, but that's ok because we've disallowed GCs anyway.
811 0 : BytecodeArray handle_storage = *this;
812 : Handle<BytecodeArray> handle(reinterpret_cast<Address*>(&handle_storage));
813 0 : interpreter::BytecodeArrayIterator iterator(handle);
814 0 : while (!iterator.done()) {
815 0 : if (!source_positions.done() &&
816 0 : iterator.current_offset() == source_positions.code_offset()) {
817 0 : os << std::setw(5) << source_positions.source_position().ScriptOffset();
818 0 : os << (source_positions.is_statement() ? " S> " : " E> ");
819 0 : source_positions.Advance();
820 : } else {
821 0 : os << " ";
822 : }
823 0 : Address current_address = base_address + iterator.current_offset();
824 0 : os << reinterpret_cast<const void*>(current_address) << " @ "
825 0 : << std::setw(4) << iterator.current_offset() << " : ";
826 : interpreter::BytecodeDecoder::Decode(
827 0 : os, reinterpret_cast<byte*>(current_address), parameter_count());
828 0 : if (interpreter::Bytecodes::IsJump(iterator.current_bytecode())) {
829 0 : Address jump_target = base_address + iterator.GetJumpTargetOffset();
830 0 : os << " (" << reinterpret_cast<void*>(jump_target) << " @ "
831 0 : << iterator.GetJumpTargetOffset() << ")";
832 : }
833 0 : if (interpreter::Bytecodes::IsSwitch(iterator.current_bytecode())) {
834 0 : os << " {";
835 : bool first_entry = true;
836 0 : for (const auto& entry : iterator.GetJumpTableTargetOffsets()) {
837 0 : if (first_entry) {
838 : first_entry = false;
839 : } else {
840 0 : os << ",";
841 : }
842 0 : os << " " << entry.case_value << ": @" << entry.target_offset;
843 : }
844 0 : os << " }";
845 : }
846 : os << std::endl;
847 0 : iterator.Advance();
848 : }
849 :
850 0 : os << "Constant pool (size = " << constant_pool()->length() << ")\n";
851 : #ifdef OBJECT_PRINT
852 : if (constant_pool()->length() > 0) {
853 : constant_pool()->Print();
854 : }
855 : #endif
856 :
857 0 : os << "Handler Table (size = " << handler_table()->length() << ")\n";
858 : #ifdef ENABLE_DISASSEMBLER
859 : if (handler_table()->length() > 0) {
860 : HandlerTable table(*this);
861 : table.HandlerTableRangePrint(os);
862 : }
863 : #endif
864 0 : }
865 :
866 10577 : void BytecodeArray::CopyBytecodesTo(BytecodeArray to) {
867 10577 : BytecodeArray from = *this;
868 : DCHECK_EQ(from->length(), to->length());
869 : CopyBytes(reinterpret_cast<byte*>(to->GetFirstBytecodeAddress()),
870 : reinterpret_cast<byte*>(from->GetFirstBytecodeAddress()),
871 31731 : from->length());
872 10577 : }
873 :
874 1552417 : void BytecodeArray::MakeOlder() {
875 : // BytecodeArray is aged in concurrent marker.
876 : // The word must be completely within the byte code array.
877 1552417 : Address age_addr = address() + kBytecodeAgeOffset;
878 : DCHECK_LE(RoundDown(age_addr, kSystemPointerSize) + kSystemPointerSize,
879 : address() + Size());
880 : Age age = bytecode_age();
881 1552417 : if (age < kLastBytecodeAge) {
882 : base::AsAtomic8::Release_CompareAndSwap(reinterpret_cast<byte*>(age_addr),
883 1201606 : age, age + 1);
884 : }
885 :
886 : DCHECK_GE(bytecode_age(), kFirstBytecodeAge);
887 : DCHECK_LE(bytecode_age(), kLastBytecodeAge);
888 1552417 : }
889 :
890 2328602 : bool BytecodeArray::IsOld() const {
891 2328602 : return bytecode_age() >= kIsOldBytecodeAge;
892 : }
893 :
894 476817 : DependentCode DependentCode::GetDependentCode(Handle<HeapObject> object) {
895 953634 : if (object->IsMap()) {
896 531874 : return Handle<Map>::cast(object)->dependent_code();
897 421760 : } else if (object->IsPropertyCell()) {
898 401426 : return Handle<PropertyCell>::cast(object)->dependent_code();
899 20334 : } else if (object->IsAllocationSite()) {
900 20334 : return Handle<AllocationSite>::cast(object)->dependent_code();
901 : }
902 0 : UNREACHABLE();
903 : }
904 :
905 126332 : void DependentCode::SetDependentCode(Handle<HeapObject> object,
906 : Handle<DependentCode> dep) {
907 252664 : if (object->IsMap()) {
908 142052 : Handle<Map>::cast(object)->set_dependent_code(*dep);
909 110612 : } else if (object->IsPropertyCell()) {
910 91616 : Handle<PropertyCell>::cast(object)->set_dependent_code(*dep);
911 18996 : } else if (object->IsAllocationSite()) {
912 18996 : Handle<AllocationSite>::cast(object)->set_dependent_code(*dep);
913 : } else {
914 0 : UNREACHABLE();
915 : }
916 126332 : }
917 :
918 476817 : void DependentCode::InstallDependency(Isolate* isolate,
919 : const MaybeObjectHandle& code,
920 : Handle<HeapObject> object,
921 : DependencyGroup group) {
922 : Handle<DependentCode> old_deps(DependentCode::GetDependentCode(object),
923 476817 : isolate);
924 : Handle<DependentCode> new_deps =
925 476817 : InsertWeakCode(isolate, old_deps, group, code);
926 : // Update the list head if necessary.
927 476817 : if (!new_deps.is_identical_to(old_deps))
928 126332 : DependentCode::SetDependentCode(object, new_deps);
929 476817 : }
930 :
931 543404 : Handle<DependentCode> DependentCode::InsertWeakCode(
932 : Isolate* isolate, Handle<DependentCode> entries, DependencyGroup group,
933 : const MaybeObjectHandle& code) {
934 1478566 : if (entries->length() == 0 || entries->group() > group) {
935 : // There is no such group.
936 84413 : return DependentCode::New(isolate, group, code, entries);
937 : }
938 917982 : if (entries->group() < group) {
939 : // The group comes later in the list.
940 133174 : Handle<DependentCode> old_next(entries->next_link(), isolate);
941 : Handle<DependentCode> new_next =
942 66587 : InsertWeakCode(isolate, old_next, group, code);
943 66587 : if (!old_next.is_identical_to(new_next)) {
944 20224 : entries->set_next_link(*new_next);
945 : }
946 66587 : return entries;
947 : }
948 : DCHECK_EQ(group, entries->group());
949 784808 : int count = entries->count();
950 : // Check for existing entry to avoid duplicates.
951 45106769 : for (int i = 0; i < count; i++) {
952 134757537 : if (entries->object_at(i) == *code) return entries;
953 : }
954 375180 : if (entries->length() < kCodesStartIndex + count + 1) {
955 53874 : entries = EnsureSpace(isolate, entries);
956 : // Count could have changed, reload it.
957 107748 : count = entries->count();
958 : }
959 562770 : entries->set_object_at(count, *code);
960 375180 : entries->set_count(count + 1);
961 187590 : return entries;
962 : }
963 :
964 84413 : Handle<DependentCode> DependentCode::New(Isolate* isolate,
965 : DependencyGroup group,
966 : const MaybeObjectHandle& object,
967 : Handle<DependentCode> next) {
968 : Handle<DependentCode> result = Handle<DependentCode>::cast(
969 84413 : isolate->factory()->NewWeakFixedArray(kCodesStartIndex + 1, TENURED));
970 168826 : result->set_next_link(*next);
971 253239 : result->set_flags(GroupField::encode(group) | CountField::encode(1));
972 253239 : result->set_object_at(0, *object);
973 84413 : return result;
974 : }
975 :
976 53874 : Handle<DependentCode> DependentCode::EnsureSpace(
977 : Isolate* isolate, Handle<DependentCode> entries) {
978 53874 : if (entries->Compact()) return entries;
979 104062 : int capacity = kCodesStartIndex + DependentCode::Grow(entries->count());
980 52031 : int grow_by = capacity - entries->length();
981 : return Handle<DependentCode>::cast(
982 52031 : isolate->factory()->CopyWeakFixedArrayAndGrow(entries, grow_by, TENURED));
983 : }
984 :
985 53874 : bool DependentCode::Compact() {
986 : int old_count = count();
987 : int new_count = 0;
988 839552 : for (int i = 0; i < old_count; i++) {
989 : MaybeObject obj = object_at(i);
990 785678 : if (!obj->IsCleared()) {
991 770557 : if (i != new_count) {
992 3106 : copy(i, new_count);
993 : }
994 770557 : new_count++;
995 : }
996 : }
997 53874 : set_count(new_count);
998 68995 : for (int i = new_count; i < old_count; i++) {
999 15121 : clear_at(i);
1000 : }
1001 53874 : return new_count < old_count;
1002 : }
1003 :
1004 18977634 : bool DependentCode::MarkCodeForDeoptimization(
1005 : Isolate* isolate, DependentCode::DependencyGroup group) {
1006 18979889 : if (this->length() == 0 || this->group() > group) {
1007 : // There is no such group.
1008 : return false;
1009 : }
1010 2184 : if (this->group() < group) {
1011 : // The group comes later in the list.
1012 310 : return next_link()->MarkCodeForDeoptimization(isolate, group);
1013 : }
1014 : DCHECK_EQ(group, this->group());
1015 : DisallowHeapAllocation no_allocation_scope;
1016 : // Mark all the code that needs to be deoptimized.
1017 : bool marked = false;
1018 : int count = this->count();
1019 4681 : for (int i = 0; i < count; i++) {
1020 2807 : MaybeObject obj = object_at(i);
1021 2818 : if (obj->IsCleared()) continue;
1022 2796 : Code code = Code::cast(obj->GetHeapObjectAssumeWeak());
1023 2796 : if (!code->marked_for_deoptimization()) {
1024 1929 : code->SetMarkedForDeoptimization(DependencyGroupName(group));
1025 : marked = true;
1026 : }
1027 : }
1028 2807 : for (int i = 0; i < count; i++) {
1029 2807 : clear_at(i);
1030 : }
1031 1874 : set_count(0);
1032 1874 : return marked;
1033 : }
1034 :
1035 18977256 : void DependentCode::DeoptimizeDependentCodeGroup(
1036 : Isolate* isolate, DependentCode::DependencyGroup group) {
1037 : DisallowHeapAllocation no_allocation_scope;
1038 18977256 : bool marked = MarkCodeForDeoptimization(isolate, group);
1039 18977263 : if (marked) {
1040 : DCHECK(AllowCodeDependencyChange::IsAllowed());
1041 1436 : Deoptimizer::DeoptimizeMarkedCode(isolate);
1042 : }
1043 18977263 : }
1044 :
1045 2002 : void Code::SetMarkedForDeoptimization(const char* reason) {
1046 2002 : set_marked_for_deoptimization(true);
1047 6006 : if (FLAG_trace_deopt &&
1048 2020 : (deoptimization_data() != GetReadOnlyRoots().empty_fixed_array())) {
1049 : DeoptimizationData deopt_data =
1050 12 : DeoptimizationData::cast(deoptimization_data());
1051 6 : CodeTracer::Scope scope(GetIsolate()->GetCodeTracer());
1052 : PrintF(scope.file(),
1053 : "[marking dependent code " V8PRIxPTR_FMT
1054 : " (opt #%d) for deoptimization, reason: %s]\n",
1055 12 : ptr(), deopt_data->OptimizationId()->value(), reason);
1056 : }
1057 2002 : }
1058 :
1059 1929 : const char* DependentCode::DependencyGroupName(DependencyGroup group) {
1060 1929 : switch (group) {
1061 : case kTransitionGroup:
1062 : return "transition";
1063 : case kPrototypeCheckGroup:
1064 811 : return "prototype-check";
1065 : case kPropertyCellChangedGroup:
1066 859 : return "property-cell-changed";
1067 : case kFieldOwnerGroup:
1068 128 : return "field-owner";
1069 : case kInitialMapChangedGroup:
1070 101 : return "initial-map-changed";
1071 : case kAllocationSiteTenuringChangedGroup:
1072 6 : return "allocation-site-tenuring-changed";
1073 : case kAllocationSiteTransitionChangedGroup:
1074 6 : return "allocation-site-transition-changed";
1075 : }
1076 0 : UNREACHABLE();
1077 : }
1078 :
1079 : } // namespace internal
1080 178779 : } // namespace v8
|