Интерфейс MemoryLayout
- Все известные подинтерфейсы:
-
AddressLayout,GroupLayout,PaddingLayout,SequenceLayout,StructLayout,UnionLayout,ValueLayout,ValueLayout.OfBoolean,ValueLayout.OfByte,ValueLayout.OfChar,ValueLayout.OfDouble,ValueLayout.OfFloat,ValueLayout.OfInt,ValueLayout.OfLong,ValueLayout.OfShort
public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, PaddingLayout, ValueLayout
В иерархии макета есть два листа: макеты значений, которые используются для представления значений заданного размера и типа, и макеты заполнения, которые, как следует из названия, используются для представления части сегмента памяти, содержимое которой должно игнорироваться, и которые в основном присутствуют по соображениям выравнивания. Некоторые общие константы макета значений, такие как ValueLayout.JAVA_INT и ValueLayout.JAVA_FLOAT_UNALIGNED, определены в классе ValueLayout. Специальный вид макета значений, а именно макет адреса, используется для моделирования значений, обозначающих адрес области памяти.
Более сложные макеты могут быть получены из более простых: последовательный макет обозначает однородное повторение нуля или более вхождений макета элемента; макет группы обозначает гетерогенную агрегацию нуля или более макетов членов. Макеты групп бывают двух типов: структурные макеты, где макеты членов располагаются один за другим, и макеты объединений, где макеты членов располагаются с одинаковым начальным смещением.
Макеты могут быть необязательно связаны с именем. Имя макета можно использовать при построении путей макета.
Рассмотрим следующее объявление структуры в C:
typedef struct {
char kind;
int value;
} TaggedValues[5];
SequenceLayout TAGGED_VALUES = MemoryLayout.sequenceLayout(5,
MemoryLayout.structLayout(
ValueLayout.JAVA_BYTE.withName("kind"),
MemoryLayout.paddingLayout(3),
ValueLayout.JAVA_INT.withName("value")
)
).withName("TaggedValues");
Характеристики макетов памяти
Все макеты имеют размер (выраженный в байтах), который определяется следующим образом:- Размер макета значения определяется связанным с макетом значения ValueLayout.carrier(). То есть константа
ValueLayout.JAVA_INTимеет носительintи размер 4 байта; - Размер макета адреса зависит от платформы. То есть константа
ValueLayout.ADDRESSимеет размер 8 байт на 64-битной платформе; - Размер макета заполнения всегда задается явно при создании;
- Размер последовательного макета, элемент которого — E, а количество элементов — L, равен размеру E, умноженному на L;
- Размер структурного макета с макетами членов M1, M2, ..., Mn, размеры которых соответственно равны S1, S2, ..., Sn, равен S1 + S2 + ... + Sn;
- Размер макета объединения U с макетами членов M1, M2, ..., Mn, размеры которых соответственно равны S1, S2, ..., Sn, равен max(S1, S2, ... Sn).
Кроме того, все макеты имеют естественное выравнивание (выраженное в байтах), которое определяется следующим образом:
- Естественное выравнивание макета заполнения равно 1;
- Естественное выравнивание макета значения, размер которого N, равно N;
- Естественное выравнивание последовательного макета, элемент которого E, равно выравниванию E;
- Естественное выравнивание макета группы с макетами членов M1, M2, ..., Mn, выравнивания которых соответственно равны A1, A2, ..., An, равно max(A1, A2 ... An).
withByteAlignment(long)), что может быть полезно для описания макетов с более слабыми или более сильными ограничениями на выравнивание. Пути макета
Путь макета используется для однозначного выбора макета, вложенного в какой-либо другой макет. Пути макета обычно выражаются как последовательность одного или более элементов пути. (Более формальное определение путей макета приведено ниже).Пути макета можно использовать для:
- получения смещений произвольно вложенных макетов;
- получения var handle, который может использоваться для доступа к значению, соответствующему выбранному макету;
- выбора произвольно вложенного макета.
Например, задан макет последовательности taggedValues, созданный выше. Мы можем получить смещение, в байтах, макета члена, названного value в первом элементе последовательности, следующим образом:
long valueOffset = TAGGED_VALUES.byteOffset(PathElement.sequenceElement(0),
PathElement.groupElement("value")); // yields 4
value, следующим образом: MemoryLayout value = TAGGED_VALUES.select(PathElement.sequenceElement(),
PathElement.groupElement("value"));
Открытые элементы пути
Некоторые элементы пути макета, называемые открытыми элементами пути, могут выбирать сразу несколько макетов. Например, открытые элементы путиMemoryLayout.PathElement.sequenceElement(), MemoryLayout.PathElement.sequenceElement(long, long) выбирают неопределенный элемент в макете последовательности. Var handle, полученный из пути макета, содержащего один или более открытых элементов пути, имеет дополнительные координаты типа long, которые могут использоваться клиентами для связывания открытых элементов в пути: VarHandle valueHandle = TAGGED_VALUES.varHandle(PathElement.sequenceElement(),
PathElement.groupElement("value"));
MemorySegment taggedValues = ...
// reads the "value" field of the third struct in the array (taggedValues[2].value)
int val = (int) valueHandle.get(taggedValues,
0L, // base offset
2L); // sequence index
Открытые элементы пути также влияют на создание дескрипторов обработчиков смещений. Каждый открытый элемент пути становится дополнительным long параметром в полученном дескрипторе обработчика. Этот параметр можно использовать для указания индекса элемента последовательности, смещение которого нужно вычислить:
MethodHandle offsetHandle = TAGGED_VALUES.byteOffsetHandle(PathElement.sequenceElement(),
PathElement.groupElement("kind"));
long offset1 = (long) offsetHandle.invokeExact(0L, 1L); // 0 + (1 * 8) = 8
long offset2 = (long) offsetHandle.invokeExact(0L, 2L); // 0 + (2 * 8) = 16
Элементы пути разыменования
Специальный тип элемента пути, называемый элементом пути разыменования, позволяет var handle, полученным из макетов памяти, следовать за указателями. Рассмотрим следующий макет:StructLayout RECTANGLE = MemoryLayout.structLayout(
ValueLayout.ADDRESS.withTargetLayout(
MemoryLayout.sequenceLayout(4,
MemoryLayout.structLayout(
ValueLayout.JAVA_INT.withName("x"),
ValueLayout.JAVA_INT.withName("y")
).withName("point")
)
).withName("points")
);
points, макет адреса, целевым макетом которого является последовательный макет из четырех структурных макетов. Каждый структурный макет описывает двумерную точку и определен как пара или ValueLayout.JAVA_INT координат, с именами x и y соответственно. С помощью элементов пути разыменования мы можем получить var handle, который обращается к y координате одной из точек в прямоугольнике, следующим образом:
VarHandle rectPointYs = RECTANGLE.varHandle(
PathElement.groupElement("points"),
PathElement.dereferenceElement(),
PathElement.sequenceElement(),
PathElement.groupElement("y")
);
MemorySegment rect = ...
// dereferences the third point struct in the "points" array, and reads its "y" coordinate (rect.points[2]->y)
int rect_y_2 = (int) rectPointYs.get(rect,
0L, // base offset
2L); // sequence index
Корректность путей макета
Путь макета применяется к макетуC_0, также называемому начальным макетом. Каждый элемент пути макета можно рассматривать как функцию, которая обновляет текущий макет C_i-1 на некоторый другой макет C_i. То есть, для каждого элемента пути E1, E2, ... En в пути макета P, мы вычисляем C_i = f_i(C_i-1), где f_i — функция выбора, связанная с элементом пути, рассматриваемым в данный момент, обозначаемая как E_i. Конечный макет C_i также называется выбранным макетом. Путь макета P считается корректным для начального макета C_0, если все его элементы пути E1, E2, ... En являются корректными для соответствующих входных макетов C_0, C_1, ... C_n-1. Элемент пути E считается корректным для макета L, если выполняется одно из следующих условий:
-
Lявляется последовательным макетом, аE— элементом пути последовательности (один изMemoryLayout.PathElement.sequenceElement(long),MemoryLayout.PathElement.sequenceElement(long, long)илиMemoryLayout.PathElement.sequenceElement()). Кроме того, еслиEсодержит один или несколько индексов последовательности, эти индексы должны быть совместимы с количеством элементов последовательного макета; -
Lявляется макетом группы, аE— элементом пути группы (один изMemoryLayout.PathElement.groupElement(String)илиMemoryLayout.PathElement.groupElement(long)). Кроме того, элемент пути группы должен ссылаться на допустимый макет члена вL, либо по имени, либо по индексу; -
Lявляется макетом адреса, аE— элементом пути разыменования. Кроме того,Lдолжен определять целевой макет .
P, который не является корректным для начального макета C_0, приведет к исключению IllegalArgumentException. Ограничения на режим доступа
Var handle, возвращаемыйvarHandle(PathElement...) или ValueLayout.varHandle(), имеет определённые характеристики доступа, которые получены из выбранного макета L: - Тип носителя
T, полученный изL.carrier() - Ограничение на выравнивание
A, полученное изL.byteAlignment() - Размер доступа
S, полученный изL.byteSize()
A совместимо с размером доступа S, то есть если A >= S. Выровненный var handle гарантированно поддерживает следующие режимы доступа:- режимы чтения/записи для всех
T. На 32-битных платформах поддерживаются режимы доступаgetиsetдляlong,doubleиMemorySegment, но они могут привести к разрыву слов, как описано в разделе 17.7 спецификации языка Java. - режимы атомного обновления для
int,long,float,doubleиMemorySegment. (Будущие основные версии платформы JDK могут поддержать дополнительные типы для некоторых в настоящее время неподдерживаемых режимов доступа.) - числовые режимы атомного обновления для
int,longиMemorySegment. (Будущие основные версии платформы JDK могут поддержать дополнительные числовые типы для некоторых в настоящее время неподдерживаемых режимов доступа.) - поразрядные режимы атомного обновления для
int,longиMemorySegment. (Будущие основные версии платформы JDK могут поддержать дополнительные числовые типы для некоторых в настоящее время неподдерживаемых режимов доступа.)
T является float, double или MemorySegment, то режимы атомного обновления сравнивают значения, используя их битовую форму (см. Float.floatToRawIntBits(float), Double.doubleToRawLongBits(double) и MemorySegment.address() соответственно). В качестве альтернативы, дескриптор переменной является невыровненным, если его ограничение выравнивания A несовместимо с размером доступа S, то есть, если A < S. Невыровненный дескриптор переменной поддерживает только режимы доступа get и set. Все остальные режимы доступа приведут к выбросу исключения UnsupportedOperationException. Кроме того, хотя и поддерживаются, режимы доступа get и set могут привести к разрыву слов.
Работа с массивами переменной длины
Мы видели, как макеты последовательностей используются для описания содержимого массива, размер которого известен статически. Однако есть случаи, когда размер массива известен только динамически. Такие массивы называются массивами переменной длины. Существуют два основных типа массивов переменной длины:- главный массив переменной длины, размер которого зависит от значения какой-либо несвязанной переменной или параметра;
- массив переменной длины, вложенный в структуру, размер которого зависит от значения какого-либо другого поля во внешней структуре.
Главные массивы переменной длины
Рассмотрим следующее объявление структуры на C:typedef struct {
int x;
int y;
} Point;
x и y соответственно). Теперь рассмотрим следующий фрагмент кода C: int size = ...
Point *points = (Point*)malloc(sizeof(Point) * size);
for (int i = 0 ; i < size ; i++) {
... points[i].x ...
}
points). Важно, что размер массива динамически привязан к значению переменной size. Внутри цикла осуществляется доступ к координате x всех точек в массиве. Для моделирования этого кода на Java давайте начнем с определения макета структуры Point следующим образом:
StructLayout POINT = MemoryLayout.structLayout(
ValueLayout.JAVA_INT.withName("x"),
ValueLayout.JAVA_INT.withName("y")
);
VarHandle POINT_ARR_X = POINT.arrayElementVarHandle(PathElement.groupElement("x"));
int size = ...
MemorySegment points = ...
for (int i = 0 ; i < size ; i++) {
... POINT_ARR_X.get(points, 0L, (long)i) ...
}
x последующей точки в массиве извлекается с помощью дескриптора переменной POINT_ARR_X, полученного с помощью метода arrayElementVarHandle(PathElement...). Этот дескриптор переменной содержит две координаты long: первая — смещение базового адреса (установленное на 0L), а вторая — логический индекс, который можно использовать для шага по всем элементам массива точек. Координата смещения базового адреса позволяет клиентам выражать сложные операции доступа, вводя дополнительные вычисления смещения в дескриптор переменной (мы увидим пример этого ниже). В случаях, когда смещение базового адреса является постоянным (как в предыдущем примере), клиенты могут, при необходимости, опустить параметр смещения базового адреса и упростить выражение доступа. Это достигается с помощью адаптера дескриптора переменной MethodHandles.insertCoordinates(VarHandle, int, Object...).
Вложенные массивы переменной длины
Рассмотрим следующее объявление структуры на C:typedef struct {
int size;
Point points[];
} Polygon;
points остается неопределенным в объявлении C, используя Гибкое член массива (функция, стандартизированная в C99). Клиенты снова могут выполнить структурированный доступ к элементам вложенного массива переменной длины, используя метод arrayElementVarHandle(PathElement...), как показано ниже:
StructLayout POLYGON = MemoryLayout.structLayout(
ValueLayout.JAVA_INT.withName("size"),
MemoryLayout.sequenceLayout(0, POINT).withName("points")
);
VarHandle POLYGON_SIZE = POLYGON.varHandle(0, PathElement.groupElement("size"));
long POINTS_OFFSET = POLYGON.byteOffset(PathElement.groupElement("points"));
POLYGON содержит макет последовательности размера ноль. Макет элемента макета последовательности — это макет POINT, показанный ранее. Макет многоугольника используется для получения дескриптора переменной, обеспечивающего доступ к размеру многоугольника, а также смещению (POINTS_OFFSET) к началу массива переменной длины points. Координаты x всех точек в многоугольнике затем можно получить следующим образом:
MemorySegment polygon = ...
int size = POLYGON_SIZE.get(polygon, 0L);
for (int i = 0 ; i < size ; i++) {
... POINT_ARR_X.get(polygon, POINTS_OFFSET, (long)i) ...
}
POLYGON_SIZE. Затем в цикле мы считываем координаты x всех точек в многоугольнике. Это делается путем предоставления пользовательского смещения (а именно, POINTS_OFFSET) к координате смещения дескриптора переменной POINT_ARR_X. Как и прежде, переменная цикла i передается как индекс дескриптора переменной POINT_ARR_X для шага по всем элементам массива переменной длины.- Требования к реализации:
- Реализации этого интерфейса неизменяемы, потокобезопасны и базируются на значении.
- Граф иерархии запечатанного класса:
- С:
- 22
Краткое описание вложенных классов
| Modifier and Type | Interface | Description |
|---|---|---|
static interface |
MemoryLayout.PathElement |
Элемент в пути макета. |
Краткое описание методов
| Modifier and Type | Method | Description |
|---|---|---|
VarHandle |
arrayElementVarHandle |
Создаёт обработчик переменной, который обращается к смежным элементам в сегменте памяти по смещениям, выбранным заданным путём макета, где доступные элементы имеют этот макет, и начальный макет в пути — это макет. |
long |
byteAlignment() |
Возвращает ограничение выравнивания, связанное с этим макетом, выраженное в байтах. |
long |
byteOffset |
Вычисляет смещение, в байтах, макета, выбранного заданным путём макета, где начальный макет в пути — это макет. |
MethodHandle |
byteOffsetHandle |
Создаёт обработчик метода, который вычисляет смещение, в байтах, макета, выбранного заданным путём макета, где начальный макет в пути — это макет. |
long |
byteSize() |
Возвращает размер макета в байтах. |
boolean |
equals |
Сравнивает указанный объект с этим макетом для проверки равенства. |
int |
hashCode() |
Возвращает значение хэш-кода для этого макета. |
Optional |
name() |
Возвращает имя (если оно есть), связанное с этим макетом. |
static PaddingLayout |
paddingLayout |
Создаёт макет заполнения заданного размера в байтах. |
long |
scale |
Возвращает offset + (byteSize() * index). |
MethodHandle |
scaleHandle() |
Возвращает обработчик метода, который может быть использован для вызова scale(long, long) для этого макета. |
MemoryLayout |
select |
Возвращает макет, выбранный из предоставленного пути, где начальный макет в пути — это макет. |
static SequenceLayout |
sequenceLayout |
Создаёт макет последовательности с заданным макетом элемента и количеством элементов. |
MethodHandle |
sliceHandle |
Создаёт обработчик метода, который, принимая сегмент памяти, возвращает срез, соответствующий макету, выбранному заданным путём макета, где начальный макет в пути — это макет. |
static StructLayout |
structLayout |
Создаёт макет структуры с заданными макетами членов. |
String |
toString() |
Возвращает строковое представление этого макета. |
static UnionLayout |
unionLayout |
Создаёт макет объединения с заданными макетами членов. |
VarHandle |
varHandle |
Создаёт обработчик переменной, который обращается к сегменту памяти по смещению, выбранному заданным путём макета, где начальный макет в пути — это макет. |
MemoryLayout |
withByteAlignment |
Возвращает макет памяти с такими же характеристиками, что и у этого макета, но с заданным ограничением выравнивания (в байтах). |
MemoryLayout |
withName |
Возвращает макет памяти с такими же характеристиками, что и у этого макета, но с заданным именем. |
MemoryLayout |
withoutName() |
Возвращает макет памяти с такими же характеристиками, что и у этого макета, но без имени. |
Подробное описание методов
byteSize
long byteSize()
- Возвращает:
- размер макета в байтах
name
Optional<String> name()
- Возвращает:
- имя (если есть) этого макета
- См. также:
withName
MemoryLayout withName(String name)
- Параметры:
-
name- имя макета - Возвращает:
- макет памяти с теми же характеристиками, что и этот макет, но с указанным именем
- См. также:
withoutName
MemoryLayout withoutName()
- Примечание API:
- Это может быть полезно для сравнения двух макетов, имеющих разные имена, но в остальном равных.
- Возвращает:
- макет памяти с теми же характеристиками, что и этот макет, но без имени
- См. также:
byteAlignment
long byteAlignment()
Выравнивание макета определяет степень двойки A, которая является байтовым выравниванием макета, где A — это количество байтов, которые должны быть выровнены для любого указателя, правильно указывающего на этот макет. Таким образом:
-
A=1означает отсутствие выравнивания (в обычном понимании), что часто используется в пакетах. -
A=8означает выравнивание по слову (на LP64),A=4выравнивание по целому числу,A=2выравнивание по короткому числу и т. д. -
A=64— это самое строгое требование выравнивания, накладываемое ABI x86/SV (для данных AVX-512).
withByteAlignment(long)), то этот метод возвращает ограничение естественного выравнивания (в байтах), связанное с этим макетом.- Возвращает:
- ограничение выравнивания, связанное с этим макетом, выраженное в байтах
withByteAlignment
MemoryLayout withByteAlignment(long byteAlignment)
- Параметры:
-
byteAlignment- ограничение выравнивания макета, выраженное в байтах - Возвращает:
- макет памяти с теми же характеристиками, что и этот макет, но с заданным ограничением выравнивания (в байтах)
- Исключения:
-
IllegalArgumentException- еслиbyteAlignmentне является степенью двойки
scale
long scale(long offset, long index)
offset + (byteSize() * index).- Параметры:
-
offset- базовый смещение -
index- индекс, который будет масштабироваться с размером этого макета в байтах - Возвращает:
offset + (byteSize() * index)- Исключения:
-
IllegalArgumentException- еслиoffsetилиindexотрицательны -
ArithmeticException- если сложение или умножение переполняет
scaleHandle
MethodHandle scaleHandle()
scale(long, long) для этого макета.- Возвращает:
- дескриптор метода, который можно использовать для вызова
scale(long, long)для этого макета
byteOffset
long byteOffset(MemoryLayout.PathElement... elements)
- Параметры:
-
elements- элементы пути макета - Возвращает:
- Смещение в байтах выбранного макета путем макета в
elements - Исключения:
-
IllegalArgumentException- если путь макета не корректен для этого макета -
IllegalArgumentException- если путь макета содержит один или несколько элементов пути для открытия -
IllegalArgumentException- если путь макета содержит один или несколько элементов пути для ссылки
byteOffsetHandle
MethodHandle byteOffsetHandle(MemoryLayout.PathElement... elements)
Возвращаемый дескриптор метода обладает следующими характеристиками:
- его тип возвращаемого значения —
long; - у него есть один ведущий
longпараметр, представляющий базовое смещение; - у него есть нуль или более последующих параметров типа
long, по одному на каждый элемент пути для открытия в предоставленном пути макета. Порядок этих параметров соответствует порядку, в котором элементы пути для открытия появляются в предоставленном пути макета.
Конечное смещение, возвращаемое дескриптором метода, вычисляется следующим образом:
гдеoffset = b + c_1 + c_2 + ... + c_m + (x_1 * s_1) + (x_2 * s_2) + ... + (x_n * s_n)
b представляет базовое смещение, предоставленное в качестве динамического long аргумента, x_1, x_2, ... x_n представляют индексы в последовательностях, предоставленных в качестве динамических long аргументов, тогда как s_1, s_2, ... s_n — это статические константы шага, полученные из размера макета элемента последовательности, а c_1, c_2, ... c_m — это другие статические константы смещения (например, смещения полей), которые получены из пути макета. Для любого заданного динамического аргумента x_i, он должен быть таким, что 0 <= x_i < size_i, где size_i — это размер элемента пути для открытия, связанного с x_i. В противном случае возвращаемый дескриптор метода генерирует исключение IndexOutOfBoundsException. Кроме того, значение b должно быть таким, чтобы вычисление offset не переполняло, иначе возвращаемый дескриптор метода генерирует исключение ArithmeticException.
- Примечание API:
- Возвращаемый дескриптор метода можно использовать для вычисления смещения макета, аналогично
byteOffset(PathElement...), но более гибко, так как некоторые индексы могут быть указаны при вызове дескриптора метода. - Параметры:
-
elements- элементы пути макета - Возвращает:
- дескриптор метода, который вычисляет смещение в байтах выбранного макета по заданному пути макета
- Исключения:
-
IllegalArgumentException- если путь макета не корректен для этого макета -
IllegalArgumentException- если путь макета содержит один или несколько элементов пути для ссылки
varHandle
VarHandle varHandle(MemoryLayout.PathElement... elements)
Возвращаемый обработчик var имеет следующие характеристики:
- его тип получен из носителя выбранного расположения значения;
- он имеет ведущий параметр типа
MemorySegment, представляющий доступный сегмент; - последующий
longпараметр, соответствующий базовому смещению, обозначенному какB; - он имеет ноль или более следующих координат доступа типа
long, по одной для каждого элемента открытого пути в предоставленном пути расположения, обозначенных какI1, I2, ... In, соответственно. Порядок этих координат доступа соответствует порядку, в котором элементы открытого пути встречаются в предоставленном пути расположения.
Если предоставленный путь расположения P не содержит элементов разыменования, то смещение O операции доступа вычисляется следующим образом:
O = this.byteOffsetHandle(P).invokeExact(B, I1, I2, ... In);
Доступ к сегменту памяти с помощью обработчика var, возвращаемого этим методом, осуществляется с проверками:
- Физический адрес доступного сегмента памяти должен быть выровнен в соответствии с ограничением выравнивания корневого расположения (это расположение), иначе выбрасывается
IllegalArgumentException. Обратите внимание, что ограничение выравнивания корневого расположения может быть более строгим (но не менее строгим), чем ограничение выравнивания выбранного расположения значения. - Операция доступа должна находиться внутри пространственных границ доступного сегмента памяти, иначе выбрасывается
IndexOutOfBoundsException. Это имеет место, когдаB + A <= S, гдеB— базовое смещение (определено выше),A— размер этого расположения, аS— размер доступного сегмента памяти. Обратите внимание, что размер этого расположения может быть больше, чем размер доступного расположения (например, при доступе к члену структуры). - Если предоставленный путь расположения имеет элемент открытого пути, размер которого равен
S, значение соответствующей координаты доступаlongIдолжно быть0 <= I < S, иначе выбрасываетсяIndexOutOfBoundsException. - Доступный сегмент памяти должен быть доступен потоку, выполняющему операцию доступа, иначе выбрасывается
WrongThreadException. - Для операций записи доступный сегмент памяти не должен быть только для чтения, иначе выбрасывается
IllegalArgumentException. - Область действия, связанная с доступным сегментом, должна быть активна, иначе выбрасывается
IllegalStateException.
Если выбранное расположение является расположением адреса, вызов VarHandle.get(Object...) на возвращаемом обработчике var вернёт новый сегмент памяти. Сегмент связан со глобальной областью. Кроме того, размер сегмента зависит от того, имеет ли расположение адреса целевое расположение. Точнее:
- Если расположение адреса имеет целевое расположение
T, то размер возвращаемого сегмента равенT.byteSize(); - В противном случае расположение адреса не имеет целевого расположения, и размер возвращаемого сегмента равен нулю.
VarHandle.set(Object...) может вызвать IllegalArgumentException, если сегмент памяти, представляющий адрес для записи, не является нативным сегментом памяти. Если предоставленный путь расположения имеет размер m и содержит элемент пути разыменования в позиции k (где k <= m), тогда выводятся два пути расположения P и Q, где P содержит все элементы пути от 0 до k - 1, а Q содержит все элементы пути от k + 1 до m (Q может быть пустым путём расположения, если k == m). Затем возвращаемый обработчик var вычисляется следующим образом:
VarHandle baseHandle = this.varHandle(P);
MemoryLayout target = ((AddressLayout)this.select(P)).targetLayout().get();
VarHandle targetHandle = target.varHandle(Q);
targetHandle = MethodHandles.insertCoordinates(targetHandle, 1, 0L); // always access nested targets at offset 0
targetHandle = MethodHandles.collectCoordinates(targetHandle, 0,
baseHandle.toMethodHandle(VarHandle.AccessMode.GET));
Например, рассмотрим расположение памяти, выраженное экземпляром GroupLayout, созданным следующим образом:
GroupLayout grp = java.lang.foreign.MemoryLayout.structLayout(
MemoryLayout.paddingLayout(4),
ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN).withName("value")
);
value, мы можем создать обработчик var следующим образом: VarHandle handle = grp.varHandle(PathElement.groupElement("value")); //(MemorySegment, long) -> int
- Примечание API:
- Полученный обработчик var имеет определённые ограничения режима доступа, которые характерны для всех обработчиков var, полученных из расположений памяти.
- Параметры:
-
elements- элементы пути расположения - Возвращает:
- обработчик var, который обращается к сегменту памяти по смещению, выбранному заданным путём расположения
- Выбрасывает:
-
IllegalArgumentException- если путь расположения не правильно сформирован для этого расположения -
IllegalArgumentException- если расположение, выбранное предоставленным путём, не является расположением значения
arrayElementVarHandle
VarHandle arrayElementVarHandle(MemoryLayout.PathElement... elements)
Возвращаемый обработчик переменной имеет следующие характеристики:
- его тип выводится из носителя выбранной компоновки значения;
- он имеет ведущий параметр типа
MemorySegment, представляющий доступный сегмент - последующий
longпараметр, соответствующий базовому смещению, обозначенному какB; - последующий
longпараметр, соответствующий индексу массива, обозначенный какI0. Индекс массива используется для масштабирования смещения доступа размером этой компоновки; - он имеет ноль или более хвостовых координат доступа типа
long, по одной для каждого открытого элемента пути в предоставленном пути компоновки, обозначенном какI1, I2, ... In, соответственно. Порядок этих координат доступа соответствует порядку, в котором открытые элементы пути встречаются в предоставленном пути компоновки.
Если предоставленный путь компоновки P не содержит элементов разыменования, то смещение O операции доступа вычисляется следующим образом:
O = this.byteOffsetHandle(P).invokeExact(this.scale(B, I0), I1, I2, ... In);
Более формально, обработчик метода, возвращаемый этим методом, получается из varHandle(PathElement...), следующим образом:
MethodHandles.collectCoordinates(varHandle(elements), 1, scaleHandle())
Доступ к сегменту памяти с помощью обработчика переменной, возвращаемого этим методом, подлежит следующим проверкам:
- Физический адрес доступного сегмента памяти должен быть выровнен в соответствии с ограничением выравнивания корневой компоновки (этой компоновки), иначе будет брошено исключение
IllegalArgumentException. Обратите внимание, что ограничение выравнивания корневой компоновки может быть более строгим (но не менее), чем ограничение выравнивания выбранной компоновки значения. - Операция доступа должна находиться внутри пространственных границ доступного сегмента памяти, иначе будет брошено исключение
IndexOutOfBoundsException. Это происходит, когдаB + A <= S, гдеB— базовое смещение (определено выше),A— размер этой компоновки, аS— размер доступного сегмента памяти. Обратите внимание, что размер этой компоновки может быть больше, чем размер доступной компоновки (например, при доступе к члену структуры). - Если предоставленный путь компоновки имеет открытый элемент пути, размер которого равен
S, соответствующее хвостовоеlongзначение координатыIдолжно быть равно0 <= I < S, иначе будет брошено исключениеIndexOutOfBoundsException. - Доступный сегмент памяти должен быть доступен для потока, выполняющего операцию доступа, иначе будет брошено исключение
WrongThreadException. - Для операций записи доступный сегмент памяти не должен быть только для чтения, иначе будет брошено исключение
IllegalArgumentException. - Область охватом, связанная с доступным сегментом, должна быть активна, иначе будет брошено исключение
IllegalStateException.
- API Note:
- Так как ведущая координата индекса
I0не ограничена никакой компоновкой последовательности, она может принимать любое неотрицательное значение — при условии, что вычисление смещения не переполнится или вычисленное смещение не выйдет за пределы пространственных границ доступного сегмента памяти. В связи с этим обработчики переменных, возвращаемые этим методом, могут быть особенно полезны при доступе к массивам переменной длины. - Parameters:
-
elements- элементы пути компоновки - Returns:
- обработчик переменной, который обращается к смежным элементам в сегменте памяти по смещениям, выбранным заданным путём компоновки
- Throws:
-
IllegalArgumentException- если путь компоновки не корректен для этой компоновки -
IllegalArgumentException- если компоновка, выбранная предоставленным путём, не является компоновкой значения
sliceHandle
MethodHandle sliceHandle(MemoryLayout.PathElement... elements)
Возвращаемый обработчик метода имеет следующие характеристики:
- его тип возвращаемого значения —
MemorySegment; - он имеет ведущий параметр типа
MemorySegment, соответствующий сегменту памяти, который нужно нарезать - последующий
longпараметр, соответствующий базовому смещению - он имеет ноль или более хвостовых параметров типа
long, по одному для каждого открытого элемента пути в предоставленном пути компоновки. Порядок этих параметров соответствует порядку, в котором открытые элементы пути встречаются в предоставленном пути компоновки.
Смещение O возвращаемого сегмента вычисляется так же, как и при вызове обработчика смещения байта, созданного с помощью предоставленных элементов пути.
Вычисление среза сегмента памяти с помощью обработчика метода, возвращаемого этим методом, подлежит следующим проверкам:
- Физический адрес доступного сегмента памяти должен быть выровнен в соответствии с ограничением выравнивания корневой компоновки (этой компоновки), иначе будет вызвано исключение
IllegalArgumentException. Обратите внимание, что ограничение выравнивания корневой компоновки может быть более строгим (но не менее), чем ограничение выравнивания выбранной компоновки. - Операция нарезки должна находиться внутри пространственных границ доступного сегмента памяти, иначе будет брошено исключение
IndexOutOfBoundsException. Это происходит, когдаB + A <= S, гдеB— базовое смещение (определено выше),A— размер этой компоновки, аS— размер доступного сегмента памяти. Обратите внимание, что размер этой компоновки может быть больше, чем размер доступной компоновки (например, при доступе к члену структуры). - Если предоставленный путь компоновки имеет открытый элемент пути, размер которого равен
S, соответствующее хвостовоеlongзначение координатыIдолжно быть равно0 <= I < S, иначе будет брошено исключениеIndexOutOfBoundsException.
- API Note:
- Возвращаемый обработчик метода может использоваться для получения среза сегмента памяти, аналогично
MemorySegment.asSlice(long, long), но более гибко, так как некоторые индексы могут быть указаны при вызове обработчика метода. - Parameters:
-
elements- элементы пути компоновки - Returns:
- обработчик метода, используемый для нарезки сегмента памяти по смещению, выбранному заданным путём компоновки
- Throws:
-
IllegalArgumentException- если путь компоновки не корректен для этой компоновки -
IllegalArgumentException- если путь компоновки содержит один или несколько элементов пути разыменования
select
MemoryLayout select(MemoryLayout.PathElement... elements)
- Parameters:
-
elements- элементы пути компоновки - Returns:
- компоновка, выбранная путём компоновки в
elements - Throws:
-
IllegalArgumentException- если путь компоновки не корректен для этой компоновки -
IllegalArgumentException- если путь компоновки содержит один или несколько элементов пути разыменования -
IllegalArgumentException- если путь компоновки содержит один или несколько элементов пути, которые выбирают один или несколько индексов последовательности, таких какMemoryLayout.PathElement.sequenceElement(long)иMemoryLayout.PathElement.sequenceElement(long, long))
equals
boolean equals(Object other)
true только в том случае, если указанный объект также является макетом и равен этому макету. Два макета считаются равными, если они одного типа, имеют одинаковый размер, имя и ограничение выравнивания. Кроме того, в зависимости от типа макета должны быть выполнены дополнительные условия: - два макета значений считаются равными, если у них одинаковый порядок и носитель. Кроме того, два макета адресов считаются равными, если у них также одинаковый целевой макет;
- два макета последовательностей считаются равными, если у них одинаковое количество элементов (см.
SequenceLayout.elementCount()), и если их макеты элементов (см.SequenceLayout.elementLayout()) также равны; - два макета групп считаются равными, если они одного типа (см.
StructLayout,UnionLayout) и если их макеты членов (см.GroupLayout.memberLayouts()) также равны.
hashCode
toString
paddingLayout
static PaddingLayout paddingLayout(long byteSize)
- Parameters:
-
byteSize- размер заполнения (выраженный в байтах) - Returns:
- новый макет селектора
- Throws:
-
IllegalArgumentException- еслиbyteSize <= 0
sequenceLayout
static SequenceLayout sequenceLayout(long elementCount, MemoryLayout elementLayout)
- Parameters:
-
elementCount- количество элементов последовательности -
elementLayout- макет элемента последовательности - Returns:
- новый макет последовательности с заданным макетом элемента и размером
- Throws:
-
IllegalArgumentException- еслиelementCountотрицательное -
IllegalArgumentException- еслиelementLayout.byteSize() * elementCountпереполняется -
IllegalArgumentException- еслиelementLayout.byteSize() % elementLayout.byteAlignment() != 0
structLayout
static StructLayout structLayout(MemoryLayout... elements)
- API Note:
- Этот фабричный метод не автоматически выравнивает макеты элементов, вставляя дополнительные макеты заполнения. Таким образом, следующее создание макета структуры завершится исключением: Чтобы избежать исключения, клиенты могут либо вставить дополнительные макеты заполнения:
structLayout(JAVA_SHORT, JAVA_INT);Или же, альтернативно, они могут использовать макет члена с меньшим ограничением выравнивания. Это приведёт к упакованному макету структуры:structLayout(JAVA_SHORT, MemoryLayout.paddingLayout(2), JAVA_INT);structLayout(JAVA_SHORT, JAVA_INT.withByteAlignment(2)); - Parameters:
-
elements- макеты членов макета структуры - Returns:
- макет структуры с заданными макетами членов
- Throws:
-
IllegalArgumentException- если сумма размеров в байтах макетов членов переполняется -
IllegalArgumentException- если макет члена вelementsвстречается в смещении (относительно начала макета структуры), которое несовместимо с его ограничением выравнивания
unionLayout
static UnionLayout unionLayout(MemoryLayout... elements)
- Parameters:
-
elements- макеты членов макета объединения - Returns:
- макет объединения с заданными макетами членов
© 1993, 2025, Oracle and/or its affiliates. All rights reserved.
Documentation extracted from Debian's OpenJDK Development Kit package.
Licensed under the GNU General Public License, version 2, with the Classpath Exception.
Various third party code in OpenJDK is licensed under different licenses (see Debian package).
Java and OpenJDK are trademarks or registered trademarks of Oracle and/or its affiliates.
https://download.java.net/java/early_access/jdk24/docs/api/java.base/java/lang/foreign/MemoryLayout.html