Skip to content

Commit 5c54d4a

Browse files
committed
Add checks whether the GlobalVariableStorage is still valid
* Add a convenience GlobalVariableReader class for CoreLibrary.
1 parent 3179da6 commit 5c54d4a

9 files changed

+91
-43
lines changed

src/main/java/org/truffleruby/core/CoreLibrary.java

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@
5757
import org.truffleruby.language.control.JavaException;
5858
import org.truffleruby.language.control.RaiseException;
5959
import org.truffleruby.language.control.TruffleFatalException;
60-
import org.truffleruby.language.globals.GlobalVariableStorage;
60+
import org.truffleruby.language.globals.GlobalVariableReader;
6161
import org.truffleruby.language.globals.GlobalVariables;
6262
import org.truffleruby.language.loader.CodeLoader;
6363
import org.truffleruby.language.loader.FileLoader;
@@ -217,12 +217,12 @@ public class CoreLibrary {
217217
@CompilationFinal private SharedMethodInfo kernelPublicSendInfo;
218218
@CompilationFinal private SharedMethodInfo truffleBootMainInfo;
219219

220-
@CompilationFinal private GlobalVariableStorage loadPathStorage;
221-
@CompilationFinal private GlobalVariableStorage loadedFeaturesStorage;
222-
@CompilationFinal private GlobalVariableStorage debugStorage;
223-
@CompilationFinal private GlobalVariableStorage verboseStorage;
224-
@CompilationFinal private GlobalVariableStorage stdinStorage;
225-
@CompilationFinal private GlobalVariableStorage stderrStorage;
220+
@CompilationFinal private GlobalVariableReader loadPathReader;
221+
@CompilationFinal private GlobalVariableReader loadedFeaturesReader;
222+
@CompilationFinal private GlobalVariableReader debugReader;
223+
@CompilationFinal private GlobalVariableReader verboseReader;
224+
@CompilationFinal private GlobalVariableReader stdinReader;
225+
@CompilationFinal private GlobalVariableReader stderrReader;
226226

227227
private final ConcurrentMap<String, Boolean> patchFiles;
228228

@@ -672,13 +672,12 @@ private Object verbosityOption() {
672672
}
673673

674674
private void findGlobalVariableStorage() {
675-
GlobalVariables globals = globalVariables;
676-
loadPathStorage = globals.getStorage("$LOAD_PATH");
677-
loadedFeaturesStorage = globals.getStorage("$LOADED_FEATURES");
678-
debugStorage = globals.getStorage("$DEBUG");
679-
verboseStorage = globals.getStorage("$VERBOSE");
680-
stdinStorage = globals.getStorage("$stdin");
681-
stderrStorage = globals.getStorage("$stderr");
675+
loadPathReader = globalVariables.getReader("$LOAD_PATH");
676+
loadedFeaturesReader = globalVariables.getReader("$LOADED_FEATURES");
677+
debugReader = globalVariables.getReader("$DEBUG");
678+
verboseReader = globalVariables.getReader("$VERBOSE");
679+
stdinReader = globalVariables.getReader("$stdin");
680+
stderrReader = globalVariables.getReader("$stderr");
682681
}
683682

684683
private void initializeConstants() {
@@ -1094,24 +1093,24 @@ public GlobalVariables getGlobalVariables() {
10941093
}
10951094

10961095
public DynamicObject getLoadPath() {
1097-
return (DynamicObject) loadPathStorage.getValue();
1096+
return (DynamicObject) loadPathReader.getValue(globalVariables);
10981097
}
10991098

11001099
public DynamicObject getLoadedFeatures() {
1101-
return (DynamicObject) loadedFeaturesStorage.getValue();
1100+
return (DynamicObject) loadedFeaturesReader.getValue(globalVariables);
11021101
}
11031102

11041103
public Object getDebug() {
1105-
if (debugStorage != null) {
1106-
return debugStorage.getValue();
1104+
if (debugReader != null) {
1105+
return debugReader.getValue(globalVariables);
11071106
} else {
11081107
return context.getOptions().DEBUG;
11091108
}
11101109
}
11111110

11121111
private Object verbosity() {
1113-
if (verboseStorage != null) {
1114-
return verboseStorage.getValue();
1112+
if (verboseReader != null) {
1113+
return verboseReader.getValue(globalVariables);
11151114
} else {
11161115
return verbosityOption();
11171116
}
@@ -1128,11 +1127,11 @@ public boolean isVerbose() {
11281127
}
11291128

11301129
public Object getStdin() {
1131-
return stdinStorage.getValue();
1130+
return stdinReader.getValue(globalVariables);
11321131
}
11331132

11341133
public Object getStderr() {
1135-
return stderrStorage.getValue();
1134+
return stderrReader.getValue(globalVariables);
11361135
}
11371136

11381137
public DynamicObject getMainObject() {
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Copyright (c) 2019 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.language.globals;
11+
12+
import com.oracle.truffle.api.CompilerDirectives;
13+
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
14+
15+
public class GlobalVariableReader {
16+
17+
private final String name;
18+
@CompilationFinal private GlobalVariableStorage storage;
19+
20+
GlobalVariableReader(GlobalVariables globalVariables, String name) {
21+
this.name = name;
22+
this.storage = globalVariables.getStorage(name);
23+
}
24+
25+
public Object getValue(GlobalVariables globalVariables) {
26+
if (!storage.getValidAssumption().isValid()) {
27+
CompilerDirectives.transferToInterpreterAndInvalidate();
28+
storage = globalVariables.getStorage(name);
29+
}
30+
31+
return storage.getValue();
32+
}
33+
34+
}

src/main/java/org/truffleruby/language/globals/GlobalVariableStorage.java

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import com.oracle.truffle.api.Assumption;
1313
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
1414
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
15+
import com.oracle.truffle.api.Truffle;
1516
import com.oracle.truffle.api.object.DynamicObject;
1617
import com.oracle.truffle.api.utilities.CyclicAssumption;
1718
import org.truffleruby.RubyContext;
@@ -21,6 +22,7 @@ public class GlobalVariableStorage {
2122

2223
private static final Object UNSET_VALUE = NotProvided.INSTANCE;
2324

25+
private final Assumption validAssumption = Truffle.getRuntime().createAssumption("global variable not aliased");
2426
private final CyclicAssumption unchangedAssumption = new CyclicAssumption("global variable unchanged");
2527
private int changes = 0;
2628

@@ -35,21 +37,17 @@ public class GlobalVariableStorage {
3537
private final DynamicObject isDefined;
3638

3739
GlobalVariableStorage(Object defaultValue, DynamicObject getter, DynamicObject setter, DynamicObject isDefined) {
38-
this.defaultValue = defaultValue;
39-
this.value = UNSET_VALUE;
40-
this.getter = getter;
41-
this.setter = setter;
42-
this.isDefined = isDefined;
43-
assert ((getter == null) == (setter == null)) & ((getter == null) == (isDefined == null));
40+
this(UNSET_VALUE, defaultValue, getter, setter, isDefined);
4441
}
4542

4643
GlobalVariableStorage(Object value, Object defaultValue, DynamicObject getter, DynamicObject setter, DynamicObject isDefined) {
44+
assert ((getter == null) == (setter == null)) & ((getter == null) == (isDefined == null));
45+
4746
this.defaultValue = defaultValue;
4847
this.value = value;
4948
this.getter = getter;
5049
this.setter = setter;
5150
this.isDefined = isDefined;
52-
assert ((getter == null) == (setter == null)) & ((getter == null) == (isDefined == null));
5351
}
5452

5553
public Object getValue() {
@@ -81,6 +79,10 @@ public DynamicObject getIsDefined() {
8179
return isDefined;
8280
}
8381

82+
public Assumption getValidAssumption() {
83+
return validAssumption;
84+
}
85+
8486
public Assumption getUnchangedAssumption() {
8587
return unchangedAssumption.getAssumption();
8688
}

src/main/java/org/truffleruby/language/globals/GlobalVariables.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,23 @@ public String getOriginalName(String name) {
3434
return aliases.getOrDefault(name, name);
3535
}
3636

37+
/**
38+
* The returned storage must be checked if it is still valid with
39+
* {@link GlobalVariableStorage#getValidAssumption()}. A storage
40+
* becomes invalid when it is aliased and therefore the storage
41+
* instance needs to change.
42+
*/
3743
@TruffleBoundary
3844
public GlobalVariableStorage getStorage(String name) {
3945
final String originalName = getOriginalName(name);
4046
return ConcurrentOperations.getOrCompute(variables, originalName,
4147
k -> new GlobalVariableStorage(defaultValue, null, null, null));
4248
}
4349

50+
public GlobalVariableReader getReader(String name) {
51+
return new GlobalVariableReader(this, name);
52+
}
53+
4454
public GlobalVariableStorage put(String name, Object value) {
4555
assert !variables.containsKey(name);
4656
final GlobalVariableStorage storage = new GlobalVariableStorage(value, defaultValue, null, null, null);
@@ -62,6 +72,7 @@ public boolean contains(String name) {
6272

6373
@TruffleBoundary
6474
public void alias(String oldName, String newName) {
75+
// TODO
6576
// Record an alias of an alias against the original.
6677
oldName = aliases.getOrDefault(oldName, oldName);
6778
aliases.put(newName, oldName);

src/main/java/org/truffleruby/language/globals/IsDefinedGlobalVariableNode.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public IsDefinedGlobalVariableNode(String name) {
3232

3333
public abstract Object executeIsDefined(VirtualFrame frame);
3434

35-
@Specialization(guards = "storage.isSimple()")
35+
@Specialization(guards = "storage.isSimple()", assumptions = "storage.getValidAssumption()")
3636
public Object executeDefined(
3737
@Cached("getStorage()") GlobalVariableStorage storage) {
3838
if (storage.isDefined()) {
@@ -42,15 +42,15 @@ public Object executeDefined(
4242
}
4343
}
4444

45-
@Specialization(guards = { "storage.hasHooks()", "arity == 0" })
45+
@Specialization(guards = { "storage.hasHooks()", "arity == 0" }, assumptions = "storage.getValidAssumption()")
4646
public Object executeDefinedHooks(
4747
@Cached("getStorage()") GlobalVariableStorage storage,
4848
@Cached("isDefinedArity(storage)") int arity,
4949
@Cached("new()") YieldNode yieldNode) {
5050
return yieldNode.dispatch(storage.getIsDefined());
5151
}
5252

53-
@Specialization(guards = { "storage.hasHooks()", "arity == 1" })
53+
@Specialization(guards = { "storage.hasHooks()", "arity == 1" }, assumptions = "storage.getValidAssumption()")
5454
public Object executeDefinedHooksWithBinding(VirtualFrame frame,
5555
@Cached("getStorage()") GlobalVariableStorage storage,
5656
@Cached("isDefinedArity(storage)") int arity,

src/main/java/org/truffleruby/language/globals/ReadGlobalVariableNode.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,22 +28,22 @@ public ReadGlobalVariableNode(String name) {
2828
this.name = name;
2929
}
3030

31-
@Specialization(guards = "storage.isSimple()")
31+
@Specialization(guards = "storage.isSimple()", assumptions = "storage.getValidAssumption()")
3232
public Object read(
3333
@Cached("getStorage()") GlobalVariableStorage storage,
3434
@Cached("create(name)") ReadSimpleGlobalVariableNode simpleNode) {
3535
return simpleNode.execute();
3636
}
3737

38-
@Specialization(guards = { "storage.hasHooks()", "arity == 0" })
38+
@Specialization(guards = { "storage.hasHooks()", "arity == 0" }, assumptions = "storage.getValidAssumption()")
3939
public Object readHooks(VirtualFrame frame,
4040
@Cached("getStorage()") GlobalVariableStorage storage,
4141
@Cached("getterArity(storage)") int arity,
4242
@Cached("new()") YieldNode yieldNode) {
4343
return yieldNode.dispatch(storage.getGetter());
4444
}
4545

46-
@Specialization(guards = { "storage.hasHooks()", "arity == 1" })
46+
@Specialization(guards = { "storage.hasHooks()", "arity == 1" }, assumptions = "storage.getValidAssumption()")
4747
public Object readHooksWithBinding(VirtualFrame frame,
4848
@Cached("getStorage()") GlobalVariableStorage storage,
4949
@Cached("getterArity(storage)") int arity,

src/main/java/org/truffleruby/language/globals/ReadSimpleGlobalVariableNode.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,14 @@ public ReadSimpleGlobalVariableNode(String name) {
1919

2020
public abstract Object execute();
2121

22-
@Specialization(assumptions = "storage.getUnchangedAssumption()")
22+
@Specialization(assumptions = { "storage.getUnchangedAssumption()", "storage.getValidAssumption()" })
2323
public Object readConstant(
2424
@Cached("getStorage()") GlobalVariableStorage storage,
2525
@Cached("storage.getValue()") Object value) {
2626
return value;
2727
}
2828

29-
@Specialization
29+
@Specialization(assumptions = "storage.getValidAssumption()")
3030
public Object read(
3131
@Cached("getStorage()") GlobalVariableStorage storage) {
3232
return storage.getValue();

src/main/java/org/truffleruby/language/globals/WriteGlobalVariableNode.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,15 @@ public WriteGlobalVariableNode(String name) {
2828
this.name = name;
2929
}
3030

31-
@Specialization(guards = "storage.isSimple()")
31+
@Specialization(guards = "storage.isSimple()", assumptions = "storage.getValidAssumption()")
3232
public Object write(VirtualFrame frame, Object value,
3333
@Cached("getStorage()") GlobalVariableStorage storage,
3434
@Cached("create(name)") WriteSimpleGlobalVariableNode simpleNode) {
3535
simpleNode.execute(value);
3636
return value;
3737
}
3838

39-
@Specialization(guards = { "storage.hasHooks()", "arity != 2" })
39+
@Specialization(guards = { "storage.hasHooks()", "arity != 2" }, assumptions = "storage.getValidAssumption()")
4040
public Object writeHooks(VirtualFrame frame, Object value,
4141
@Cached("getStorage()") GlobalVariableStorage storage,
4242
@Cached("setterArity(storage)") int arity,
@@ -45,7 +45,7 @@ public Object writeHooks(VirtualFrame frame, Object value,
4545
return value;
4646
}
4747

48-
@Specialization(guards = { "storage.hasHooks()", "arity == 2" })
48+
@Specialization(guards = { "storage.hasHooks()", "arity == 2" }, assumptions = "storage.getValidAssumption()")
4949
public Object writeHooksWithBinding(VirtualFrame frame, Object value,
5050
@Cached("getStorage()") GlobalVariableStorage storage,
5151
@Cached("setterArity(storage)") int arity,

src/main/java/org/truffleruby/language/globals/WriteSimpleGlobalVariableNode.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ public WriteSimpleGlobalVariableNode(String name) {
2525

2626
public abstract Object execute(Object value);
2727

28-
@Specialization(guards = "referenceEqualNode.executeReferenceEqual(value, previousValue)", assumptions = "storage.getUnchangedAssumption()")
28+
@Specialization(guards = "referenceEqualNode.executeReferenceEqual(value, previousValue)",
29+
assumptions = { "storage.getUnchangedAssumption()", "storage.getValidAssumption()" })
2930
public Object writeTryToKeepConstant(Object value,
3031
@Cached("getStorage()") GlobalVariableStorage storage,
3132
@Cached("storage.getValue()") Object previousValue) {
@@ -35,7 +36,8 @@ public Object writeTryToKeepConstant(Object value,
3536
return previousValue;
3637
}
3738

38-
@Specialization(guards = "storage.isAssumeConstant()", assumptions = "storage.getUnchangedAssumption()")
39+
@Specialization(guards = "storage.isAssumeConstant()",
40+
assumptions = { "storage.getUnchangedAssumption()", "storage.getValidAssumption()" })
3941
public Object writeAssumeConstant(Object value,
4042
@Cached("getStorage()") GlobalVariableStorage storage) {
4143
if (getContext().getSharedObjects().isSharing()) {
@@ -46,7 +48,7 @@ public Object writeAssumeConstant(Object value,
4648
return value;
4749
}
4850

49-
@Specialization(guards = "!storage.isAssumeConstant()", replaces = "writeAssumeConstant")
51+
@Specialization(guards = "!storage.isAssumeConstant()", assumptions = "storage.getValidAssumption()", replaces = "writeAssumeConstant")
5052
public Object write(Object value,
5153
@Cached("getStorage()") GlobalVariableStorage storage) {
5254
if (getContext().getSharedObjects().isSharing()) {

0 commit comments

Comments
 (0)