зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1633425 - Add js::TrailingArray type for script data structures. r=jandem
This type is a mixin with helper methods for casting and initializing arrays that follow a struct in the same allocation. Use this for existing JitScript, PrivateScriptData, RuntimeScriptData, ImmutableScriptData types. Differential Revision: https://phabricator.services.mozilla.com/D72672
This commit is contained in:
Родитель
5903f79933
Коммит
6513f435fd
|
@ -13501,7 +13501,7 @@ void CodeGenerator::visitRecompileCheck(LRecompileCheck* ins) {
|
|||
|
||||
// Check if warm-up counter is high enough.
|
||||
AbsoluteAddress warmUpCount =
|
||||
AbsoluteAddress(jitScript->addressOfWarmUpCount());
|
||||
AbsoluteAddress(jitScript).offset(JitScript::offsetOfWarmUpCount());
|
||||
if (ins->mir()->increaseWarmUpCounter()) {
|
||||
masm.load32(warmUpCount, tmp);
|
||||
masm.add32(Imm32(1), tmp);
|
||||
|
|
|
@ -54,19 +54,17 @@ size_t JitScript::NumTypeSets(JSScript* script) {
|
|||
return num;
|
||||
}
|
||||
|
||||
JitScript::JitScript(JSScript* script, uint32_t typeSetOffset,
|
||||
uint32_t bytecodeTypeMapOffset, uint32_t allocBytes,
|
||||
JitScript::JitScript(JSScript* script, Offset typeSetOffset,
|
||||
Offset bytecodeTypeMapOffset, Offset endOffset,
|
||||
const char* profileString)
|
||||
: profileString_(profileString),
|
||||
typeSetOffset_(typeSetOffset),
|
||||
bytecodeTypeMapOffset_(bytecodeTypeMapOffset),
|
||||
allocBytes_(allocBytes) {
|
||||
endOffset_(endOffset) {
|
||||
setTypesGeneration(script->zone()->types.generation);
|
||||
|
||||
if (IsTypeInferenceEnabled()) {
|
||||
uint8_t* base = reinterpret_cast<uint8_t*>(this);
|
||||
DefaultInitializeElements<StackTypeSet>(base + typeSetOffset,
|
||||
numTypeSets());
|
||||
initElements<StackTypeSet>(typeSetOffset, numTypeSets());
|
||||
}
|
||||
|
||||
// Initialize the warm-up count from the count stored in the script.
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "jstypes.h"
|
||||
#include "jit/BaselineIC.h"
|
||||
#include "js/UniquePtr.h"
|
||||
#include "util/TrailingArray.h"
|
||||
#include "vm/TypeInference.h"
|
||||
|
||||
class JS_PUBLIC_API JSScript;
|
||||
|
@ -108,13 +109,13 @@ static IonScript* const IonCompilingScriptPtr =
|
|||
// Item | Offset
|
||||
// ------------------------+------------------------
|
||||
// JitScript | 0
|
||||
// ICEntry[] | sizeof(JitScript)
|
||||
// StackTypeSet[] | typeSetOffset_
|
||||
// uint32_t[] | bytecodeTypeMapOffset_
|
||||
// ICEntry[] | icEntriesOffset()
|
||||
// StackTypeSet[] | typeSetOffset()
|
||||
// uint32_t[] | bytecodeTypeMapOffset()
|
||||
// (= bytecode type map) |
|
||||
//
|
||||
// These offsets are also used to compute numICEntries and numTypeSets.
|
||||
class alignas(uintptr_t) JitScript final {
|
||||
class alignas(uintptr_t) JitScript final : public TrailingArray {
|
||||
friend class ::JSScript;
|
||||
|
||||
// Allocated space for fallback IC stubs.
|
||||
|
@ -184,18 +185,18 @@ class alignas(uintptr_t) JitScript final {
|
|||
mozilla::Atomic<uint32_t, mozilla::Relaxed> warmUpCount_ = {};
|
||||
|
||||
// Offset of the StackTypeSet array.
|
||||
uint32_t typeSetOffset_ = 0;
|
||||
Offset typeSetOffset_ = 0;
|
||||
|
||||
// Offset of the bytecode type map.
|
||||
uint32_t bytecodeTypeMapOffset_ = 0;
|
||||
Offset bytecodeTypeMapOffset_ = 0;
|
||||
|
||||
// The size of this allocation.
|
||||
Offset endOffset_ = 0;
|
||||
|
||||
// This field is used to avoid binary searches for the sought entry when
|
||||
// bytecode map queries are in linear order.
|
||||
uint32_t bytecodeTypeMapHint_ = 0;
|
||||
|
||||
// The size of this allocation.
|
||||
uint32_t allocBytes_ = 0;
|
||||
|
||||
struct Flags {
|
||||
// Flag set when discarding JIT code to indicate this script is on the stack
|
||||
// and type information and JIT code should not be discarded.
|
||||
|
@ -215,15 +216,18 @@ class alignas(uintptr_t) JitScript final {
|
|||
};
|
||||
Flags flags_ = {}; // Zero-initialize flags.
|
||||
|
||||
ICEntry* icEntries() {
|
||||
uint8_t* base = reinterpret_cast<uint8_t*>(this);
|
||||
return reinterpret_cast<ICEntry*>(base + offsetOfICEntries());
|
||||
}
|
||||
// End of fields.
|
||||
|
||||
Offset icEntriesOffset() const { return offsetOfICEntries(); }
|
||||
Offset typeSetOffset() const { return typeSetOffset_; }
|
||||
Offset bytecodeTypeMapOffset() const { return bytecodeTypeMapOffset_; }
|
||||
Offset endOffset() const { return endOffset_; }
|
||||
|
||||
ICEntry* icEntries() { return offsetToPointer<ICEntry>(icEntriesOffset()); }
|
||||
|
||||
StackTypeSet* typeArrayDontCheckGeneration() {
|
||||
MOZ_ASSERT(IsTypeInferenceEnabled());
|
||||
uint8_t* base = reinterpret_cast<uint8_t*>(this);
|
||||
return reinterpret_cast<StackTypeSet*>(base + typeSetOffset_);
|
||||
return offsetToPointer<StackTypeSet>(typeSetOffset());
|
||||
}
|
||||
|
||||
uint32_t typesGeneration() const { return uint32_t(flags_.typesGeneration); }
|
||||
|
@ -244,8 +248,8 @@ class alignas(uintptr_t) JitScript final {
|
|||
}
|
||||
|
||||
public:
|
||||
JitScript(JSScript* script, uint32_t typeSetOffset,
|
||||
uint32_t bytecodeTypeMapOffset, uint32_t allocBytes,
|
||||
JitScript(JSScript* script, Offset typeSetOffset,
|
||||
Offset bytecodeTypeMapOffset, Offset endOffset,
|
||||
const char* profileString);
|
||||
|
||||
#ifdef DEBUG
|
||||
|
@ -300,11 +304,11 @@ class alignas(uintptr_t) JitScript final {
|
|||
}
|
||||
|
||||
uint32_t numICEntries() const {
|
||||
return (typeSetOffset_ - offsetOfICEntries()) / sizeof(ICEntry);
|
||||
return (typeSetOffset() - icEntriesOffset()) / sizeof(ICEntry);
|
||||
}
|
||||
uint32_t numTypeSets() const {
|
||||
MOZ_ASSERT(IsTypeInferenceEnabled());
|
||||
return (bytecodeTypeMapOffset_ - typeSetOffset_) / sizeof(StackTypeSet);
|
||||
return (bytecodeTypeMapOffset() - typeSetOffset()) / sizeof(StackTypeSet);
|
||||
}
|
||||
|
||||
uint32_t* bytecodeTypeMapHint() { return &bytecodeTypeMapHint_; }
|
||||
|
@ -328,8 +332,7 @@ class alignas(uintptr_t) JitScript final {
|
|||
|
||||
uint32_t* bytecodeTypeMap() {
|
||||
MOZ_ASSERT(IsTypeInferenceEnabled());
|
||||
uint8_t* base = reinterpret_cast<uint8_t*>(this);
|
||||
return reinterpret_cast<uint32_t*>(base + bytecodeTypeMapOffset_);
|
||||
return offsetToPointer<uint32_t>(bytecodeTypeMapOffset());
|
||||
}
|
||||
|
||||
inline StackTypeSet* thisTypes(const AutoSweepJitScript& sweep,
|
||||
|
@ -399,7 +402,7 @@ class alignas(uintptr_t) JitScript final {
|
|||
|
||||
static void Destroy(Zone* zone, JitScript* script);
|
||||
|
||||
static constexpr size_t offsetOfICEntries() { return sizeof(JitScript); }
|
||||
static constexpr Offset offsetOfICEntries() { return sizeof(JitScript); }
|
||||
|
||||
static constexpr size_t offsetOfJitCodeSkipArgCheck() {
|
||||
return offsetof(JitScript, jitCodeSkipArgCheck_);
|
||||
|
@ -415,9 +418,6 @@ class alignas(uintptr_t) JitScript final {
|
|||
}
|
||||
|
||||
uint32_t warmUpCount() const { return warmUpCount_; }
|
||||
uint32_t* addressOfWarmUpCount() {
|
||||
return reinterpret_cast<uint32_t*>(&warmUpCount_);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void printTypes(JSContext* cx, HandleScript script);
|
||||
|
@ -470,7 +470,7 @@ class alignas(uintptr_t) JitScript final {
|
|||
void removeDependentWasmImport(wasm::Instance& instance, uint32_t idx);
|
||||
void unlinkDependentWasmImports();
|
||||
|
||||
size_t allocBytes() const { return allocBytes_; }
|
||||
size_t allocBytes() const { return endOffset(); }
|
||||
|
||||
EnvironmentObject* templateEnvironment() const {
|
||||
return cachedIonData().templateEnv;
|
||||
|
|
|
@ -41,21 +41,6 @@ static constexpr T AlignBytes(T bytes, U alignment) {
|
|||
return bytes + ComputeByteAlignment(bytes, alignment);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
// Placement-new elements of an array. This should optimize away for types with
|
||||
// trivial default initiation.
|
||||
template <typename T>
|
||||
static void DefaultInitializeElements(void* arrayPtr, size_t length) {
|
||||
uintptr_t elem = reinterpret_cast<uintptr_t>(arrayPtr);
|
||||
MOZ_ASSERT(elem % alignof(T) == 0);
|
||||
|
||||
for (size_t i = 0; i < length; ++i) {
|
||||
new (reinterpret_cast<void*>(elem)) T;
|
||||
elem += sizeof(T);
|
||||
}
|
||||
}
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* util_Memory_h */
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: set ts=8 sts=2 et sw=2 tw=80:
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef util_TrailingArray_h
|
||||
#define util_TrailingArray_h
|
||||
|
||||
#include "mozilla/Assertions.h" // MOZ_ASSERT
|
||||
|
||||
#include <stddef.h> // size_t
|
||||
#include <stdint.h> // uint32_t, uintptr_t
|
||||
|
||||
namespace js {
|
||||
|
||||
// Placement-new the elements of an array. This should optimize away for types
|
||||
// with trivial default initialization.
|
||||
template <typename T>
|
||||
static void DefaultInitializeElements(void* arrayPtr, size_t nelem) {
|
||||
uintptr_t elem = reinterpret_cast<uintptr_t>(arrayPtr);
|
||||
MOZ_ASSERT(elem % alignof(T) == 0);
|
||||
|
||||
for (size_t i = 0; i < nelem; ++i) {
|
||||
new (reinterpret_cast<void*>(elem)) T;
|
||||
elem += sizeof(T);
|
||||
}
|
||||
}
|
||||
|
||||
// This is a mixin class to use for types that have trailing arrays and use
|
||||
// offsets to delimit them. It provides helper methods to do casting and
|
||||
// initialization while avoiding C++ undefined behaviour.
|
||||
class TrailingArray {
|
||||
protected:
|
||||
// Offsets are measured in bytes relative to 'this'.
|
||||
using Offset = uint32_t;
|
||||
|
||||
// Translate an offset into a concrete pointer.
|
||||
template <typename T>
|
||||
T* offsetToPointer(Offset offset) {
|
||||
uintptr_t base = reinterpret_cast<uintptr_t>(this);
|
||||
return reinterpret_cast<T*>(base + offset);
|
||||
}
|
||||
template <typename T>
|
||||
const T* offsetToPointer(Offset offset) const {
|
||||
uintptr_t base = reinterpret_cast<uintptr_t>(this);
|
||||
return reinterpret_cast<const T*>(base + offset);
|
||||
}
|
||||
|
||||
// Placement-new the elements of an array. This should optimize away for types
|
||||
// with trivial default initialization.
|
||||
template <typename T>
|
||||
void initElements(Offset offset, size_t nelem) {
|
||||
void* raw = offsetToPointer<void>(offset);
|
||||
DefaultInitializeElements<T>(raw, nelem);
|
||||
}
|
||||
|
||||
// Constructor is protected so a derived type is required.
|
||||
TrailingArray() = default;
|
||||
|
||||
public:
|
||||
// Type has trailing data so isn't copyable or movable.
|
||||
TrailingArray(const TrailingArray&) = delete;
|
||||
TrailingArray& operator=(const TrailingArray&) = delete;
|
||||
};
|
||||
|
||||
} // namespace js
|
||||
|
||||
#endif // util_TrailingArray_h
|
|
@ -751,14 +751,6 @@ XDRResult js::PrivateScriptData::XDR(XDRState<mode>* xdr, HandleScript script,
|
|||
return size;
|
||||
}
|
||||
|
||||
// Placement-new elements of an array. This should optimize away for types with
|
||||
// trivial default initiation.
|
||||
template <typename T>
|
||||
void ImmutableScriptData::initElements(size_t offset, size_t length) {
|
||||
uintptr_t base = reinterpret_cast<uintptr_t>(this);
|
||||
DefaultInitializeElements<T>(reinterpret_cast<void*>(base + offset), length);
|
||||
}
|
||||
|
||||
// Initialize the optional arrays in the trailing allocation. This is a set of
|
||||
// offsets that delimit each optional array followed by the arrays themselves.
|
||||
// See comment before 'ImmutableScriptData' for more details.
|
||||
|
@ -955,14 +947,6 @@ static XDRResult XDRImmutableScriptData(XDRState<mode>* xdr,
|
|||
return size;
|
||||
}
|
||||
|
||||
// Placement-new elements of an array. This should optimize away for types with
|
||||
// trivial default initiation.
|
||||
template <typename T>
|
||||
void RuntimeScriptData::initElements(size_t offset, size_t length) {
|
||||
uintptr_t base = reinterpret_cast<uintptr_t>(this);
|
||||
DefaultInitializeElements<T>(reinterpret_cast<void*>(base + offset), length);
|
||||
}
|
||||
|
||||
RuntimeScriptData::RuntimeScriptData(uint32_t natoms) : natoms_(natoms) {
|
||||
// Variable-length data begins immediately after RuntimeScriptData itself.
|
||||
size_t cursor = sizeof(*this);
|
||||
|
@ -4130,14 +4114,6 @@ inline size_t PrivateScriptData::allocationSize() const {
|
|||
return AllocationSize(ngcthings);
|
||||
}
|
||||
|
||||
// Placement-new elements of an array. This should optimize away for types with
|
||||
// trivial default initiation.
|
||||
template <typename T>
|
||||
void PrivateScriptData::initElements(size_t offset, size_t length) {
|
||||
void* raw = offsetToPointer<void>(offset);
|
||||
DefaultInitializeElements<T>(raw, length);
|
||||
}
|
||||
|
||||
// Initialize and placement-new the trailing arrays.
|
||||
PrivateScriptData::PrivateScriptData(uint32_t ngcthings)
|
||||
: ngcthings(ngcthings) {
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include "js/UniquePtr.h"
|
||||
#include "js/Utility.h"
|
||||
#include "util/StructuredSpewer.h"
|
||||
#include "util/TrailingArray.h"
|
||||
#include "vm/BigIntType.h"
|
||||
#include "vm/BytecodeIterator.h"
|
||||
#include "vm/BytecodeLocation.h"
|
||||
|
@ -1409,29 +1410,17 @@ struct FieldInitializers {
|
|||
// [SMDOC] - JSScript data layout (unshared)
|
||||
//
|
||||
// PrivateScriptData stores variable-length data associated with a script.
|
||||
// Abstractly a PrivateScriptData consists of all these arrays:
|
||||
// Abstractly a PrivateScriptData consists of the following:
|
||||
//
|
||||
// * A non-empty array of GCCellPtr in gcthings()
|
||||
//
|
||||
// Accessing this array just requires calling the appropriate public
|
||||
// Span-computing function.
|
||||
class alignas(uintptr_t) PrivateScriptData final {
|
||||
class alignas(uintptr_t) PrivateScriptData final : public TrailingArray {
|
||||
uint32_t ngcthings = 0;
|
||||
|
||||
js::FieldInitializers fieldInitializers_ = js::FieldInitializers::Invalid();
|
||||
|
||||
// Translate an offset into a concrete pointer.
|
||||
template <typename T>
|
||||
T* offsetToPointer(size_t offset) {
|
||||
uintptr_t base = reinterpret_cast<uintptr_t>(this);
|
||||
uintptr_t elem = base + offset;
|
||||
return reinterpret_cast<T*>(elem);
|
||||
}
|
||||
|
||||
// Helpers for creating initializing trailing data
|
||||
template <typename T>
|
||||
void initElements(size_t offset, size_t length);
|
||||
|
||||
// Size to allocate
|
||||
static size_t AllocationSize(uint32_t ngcthings);
|
||||
|
||||
|
@ -1445,7 +1434,7 @@ class alignas(uintptr_t) PrivateScriptData final {
|
|||
|
||||
// Accessors for typed array spans.
|
||||
mozilla::Span<JS::GCCellPtr> gcthings() {
|
||||
size_t offset = offsetOfGCThings();
|
||||
Offset offset = offsetOfGCThings();
|
||||
return mozilla::MakeSpan(offsetToPointer<JS::GCCellPtr>(offset), ngcthings);
|
||||
}
|
||||
|
||||
|
@ -1481,7 +1470,7 @@ class alignas(uintptr_t) PrivateScriptData final {
|
|||
};
|
||||
|
||||
// Script data that is shareable across a JSRuntime.
|
||||
class RuntimeScriptData final {
|
||||
class alignas(uintptr_t) RuntimeScriptData final : public TrailingArray {
|
||||
// This class is reference counted as follows: each pointer from a JSScript
|
||||
// counts as one reference plus there may be one reference from the shared
|
||||
// script data table.
|
||||
|
@ -1497,15 +1486,9 @@ class RuntimeScriptData final {
|
|||
friend class ::JSScript;
|
||||
|
||||
private:
|
||||
// Layout of trailing arrays.
|
||||
size_t atomOffset() const { return offsetOfAtoms(); }
|
||||
|
||||
// Size to allocate.
|
||||
static size_t AllocationSize(uint32_t natoms);
|
||||
|
||||
template <typename T>
|
||||
void initElements(size_t offset, size_t length);
|
||||
|
||||
// Initialize to GC-safe state.
|
||||
explicit RuntimeScriptData(uint32_t natoms);
|
||||
|
||||
|
@ -1528,15 +1511,13 @@ class RuntimeScriptData final {
|
|||
|
||||
uint32_t natoms() const { return natoms_; }
|
||||
GCPtrAtom* atoms() {
|
||||
uintptr_t base = reinterpret_cast<uintptr_t>(this);
|
||||
return reinterpret_cast<GCPtrAtom*>(base + atomOffset());
|
||||
Offset offset = offsetOfAtoms();
|
||||
return offsetToPointer<GCPtrAtom>(offset);
|
||||
}
|
||||
|
||||
mozilla::Span<const GCPtrAtom> atomsSpan() const {
|
||||
uintptr_t base = reinterpret_cast<uintptr_t>(this);
|
||||
const GCPtrAtom* p =
|
||||
reinterpret_cast<const GCPtrAtom*>(base + atomOffset());
|
||||
return mozilla::MakeSpan(p, natoms_);
|
||||
Offset offset = offsetOfAtoms();
|
||||
return mozilla::MakeSpan(offsetToPointer<GCPtrAtom>(offset), natoms_);
|
||||
}
|
||||
|
||||
static constexpr size_t offsetOfAtoms() { return sizeof(RuntimeScriptData); }
|
||||
|
|
|
@ -14,8 +14,9 @@
|
|||
|
||||
#include "frontend/SourceNotes.h" // js::SrcNote
|
||||
#include "js/CompileOptions.h" // JS::{ReadOnlyCompileOptions,TransitiveCompileOptions}
|
||||
#include "js/TypeDecls.h" // JSContext,jsbytecode
|
||||
#include "js/UniquePtr.h" // js::UniquePtr
|
||||
#include "js/TypeDecls.h" // JSContext,jsbytecode
|
||||
#include "js/UniquePtr.h" // js::UniquePtr
|
||||
#include "util/TrailingArray.h" // js::TrailingArray
|
||||
#include "vm/StencilEnums.h" // js::{TryNoteKind,ImmutableScriptFlagsEnum,MutableScriptFlagsEnum}
|
||||
|
||||
//
|
||||
|
@ -221,11 +222,8 @@ class MutableScriptFlags : public ScriptFlagBase<MutableScriptFlagsEnum> {
|
|||
// In general, the length of each array is computed from subtracting the start
|
||||
// offset of the array from the start offset of the subsequent array. The
|
||||
// notable exception is that bytecode length is stored explicitly.
|
||||
class alignas(uint32_t) ImmutableScriptData final {
|
||||
class alignas(uint32_t) ImmutableScriptData final : public TrailingArray {
|
||||
private:
|
||||
// Offsets are measured in bytes relative to 'this'.
|
||||
using Offset = uint32_t;
|
||||
|
||||
Offset optArrayOffset_ = 0;
|
||||
|
||||
// Length of bytecode
|
||||
|
@ -269,10 +267,10 @@ class alignas(uint32_t) ImmutableScriptData final {
|
|||
// Offsets (in bytes) from 'this' to each component array. The delta between
|
||||
// each offset and the next offset is the size of each array and is defined
|
||||
// even if an array is empty.
|
||||
size_t flagOffset() const { return offsetOfCode() - sizeof(Flags); }
|
||||
size_t codeOffset() const { return offsetOfCode(); }
|
||||
size_t noteOffset() const { return offsetOfCode() + codeLength_; }
|
||||
size_t optionalOffsetsOffset() const {
|
||||
Offset flagOffset() const { return offsetOfCode() - sizeof(Flags); }
|
||||
Offset codeOffset() const { return offsetOfCode(); }
|
||||
Offset noteOffset() const { return offsetOfCode() + codeLength_; }
|
||||
Offset optionalOffsetsOffset() const {
|
||||
// Determine the location to beginning of optional-offsets array by looking
|
||||
// at index for try-notes.
|
||||
//
|
||||
|
@ -288,14 +286,14 @@ class alignas(uint32_t) ImmutableScriptData final {
|
|||
|
||||
return optArrayOffset_ - (numOffsets * sizeof(Offset));
|
||||
}
|
||||
size_t resumeOffsetsOffset() const { return optArrayOffset_; }
|
||||
size_t scopeNotesOffset() const {
|
||||
Offset resumeOffsetsOffset() const { return optArrayOffset_; }
|
||||
Offset scopeNotesOffset() const {
|
||||
return getOptionalOffset(flags().resumeOffsetsEndIndex);
|
||||
}
|
||||
size_t tryNotesOffset() const {
|
||||
Offset tryNotesOffset() const {
|
||||
return getOptionalOffset(flags().scopeNotesEndIndex);
|
||||
}
|
||||
size_t endOffset() const {
|
||||
Offset endOffset() const {
|
||||
return getOptionalOffset(flags().tryNotesEndIndex);
|
||||
}
|
||||
|
||||
|
@ -304,16 +302,6 @@ class alignas(uint32_t) ImmutableScriptData final {
|
|||
uint32_t numResumeOffsets,
|
||||
uint32_t numScopeNotes, uint32_t numTryNotes);
|
||||
|
||||
// Translate an offset into a concrete pointer.
|
||||
template <typename T>
|
||||
T* offsetToPointer(size_t offset) {
|
||||
uintptr_t base = reinterpret_cast<uintptr_t>(this);
|
||||
return reinterpret_cast<T*>(base + offset);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void initElements(size_t offset, size_t length);
|
||||
|
||||
void initOptionalArrays(size_t* cursor, Flags* flags,
|
||||
uint32_t numResumeOffsets, uint32_t numScopeNotes,
|
||||
uint32_t numTryNotes);
|
||||
|
|
Загрузка…
Ссылка в новой задаче