Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jruby/jruby
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 1011130ec55a
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 65eed013a3c4
Choose a head ref
  • 2 commits
  • 9 files changed
  • 1 contributor

Commits on Apr 6, 2016

  1. 2
    Copy the full SHA
    b73d9fb View commit details
  2. Copy the full SHA
    65eed01 View commit details
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;
} 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);
26 changes: 20 additions & 6 deletions truffle/src/main/ruby/core/thread.rb
Original file line number Diff line number Diff line change
@@ -7,17 +7,19 @@
# GNU Lesser General Public License version 2.1

class Thread
# TODO (pitr-ch 06-Apr-2016): thread local variables do not have to be synchronized,
# they are only to protect against non-thread-safe Hash implementation

def [](symbol)
__thread_local_variables[symbol.to_sym]
__thread_local_variables_lock { __thread_local_variables[symbol.to_sym] }
end

def []=(symbol, value)
__thread_local_variables[symbol.to_sym] = value
__thread_local_variables_lock { __thread_local_variables[symbol.to_sym] = value }
end

def thread_variable?(symbol)
__thread_local_variables.has_key? symbol.to_sym
__thread_local_variables_lock { __thread_local_variables.has_key? symbol.to_sym }
end

alias_method :thread_variable_get, :[]
@@ -29,12 +31,24 @@ def __thread_local_variables
if defined?(@__thread_local_variables)
@__thread_local_variables
else
LOCK.synchronize { @__thread_local_variables ||= {} }
LOCK.synchronize do
@__thread_local_variables ||= {}
end
end
end

def __thread_local_variables_lock
if defined?(@__thread_local_variables_lock)
@__thread_local_variables_lock
else
LOCK.synchronize do
@__thread_local_variables_lock ||= Mutex.new
end
end.synchronize { yield }
end

def thread_variables
__thread_local_variables.keys
__thread_local_variables_lock { __thread_local_variables.keys }
end

def self.start(*args, &block)
@@ -62,7 +76,7 @@ def self.handle_interrupt(config, &block)
end

def freeze
__thread_local_variables.freeze
__thread_local_variables_lock { __thread_local_variables.freeze }
super
end