Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update shared FFI code #5948

Merged
merged 29 commits into from Feb 18, 2020
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
740be10
Update configs from FFI and remove generator code.
headius Oct 28, 2019
ea20d2d
Update shared sources from FFI gem.
headius Oct 28, 2019
84b5c39
Update FFI specs from FFI gem.
headius Oct 28, 2019
7ab6328
Add JRuby-specific setup.
headius Oct 28, 2019
03d2063
Eliminate double-def of FFI::Platform consts and methods.
headius Oct 28, 2019
aab7c6b
Align VariadicInvoker with FFI gem.
headius Oct 28, 2019
8209ab6
Only add i386 and x86_64 arch if that's the platform.
headius Oct 28, 2019
221b11d
Just use the Ruby definition of this type.
headius Oct 28, 2019
de3c22a
javadoc fixes.
headius Oct 28, 2019
051e506
Partial impl of StructLayout#__union!
headius Oct 28, 2019
fa1e977
Merge branch 'master' into update_ffi
headius Jan 7, 2020
6cc8235
Enums, Enum, and DataConverter are in Ruby now
headius Jan 8, 2020
4d84cca
Align error handling with C ffi
headius Jan 8, 2020
69a1731
Fix all MemoryPointer specs
headius Jan 8, 2020
fb0740a
Fix all pointer specs.
headius Jan 8, 2020
c647799
Order type checks the same as C FFI
headius Jan 8, 2020
21a8a8c
Do not cache the struct layout in the metaclass
headius Jan 8, 2020
a5eb643
Remove whitespace.
headius Jan 8, 2020
3d0cb54
Update specs and libs from ffi gem.
headius Jan 10, 2020
95c73a6
Revert "Do not cache the struct layout in the metaclass"
headius Jan 10, 2020
24f7fc4
Merge branch 'master' into update_ffi
headius Feb 14, 2020
5996596
IS_DRAGONFLYBSD is define in Ruby elsewhere now
headius Feb 14, 2020
2ab63ec
remove struct by reference
ahorek Feb 15, 2020
bcec463
throw ArgumentError instead of SecurityError
ahorek Feb 15, 2020
16ea5d2
Add FFI::LastError.winapi_error
ahorek Feb 15, 2020
eeb3f6f
[RbConfig] RUBY_SO_NAME and RUBY_BASE_NAME
ahorek Feb 15, 2020
843067e
x32 build shouldnt contain a prefix
ahorek Feb 15, 2020
be3c5c1
Update specs from ffi gem
headius Feb 16, 2020
f40efb1
Add missing Field#get and Field#put
headius Feb 16, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions core/src/main/java/org/jruby/ext/ffi/NativeType.java
Expand Up @@ -50,6 +50,7 @@ public enum NativeType {
ULONG,
FLOAT,
DOUBLE,
LONGDOUBLE,
POINTER,
BUFFER_IN,
BUFFER_OUT,
Expand Down
37 changes: 0 additions & 37 deletions core/src/main/java/org/jruby/ext/ffi/Platform.java
Expand Up @@ -317,49 +317,12 @@ public static void createPlatformModule(Ruby runtime, RubyModule ffi) {
OS_TYPE os = platform.getOS();
module.defineConstant("ADDRESS_SIZE", runtime.newFixnum(platform.addressSize));
module.defineConstant("LONG_SIZE", runtime.newFixnum(platform.longSize));
module.defineConstant("OS", runtime.newString(OS.toString()));
module.defineConstant("ARCH", runtime.newString(platform.getCPU().toString()));
module.defineConstant("NAME", runtime.newString(platform.getName()));
module.defineConstant("IS_WINDOWS", runtime.newBoolean(os == OS.WINDOWS));
module.defineConstant("IS_BSD", runtime.newBoolean(platform.isBSD()));
module.defineConstant("IS_FREEBSD", runtime.newBoolean(os == OS.FREEBSD));
module.defineConstant("IS_DRAGONFLYBSD", runtime.newBoolean(os == OS.DRAGONFLYBSD));
headius marked this conversation as resolved.
Show resolved Hide resolved
module.defineConstant("IS_OPENBSD", runtime.newBoolean(os == OS.OPENBSD));
module.defineConstant("IS_SOLARIS", runtime.newBoolean(os == OS.SOLARIS));
module.defineConstant("IS_LINUX", runtime.newBoolean(os == OS.LINUX));
module.defineConstant("IS_MAC", runtime.newBoolean(os == OS.DARWIN));
module.defineConstant("LIBC", runtime.newString(LIBC));
module.defineConstant("LIBPREFIX", runtime.newString(LIBPREFIX));
module.defineConstant("LIBSUFFIX", runtime.newString(LIBSUFFIX));
module.defineConstant("BYTE_ORDER", runtime.newFixnum(BYTE_ORDER));
module.defineConstant("BIG_ENDIAN", runtime.newFixnum(BIG_ENDIAN));
module.defineConstant("LITTLE_ENDIAN", runtime.newFixnum(LITTLE_ENDIAN));
module.defineAnnotatedMethods(Platform.class);
}
@JRubyMethod(name = "windows?", module=true)
public static IRubyObject windows_p(ThreadContext context, IRubyObject recv) {
return context.runtime.newBoolean(OS == OS.WINDOWS);
}
@JRubyMethod(name = "mac?", module=true)
public static IRubyObject mac_p(ThreadContext context, IRubyObject recv) {
return context.runtime.newBoolean(OS == OS.DARWIN);
}
@JRubyMethod(name = "unix?", module=true)
public static IRubyObject unix_p(ThreadContext context, IRubyObject recv) {
return context.runtime.newBoolean(Platform.getPlatform().isUnix());
}
@JRubyMethod(name = "bsd?", module=true)
public static IRubyObject bsd_p(ThreadContext context, IRubyObject recv) {
return context.runtime.newBoolean(Platform.getPlatform().isBSD());
}
@JRubyMethod(name = "linux?", module=true)
public static IRubyObject linux_p(ThreadContext context, IRubyObject recv) {
return context.runtime.newBoolean(OS == OS.LINUX);
}
@JRubyMethod(name = "solaris?", module=true)
public static IRubyObject solaris_p(ThreadContext context, IRubyObject recv) {
return context.runtime.newBoolean(OS == OS.SOLARIS);
}
/**
* An extension over <code>System.getProperty</code> method.
* Handles security restrictions, and returns the default
Expand Down
1 change: 1 addition & 0 deletions core/src/main/java/org/jruby/ext/ffi/jffi/FFIUtil.java
Expand Up @@ -44,6 +44,7 @@ private static final Map<NativeType, com.kenai.jffi.Type> buildTypeMap() {

m.put(NativeType.FLOAT, com.kenai.jffi.Type.FLOAT);
m.put(NativeType.DOUBLE, com.kenai.jffi.Type.DOUBLE);
m.put(NativeType.LONGDOUBLE, com.kenai.jffi.Type.LONGDOUBLE);
m.put(NativeType.POINTER, com.kenai.jffi.Type.POINTER);
m.put(NativeType.BUFFER_IN, com.kenai.jffi.Type.POINTER);
m.put(NativeType.BUFFER_OUT, com.kenai.jffi.Type.POINTER);
Expand Down
25 changes: 24 additions & 1 deletion lib/ruby/stdlib/ffi.rb
@@ -1 +1,24 @@
require 'ffi/ffi'
if !defined?(RUBY_ENGINE) || RUBY_ENGINE == 'ruby' || RUBY_ENGINE == 'rbx'
Object.send(:remove_const, :FFI) if defined?(::FFI)
begin
require RUBY_VERSION.split('.')[0, 2].join('.') + '/ffi_c'
rescue Exception
require 'ffi_c'
end

require 'ffi/ffi'

elsif RUBY_ENGINE == 'jruby'
JRuby::Util.load_ext("org.jruby.ext.ffi.FFIService")
require 'ffi/ffi'

elsif defined?(RUBY_ENGINE)
# Remove the ffi gem dir from the load path, then reload the internal ffi implementation
$LOAD_PATH.delete(File.dirname(__FILE__))
$LOAD_PATH.delete(File.join(File.dirname(__FILE__), 'ffi'))
unless $LOADED_FEATURES.nil?
$LOADED_FEATURES.delete(__FILE__)
$LOADED_FEATURES.delete('ffi.rb')
end
require 'ffi.rb'
end
208 changes: 187 additions & 21 deletions lib/ruby/stdlib/ffi/autopointer.rb
@@ -1,37 +1,203 @@
#
# Copyright (C) 2008-2010 Wayne Meissner
# Copyright (C) 2008 Mike Dalessio
#
# Version: EPL 2.0/GPL 2.0/LGPL 2.1
# This file is part of ruby-ffi.
#
# The contents of this file are subject to the Common Public
# License Version 1.0 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.eclipse.org/legal/cpl-v10.html
# All rights reserved.
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
# implied. See the License for the specific language governing
# rights and limitations under the License.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# Alternatively, the contents of this file may be used under the terms of
# either of the GNU General Public License Version 2 or later (the "GPL"),
# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the EPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the EPL, the GPL or the LGPL.
# * 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 the Ruby FFI project 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 FFI
class AutoPointer < Pointer
extend DataConverter

# @overload initialize(pointer, method)
# @param pointer [Pointer]
# @param method [Method]
# @return [self]
# The passed Method will be invoked at GC time.
# @overload initialize(pointer, proc)
# @param pointer [Pointer]
# @return [self]
# The passed Proc will be invoked at GC time (SEE WARNING BELOW!)
# @note WARNING: passing a proc _may_ cause your pointer to never be
# GC'd, unless you're careful to avoid trapping a reference to the
# pointer in the proc. See the test specs for examples.
# @overload initialize(pointer) { |p| ... }
# @param pointer [Pointer]
# @yieldparam [Pointer] p +pointer+ passed to the block
# @return [self]
# The passed block will be invoked at GC time.
# @note
# WARNING: passing a block will cause your pointer to never be GC'd.
# This is bad.
# @overload initialize(pointer)
# @param pointer [Pointer]
# @return [self]
# The pointer's release() class method will be invoked at GC time.
#
# @note The safest, and therefore preferred, calling
# idiom is to pass a Method as the second parameter. Example usage:
#
# class PointerHelper
# def self.release(pointer)
# ...
# end
# end
#
# p = AutoPointer.new(other_pointer, PointerHelper.method(:release))
#
# The above code will cause PointerHelper#release to be invoked at GC time.
#
# @note
# The last calling idiom (only one parameter) is generally only
# going to be useful if you subclass {AutoPointer}, and override
# #release, which by default does nothing.
def initialize(ptr, proc=nil, &block)
super(ptr.type_size, ptr)
raise TypeError, "Invalid pointer" if ptr.nil? || !ptr.kind_of?(Pointer) \
|| ptr.kind_of?(MemoryPointer) || ptr.kind_of?(AutoPointer)

@releaser = if proc
if not proc.respond_to?(:call)
raise RuntimeError.new("proc must be callable")
end
CallableReleaser.new(ptr, proc)

else
if not self.class.respond_to?(:release)
raise RuntimeError.new("no release method defined")
end
DefaultReleaser.new(ptr, self.class)
end

ObjectSpace.define_finalizer(self, @releaser)
self
end

# @return [nil]
# Free the pointer.
def free
@releaser.free
end

# @param [Boolean] autorelease
# @return [Boolean] +autorelease+
# Set +autorelease+ property. See {Pointer Autorelease section at Pointer}.
def autorelease=(autorelease)
@releaser.autorelease=(autorelease)
end

# @return [Boolean] +autorelease+
# Get +autorelease+ property. See {Pointer Autorelease section at Pointer}.
def autorelease?
@releaser.autorelease
end

# @abstract Base class for {AutoPointer}'s releasers.
#
# All subclasses of Releaser should define a +#release(ptr)+ method.
# A releaser is an object in charge of release an {AutoPointer}.
class Releaser
attr_accessor :autorelease

# @param [Pointer] ptr
# @param [#call] proc
# @return [nil]
# A new instance of Releaser.
def initialize(ptr, proc)
@ptr = ptr
@proc = proc
@autorelease = true
end

# @return [nil]
# Free pointer.
def free
if @ptr
release(@ptr)
@autorelease = false
@ptr = nil
@proc = nil
end
end

# @param args
# Release pointer if +autorelease+ is set.
def call(*args)
release(@ptr) if @autorelease && @ptr
end
end

# DefaultReleaser is a {Releaser} used when an {AutoPointer} is defined
# without Proc or Method. In this case, the pointer to release must be of
# a class derived from AutoPointer with a {release} class method.
class DefaultReleaser < Releaser
# @param [Pointer] ptr
# @return [nil]
# Release +ptr+ using the {release} class method of its class.
def release(ptr)
@proc.release(ptr)
end
end

# CallableReleaser is a {Releaser} used when an {AutoPointer} is defined with a
# Proc or a Method.
class CallableReleaser < Releaser
# Release +ptr+ by using Proc or Method defined at +ptr+
# {AutoPointer#initialize initialization}.
#
# @param [Pointer] ptr
# @return [nil]
def release(ptr)
@proc.call(ptr)
end
end

# Return native type of AutoPointer.
#
# Override {DataConverter#native_type}.
# @return [Type::POINTER]
# @raise {RuntimeError} if class does not implement a +#release+ method
def self.native_type
raise RuntimeError.new("no release method defined for #{self.inspect}") unless self.respond_to?(:release)
if not self.respond_to?(:release)
raise RuntimeError.new("no release method defined for #{self.inspect}")
end
Type::POINTER
end

# Create a new AutoPointer.
#
# Override {DataConverter#from_native}.
# @overload self.from_native(ptr, ctx)
# @param [Pointer] ptr
# @param ctx not used. Please set +nil+.
# @return [AutoPointer]
def self.from_native(val, ctx)
self.new(val)
end
end

end
5 changes: 4 additions & 1 deletion lib/ruby/stdlib/ffi/buffer.rb
@@ -1 +1,4 @@
# This file intentionally left blank
#
# All the code from this file is now implemented in C. This file remains
# to satisfy any leftover require 'ffi/buffer' in user code
#
4 changes: 4 additions & 0 deletions lib/ruby/stdlib/ffi/callback.rb
@@ -0,0 +1,4 @@
#
# All the code from this file is now implemented in C. This file remains
# to satisfy any leftover require 'ffi/callback' in user code
#
67 changes: 67 additions & 0 deletions lib/ruby/stdlib/ffi/data_converter.rb
@@ -0,0 +1,67 @@
#
# Copyright (C) 2008-2010 Wayne Meissner
#
# This file is part of ruby-ffi.
#
# 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 the Ruby FFI project 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 FFI
# This module is used to extend somes classes and give then a common API.
#
# Most of methods defined here must be overriden.
module DataConverter
# Get native type.
#
# @overload native_type(type)
# @param [String, Symbol, Type] type
# @return [Type]
# Get native type from +type+.
#
# @overload native_type
# @raise {NotImplementedError} This method must be overriden.
def native_type(type = nil)
if type
@native_type = FFI.find_type(type)
else
native_type = @native_type
unless native_type
raise NotImplementedError, 'native_type method not overridden and no native_type set'
end
native_type
end
end

# Convert to a native type.
def to_native(value, ctx)
value
end

# Convert from a native type.
def from_native(value, ctx)
value
end
end
end