Skip to content

Commit 9189fe1

Browse files
committed
Add a ValueWrapperManager to handle multiple ruby contexts.
1 parent a9e7146 commit 9189fe1

File tree

7 files changed

+114
-83
lines changed

7 files changed

+114
-83
lines changed

src/main/java/org/truffleruby/RubyContext.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import com.oracle.truffle.api.source.SourceSection;
2424
import org.joni.Regex;
2525
import org.truffleruby.builtins.PrimitiveManager;
26+
import org.truffleruby.cext.ValueWrapperManager;
2627
import org.truffleruby.collections.WeakValueCache;
2728
import org.truffleruby.core.CoreLibrary;
2829
import org.truffleruby.core.FinalizationService;
@@ -117,6 +118,7 @@ public class RubyContext {
117118
private final WeakValueCache<RegexpCacheKey, Regex> regexpCache = new WeakValueCache<>();
118119
private final PreInitializationManager preInitializationManager;
119120
private final NativeConfiguration nativeConfiguration;
121+
private final ValueWrapperManager valueWrapperManager = new ValueWrapperManager(this);
120122

121123
private final CompilerOptions compilerOptions = Truffle.getRuntime().createCompilerOptions();
122124

@@ -778,6 +780,10 @@ public NativeConfiguration getNativeConfiguration() {
778780
return nativeConfiguration;
779781
}
780782

783+
public ValueWrapperManager getValueWrapperManager() {
784+
return valueWrapperManager;
785+
}
786+
781787
private static SecureRandom createRandomInstance() {
782788
try {
783789
/*

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public Object unwrapTypeCastObject(TruffleObject value,
4747
}
4848

4949
private Object unwrapHandle(long handle) {
50-
return ValueWrapperObjectType.getFromHandleMap(handle);
50+
return getContext().getValueWrapperManager().getFromHandleMap(handle);
5151
}
5252

5353
public static boolean isWrapper(TruffleObject value) {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
* methods to be set up which convert these value wrappers to native pointers without affecting the
1818
* semantics of the wrapped objects.
1919
*/
20-
@Layout(objectTypeSuperclass = ValueWrapperObjectType.class, implicitCastIntToLong = true)
20+
@Layout(objectTypeSuperclass = ValueWrapperObjectType.class)
2121
public interface ValueWrapperLayout {
2222

2323
DynamicObject createValueWrapper(Object object,
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/*
2+
* Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved. This
3+
* code is released under a tri EPL/GPL/LGPL license. You can use it,
4+
* redistribute it and/or modify it under the terms of the:
5+
*
6+
* Eclipse Public License version 1.0, or
7+
* GNU General Public License version 2, or
8+
* GNU Lesser General Public License version 2.1.
9+
*/
10+
package org.truffleruby.cext;
11+
12+
import java.lang.ref.WeakReference;
13+
14+
import org.truffleruby.Layouts;
15+
import org.truffleruby.RubyContext;
16+
import org.truffleruby.collections.LongHashMap;
17+
import org.truffleruby.language.NotProvided;
18+
19+
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
20+
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
21+
import com.oracle.truffle.api.object.DynamicObject;
22+
23+
public class ValueWrapperManager {
24+
25+
@CompilationFinal private DynamicObject undefWrapper = null;
26+
@CompilationFinal private DynamicObject trueWrapper = null;
27+
@CompilationFinal private DynamicObject falseWrapper = null;
28+
29+
private final LongHashMap<DynamicObject> longMap = new LongHashMap<>(128);
30+
private final LongHashMap<WeakReference<DynamicObject>> handleMap = new LongHashMap<>(1024);
31+
32+
RubyContext context;
33+
34+
public ValueWrapperManager(RubyContext context) {
35+
this.context = context;
36+
}
37+
38+
public DynamicObject undefWrapper() {
39+
return undefWrapper != null ? undefWrapper : (undefWrapper = Layouts.VALUE_WRAPPER.createValueWrapper(NotProvided.INSTANCE, ValueWrapperObjectType.UNSET_HANDLE));
40+
41+
}
42+
43+
public DynamicObject booleanWrapper(boolean value) {
44+
if (value) {
45+
return trueWrapper != null ? trueWrapper : (trueWrapper = Layouts.VALUE_WRAPPER.createValueWrapper(true, ValueWrapperObjectType.UNSET_HANDLE));
46+
} else {
47+
return falseWrapper != null ? falseWrapper : (falseWrapper = createFalseWrapper());
48+
}
49+
}
50+
51+
private DynamicObject createFalseWrapper() {
52+
// Ensure that Qfalse will by falsy in C.
53+
return Layouts.VALUE_WRAPPER.createValueWrapper(false, 0);
54+
}
55+
56+
/*
57+
* We keep a map of long wrappers that have been generated because various C extensions assume
58+
* that any given fixnum will translate to a given VALUE.
59+
*/
60+
@TruffleBoundary
61+
public synchronized DynamicObject longWrapper(long value) {
62+
DynamicObject wrapper = longMap.get(value);
63+
if (wrapper == null) {
64+
wrapper = Layouts.VALUE_WRAPPER.createValueWrapper(value, ValueWrapperObjectType.UNSET_HANDLE);
65+
longMap.put(value, wrapper);
66+
}
67+
return wrapper;
68+
}
69+
70+
public DynamicObject doubleWrapper(double value) {
71+
return Layouts.VALUE_WRAPPER.createValueWrapper(value, ValueWrapperObjectType.UNSET_HANDLE);
72+
}
73+
74+
@TruffleBoundary
75+
public synchronized void addToHandleMap(long handle, DynamicObject wrapper) {
76+
handleMap.put(handle, new WeakReference<>(wrapper));
77+
}
78+
79+
@TruffleBoundary
80+
public synchronized Object getFromHandleMap(long handle) {
81+
WeakReference<DynamicObject> ref = handleMap.get(handle);
82+
DynamicObject object;
83+
if (ref == null) {
84+
return null;
85+
}
86+
if ((object = ref.get()) == null) {
87+
return null;
88+
}
89+
return Layouts.VALUE_WRAPPER.getObject(object);
90+
}
91+
92+
@TruffleBoundary
93+
public synchronized void removeFromHandleMap(long handle) {
94+
handleMap.remove(handle);
95+
}
96+
97+
}

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,18 +60,18 @@ protected long createHandle(DynamicObject wrapper) {
6060
Pointer handlePointer = Pointer.malloc(8);
6161
long handleAddress = handlePointer.getAddress();
6262
Layouts.VALUE_WRAPPER.setHandle(wrapper, handleAddress);
63-
ValueWrapperObjectType.addToHandleMap(handleAddress, wrapper);
63+
getContext().getValueWrapperManager().addToHandleMap(handleAddress, wrapper);
6464
// Add a finaliser to remove the map entry.
6565
getContext().getFinalizationService().addFinalizer(
6666
wrapper, null, ValueWrapperObjectType.class,
67-
finalizer(handlePointer), null);
67+
finalizer(getContext().getValueWrapperManager(), handlePointer), null);
6868
return handleAddress;
6969
}
7070
}
7171

72-
private static Runnable finalizer(Pointer handle) {
72+
private static Runnable finalizer(ValueWrapperManager manager, Pointer handle) {
7373
return () -> {
74-
ValueWrapperObjectType.removeFromHandleMap(handle.getAddress());
74+
manager.removeFromHandleMap(handle.getAddress());
7575
handle.free();
7676
};
7777

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

Lines changed: 0 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,7 @@
1010
package org.truffleruby.cext;
1111

1212
import org.truffleruby.Layouts;
13-
import java.lang.ref.WeakReference;
1413

15-
import org.truffleruby.collections.LongHashMap;
16-
import org.truffleruby.language.NotProvided;
17-
18-
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
1914
import com.oracle.truffle.api.interop.ForeignAccess;
2015
import com.oracle.truffle.api.interop.TruffleObject;
2116
import com.oracle.truffle.api.object.DynamicObject;
@@ -25,77 +20,10 @@ public class ValueWrapperObjectType extends ObjectType {
2520

2621
static final int UNSET_HANDLE = -1;
2722

28-
private static DynamicObject UNDEF_WRAPPER = null;
29-
30-
private static DynamicObject TRUE_WRAPPER = null;
31-
private static DynamicObject FALSE_WRAPPER = null;
32-
33-
private static LongHashMap<DynamicObject> longMap = new LongHashMap<>(128);
34-
35-
private static LongHashMap<WeakReference<DynamicObject>> handleMap = new LongHashMap<>(1024);
36-
3723
public static DynamicObject createValueWrapper(Object value) {
3824
return Layouts.VALUE_WRAPPER.createValueWrapper(value, UNSET_HANDLE);
3925
}
4026

41-
public static synchronized DynamicObject createUndefWrapper(NotProvided value) {
42-
return UNDEF_WRAPPER != null ? UNDEF_WRAPPER : (UNDEF_WRAPPER = Layouts.VALUE_WRAPPER.createValueWrapper(value, UNSET_HANDLE));
43-
}
44-
45-
public static synchronized DynamicObject createBooleanWrapper(boolean value) {
46-
if (value) {
47-
return TRUE_WRAPPER != null ? TRUE_WRAPPER : (TRUE_WRAPPER = Layouts.VALUE_WRAPPER.createValueWrapper(true, UNSET_HANDLE));
48-
} else {
49-
return FALSE_WRAPPER != null ? FALSE_WRAPPER : (FALSE_WRAPPER = createFalseWrapper());
50-
}
51-
}
52-
53-
private static DynamicObject createFalseWrapper() {
54-
// Ensure that Qfalse will by falsy in C.
55-
return Layouts.VALUE_WRAPPER.createValueWrapper(false, 0);
56-
}
57-
58-
/*
59-
* We keep a map of long wrappers that have been generated because various C extensions assume
60-
* that any given fixnum will translate to a given VALUE.
61-
*/
62-
@TruffleBoundary
63-
public static synchronized DynamicObject createLongWrapper(long value) {
64-
DynamicObject wrapper = longMap.get(value);
65-
if (wrapper == null) {
66-
wrapper = Layouts.VALUE_WRAPPER.createValueWrapper(value, UNSET_HANDLE);
67-
longMap.put(value, wrapper);
68-
}
69-
return wrapper;
70-
}
71-
72-
@TruffleBoundary
73-
public static synchronized DynamicObject createDoubleWrapper(double value) {
74-
return Layouts.VALUE_WRAPPER.createValueWrapper(value, UNSET_HANDLE);
75-
}
76-
77-
public static synchronized void addToHandleMap(long handle, DynamicObject wrapper) {
78-
handleMap.put(handle, new WeakReference<>(wrapper));
79-
}
80-
81-
@TruffleBoundary
82-
public static synchronized Object getFromHandleMap(long handle) {
83-
WeakReference<DynamicObject> ref = handleMap.get(handle);
84-
DynamicObject object;
85-
if (ref == null) {
86-
return null;
87-
}
88-
if ((object = ref.get()) == null) {
89-
return null;
90-
}
91-
return Layouts.VALUE_WRAPPER.getObject(object);
92-
}
93-
94-
@TruffleBoundary
95-
public static synchronized void removeFromHandleMap(long handle) {
96-
handleMap.remove(handle);
97-
}
98-
9927
public static boolean isInstance(TruffleObject receiver) {
10028
return Layouts.VALUE_WRAPPER.isValueWrapper(receiver);
10129
}

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,27 +22,27 @@ public abstract class WrapNode extends RubyBaseNode {
2222

2323
@Specialization
2424
public DynamicObject wrapInt(int value) {
25-
return ValueWrapperObjectType.createLongWrapper(value);
25+
return getContext().getValueWrapperManager().longWrapper(value);
2626
}
2727

2828
@Specialization
2929
public DynamicObject wrapLong(long value) {
30-
return ValueWrapperObjectType.createLongWrapper(value);
30+
return getContext().getValueWrapperManager().longWrapper(value);
3131
}
3232

3333
@Specialization
3434
public DynamicObject wrapDouble(double value) {
35-
return ValueWrapperObjectType.createDoubleWrapper(value);
35+
return getContext().getValueWrapperManager().doubleWrapper(value);
3636
}
3737

3838
@Specialization
3939
public DynamicObject wrapBoolean(boolean value) {
40-
return ValueWrapperObjectType.createBooleanWrapper(value);
40+
return getContext().getValueWrapperManager().booleanWrapper(value);
4141
}
4242

4343
@Specialization
4444
public DynamicObject wrapUndef(NotProvided value) {
45-
return ValueWrapperObjectType.createUndefWrapper(value);
45+
return getContext().getValueWrapperManager().undefWrapper();
4646
}
4747

4848
@Specialization(guards = "isWrapped(value)")

0 commit comments

Comments
 (0)