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: 727f65bc0daf
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 1d955ff3432c
Choose a head ref
  • 3 commits
  • 31 files changed
  • 1 contributor

Commits on Jun 20, 2015

  1. Copy the full SHA
    df2ab1e View commit details
  2. 7
    Copy the full SHA
    9f47fbf View commit details
  3. Copy the full SHA
    1d955ff View commit details
Showing with 555 additions and 111 deletions.
  1. +0 −3 spec/truffle/tags/core/env/assoc_tags.txt
  2. +0 −1 spec/truffle/tags/core/env/clear_tags.txt
  3. +0 −5 spec/truffle/tags/core/env/delete_if_tags.txt
  4. +0 −1 spec/truffle/tags/core/env/delete_tags.txt
  5. +0 −3 spec/truffle/tags/core/env/each_key_tags.txt
  6. +0 −4 spec/truffle/tags/core/env/each_pair_tags.txt
  7. +0 −4 spec/truffle/tags/core/env/each_tags.txt
  8. +0 −3 spec/truffle/tags/core/env/each_value_tags.txt
  9. +0 −3 spec/truffle/tags/core/env/element_reference_tags.txt
  10. +0 −6 spec/truffle/tags/core/env/element_set_tags.txt
  11. +0 −2 spec/truffle/tags/core/env/empty_tags.txt
  12. +0 −3 spec/truffle/tags/core/env/fetch_tags.txt
  13. +0 −2 spec/truffle/tags/core/env/index_tags.txt
  14. +0 −5 spec/truffle/tags/core/env/keep_if_tags.txt
  15. +0 −2 spec/truffle/tags/core/env/key_tags.txt
  16. +0 −1 spec/truffle/tags/core/env/keys_tags.txt
  17. +0 −1 spec/truffle/tags/core/env/length_tags.txt
  18. +0 −3 spec/truffle/tags/core/env/rassoc_tags.txt
  19. +0 −10 spec/truffle/tags/core/env/reject_tags.txt
  20. +0 −1 spec/truffle/tags/core/env/replace_tags.txt
  21. +0 −7 spec/truffle/tags/core/env/select_tags.txt
  22. +0 −1 spec/truffle/tags/core/env/shift_tags.txt
  23. +34 −10 truffle/src/main/java/org/jruby/truffle/nodes/core/KernelNodes.java
  24. +83 −0 truffle/src/main/java/org/jruby/truffle/nodes/rubinius/PosixNodes.java
  25. +11 −21 truffle/src/main/java/org/jruby/truffle/runtime/core/CoreLibrary.java
  26. +6 −4 truffle/src/main/ruby/core.rb
  27. +9 −5 truffle/src/main/ruby/core/library.rb
  28. +5 −0 truffle/src/main/ruby/core/rubinius/bootstrap/kernel.rb
  29. +324 −0 truffle/src/main/ruby/core/rubinius/common/env.rb
  30. +46 −0 truffle/src/main/ruby/core/rubinius/delta/ffi.rb
  31. +37 −0 truffle/src/main/ruby/core/rubinius/platform/env.rb
3 changes: 0 additions & 3 deletions spec/truffle/tags/core/env/assoc_tags.txt

This file was deleted.

1 change: 0 additions & 1 deletion spec/truffle/tags/core/env/clear_tags.txt

This file was deleted.

5 changes: 0 additions & 5 deletions spec/truffle/tags/core/env/delete_if_tags.txt

This file was deleted.

1 change: 0 additions & 1 deletion spec/truffle/tags/core/env/delete_tags.txt

This file was deleted.

3 changes: 0 additions & 3 deletions spec/truffle/tags/core/env/each_key_tags.txt

This file was deleted.

4 changes: 0 additions & 4 deletions spec/truffle/tags/core/env/each_pair_tags.txt

This file was deleted.

4 changes: 0 additions & 4 deletions spec/truffle/tags/core/env/each_tags.txt

This file was deleted.

3 changes: 0 additions & 3 deletions spec/truffle/tags/core/env/each_value_tags.txt

This file was deleted.

3 changes: 0 additions & 3 deletions spec/truffle/tags/core/env/element_reference_tags.txt

This file was deleted.

6 changes: 0 additions & 6 deletions spec/truffle/tags/core/env/element_set_tags.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,2 @@
fails:ENV.[]= deletes the environment variable when the value is nil
fails:ENV.[]= coerces the key argument with #to_str
fails:ENV.[]= coerces the value argument with #to_str
fails:ENV.[]= raises TypeError when the key is not coercible to String
fails:ENV.[]= raises TypeError when the value is not coercible to String
fails:ENV.[]= raises Errno::EINVAL when the key contains the '=' character
fails:ENV.[]= raises Errno::EINVAL when the key is an empty string
fails:ENV.[]= does nothing when the key is not a valid environment variable key and the value is nil
2 changes: 0 additions & 2 deletions spec/truffle/tags/core/env/empty_tags.txt

This file was deleted.

3 changes: 0 additions & 3 deletions spec/truffle/tags/core/env/fetch_tags.txt

This file was deleted.

2 changes: 0 additions & 2 deletions spec/truffle/tags/core/env/index_tags.txt

This file was deleted.

5 changes: 0 additions & 5 deletions spec/truffle/tags/core/env/keep_if_tags.txt

This file was deleted.

2 changes: 0 additions & 2 deletions spec/truffle/tags/core/env/key_tags.txt

This file was deleted.

1 change: 0 additions & 1 deletion spec/truffle/tags/core/env/keys_tags.txt

This file was deleted.

1 change: 0 additions & 1 deletion spec/truffle/tags/core/env/length_tags.txt

This file was deleted.

3 changes: 0 additions & 3 deletions spec/truffle/tags/core/env/rassoc_tags.txt

This file was deleted.

10 changes: 0 additions & 10 deletions spec/truffle/tags/core/env/reject_tags.txt
Original file line number Diff line number Diff line change
@@ -1,11 +1 @@
fails:ENV.reject! rejects entries based on key
fails:ENV.reject! rejects entries based on value
fails:ENV.reject! returns itself or nil
fails:ENV.reject! returns an Enumerator if called without a block
fails:ENV.reject! doesn't raise if empty
fails:ENV.reject rejects entries based on key
fails:ENV.reject rejects entries based on value
fails:ENV.reject returns a Hash
fails:ENV.reject doesn't raise if empty
fails:ENV.reject! when no block is given returned Enumerator size returns the enumerable size
fails:ENV.reject when no block is given returned Enumerator size returns the enumerable size
1 change: 0 additions & 1 deletion spec/truffle/tags/core/env/replace_tags.txt

This file was deleted.

7 changes: 0 additions & 7 deletions spec/truffle/tags/core/env/select_tags.txt

This file was deleted.

1 change: 0 additions & 1 deletion spec/truffle/tags/core/env/shift_tags.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
fails:ENV.shift returns a pair and deletes it
fails:ENV.shift returns nil if ENV.empty?
fails:ENV.shift uses the locale encoding if Encoding.default_internal is nil
fails:ENV.shift transcodes from the locale encoding to Encoding.default_internal if set
44 changes: 34 additions & 10 deletions truffle/src/main/java/org/jruby/truffle/nodes/core/KernelNodes.java
Original file line number Diff line number Diff line change
@@ -76,24 +76,32 @@ public abstract class KernelNodes {
@CoreMethod(names = "`", isModuleFunction = true, needsSelf = false, required = 1)
public abstract static class BacktickNode extends CoreMethodArrayArgumentsNode {

@Child private CallDispatchHeadNode toHashNode;

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

@Specialization
public RubyBasicObject backtick(RubyString command) {
public RubyBasicObject backtick(VirtualFrame frame, RubyString command) {
// Command is lexically a string interoplation, so variables will already have been expanded

if (toHashNode == null) {
CompilerDirectives.transferToInterpreter();
toHashNode = insert(DispatchHeadNodeFactory.createMethodCall(getContext()));
}

CompilerDirectives.transferToInterpreter();

final RubyContext context = getContext();

final RubyBasicObject env = context.getCoreLibrary().getENV();
final RubyBasicObject envAsHash = (RubyBasicObject) toHashNode.call(frame, env, "to_hash", null);

final List<String> envp = new ArrayList<>();

// TODO(CS): cast
for (Map.Entry<Object, Object> keyValue : HashNodes.iterableKeyValues(env)) {
for (Map.Entry<Object, Object> keyValue : HashNodes.iterableKeyValues(envAsHash)) {
envp.add(keyValue.getKey().toString() + "=" + keyValue.getValue().toString());
}

@@ -528,12 +536,19 @@ public Object eval(RubyString source, RubyBasicObject badBinding, NotProvided fi
@CoreMethod(names = "exec", isModuleFunction = true, required = 1, argumentsAsArray = true)
public abstract static class ExecNode extends CoreMethodArrayArgumentsNode {

@Child private CallDispatchHeadNode toHashNode;

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

@Specialization
public Object require(Object[] args) {
public Object require(VirtualFrame frame, Object[] args) {
if (toHashNode == null) {
CompilerDirectives.transferToInterpreter();
toHashNode = insert(DispatchHeadNodeFactory.createMethodCall(getContext()));
}

CompilerDirectives.transferToInterpreter();

final String[] commandLine = new String[args.length];
@@ -542,19 +557,20 @@ public Object require(Object[] args) {
commandLine[n] = args[n].toString();
}

exec(getContext(), commandLine);
final RubyBasicObject env = getContext().getCoreLibrary().getENV();
final RubyBasicObject envAsHash = (RubyBasicObject) toHashNode.call(frame, env, "to_hash", null);

exec(getContext(), envAsHash, commandLine);

return null;
}

@TruffleBoundary
private static void exec(RubyContext context, String[] commandLine) {
private static void exec(RubyContext context, RubyBasicObject envAsHash, String[] commandLine) {
final ProcessBuilder builder = new ProcessBuilder(commandLine);
builder.inheritIO();

final RubyBasicObject env = context.getCoreLibrary().getENV();

for (Map.Entry<Object, Object> keyValue : HashNodes.iterableKeyValues(env)) {
for (Map.Entry<Object, Object> keyValue : HashNodes.iterableKeyValues(envAsHash)) {
builder.environment().put(keyValue.getKey().toString(), keyValue.getValue().toString());
}

@@ -1804,22 +1820,30 @@ protected RubyString asRubyString(Object arg) {
@CoreMethod(names = "system", isModuleFunction = true, needsSelf = false, required = 1)
public abstract static class SystemNode extends CoreMethodArrayArgumentsNode {

@Child private CallDispatchHeadNode toHashNode;

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

@Specialization
public boolean system(RubyString command) {
public boolean system(VirtualFrame frame, RubyString command) {
if (toHashNode == null) {
CompilerDirectives.transferToInterpreter();
toHashNode = insert(DispatchHeadNodeFactory.createMethodCall(getContext()));
}

CompilerDirectives.transferToInterpreter();

// TODO(CS 5-JAN-15): very simplistic implementation

final RubyBasicObject env = getContext().getCoreLibrary().getENV();
final RubyBasicObject envAsHash = (RubyBasicObject) toHashNode.call(frame, env, "to_hash", null);

final List<String> envp = new ArrayList<>();

// TODO(CS): cast
for (Map.Entry<Object, Object> keyValue : HashNodes.iterableKeyValues(env)) {
for (Map.Entry<Object, Object> keyValue : HashNodes.iterableKeyValues(envAsHash)) {
envp.add(keyValue.getKey().toString() + "=" + keyValue.getValue().toString());
}

Original file line number Diff line number Diff line change
@@ -20,12 +20,14 @@
import org.jruby.truffle.nodes.core.CoreMethod;
import org.jruby.truffle.nodes.core.CoreMethodArrayArgumentsNode;
import org.jruby.truffle.nodes.core.StringNodes;
import org.jruby.truffle.nodes.core.array.ArrayNodes;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.control.RaiseException;
import org.jruby.truffle.runtime.core.RubyBasicObject;
import org.jruby.truffle.runtime.core.RubyString;

import java.nio.charset.StandardCharsets;
import java.util.Map;

@CoreClass(name = "Rubinius::FFI::Platform::POSIX")
public abstract class PosixNodes {
@@ -87,6 +89,19 @@ public int dup(int descriptor) {

}

@CoreMethod(names = "environ", isModuleFunction = true)
public abstract static class EnvironNode extends CoreMethodArrayArgumentsNode {

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

@Specialization
public RubyBasicObject environ() {
return PointerNodes.createPointer(getContext().getCoreLibrary().getRubiniusFFIPointerClass(), posix().environ());
}
}

@CoreMethod(names = "fchmod", isModuleFunction = true, required = 2)
public abstract static class FchmodNode extends CoreMethodArrayArgumentsNode {

@@ -145,6 +160,27 @@ public int getEGID() {

}

@CoreMethod(names = "getenv", isModuleFunction = true, required = 1)
public abstract static class GetenvNode extends CoreMethodArrayArgumentsNode {

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

@Specialization(guards = "isRubyString(name)")
public RubyBasicObject getenv(RubyBasicObject name) {
final String nameString = RubyEncoding.decodeUTF8(StringNodes.getByteList(name).getUnsafeBytes(), StringNodes.getByteList(name).getBegin(), StringNodes.getByteList(name).getRealSize());

Object result = posix().getenv(nameString);

if (result == null) {
return nil();
}

return StringNodes.createString(getContext().getCoreLibrary().getStringClass(), (String) result);
}
}

@CoreMethod(names = "geteuid", isModuleFunction = true)
public abstract static class GetEUIDNode extends CoreMethodArrayArgumentsNode {

@@ -257,6 +293,20 @@ public RubyBasicObject memset(RubyBasicObject pointer, int c, long length) {

}

@CoreMethod(names = "putenv", isModuleFunction = true, required = 1)
public abstract static class PutenvNode extends CoreMethodArrayArgumentsNode {

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

@Specialization(guards = "isRubyString(nameValuePair)")
public int putenv(RubyBasicObject nameValuePair) {
throw new UnsupportedOperationException("Not yet implemented in jnr-posix");
}

}

@CoreMethod(names = "readlink", isModuleFunction = true, required = 3)
public abstract static class ReadlinkNode extends CoreMethodArrayArgumentsNode {

@@ -279,6 +329,23 @@ public int readlink(RubyString path, RubyBasicObject pointer, int bufsize) {

}

@CoreMethod(names = "setenv", isModuleFunction = true, required = 3)
public abstract static class SetenvNode extends CoreMethodArrayArgumentsNode {

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

@Specialization(guards = { "isRubyString(name)", "isRubyString(value)" })
public int setenv(RubyBasicObject name, RubyBasicObject value, int overwrite) {
final String nameString = RubyEncoding.decodeUTF8(StringNodes.getByteList(name).getUnsafeBytes(), StringNodes.getByteList(name).getBegin(), StringNodes.getByteList(name).getRealSize());
final String valueString = RubyEncoding.decodeUTF8(StringNodes.getByteList(value).getUnsafeBytes(), StringNodes.getByteList(value).getBegin(), StringNodes.getByteList(value).getRealSize());

return posix().setenv(nameString, valueString, overwrite);
}

}

@CoreMethod(names = "link", isModuleFunction = true, required = 2)
public abstract static class LinkNode extends CoreMethodArrayArgumentsNode {

@@ -323,6 +390,22 @@ public int umask(int mask) {

}

@CoreMethod(names = "unsetenv", isModuleFunction = true, required = 1)
public abstract static class UnsetenvNode extends CoreMethodArrayArgumentsNode {

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

@Specialization(guards = "isRubyString(name)")
public int unsetenv(RubyBasicObject name) {
final String nameString = RubyEncoding.decodeUTF8(StringNodes.getByteList(name).getUnsafeBytes(), StringNodes.getByteList(name).getBegin(), StringNodes.getByteList(name).getRealSize());

return posix().unsetenv(nameString);
}

}

@CoreMethod(names = "utimes", isModuleFunction = true, required = 2)
public abstract static class UtimesNode extends CoreMethodArrayArgumentsNode {

Original file line number Diff line number Diff line change
@@ -20,6 +20,7 @@
import org.jcodings.Encoding;
import org.jcodings.EncodingDB;
import org.jcodings.transcode.EConvFlags;
import org.jruby.ext.ffi.Platform;
import org.jruby.runtime.Constants;
import org.jruby.runtime.encoding.EncodingService;
import org.jruby.runtime.load.LoadServiceResource;
@@ -37,6 +38,8 @@
import org.jruby.truffle.nodes.ext.ZlibNodesFactory;
import org.jruby.truffle.nodes.objects.*;
import org.jruby.truffle.nodes.rubinius.*;
import org.jruby.truffle.runtime.LexicalScope;
import org.jruby.truffle.runtime.ModuleOperations;
import org.jruby.truffle.runtime.RubyCallStack;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.backtrace.Backtrace;
@@ -125,6 +128,7 @@ public class CoreLibrary {
private final RubyModule rubiniusModule;
private final RubyClass rubiniusChannelClass;
private final RubyModule rubiniusFFIModule;
private final RubyClass rubiniusFFIPointerClass;
private final RubyClass rubiniusMirrorClass;
private final RubyModule signalModule;
private final RubyModule truffleModule;
@@ -150,8 +154,6 @@ public class CoreLibrary {
private final RubyClass rubyInternalMethod;
private final Map<Errno, RubyClass> errnoClasses = new HashMap<>();

@CompilationFinal private RubyBasicObject envHash;

@CompilationFinal private InternalMethod basicObjectSendMethod;

private enum State {
@@ -357,7 +359,7 @@ public CoreLibrary(RubyContext context) {

rubiniusFFIModule = defineModule(rubiniusModule, "FFI");
defineModule(defineModule(rubiniusFFIModule, "Platform"), "POSIX");
defineClass(rubiniusFFIModule, objectClass, "Pointer", new PointerNodes.PointerAllocator());
rubiniusFFIPointerClass = defineClass(rubiniusFFIModule, objectClass, "Pointer", new PointerNodes.PointerAllocator());

rubiniusChannelClass = defineClass(rubiniusModule, objectClass, "Channel");
rubiniusMirrorClass = defineClass(rubiniusModule, objectClass, "Mirror");
@@ -507,6 +509,7 @@ private void initializeConstants() {
objectClass.setConstant(node, "ARGV", argv);

rubiniusModule.setConstant(node, "UNDEFINED", rubiniusUndefined);
rubiniusModule.setConstant(node, "LIBC", Platform.LIBC);

processModule.setConstant(node, "CLOCK_MONOTONIC", ProcessNodes.CLOCK_MONOTONIC);
processModule.setConstant(node, "CLOCK_REALTIME", ProcessNodes.CLOCK_REALTIME);
@@ -573,11 +576,6 @@ private RubyModule defineModule(RubyModule lexicalParent, String name) {
public void initializeAfterMethodsAdded() {
initializeRubiniusFFI();

// ENV is supposed to be an object that actually updates the environment, and sees any updates

envHash = getSystemEnv();
objectClass.setConstant(node, "ENV", envHash);

// Load Ruby core

try {
@@ -1325,19 +1323,7 @@ public RubyBasicObject getNilObject() {
}

public RubyBasicObject getENV() {
return envHash;
}

private RubyBasicObject getSystemEnv() {
final Map<Object, Object> entries = new HashMap<>();

for (Map.Entry<String, String> variable : System.getenv().entrySet()) {
entries.put(
StringNodes.createString(context.getCoreLibrary().getStringClass(), variable.getKey()),
StringNodes.createString(context.getCoreLibrary().getStringClass(), variable.getValue()));
}

return BucketsStrategy.create(context.getCoreLibrary().getHashClass(), entries.entrySet(), false);
return (RubyBasicObject) objectClass.getConstants().get("ENV").getValue();
}

public ArrayNodes.MinBlock getArrayMinBlock() {
@@ -1396,6 +1382,10 @@ public RubyClass getRubiniusChannelClass() {
return rubiniusChannelClass;
}

public RubyClass getRubiniusFFIPointerClass() {
return rubiniusFFIPointerClass;
}

public RubyClass getRubiniusMirrorClass() {
return rubiniusMirrorClass;
}
10 changes: 6 additions & 4 deletions truffle/src/main/ruby/core.rb
Original file line number Diff line number Diff line change
@@ -95,12 +95,14 @@ def self.omit(reason)

# Load platform (ordered according to Rubinius' load_order.txt)

require_relative 'core/library'

require_relative 'core/rubinius/platform/ffi'
#require_relative 'core/rubinius/platform/enum'
#require_relative 'core/rubinius/platform/library'
require_relative 'core/rubinius/platform/pointer_accessors'
require_relative 'core/rubinius/platform/pointer'
#require_relative 'core/rubinius/platform/env'
require_relative 'core/rubinius/platform/env'
require_relative 'core/rubinius/platform/file'
#require_relative 'core/rubinius/platform/math'
#require_relative 'core/rubinius/platform/posix'
@@ -158,7 +160,8 @@ def self.omit(reason)
require_relative 'core/rubinius/common/lru_cache'
require_relative 'core/rubinius/api/shims/encoding'
require_relative 'core/rubinius/common/encoding'
#require_relative 'core/rubinius/common/env'
require_relative 'core/rubinius/common/env'
ENV = Rubinius::EnvironmentVariables.new
require_relative 'core/rubinius/common/errno'
#require_relative 'core/rubinius/common/eval'
require_relative 'core/rubinius/common/false'
@@ -231,7 +234,7 @@ def self.omit(reason)
#require_relative 'core/rubinius/delta/code_loader'
#require_relative 'core/rubinius/delta/fsevent'
#require_relative 'core/rubinius/delta/console'
#require_relative 'core/rubinius/delta/ffi'
require_relative 'core/rubinius/delta/ffi'
#require_relative 'core/rubinius/delta/ruby_constants'
#require_relative 'core/rubinius/delta/pack'
#require_relative 'core/rubinius/delta/metrics'
@@ -249,7 +252,6 @@ def self.omit(reason)
require_relative 'core/string'
require_relative 'core/thread'
require_relative 'core/unbound_method'
require_relative 'core/library'
require_relative 'core/type'

# Dirty fixes we'd like to get rid of soon
14 changes: 9 additions & 5 deletions truffle/src/main/ruby/core/library.rb
Original file line number Diff line number Diff line change
@@ -60,11 +60,15 @@ def attach_function(name, a2, a3, a4=nil, a5=nil)

caller = Truffle::Primitive.source_of_caller

if caller.end_with? 'ruby/truffle/rubysl/rubysl-socket/lib/rubysl/socket.rb'
if Rubinius::FFI::Platform::POSIX.respond_to? mname
define_method mname, Rubinius::FFI::Platform::POSIX.method(mname)
module_function mname
return
suffixes = ['ruby/truffle/rubysl/rubysl-socket/lib/rubysl/socket.rb', 'core:/core/rubinius/platform/env.rb']

suffixes.each do |suffix|
if caller[-suffix.length, suffix.length] == suffix
if Rubinius::FFI::Platform::POSIX.respond_to? mname
define_method mname, Rubinius::FFI::Platform::POSIX.method(mname)
module_function mname
return
end
end
end

5 changes: 5 additions & 0 deletions truffle/src/main/ruby/core/rubinius/bootstrap/kernel.rb
Original file line number Diff line number Diff line change
@@ -33,4 +33,9 @@ module Kernel
# Truffle: no extra indirection for Kernel#send.
alias_method :send, :__send__ # from BasicObject

def extend(mod)
Rubinius::Type.object_singleton_class(self).include(mod)
self
end

end
324 changes: 324 additions & 0 deletions truffle/src/main/ruby/core/rubinius/common/env.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,324 @@
# Copyright (c) 2007-2015, Evan Phoenix and contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# * Neither the name of Rubinius nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

##
# Interface to process environment variables.

module Rubinius
class EnvironmentVariables
include Enumerable
include Rubinius::EnvironmentAccess

def [](key)
value = getenv(StringValue(key))
if value
value = set_encoding value
value.freeze
end
value
end

def []=(key, value)
key = StringValue(key)
if value.nil?
unsetenv(key)
else
if setenv(key, StringValue(value), 1) != 0
Errno.handle("setenv")
end
end
value
end

alias_method :store, :[]=

def each_key
return to_enum(:each_key) { size } unless block_given?

each { |k, v| yield k }
end

def each_value
return to_enum(:each_value) { size } unless block_given?

each { |k, v| yield v }
end

def each
return to_enum(:each) { size } unless block_given?

env = environ()
ptr_size = FFI.type_size FFI.find_type(:pointer)

offset = 0
cur = env + offset

until cur.read_pointer.null?
entry = cur.read_pointer.read_string
key, value = entry.split '=', 2
value.taint if value
key.taint if key

key = set_encoding key
value = set_encoding value

yield key, value

offset += ptr_size
cur = env + offset
end

self
end

alias_method :each_pair, :each

def delete(key)
existing_value = self[key]
if existing_value
self[key] = nil
elsif block_given?
yield key
end
existing_value
end

def delete_if(&block)
return to_enum(:delete_if) { size } unless block_given?
reject!(&block)
self
end

def include?(key)
!self[key].nil?
end

alias_method :has_key?, :include?
alias_method :key?, :include?

# More efficient than using the one from Enumerable
alias_method :member?, :include?

def fetch(key, absent=undefined)
if block_given? and !undefined.equal?(absent)
warn "block supersedes default value argument"
end

if value = self[key]
return value
end

if block_given?
return yield(key)
elsif undefined.equal?(absent)
raise KeyError, "key not found"
end

return absent
end

def to_s
"ENV"
end

def inspect
to_hash.inspect
end

def reject(&block)
to_hash.reject(&block)
end

def reject!
return to_enum(:reject!) { size } unless block_given?

# Avoid deleting from environ while iterating because the
# OS can handle that in a million different bad ways.

keys = []
each { |k, v| keys << k if yield(k, v) }
keys.each { |k| delete k }

keys.empty? ? nil : self
end

def clear
# Avoid deleting from environ while iterating because the
# OS can handle that in a million different bad ways.

keys = []
each { |k, v| keys << k }
keys.each { |k| delete k }

self
end

def has_value?(value)
each { |k, v| return true if v == value }
return false
end

alias_method :value?, :has_value?

def values_at(*params)
params.map{ |k| self[k] }
end

def index(value)
each do |k, v|
return k if v == value
end
nil
end

def invert
to_hash.invert
end

def key(value)
index(value)
end

def keys
keys = []
each { |k, v| keys << k }
keys
end

def values
vals = []
each { |k, v| vals << v }
vals
end

def empty?
each { return false }
return true
end

def length
sz = 0
each { |k, v| sz += 1 }
sz
end

alias_method :size, :length

def rehash
# No need to do anything, our keys are always strings
end

def replace(other)
clear
other.each { |k, v| self[k] = v }
end

def select(&blk)
return to_enum { size } unless block_given?
to_hash.select(&blk)
end

def shift
env = environ()

offset = 0
cur = env + offset

ptr = cur.read_pointer
return nil unless ptr

key, value = ptr.read_string.split "=", 2

return nil unless key

key.taint if key
value.taint if value

delete key

key = set_encoding key
value = set_encoding value

return [key, value]
end

def to_a
ary = []
each { |k, v| ary << [k, v] }
ary
end

def to_hash
hsh = {}
each { |k, v| hsh[k] = v }
hsh
end

alias_method :to_h, :to_hash

def update(other)
if block_given?
other.each { |k, v| self[k] = yield(k, self[k], v) }
else
other.each { |k, v| self[k] = v }
end
end

def keep_if(&block)
return to_enum(:keep_if) { size } unless block_given?
select!(&block)
self
end

def select!
return to_enum(:select!) { size } unless block_given?
reject! { |k, v| !yield(k, v) }
end

def assoc(key)
key = StringValue(key)
value = self[key]
value ? [key, value] : nil
end

def rassoc(value)
value = StringValue(value)
key = index(value)
key ? [key, value] : nil
end

def set_encoding(value)
return unless value.kind_of? String
if Encoding.default_internal && value.ascii_only?
value.encode Encoding.default_internal, Encoding.find("locale")
else
value.force_encoding Encoding.find("locale")
end
end

private :set_encoding
end
end
46 changes: 46 additions & 0 deletions truffle/src/main/ruby/core/rubinius/delta/ffi.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Copyright (c) 2007-2015, Evan Phoenix and contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# * Neither the name of Rubinius nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

module Rubinius
module FFI

module Library
# Once the kernel is loaded, we want to raise an error if attempting to
# attach to a non-existent function.
def ffi_function_missing(name, *args)
raise FFI::NotFoundError, "Unable to find foreign function '#{name}'"
end
end

# We can only add Enumerable here since it needs everything else setup
class Struct
class InlineArray
include Enumerable
end
end

end
end
37 changes: 37 additions & 0 deletions truffle/src/main/ruby/core/rubinius/platform/env.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Copyright (c) 2007-2015, Evan Phoenix and contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# * Neither the name of Rubinius nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

module Rubinius
module EnvironmentAccess
extend FFI::Library

attach_function :getenv, [:string], :string
attach_function :putenv, [:string], :int
attach_function :setenv, [:string, :string, :int], :int
attach_function :unsetenv, [:string], :int
attach_function :environ, 'ffi_environ', [], :pointer
end
end