Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8241504: Expose MemoryLayout annotations/attributes in the public API #64

Closed
wants to merge 18 commits into from
Closed
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
8ce2aeb
Rename annotations to attributes, and expose them in the public API.
JornVernee Mar 11, 2020
ab1d344
Removed abiType, added type-casting helper for attribute
JornVernee Mar 24, 2020
78c9d57
Clean up diff
JornVernee Mar 24, 2020
e09a98c
Removed trailing whitespace
JornVernee Mar 24, 2020
2d58b86
Addressed review comments + added basic tests
JornVernee Mar 24, 2020
380a1b0
Update src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/…
JornVernee Mar 24, 2020
590ef4e
Remove ML::attribute(String, Class) helper method.
JornVernee Mar 24, 2020
d3baa35
Merge branch 'Attributes' of https://github.com/JornVernee/panama-for…
JornVernee Mar 24, 2020
b5a5df5
Backport 8237573 to foreign-abi
JornVernee Mar 26, 2020
a0bb125
Rename annotations to attributes, and expose them in the public API.
JornVernee Mar 11, 2020
880ec1e
Removed abiType, added type-casting helper for attribute
JornVernee Mar 24, 2020
b845363
Clean up diff
JornVernee Mar 24, 2020
c21fb15
Removed trailing whitespace
JornVernee Mar 24, 2020
98becba
Addressed review comments + added basic tests
JornVernee Mar 24, 2020
0feb882
Remove ML::attribute(String, Class) helper method.
JornVernee Mar 24, 2020
4f6098f
Update src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/…
JornVernee Mar 24, 2020
0d76e22
Don't filter by type when looking up layout attributes, and instead f…
JornVernee Mar 26, 2020
19e5560
Merge branch 'Attributes' of https://github.com/JornVernee/panama-for…
JornVernee Mar 26, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -40,57 +40,60 @@
import java.util.Objects;
import java.util.Optional;
import java.util.OptionalLong;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static java.lang.constant.ConstantDescs.BSM_INVOKE;
import static java.lang.constant.ConstantDescs.CD_String;
import static java.lang.constant.ConstantDescs.CD_long;

abstract class AbstractLayout implements MemoryLayout {
// memory layout attribute key for layout name
static final String NAME = "name";

private final OptionalLong size;
final long alignment;
protected final Map<String, Constable> annotations;
protected final Map<String, Constable> attributes;

public AbstractLayout(OptionalLong size, long alignment, Map<String, Constable> annotations) {
public AbstractLayout(OptionalLong size, long alignment, Map<String, Constable> attributes) {
this.size = size;
this.alignment = alignment;
this.annotations = Collections.unmodifiableMap(annotations);
this.attributes = Collections.unmodifiableMap(attributes);
}

Optional<String> optName() {
return Optional.ofNullable((String)annotations.get(NAME));
}

// memory layout annotation key for abi native type
static final String NATIVE_TYPE = "abi/native-type";

Optional<SystemABI.Type> optABIType() {
return Optional.ofNullable((SystemABI.Type)annotations.get(NATIVE_TYPE));
@Override
public AbstractLayout withName(String name) {
return withAttribute(NAME, name);
}

@Override
public AbstractLayout withName(String name) {
return withAnnotation(NAME, name);
public final Optional<String> name() {
return attribute(NAME).map(String.class::cast);
}

@SuppressWarnings("unchecked")
public <Z extends AbstractLayout> Z withAnnotation(String name, Constable value) {
Map<String, Constable> new_annos = new HashMap<>(annotations);
new_annos.put(name, value);
return (Z)dup(alignment, new_annos);
@Override
public Optional<Constable> attribute(String name) {
return Optional.ofNullable(attributes.get(name));
}

@Override
public final Optional<String> name() {
return optName();
public Stream<String> attributes() {
return attributes.keySet().stream();
}

@Override
public final Optional<SystemABI.Type> abiType() {
return optABIType();
public AbstractLayout withAttribute(String name, Constable value) {
Map<String, Constable> newAttributes = new HashMap<>(attributes);
newAttributes.put(name, value);
return dup(alignment, newAttributes);
}

abstract AbstractLayout dup(long alignment, Map<String, Constable> annos);

@Override
public AbstractLayout withBitAlignment(long alignmentBits) {
checkAlignment(alignmentBits);
return dup(alignmentBits, annotations);
return dup(alignmentBits, attributes);
}

void checkAlignment(long alignmentBitCount) {
Expand Down Expand Up @@ -134,22 +137,40 @@ private static UnsupportedOperationException badSizeException() {
}

String decorateLayoutString(String s) {
if (optName().isPresent()) {
s = String.format("%s(%s)", s, optName().get());
if (name().isPresent()) {
s = String.format("%s(%s)", s, name().get());
}
if (!hasNaturalAlignment()) {
s = alignment + "%" + s;
}
if (!attributes.isEmpty()) {
s += attributes.entrySet().stream()
.map(e -> e.getKey() + "=" + e.getValue())
.collect(Collectors.joining(",", "[", "]"));
}
return s;
}

<T> DynamicConstantDesc<T> decorateLayoutConstant(DynamicConstantDesc<T> desc) {
if (!hasNaturalAlignment()) {
desc = DynamicConstantDesc.ofNamed(BSM_INVOKE, "withBitAlignment", desc.constantType(), MH_WITH_BIT_ALIGNMENT,
desc, bitAlignment());
}
for (var e : attributes.entrySet()) {
desc = DynamicConstantDesc.ofNamed(BSM_INVOKE, "withAttribute", desc.constantType(), MH_WITH_ATTRIBUTE,
desc, e.getKey(), e.getValue().describeConstable().orElseThrow());
}

return desc;
}

boolean hasNaturalAlignment() {
return size.isPresent() && size.getAsLong() == alignment;
}

@Override
public int hashCode() {
return annotations.hashCode() << Long.hashCode(alignment);
return attributes.hashCode() << Long.hashCode(alignment);
}

@Override
Expand All @@ -162,19 +183,17 @@ public boolean equals(Object other) {
return false;
}

return Objects.equals(annotations, ((AbstractLayout)other).annotations) &&
Objects.equals(alignment, ((AbstractLayout)other).alignment);
return Objects.equals(attributes, ((AbstractLayout) other).attributes) &&
Objects.equals(alignment, ((AbstractLayout) other).alignment);
}

static final String NAME = "name";

/*** Helper constants for implementing Layout::describeConstable ***/

static final DirectMethodHandleDesc BSM_GET_STATIC_FINAL
= ConstantDescs.ofConstantBootstrap(ConstantDescs.CD_ConstantBootstraps, "getStaticFinal",
ConstantDescs.CD_Object, ConstantDescs.CD_Class);

static final ClassDesc CD_LAYOUT = MemoryLayout.class.describeConstable().get();
static final ClassDesc CD_MEMORY_LAYOUT = MemoryLayout.class.describeConstable().get();

static final ClassDesc CD_VALUE_LAYOUT = ValueLayout.class.describeConstable().get();

Expand All @@ -186,6 +205,8 @@ public boolean equals(Object other) {

static final ClassDesc CD_FUNCTION_DESC = FunctionDescriptor.class.describeConstable().get();

static final ClassDesc CD_Constable = Constable.class.describeConstable().get();

static final ConstantDesc BIG_ENDIAN = DynamicConstantDesc.ofNamed(BSM_GET_STATIC_FINAL, "BIG_ENDIAN", CD_BYTEORDER, CD_BYTEORDER);

static final ConstantDesc LITTLE_ENDIAN = DynamicConstantDesc.ofNamed(BSM_GET_STATIC_FINAL, "LITTLE_ENDIAN", CD_BYTEORDER, CD_BYTEORDER);
Expand All @@ -194,27 +215,33 @@ public boolean equals(Object other) {

static final ConstantDesc FALSE = DynamicConstantDesc.ofNamed(BSM_GET_STATIC_FINAL, "FALSE", ConstantDescs.CD_Boolean, ConstantDescs.CD_Boolean);

static final MethodHandleDesc MH_PADDING = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_STATIC, CD_LAYOUT, "ofPaddingBits",
MethodTypeDesc.of(CD_LAYOUT, ConstantDescs.CD_long));
static final MethodHandleDesc MH_PADDING = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_STATIC, CD_MEMORY_LAYOUT, "ofPaddingBits",
MethodTypeDesc.of(CD_MEMORY_LAYOUT, CD_long));

static final MethodHandleDesc MH_VALUE = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_STATIC, CD_MEMORY_LAYOUT, "ofValueBits",
MethodTypeDesc.of(CD_VALUE_LAYOUT, CD_long, CD_BYTEORDER));

static final MethodHandleDesc MH_SIZED_SEQUENCE = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_STATIC, CD_MEMORY_LAYOUT, "ofSequence",
MethodTypeDesc.of(CD_SEQUENCE_LAYOUT, CD_long, CD_MEMORY_LAYOUT));

static final MethodHandleDesc MH_VALUE = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_STATIC, CD_LAYOUT, "ofValueBits",
MethodTypeDesc.of(CD_VALUE_LAYOUT, ConstantDescs.CD_long, CD_BYTEORDER));
static final MethodHandleDesc MH_UNSIZED_SEQUENCE = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_STATIC, CD_MEMORY_LAYOUT, "ofSequence",
MethodTypeDesc.of(CD_SEQUENCE_LAYOUT, CD_MEMORY_LAYOUT));

static final MethodHandleDesc MH_SIZED_SEQUENCE = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_STATIC, CD_LAYOUT, "ofSequence",
MethodTypeDesc.of(CD_SEQUENCE_LAYOUT, ConstantDescs.CD_long, CD_LAYOUT));
static final MethodHandleDesc MH_STRUCT = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_STATIC, CD_MEMORY_LAYOUT, "ofStruct",
MethodTypeDesc.of(CD_GROUP_LAYOUT, CD_MEMORY_LAYOUT.arrayType()));

static final MethodHandleDesc MH_UNSIZED_SEQUENCE = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_STATIC, CD_LAYOUT, "ofSequence",
MethodTypeDesc.of(CD_SEQUENCE_LAYOUT, CD_LAYOUT));
static final MethodHandleDesc MH_UNION = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_STATIC, CD_MEMORY_LAYOUT, "ofUnion",
MethodTypeDesc.of(CD_GROUP_LAYOUT, CD_MEMORY_LAYOUT.arrayType()));

static final MethodHandleDesc MH_STRUCT = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_STATIC, CD_LAYOUT, "ofStruct",
MethodTypeDesc.of(CD_GROUP_LAYOUT, CD_LAYOUT.arrayType()));
static final MethodHandleDesc MH_VOID_FUNCTION = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.STATIC, CD_FUNCTION_DESC, "ofVoid",
MethodTypeDesc.of(CD_FUNCTION_DESC, CD_MEMORY_LAYOUT.arrayType()));

static final MethodHandleDesc MH_UNION = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_STATIC, CD_LAYOUT, "ofUnion",
MethodTypeDesc.of(CD_GROUP_LAYOUT, CD_LAYOUT.arrayType()));
static final MethodHandleDesc MH_FUNCTION = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.STATIC, CD_FUNCTION_DESC, "of",
MethodTypeDesc.of(CD_FUNCTION_DESC, CD_MEMORY_LAYOUT, CD_MEMORY_LAYOUT.arrayType()));

static final MethodHandleDesc MH_VOID_FUNCTION = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_STATIC, CD_FUNCTION_DESC, "ofVoid",
MethodTypeDesc.of(CD_FUNCTION_DESC, CD_LAYOUT.arrayType()));
static final MethodHandleDesc MH_WITH_BIT_ALIGNMENT = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_VIRTUAL, CD_MEMORY_LAYOUT, "withBitAlignment",
MethodTypeDesc.of(CD_MEMORY_LAYOUT, CD_long));

static final MethodHandleDesc MH_FUNCTION = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_STATIC, CD_FUNCTION_DESC, "of",
MethodTypeDesc.of(CD_FUNCTION_DESC, CD_LAYOUT, CD_LAYOUT.arrayType()));
static final MethodHandleDesc MH_WITH_ATTRIBUTE = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_VIRTUAL, CD_MEMORY_LAYOUT, "withAttribute",
MethodTypeDesc.of(CD_MEMORY_LAYOUT, CD_String, CD_Constable));
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import java.lang.constant.DynamicConstantDesc;
import java.lang.constant.MethodHandleDesc;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
Expand Down Expand Up @@ -105,8 +106,8 @@ long alignof(List<MemoryLayout> elems) {
this(kind, elements, kind.alignof(elements), Map.of());
}

GroupLayout(Kind kind, List<MemoryLayout> elements, long alignment, Map<String, Constable> annotations) {
super(kind.sizeof(elements), alignment, annotations);
GroupLayout(Kind kind, List<MemoryLayout> elements, long alignment, Map<String, Constable> attributes) {
super(kind.sizeof(elements), alignment, attributes);
this.kind = kind;
this.elements = elements;
}
Expand Down Expand Up @@ -170,8 +171,8 @@ public int hashCode() {
}

@Override
GroupLayout dup(long alignment, Map<String, Constable> annotations) {
return new GroupLayout(kind, elements, alignment, annotations);
GroupLayout dup(long alignment, Map<String, Constable> attributes) {
return new GroupLayout(kind, elements, alignment, attributes);
}

@Override
Expand All @@ -186,9 +187,9 @@ public Optional<DynamicConstantDesc<GroupLayout>> describeConstable() {
for (int i = 0 ; i < elements.size() ; i++) {
constants[i + 1] = elements.get(i).describeConstable().get();
}
return Optional.of(DynamicConstantDesc.ofNamed(
return Optional.of(decorateLayoutConstant(DynamicConstantDesc.ofNamed(
ConstantDescs.BSM_INVOKE, kind.name().toLowerCase(),
CD_GROUP_LAYOUT, constants));
CD_GROUP_LAYOUT, constants)));
}

//hack: the declarations below are to make javadoc happy; we could have used generics in AbstractLayout
Expand All @@ -209,4 +210,12 @@ public GroupLayout withName(String name) {
public GroupLayout withBitAlignment(long alignmentBits) {
return (GroupLayout)super.withBitAlignment(alignmentBits);
}

/**
* {@inheritDoc}
*/
@Override
public GroupLayout withAttribute(String name, Constable value) {
return (GroupLayout)super.withAttribute(name, value);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import java.util.Set;
import java.util.function.Function;
import java.util.function.UnaryOperator;
import java.util.stream.Stream;

/**
* A memory layout can be used to describe the contents of a memory segment in a <em>language neutral</em> fashion.
Expand Down Expand Up @@ -226,13 +227,6 @@ default long byteSize() {
*/
Optional<String> name();

/**
* Return the ABI <em>type</em> (if any) associated with this layout.
*
* @return the layout ABI <em>type</em> (if any).
*/
Optional<SystemABI.Type> abiType();

/**
* Creates a new layout which features the desired layout <em>name</em>.
*
Expand Down Expand Up @@ -291,6 +285,30 @@ default long byteAlignment() {
*/
MemoryLayout withBitAlignment(long bitAlignment);

/**
* Returns the attribute with the given name if it exists, or an empty optional
*
* @param name the name of the attribute
* @return the optional attribute
*/
Optional<Constable> attribute(String name);

/**
* Returns a new MemoryLayout with the given additional attribute
*
* @param name the name of the attribute
* @param value the value of the attribute
* @return the new MemoryLayout
*/
MemoryLayout withAttribute(String name, Constable value);

/**
* Returns a stream of the names of the attributes of this layout
*
* @return the stream of names
*/
Stream<String> attributes();

/**
* Computes the offset, in bits, of the layout selected by a given layout path, where the path is considered rooted in this
* layout.
Expand Down
Loading