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