Ruby on LLP64

A

aquammles22f

Hi,

I am interested in embedding ruby on some physics simulation code. My
application is numerically intensive and it is important to me that the code
can be compiled with 64-bit windows in native 64 bit mode (at least soon in
future). I searched on the internet, but so far I cannot find much on this
issue except that the ruby official page says that it works only in win32
mode.
The source of my concern is that Win64 is based on LLP64, where sizeof(long)
is 4, while sizeof(void*) is 8. Here and there I find statements that say
size of long and void* has to be the same for ruby to run correctly because
of the way VALUE is used, but I just do not know how serious this constraint
is. For example, just defining

#define VALUE long long

will solve the problem or are there more fundamental problems regarding this
issue?

Thanks,
aquamm
 
Y

Yukihiro Matsumoto

In message "Re: Ruby on LLP64"

|The source of my concern is that Win64 is based on LLP64, where sizeof(long)
|is 4, while sizeof(void*) is 8. Here and there I find statements that say
|size of long and void* has to be the same for ruby to run correctly because
|of the way VALUE is used, but I just do not know how serious this constraint
|is. For example, just defining
|
|#define VALUE long long
|
|will solve the problem or are there more fundamental problems regarding this
|issue?

Maybe. The following patch would solve your concern, if I haven't
misunderstand the problem. Can you try?

matz.

--- ruby.h 7 Jun 2005 23:33:51 -0000 1.97.2.5
+++ ruby.h 26 Jul 2005 08:43:18 -0000
@@ -72,7 +72,14 @@ extern "C" {

-#if SIZEOF_LONG != SIZEOF_VOIDP
-# error ---->> ruby requires sizeof(void*) == sizeof(long) to be compiled. <<----
-#endif
+#if SIZEOF_LONG == SIZEOF_VOIDP
typedef unsigned long VALUE;
typedef unsigned long ID;
+#elif SIZEOF_LONG_LONG == SIZEOF_VOIDP
+typedef unsigned long long VALUE;
+typedef unsigned long long ID;
+#elif SIZEOF___INT64 == SIZEOF_VOIDP
+typedef unsigned __int64 VALUE;
+typedef unsigned __int64 ID;
+#else
+# error ---->> ruby requires sizeof(void*) == sizeof(long) to be compiled. <<----
+#endif
 
N

nobu.nokada

Hi,

At Tue, 26 Jul 2005 17:45:09 +0900,
Yukihiro Matsumoto wrote in [ruby-talk:149545]:
Maybe. The following patch would solve your concern, if I haven't
misunderstand the problem. Can you try?

I think it's not enough; printf() format specifiers for VALUE
would have to be changed.
 
A

aquammles22f

Maybe. The following patch would solve your concern, if I haven't
misunderstand the problem. Can you try?

Thanks, you already seem to know the answer. I will try when the machine
becomes available for me. Hope that this will be in the standard
distribution soon.

Aquamm.
 
N

nobuyoshi nakada

Hi,

At Tue, 26 Jul 2005 22:07:47 +0900,
Yukihiro Matsumoto wrote in [ruby-talk:149564]:
|I think it's not enough; printf() format specifiers for VALUE
|would have to be changed.

Should we use %p for all the case? Or it isn't enough?

I expect %p to work, but am not certain all old platforms
support %p. And VALUEs may need to be casted to pointers.

Also, id2ref() in gc.c assumes unsigned long is long enough to
hold pointers, and SIZEOF_LONG_LONG and LONG_LONG are defined
if __int64 is available.


Index: ruby.h
===================================================================
RCS file: /cvs/ruby/src/ruby/ruby.h,v
retrieving revision 1.117
diff -U2 -p -r1.117 ruby.h
--- ruby.h 26 Jul 2005 09:16:37 -0000 1.117
+++ ruby.h 27 Jul 2005 01:43:14 -0000
@@ -82,9 +82,6 @@ typedef unsigned long VALUE;
typedef unsigned long ID;
#elif SIZEOF_LONG_LONG == SIZEOF_VOIDP
-typedef unsigned long long VALUE;
-typedef unsigned long long ID;
-#elif SIZEOF___INT64 == SIZEOF_VOIDP
-typedef unsigned __int64 VALUE;
-typedef unsigned __int64 ID;
+typedef unsigned LONG_LONG VALUE;
+typedef unsigned LONG_LONG ID;
#else
# error ---->> ruby requires sizeof(void*) == sizeof(long) to be compiled. <<----
Index: eval.c
===================================================================
RCS file: /cvs/ruby/src/ruby/eval.c,v
retrieving revision 1.805
diff -U2 -p -r1.805 eval.c
--- eval.c 23 Jul 2005 02:46:41 -0000 1.805
+++ eval.c 27 Jul 2005 01:33:22 -0000
@@ -2827,11 +2827,11 @@ unknown_node(node)
ruby_current_node = 0;
if (node->flags == 0) {
- rb_bug("terminated node (0x%lx)", (long)node);
+ rb_bug("terminated node (%p)", node);
}
else if (BUILTIN_TYPE(node) != T_NODE) {
- rb_bug("not a node 0x%02lx (0x%lx)", BUILTIN_TYPE(node), (long)node);
+ rb_bug("not a node 0x%02lx (%p)", BUILTIN_TYPE(node), node);
}
else {
- rb_bug("unknown node type %d (0x%lx)", nd_type(node), (long)node);
+ rb_bug("unknown node type %d (%p)", nd_type(node), node);
}
}
@@ -5951,6 +5951,6 @@ rb_call(klass, recv, mid, argc, argv, sc

if (!klass) {
- rb_raise(rb_eNotImpError, "method `%s' called on terminated object (0x%lx)",
- rb_id2name(mid), recv);
+ rb_raise(rb_eNotImpError, "method `%s' called on terminated object (%p)",
+ rb_id2name(mid), (void *)recv);
}
/* is it in the method cache? */
@@ -10614,5 +10614,5 @@ rb_thread_deadlock()
VALUE e;

- sprintf(msg, "Thread(0x%lx): deadlock", curr_thread->thread);
+ sprintf(msg, "Thread(%p): deadlock", (void *)curr_thread->thread);
e = rb_exc_new2(rb_eFatal, msg);
if (curr_thread == main_thread) {
@@ -10916,11 +10916,11 @@ rb_thread_schedule()
}
FOREACH_THREAD_FROM(curr, th) {
- warn_printf("deadlock 0x%lx: %s:",
- th->thread, thread_status_name(th->status));
+ warn_printf("deadlock %p: %s:",
+ (void *)th->thread, thread_status_name(th->status));
if (th->wait_for & WAIT_FD) warn_printf("F(%d)", th->fd);
if (th->wait_for & WAIT_SELECT) warn_printf("S");
if (th->wait_for & WAIT_TIME) warn_printf("T(%f)", th->delay);
if (th->wait_for & WAIT_JOIN)
- warn_printf("J(0x%lx)", th->join ? th->join->thread : 0);
+ warn_printf("J(%p)", (void *)(th->join ? th->join->thread : 0));
if (th->wait_for & WAIT_PID) warn_printf("P");
if (!th->wait_for) warn_printf("-");
@@ -11158,9 +11158,9 @@ rb_thread_join(th, limit)
if (!rb_thread_dead(th)) {
if (th == curr_thread)
- rb_raise(rb_eThreadError, "thread 0x%lx tried to join itself",
- th->thread);
+ rb_raise(rb_eThreadError, "thread %p tried to join itself",
+ (void *)th->thread);
if ((th->wait_for & WAIT_JOIN) && th->join == curr_thread)
- rb_raise(rb_eThreadError, "Thread#join: deadlock 0x%lx - mutual join(0x%lx)",
- curr_thread->thread, th->thread);
+ rb_raise(rb_eThreadError, "Thread#join: deadlock %p - mutual join(%p)",
+ (void *)curr_thread->thread, (void *)th->thread);
if (curr_thread->status == THREAD_TO_KILL)
last_status = THREAD_TO_KILL;
@@ -12774,5 +12774,5 @@ rb_thread_inspect(thread)
VALUE str;

- str = rb_sprintf("#<%s:0x%lx %s>", cname, thread, status);
+ str = rb_sprintf("#<%s:%p %s>", cname, (void *)thread, status);
OBJ_INFECT(str, thread);

@@ -13311,7 +13311,7 @@ rb_f_throw(argc, argv)
}
if (tt->tag == PROT_THREAD) {
- rb_raise(rb_eThreadError, "uncaught throw `%s' in thread 0x%lx",
+ rb_raise(rb_eThreadError, "uncaught throw `%s' in thread %",
rb_id2name(SYM2ID(tag)),
- curr_thread);
+ (void *)curr_thread);
}
tt = tt->prev;
Index: gc.c
===================================================================
RCS file: /cvs/ruby/src/ruby/gc.c,v
retrieving revision 1.203
diff -U2 -p -r1.203 gc.c
--- gc.c 19 Jun 2005 17:15:46 -0000 1.203
+++ gc.c 27 Jul 2005 01:46:41 -0000
@@ -985,6 +985,6 @@ gc_mark_children(ptr, lev)

default:
- rb_bug("rb_gc_mark(): unknown data type 0x%lx(0x%lx) %s",
- obj->as.basic.flags & T_MASK, obj,
+ rb_bug("rb_gc_mark(): unknown data type 0x%lx(%p) %s",
+ (unsigned long)(obj->as.basic.flags & T_MASK), obj,
is_pointer_to_heap(obj) ? "corrupted object" : "non object");
}
@@ -1237,6 +1237,6 @@ obj_free(obj)

default:
- rb_bug("gc_sweep(): unknown data type 0x%lx(%ld)", obj,
- RANY(obj)->as.basic.flags & T_MASK);
+ rb_bug("gc_sweep(): unknown data type 0x%lx(%p)",
+ (unsigned long)RANY(obj)->as.basic.flags & T_MASK, (void *)obj);
}
}
@@ -1872,8 +1872,16 @@ id2ref(obj, id)
VALUE obj, id;
{
- unsigned long ptr, p0;
+#if SIZEOF_LONG == SIZEOF_VOIDP
+#define NUM2PTR(x) NUM2ULONG(x)
+#elif SIZEOF_LONG_LONG == SIZEOF_VOIDP
+#define NUM2PTR(x) NUM2ULL(x)
+#endif
+ VALUE ptr;
+ void *p0;

rb_secure(4);
- p0 = ptr = NUM2ULONG(id);
+ ptr = NUM2PTR(id);
+ p0 = (void *)ptr;
+
if (ptr == Qtrue) return Qtrue;
if (ptr == Qfalse) return Qfalse;
@@ -1886,8 +1894,8 @@ id2ref(obj, id)
ptr = id ^ FIXNUM_FLAG; /* unset FIXNUM_FLAG */
if (!is_pointer_to_heap((void *)ptr)|| BUILTIN_TYPE(ptr) >= T_BLOCK) {
- rb_raise(rb_eRangeError, "0x%lx is not id value", p0);
+ rb_raise(rb_eRangeError, "%p is not id value", p0);
}
if (BUILTIN_TYPE(ptr) == 0 || RBASIC(ptr)->klass == 0) {
- rb_raise(rb_eRangeError, "0x%lx is recycled object", p0);
+ rb_raise(rb_eRangeError, "%p is recycled object", p0);
}
return (VALUE)ptr;
Index: object.c
===================================================================
RCS file: /cvs/ruby/src/ruby/object.c,v
retrieving revision 1.173
diff -U2 -p -r1.173 object.c
--- object.c 23 Jul 2005 01:02:10 -0000 1.173
+++ object.c 27 Jul 2005 01:47:12 -0000
@@ -301,5 +301,5 @@ rb_any_to_s(obj)
VALUE str;

- str = rb_sprintf("#<%s:0x%lx>", cname, obj);
+ str = rb_sprintf("#<%s:%p>", cname, (void *)obj);
if (OBJ_TAINTED(obj)) OBJ_TAINT(str);

@@ -385,5 +385,5 @@ rb_obj_inspect(obj)

c = rb_obj_classname(obj);
- str = rb_sprintf("-<%s:0x%lx", c, obj);
+ str = rb_sprintf("-<%s:%p", c, (void *)obj);
return rb_exec_recursive(inspect_obj, obj, str);
}
Index: variable.c
===================================================================
RCS file: /cvs/ruby/src/ruby/variable.c,v
retrieving revision 1.124
diff -U2 -p -r1.124 variable.c
--- variable.c 23 Jul 2005 01:02:11 -0000 1.124
+++ variable.c 27 Jul 2005 01:47:23 -0000
@@ -206,5 +206,5 @@ rb_class_path(klass)
}
}
- path = rb_sprintf("#<%s:0x%lx>", s, klass);
+ path = rb_sprintf("#<%s:%p>", s, (void *)klass);
rb_ivar_set(klass, tmp_classpath, path);
 
N

nobuyoshi nakada

Hi,

At Wed, 27 Jul 2005 10:56:18 +0900,
nobuyoshi nakada wrote in [ruby-talk:149645]:
I expect %p to work, but am not certain all old platforms
support %p. And VALUEs may need to be casted to pointers.

Also, id2ref() in gc.c assumes unsigned long is long enough to
hold pointers, and SIZEOF_LONG_LONG and LONG_LONG are defined
if __int64 is available.

Oops, missing/vsnprintf.c didn't support %p where void* is
bigger than long.


Index: missing/vsnprintf.c
===================================================================
RCS file: /cvs/ruby/src/ruby/missing/vsnprintf.c,v
retrieving revision 1.9
diff -U2 -p -r1.9 vsnprintf.c
--- missing/vsnprintf.c 23 Jul 2005 01:02:17 -0000 1.9
+++ missing/vsnprintf.c 27 Jul 2005 02:13:37 -0000
@@ -65,4 +65,9 @@
#define u_short unsigned short
#define u_int unsigned int
+#ifdef HAVE_LONG_LONG
+#define quad_t LONG_LONG
+#define u_quad_t unsigned LONG_LONG
+#define _HAVE_SANE_QUAD_ 1
+#endif

#if !defined(HAVE_STDARG_PROTOTYPES)
@@ -423,4 +428,61 @@ BSD__ultoa(val, endp, base, octzero, xdi
}

+#ifdef _HAVE_SANE_QUAD_
+/*
+ * Convert an unsigned long long to ASCII for printf purposes, returning
+ * a pointer to the first character of the string representation.
+ * Octal numbers can be forced to have a leading zero; hex numbers
+ * use the given digits.
+ */
+static char *
+__uqtoa(val, endp, base, octzero, xdigs)
+ register u_quad_t val;
+ char *endp;
+ int base, octzero;
+ char *xdigs;
+{
+ register char *cp = endp;
+ quad_t sval;
+
+ switch (base) {
+ case 10:
+ if (val < 10) {
+ *--cp = to_char(val);
+ return (cp);
+ }
+ if (val > LLONG_MAX) {
+ *--cp = to_char(val % 10);
+ sval = val / 10;
+ } else
+ sval = val;
+ do {
+ *--cp = to_char(sval % 10);
+ sval /= 10;
+ } while (sval != 0);
+ break;
+
+ case 8:
+ do {
+ *--cp = to_char(val & 7);
+ val >>= 3;
+ } while (val);
+ if (octzero && *cp != '0')
+ *--cp = '0';
+ break;
+
+ case 16:
+ do {
+ *--cp = xdigs[val & 15];
+ val >>= 4;
+ } while (val);
+ break;
+
+ default: /* oops */
+ break;
+ }
+ return (cp);
+}
+#endif
+
#ifdef FLOATING_POINT
#include <math.h>
@@ -790,12 +852,19 @@ fp_begin: _double = va_arg(ap, double);
* -- ANSI X3J11
*/
+#if SIZEOF_LONG < SIZEOF_VOIDP
+ uqval = (u_quad_t)va_arg(ap, void *);
+#else
ulval = (u_long)va_arg(ap, void *);
+#endif
base = 16;
xdigs = "0123456789abcdef";
+#if SIZEOF_LONG < SIZEOF_VOIDP
+ flags |= QUADINT;
+#else
#ifdef _HAVE_SANE_QUAD_
- flags = (flags & ~QUADINT) | HEXPREFIX;
-#else /* _HAVE_SANE_QUAD_ */
- flags = (flags) | HEXPREFIX;
+ flags &= ~QUADINT;
#endif /* _HAVE_SANE_QUAD_ */
+#endif
+ flags |= HEXPREFIX;
ch = 'x';
goto nosign;
 
D

Daniel Brockman

nobuyoshi nakada said:
if (tt->tag =3D=3D PROT_THREAD) {
- rb_raise(rb_eThreadError, "uncaught throw `%s' in thread 0x%lx",
+ rb_raise(rb_eThreadError, "uncaught throw `%s' in thread %",
rb_id2name(SYM2ID(tag)),

You missed the =E2=80=98p=E2=80=99 after the =E2=80=98%=E2=80=99 there.

Given enough eyes... :)

--=20
Daniel Brockman <[email protected]>

So really, we all have to ask ourselves:
Am I waiting for RMS to do this? --TTN.
 
Y

Yukihiro Matsumoto

Hi,

In message "Re: Ruby on LLP64"

|I expect %p to work, but am not certain all old platforms
|support %p. And VALUEs may need to be casted to pointers.
|
|Also, id2ref() in gc.c assumes unsigned long is long enough to
|hold pointers, and SIZEOF_LONG_LONG and LONG_LONG are defined
|if __int64 is available.

I committed the fix including yours, but I might be too optimistic
about the old platform problem. Linux manual page says:

HISTORY

BSD 4.3 Reno has the flag 0, the length modifiers h and L, and the
conversions n, p, E, G, X (with current meaning) and deprecates
D,O,U.

OK, I will revert those changes for 1.8 branch, and put it only to the
HEAD, where we use our own implementation of sprintf.

matz.
 
N

nobuyoshi nakada

Hi,

At Wed, 27 Jul 2005 11:51:09 +0900,
Yukihiro Matsumoto wrote in [ruby-talk:149652]:
I committed the fix including yours, but I might be too optimistic
about the old platform problem. Linux manual page says:

HISTORY

BSD 4.3 Reno has the flag 0, the length modifiers h and L, and the
conversions n, p, E, G, X (with current meaning) and deprecates
D,O,U.

It wouldn't be a problem, perhaps. But


Index: gc.c
===================================================================
RCS file: /cvs/ruby/src/ruby/gc.c,v
retrieving revision 1.203
retrieving revision 1.204
diff -U2 -p -u -r1.203 -r1.204
--- gc.c 19 Jun 2005 17:15:46 -0000 1.203
+++ gc.c 27 Jul 2005 07:27:18 -0000 1.204
@@ -985,5 +985,5 @@ gc_mark_children(ptr, lev)

default:
- rb_bug("rb_gc_mark(): unknown data type 0x%lx(0x%lx) %s",
+ rb_bug("rb_gc_mark(): unknown data type %p(%p) %s",
obj->as.basic.flags & T_MASK, obj,
is_pointer_to_heap(obj) ? "corrupted object" : "non object");

The second argument is not a pointer.

@@ -1237,5 +1237,5 @@ obj_free(obj)

default:
- rb_bug("gc_sweep(): unknown data type 0x%lx(%ld)", obj,
+ rb_bug("gc_sweep(): unknown data type %p(%ld)", obj,
RANY(obj)->as.basic.flags & T_MASK);
}

This message differs from the above, so might confuse.

And I suspect vsnprintf.c needs quad_t not only u_quad_t, if
_HAVE_SANE_QUAD_ is defined.
 
Y

Yukihiro Matsumoto

Hi,

In message "Re: Ruby on LLP64"

|- rb_bug("rb_gc_mark(): unknown data type 0x%lx(0x%lx) %s",
|+ rb_bug("rb_gc_mark(): unknown data type %p(%p) %s",
| obj->as.basic.flags & T_MASK, obj,
| is_pointer_to_heap(obj) ? "corrupted object" : "non object");
|
|The second argument is not a pointer.
|
|@@ -1237,5 +1237,5 @@ obj_free(obj)
|
|- rb_bug("gc_sweep(): unknown data type 0x%lx(%ld)", obj,
|+ rb_bug("gc_sweep(): unknown data type %p(%ld)", obj,
| RANY(obj)->as.basic.flags & T_MASK);
| }
|
|This message differs from the above, so might confuse.
|
|And I suspect vsnprintf.c needs quad_t not only u_quad_t, if
|_HAVE_SANE_QUAD_ is defined.

I fixed all three. Thank you.

matz.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,176
Messages
2,570,949
Members
47,500
Latest member
ArianneJsb

Latest Threads

Top