blob: c43e07c1f923aeada7e4e952e89d9889489cd473 [file] [log] [blame]
// 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/objects.h"
#include "src/objects/fixed-array.h"
// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"
namespace v8 {
namespace internal {
class ByteArray;
class BytecodeArray;
class CodeDataContainer;
// HandlerTable is a fixed array containing entries for exception handlers in
// the code object it is associated with. The tables comes in two flavors:
// 1) Based on ranges: Used for unoptimized code. Contains one entry per
// exception handler and a range representing the try-block covered by that
// handler. Layout looks as follows:
// [ range-start , range-end , handler-offset , handler-data ]
// 2) Based on return addresses: Used for turbofanned code. Contains one entry
// per call-site that could throw an exception. Layout looks as follows:
// [ return-address-offset , handler-offset ]
class HandlerTable : public FixedArray {
public:
// Conservative prediction whether a given handler will locally catch an
// exception or cause a re-throw to outside the code boundary. Since this is
// undecidable it is merely an approximation (e.g. useful for debugger).
enum CatchPrediction {
UNCAUGHT, // The handler will (likely) rethrow the exception.
CAUGHT, // The exception will be caught by the handler.
PROMISE, // The exception will be caught and cause a promise rejection.
DESUGARING, // The exception will be caught, but both the exception and the
// catching are part of a desugaring and should therefore not
// be visible to the user (we won't notify the debugger of such
// exceptions).
ASYNC_AWAIT, // The exception will be caught and cause a promise rejection
// in the desugaring of an async function, so special
// async/await handling in the debugger can take place.
};
// Getters for handler table based on ranges.
inline int GetRangeStart(int index) const;
inline int GetRangeEnd(int index) const;
inline int GetRangeHandler(int index) const;
inline int GetRangeData(int index) const;
// Setters for handler table based on ranges.
inline void SetRangeStart(int index, int value);
inline void SetRangeEnd(int index, int value);
inline void SetRangeHandler(int index, int offset, CatchPrediction pred);
inline void SetRangeData(int index, int value);
// Setters for handler table based on return addresses.
inline void SetReturnOffset(int index, int value);
inline void SetReturnHandler(int index, int offset);
// Lookup handler in a table based on ranges. The {pc_offset} is an offset to
// the start of the potentially throwing instruction (using return addresses
// for this value would be invalid).
int LookupRange(int pc_offset, int* data, CatchPrediction* prediction);
// Lookup handler in a table based on return addresses.
int LookupReturn(int pc_offset);
// Returns the number of entries in the table.
inline int NumberOfRangeEntries() const;
// Returns the required length of the underlying fixed array.
static int LengthForRange(int entries) { return entries * kRangeEntrySize; }
static int LengthForReturn(int entries) { return entries * kReturnEntrySize; }
// Returns an empty handler table.
static Handle<HandlerTable> Empty(Isolate* isolate);
DECL_CAST(HandlerTable)
#ifdef ENABLE_DISASSEMBLER
void HandlerTableRangePrint(std::ostream& os); // NOLINT
void HandlerTableReturnPrint(std::ostream& os); // NOLINT
#endif
private:
// Layout description for handler table based on ranges.
static const int kRangeStartIndex = 0;
static const int kRangeEndIndex = 1;
static const int kRangeHandlerIndex = 2;
static const int kRangeDataIndex = 3;
static const int kRangeEntrySize = 4;
// Layout description for handler table based on return addresses.
static const int kReturnOffsetIndex = 0;
static const int kReturnHandlerIndex = 1;
static const int kReturnEntrySize = 2;
// Encoding of the {handler} field.
class HandlerPredictionField : public BitField<CatchPrediction, 0, 3> {};
class HandlerOffsetField : public BitField<int, 3, 29> {};
};
// Code describes objects with on-the-fly generated machine code.
class Code : public HeapObject {
public:
// Opaque data type for encapsulating code flags like kind, inline
// cache state, and arguments count.
typedef uint32_t Flags;
#define CODE_KIND_LIST(V) \
V(OPTIMIZED_FUNCTION) \
V(BYTECODE_HANDLER) \
V(STUB) \
V(BUILTIN) \
V(REGEXP) \
V(WASM_FUNCTION) \
V(WASM_TO_JS_FUNCTION) \
V(WASM_TO_WASM_FUNCTION) \
V(JS_TO_WASM_FUNCTION) \
V(WASM_INTERPRETER_ENTRY) \
V(C_WASM_ENTRY)
enum Kind {
#define DEFINE_CODE_KIND_ENUM(name) name,
CODE_KIND_LIST(DEFINE_CODE_KIND_ENUM)
#undef DEFINE_CODE_KIND_ENUM
NUMBER_OF_KINDS
};
static const char* Kind2String(Kind kind);
#if defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER)
// Printing
static const char* ICState2String(InlineCacheState state);
#endif // defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER)
#ifdef ENABLE_DISASSEMBLER
void Disassemble(const char* name, std::ostream& os,
void* current_pc = nullptr); // NOLINT
#endif
// [instruction_size]: Size of the native instructions
inline int instruction_size() const;
inline void set_instruction_size(int value);
// [relocation_info]: Code relocation information
DECL_ACCESSORS(relocation_info, ByteArray)
void InvalidateEmbeddedObjects();
// [handler_table]: Fixed array containing offsets of exception handlers.
DECL_ACCESSORS(handler_table, FixedArray)
// [deoptimization_data]: Array containing data for deopt.
DECL_ACCESSORS(deoptimization_data, FixedArray)
// [source_position_table]: ByteArray for the source positions table or
// SourcePositionTableWithFrameCache.
DECL_ACCESSORS(source_position_table, Object)
inline ByteArray* SourcePositionTable() const;
// TODO(mtrofin): remove when we don't need FLAG_wasm_jit_to_native
// [protected instructions]: Array containing list of protected
// instructions and corresponding landing pad offset.
DECL_ACCESSORS(protected_instructions, FixedArray)
// [code_data_container]: A container indirection for all mutable fields.
DECL_ACCESSORS(code_data_container, CodeDataContainer)
// [trap_handler_index]: An index into the trap handler's master list of code
// objects.
DECL_ACCESSORS(trap_handler_index, Smi)
// [stub_key]: The major/minor key of a code stub.
inline uint32_t stub_key() const;
inline void set_stub_key(uint32_t key);
// [next_code_link]: Link for lists of optimized or deoptimized code.
// Note that this field is stored in the {CodeDataContainer} to be mutable.
inline Object* next_code_link() const;
inline void set_next_code_link(Object* value);
// [constant_pool offset]: Offset of the constant pool.
// Valid for FLAG_enable_embedded_constant_pool only
inline int constant_pool_offset() const;
inline void set_constant_pool_offset(int offset);
// Unchecked accessors to be used during GC.
inline ByteArray* unchecked_relocation_info() const;
inline int relocation_size() const;
// [kind]: Access to specific code kind.
inline Kind kind() const;
inline bool is_stub() const;
inline bool is_optimized_code() const;
inline bool is_wasm_code() const;
// Testers for interpreter builtins.
inline bool is_interpreter_trampoline_builtin() const;
// Tells whether the code checks the optimization marker in the function's
// feedback vector.
inline bool checks_optimization_marker() const;
// [has_tagged_params]: For compiled code or builtins: Tells whether the
// outgoing parameters of this code are tagged pointers. True for other kinds.
inline bool has_tagged_params() const;
inline void set_has_tagged_params(bool value);
// [is_turbofanned]: For kind STUB or OPTIMIZED_FUNCTION, tells whether the
// code object was generated by the TurboFan optimizing compiler.
inline bool is_turbofanned() const;
// [can_have_weak_objects]: For kind OPTIMIZED_FUNCTION, tells whether the
// embedded objects in code should be treated weakly.
inline bool can_have_weak_objects() const;
inline void set_can_have_weak_objects(bool value);
// [is_construct_stub]: For kind BUILTIN, tells whether the code object
// represents a hand-written construct stub
// (e.g., NumberConstructor_ConstructStub).
inline bool is_construct_stub() const;
inline void set_is_construct_stub(bool value);
// [builtin_index]: For builtins, tells which builtin index the code object
// has. The builtin index is a non-negative integer for builtins, and -1
// otherwise.
inline int builtin_index() const;
inline void set_builtin_index(int id);
inline bool is_builtin() const;
inline bool has_safepoint_info() const;
// [stack_slots]: If {has_safepoint_info()}, the number of stack slots
// reserved in the code prologue.
inline int stack_slots() const;
// [safepoint_table_offset]: If {has_safepoint_info()}, the offset in the
// instruction stream where the safepoint table starts.
inline int safepoint_table_offset() const;
inline void set_safepoint_table_offset(int offset);
// [marked_for_deoptimization]: For kind OPTIMIZED_FUNCTION tells whether
// the code is going to be deoptimized because of dead embedded maps.
inline bool marked_for_deoptimization() const;
inline void set_marked_for_deoptimization(bool flag);
// [deopt_already_counted]: For kind OPTIMIZED_FUNCTION tells whether
// the code was already deoptimized.
inline bool deopt_already_counted() const;
inline void set_deopt_already_counted(bool flag);
// [is_promise_rejection]: For kind BUILTIN tells whether the
// exception thrown by the code will lead to promise rejection or
// uncaught if both this and is_exception_caught is set.
// Use GetBuiltinCatchPrediction to access this.
inline void set_is_promise_rejection(bool flag);
// [is_exception_caught]: For kind BUILTIN tells whether the
// exception thrown by the code will be caught internally or
// uncaught if both this and is_promise_rejection is set.
// Use GetBuiltinCatchPrediction to access this.
inline void set_is_exception_caught(bool flag);
// [constant_pool]: The constant pool for this function.
inline Address constant_pool();
// Get the safepoint entry for the given pc.
SafepointEntry GetSafepointEntry(Address pc);
// The entire code object including its header is copied verbatim to the
// snapshot so that it can be written in one, fast, memcpy during
// deserialization. The deserializer will overwrite some pointers, rather
// like a runtime linker, but the random allocation addresses used in the
// mksnapshot process would still be present in the unlinked snapshot data,
// which would make snapshot production non-reproducible. This method wipes
// out the to-be-overwritten header data for reproducible snapshots.
inline void WipeOutHeader();
// Clear uninitialized padding space. This ensures that the snapshot content
// is deterministic.
inline void clear_padding();
// Initialize the flags field. Similar to clear_padding above this ensure that
// the snapshot content is deterministic.
inline void initialize_flags(Kind kind, bool has_unwinding_info,
bool is_turbofanned, int stack_slots);
// Convert a target address into a code object.
static inline Code* GetCodeFromTargetAddress(Address address);
// Convert an entry address into an object.
static inline Object* GetObjectFromEntryAddress(Address location_of_address);
// Convert a code entry into an object.
static inline Object* GetObjectFromCodeEntry(Address code_entry);
// Returns the address of the first instruction.
inline byte* instruction_start() const;
// Returns the address right after the last instruction.
inline byte* instruction_end() const;
// Returns the size of the instructions, padding, relocation and unwinding
// information.
inline int body_size() const;
// Returns the size of code and its metadata. This includes the size of code
// relocation information, deoptimization data and handler table.
inline int SizeIncludingMetadata() const;
// Returns the address of the first relocation info (read backwards!).
inline byte* relocation_start() const;
// [has_unwinding_info]: Whether this code object has unwinding information.
// If it doesn't, unwinding_information_start() will point to invalid data.
//
// The body of all code objects has the following layout.
//
// +--------------------------+ <-- instruction_start()
// | instructions |
// | ... |
// +--------------------------+
// | relocation info |
// | ... |
// +--------------------------+ <-- instruction_end()
//
// If has_unwinding_info() is false, instruction_end() points to the first
// memory location after the end of the code object. Otherwise, the body
// continues as follows:
//
// +--------------------------+
// | padding to the next |
// | 8-byte aligned address |
// +--------------------------+ <-- instruction_end()
// | [unwinding_info_size] |
// | as uint64_t |
// +--------------------------+ <-- unwinding_info_start()
// | unwinding info |
// | ... |
// +--------------------------+ <-- unwinding_info_end()
//
// and unwinding_info_end() points to the first memory location after the end
// of the code object.
//
inline bool has_unwinding_info() const;
// [unwinding_info_size]: Size of the unwinding information.
inline int unwinding_info_size() const;
inline void set_unwinding_info_size(int value);
// Returns the address of the unwinding information, if any.
inline byte* unwinding_info_start() const;
// Returns the address right after the end of the unwinding information.
inline byte* unwinding_info_end() const;
// Code entry point.
inline byte* entry() const;
// Returns true if pc is inside this object's instructions.
inline bool contains(byte* pc);
// Relocate the code by delta bytes. Called to signal that this code
// object has been moved by delta bytes.
void Relocate(intptr_t delta);
// Migrate code described by desc.
void CopyFrom(const CodeDesc& desc);
// Returns the object size for a given body (used for allocation).
static int SizeFor(int body_size) {
DCHECK_SIZE_TAG_ALIGNED(body_size);
return RoundUp(kHeaderSize + body_size, kCodeAlignment);
}
// Calculate the size of the code object to report for log events. This takes
// the layout of the code object into account.
inline int ExecutableSize() const;
DECL_CAST(Code)
// Dispatched behavior.
inline int CodeSize() const;
DECL_PRINTER(Code)
DECL_VERIFIER(Code)
void PrintDeoptLocation(FILE* out, const char* str, Address pc);
bool CanDeoptAt(Address pc);
inline HandlerTable::CatchPrediction GetBuiltinCatchPrediction();
#ifdef VERIFY_HEAP
void VerifyEmbeddedObjectsDependency();
#endif
#ifdef DEBUG
enum VerifyMode { kNoContextSpecificPointers, kNoContextRetainingPointers };
void VerifyEmbeddedObjects(VerifyMode mode = kNoContextRetainingPointers);
#endif // DEBUG
inline bool CanContainWeakObjects();
inline bool IsWeakObject(Object* object);
static inline bool IsWeakObjectInOptimizedCode(Object* object);
static Handle<WeakCell> WeakCellFor(Handle<Code> code);
WeakCell* CachedWeakCell();
// Return true if the function is inlined in the code.
bool Inlines(SharedFunctionInfo* sfi);
class OptimizedCodeIterator {
public:
explicit OptimizedCodeIterator(Isolate* isolate);
Code* Next();
private:
Context* next_context_;
Code* current_code_;
Isolate* isolate_;
DisallowHeapAllocation no_gc;
DISALLOW_COPY_AND_ASSIGN(OptimizedCodeIterator)
};
static const int kConstantPoolSize =
FLAG_enable_embedded_constant_pool ? kIntSize : 0;
// Layout description.
static const int kRelocationInfoOffset = HeapObject::kHeaderSize;
static const int kHandlerTableOffset = kRelocationInfoOffset + kPointerSize;
static const int kDeoptimizationDataOffset =
kHandlerTableOffset + kPointerSize;
static const int kSourcePositionTableOffset =
kDeoptimizationDataOffset + kPointerSize;
static const int kProtectedInstructionsOffset =
kSourcePositionTableOffset + kPointerSize;
static const int kCodeDataContainerOffset =
kProtectedInstructionsOffset + kPointerSize;
static const int kInstructionSizeOffset =
kCodeDataContainerOffset + kPointerSize;
static const int kFlagsOffset = kInstructionSizeOffset + kIntSize;
static const int kSafepointTableOffsetOffset = kFlagsOffset + kIntSize;
static const int kStubKeyOffset = kSafepointTableOffsetOffset + kIntSize;
static const int kConstantPoolOffset = kStubKeyOffset + kIntSize;
static const int kBuiltinIndexOffset =
kConstantPoolOffset + kConstantPoolSize;
static const int kTrapHandlerIndex = kBuiltinIndexOffset + kIntSize;
static const int kHeaderPaddingStart = kTrapHandlerIndex + kPointerSize;
// Add padding to align the instruction start following right after
// the Code object header.
static const int kHeaderSize =
(kHeaderPaddingStart + kCodeAlignmentMask) & ~kCodeAlignmentMask;
// Data or code not directly visited by GC directly starts here.
// The serializer needs to copy bytes starting from here verbatim.
// Objects embedded into code is visited via reloc info.
static const int kDataStart = kInstructionSizeOffset;
enum TrapFields { kTrapCodeOffset, kTrapLandingOffset, kTrapDataSize };
inline int GetUnwindingInfoSizeOffset() const;
class BodyDescriptor;
// Flags layout. BitField<type, shift, size>.
#define CODE_FLAGS_BIT_FIELDS(V, _) \
V(HasUnwindingInfoField, bool, 1, _) \
V(KindField, Kind, 5, _) \
V(HasTaggedStackField, bool, 1, _) \
V(IsTurbofannedField, bool, 1, _) \
V(StackSlotsField, int, 24, _)
DEFINE_BIT_FIELDS(CODE_FLAGS_BIT_FIELDS)
#undef CODE_FLAGS_BIT_FIELDS
static_assert(NUMBER_OF_KINDS <= KindField::kMax, "Code::KindField size");
static_assert(StackSlotsField::kNext <= 32, "Code::flags field exhausted");
// KindSpecificFlags layout (STUB, BUILTIN and OPTIMIZED_FUNCTION)
#define CODE_KIND_SPECIFIC_FLAGS_BIT_FIELDS(V, _) \
V(MarkedForDeoptimizationField, bool, 1, _) \
V(DeoptAlreadyCountedField, bool, 1, _) \
V(CanHaveWeakObjectsField, bool, 1, _) \
V(IsConstructStubField, bool, 1, _) \
V(IsPromiseRejectionField, bool, 1, _) \
V(IsExceptionCaughtField, bool, 1, _)
DEFINE_BIT_FIELDS(CODE_KIND_SPECIFIC_FLAGS_BIT_FIELDS)
#undef CODE_KIND_SPECIFIC_FLAGS_BIT_FIELDS
static_assert(IsExceptionCaughtField::kNext <= 32, "KindSpecificFlags full");
// The {marked_for_deoptimization} field is accessed from generated code.
static const int kMarkedForDeoptimizationBit =
MarkedForDeoptimizationField::kShift;
static const int kArgumentsBits = 16;
static const int kMaxArguments = (1 << kArgumentsBits) - 1;
private:
friend class RelocIterator;
bool is_promise_rejection() const;
bool is_exception_caught() const;
DISALLOW_IMPLICIT_CONSTRUCTORS(Code);
};
// CodeDataContainer is a container for all mutable fields associated with its
// referencing {Code} object. Since {Code} objects reside on write-protected
// pages within the heap, its header fields need to be immutable. There always
// is a 1-to-1 relation between {Code} and {CodeDataContainer}, the referencing
// field {Code::code_data_container} itself is immutable.
class CodeDataContainer : public HeapObject {
public:
DECL_ACCESSORS(next_code_link, Object)
DECL_INT_ACCESSORS(kind_specific_flags)
// Clear uninitialized padding space. This ensures that the snapshot content
// is deterministic.
inline void clear_padding();
DECL_CAST(CodeDataContainer)
// Dispatched behavior.
DECL_PRINTER(CodeDataContainer)
DECL_VERIFIER(CodeDataContainer)
static const int kNextCodeLinkOffset = HeapObject::kHeaderSize;
static const int kKindSpecificFlagsOffset =
kNextCodeLinkOffset + kPointerSize;
static const int kUnalignedSize = kKindSpecificFlagsOffset + kIntSize;
static const int kSize = OBJECT_POINTER_ALIGN(kUnalignedSize);
// During mark compact we need to take special care for weak fields.
static const int kPointerFieldsStrongEndOffset = kNextCodeLinkOffset;
static const int kPointerFieldsWeakEndOffset = kKindSpecificFlagsOffset;
// Ignores weakness.
typedef FixedBodyDescriptor<HeapObject::kHeaderSize,
kPointerFieldsWeakEndOffset, kSize>
BodyDescriptor;
// Respects weakness.
typedef FixedBodyDescriptor<HeapObject::kHeaderSize,
kPointerFieldsStrongEndOffset, kSize>
BodyDescriptorWeak;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(CodeDataContainer);
};
class AbstractCode : public HeapObject {
public:
// All code kinds and INTERPRETED_FUNCTION.
enum Kind {
#define DEFINE_CODE_KIND_ENUM(name) name,
CODE_KIND_LIST(DEFINE_CODE_KIND_ENUM)
#undef DEFINE_CODE_KIND_ENUM
INTERPRETED_FUNCTION,
NUMBER_OF_KINDS
};
static const char* Kind2String(Kind kind);
int SourcePosition(int offset);
int SourceStatementPosition(int offset);
// Returns the address of the first instruction.
inline Address instruction_start();
// Returns the address right after the last instruction.
inline Address instruction_end();
// Returns the size of the code instructions.
inline int instruction_size();
// Return the source position table.
inline ByteArray* source_position_table();
inline Object* stack_frame_cache();
static void SetStackFrameCache(Handle<AbstractCode> abstract_code,
Handle<NumberDictionary> cache);
void DropStackFrameCache();
// Returns the size of instructions and the metadata.
inline int SizeIncludingMetadata();
// Returns true if pc is inside this object's instructions.
inline bool contains(byte* pc);
// Returns the AbstractCode::Kind of the code.
inline Kind kind();
// Calculate the size of the code object to report for log events. This takes
// the layout of the code object into account.
inline int ExecutableSize();
DECL_CAST(AbstractCode)
inline Code* GetCode();
inline BytecodeArray* GetBytecodeArray();
// Max loop nesting marker used to postpose OSR. We don't take loop
// nesting that is deeper than 5 levels into account.
static const int kMaxLoopNestingMarker = 6;
};
// Dependent code is a singly linked list of fixed arrays. Each array contains
// code objects in weak cells for one dependent group. The suffix of the array
// can be filled with the undefined value if the number of codes is less than
// the length of the array.
//
// +------+-----------------+--------+--------+-----+--------+-----------+-----+
// | next | count & group 1 | code 1 | code 2 | ... | code n | undefined | ... |
// +------+-----------------+--------+--------+-----+--------+-----------+-----+
// |
// V
// +------+-----------------+--------+--------+-----+--------+-----------+-----+
// | next | count & group 2 | code 1 | code 2 | ... | code m | undefined | ... |
// +------+-----------------+--------+--------+-----+--------+-----------+-----+
// |
// V
// empty_fixed_array()
//
// The list of fixed arrays is ordered by dependency groups.
class DependentCode : public FixedArray {
public:
enum DependencyGroup {
// Group of code that weakly embed this map and depend on being
// deoptimized when the map is garbage collected.
kWeakCodeGroup,
// Group of code that embed a transition to this map, and depend on being
// deoptimized when the transition is replaced by a new version.
kTransitionGroup,
// Group of code that omit run-time prototype checks for prototypes
// described by this map. The group is deoptimized whenever an object
// described by this map changes shape (and transitions to a new map),
// possibly invalidating the assumptions embedded in the code.
kPrototypeCheckGroup,
// Group of code that depends on global property values in property cells
// not being changed.
kPropertyCellChangedGroup,
// Group of code that omit run-time checks for field(s) introduced by
// this map, i.e. for the field type.
kFieldOwnerGroup,
// Group of code that omit run-time type checks for initial maps of
// constructors.
kInitialMapChangedGroup,
// Group of code that depends on tenuring information in AllocationSites
// not being changed.
kAllocationSiteTenuringChangedGroup,
// Group of code that depends on element transition information in
// AllocationSites not being changed.
kAllocationSiteTransitionChangedGroup
};
static const int kGroupCount = kAllocationSiteTransitionChangedGroup + 1;
static const int kNextLinkIndex = 0;
static const int kFlagsIndex = 1;
static const int kCodesStartIndex = 2;
bool Contains(DependencyGroup group, WeakCell* code_cell);
bool IsEmpty(DependencyGroup group);
static Handle<DependentCode> InsertCompilationDependencies(
Handle<DependentCode> entries, DependencyGroup group,
Handle<Foreign> info);
static Handle<DependentCode> InsertWeakCode(Handle<DependentCode> entries,
DependencyGroup group,
Handle<WeakCell> code_cell);
void UpdateToFinishedCode(DependencyGroup group, Foreign* info,
WeakCell* code_cell);
void RemoveCompilationDependencies(DependentCode::DependencyGroup group,
Foreign* info);
void DeoptimizeDependentCodeGroup(Isolate* isolate,
DependentCode::DependencyGroup group);
bool MarkCodeForDeoptimization(Isolate* isolate,
DependentCode::DependencyGroup group);
// The following low-level accessors should only be used by this class
// and the mark compact collector.
inline DependentCode* next_link();
inline void set_next_link(DependentCode* next);
inline int count();
inline void set_count(int value);
inline DependencyGroup group();
inline void set_group(DependencyGroup group);
inline Object* object_at(int i);
inline void set_object_at(int i, Object* object);
inline void clear_at(int i);
inline void copy(int from, int to);
DECL_CAST(DependentCode)
static const char* DependencyGroupName(DependencyGroup group);
static void SetMarkedForDeoptimization(Code* code, DependencyGroup group);
private:
static Handle<DependentCode> Insert(Handle<DependentCode> entries,
DependencyGroup group,
Handle<Object> object);
static Handle<DependentCode> New(DependencyGroup group, Handle<Object> object,
Handle<DependentCode> next);
static Handle<DependentCode> EnsureSpace(Handle<DependentCode> entries);
// Compact by removing cleared weak cells and return true if there was
// any cleared weak cell.
bool Compact();
static int Grow(int number_of_entries) {
if (number_of_entries < 5) return number_of_entries + 1;
return number_of_entries * 5 / 4;
}
inline int flags();
inline void set_flags(int flags);
class GroupField : public BitField<int, 0, 3> {};
class CountField : public BitField<int, 3, 27> {};
STATIC_ASSERT(kGroupCount <= GroupField::kMax + 1);
};
// BytecodeArray represents a sequence of interpreter bytecodes.
class BytecodeArray : public FixedArrayBase {
public:
enum Age {
kNoAgeBytecodeAge = 0,
kQuadragenarianBytecodeAge,
kQuinquagenarianBytecodeAge,
kSexagenarianBytecodeAge,
kSeptuagenarianBytecodeAge,
kOctogenarianBytecodeAge,
kAfterLastBytecodeAge,
kFirstBytecodeAge = kNoAgeBytecodeAge,
kLastBytecodeAge = kAfterLastBytecodeAge - 1,
kBytecodeAgeCount = kAfterLastBytecodeAge - kFirstBytecodeAge - 1,
kIsOldBytecodeAge = kSexagenarianBytecodeAge
};
static int SizeFor(int length) {
return OBJECT_POINTER_ALIGN(kHeaderSize + length);
}
// Setter and getter
inline byte get(int index);
inline void set(int index, byte value);
// Returns data start address.
inline Address GetFirstBytecodeAddress();
// Accessors for frame size.
inline int frame_size() const;
inline void set_frame_size(int frame_size);
// Accessor for register count (derived from frame_size).
inline int register_count() const;
// Accessors for parameter count (including implicit 'this' receiver).
inline int parameter_count() const;
inline void set_parameter_count(int number_of_parameters);
// Register used to pass the incoming new.target or generator object from the
// fucntion call.
inline interpreter::Register incoming_new_target_or_generator_register()
const;
inline void set_incoming_new_target_or_generator_register(
interpreter::Register incoming_new_target_or_generator_register);
// Accessors for profiling count.
inline int interrupt_budget() const;
inline void set_interrupt_budget(int interrupt_budget);
// Accessors for OSR loop nesting level.
inline int osr_loop_nesting_level() const;
inline void set_osr_loop_nesting_level(int depth);
// Accessors for bytecode's code age.
inline Age bytecode_age() const;
inline void set_bytecode_age(Age age);
// Accessors for the constant pool.
DECL_ACCESSORS(constant_pool, FixedArray)
// Accessors for handler table containing offsets of exception handlers.
DECL_ACCESSORS(handler_table, FixedArray)
// Accessors for source position table containing mappings between byte code
// offset and source position or SourcePositionTableWithFrameCache.
DECL_ACCESSORS(source_position_table, Object)
inline ByteArray* SourcePositionTable();
inline void ClearFrameCacheFromSourcePositionTable();
DECL_CAST(BytecodeArray)
// Dispatched behavior.
inline int BytecodeArraySize();
inline int instruction_size();
// Returns the size of bytecode and its metadata. This includes the size of
// bytecode, constant pool, source position table, and handler table.
inline int SizeIncludingMetadata();
int SourcePosition(int offset);
int SourceStatementPosition(int offset);
DECL_PRINTER(BytecodeArray)
DECL_VERIFIER(BytecodeArray)
void Disassemble(std::ostream& os);
void CopyBytecodesTo(BytecodeArray* to);
// Bytecode aging
bool IsOld() const;
void MakeOlder();
// Clear uninitialized padding space. This ensures that the snapshot content
// is deterministic.
inline void clear_padding();
// Layout description.
#define BYTECODE_ARRAY_FIELDS(V) \
/* Pointer fields. */ \
V(kConstantPoolOffset, kPointerSize) \
V(kHandlerTableOffset, kPointerSize) \
V(kSourcePositionTableOffset, kPointerSize) \
V(kFrameSizeOffset, kIntSize) \
V(kParameterSizeOffset, kIntSize) \
V(kIncomingNewTargetOrGeneratorRegisterOffset, kIntSize) \
V(kInterruptBudgetOffset, kIntSize) \
V(kOSRNestingLevelOffset, kCharSize) \
V(kBytecodeAgeOffset, kCharSize) \
/* Total size. */ \
V(kHeaderSize, 0)
DEFINE_FIELD_OFFSET_CONSTANTS(FixedArrayBase::kHeaderSize,
BYTECODE_ARRAY_FIELDS)
#undef BYTECODE_ARRAY_FIELDS
// Maximal memory consumption for a single BytecodeArray.
static const int kMaxSize = 512 * MB;
// Maximal length of a single BytecodeArray.
static const int kMaxLength = kMaxSize - kHeaderSize;
class BodyDescriptor;
// No weak fields.
typedef BodyDescriptor BodyDescriptorWeak;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(BytecodeArray);
};
// DeoptimizationData is a fixed array used to hold the deoptimization data for
// optimized code. It also contains information about functions that were
// inlined. If N different functions were inlined then the first N elements of
// the literal array will contain these functions.
//
// It can be empty.
class DeoptimizationData : public FixedArray {
public:
// Layout description. Indices in the array.
static const int kTranslationByteArrayIndex = 0;
static const int kInlinedFunctionCountIndex = 1;
static const int kLiteralArrayIndex = 2;
static const int kOsrBytecodeOffsetIndex = 3;
static const int kOsrPcOffsetIndex = 4;
static const int kOptimizationIdIndex = 5;
static const int kSharedFunctionInfoIndex = 6;
static const int kWeakCellCacheIndex = 7;
static const int kInliningPositionsIndex = 8;
static const int kFirstDeoptEntryIndex = 9;
// Offsets of deopt entry elements relative to the start of the entry.
static const int kBytecodeOffsetRawOffset = 0;
static const int kTranslationIndexOffset = 1;
static const int kPcOffset = 2;
static const int kDeoptEntrySize = 3;
// Simple element accessors.
#define DECL_ELEMENT_ACCESSORS(name, type) \
inline type* name(); \
inline void Set##name(type* value);
DECL_ELEMENT_ACCESSORS(TranslationByteArray, ByteArray)
DECL_ELEMENT_ACCESSORS(InlinedFunctionCount, Smi)
DECL_ELEMENT_ACCESSORS(LiteralArray, FixedArray)
DECL_ELEMENT_ACCESSORS(OsrBytecodeOffset, Smi)
DECL_ELEMENT_ACCESSORS(OsrPcOffset, Smi)
DECL_ELEMENT_ACCESSORS(OptimizationId, Smi)
DECL_ELEMENT_ACCESSORS(SharedFunctionInfo, Object)
DECL_ELEMENT_ACCESSORS(WeakCellCache, Object)
DECL_ELEMENT_ACCESSORS(InliningPositions, PodArray<InliningPosition>)
#undef DECL_ELEMENT_ACCESSORS
// Accessors for elements of the ith deoptimization entry.
#define DECL_ENTRY_ACCESSORS(name, type) \
inline type* name(int i); \
inline void Set##name(int i, type* value);
DECL_ENTRY_ACCESSORS(BytecodeOffsetRaw, Smi)
DECL_ENTRY_ACCESSORS(TranslationIndex, Smi)
DECL_ENTRY_ACCESSORS(Pc, Smi)
#undef DECL_ENTRY_ACCESSORS
inline BailoutId BytecodeOffset(int i);
inline void SetBytecodeOffset(int i, BailoutId value);
inline int DeoptCount();
static const int kNotInlinedIndex = -1;
// Returns the inlined function at the given position in LiteralArray, or the
// outer function if index == kNotInlinedIndex.
class SharedFunctionInfo* GetInlinedFunction(int index);
// Allocates a DeoptimizationData.
static Handle<DeoptimizationData> New(Isolate* isolate, int deopt_entry_count,
PretenureFlag pretenure);
// Return an empty DeoptimizationData.
static Handle<DeoptimizationData> Empty(Isolate* isolate);
DECL_CAST(DeoptimizationData)
#ifdef ENABLE_DISASSEMBLER
void DeoptimizationDataPrint(std::ostream& os); // NOLINT
#endif
private:
static int IndexForEntry(int i) {
return kFirstDeoptEntryIndex + (i * kDeoptEntrySize);
}
static int LengthFor(int entry_count) { return IndexForEntry(entry_count); }
};
} // namespace internal
} // namespace v8
#include "src/objects/object-macros-undef.h"
#endif // V8_OBJECTS_CODE_H_