Skip to content

Commit c3a03ee

Browse files
committed
Tagged pointers for native.
1 parent 6e6ce74 commit c3a03ee

File tree

3 files changed

+88
-47
lines changed

3 files changed

+88
-47
lines changed

src/main/java/org/truffleruby/cext/UnwrapNode.java

Lines changed: 56 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
package org.truffleruby.cext;
22

3+
import static org.truffleruby.cext.ValueWrapperManager.LONG_TAG;
4+
import static org.truffleruby.cext.ValueWrapperManager.OBJECT_TAG;
5+
36
import org.truffleruby.Layouts;
7+
8+
import org.truffleruby.cext.UnwrapNodeGen.UnwrapNativeNodeGen;
9+
import org.truffleruby.language.NotProvided;
410
import org.truffleruby.language.RubyBaseNode;
511
import org.truffleruby.language.control.RaiseException;
612

@@ -18,6 +24,54 @@
1824
@ImportStatic(Message.class)
1925
public abstract class UnwrapNode extends RubyBaseNode {
2026

27+
@ImportStatic(ValueWrapperManager.class)
28+
public static abstract class UnwrapNativeNode extends RubyBaseNode {
29+
30+
public abstract Object execute(long handle);
31+
32+
@Specialization(guards = "handle == FALSE_HANDLE")
33+
public Object unwrapFalse(long handle) {
34+
return false;
35+
}
36+
37+
@Specialization(guards = "handle == TRUE_HANDLE")
38+
public Object unwrapTrue(long handle) {
39+
return true;
40+
}
41+
42+
@Specialization(guards = "handle == UNDEF_HANDLE")
43+
public Object unwrapUndef(long handle) {
44+
return NotProvided.INSTANCE;
45+
}
46+
47+
@Specialization(guards = "handle == NIL_HANDLE")
48+
public Object unwrapNil(long handle) {
49+
return nil();
50+
}
51+
52+
@Specialization(guards = "isTaggedLong(handle)")
53+
public Object unwrapTaggedLong(long handle) {
54+
return handle >> 3;
55+
}
56+
57+
@Specialization(guards = "isTaggedObject(handle)")
58+
public Object unwrapTaggedObject(long handle) {
59+
return getContext().getValueWrapperManager().getFromHandleMap(handle);
60+
}
61+
62+
public boolean isTaggedLong(long handle) {
63+
return (handle & 0x7L) == LONG_TAG;
64+
}
65+
66+
public boolean isTaggedObject(long handle) {
67+
return (handle & 0x7L) == OBJECT_TAG;
68+
}
69+
70+
public static UnwrapNativeNode create() {
71+
return UnwrapNativeNodeGen.create();
72+
}
73+
}
74+
2175
public abstract Object execute(Object value);
2276

2377
@Specialization(guards = "isWrapper(value)")
@@ -29,6 +83,7 @@ public Object unwrapValue(DynamicObject value) {
2983
public Object unwrapTypeCastObject(TruffleObject value,
3084
@Cached("IS_POINTER.createNode()") Node isPointerNode,
3185
@Cached("AS_POINTER.createNode()") Node asPointerNode,
86+
@Cached("create()") UnwrapNativeNode unwrapNativeNode,
3287
@Cached("create()") BranchProfile unsupportedProfile,
3388
@Cached("create()") BranchProfile nonPointerProfile) {
3489
if (ForeignAccess.sendIsPointer(isPointerNode, value)) {
@@ -39,17 +94,13 @@ public Object unwrapTypeCastObject(TruffleObject value,
3994
unsupportedProfile.enter();
4095
throw new RaiseException(getContext(), coreExceptions().argumentError(e.getMessage(), this, e));
4196
}
42-
return unwrapHandle(handle);
97+
return unwrapNativeNode.execute(handle);
4398
} else {
4499
nonPointerProfile.enter();
45100
throw new RaiseException(getContext(), coreExceptions().argumentError("Not a handle or a pointer", this));
46101
}
47102
}
48103

49-
private Object unwrapHandle(long handle) {
50-
return getContext().getValueWrapperManager().getFromHandleMap(handle);
51-
}
52-
53104
public static boolean isWrapper(TruffleObject value) {
54105
return ValueWrapperObjectType.isInstance(value);
55106
}

src/main/java/org/truffleruby/cext/ValueWrapperManager.java

Lines changed: 8 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,14 @@
2323
public class ValueWrapperManager {
2424

2525
static final int UNSET_HANDLE = -1;
26+
public static final int FALSE_HANDLE = 0;
27+
public static final int TRUE_HANDLE = 1;
28+
public static final int UNDEF_HANDLE = 2;
29+
public static final int NIL_HANDLE = 3;
2630

27-
@CompilationFinal private DynamicObject undefWrapper = null;
28-
@CompilationFinal private DynamicObject trueWrapper = null;
29-
@CompilationFinal private DynamicObject falseWrapper = null;
31+
public static final int LONG_TAG = 4;
32+
public static final int OBJECT_TAG = 7;
3033

31-
private final LongHashMap<DynamicObject> longMap = new LongHashMap<>(128);
3234
private final LongHashMap<WeakReference<DynamicObject>> handleMap = new LongHashMap<>(1024);
3335

3436
private final RubyContext context;
@@ -37,48 +39,17 @@ public ValueWrapperManager(RubyContext context) {
3739
this.context = context;
3840
}
3941

40-
public DynamicObject undefWrapper() {
41-
if (undefWrapper == null) {
42-
undefWrapper = Layouts.VALUE_WRAPPER.createValueWrapper(NotProvided.INSTANCE, UNSET_HANDLE);
43-
}
44-
return undefWrapper;
45-
}
46-
47-
public DynamicObject booleanWrapper(boolean value) {
48-
if (value) {
49-
if (trueWrapper == null) {
50-
trueWrapper = Layouts.VALUE_WRAPPER.createValueWrapper(true, UNSET_HANDLE);
51-
}
52-
return trueWrapper;
53-
} else {
54-
if (falseWrapper == null) {
55-
falseWrapper = createFalseWrapper();
56-
}
57-
return falseWrapper;
58-
}
59-
}
60-
61-
private DynamicObject createFalseWrapper() {
62-
// Ensure that Qfalse will by falsy in C.
63-
return Layouts.VALUE_WRAPPER.createValueWrapper(false, 0);
64-
}
65-
6642
/*
6743
* We keep a map of long wrappers that have been generated because various C extensions assume
6844
* that any given fixnum will translate to a given VALUE.
6945
*/
7046
@TruffleBoundary
7147
public synchronized DynamicObject longWrapper(long value) {
72-
DynamicObject wrapper = longMap.get(value);
73-
if (wrapper == null) {
74-
wrapper = Layouts.VALUE_WRAPPER.createValueWrapper(value, ValueWrapperManager.UNSET_HANDLE);
75-
longMap.put(value, wrapper);
76-
}
77-
return wrapper;
48+
return Layouts.VALUE_WRAPPER.createValueWrapper(value, UNSET_HANDLE);
7849
}
7950

8051
public DynamicObject doubleWrapper(double value) {
81-
return Layouts.VALUE_WRAPPER.createValueWrapper(value, ValueWrapperManager.UNSET_HANDLE);
52+
return Layouts.VALUE_WRAPPER.createValueWrapper(value, UNSET_HANDLE);
8253
}
8354

8455
@TruffleBoundary

src/main/java/org/truffleruby/cext/WrapNode.java

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
package org.truffleruby.cext;
22

3+
import static org.truffleruby.cext.ValueWrapperManager.FALSE_HANDLE;
4+
import static org.truffleruby.cext.ValueWrapperManager.TRUE_HANDLE;
5+
import static org.truffleruby.cext.ValueWrapperManager.LONG_TAG;
6+
import static org.truffleruby.cext.ValueWrapperManager.NIL_HANDLE;
7+
import static org.truffleruby.cext.ValueWrapperManager.UNDEF_HANDLE;
8+
39
import org.jcodings.specific.UTF8Encoding;
410
import org.truffleruby.Layouts;
511
import org.truffleruby.core.rope.RopeOperations;
@@ -22,12 +28,20 @@ public abstract class WrapNode extends RubyBaseNode {
2228

2329
@Specialization
2430
public DynamicObject wrapInt(int value) {
25-
return getContext().getValueWrapperManager().longWrapper(value);
31+
return wrapLong(value);
2632
}
2733

34+
private final long MIN_VALUE = 0xf000_0000_0000_0000L;
35+
private final long MAX_VALUE = 0x0fff_ffff_ffff_ffffL;
36+
2837
@Specialization
2938
public DynamicObject wrapLong(long value) {
30-
return getContext().getValueWrapperManager().longWrapper(value);
39+
if (value >= MIN_VALUE && value <= MAX_VALUE) {
40+
long val = (value << 3) | LONG_TAG;
41+
return Layouts.VALUE_WRAPPER.createValueWrapper(value, val);
42+
} else {
43+
return getContext().getValueWrapperManager().longWrapper(value);
44+
}
3145
}
3246

3347
@Specialization
@@ -37,20 +51,25 @@ public DynamicObject wrapDouble(double value) {
3751

3852
@Specialization
3953
public DynamicObject wrapBoolean(boolean value) {
40-
return getContext().getValueWrapperManager().booleanWrapper(value);
54+
return Layouts.VALUE_WRAPPER.createValueWrapper(value, value ? TRUE_HANDLE : FALSE_HANDLE);
4155
}
4256

4357
@Specialization
4458
public DynamicObject wrapUndef(NotProvided value) {
45-
return getContext().getValueWrapperManager().undefWrapper();
59+
return Layouts.VALUE_WRAPPER.createValueWrapper(value, UNDEF_HANDLE);
4660
}
4761

4862
@Specialization(guards = "isWrapped(value)")
4963
public DynamicObject wrapWrappedValue(DynamicObject value) {
5064
throw new RaiseException(getContext(), coreExceptions().argumentError(RopeOperations.encodeAscii("Wrapping wrapped object", UTF8Encoding.INSTANCE), this));
5165
}
5266

53-
@Specialization(guards = "isRubyBasicObject(value)")
67+
@Specialization(guards = "isNil(value)")
68+
public DynamicObject wrapNil(DynamicObject value) {
69+
return Layouts.VALUE_WRAPPER.createValueWrapper(nil(), NIL_HANDLE);
70+
}
71+
72+
@Specialization(guards = { "isRubyBasicObject(value)", "!isNil(value)" })
5473
public DynamicObject wrapValue(DynamicObject value,
5574
@Cached("createReader()") ReadObjectFieldNode readWrapperNode,
5675
@Cached("createWriter()") WriteObjectFieldNode writeWrapperNode) {

0 commit comments

Comments
 (0)