Skip to content

Commit

Permalink
Showing 8 changed files with 138 additions and 65 deletions.
37 changes: 19 additions & 18 deletions truffle/src/main/java/org/jruby/truffle/core/CoreLibrary.java
Original file line number Diff line number Diff line change
@@ -86,6 +86,7 @@
import org.jruby.truffle.language.backtrace.BacktraceFormatter;
import org.jruby.truffle.language.control.RaiseException;
import org.jruby.truffle.language.control.TruffleFatalException;
import org.jruby.truffle.language.globals.GlobalVariables;
import org.jruby.truffle.language.loader.CodeLoader;
import org.jruby.truffle.language.methods.DeclarationContext;
import org.jruby.truffle.language.methods.InternalMethod;
@@ -219,7 +220,7 @@ public class CoreLibrary {
private final DynamicObjectFactory handleFactory;

private final DynamicObject argv;
private final DynamicObject globalVariablesObject;
private final GlobalVariables globalVariables;
private final DynamicObject mainObject;
private final DynamicObject nilObject;
private final DynamicObject rubiniusUndefined;
@@ -552,7 +553,7 @@ public CoreLibrary(RubyContext context) {
argv = Layouts.ARRAY.createArray(Layouts.CLASS.getInstanceFactory(arrayClass), null, 0);
rubiniusUndefined = Layouts.CLASS.getInstanceFactory(objectClass).newInstance();

globalVariablesObject = Layouts.CLASS.getInstanceFactory(objectClass).newInstance();
globalVariables = new GlobalVariables(nilObject);

digestClass = defineClass(truffleModule, basicObjectClass, "Digest");
Layouts.CLASS.setInstanceFactoryUnsafe(digestClass, DigestLayoutImpl.INSTANCE.createDigestShape(digestClass, digestClass));
@@ -649,28 +650,28 @@ public void addCoreMethods() {
}

private void initializeGlobalVariables() {
DynamicObject globals = globalVariablesObject;
GlobalVariables globals = globalVariables;

globals.define("$LOAD_PATH", Layouts.ARRAY.createArray(Layouts.CLASS.getInstanceFactory(arrayClass), null, 0), 0);
globals.define("$LOADED_FEATURES", Layouts.ARRAY.createArray(Layouts.CLASS.getInstanceFactory(arrayClass), new Object[0], 0), 0);
globals.define("$:", globals.get("$LOAD_PATH", nilObject), 0);
globals.define("$\"", globals.get("$LOADED_FEATURES", nilObject), 0);
globals.define("$,", nilObject, 0);
globals.define("$*", argv, 0);
globals.define("$0", StringOperations.createString(context, StringOperations.encodeRope(context.getJRubyRuntime().getInstanceConfig().displayedFileName(), UTF8Encoding.INSTANCE)), 0);
globals.put("$LOAD_PATH", Layouts.ARRAY.createArray(Layouts.CLASS.getInstanceFactory(arrayClass), null, 0));
globals.put("$LOADED_FEATURES", Layouts.ARRAY.createArray(Layouts.CLASS.getInstanceFactory(arrayClass), new Object[0], 0));
globals.put("$:", globals.getOrDefault("$LOAD_PATH", nilObject));
globals.put("$\"", globals.getOrDefault("$LOADED_FEATURES", nilObject));
globals.put("$,", nilObject);
globals.put("$*", argv);
globals.put("$0", StringOperations.createString(context, StringOperations.encodeRope(context.getJRubyRuntime().getInstanceConfig().displayedFileName(), UTF8Encoding.INSTANCE)));

globals.define("$DEBUG", context.getJRubyRuntime().isDebug(), 0);
globals.put("$DEBUG", context.getJRubyRuntime().isDebug());

Object value = context.getJRubyRuntime().warningsEnabled() ? context.getJRubyRuntime().isVerbose() : nilObject;
globals.define("$VERBOSE", value, 0);
globals.put("$VERBOSE", value);

final DynamicObject defaultRecordSeparator = StringOperations.createString(context, StringOperations.encodeRope(CLI_RECORD_SEPARATOR, UTF8Encoding.INSTANCE));
node.freezeNode.executeFreeze(defaultRecordSeparator);

// TODO (nirvdrum 05-Feb-15) We need to support the $-0 alias as well.
globals.define("$/", defaultRecordSeparator, 0);
globals.put("$/", defaultRecordSeparator);

globals.define("$SAFE", 0, 0);
globals.put("$SAFE", 0);
}

private void initializeConstants() {
@@ -1590,16 +1591,16 @@ public DynamicObject getArgv() {
return argv;
}

public DynamicObject getGlobalVariablesObject() {
return globalVariablesObject;
public GlobalVariables getGlobalVariables() {
return globalVariables;
}

public DynamicObject getLoadPath() {
return (DynamicObject) globalVariablesObject.get("$LOAD_PATH", context.getCoreLibrary().getNilObject());
return (DynamicObject) globalVariables.getOrDefault("$LOAD_PATH", context.getCoreLibrary().getNilObject());
}

public DynamicObject getLoadedFeatures() {
return (DynamicObject) globalVariablesObject.get("$LOADED_FEATURES", context.getCoreLibrary().getNilObject());
return (DynamicObject) globalVariables.getOrDefault("$LOADED_FEATURES", context.getCoreLibrary().getNilObject());
}

public DynamicObject getMainObject() {
Original file line number Diff line number Diff line change
@@ -856,7 +856,7 @@ public RunJRubyRootNode(RubyContext context, SourceSection sourceSection) {

@Specialization
public Object runJRubyRootNode(VirtualFrame frame, @Cached("create()")IndirectCallNode callNode) {
coreLibrary().getGlobalVariablesObject().define(
coreLibrary().getGlobalVariables().put(
"$0",
StringOperations.createString(getContext(),
ByteList.create(getContext().getJRubyInterop().getArg0())));
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* Copyright (c) 2015, 2016 Oracle and/or its affiliates. All rights reserved. This
* code is released under a tri EPL/GPL/LGPL license. You can use it,
* redistribute it and/or modify it under the terms of the:
*
* Eclipse Public License version 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/

package org.jruby.truffle.language.globals;

public class GlobalVariableStorage {
public volatile Object value;

GlobalVariableStorage(Object value) {
this.value = value;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* Copyright (c) 2015, 2016 Oracle and/or its affiliates. All rights reserved. This
* code is released under a tri EPL/GPL/LGPL license. You can use it,
* redistribute it and/or modify it under the terms of the:
*
* Eclipse Public License version 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/

package org.jruby.truffle.language.globals;

import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.object.DynamicObject;

import java.util.ArrayList;
import java.util.Collection;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

public class GlobalVariables {

private final DynamicObject defaultValue;

ConcurrentMap<String, GlobalVariableStorage> variables;

public GlobalVariables(DynamicObject defaultValue) {
this.defaultValue = defaultValue;
this.variables = new ConcurrentHashMap<>();
}

public Object getOrDefault(String key, Object defaultValue) {
final Object v;
return ((v = get(key)) != null) ? v : defaultValue;
}

public Object get(String key) {
return getStorage(key).value;
}

@TruffleBoundary
public GlobalVariableStorage getStorage(String key) {
final GlobalVariableStorage currentStorage = variables.get(key);
if (currentStorage == null) {
final GlobalVariableStorage newStorage = new GlobalVariableStorage(defaultValue);
final GlobalVariableStorage wasStorage = variables.putIfAbsent(key, newStorage);
return (wasStorage == null) ? newStorage : wasStorage;

This comment has been minimized.

Copy link
@eregon

eregon Apr 7, 2016

Member

oldStorage or previousStorage would be better I think.

This comment has been minimized.

Copy link
@pitr-ch

pitr-ch Apr 7, 2016

Author Member

yeah it is not the best, I've went with racyNewStorage

} else {
return currentStorage;
}
}

public void put(String key, Object value) {
getStorage(key).value = value;
}

public Collection<DynamicObject> dynamicObjectValues() {
final Collection<GlobalVariableStorage> storages = variables.values();
final ArrayList<DynamicObject> values = new ArrayList<>(storages.size());
for (GlobalVariableStorage storage : storages) {
final Object value = storage.value;
if (value instanceof DynamicObject) {
values.add((DynamicObject) value);
}
}
return values;
}

}
Original file line number Diff line number Diff line change
@@ -9,46 +9,38 @@
*/
package org.jruby.truffle.language.globals;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.language.RubyNode;
import org.jruby.truffle.language.objects.ReadObjectFieldNode;
import org.jruby.truffle.language.objects.ReadObjectFieldNodeGen;

public class ReadGlobalVariableNode extends RubyNode {
public abstract class ReadGlobalVariableNode extends RubyNode {

private final String name;

@Child private ReadObjectFieldNode readNode;

public ReadGlobalVariableNode(RubyContext context, SourceSection sourceSection, String name) {
super(context, sourceSection);
this.name = name;
}

@Override
public Object execute(VirtualFrame frame) {
return getReadNode().execute(coreLibrary().getGlobalVariablesObject());
@Specialization
public Object read(@Cached("getStorage()") GlobalVariableStorage storage) {
return storage.value;
}

protected GlobalVariableStorage getStorage() {
return getContext().getCoreLibrary().getGlobalVariables().getStorage(name);
}

@Override
public Object isDefined(VirtualFrame frame) {
if (getReadNode().execute(coreLibrary().getGlobalVariablesObject()) != nil()) {
if (coreLibrary().getGlobalVariables().get(name) != nil()) {
return coreStrings().GLOBAL_VARIABLE.createInstance();
} else {
return nil();
}
}

private ReadObjectFieldNode getReadNode() {
if (readNode == null) {
CompilerDirectives.transferToInterpreter();
readNode = insert(ReadObjectFieldNodeGen.create(getContext(), name, nil()));
}

return readNode;
}

}
Original file line number Diff line number Diff line change
@@ -9,46 +9,36 @@
*/
package org.jruby.truffle.language.globals;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.language.RubyNode;
import org.jruby.truffle.language.objects.WriteObjectFieldNode;
import org.jruby.truffle.language.objects.WriteObjectFieldNodeGen;

public class WriteGlobalVariableNode extends RubyNode {
@NodeChild(value = "value")
public abstract class WriteGlobalVariableNode extends RubyNode {

private final String name;

@Child private RubyNode rhs;
@Child private WriteObjectFieldNode writeNode;
@Specialization
public Object write(Object value, @Cached("getStorage()") GlobalVariableStorage storage) {
return storage.value = value;
}

public WriteGlobalVariableNode(RubyContext context, SourceSection sourceSection, String name, RubyNode rhs) {
super(context, sourceSection);
this.name = name;
this.rhs = rhs;
protected GlobalVariableStorage getStorage() {
return getContext().getCoreLibrary().getGlobalVariables().getStorage(name);
}

@Override
public Object execute(VirtualFrame frame) {
final Object value = rhs.execute(frame);
getWriteNode().execute(coreLibrary().getGlobalVariablesObject(), value);
return value;
public WriteGlobalVariableNode(RubyContext context, SourceSection sourceSection, String name) {
super(context, sourceSection);
this.name = name;
}

@Override
public Object isDefined(VirtualFrame frame) {
return coreStrings().ASSIGNMENT.createInstance();
}

private WriteObjectFieldNode getWriteNode() {
if (writeNode == null) {
CompilerDirectives.transferToInterpreter();
writeNode = insert(WriteObjectFieldNodeGen.create(getContext(), name));
}

return writeNode;
}

}
Original file line number Diff line number Diff line change
@@ -101,7 +101,7 @@ public void run(DynamicObject thread, Node currentNode) {

public static void visitContextRoots(RubyContext context, Collection<DynamicObject> stack) {
// We do not want to expose the global object
stack.addAll(ObjectGraph.getAdjacentObjects(context.getCoreLibrary().getGlobalVariablesObject()));
stack.addAll(context.getCoreLibrary().getGlobalVariables().dynamicObjectValues());
stack.addAll(context.getAtExitManager().getHandlers());
stack.addAll(context.getObjectSpaceManager().getFinalizerHandlers());
}
Original file line number Diff line number Diff line change
@@ -113,12 +113,14 @@
import org.jruby.truffle.language.globals.CheckRecordSeparatorVariableTypeNode;
import org.jruby.truffle.language.globals.CheckStdoutVariableTypeNode;
import org.jruby.truffle.language.globals.ReadGlobalVariableNode;
import org.jruby.truffle.language.globals.ReadGlobalVariableNodeGen;
import org.jruby.truffle.language.globals.ReadLastBacktraceNode;
import org.jruby.truffle.language.globals.ReadMatchReferenceNode;
import org.jruby.truffle.language.globals.ReadThreadLocalGlobalVariableNode;
import org.jruby.truffle.language.globals.UpdateLastBacktraceNode;
import org.jruby.truffle.language.globals.UpdateVerbosityNode;
import org.jruby.truffle.language.globals.WriteGlobalVariableNode;
import org.jruby.truffle.language.globals.WriteGlobalVariableNodeGen;
import org.jruby.truffle.language.globals.WriteProgramNameNodeGen;
import org.jruby.truffle.language.globals.WriteReadOnlyGlobalNode;
import org.jruby.truffle.language.literal.BooleanLiteralNode;
@@ -1658,7 +1660,7 @@ public RubyNode visitGlobalAsgnNode(org.jruby.ast.GlobalAsgnNode node) {

return addNewlineIfNeeded(node, assignment);
} else {
final RubyNode writeGlobalVariableNode = new WriteGlobalVariableNode(context, sourceSection, name, rhs);
final RubyNode writeGlobalVariableNode = WriteGlobalVariableNodeGen.create(context, sourceSection, name, rhs);

final RubyNode translated;

@@ -1706,7 +1708,7 @@ public RubyNode visitGlobalVarNode(org.jruby.ast.GlobalVarNode node) {
// Instead, it reads the backtrace field of the thread-local $! value.
ret = new ReadLastBacktraceNode(context, sourceSection);
} else {
ret = new ReadGlobalVariableNode(context, sourceSection, name);
ret = ReadGlobalVariableNodeGen.create(context, sourceSection, name);
}

return addNewlineIfNeeded(node, ret);

0 comments on commit b73d9fb

Please sign in to comment.