-
Notifications
You must be signed in to change notification settings - Fork 3.1k
Offer stronger guarantees under the Java Memory Model for List & Vector (using releaseFence) #6425
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
Changes from 1 commit
51d6e60
6541df7
b6d74ff
2c6d90c
054a9ac
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,10 @@ | ||
package scala.runtime; | ||
|
||
import java.lang.invoke.MethodHandle; | ||
import java.lang.invoke.MethodHandles; | ||
import java.lang.invoke.MethodType; | ||
import java.lang.reflect.Field; | ||
|
||
/** Not for public consumption. Usage by the runtime only. | ||
*/ | ||
|
||
|
@@ -117,4 +122,48 @@ public static int anyHash(Object x) { | |
|
||
/** Used as a marker object to return from PartialFunctions */ | ||
public static final Object pfMarker = new Object(); | ||
|
||
// @ForceInline would be nice here. | ||
public static void releaseFence() throws Throwable { | ||
VM.RELEASE_FENCE.invoke(); | ||
} | ||
|
||
final static class VM { | ||
static final MethodHandle RELEASE_FENCE; | ||
|
||
static { | ||
RELEASE_FENCE = mkHandle(); | ||
} | ||
|
||
private static MethodHandle mkHandle() { | ||
MethodHandles.Lookup lookup = MethodHandles.lookup(); | ||
try { | ||
return lookup.findStatic(Class.forName("java.lang.invoke.VarHandle"), "releaseFence", MethodType.methodType(Void.TYPE)); | ||
} catch (ClassNotFoundException e) { | ||
try { | ||
Class<?> unsafeClass = Class.forName("sun.misc.Unsafe"); | ||
return lookup.findVirtual(unsafeClass, "storeFence", MethodType.methodType(void.class)).bindTo(findUnsafe(unsafeClass)); | ||
} catch (NoSuchMethodException | ClassNotFoundException | IllegalAccessException e1) { | ||
ExceptionInInitializerError error = new ExceptionInInitializerError(e1); | ||
error.addSuppressed(e); | ||
throw error; | ||
} | ||
} catch (NoSuchMethodException | IllegalAccessException e) { | ||
throw new ExceptionInInitializerError(e); | ||
} | ||
} | ||
|
||
private static Object findUnsafe(Class<?> unsafeClass) throws IllegalAccessException { | ||
Object found = null; | ||
for (Field field : unsafeClass.getDeclaredFields()) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't have experience with Unsafe, so I googled a bit. https://dzone.com/articles/understanding-sunmiscunsafe suggest that you could create a new Unsafe instance instead of getting the singleton, as the latter doesn't work on Android. Not sure if that's still relevant. Apart from that, the use of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unless things changed without me noticing Android is not really Java8+ so Scala nowadays does not work on it in any case, so most likely this should not be a consideration here. Though one may want to check if I'm up to date about that. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good point re: In that case, we catch the We could do something similar here, I guess, but it would be good to alert the user somehow that the memory barriers aren't supported in that configuration. For instance, we could throw an exception that says "restart with -Dscala.barrier.noop=true to accept this limitation". Not nice :( There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This would only affect users on Java 8, of course. On 9+ we just use the public There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not very nice, but I think that's our only option. Silently skipping the fence is certainly not a good idea. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks like the proposal discussed here wasn't implemented in this PR. Should a ticket on http://github.com/scala/scala-dev/ be created to track this? |
||
if (field.getType() == unsafeClass) { | ||
field.setAccessible(true); | ||
found = field.get(null); | ||
break; | ||
} | ||
} | ||
if (found == null) throw new IllegalStateException("No instance of Unsafe found"); | ||
return found; | ||
} | ||
} | ||
} |
This file was deleted.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Echoing @adriaanm's comments from #7028 that belong over in this PR.
My rationale is that this is the where the reference to the
List
is given out. Only after this point could client code share it with another thread. My assumption is that users are only using theListBuilder
itself on a single thread, and its only the resultingList
that needs to be safely publishible.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm happy to add the fence after each mutation of
tail
, at least initially, to make things easier to reason about.