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: 428e3b269f12
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: ce46667d586e
Choose a head ref
  • 6 commits
  • 12 files changed
  • 1 contributor

Commits on Jul 11, 2015

  1. Verified

    This commit was signed with the committer’s verified signature.
    headius Charles Oliver Nutter
    Copy the full SHA
    aff3db9 View commit details
  2. Add missing stdlib require

    eregon committed Jul 11, 2015

    Verified

    This commit was signed with the committer’s verified signature.
    headius Charles Oliver Nutter
    Copy the full SHA
    83e437d View commit details
  3. Copy the full SHA
    43561c1 View commit details
  4. Copy the full SHA
    63d867b View commit details
  5. Copy the full SHA
    93e44e7 View commit details
  6. Copy the full SHA
    ce46667 View commit details
1 change: 1 addition & 0 deletions spec/ruby/core/module/autoload_spec.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
require File.expand_path('../../../spec_helper', __FILE__)
require File.expand_path('../fixtures/classes', __FILE__)
require 'thread'

describe "Module#autoload?" do
it "returns the name of the file that will be autoloaded" do
3 changes: 0 additions & 3 deletions spec/truffle/tags/core/kernel/autoload_tags.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1 @@
fails:Kernel.autoload sets the autoload constant in Object's constant table
fails:Kernel.autoload calls #to_path on non-String filenames
fails(locale problem on CI):Kernel#autoload when Object is frozen raises a RuntimeError before defining the constant
slow:Kernel#autoload when Object is frozen raises a RuntimeError before defining the constant
30 changes: 0 additions & 30 deletions spec/truffle/tags/core/kernel/require_tags.txt
Original file line number Diff line number Diff line change
@@ -1,29 +1,17 @@
fails:Kernel#require (path resolution) calls #to_str on non-String objects
fails:Kernel#require (path resolution) raises a TypeError if #to_str does not return a String
fails:Kernel#require (path resolution) calls #to_path on non-String objects
fails:Kernel#require (path resolution) calls #to_path on a String
fails:Kernel#require (path resolution) calls #to_str on non-String objects returned by #to_path
fails:Kernel#require (path resolution) loads a ../ relative path from the current working directory with empty $LOAD_PATH
fails:Kernel#require (path resolution) loads a ../ relative path from the current working directory with non-empty $LOAD_PATH
fails:Kernel#require (path resolution) loads a non-canonical path from the current working directory with non-empty $LOAD_PATH
fails:Kernel#require (path resolution) does not require file twice after $LOAD_PATH change
fails:Kernel#require (path resolution) does not resolve a ../ relative path against $LOAD_PATH entries
fails:Kernel#require (path resolution) loads a path with duplicate path separators
fails:Kernel#require (path resolution) with an unreadable file raises a LoadError
fails:Kernel#require (file extensions) loads a .rb extensioned file when passed a non-extensioned path
fails:Kernel#require (file extensions) loads a .rb extensioned file when a C-extension file of the same name is loaded
fails:Kernel#require (file extensions) does not load a C-extension file if a .rb extensioned file is already loaded
fails:Kernel#require (file extensions) loads a .rb extensioned file when passed a non-.rb extensioned path
fails:Kernel#require (file extensions) loads a .rb extensioned file when a complex-extensioned C-extension file of the same name is loaded
fails:Kernel#require (file extensions) does not load a C-extension file if a complex-extensioned .rb file is already loaded
fails:Kernel#require ($LOAD_FEATURES) does not store the path if the load fails
fails:Kernel#require ($LOAD_FEATURES) does not load an absolute path that is already stored
fails:Kernel#require ($LOAD_FEATURES) does not load a ./ relative path that is already stored
fails:Kernel#require ($LOAD_FEATURES) does not load a ../ relative path that is already stored
fails:Kernel#require ($LOAD_FEATURES) does not load a non-canonical path that is already stored
fails:Kernel#require ($LOAD_FEATURES) does not load twice the same file with and without extension
fails:Kernel#require ($LOAD_FEATURES) stores ../ relative paths as absolute paths
fails:Kernel#require ($LOAD_FEATURES) collapses duplicate path separators
fails:Kernel#require ($LOAD_FEATURES) adds the suffix of the resolved filename
fails:Kernel#require ($LOAD_FEATURES) does not load a non-canonical path for a file already loaded
fails:Kernel#require ($LOAD_FEATURES) does not load a ./ relative path for a file already loaded
@@ -34,38 +22,20 @@ fails:Kernel#require ($LOAD_FEATURES) when a non-extensioned file is in $LOADED_
fails:Kernel#require ($LOAD_FEATURES) when a non-extensioned file is in $LOADED_FEATURES returns false when passed a path and the file is not found
fails:Kernel#require (shell expansion) performs tilde expansion on a .rb file before storing paths in $LOADED_FEATURES
fails:Kernel#require (shell expansion) performs tilde expansion on a non-extensioned file before storing paths in $LOADED_FEATURES
fails:Kernel.require (path resolution) loads a non-canonical absolute path
fails:Kernel.require (path resolution) calls #to_str on non-String objects
fails:Kernel.require (path resolution) raises a TypeError if #to_str does not return a String
fails:Kernel.require (path resolution) calls #to_path on non-String objects
fails:Kernel.require (path resolution) calls #to_path on a String
fails:Kernel.require (path resolution) calls #to_str on non-String objects returned by #to_path
fails:Kernel.require (path resolution) loads a ./ relative path from the current working directory with empty $LOAD_PATH
fails:Kernel.require (path resolution) loads a ../ relative path from the current working directory with empty $LOAD_PATH
fails:Kernel.require (path resolution) loads a ./ relative path from the current working directory with non-empty $LOAD_PATH
fails:Kernel.require (path resolution) loads a ../ relative path from the current working directory with non-empty $LOAD_PATH
fails:Kernel.require (path resolution) loads a non-canonical path from the current working directory with non-empty $LOAD_PATH
fails:Kernel.require (path resolution) does not require file twice after $LOAD_PATH change
fails:Kernel.require (path resolution) does not resolve a ./ relative path against $LOAD_PATH entries
fails:Kernel.require (path resolution) does not resolve a ../ relative path against $LOAD_PATH entries
fails:Kernel.require (path resolution) loads a path with duplicate path separators
fails:Kernel.require (path resolution) with an unreadable file raises a LoadError
fails:Kernel.require (file extensions) loads a .rb extensioned file when passed a non-extensioned path
fails:Kernel.require (file extensions) loads a .rb extensioned file when a C-extension file of the same name is loaded
fails:Kernel.require (file extensions) does not load a C-extension file if a .rb extensioned file is already loaded
fails:Kernel.require (file extensions) loads a .rb extensioned file when passed a non-.rb extensioned path
fails:Kernel.require (file extensions) loads a .rb extensioned file when a complex-extensioned C-extension file of the same name is loaded
fails:Kernel.require (file extensions) does not load a C-extension file if a complex-extensioned .rb file is already loaded
fails:Kernel.require ($LOAD_FEATURES) does not store the path if the load fails
fails:Kernel.require ($LOAD_FEATURES) does not load an absolute path that is already stored
fails:Kernel.require ($LOAD_FEATURES) does not load a ./ relative path that is already stored
fails:Kernel.require ($LOAD_FEATURES) does not load a ../ relative path that is already stored
fails:Kernel.require ($LOAD_FEATURES) does not load a non-canonical path that is already stored
fails:Kernel.require ($LOAD_FEATURES) does not load twice the same file with and without extension
fails:Kernel.require ($LOAD_FEATURES) stores ../ relative paths as absolute paths
fails:Kernel.require ($LOAD_FEATURES) stores ./ relative paths as absolute paths
fails:Kernel.require ($LOAD_FEATURES) collapses duplicate path separators
fails:Kernel.require ($LOAD_FEATURES) canonicalizes non-unique absolute paths
fails:Kernel.require ($LOAD_FEATURES) adds the suffix of the resolved filename
fails:Kernel.require ($LOAD_FEATURES) does not load a non-canonical path for a file already loaded
fails:Kernel.require ($LOAD_FEATURES) does not load a ./ relative path for a file already loaded
4 changes: 0 additions & 4 deletions spec/truffle/tags/core/module/autoload_tags.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
fails:Module#autoload does not remove the constant from the constant table if the loaded files does not define it
fails:Module#autoload calls #to_path on non-string filenames
fails:Module#autoload calls #to_path on non-String filename arguments
fails:Module#autoload (concurrently) blocks a second thread while a first is doing the autoload
fails:Module#autoload (concurrently) blocks others threads while doing an autoload
fails:Module#autoload shares the autoload request across dup'ed copies of modules
fails:Module#autoload when changing $LOAD_PATH does not reload a file due to a different load path
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright (c) 2015 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.nodes.coerce;

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.nodes.RubyNode;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.core.RubyBasicObject;
import org.jruby.truffle.runtime.core.RubyString;

@NodeChild(value = "child", type = RubyNode.class)
public abstract class ToPathNode extends RubyNode {

public ToPathNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

public abstract RubyString executeRubyString(VirtualFrame frame, Object object);

@Specialization(guards = "isRubyString(path)")
public RubyBasicObject coerceRubyString(RubyBasicObject path) {
return path;
}

@Specialization(guards = "!isRubyString(object)")
public RubyBasicObject coerceObject(VirtualFrame frame, Object object) {
return (RubyBasicObject) ruby(frame, "Rubinius::Type.coerce_to_path(object)", "object", object);
}

}
Original file line number Diff line number Diff line change
@@ -49,9 +49,7 @@ public RubyBasicObject coerceObject(VirtualFrame frame, Object object) {
} catch (RaiseException e) {
if (e.getRubyException().getLogicalClass() == getContext().getCoreLibrary().getNoMethodErrorClass()) {
CompilerDirectives.transferToInterpreter();

throw new RaiseException(
getContext().getCoreLibrary().typeErrorNoImplicitConversion(object, "String", this));
throw new RaiseException(getContext().getCoreLibrary().typeErrorNoImplicitConversion(object, "String", this));
} else {
throw e;
}
@@ -61,9 +59,7 @@ public RubyBasicObject coerceObject(VirtualFrame frame, Object object) {
return (RubyBasicObject) coerced;
} else {
CompilerDirectives.transferToInterpreter();

throw new RaiseException(
getContext().getCoreLibrary().typeErrorBadCoercion(object, "String", "to_str", coerced, this));
throw new RaiseException(getContext().getCoreLibrary().typeErrorBadCoercion(object, "String", "to_str", coerced, this));
}
}

Original file line number Diff line number Diff line change
@@ -52,10 +52,18 @@ protected Object getConstant(RubyModule module, String name, RubyConstant consta
protected Object autoloadConstant(VirtualFrame frame, RubyModule module, String name, RubyConstant constant,
@Cached("createRequireNode()") RequireNode requireNode) {

requireNode.require((RubyBasicObject) constant.getValue());
final RubyBasicObject path = (RubyBasicObject) constant.getValue();

// retry
return this.executeGetConstant(frame, module, name);
// The autoload constant must only be removed if everything succeeds.
// We remove it first to allow lookup to ignore it and add it back if there was a failure.
constant.getDeclaringModule().removeConstant(this, name);
try {
requireNode.require(path);
return executeGetConstant(frame, module, name);
} catch (RaiseException e) {
constant.getDeclaringModule().setAutoloadConstant(this, name, path);
throw e;
}
}

@Specialization(guards = "constant == null")
@@ -71,7 +79,7 @@ protected Object missingConstant(VirtualFrame frame, RubyModule module, String n
}

protected RequireNode createRequireNode() {
return KernelNodesFactory.RequireNodeFactory.create(getContext(), getSourceSection(), new RubyNode[] {});
return KernelNodesFactory.RequireNodeFactory.create(getContext(), getSourceSection(), null);
}

protected boolean isValidConstantName(String name) {
Original file line number Diff line number Diff line change
@@ -22,6 +22,7 @@
import com.oracle.truffle.api.source.Source;
import com.oracle.truffle.api.source.SourceSection;
import com.oracle.truffle.api.utilities.ConditionProfile;

import org.jcodings.Encoding;
import org.jcodings.specific.USASCIIEncoding;
import org.jcodings.specific.UTF8Encoding;
@@ -36,6 +37,7 @@
import org.jruby.truffle.nodes.cast.NumericToFloatNode;
import org.jruby.truffle.nodes.cast.NumericToFloatNodeGen;
import org.jruby.truffle.nodes.coerce.NameToJavaStringNodeGen;
import org.jruby.truffle.nodes.coerce.ToPathNodeGen;
import org.jruby.truffle.nodes.coerce.ToStrNodeGen;
import org.jruby.truffle.nodes.core.KernelNodesFactory.CopyNodeFactory;
import org.jruby.truffle.nodes.core.KernelNodesFactory.SameOrEqualNodeFactory;
@@ -1502,13 +1504,20 @@ protected boolean isNonZero(long max) {
}

@CoreMethod(names = "require", isModuleFunction = true, required = 1)
public abstract static class RequireNode extends CoreMethodArrayArgumentsNode {
@NodeChildren({
@NodeChild(type = RubyNode.class, value = "feature")
})
public abstract static class RequireNode extends CoreMethodNode {

public RequireNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

@TruffleBoundary
@CreateCast("feature")
public RubyNode coerceFeatureToPath(RubyNode feature) {
return ToPathNodeGen.create(getContext(), getSourceSection(), feature);
}

@Specialization(guards = "isRubyString(feature)")
public boolean require(RubyBasicObject feature) {
CompilerDirectives.transferToInterpreter();
Original file line number Diff line number Diff line change
@@ -528,23 +528,16 @@ public AutoloadNode(RubyContext context, SourceSection sourceSection) {
emptyNode = StringNodesFactory.EmptyNodeFactory.create(context, sourceSection, new RubyNode[]{});
}

@CreateCast("filename") public RubyNode coerceFilenameToString(RubyNode filename) {
return ToStrNodeGen.create(getContext(), getSourceSection(), filename);
}

@Specialization(guards = {"isRubySymbol(name)", "isRubyString(filename)"})
public RubyBasicObject autoloadSymbol(RubyModule module, RubyBasicObject name, RubyBasicObject filename) {
return autoload(module, SymbolNodes.getString(name), filename);
@CreateCast("name") public RubyNode coerceNameToString(RubyNode name) {
return NameToJavaStringNodeGen.create(getContext(), getSourceSection(), name);
}

@Specialization(guards = {"isRubyString(name)", "isRubyString(filename)"})
public RubyBasicObject autoloadString(RubyModule module, RubyBasicObject name, RubyBasicObject filename) {
return autoload(module, name.toString(), filename);
@CreateCast("filename") public RubyNode coerceFilenameToPath(RubyNode filename) {
return ToPathNodeGen.create(getContext(), getSourceSection(), filename);
}

private RubyBasicObject autoload(RubyModule module, String name, RubyBasicObject filename) {
assert RubyGuards.isRubyString(filename);

@Specialization(guards = "isRubyString(filename)")
public RubyBasicObject autoload(RubyModule module, String name, RubyBasicObject filename) {
if (invalidConstantName.profile(!IdUtil.isValidConstantName19(name))) {
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().getCoreLibrary().nameError(String.format("autoload must be constant name: %s", name), name, this));
Original file line number Diff line number Diff line change
@@ -100,7 +100,7 @@ protected RubyConstant lookupForExistingModule(RubyModule lexicalParent) {
if ((constant != null) && constant.isAutoload()) {
if (requireNode == null) {
CompilerDirectives.transferToInterpreter();
requireNode = insert(KernelNodesFactory.RequireNodeFactory.create(getContext(), getSourceSection(), new RubyNode[]{}));
requireNode = insert(KernelNodesFactory.RequireNodeFactory.create(getContext(), getSourceSection(), null));
}

// We know that we're redefining this constant as we're defining a class/module with that name. We remove
Original file line number Diff line number Diff line change
@@ -27,6 +27,10 @@ public RubyConstant(RubyModule declaringModule, Object value, boolean isPrivate,
this.autoload = autoload;
}

public RubyModule getDeclaringModule() {
return declaringModule;
}

public Object getValue() {
return value;
}
Original file line number Diff line number Diff line change
@@ -17,7 +17,9 @@
import org.jruby.truffle.runtime.ModuleOperations;
import org.jruby.truffle.runtime.RubyConstant;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.array.ArrayMirror;
import org.jruby.truffle.runtime.control.RaiseException;
import org.jruby.truffle.runtime.core.RubyBasicObject;
import org.jruby.util.cli.Options;

import java.io.File;
@@ -50,7 +52,10 @@ public boolean require(String feature, Node currentNode) throws IOException {

if (feature.startsWith("./")) {
final String cwd = context.getRuntime().getCurrentDirectory();
feature = cwd + "/" + feature;
feature = cwd + "/" + feature.substring(2);
} else if (feature.startsWith("../")) {
final String cwd = context.getRuntime().getCurrentDirectory();
feature = cwd.substring(0, cwd.lastIndexOf('/')) + "/" + feature.substring(3);
}

try {
@@ -106,11 +111,12 @@ public boolean isAbsolutePath(String path) {
private boolean requireFile(String feature, String path, Node currentNode) throws IOException {
// We expect '/' in various classpath URLs, so normalize Windows file paths to use '/'
path = path.replace('\\', '/');
final RubyBasicObject loadedFeatures = context.getCoreLibrary().getLoadedFeatures();

if (path.startsWith("uri:classloader:/")) {
// TODO CS 13-Feb-15 this uri:classloader:/ and core:/ thing is a hack - simplify it

for (Object loaded : Arrays.asList(ArrayNodes.slowToArray(context.getCoreLibrary().getLoadedFeatures()))) {
for (Object loaded : Arrays.asList(ArrayNodes.slowToArray(loadedFeatures))) {
if (loaded.toString().equals(path)) {
return true;
}
@@ -129,12 +135,12 @@ private boolean requireFile(String feature, String path, Node currentNode) throw
}

context.getCoreLibrary().loadRubyCore(coreFileName, "uri:classloader:/");
ArrayNodes.slowPush(context.getCoreLibrary().getLoadedFeatures(), StringNodes.createString(context.getCoreLibrary().getStringClass(), path));
ArrayNodes.slowPush(loadedFeatures, StringNodes.createString(context.getCoreLibrary().getStringClass(), path));

return true;
}
else if (path.startsWith("core:/")) {
for (Object loaded : Arrays.asList(ArrayNodes.slowToArray(context.getCoreLibrary().getLoadedFeatures()))) {
for (Object loaded : Arrays.asList(ArrayNodes.slowToArray(loadedFeatures))) {
if (loaded.toString().equals(path)) {
return true;
}
@@ -151,7 +157,7 @@ else if (path.startsWith("core:/")) {
}

context.getCoreLibrary().loadRubyCore(coreFileName, "core:/");
ArrayNodes.slowPush(context.getCoreLibrary().getLoadedFeatures(), StringNodes.createString(context.getCoreLibrary().getStringClass(), path));
ArrayNodes.slowPush(loadedFeatures, StringNodes.createString(context.getCoreLibrary().getStringClass(), path));

return true;
} else {
@@ -165,20 +171,35 @@ else if (path.startsWith("core:/")) {

final String expandedPath = expandPath(context, path);

for (Object loaded : Arrays.asList(ArrayNodes.slowToArray(context.getCoreLibrary().getLoadedFeatures()))) {
for (Object loaded : Arrays.asList(ArrayNodes.slowToArray(loadedFeatures))) {
if (loaded.toString().equals(expandedPath)) {
return true;
}
}

ArrayNodes.slowPush(context.getCoreLibrary().getLoadedFeatures(), StringNodes.createString(context.getCoreLibrary().getStringClass(), expandedPath));

if (SHOW_RESOLUTION) {
System.err.printf("resolved %s -> %s%n", feature, expandedPath);
}

// TODO (nirvdrum 15-Jan-15): If we fail to load, we should remove the path from the loaded features because subsequent requires of the same statement may succeed.
context.loadFile(path, currentNode);
final RubyBasicObject pathString = StringNodes.createString(context.getCoreLibrary().getStringClass(), expandedPath);
ArrayNodes.slowPush(loadedFeatures, pathString);
try {
context.loadFile(path, currentNode);
} catch (RaiseException e) {
final ArrayMirror mirror = ArrayMirror.reflect((Object[]) ArrayNodes.getStore(loadedFeatures));
final int length = ArrayNodes.getSize(loadedFeatures);
for (int i = length - 1; i >= 0; i--) {
if (mirror.get(i) == pathString) {
for (int j = length - 1; j > i; j--) {
mirror.set(i - 1, mirror.get(i));
}
ArrayNodes.setSize(loadedFeatures, length - 1);
break;
}
}
throw e;
}
}

return true;