summaryrefslogtreecommitdiffstats
path: root/chromium/v8/src/objects/code.h
blob: 0ddfff4c7b58b2034551cc0e632d6f8c0b44fbe3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef V8_OBJECTS_CODE_H_
#define V8_OBJECTS_CODE_H_

#include "src/codegen/maglev-safepoint-table.h"
#include "src/objects/code-kind.h"
#include "src/objects/heap-object.h"

// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"

namespace v8 {
namespace internal {

class BytecodeArray;
class CodeDesc;
class Factory;
template <typename Impl>
class FactoryBase;
class LocalFactory;

enum class Builtin;

// Code is a container for data fields related to its associated
// {InstructionStream} object. Since {InstructionStream} objects reside on
// write-protected pages within the heap, its header fields need to be
// immutable.  Every InstructionStream object has an associated Code object,
// but not every Code object has an InstructionStream (e.g. for builtins).
//
// Embedded builtins consist of on-heap Code objects, with an out-of-line body
// section. Accessors (e.g. InstructionStart), redirect to the off-heap area.
// Metadata table offsets remain relative to MetadataStart(), i.e. they point
// into the off-heap metadata section. The off-heap layout is described in
// detail in the EmbeddedData class, but at a high level one can assume a
// dedicated, out-of-line, instruction and metadata section for each embedded
// builtin:
//
//  +--------------------------+  <-- InstructionStart()
//  |   off-heap instructions  |
//  |           ...            |
//  +--------------------------+  <-- InstructionEnd()
//
//  +--------------------------+  <-- MetadataStart() (MS)
//  |    off-heap metadata     |
//  |           ...            |  <-- MS + handler_table_offset()
//  |                          |  <-- MS + constant_pool_offset()
//  |                          |  <-- MS + code_comments_offset()
//  |                          |  <-- MS + unwinding_info_offset()
//  +--------------------------+  <-- MetadataEnd()
//
class Code : public HeapObject {
 public:
  // When V8_EXTERNAL_CODE_SPACE is enabled, InstructionStream objects are
  // allocated in a separate pointer compression cage instead of the cage where
  // all the other objects are allocated.
  inline PtrComprCageBase code_cage_base() const;

  // Back-reference to the InstructionStream object.
  //
  // Note the cage-less accessor versions may not be called if the current Code
  // object is InReadOnlySpace. That may only be the case for Code objects
  // representing builtins, or in other words, Code objects for which
  // has_instruction_stream() is never true.
  DECL_GETTER(instruction_stream, Tagged<InstructionStream>)
  DECL_RELAXED_GETTER(instruction_stream, Tagged<InstructionStream>)
  DECL_ACCESSORS(raw_instruction_stream, Tagged<Object>)
  DECL_RELAXED_GETTER(raw_instruction_stream, Tagged<Object>)
  // An unchecked accessor to be used during GC.
  inline Tagged<InstructionStream> unchecked_instruction_stream() const;

  // Whether this Code object has an associated InstructionStream (embedded
  // builtins don't).
  inline bool has_instruction_stream() const;
  inline bool has_instruction_stream(RelaxedLoadTag) const;

  // The start of the associated instruction stream. Points either into an
  // on-heap InstructionStream object, or to the beginning of an embedded
  // builtin.
  DECL_GETTER(instruction_start, Address)
  DECL_PRIMITIVE_ACCESSORS(instruction_size, int)
  inline Address instruction_end() const;

  inline void init_instruction_start(Isolate* isolate, Address initial_value);
  inline void SetInstructionStreamAndInstructionStart(
      Isolate* isolate_for_sandbox, Tagged<InstructionStream> code,
      WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
  inline void SetInstructionStartForOffHeapBuiltin(Isolate* isolate_for_sandbox,
                                                   Address entry);
  inline void ClearInstructionStartForSerialization(Isolate* isolate);
  inline void UpdateInstructionStart(Isolate* isolate_for_sandbox,
                                     Tagged<InstructionStream> istream);

  inline void initialize_flags(CodeKind kind, bool is_turbofanned,
                               int stack_slots);

  // Clear uninitialized padding space. This ensures that the snapshot content
  // is deterministic.
  inline void clear_padding();

  // Flushes the instruction cache for the executable instructions of this code
  // object. Make sure to call this while the code is still writable.
  void FlushICache() const;

  DECL_PRIMITIVE_ACCESSORS(can_have_weak_objects, bool)
  DECL_PRIMITIVE_ACCESSORS(marked_for_deoptimization, bool)

  DECL_PRIMITIVE_ACCESSORS(metadata_size, int)
  // [handler_table_offset]: The offset where the exception handler table
  // starts.
  DECL_PRIMITIVE_ACCESSORS(handler_table_offset, int)
  // [unwinding_info_offset]: Offset of the unwinding info section.
  DECL_PRIMITIVE_ACCESSORS(unwinding_info_offset, int32_t)
  // [deoptimization_data]: Array containing data for deopt for non-baseline
  // code.
  DECL_ACCESSORS(deoptimization_data, Tagged<FixedArray>)
  // [bytecode_or_interpreter_data]: BytecodeArray or InterpreterData for
  // baseline code.
  DECL_ACCESSORS(bytecode_or_interpreter_data, Tagged<HeapObject>)
  // [source_position_table]: ByteArray for the source positions table for
  // non-baseline code.
  DECL_ACCESSORS(source_position_table, Tagged<ByteArray>)
  // [bytecode_offset_table]: ByteArray for the bytecode offset for baseline
  // code.
  DECL_ACCESSORS(bytecode_offset_table, Tagged<ByteArray>)
  DECL_PRIMITIVE_ACCESSORS(inlined_bytecode_size, unsigned)
  DECL_PRIMITIVE_ACCESSORS(osr_offset, BytecodeOffset)
  // [code_comments_offset]: Offset of the code comment section.
  DECL_PRIMITIVE_ACCESSORS(code_comments_offset, int)
  // [constant_pool offset]: Offset of the constant pool.
  DECL_PRIMITIVE_ACCESSORS(constant_pool_offset, int)

  // Unchecked accessors to be used during GC.
  inline Tagged<FixedArray> unchecked_deoptimization_data() const;

  DECL_RELAXED_UINT32_ACCESSORS(flags)

  inline CodeKind kind() const;

  inline void set_builtin_id(Builtin builtin_id);
  inline Builtin builtin_id() const;
  inline bool is_builtin() const;

  inline bool is_optimized_code() const;
  inline bool is_wasm_code() const;

  inline bool is_interpreter_trampoline_builtin() const;
  inline bool is_baseline_trampoline_builtin() const;
  inline bool is_baseline_leave_frame_builtin() const;

  // Tells whether the code checks the tiering state in the function's feedback
  // vector.
  inline bool checks_tiering_state() const;

  // Tells whether the outgoing parameters of this code are tagged pointers.
  inline bool has_tagged_outgoing_params() const;

  // [is_maglevved]: Tells whether the code object was generated by the
  // Maglev optimizing compiler.
  inline bool is_maglevved() const;

  // [is_turbofanned]: Tells whether the code object was generated by the
  // TurboFan optimizing compiler.
  inline bool is_turbofanned() const;

  // [uses_safepoint_table]: Whether this InstructionStream object uses
  // safepoint tables (note the table may still be empty, see
  // has_safepoint_table).
  inline bool uses_safepoint_table() const;

  // [stack_slots]: If {uses_safepoint_table()}, the number of stack slots
  // reserved in the code prologue; otherwise 0.
  inline int stack_slots() const;

  inline Tagged<ByteArray> SourcePositionTable(
      Isolate* isolate, Tagged<SharedFunctionInfo> sfi) const;

  inline Address safepoint_table_address() const;
  inline int safepoint_table_size() const;
  inline bool has_safepoint_table() const;

  inline Address handler_table_address() const;
  inline int handler_table_size() const;
  inline bool has_handler_table() const;

  inline Address constant_pool() const;
  // An accessor to be used during GC if the instruction_stream moved and the
  // field was not updated yet.
  inline Address constant_pool(
      Tagged<InstructionStream> instruction_stream) const;
  inline int constant_pool_size() const;
  inline bool has_constant_pool() const;

  inline Address code_comments() const;
  inline int code_comments_size() const;
  inline bool has_code_comments() const;

  inline Address unwinding_info_start() const;
  inline Address unwinding_info_end() const;
  inline int unwinding_info_size() const;
  inline bool has_unwinding_info() const;

  inline uint8_t* relocation_start() const;
  inline uint8_t* relocation_end() const;
  inline int relocation_size() const;

  inline int safepoint_table_offset() const { return 0; }

  inline Address body_start() const;
  inline Address body_end() const;
  inline int body_size() const;

  inline Address metadata_start() const;
  inline Address metadata_end() const;

  // The size of the associated InstructionStream object, if it exists.
  inline int InstructionStreamObjectSize() const;

  // TODO(jgruber): This function tries to account for various parts of the
  // object graph, but is incomplete. Take it as a lower bound for the memory
  // associated with this Code object.
  inline int SizeIncludingMetadata() const;

  // The following functions include support for short builtin calls:
  //
  // When builtins un-embedding is enabled for the Isolate
  // (see Isolate::is_short_builtin_calls_enabled()) then both embedded and
  // un-embedded builtins might be exeuted and thus two kinds of |pc|s might
  // appear on the stack.
  // Unlike the paremeterless versions of the functions above the below variants
  // ensure that the instruction start correspond to the given |pc| value.
  // Thus for off-heap trampoline InstructionStream objects the result might be
  // the instruction start/end of the embedded code stream or of un-embedded
  // one. For normal InstructionStream objects these functions just return the
  // instruction_start/end() values.
  // TODO(11527): remove these versions once the full solution is ready.
  inline Address InstructionStart(Isolate* isolate, Address pc) const;
  inline Address InstructionEnd(Isolate* isolate, Address pc) const;
  inline bool contains(Isolate* isolate, Address pc) const;
  inline int GetOffsetFromInstructionStart(Isolate* isolate, Address pc) const;
  // Support for short builtin calls END.

  SafepointEntry GetSafepointEntry(Isolate* isolate, Address pc);
  MaglevSafepointEntry GetMaglevSafepointEntry(Isolate* isolate, Address pc);

  void SetMarkedForDeoptimization(Isolate* isolate, const char* reason);

  inline bool CanContainWeakObjects();
  inline bool IsWeakObject(Tagged<HeapObject> object);
  static inline bool IsWeakObjectInOptimizedCode(Tagged<HeapObject> object);
  static inline bool IsWeakObjectInDeoptimizationLiteralArray(
      Tagged<Object> object);

  // This function should be called only from GC.
  void ClearEmbeddedObjects(Heap* heap);

  // [embedded_objects_cleared]: If CodeKindIsOptimizedJSFunction(kind), tells
  // whether the embedded objects in the code marked for deoptimization were
  // cleared. Note that embedded_objects_cleared() implies
  // marked_for_deoptimization().
  inline bool embedded_objects_cleared() const;
  inline void set_embedded_objects_cleared(bool flag);

  bool IsIsolateIndependent(Isolate* isolate);

  inline uintptr_t GetBaselineStartPCForBytecodeOffset(
      int bytecode_offset, Tagged<BytecodeArray> bytecodes);

  inline uintptr_t GetBaselineEndPCForBytecodeOffset(
      int bytecode_offset, Tagged<BytecodeArray> bytecodes);

  // Returns true if the function is inlined in the code.
  bool Inlines(Tagged<SharedFunctionInfo> sfi);

  // Returns the PC of the next bytecode in execution order.
  // If the bytecode at the given offset is JumpLoop, the PC of the jump target
  // is returned. Other jumps are not allowed.
  // For other bytecodes this is equivalent to
  // GetBaselineEndPCForBytecodeOffset.
  inline uintptr_t GetBaselinePCForNextExecutedBytecode(
      int bytecode_offset, Tagged<BytecodeArray> bytecodes);

  inline int GetBytecodeOffsetForBaselinePC(Address baseline_pc,
                                            Tagged<BytecodeArray> bytecodes);

  inline void IterateDeoptimizationLiterals(RootVisitor* v);

  static inline Tagged<Code> FromTargetAddress(Address address);

#ifdef ENABLE_DISASSEMBLER
  V8_EXPORT_PRIVATE void Disassemble(const char* name, std::ostream& os,
                                     Isolate* isolate,
                                     Address current_pc = kNullAddress);
  V8_EXPORT_PRIVATE void DisassembleOnlyCode(const char* name, std::ostream& os,
                                             Isolate* isolate,
                                             Address current_pc,
                                             size_t range_limit);
#endif  // ENABLE_DISASSEMBLER

#ifdef OBJECT_PRINT
  void CodePrint(std::ostream& os, const char* name = nullptr,
                 Address current_pc = kNullAddress);
#endif

  DECL_CAST(Code)
  DECL_VERIFIER(Code)

// Layout description.
#define CODE_DATA_FIELDS(V)                                                   \
  /* Strong pointer fields. */                                                \
  V(kStartOfStrongFieldsOffset, 0)                                            \
  V(kDeoptimizationDataOrInterpreterDataOffset, kTaggedSize)                  \
  V(kPositionTableOffset, kTaggedSize)                                        \
  V(kEndOfStrongFieldsWithMainCageBaseOffset, 0)                              \
  /* The InstructionStream field is special: it uses code_cage_base. */       \
  V(kInstructionStreamOffset, kTaggedSize)                                    \
  V(kEndOfStrongFieldsOffset, 0)                                              \
  /* Untagged data not directly visited by GC starts here. */                 \
  /* When the sandbox is off, the instruction_start field contains a raw */   \
  /* pointer to the first instruction of this Code. */                        \
  /* If the sandbox is on, this field instead contains the handle for the */  \
  /* code pointer table entry of this Code object. The instruction start */   \
  /* value is then stored in that entry. */                                   \
  V(kInstructionStartOffset,                                                  \
    V8_CODE_POINTER_SANDBOXING_BOOL ? 0 : kSystemPointerSize)                 \
  V(kCodePointerTableEntryOffset,                                             \
    V8_CODE_POINTER_SANDBOXING_BOOL ? kIndirectPointerSlotSize : 0)           \
  /* The serializer needs to copy bytes starting from here verbatim. */       \
  V(kFlagsOffset, kUInt32Size)                                                \
  V(kInstructionSizeOffset, kIntSize)                                         \
  V(kMetadataSizeOffset, kIntSize)                                            \
  /* TODO(jgruber): TF-specific fields could be merged with builtin_id. */    \
  V(kInlinedBytecodeSizeOffset, kIntSize)                                     \
  V(kOsrOffsetOffset, kInt32Size)                                             \
  V(kHandlerTableOffsetOffset, kIntSize)                                      \
  V(kUnwindingInfoOffsetOffset, kInt32Size)                                   \
  V(kConstantPoolOffsetOffset, V8_EMBEDDED_CONSTANT_POOL_BOOL ? kIntSize : 0) \
  V(kCodeCommentsOffsetOffset, kIntSize)                                      \
  /* TODO(jgruber): 12 bits would suffice, steal from here if needed. */      \
  V(kBuiltinIdOffset, kInt16Size)                                             \
  V(kUnalignedSize, OBJECT_POINTER_PADDING(kUnalignedSize))                   \
  /* Total size. */                                                           \
  V(kSize, 0)

  DEFINE_FIELD_OFFSET_CONSTANTS(HeapObject::kHeaderSize, CODE_DATA_FIELDS)
#undef CODE_DATA_FIELDS

#ifdef V8_EXTERNAL_CODE_SPACE
  template <typename T>
  using ExternalCodeField =
      TaggedField<T, kInstructionStreamOffset, ExternalCodeCompressionScheme>;
#else
  template <typename T>
  using ExternalCodeField = TaggedField<T, kInstructionStreamOffset>;
#endif  // V8_EXTERNAL_CODE_SPACE

  class BodyDescriptor;

  // Flags layout.
#define FLAGS_BIT_FIELDS(V, _)                \
  V(KindField, CodeKind, 4, _)                \
  V(IsTurbofannedField, bool, 1, _)           \
  /* Steal bits from here if needed: */       \
  V(StackSlotsField, int, 24, _)              \
  V(MarkedForDeoptimizationField, bool, 1, _) \
  V(EmbeddedObjectsClearedField, bool, 1, _)  \
  V(CanHaveWeakObjectsField, bool, 1, _)
  DEFINE_BIT_FIELDS(FLAGS_BIT_FIELDS)
#undef FLAGS_BIT_FIELDS
  static_assert(FLAGS_BIT_FIELDS_Ranges::kBitsCount == 32);
  static_assert(FLAGS_BIT_FIELDS_Ranges::kBitsCount <=
                FIELD_SIZE(kFlagsOffset) * kBitsPerByte);
  static_assert(kCodeKindCount <= KindField::kNumValues);

  // The {marked_for_deoptimization} field is accessed from generated code.
  static const int kMarkedForDeoptimizationBit =
      MarkedForDeoptimizationField::kShift;
  static const int kIsTurbofannedBit = IsTurbofannedField::kShift;

  // Reserve one argument count value as the "don't adapt arguments" sentinel.
  static const int kArgumentsBits = 16;
  // Slightly less than 2^kArgumentBits-1 to allow for extra implicit arguments
  // on the call nodes without overflowing the uint16_t input_count.
  static const int kMaxArguments = (1 << kArgumentsBits) - 10;

 private:
  inline void set_instruction_start(Isolate* isolate, Address value);

  // TODO(jgruber): These field names are incomplete, we've squashed in more
  // overloaded contents in the meantime. Update the field names.
  Tagged<HeapObject> raw_deoptimization_data_or_interpreter_data() const;
  Tagged<ByteArray> raw_position_table() const;

  enum BytecodeToPCPosition {
    kPcAtStartOfBytecode,
    // End of bytecode equals the start of the next bytecode.
    // We need it when we deoptimize to the next bytecode (lazy deopt or deopt
    // of non-topmost frame).
    kPcAtEndOfBytecode
  };
  inline uintptr_t GetBaselinePCForBytecodeOffset(
      int bytecode_offset, BytecodeToPCPosition position,
      Tagged<BytecodeArray> bytecodes);

  template <typename IsolateT>
  friend class Deserializer;
  friend Factory;
  friend FactoryBase<Factory>;
  friend FactoryBase<LocalFactory>;

  OBJECT_CONSTRUCTORS(Code, HeapObject);
};

// A Code object when used in situations where gc might be in progress. The
// underlying pointer is guaranteed to be a Code object.
//
// Semantics around Code and InstructionStream objects are quite delicate when
// GC is in progress and objects are currently being moved, because the
// tightly-coupled object pair {Code,InstructionStream} are conceptually
// treated as a single object in our codebase, and we frequently convert
// between the two. However, during GC, extra care must be taken when accessing
// the `Code::instruction_stream` and `InstructionStream::code` slots because
// they may contain forwarding pointers.
//
// This class a) clarifies at use sites that we're dealing with a Code object
// in a situation that requires special semantics, and b) safely implements
// related functions.
//
// Note that both the underlying Code object and the associated
// InstructionStream may be forwarding pointers, thus type checks and normal
// (checked) casts do not work on GcSafeCode.
class GcSafeCode : public HeapObject {
 public:
  DECL_CAST(GcSafeCode)

  // Use with care, this casts away knowledge that we're dealing with a
  // special-semantics object.
  inline Tagged<Code> UnsafeCastToCode() const;

  // Safe accessors (these just forward to Code methods).
  inline Address instruction_start() const;
  inline Address instruction_end() const;
  inline bool is_builtin() const;
  inline Builtin builtin_id() const;
  inline CodeKind kind() const;
  inline bool is_interpreter_trampoline_builtin() const;
  inline bool is_baseline_trampoline_builtin() const;
  inline bool is_baseline_leave_frame_builtin() const;
  inline bool has_instruction_stream() const;
  inline bool is_maglevved() const;
  inline bool is_turbofanned() const;
  inline bool has_tagged_outgoing_params() const;
  inline bool marked_for_deoptimization() const;
  inline Tagged<Object> raw_instruction_stream() const;
  inline Address constant_pool() const;
  inline Address constant_pool(Tagged<InstructionStream> istream) const;
  inline Address safepoint_table_address() const;
  inline int stack_slots() const;

  inline int GetOffsetFromInstructionStart(Isolate* isolate, Address pc) const;
  inline Address InstructionStart(Isolate* isolate, Address pc) const;
  inline Address InstructionEnd(Isolate* isolate, Address pc) const;
  inline bool CanDeoptAt(Isolate* isolate, Address pc) const;
  inline Tagged<Object> raw_instruction_stream(
      PtrComprCageBase code_cage_base) const;

 private:
  OBJECT_CONSTRUCTORS(GcSafeCode, HeapObject);
};

}  // namespace internal
}  // namespace v8

#include "src/objects/object-macros-undef.h"

#endif  // V8_OBJECTS_CODE_H_