Re: [perl #26057] [PATCH] Unified PMC/PObj accessors phase 2

2005-09-22 Thread Gordon Henriksen

On Sep 22, 2005, at 03:46, Joshua Hoblitt via RT wrote:


[ghenriksen - Thu Feb 05 20:15:50 2004]:

Leo,

The patch is at the URL below, and I've split it into 4 for you. The
classes-include-lib patch must be applied before any of the other 3.
I've resolved the 3-4 conflicts that occurred since the patch was  
first

abortively submitted on Monday, so the old patch (named
20040202-pmc-accessors.patch) should be discarded if it resurfaces.

http://www.ma.iclub.com/pub/parrot/

I realized that some of the accessor macros should've been named  
PObj_*
instead of PMC_* (since they apply to STRINGs and Buffers, too).  
So they

are as of this patch. I've also macro-ized access to UnionVal in
general, since it was sometimes used outside of the context of a
pobj. [*]

The old syntax continues to work, and so nobody's patches will break
excl. those w conflicts. But the pobj-cache.foo_val and
PMC_ptr1p/PMC_ptr2v macros ought to be treated as deprecated.

—

Gordon Henriksen
[EMAIL PROTECTED]

[* - Somewhat inadvisedly, I think. UnionVal is 8 bytes on a 32-bit
architecture, but bloats to 16 bytes on a 64-bit architecture. The
generic containers which use UnionVal don't appear to use both ptrs
simultaneously or make use of the void*/int pair, so could use an  
8-byte

structure as their bucket type.]


The URL for the patches seems to be dead.  Do you still want your
patches to be considered?

-J


There's absolutely no way that these patches would still apply  
cleanly. It would be less work to recreate them than to attempt to  
resolve the conflicts.


—

Gordon Henriksen
[EMAIL PROTECTED]




RE: [CVS ci] class refactoring 1 - Integer

2004-12-10 Thread Gordon Henriksen
Precedence.

print(day\n xor night\n);

-- 
 
Gordon Henriksen
IT Manager
ICLUBcentral Inc.
[EMAIL PROTECTED]

-Original Message-
From: Sam Ruby [mailto:[EMAIL PROTECTED] 
Sent: Friday December 10, 2004 13:28
To: [EMAIL PROTECTED]
Cc: [EMAIL PROTECTED]
Subject: Re: [CVS ci] class refactoring 1 - Integer

Mike Guy wrote:
 
 Perl5 Cxor always returns a standard boolean value, i.e.
 dualvar(0, '') or dualvar(1, '1').Perl6/Parrot should do the same
 thing.

Try:

 perl -le print 'day' xor 'night'

On the version of Perl I have installed, I get day as the result.

- Sam Ruby



RE: First draft, IO event design

2004-05-27 Thread Gordon Henriksen
Dan Sugalski wrote:

 Gordon Henriksen wrote:
 
  So, for GUI events, could calling into parrot and doing the 
  following from the OS event handler work to synchronously dispatch 
  an event?
 
  ... parrot-ify a mouse-moved event into $P5 ...
  post $P5
  checkevent
 
  Hm. No.
 
 For that I think you'd want:
 
   post $P5
   wait $P5

I suppose that would work, since the wait would block the main OS
thread. It does cause unnecessary context switches, though.

What happens in this case if the parrot eventloop is stopped? Does the
GUI thread block indefinitely in the wait op? That would keep the
program open even though parrot seemingly wanted to shut down.

Just decoupling the event queue and dispatch mechanisms seems cleaner to
my eye.

-- 

Gordon Henriksen
IT Manager
ICLUBcentral Inc.
[EMAIL PROTECTED]



Re: First draft, IO event design

2004-05-26 Thread Gordon Henriksen
On May 24, 2004, at 15.20, Dan Sugalski wrote:
Event Ops
=
The opcodes in this section are a combination of event requests and 
event handling ops. It doesn't include the IO ops--those are separate.

Most of the event request ops have two forms, one of which takes a 
callback PMC and user data PMC.

   checkevent
Explicitly check to see if there are any events pending in the event 
queue and, if so process one.
So, for GUI events, could calling into parrot and doing the following 
from the OS event handler work to synchronously dispatch an event?

... parrot-ify a mouse-moved event into $P5 ...
post $P5
checkevent
Hm. No. If there's already an event in the queue, then that won't 
work... :( Maybe this change, instead:

polleventq(out Pevent)
Shifts one event off of the queue into Pevent, or nulls Pevent.

dispatch(in Pevent)
Invokes the registered event handler(s) for Pevent.
Which makes checkevent really this:
polleventq Py
isnull Py, .NO_EVENT
dispatch Py
.NO_EVENT:

Gordon Henriksen
IT Manager
ICLUBcentral Inc.
[EMAIL PROTECTED]


RE: Non-flow-control logical tests

2004-05-20 Thread Gordon Henriksen
Dan Sugalski wrote:

 Right now the only good way to find out if a value is true or not is 
 to do something like:
 
   $I0 = 1
   if $P0, done
   $I0 = 0
   done:
 
 and look in $I0 for the result. This is OK, but if you're dealing 
 with a language with relatively primitive views of logical operations 
 (i.e they return 0 or 1) you end up with a *lot* of these little code 
 snippets when evaluating something like:
 
 if ((foo or bar) and ((x1 = 12) or (x2  15) or (x5 and x6 and 
 x7)) goto somewhere
 
 (And yes, that's close to a real code snippet. Feel my pain here :) 
 Not a huge deal to translate, but once you hit 30K basic blocks in a 
 sub the register coloring algorithm really gets unhappy and dies an 
 unpleasant death after an hour or so.

So: branches are bad for modern (CPUs|VMs|...). I thought we'd
established that? :)


 Anyway, because of it I'm pondering non-flowcontrol logical ops. That 
 is, something like:
 
 istrue I0, P5# I0 = 1 if P5 is true
 isgt I0, P5, P6  # I0 = i if P5  P6

There's definitely precedence for primitive bools, which is one step
beyond where you're writing about. PowerPCs have a condition register,
which is really better thought of as a set of 32 one-bit boolean
registers. The bits can be filled by gt and lt operators and the like.
Next, they can be 'd, ||'d, !'d, etc. Finally, the branch conditional
instruction executes, deciding whether to branch just off of that one
bit in the CR. Using CR operators can save pipeline bubbles over 's
with branches.

Of course, short-circuiting expression evaluation requires actually
branching mid-expression.


 Given the semi-self-serving nature of these I think some discussion's 
 in order first.

Doesn't seem self-serving at all if it helps make common code constructs
more amenable to the optimizer.

-- 

Gordon Henriksen
IT Manager
ICLUBcentral Inc.
[EMAIL PROTECTED]



RE: Events (I think we need a new name)

2004-05-13 Thread Gordon Henriksen
Matt Fowles wrote:

 I think Page already has a different meaning in computers, 
 namely a page of memory.

Not to mention a web page.

 For what it is worth, I support event as the name.

Being as I think I'm largely responsible for the sense that the name
needs to be changed, I should point out that I do actually support
calling these events--so long as they're modified to play nice with OS
event loops. Upon reflection, that just requires a means to
synchronously dispatch an event to a handler chain from a C callback.

-- 

Gordon Henriksen
IT Manager
ICLUBcentral Inc.
[EMAIL PROTECTED]



Re: Event design sketch

2004-05-12 Thread Gordon Henriksen
On May 12, 2004, at 09.12, Dan Sugalski wrote:

At 2:59 PM -0400 5/11/04, Gordon Henriksen wrote:

As I pointed out in another post, this doesn't work for integrating 
with at least two significant event sources: Windows and the Mac 
OS. :) UI events need to be handled synchronously on the thread to 
which they were delivered, since the GUI APIs are not threadsafe.
Oh, it's worse than thatGUI commands need to be issued from the main 
thread, at least with OS X. (There's no actual requirement as to which 
thread handles the actual events as long as you treat the OS event 
queue as the thread-unsafe thing it seems to be) Or so the docs seem 
to indicate, though they may be a bit conservative.
That's exactly true, and exactly my point. GUI APIs are definitely not 
thread-safe, and for very good reasons. Not only do the system APIs 
essentially mandate it, but any depth of thought will make it obvious 
that UI events must be handled synchronously. Keeping also in mind that 
the main event loop stays on the execution stack, waking up to call 
back into event handlers; WaitNextEvent is dead. So funneling all event 
delivery through a Big Parrot Queue is unfeasible if your definition of 
event includes UI events. UI events, with their threading and context 
requirements, are really much more an issue of NCI callbacks, 
re-entrancy, and wrappers around system types.

That said, the technology you're proposing is still, exactly as it 
stands, incredibly useful:

	 Asynchronous completion.
	 Signal handling.
	 Runtime state change notifications, for undoing speculative 
optimizations.

It's just not at all suitable for handling GUI events. Which is 
perfectly fine: Just either

	1. Don't call it events so that people aren't disappointed and 
frustrated, or
	2. Figure out some way to fold in GUI events.



Gordon Henriksen
IT Manager
ICLUBcentral Inc.
[EMAIL PROTECTED]

Haps

2004-05-12 Thread Gordon Henriksen
That's really and truly evil. I love it.

-- 

Gordon Henriksen
IT Manager
ICLUBcentral Inc.
[EMAIL PROTECTED]



RE: Event design sketch

2004-05-12 Thread Gordon Henriksen
Brent 'Dax' Royal-Gordon wrote:

 Gordon Henriksen wrote:
 
  Oh, it's worse than that—GUI commands need to be issued 
 from the main 
  thread, at least with OS X. (There's no actual requirement 
 as to which 
  thread handles the actual events as long as you treat the OS event 
  queue as the thread-unsafe thing it seems to be) Or so the 
 docs seem 
  to indicate, though they may be a bit conservative.
 ...
  1. Don't call it events so that people aren't 
 disappointed and 
  frustrated, or
  2. Figure out some way to fold in GUI events.
 
 One general-purpose Parrot event queue, plus another for the 
 GUI thread. 
   When you call a method on the GUI bindings, it really enqueues an 
 event for the GUI thread, which receives the message and calls the 
 actual method.
 
 Or for that matter, enqueue an event in the main queue that 
 only the GUI thread is interested in.

Brent,

That's tantamount to fine-grained locking on a collection; instead of a
mutex, an OS thread does the serialization. Fine-grained locking doesn't
work.

It's also going to be ridiculously slow.

Can you imagine what havoc this would wreak with multiple writers? Not
a solution.

The Carbon Event Manager is (synchronously) interested in your
callback's return value; if a Carbon event handler callback returns
kEventNotHandled, the Event Manager may supply a default implementation.

Not a solution. A GUI event simply MUST be handled from the context that
the operating system or GUI toolkit called the callback; anything else
is addled.



This might be too large a problem, despite seemingly easy to squash into
one API at the first pass. Might it help to consider breaking down and
decoupling the problem for better flexibility? Here's a pass...

 - class: EventData

Parameter block storing information about an event that has
occurred. Passed as the only argument to event handlers by
convention. No intrinsic fields or operations.

Subclasses: IOEventData,
SignalEventData,
MacMouseEventData,
Win32MouseEventData,
...

 - class: Event

A registery of event handlers for a particular event. Defines
ordering and fallback behavior and soforth, should multiple
handlers be registered.

Instantiate one Event for each distinguishable kind of event
which can occur; handlers can then.

Anonymous handlers? Not so much. How magic collections which
make Events on-demand?

Methods: RegisterHandler(handler)
 UnregisterHandler(handler)
   This API is awkward without method pointers.
   So add a userdata parameter; whatever, details.

 CallHandlers([EMAIL PROTECTED])
   Synchronously calls registered handlers.
   Parrot's event loop would call this, as would
   anything which wanted to control the thread on
   which events were dispatched.

Subclasses? Maybe to override the behavior of CallHandlers,
for specialized fallback behaviors. Or perhaps to register
interest in the event with the OS event.

 - class: EventSource

Something that can wake parrot's main event loop.

Methods: Enable()
   Turn on the spigot: Register the event source
   with parrot's main event loop.

 Disable()
   Turn the spigot back off. Non-recurring sources
   (e.g., one-off timers) ought to disable themselves
   automatically.

Subclasses: Timer,
IOEventSource,
SignalEventource

This is all user-mode API, very close to the operations I'd want to
see from an HLL. Adapt for C/parrot core use as appropriate. I've
avoided cluttering the API by adding state variables; method pointers
generally take care of that just fine.

If EventData is kept naïve of Event, and Event is kept naïve of
EventSource, then I think this comprises a pretty agile design.

All a GUI event loop needs to do to fit in is to invoke
CallHandlers(...) on an Event from a C shim. The event will be handled
synchronously on that thread, and any return values necessary can be
passed back in a field of the EventData. (Parameter blocks are good for
both directions, after all.) Since the event loop would know the
thread/interpreter, it can safely create the EventData object.

For high-performance subsystems, it might be best to be able to skip the
EventData if no parameters to the operation are necessary.

Also consider user-mode events. A user program might want to use events
to, say, signal changes in data to UI views which are displaying that
data. That's probably a synchronous, rather than asynchronous,
operation.

All of the scary asynchronous stuff is hidden away in the EventSource
and parrot's event loop. Nothing above is so intrinsically asynchronous.
Which is fine.

The internal event queue and runloop undoubtedly require considerable

RE: Event design sketch

2004-05-11 Thread Gordon Henriksen
Dan Sugalski wrote:

 At 10:33 AM -0700 5/11/04, chromatic wrote:
 On Tue, 2004-05-11 at 10:24, Dan Sugalski wrote:
 
   I'm also curious how to write an interface to an 
 existing event system.
   Being able to write it all in PASM is a bonus.
 
   I don't think it can be all-PASM, except maybe (and maybe not...)
   with a separate thread for the existing event source. To 
 do it in all
   pasm means calling back into parrot from interrupt level, 
 which isn't
   really doable, or have a thread just waiting on events from the
   alternate event system to post into the parrot event queue.
 
 Another approach may be to expose the PollEvent and 
 WaitEvent functions
 to the event system as alternate sources of events.  If I can do that
 from PASM, I think I'm okay.
 
 That'll still need some C. The event system as it stands is all 
 active--all event sources put events into the system, rather than 
 having the event system go looking at event sources for events. You'd 
 either need to queue up regular timer events to go check for new 
 stuff or have a thread actively polling the source for events and 
 throwing them into parrot's event queue.

What's the plan for integrating with system events, then? Mac OS X and
Windows both have robust, irreplacable, system-managed event loops.
parrot's loop can (and should) run in a parallel thread to those, but
certainly can't presume to take over entirely. It simply can't work.

If you're calling this an event system, it ought to mesh in with the
notion of events that every programmer who uses them will have:

 - Mouse events.
 - Keyboard events.
 - Redraw events.
 - Drag-'n'-drop events.
 - Menu command events.
 - etc., etc., etc..

Problems in this domain also include: Focus management, propagation
along the responder chain, enabling/disabling commands, default event
handlers.

You won't get any of these events from an I/O wait on Win32 or on a Mac;
they're not even delivered via Unix I/O. Note that the thread on which
these events must be handled is the thread to which they are delivered
(and not by parrot's event loop): UI APIs are not thread-safe. So the UI
thread needs to be able to enter a parrot callback on the same thread. 

Asynchronous I/O completion is surely considered less of an
event-handling problem and more of a thread-synchronization problem.
Also, parrot async I/O completion hopefully won't need to be serialized
through an I/O retirement thread (event loop, whatever you want to
call it) except when the platform winds up requiring that through sloppy
async APIs.

This is really an asynchronous notification API, where asynchronous
completion is a very important fires-once form of asynchronous
notification. It's far, far below what programmers will expect when
hearing the term event.

.NET's thread pool is a very close match to what you're discussing. A
.NET WaitHandle is almost identical to your event source. (Right down
to the waitone/waitany ops you just suggested.)

The intuitive concept of events isn't even in the same class of
problem that your document addresses. Probably best to use another term
for this (very cool, very necessary) technology.

-- 

Gordon Henriksen
IT Manager
ICLUBcentral Inc.
[EMAIL PROTECTED]


P.S. - Now that they're in, have you considered using objects and
methods instead of opcodes to define parrot APIs? If parrot technologies
are exposed through objects, you'll save on opcount, and HLLs won't need
to build yet another a shim for every new parrot feature. Dogfood.



RE: Event design sketch

2004-05-11 Thread Gordon Henriksen
Dan Sugalski wrote:

 chromatic wrote:
 
  So for SDL, I'd start a separate thread that blocks on
SDL_WaitEvent,
  creating and posting events when they happen.  My main program would
  handle the events as normal Parrot events.  Standard producer
consumer 
  stuff.
 
  Since it's blocking, it won't eat up too many resources -- 
  that's nice. It'd be nice to have the SDL event thread ignore events

  I don't care about though, instead of creating event PMCs I'll just 
  throw away later.
 
 You can always Get Horribly Clever in the event handling thread and 
 look at what the SDL library's handed you. If it's uninteresting you 
 can just throw it away rather than creating an event to be discarded.
 
  Is this what you have in mind?
 
 Yep.

As I pointed out in another post, this doesn't work for integrating with
at least two significant event sources: Windows and the Mac OS. :) UI
events need to be handled synchronously on the thread to which they were
delivered, since the GUI APIs are not threadsafe. Trying to handle these
events from another thread is, quite simply, a doomed endeavour.

-- 

Gordon Henriksen
IT Manager
ICLUBcentral Inc.
[EMAIL PROTECTED]



Reference/value semantics, destructive operators, etc.

2004-04-21 Thread Gordon Henriksen
(Just a quick post from work. Lost the thread, sorry, so it's not a
f'up.)
 
Why not use +=, -=, *=, /=, etc.? Arithmetic operators would take just 2
arguments and mutate the first. I always used this technique for
implementing value-ish classes in C++:

thing operator +(thing lhs, thing rhs) {
return new thing(lhs) += rhs;
}

This is really pretty much the same problem.
 
Current add-in-place op becomes:

# P3 = P4 + P5
P3 = P4 # (copy)
P3 += P5

Add-in-place to a global becomes:

; $::whatever += P4
fetch_global P3, whatever
P3 += P4

Chained expressions become:

# P3 = P4 + P5 + P6 + P7
P3 = P4 # (copy)
P3 += P5
P3 += P6
P3 += P7

I can see generating this syntax from an AST without completely
inordinate pain. It's not as convenient as a temp-making addition (Px =
Py + Pz) operator would be, but it also solves the modify-in-place
problem (since PMCs have reference semantics). So long as the x=
operators are also available for native types, so that the the same AST
traversal algorithm can work for all register types.
 
-- 

Gordon Henriksen
[EMAIL PROTECTED]


Re: Basic Library Paths (was Re: ICU data file location issues)

2004-04-19 Thread Gordon Henriksen
On Saturday, April 17, 2004, at 10:35 , Gordon Henriksen wrote:

Which suggests to me a linked list of resource resolvers. First one in 
the chain to return a file handle to the data or PBC wins. The head of 
parrot's own system chain would be available to be appended to any 
other chains that wanted it.
And the more I mull this over, the more I really come up with maybe 4 
slots in the search chain which are logically important. The order is up 
for debate, but they all need to be in there (whenever they apply, that 
is).

1.  Paths relative to the PBC binary which is searching for a library.
2.  Paths relative to the embedding application.
3.  Paths relative to parrot itself (be that libparrot.shlib or parrot).
4.  Paths to system libraries as specified by the administrator.
When searching for resources, only #1 should be used. Here are some 
examples:

PBC File: (whatever)
Host app: /usr/local/bin/parrot
Parrot: /usr/local/lib/libparrot.shlib
Consider searches for:
icu.dat
Search path:
1.  /usr/local/shared   # Relative to executable
PBC File: D:\inetpub\wwwroot\example.pbchtml
Host app: C:\Apache\libexec\httpd.exe
Parrot: C:\Parrot\lib
Consider searches for:
icu.dat
mod_parrot.pbc
My::WWWUtil.pbc
Time::HiRes.pbc
Search path:
D:\inetpub\wwwroot{,\lib,\..\lib}  # Relative to PBC
C:\Apache\libexec{,\lib,\..\lib}  # Relative to host app
C:\CPAN\lib  # System libraries
C:\Parrot\lib  # Relative to parrot
PBC File: ./bin/fib
Host app: /home/me/bin/parrot
Parrot: /home/me/bin/parrot
Consider searches for:
icu.dat
Time::HiRes.pbc
fib.parrot_resource_file
One possible search path:
./bin/{,/lib,/../lib}  # Relative to PBC
/usr/local/lib  # System libraries
/home/me/lib  # Relative to parrot


The scenario which gives me a little bit of heartburn is one like this, 
though:

Consider, say, an e-commercesite package. Call it OneStep::ECS. Runs 
under mod_parrot in Apache. Has hooks to load plugins:

	 Third-party plugins to provide connectivity to payment processing 
engines (call it OneStep::VeriSignPayflow.pbc).
	 First-party plugins allowing the customer to integrate his 
storefront with his database (call it 
MySite::OneStepECSCustomizations.pbc).

Now consider searches for VeriSign::PayflowPro.pbc, PayFlowPro.dll, 
MySite::CRM.pbc, MySite::Reporting.pbc, mysite_logo.png, 
Time::HiRes.pbc, libparrot.pbc, CGI.pbc

So maybe some libraries are hosts and need to be included in the 
search paths of libraries which are linked to them. One could even look 
at libparrot that way, in which case the search path model becomes:

Paths relative to this PBC file.
Paths relative to its hosts.
Paths relative to its hosts' hosts.
Paths relative to its hosts' hosts' hosts.
...
Paths configured by the system administrator.


Gordon Henriksen
[EMAIL PROTECTED]


Re: ICU data file location issues

2004-04-19 Thread Gordon Henriksen
On Saturday, April 17, 2004, at 02:17 , Gordon Henriksen wrote:

On Thursday, April 15, 2004, at 02:25 , Jeff Clites wrote:

For Unix platforms at least, you should be able to do this:

	executablePath = isAbsolute($0) ? dirname($0) : cwd().dirname($0)
That absolutely does not work, as already pointed out. Ths looks like a 
reasonable reference implementation (LGPL), though:

http://www.opensource.apple.com/darwinsource/10.3/libiconv-9/libiconv/srclib/
progreloc.c
On Windows and Linux, it uses Win32 and /proc to provide a robust 
implementation. Otherwise, it guesses by looking at $0 and $ENV{PATH}.

My guess is that there's a more reliable (and non-portable) way to do 
this on Mac OS X, since Carbon applications need to reliably open the 
resource fork of the executable.
Ah! Indeed there is.

http://developer.apple.com/documentation/Carbon/Reference/Process_Manager/
index.html
And, indeed, it is witheringly non-portable.

	CFDictionaryRef dict = ProcessInformationCopyDictionary(
		kCurrentProcess, kProcessDictionaryIncludeAllInformationMask);
	CFString cfPath = (CFString *) CFDictionaryGetValue(dict, 
kIOBundleExecutableKey);
	CFIndex length = CFStringGetMaximumSizeForEncoding(cfPath, 
kCFEncodingUTF8);
	char *path = (char *) malloc(length + 1);
	CFStringGetCString(cfPath, path, length + 1, kCFEncodingUTF8);
	CFRelease(dict);

Ahem.

I'm sure the ProcessInformationCopyDictionary API is implemented in 
terms of something sane at the Darwin level, but God only knows what it 
is.



Gordon Henriksen
[EMAIL PROTECTED]


Re: Basic Library Paths (was Re: ICU data file location issues)

2004-04-19 Thread Gordon Henriksen
Dan Sugalski wrote:

Brent 'Dax' Royal-Gordon wrote:

Dan Sugalski wrote:

3) Parrot itself (the main executable) has a static, global 1K buffer 
in it that starts and ends with some recognizable string (like, say, 
***+++***START| and |END***+++***) so we can find it and 
overwrite the contents if the library gets moved, for use on 
platforms where the only way to put a path in is to stick it 
statically in the executable.
That's pretty disgusting, but I don't know that I have a better idea.
There isn't one, alas, at least for some people.
Everyone running tripwire, et al. (or simply md5sum'ing files to verify 
integrity) will just love this strategy to death.

Finding resource and library files relative to the binary really is a 
very good strategy. Windows is adopting the placed-near-the-binary 
strategy for locating resources and libraries. It has completely 
eliminated DLL hell for .NET programs. Mac OS 7 through X have all 
used the same strategy. They have never had major problems with library 
or resource location. Looks like a strong precedent and a proven 
technique.

Of course, one can find pathological casesespecially on Unix, which 
seems designed to thwart this sort of easy-to-administer technology:

	 parrot binary unlink'd between exec and main(). (Can't happen on 
Windows.)
	 Launched through a symlink to the binary.
	 Launched through a hard link to the binary.
	 bin/ is a symlink, so ../share won't work.
	 Platform can't find the binary. (Can't happen on Windows, Linux, 
or Mac OS X.)
	chroot (which, in general, near-the-binary solves rather than 
complicates).

But I'd say these are all are heavily outweighed by the advantages. And, 
in any case, it's a trivial matter at this point in design to offer 
support for replacing a call to Parrot_get_bin_path() (or whatever) with 
/usr/local/bin at configure time. That resolves all of the above. With 
a loss of functionality, true, but: Users on platforms which can't 
support this feature won't after all expect /opt/parrot to work after it 
was mv'd.

As for the security concerns of trusting anything but one's current 
binary*, parrot could adopt a cryptographic solution for verifying 
integrity of resource files, if anybody's really all that worried about 
an errant Unicode character database.



Gordon Henriksen
[EMAIL PROTECTED]
* - Is the binary itself is really all that trustworthy in the first 
place? If a user is executing a program through an untrusted or 
compromised path, they're already putting their life in their hands, and 
accessing ${bin}/../share won't make the configuration any more 
trustworthy.


Re: Basic Library Paths (was Re: ICU data file location issues)

2004-04-19 Thread Gordon Henriksen
On Thursday, April 15, 2004, at 01:48 , Dan Sugalski wrote:

At this point I can say I don't honestly care all that much, and most 
of my worries are based on vague feelings that there are platforms out 
there where finding the actual executable name is somewhere between 
hard and impossible. I will, then, do the sensible thing and just punt 
on this--we can work out a best practices thing and enshrine it as the 
default on systems which can support it and be done with it.

The other question, then, is do we see the need for multiple categories 
of library which would want separately settable library paths?
Wouldn't it be sensible to build something robust enough to also solve 
the problems of finding parrot user libraries and user resources? In 
which case, a static search path is decidedly retro. It would hardly 
make sense to not include, at the front of the search path, directories 
relative to the PBC file trying to find its libraries or resources.*

For finding resources, one doesn't generally want to fall back to system 
paths. Finding libraries is another matter.

Then there's the mention of using URLs to load resources (e.g., over 
HTTP). Which seems sensible and forward-thinking to me.

Which suggests to me a linked list of resource resolvers. First one in 
the chain to return a file handle to the data or PBC wins. The head of 
parrot's own system chain would be available to be appended to any 
other chains that wanted it.



Gordon Henriksen
[EMAIL PROTECTED]
(* - The directory containing every loaded PBC file is not at all 
important; consider an application like Apache+mod_parrot which is 
loading multiple independent PBC files. It would be useful to allow the 
administrator to install both the production PBC in addition to a 
development release of the same application on the same web server [just 
at different paths], with confidence that mod_parrot won't get the two 
confused. [IIS can do this. It's very cool.])


Re: ICU data file location issues

2004-04-19 Thread Gordon Henriksen
On Thursday, April 15, 2004, at 02:25 , Jeff Clites wrote:

For Unix platforms at least, you should be able to do this:

	executablePath = isAbsolute($0) ? dirname($0) : cwd().dirname($0)
That absolutely does not work, as already pointed out. Ths looks like a 
reasonable reference implementation (LGPL), though:

http://www.opensource.apple.com/darwinsource/10.3/libiconv-9/libiconv/srclib/
progreloc.c
On Windows and Linux, it uses Win32 and /proc to provide a robust 
implementation. Otherwise, it guesses by looking at $0 and $ENV{PATH}.

My guess is that there's a more reliable (and non-portable) way to do 
this on Mac OS X, since Carbon applications need to reliably open the 
resource fork of the executable.



Gordon Henriksen
[EMAIL PROTECTED]


RE: Dates. Or, rather, months

2004-03-11 Thread Gordon Henriksen
(YAY!)

-- 

Gordon Henriksen
IT Manager
ICLUBcentral Inc.
[EMAIL PROTECTED]


 -Original Message-
 From: Dan Sugalski [mailto:[EMAIL PROTECTED] 
 Sent: Thursday March 11, 2004 10:34
 To: [EMAIL PROTECTED]
 Subject: Dates. Or, rather, months
 
 
 Okay, unless there are objections I'm going to rejig the date 
 decoding logic to return months from 1-12, rather than 0-11. We 
 already fix years, so it seems to make sense.
 -- 
  Dan
 
 --it's like 
 this---
 Dan Sugalski  even samurai
 [EMAIL PROTECTED] have teddy bears and even
teddy bears get drunk
 



RE: Dates and Times

2004-03-09 Thread Gordon Henriksen
Jared Rhine wrote:

 Gordon Henriksen wrote:
 
  gmclock(out Nx)
  UTC clock in seconds since  hrs Jan 1, 2000,
  ignoring leap seconds.
  
  tolocal out Nx, out Iy, in Nz
  x is set to z converted to the local time zone. y - 1
  if Daylight Savings Time was in effect at z; y - 0
  otherwise.
  
  splittime Px, Nx
  Splits date up like Perl 5 gmtime. (But without
  annoying y -= 1900 and m -= 1?)
  
  add_months(out Nx, in Ny, in Nz)
  Sets x to y + z months.
 
 This proposal was perhaps taken offline by the core team, but to avoid
 a Warnock, I'll pipe up and say I like this proposal as a core
 instruction set.

Thanks for the anti-Warnock.


 It'd be nice if the first item, gmclock wasn't defined in terms of
 UTC.  Regardless of the future fate of UTC leap seconds, any
 UTC-based clock would need to account for leap seconds going back,
 right?  So it seems that GMT should be preferred in the core, with any
 UTC calculations being performed at the language or module level.
 
 So, gmclock seems the right opcode (not utcclock), making the
 definition GMT clock in seconds since  hrs Jan 1, 2000.

Fair enough. I wasn't trying to load terms for once. In point of fact,
this set of opcodes is very much agnostic to whether or not leap 
seconds are used.

The reason that add_months belongs as an opcode is because there's been
no decision made re leap seconds, and in fact some anti-decisions have
been proposed. Without some way to manipulate dates in accordance with
the actual rules that get used (which might be platform dependent at
this point), a portable program can't be written. Were this decision
made solidly, then all of the ops except gmclock and possibly tolocal
would be better written as library code.

Were leap seconds to fall in the middle of a month, then we would need
to have an add_days op. Since that's not the case, the assumption that
a day is 86400 seconds long is safe so long as you avoid adding enough 
days to cross a year boundary. Meanwhile, add_months encapsulates the 
leap-second worries AND lets IMC code conveniently manipulate dates 
without days-per-month tables and is-it-a-leap-year algorithms (which
are required to convert add_months to add_days).


 Daylight savings time calculation seems appropriate to stay in the
 core, but perhaps additional opcodes are need to set the clock's
 understanding of the time zone used for DST calculations?

Indeed; the local time zone is pretty narrow-minded and backwards-
thinking. The problem is balancing weight with efficiency, and time
zone databases are pretty heavy critters, which make me think get 
thee OUT of the core!...


 # years
 Nz = Py[5]
 Nz = Nz - 2000# epoch based at year 2000
 Nz = Nz * 12  # = months per year
 
 inappropriate sarcasmI look forward to the exciting advancement of
 changing from subtracting 1900 from all my dates to subtracting 2000
 or dealing with negative numbers; that'll change everything and really
 advance the state of the art./sarcasm

What you're complaining about is the elements of Perl's gmtime/localtime
arrays. Actually, I suggested removing that quirk from splittime:

  splittime Px, Nx
  Splits date up like Perl 5 gmtime. (But without
  annoying y -= 1900 and m -= 1?) ^^^
^^
The Nz - 2000 is conversion *to* the epoch, not reinterpreting the value

in the array.

Unless you think storing dates and times as the number of seconds since
Jan 1  is a good idea, perhaps. :)

I'd used Jan 1 2000 as an epoch since Larry suggested that's what he was
planning for Perl 6 to use.

-- 

Gordon Henriksen
IT Manager
ICLUBcentral Inc.
[EMAIL PROTECTED]



RE: Dates and Times

2004-03-09 Thread Gordon Henriksen
Edward S. Peschko wrote:

 Gordon Henriksen wrote:
 
  Leave parsing and formatting entirely to libraries. 
  Absolutely no need for that in the instruction set.
 
 well, I have a bit of a problem with that... As it was pointed out
 before, people have gone hogwild with the parsing and formatting
 routines, and its a bloodbath of modules on CPAN with different
 methods for time parsing.

Not an opcode doesn't mean balkanized. There is a parrot/stdlib
directory.

 Perhaps there could be an extra argument for locales - and maybe the 
 op could be split in two (ie: for (r_)gm_fmtime, (r_)local_fmtime), 
 but for me, in processing time values most of the time you know the 
 format for dates - as long as they are machine generated. If they are
not, 
 you can always fall back to the very slow Date::Parse and cousins, or 
 maybe string these ops along in a chain of '||' to query for multiple
 formats.  
 
 But how many times are you going to need to parse formats 
 like '3 weeks from next Wednesday?'. 

Uh. Yeah.

This sort of creeping featuritis is why date formatting and especially 
parsing do NOT belong as opcodes. It's too big a problem to solve in the

core, and regardless of how rich the interface is, it'll never be quite 
rich enough to satisfy everyone.

Someone depends on formats like 3 weeks from next Wednesday on a
regular
basis. You might not need to format dates from the Chinese lunar
calendar,
but you can bet that it's vital to someone. Eras? Well, sure. Fuzzy date
parsing? (Guessing.) Oh, baby. Global time zone database? Bring it on. A
kl-hw (Klingon Homeworld) locale? But of course!

There'll always be pressure to further enhance the feature, increasing
parrot's *core* memory footprint. You can't skip loading the implem-
entation of core parrot ops like you can avoid DateTime.pm.

So keep it to (un)loadable user code, and provide a class that solves
90%
of the problem in the stdlib.


Also, trying to nail down a rich interface before seeing what Larry has 
in mind for Perl 6 date handling is roughly a waste of time

-- 

Gordon Henriksen
IT Manager
ICLUBcentral Inc.
[EMAIL PROTECTED]



Re: Dates and Times

2004-03-09 Thread Gordon Henriksen
Edward,

Want to call strptime? Use NCI. No need for anything new in the core. 
That's WHY it's the CORE.



Gordon Henriksen
[EMAIL PROTECTED]


RE: Dates and Times

2004-03-03 Thread Gordon Henriksen
Oracle actually has the most elegant Gregorian time manipulation
implementation I've seen. The only operations it really supports are
add_months and add_days. Year +/- can be implemented with add_months*12.
All of add_week|hour|minute|second|ms|us|ns can be synthesized from
add_days. This scarcity of operations yields the elegance, and is
perfect for an instruction set. Based on that model, I'd suggest:

gmclock(out Nx)
UTC clock in seconds since  hrs Jan 1, 2000, ignoring leap
seconds.

gmtime(out Px, in Nx)
Splits date up like Perl 5 gmtime. (But without annoying y -= 
1900 and m -= 1?)

localtime(out Px, in Nx)
Splits date up like Perl 5 localtime. (But without annoying y -=

1900 and m -= 1?)

add_months(out Nx, in Ny, in Nz)
Sets x to y + z months.

That's the minimal core set of operations.

But the redundancy of gmtime and localtime has always bothered me, so I
could see this instead:

gmclock(out Nx)
UTC clock in seconds since  hrs Jan 1, 2000, ignoring leap
seconds.

tolocal out Nx, out Iy, in Nz
x is set to z converted to the local time zone. y - 1 if 
Daylight Savings Time was in effect at z; y - 0 otherwise.

splittime Px, Nx
Splits date up like Perl 5 gmtime. (But without annoying y -= 
1900 and m -= 1?)

add_months(out Nx, in Ny, in Nz)
Sets x to y + z months.



By contrast, date manipulation in Perl 5 is truly horrid. I've seen
modules which turned a gmtime array back into an epoch-base value by
using localtime to converge on the correct value using progressive
approximation, as if finding the root of an arbitrary mathematical
function. Doing the same using the above instructions can easily be
implemented in 17 instructions flat with no branches:

# out Nx: clock-style seconds-since-epoch
# in Py: splittime-style array
# Nz: temp 

Nx = 0

# years
Nz = Py[5]
Nz = Nz - 2000# epoch based at year 2000
Nz = Nz * 12  # = months per year
add_months Nx, Nx, Nz

# months
Nz = Py[4]
add_months Nx, Nx, Nz

# days
Nz = Py[3]
Nz = Nz * 86400  # = 24 * 60 * 60 seconds per day
Nx = Nx + Nz

# hours
Nz = Py[2]
Nz = Nz * 3600   # = 60 * 60 seconds per hour
Nx = Nx + Nz

# minutes
Nz = Py[1]
Nz = Nz * 60 # = 60 seconds per minute
Nx = Nx + Nz

# seconds
Nz = Py[0]
Nx = Nx + Nz


Leave parsing and formatting entirely to libraries. Absolutely no need
for that in the instruction set.

-- 

Gordon Henriksen
IT Manager
ICLUBcentral Inc.
[EMAIL PROTECTED]



Re: [PATCH] Configure test for inet_aton

2004-02-29 Thread Gordon Henriksen
On Friday, February 27, 2004, at 12:26 , Andrew Dougherty wrote:

On Fri, 27 Feb 2004, Gordon Henriksen wrote:

inet_pton is preferrable, as it supports IPv6.

That is, inet_pton should trump inet_aton if both are available.
Probably, but that would require testing to see if inet_pton is 
available. That information is not available from perl5's Configure, 
and there currently is no infrastructure in parrot for making such a 
test. Obviously that needs to change eventually.

On Mac OS X, the preferred technique would be to weak link with 
inet_pton and test for its availability at run-time. (inet_pton is not 
available on 10.1, but is available on 10.3.) This would be another 
case entirely.
Yes, indeed, that's the sort of thing that makes testing for function 
availability so much fun :-).
FWIW, this can't work across the 10.1/10.2 schizm.

	http://developer.apple.com/technotes/tn2002/tn2064.html

So parrot would need to:

  - either use a separate 10.1 binary (yuck),
  - or forgo use of inet_pton and IPv6 on Mac OS X 10.2 even though it 
is available (yuck),
  - or link in at runtime a different driver DLL for 10.1 vs. 10.2 
(yuck).

Roll-your-own doesn't really sound so bad. But until the implementation 
is not hardcoded to IPv6, preferring inet_aton (as present) gets the 
right behavior. But IPv6 can't be ignored forever.

Whatevsies.



Gordon Henriksen
[EMAIL PROTECTED]


RE: [PATCH] Configure test for inet_aton

2004-02-27 Thread Gordon Henriksen
inet_pton is preferrable, as it supports IPv6. I think the code should
read either:

#if PARROT_HAS_INET_PTON
... use inet_pton ...
#else
... use inet_aton ...
#endif

or

#if PARROT_HAS_INET_PTON
... use inet_pton ...
#elsif PARROT_HAS_INET_ATON
... use inet_aton ...
#else
#error
#endif

That is, inet_pton should trump inet_aton if both are available.

On Mac OS X, the preferred technique would be to weak link with
inet_pton and test for its availability at run-time. (inet_pton is not
available on 10.1, but is available on 10.3.) This would be another case
entirely.

-- 

Gordon Henriksen
IT Manager
ICLUBcentral Inc.
[EMAIL PROTECTED]


 -Original Message-
 From: Andrew Dougherty [mailto:[EMAIL PROTECTED] 
 Sent: Friday February 27, 2004 11:52
 To: Perl6 Internals
 Subject: [PATCH] Configure test for inet_aton
 
 
 On Fri, 27 Feb 2004, Leopold Toetsch wrote:
 
  Peter Sinnott wrote:
 
   I have downloaded the snapshot dated 27-Feb-2004 00:01  from
   http://cvs.perl.org/snapshots/parrot/ and tested it on hpux.
  
   I order to get it to compile I have to revert to using inet_aton
   at line 623 of io_unix.c. inet_pton was causing 
 unsatisfied symbols
   at link time.
 
  We need a config test here.
 
 Something like this ought to do the trick for now.  Longer 
 term, we need
 to build up some infrastructure for testing for functions on 
 our own. We
 also need to centralize things more to avoid some of the 
 duplication of
 code and information we're ending up with here.
 
 
 diff -r -u -N parrot-current/MANIFEST parrot-andy/MANIFEST
 --- parrot-current/MANIFEST   2004-02-27 03:00:34.0 -0500
 +++ parrot-andy/MANIFEST  2004-02-27 09:36:23.0 -0500
 @@ -78,6 +78,7 @@
  config/auto/format.pl []
  config/auto/funcptr.pl[]
  config/auto/funcptr/test_c.in []
 +config/auto/functions.pl  []
  config/auto/gc.pl []
  config/auto/gc/test_c.in  []
  config/auto/gcc.pl[]
 diff -r -u -N parrot-current/config/auto/functions.pl 
 parrot-andy/config/auto/functions.pl
 --- parrot-current/config/auto/functions.pl   1969-12-31 
 19:00:00.0 -0500
 +++ parrot-andy/config/auto/functions.pl  2004-02-27 
 09:36:56.0 -0500
 @@ -0,0 +1,33 @@
 +#! perl -w
 +# Copyright: 20004 The Perl Foundation.  All Rights Reserved.
 +# $Id:$
 +
 +=head1 NAME
 +
 +config/auto/functions.pl - Probe for Various Functions
 +
 +=head1 DESCRIPTION
 +
 +This command probes for the existence of various functions.
 +For the moment, it just pulls information from perl5's Configure;
 +in the future, it ought to go looking on its own.
 +
 +=cut
 +
 +package Configure::Step;
 +
 +use strict;
 +use vars qw($description @args);
 +
 +$description=Looking for various functions...;
 +
 [EMAIL PROTECTED]();
 +
 +sub runstep {
 +# Do we have inet_aton() ?
 +Configure::Data-set(
 +  d_inet_aton = $Config{d_inetaton},
 +);
 +}
 +
 +1;
 diff -r -u -N 
 parrot-current/config/gen/feature_h/feature_h.in 
 parrot-andy/config/gen/feature_h/feature_h.in
 --- parrot-current/config/gen/feature_h/feature_h.in  
 2004-01-08 19:01:00.0 -0500
 +++ parrot-andy/config/gen/feature_h/feature_h.in 
 2004-02-27 09:36:23.0 -0500
 @@ -96,6 +96,21 @@
 
  print OUT EOP;
 
 +/* from config/auto/functions.pl */
 +EOP
 +if (${d_inet_aton}) {
 + print OUT EOP;
 +#define PARROT_HAS_INET_ATON 1
 +EOP
 +}
 +else {
 + print OUT EOP;
 +/* #undef PARROT_HAS_INET_ATON */
 +EOP
 +}
 +
 +print OUT EOP;
 +
  /* from config/auto/inline */
  EOP
  if (${inline} ne '') {
 diff -r -u -N parrot-current/io/io_unix.c parrot-andy/io/io_unix.c
 --- parrot-current/io/io_unix.c   2004-02-19 
 19:00:06.0 -0500
 +++ parrot-andy/io/io_unix.c  2004-02-27 11:09:48.0 -0500
 @@ -617,11 +617,16 @@
  {
  struct sockaddr_in sa;
  /* Hard coded to IPv4 for now */
 -int family = AF_INET;
 +#if !PARROT_HAS_INET_ATON
 +int family = AF_INET;   /* for inet_pton() */
 +#endif
 
  char * s = string_to_cstring(interpreter, addr);
 -/*if(inet_aton(s, sa.sin_addr) != 0) {*/
 +#if PARROT_HAS_INET_ATON
 +if(inet_aton(s, sa.sin_addr) != 0) {
 +#else
  if(inet_pton(family, s, sa.sin_addr) != 0) {
 +#endif
  /* Success converting numeric IP */
  }
  else {
 diff -r -u -N parrot-current/lib/Parrot/Configure/RunSteps.pm 
 parrot-andy/lib/Parrot/Configure/RunSteps.pm
 --- parrot-current/lib/Parrot/Configure/RunSteps.pm   
 2003-11-27 19:00:50.0 -0500
 +++ parrot-andy/lib/Parrot/Configure/RunSteps.pm  
 2004-02-27 09:36:23.0 -0500
 @@ -4,6 +4,8 @@
  use vars qw(@steps);
 
  # EDIT HERE TO ADD NEW TESTS
 +# Also update the slightly different version of this list
 +# in Parrot::Configure::Docs:Section:Config.pm
  @steps=qw(
   init

RE: [PATCH] Configure test for inet_aton

2004-02-27 Thread Gordon Henriksen
Andrew Dougherty wrote: 

 On Fri, 27 Feb 2004, Gordon Henriksen wrote:
 
  On Mac OS X, the preferred technique would be to weak link with
  inet_pton and test for its availability at run-time. (inet_pton is
  not available on 10.1, but is available on 10.3.) This would be 
  another case entirely.
 
 Yes, indeed, that's the sort of thing that makes testing for function
 availability so much fun :-).

Further, this trickery requires that such compatible builds of parrot 
be built with the latest environment (where the function prototypes at
least are available)... Ah, fun, fun, fun.

-- 

Gordon Henriksen
IT Manager
ICLUBcentral Inc.
[EMAIL PROTECTED]



Re: pdd15_objects.pod, attributes, properties, and life

2004-02-27 Thread Gordon Henriksen
On Friday, February 27, 2004, at 12:22 , Dan Sugalski wrote:

At 4:41 PM +0100 2/27/04, Paolo Molaro wrote:
On 02/27/04 Dan Sugalski wrote:
   What .NET calls an attribute parrot calls a property
   What .NET calls a property parrot calls an attribute
[...]
 Oh, yeah. No matter which way we go we'll be confusing someone, since
 there are languages that call what we call an attribute an attribute.
  The .NET reversal's just the big nasty one.
[Paolo's property and attribute for .net explanation snipped]

Okay, now I'm *really* confused. This seems to contradict the 
explanations in the C# in a Nutshell book, assuming that C# and .NET 
use the same underlying terminology. OTOH I could be misreading the 
book, and OTTH I'd be foolish to not take Paolo's explanation as most 
correct. I think I may well just chop out part of the glossary.

I swear, I'm going to rename these things to Fred and Barney and not 
tell anyone which is which...
Ordered by ascending esotericism:

Fields: Class data members.
Properties: Syntactic sugar for getter and setter methods.
Attributes: Extensible metadata for compile-time objects.
In context:

using System;
using ICLUBcentral.Testing;

namespace ICLUBcentral.Example {
class Eg {
//  This is a field:
private int _num;

//  This is a property:
public int Num {
get { return _num; }
set { _num = value; }
}

[TestCase(2)]  //  -- This is an attribute.
private void _TestNum() {
Test.OK(Num == 0, default value);
Num = 43;
Test.OK(Num == 43, changed value);
}
}
}
I have a program which will load the resultant DLL and run all methods 
which have a TestCase attribute applied to them.

Am very, very sure of this terminology.



Gordon Henriksen
[EMAIL PROTECTED]


Re: Build broken due to missing inet_aton on Solaris 8

2004-02-17 Thread Gordon Henriksen
On Thursday, February 12, 2004, at 10:46 , Melvin Smith wrote:

At 10:26 AM 2/12/2004 -0500, Andrew Dougherty wrote:

A fresh checkout of parrot won't build for me due to the missing 
inet_aton symbol on Solaris 8.  My perl5 configuration correctly 
records $Config{d_inetaton}=undef, but io_unix.o unconditionally 
expects inet_aton.

cc -o parrot -L/usr/local/lib -R/usr/local/lib imcc/main.o \
blib/lib/libparrot.a -lsocket -lnsl -ldl -lm -lpthread -lrt
Undefined   first referenced
 symbol in file
inet_aton   blib/lib/libparrot.a(io_unix.o)
ld: fatal: Symbol referencing errors. No output written to parr
I know I only develop on Linux and Solaris. Linux can use either
but Solaris needed inet_pton.
I'm not sure why Leo changed it, but I'll put it back.

Leo do you have an OS that does not have inet_pton?
(Sorry if this has already been discussed; catching up after being out 
of down.)

Early versions of Mac OS X do not have inet_pton.



Gordon Henriksen
[EMAIL PROTECTED]


As the world stops: of GC and threads

2004-02-07 Thread Gordon Henriksen
So, I haven't heard any convincing evidence that execution in other 
threads can continue while garbage collection is executing, copying 
collector or not. (Point of fact, the copying collector has nothing to 
do with it.) So what are the options to stop the world? I've heard the 
first 2 of these from Dan and Leo. The third is mine. Any others?

* Taking the read half of a reader-writer lock for all pointer mutations
The point here is to block all mutators from mutating the object graph 
while the collector is traversing it. I can't imagine this being good 
for performance. This is in addition to the mutex on the PMC. Other 
threads might be scheduled before GC completes, but don't have to be for 
GC to proceed.

* OS pause thread support
Lots of operating systems (including at least several versions of Mac OS 
X) don't support this. Maybe parrot can use it when it is available. 
It's always a dangerous proposition, though; the paused thread might be 
holding the system's malloc() mutex or something similarly evil. (This 
evil is why platforms don't always support the construct.) I don't think 
this is feasible for portability reasons. In this case, other threads 
would not be scheduled before GC completes.

* Use events
This is my proposition: Have the garbage collector broadcast a STOP! 
event to every other parrot thread, and then wait for them all to 
rendezvous that they've stopped before GC proceeds. Hold a lock on the 
thread mutex while doing this, so threads won't start or finish. This 
has the worst latency characteristics of the three: All other threads 
would need to be scheduled before GC can begin. Corner cases exist: NCI 
calls could be long-running and shouldn't block parrot until completion; 
another thread might try to allocate memory before checking events. 
Neither is insurmountable.



Gordon Henriksen
[EMAIL PROTECTED]


RE: [PATCH] Unified PMC/PObj accessors phase 2

2004-02-06 Thread Gordon Henriksen
  [* - Somewhat inadvisedly, I think. UnionVal is 8 bytes on 
  a 32-bit architecture, but bloats to 16 bytes on a 64-bit 
  architecture.
 
 That's likely so because of alignment. But real numbers would 
 be better of course.

Err? No, I'd think it's because the union contains two 16-byte
structs (64-bit ptr + 64-bit ptr = 128-bit struct = 16 bytes).
Shouldn't be any padding in UnionVal unless there's a 32-bit
architecture out there that wants to align 32-bit values to 64-
bit boundaries...

-- 

Gordon Henriksen
IT Manager
ICLUBcentral Inc.
[EMAIL PROTECTED]



Re: [PATCH] Unified PMC/PObj accessors phase 2

2004-02-06 Thread Gordon Henriksen
Leopold Toetsch wrote:

Gordon Henriksen wrote:

The patch is at the URL below, and I've split it into 4 for you. The 
classes-include-lib patch must be applied before any of the other 3. 
I've resolved the 3-4 conflicts that occurred since the patch was first
I've applied now pmc-accessors2-classes-include-lib. *But*

2) The *misc.patch doesn't compile in jit/i386

3) *src-a*.patch reverts Mike's docu patch
Ack! Bad cvs update! No cookie! Not sure why those didn't merge.

http://www.ma.iclub.com/pub/parrot/ now lists a .tgz with separate 
patches for each file. You can apply the patches in any order, or not at 
all; there are no interdependencies. Except!: include_parrot_pobj.h will 
remove the compatibility interfaces, so you may wish to sit on that for 
a month or so.

--

Gordon Henriksen
[EMAIL PROTECTED]


Patch vaporized?

2004-02-05 Thread Gordon Henriksen
I've submitted a patch to bugs-parrot, and it didn't seem to get posted
to RT or otherwise handled. Anyone know where it might've gone?
http://www.parrotcode.org/openpatches
http://www.parrotcode.org/openpatches isn't working (ERROR RETRIEVING
DATA).
 
-- 

Gordon Henriksen
IT Manager
ICLUBcentral Inc.
[EMAIL PROTECTED]


RE: Patch vaporized?

2004-02-05 Thread Gordon Henriksen
Larry Wall wrote:

 Gordon Henriksen wrote:
 
  I've submitted a patch to bugs-parrot, and it didn't seem 
  to get posted to RT or otherwise handled. Anyone know where it 
  might've gone?
 
 Did it have an executable attachment?  :-)

Thanks, Larry, but no. :)

It was a very lage patch, however; it converts pmc-cache.int_val
etc. to PObj_int_val(pmc) etc. across the entire source tree. (Sorry,
Leo, by far the easiest way to find them all was to change the field
names and fix them as make found them; rather makes it difficult to
create incremental patches.) So maybe sheer size was the problem.

I'll post the file to my web server this evening and just include a
link to it in YA resubmission, I suppose. How annoying...

-- 

Gordon Henriksen
IT Manager
ICLUBcentral Inc.
[EMAIL PROTECTED]



[PATCH] Unified PMC/PObj accessors phase 2

2004-02-05 Thread Gordon Henriksen
Leo,

The patch is at the URL below, and I've split it into 4 for you. The 
classes-include-lib patch must be applied before any of the other 3. 
I've resolved the 3-4 conflicts that occurred since the patch was first 
abortively submitted on Monday, so the old patch (named 
20040202-pmc-accessors.patch) should be discarded if it resurfaces.

	http://www.ma.iclub.com/pub/parrot/

I realized that some of the accessor macros should've been named PObj_* 
instead of PMC_* (since they apply to STRINGs and Buffers, too). So they 
are as of this patch. I've also macro-ized access to UnionVal in 
general, since it was sometimes used outside of the context of a 
pobj. [*]

The old syntax continues to work, and so nobody's patches will break 
excl. those w conflicts. But the pobj-cache.foo_val and 
PMC_ptr1p/PMC_ptr2v macros ought to be treated as deprecated.



Gordon Henriksen
[EMAIL PROTECTED]
[* - Somewhat inadvisedly, I think. UnionVal is 8 bytes on a 32-bit 
architecture, but bloats to 16 bytes on a 64-bit architecture. The 
generic containers which use UnionVal don't appear to use both ptrs 
simultaneously or make use of the void*/int pair, so could use an 8-byte 
structure as their bucket type.]


Re: Alignment Issues with *ManagedStruct?

2004-02-05 Thread Gordon Henriksen
On Thursday, February 5, 2004, at 05:23 , Leopold Toetsch wrote:

Nested structs are ugly. The alignment of the first item seems to depend
on the biggest item in the struct.
[...]
Yeah, the struct is aligned to align the largest element therein. e.g.:

struct { char; struct { char; char; char; } }
is at +0, +1, +2, +3
But: struct { char; struct { char; char; short; } }
is at +0, +2, +3, +4
And: struct { char; struct { char; short; char; } }
is at +0, +2, +4, +6

So we need some notion of nested structs or a hint for correct
alignment. I've checked in basic alignment handling for normal
cases, but not the second one above.
Maybe you ought to capitulate to the hierarchical nature of it all and 
simply push on another struct layout specifier to handle the nesting.


struct xt {
char x;
struct yt {
char i;
int  j;   // use different items here
} _y;
char z;
} _x;
int main(void) {
printf(x : %d\n, offsetof(struct xt, x));
printf(i : %d\n, offsetof(struct xt, _y.i));
printf(j : %d\n, offsetof(struct xt, _y.j));
printf(z : %d\n, offsetof(struct xt, z));
return 0;
}
Mac OS X output is:

x : 0
i : 4
j : 8
z : 12


Gordon Henriksen
[EMAIL PROTECTED]


Re: Patch vaporized?

2004-02-05 Thread Gordon Henriksen
On Thursday, February 5, 2004, at 11:35 , Robert Spier wrote:

I think I've tracked this down, mostly.

The patch was rejected from the mailing list because it was too big.  
(Several hundred k.)
That's what I figured.

You can find it in RT as

26056: [PATCH] Unify PMC accessor macros 2
26057: [PATCH] Unified PMC/PObj accessors phase 2
(26057 is one that points to a URL.  Gordon, should I merge the two 
tickets?)
Either merge them or close 26056 as wontfix or equivalent (sorry, I'm a 
Bugzilla feak :). The first patch has conflicts with current source, 
which is why I freaked out when it didn't show up pronto.



Gordon Henriksen
[EMAIL PROTECTED]


RE: More on threads

2004-01-30 Thread Gordon Henriksen
Dan Sugalski wrote:

 Gordon Henriksen wrote:
 
  Leopold Toetsch wrote:
 
   Gordon Henriksen wrote:
  
... Best example: morph. morph must die.
  
   Morph is necessary. But please note: morph changes the vtable of
   the PMC to point to the new data types table. It has nothing to do

   with a typed union.
 
  The vtable IS the discriminator. I'm referring to this:
 
  typedef union UnionVal {
  struct {/* Buffers structure */
  void * bufstart;
  size_t buflen;
  } b;
  struct {/* PMC unionval members */
  DPOINTER* _struct_val;  /* two ptrs, both are 
defines */
  PMC* _pmc_val;
  } ptrs;
  INTVAL int_val;
  FLOATVAL num_val;
  struct parrot_string_t * string_val;
  } UnionVal;
 
  So long as the discriminator does not change, the union is 
  type stable.
 
 The vtable's not the discriminator there, the flags in the pmc are 
 the discriminator, as they're what indicates that the union's a 
 GCable thing or not. I will admit, though, that looks *very* 
 different than it did when I put that stuff in originally. (It used 
 to be just a union of FLOATVAL, INTVAL, and string pointer...)

Hm. Well, both are a discriminator, then; dispatch to code which
presumes the contents of the union is quite frequently done without
examining the flags. Maybe use a VTABLE func instead to get certain
flags? i.e.,

INTVAL parrot_string_get_flags(..., PMC *pmc) {
return PMC_FLAG_IS_POBJ + ...;
}

Then, updating the vtable would atomically update the flags as well.
Or, hell, put the flags directly in the VTABLE if it's not necessary
for them to vary across instances.

I have the entire source tree (save src/ tests) scoured of that rat's
nest of macros for accessing PMC/PObj fields, but I broke something and
haven't had the motivation to track down what in the multi-thousand-
line-diff it was, yet. :( Else you'd have the patch already and plenty
of mobility in the layout of that struct. Near time to upgrade my poor
old G3, methinks; the build cycle kills me when I touch parrot/pobj.h.


Do any PMC classes use *both* struct_val *and* pmc_val concurrently? I
was looking for that, but am afraid I didn't actually notice.

-- 

Gordon Henriksen
IT Manager
ICLUBcentral Inc.
[EMAIL PROTECTED]



RE: More on threads

2004-01-30 Thread Gordon Henriksen
Leopold Toetsch wrote:

 Gordon Henriksen wrote:
 
  ... in the multi-thousand-
  line-diff it was, yet. :( Else you'd have the patch already
 
 1) *no* multi-thousands line diffs
 2) what is the problem, you like to solve?

Er? Extending to the rest of the source tree the huge patch to
classes which you already applied. No logic changes; just
cleaning those PObj accessor macros up.

-- 

Gordon Henriksen
IT Manager
ICLUBcentral Inc.
[EMAIL PROTECTED]



RE: More on threads

2004-01-30 Thread Gordon Henriksen
Leopold Toetsch wrote:

 Gordon Henriksen wrote:
 
  Or, hell, put the flags directly in the VTABLE if it's not 
  necessary for them to vary across instances.
 
 No, flags are mutable and per PMC *not* per class.

Of course there are flags which must remain per-PMC. I wasn't
referring to them. Sorry if that wasn't clear.

If a flag is only saying my VTABLE methods use the UnionVal as {a
void*/a PObj*/a PMC*/data}, so GC should trace accordingly, it may be
a waste of a per-object flag bit to store those flags with the PMC
instance rather than with the PMC class. And if it's with the VTABLE,
then it doesn't need to be traced. (But, then, all PObjs don't have
VTABLES...)


Sidebar:
If we're looking at lock-free concurrency, flag updates probably have
to be performed with atomic 's and |'s. BUT: Doesn't apply during GC,
since other threads will have to be stalled then.


  Do any PMC classes use *both* struct_val *and* pmc_val concurrently?
 
 E.g. iterator.pmc. UnmanagedStruct uses int_val  pmc_val. This is no 
 problem. These PMCs don't morph.

Er, int_val and pmc_val at the same time? That's not quite what the
layout
provides for:

typedef union UnionVal {
struct {/* Buffers structure */
void * bufstart;
size_t buflen;
} b;
struct {/* PMC unionval members */
DPOINTER* _struct_val;   /* two ptrs, both are defines */
PMC* _pmc_val;
} ptrs;
INTVAL int_val;
FLOATVAL num_val;
struct parrot_string_t * string_val;
} UnionVal;

Says to me:

struct_val and pmc_val concurrently
  -- or --
bufstart and buflen concurrently
  -- or --
int_val
  -- or --
num_val
  -- or --
string_val

I don't know if C provides a guarantee that int_val and ptrs._pmc_val
won't 
overlap just because INTVAL and DPOINTER* fields happen to be the same
size.
At  least one optimizing compiler I know of, MrC/MrC++, would do some
struct
rearrangement when it felt like it.

-- 

Gordon Henriksen
IT Manager
ICLUBcentral Inc.
[EMAIL PROTECTED]



RE: Re[2]: Embedding vs. extending interface types

2004-01-30 Thread Gordon Henriksen
Dan Sugalski wrote:

 And pointless. Let's just rename it to Parrot_Interp everywhere.

I've submitted a patch for this already.

-- 

Gordon Henriksen
IT Manager
ICLUBcentral Inc.
[EMAIL PROTECTED]



Re: DOD, mutation, and generational collectors

2004-01-30 Thread Gordon Henriksen
On Thursday, January 29, 2004, at 08:41 , Dan Sugalski wrote:

So, while I'm heaping much grumpiness on threads (though I suppose, as 
I've been out of touch for a bit maybe you've all solved the problem. 
That'd be nice) I've also been thinking about DOD, as there's a fair 
amount of overlap in the things that cause problems for threads and the 
ones that cause problems for generational garbage collectors.
Can you elaborate a bit on your concept of generational collection as 
they apply to parrot? To my ear, generational collection implies all of 
this (which is a lot, and a lot of it grossly inapplicable to parrot as 
the runtime now stands):

GENERATIONAL GARBAGE COLLECTORS

Rationale: Most objects are short-lived, and those which are not are 
less likely to become garbage. Marking or copying the older is 
statistically wasted effort. A garbage collector which usually traces 
only new objects will thus tend to perform better than one which traces 
all of them.

Implementation: Most generational collectors are copying collectors. 
They are generally mutations upon a hemispace collector. The variation 
is that collection always proceeds from a small, fixed-sized space to a 
larger, growable space, rather than swapping back and forth between two 
symmetric spaces. These asymmetric spaces are the so-called generations, 
and the small one containing the younger objects is dubbed the nursery. 
Moving an object from the nursery is called tenuring. Thus, the 
generation of an object is not so much a property of an object as it 
is a property of the pool from which the object is presently allocated.

Some generational collectors have intermediate generations, but most do 
not. (Parrot might benefit from a younger-than-the-nursery generation 
for impatient destructors, but then that property would need to be 
ascertainable at construction time.)

The nursery is typically explicitly un-fragmented. All live objects in 
it are tenured from it when it fills. Thus, allocation can be as simple 
as an atomic pointer increment and filling in an object header. The 
tenured generation might be a heap.

To avoid tracing from the roots, the generational collector requires a 
cooperative mutator to maintain a table of references from tenured 
objects to objects within the nursery. This is often forced upon the 
mutator through the use of VM write barriers. The write barrier function 
marks the VM page as dirty and then removes write protection for that 
page. When invoked, the garbage collector will examine all dirtied 
pages, updating the table of references.

A truly cooperative mutator will update a table of dirty pages every 
time it changes a pointer variable. Usually, the pages are smaller than 
VM pages, and thus called cards instead. This operation can be as 
simple as card_table[((int) ptr)  n] = 1; ptr = obj;.[1] An expensive 
proposition, at least doubling the memory bandwidth overhead of pointer 
manipulation. But, since cards are smaller than pages, it can reduce the 
amount of memory which has to be scanned at collection time.

Despite being incremental by nature, a generational collector is not a 
concurrent collector. That is, it still stops the world, it just 
doesn't do it for quite a long as a traditional hemispace or mark-sweep 
collector might.

Being a copying collector in the traditional mold has its drawbacks. It 
requires accurate reference tracing, in particular. A traditional 
copying collector cannot work with a conservative collector. For 
instance, it cannot operate on the OS stack (unless the program is 
written very cooperatively), since the collector cannot ascertain for 
certain whether a value is a pointer (which should be traced and 
possibly updated) or data (which should be left alone).

But parrot has anchored objects and other sorts of things which are 
incompatible with this. In particular, the fast-path nursery allocator 
(the very fast allocation being a major benefit of generational 
collectors) can't work: If an object were anchored in the nursery, it 
must stay there after GC rather than being tenured; this leaves the 
nursery fragmented and complicates the very hot allocation code path. 
Then there's the whole PMCs don't move guarantee. And there's also the 
conservative tracing of system areas.



Gordon Henriksen
[EMAIL PROTECTED]
[1] To be that simple, all allocated memory must be contiguous. So it's 
not usually that simple. More likely, this:

(((alloc_header*) obj) - 1)-pool.card_table[((int) obj)  n];
obj-ptr = newvalue;


Re: Threads... last call

2004-01-29 Thread Gordon Henriksen
 set of collections (incl. Vector). It was a major 
design flaw, crippling the performance of early Java programs. Fixing it 
for Java 2's class library was quite non-trivial, but because the VM was 
powerful enough to allow it, more efficient unsynchronized collections 
could be made available as a class library even for the earlier Java VMs.



Gordon Henriksen
[EMAIL PROTECTED]


Re: Messages delayed, out of order

2004-01-29 Thread Gordon Henriksen
On Thursday, January 29, 2004, at 09:12 , Matt Fowles wrote:

I have been getting out of order messages from this list for months... 
I just assumed that the internet was a mysterious thing...
Methinks the list is also manually moderated



Gordon Henriksen
[EMAIL PROTECTED]


Re: Threads... last call

2004-01-29 Thread Gordon Henriksen
On Thursday, January 29, 2004, at 11:55 , Melvin Smith wrote:

At 11:45 PM 1/28/2004 -0500, Gordon Henriksen wrote:

On Wednesday, January 28, 2004, at 12:53 , Melvin Smith wrote:

At 12:27 PM 1/23/2004 -0800, Damien Neil wrote:

Java Collections are a standard Java library of common data 
structures such as arrays and hashes.  Collections are not 
synchronized; access involves no locks at all.  Multiple threads 
accessing the same collection at the same time cannot, however, 
result in the virtual machine crashing.  (They can result in data 
structure corruption, but this corruption is limited to surprising 
results rather than VM crash.)
But this accomplishes nothing useful and still means the data 
structure is not re-entrant, nor is it corruption resistant, 
regardless of how we judge it.
It does accomplish something very useful indeed: It avoids the 
overhead of automatic locking when it isn't necessary. When *is* that 
locking necessary? To a second order approximation, ***NEVER.***
Pardon me but I've apparently lost track of context here.

I thought we were discussing correct behavior of a shared data 
structure, not general cases. Or maybe this is the general case and I 
should go read more backlog? :)
A shared data structure, as per Dan's document? It's a somewhat novel 
approach, trying to avoid locking overhead with dynamic dispatch and 
vtable swizzling. I'm discussing somewhat more traditional technologies, 
which simply allow an object to perform equally correctly and with no 
differentiation between shared and unshared cases. In essence, I'm 
arguing that a shared case isn't necessary for some data structures in 
the first place.



Gordon Henriksen
[EMAIL PROTECTED]


Re: [perl #25253] [PATCH] Remove Parrot_INTERP

2004-01-26 Thread Gordon Henriksen
Seiler Thomas wrote:

Gordon Henriksen wrote:

The Parrot_INTERP type from embed.c and embed.h serves no purpose.
[linking failures...]

mem_alloc_executable
mem_free_executable
mem_realloc_executable
[...]
Re-ran Configure.pl and these went away, in case anyone else has this.

inet_pton
Is a IPv6 avare inet_aton. Attached is a Configure.pl test to determine 
if inet_pton is available and a small patch to switch to inet_aton if 
not. Works for cygwin and linux but no windows support yet. I would 
like to eventually include a fall-back implementation of inet_pton in 
order to prevent the ifdefs, but had not enough time-knowledge yet...
Def. the right solution. (I'd just uncommented the usage of inet_aton 
out of laziness. :)



Gordon Henriksen
[EMAIL PROTECTED]


Re: [RESEND] Q: Array vs SArray

2004-01-25 Thread Gordon Henriksen
On Sunday, January 25, 2004, at 06:10 , Michael Scott wrote:

On 25 Jan 2004, at 00:50, Gordon Henriksen wrote:

[...]

Is there something so terribly wrong with English? How about a general 
scheme of adjective* noun? So, respectively,

MixedArray
Array
FixedArray
StringArray
FixedStringArray
Array is what Perl familiars will usually want.
Did I miss something? What is Array here?

General scheme: Need something more specific? Type more. Not sure on 
Fixed, but I like it more than FLen. Other option is to flip it around 
and tag Resizable, but that violates my previous pricipal of most 
useful = most convenient. I don't think MixedArray will see much use, 
so FixedMixedArray doesn't worry me too much. :)

I would definitely avoid the words mutable/immutable, as that will 
certainly be read by many (me :) to pertain to the values contained 
within the array.

Yes, I'm already anti-me on that. It should have been Resizable. And 
though that's more precise than Fixed, I agree with your principle.

So, to go back to Dan's original list, does that give us:

(FixedMixedArray - fixed-size, mixed-type array)
MixedArray - variable-sized, mixed-type array
FixedPMCArray - fixed-size, PMC array
PMCArray - variable-sized, PMC array
I'd abbreviate PMC as , since it's certain to be the most 
commonly-used. OTOH, PMC isn't a very long identifier to type.

FixedStringArray - fixed-size, string array
StringArray - variable-sized, string array
FixedNumberArray - fixed-size, number array
StringArray - variable-sized, number array
FixedIntegerArray - fixed-size, integer array
IntegerArray - variable-sized, integer array
with

fixedarray - abstract fixed-size array
array - abstract variable-sized array
Perhaps base*. Or perhaps not.



Gordon Henriksen
[EMAIL PROTECTED]


Re: More on threads

2004-01-25 Thread Gordon Henriksen
Leopold Toetsch wrote:

Gordon Henriksen wrote:

I overstated when I said that morph must die. morph could live IF:
[ long proposal ]

Increasing the union size, so that each pointer is distinct is not an 
option. This imposes considerable overhead on a non-threaded program 
too, due its bigger PMC size.
That was the brute-force approach, separating out all pointers. If the 
scalar hierarchy doesn't use all 4 of the pointers, then the bloat can 
be reduced. So long as a morph can't make a memory location which was 
formerly a pointer variable point to a new type, or reuse the memory 
location for data--then pointers can be part of a union without 
violating the principal of operation.

And what of the per-PMC mutex? Is that not also considerable overhead? 
More than an unused field, even.

To keep internal state consistent we have to LOCK shared PMCs, that's 
it. This locking is sometimes necessary for reading too.
Sometimes? Unless parrot can prove a PMC is not shared, PMC locking is 
ALWAYS necessary for ALL accesses to ANY PMC. (This is easy to show; for 
any thread, hypothesize a preemption and morph at an inconvenient PC. 
Some morph will always put an int where a pointer was expected, or 
change the type of a pointer.)

We seem to be painting ourselves into a corner here with impossible 
constraints. Clearly, adding size to PMCs is undesirable, and I 
recognize that you put a lot of work into shrinking the PMC struct over 
a Perl 5 scalar. But, fresh from CVS:

BENCHMARK USER SYS  %CPUTOTAL
-- --- --- - 
addit.imc   23.53s   0.05s   96%   24.517
addit2.imc  15.97s   0.07s   98%   16.258
arriter.imc  0.03s   0.03s   37%0.159
arriter_o1.imc  0.02s   0.04s   37%0.160
fib.imc  4.41s   3.07s   97%7.691
addit.pasm  17.84s   0.05s   95%   18.827
bench_newp.pasm  4.53s   0.16s   97%4.824
freeze.pasm  1.47s   0.18s   82%1.991
gc_alloc_new.pasm0.20s   0.41s   72%0.836
gc_alloc_reuse.pasm 19.09s  13.15s   98%   32.731
gc_generations.pasm 14.02s   5.42s   95%   20.424
gc_header_new.pasm   7.91s   1.37s   97%9.558
gc_header_reuse.pasm11.45s   0.09s   98%   11.733
gc_waves_headers.pasm3.05s   0.40s   95%3.597
gc_waves_sizeable_data.pasm  2.22s   3.81s   97%6.200
gc_waves_sizeable_headers.pasm   7.48s   1.78s   97%9.480
hash-utf8.pasm   7.02s   0.07s   95%7.404
primes.pasm 61.63s   0.10s   97% 1:03.300
primes2.pasm39.26s   0.09s   97%   40.189
primes2_p.pasm  69.00s   0.17s   96% 1:11.840
stress.pasm  2.19s   0.28s   91%2.705
stress1.pasm46.95s   1.33s   95%   50.377
stress2.pasm 8.63s   0.24s   98%9.026
stress3.pasm26.19s   0.78s   96%   28.063
TOTAL7:21.890
And with a PMC struct that's bloated by 16 bytes as proposed:

BENCHMARK USER SYS  %CPUTOTAL
-- --- --- - 
addit.imc   23.67s   0.10s   96%   24.745
addit2.imc  16.05s   0.07s   98%   16.414
arriter.imc  0.03s   0.03s   44%0.135
arriter_o1.imc   0.03s   0.04s   48%0.144
fib.imc  4.47s   2.99s   86%8.651
addit.pasm  18.08s   0.08s   98%   18.442
bench_newp.pasm  4.73s   0.18s   97%5.019
freeze.pasm  1.56s   0.29s   89%2.075
gc_alloc_new.pasm0.25s   0.35s   89%0.673
gc_alloc_reuse.pasm 18.90s  13.58s   96%   33.642
gc_generations.pasm 13.84s   5.80s   98%   19.942
gc_header_new.pasm   7.98s   1.29s   97%9.492
gc_header_reuse.pasm11.37s   0.05s   98%   11.552
gc_waves_headers.pasm3.09s   0.33s   96%3.538
gc_waves_sizeable_data.pasm  1.98s   4.01s   96%6.207
gc_waves_sizeable_headers.pasm   7.67s   1.60s   91%   10.112
hash-utf8.pasm   7.03s   0.05s   97%7.287
primes.pasm 61.68s   0.15s   98% 1:02.800
primes2.pasm39.17s   0.12s   99%   39.553
primes2_p.pasm  69.01s   0.18s   96% 1:11.640
stress.pasm  2.32s   0.43s   96%2.840
stress1.pasm50.85s   1.79s   93%   56.189
stress2.pasm 9.18s   0.32s   98%9.689
stress3.pasm29.06s   1.23s   98%   30.748
TOTAL7:31.527
That's only 2.1%.

What do you think the overall performance effect of fine-grained locking

Re: Embedding vs. extending interface types

2004-01-25 Thread Gordon Henriksen
On Saturday, January 24, 2004, at 02:28 , Leopold Toetsch wrote:

Mattia Barbon [EMAIL PROTECTED] wrote:

I feel I'm becoming annoying, but: the embedding and extending 
interfaces are still using different names for 
Parrot_Interp/Parrot_INTERP. Which one is correct?
AFAIK both. Embedding and extending are to different APIs. The former 
has access to internals the latter doesn't. So they get different types 
for e.g. the interpreter.
All embedders see is this:

/* include/parrot/interpreter.h */
struct Parrot_Interp;
typedef struct Parrot_Interp *Parrot_Interp;
i.e., struct Parrot_Interp is declared, but never defined. So the extra 
Parrot_INTERP type is just cruft. Also, it's not used anywhere in the 
source tree except in extend.h and extend.c.

And does anyone ever use the Interp type from below?

/* include/parrot/interpreter.h */
typedef struct Parrot_Interp {
...
} Interp;


Gordon Henriksen
[EMAIL PROTECTED]


Re: Embedding vs. extending interface types

2004-01-25 Thread Gordon Henriksen
On Sunday, January 25, 2004, at 03:44 , Leopold Toetsch wrote:

Gordon Henriksen [EMAIL PROTECTED] wrote:

All embedders see is this:

	typedef struct Parrot_Interp *Parrot_Interp;
I don't do decisions on embedding or extending interfaces. But it seems 
to be the time to decide (and clean/unite) [...]
Speaking of cleaning and uniting, what is with this?

#define bufstart obj.u.b.bufstart
#define buflen   obj.u.b.buflen
#if ! DISABLE_GC_DEBUG
#  define pobj_version obj.pobj_version
#endif
#define struct_val ptrs._struct_val
#define pmc_val ptrs._pmc_val
#define cache obj.u
#define metadata pmc_ext-metadata
#define next_for_GC pmc_ext-next_for_GC
#define synchronize pmc_ext-synchronize
#  define PMC_data(pmc) (pmc)-pmc_ext-data
#else
#  define PMC_data(pmc) (pmc)-data
#endif


Gordon Henriksen
[EMAIL PROTECTED]


Re: Benchmark Suite

2004-01-25 Thread Gordon Henriksen
On Sunday, January 25, 2004, at 06:01 , Matt Fowles wrote:

Of late it seems that everybody has been throwing around their own 
little homegrown benchmarks to support their points.  But many people 
frequently point out that these benchmarks are flawed on one way or 
another.

I suggest that we add a benchmark/ subdirectory and create a canonical 
suite of benchmarks that exercise things well (and hopefully fully). 
Then we can all post relative times for runs on this benchmark suite, 
and we will know exactly what is being tested and how valid it is.
Well, there's already examples/benchmarks. If those programs are not at 
all realistic, then more realistic benchmarks should be added.

Would be nice if there were a convenient way to run the lot of them and 
collect the timing information, though.



Gordon Henriksen
[EMAIL PROTECTED]


Re: t/src/io failure

2004-01-25 Thread Gordon Henriksen
On Sunday, January 25, 2004, at 06:42 , Michael Scott wrote:

I see that t/src/io is now failing on OS X 10.3.2. Is anyone else 
seeing this on another system?
Also on 10.1.5.



Gordon Henriksen
[EMAIL PROTECTED]


Re: Embedding vs. extending interface types

2004-01-25 Thread Gordon Henriksen
On Sunday, January 25, 2004, at 07:08 , Leopold Toetsch wrote:

Gordon Henriksen [EMAIL PROTECTED] wrote:

Speaking of cleaning and uniting, what is with this?

#define bufstart obj.u.b.bufstart
#define buflen   obj.u.b.buflen
These are *currently* necessary macros, until the PMC/PObj layout is 
really carved in stones. You had in your proposal a different PMC 
structure layout. Testing such things is vastly simplified by having 
accessor macros.
Yes, I know. ;) I was going to test a real layout change, but the macros 
were so tangled up that I wound up just appending 4 ints to struct PMC 
to simulate.

I'm not a friend of such macros. But they are needed as long as the 
actual structure might change. I did introduce all pobj.h related 
macros. They can go away, when *all* issues are resolved.
I know what they are, and have no problem with them. I don't think they 
should be removed. But this particular batch are a mess. I just 
submitted a couple of patches to clean them up a little, though I didn't 
get through the entire source tree yet.



Gordon Henriksen
[EMAIL PROTECTED]


Re: More on threads

2004-01-24 Thread Gordon Henriksen
On Saturday, January 24, 2004, at 09:23 , Leopold Toetsch wrote:

Gordon Henriksen [EMAIL PROTECTED] wrote:

... Best example: morph. morph must die.
Morph is necessary. But please note: morph changes the vtable of the 
PMC to point to the new data types table. It has nothing to do with a 
typed union.
The vtable IS the discriminator. I'm referring to this:

typedef union UnionVal {
struct {/* Buffers structure */
void * bufstart;
size_t buflen;
} b;
struct {/* PMC unionval members */
DPOINTER* _struct_val;   /* two ptrs, both are defines */
PMC* _pmc_val;
} ptrs;
INTVAL int_val;
FLOATVAL num_val;
struct parrot_string_t * string_val;
} UnionVal;
So long as the discriminator does not change, the union is type stable. 
When the discriminator does change, as per here:

	void
	Parrot_PerlInt_set_string_native(Parrot_Interp interpreter, PMC* 
pmc, STRING* value)
	{
	 VTABLE_morph(interpreter, pmc, enum_class_PerlString);
	 VTABLE_set_string_native(interpreter, pmc, value);
	}
	
	void
	Parrot_perlscalar_morph(Parrot_Interp interpreter, PMC* pmc, INTVAL 
type)
	{
	if (pmc-vtable-base_type == enum_class_PerlString) {
	if (type == enum_class_PerlString)
	return;
	PObj_custom_mark_CLEAR(pmc);
	pmc-vtable = Parrot_base_vtables[type];
	return;
	}
	if (type == enum_class_PerlString) {
	pmc-vtable = Parrot_base_vtables[type];
	 VTABLE_init(interpreter, pmc);
	return;
	}
	PObj_custom_mark_CLEAR(pmc);
	pmc-vtable = Parrot_base_vtables[type];
	
	}

... then these can both run:

Parrot_scalar_get_string(Parrot_Interp interpreter, PMC* pmc)
{
return (STRING*)pmc-cache.string_val;
}

FLOATVAL
Parrot_scalar_get_number(Parrot_Interp interpreter, PMC* pmc)
{
return pmc-cache.num_val;
}
That clearly allows a struct parrot_string_t * to freely share the same 
memory as a double. Were it an int and a double, the surprising 
results from this unprotected access wouldn't violate the no crashes 
guarantee. But it's a pointer! Dereferencing it could cause a segfault, 
or a read or write of an arbitrary memory location. Both clearly violate 
the crucial guarantee.



Gordon Henriksen
[EMAIL PROTECTED]


Re: More on threads

2004-01-24 Thread Gordon Henriksen
Leopold Toetsch wrote:

Gordon Henriksen [EMAIL PROTECTED] wrote:

... Best example: morph. morph must die.
Morph is necessary. But please note: morph changes the vtable of the 
PMC to point to the new data types table. It has nothing to do with a 
typed union.
I overstated when I said that morph must die. morph could live IF:

 the UnionVal struct were rearranged
 bounds ere placed upon how far a morph could... well, morph
It doesn't matter if an int field could read half of a double or v.v.; 
it won't crash the program. Only pointers matter.

To allow PMC classes to guarantee segfault-free operation, morph and 
cooperating PMC classes must conform to the following rule. Other 
classes would require locking.

With this vocabulary:
	variable: A memory location which is reachable (i.e., not garbage). [*]
	pointer: The address of a variable.
	pointer variable: A variable which contains a pointer.
	access: For a pointer p, any dereference of p*p, p-field, or 
p[i]whether for the purposes of reading or writing to that variable.

And considering:
	any specific pointer variable (ptr), and
	all accesses which parrot might perform[**] on any pointer ever 
stored in ptr (A) [***], and
	any proposed assignment to ptr

Then:
	If any A which once accessed a pointer variable would now access a 
non-pointer variable,
	Then the proposed assignment MUST NOT be performed.

This is a relaxed type-stabilitydefinition. (Relaxed: It provides type 
stability only for pointer variables, not for data variables. It does 
not discriminate the types of pointers, only that the data structures 
they directly reference have the same layout of pointers. Also, a 
loophole allows non-pointer variables to become pointer variables, but 
not the reverse.)

These rules ensure that dereferencing a pointer will not segfault. They 
also ensure that it is safe to deference a pointer obtained from a union 
according to the union's discriminatorregardless of when or in which 
order or how often parrot read the pointer or the discriminator.[***] I 
think they're actually the loosest possible set of rules to do this.

[*] Two union members are the same variable.
[**] This is in the variable ptr specifically, not merely in the same 
field of a similar struct. That is, having an immutable discriminator 
which selects s.u.v or s.u.i from struct { union { void * v; int i; } 
u } s is valid. A mutable discriminator is also validso long as the 
interpretation of pointer fields does not change.
[***] But only if the architecture prevents shearing in pointer reads 
and writes.

From another perspective this is to say:

Every pointer variable must forever remain a pointer.
Union discriminators must not change such that a pointer will no longer 
be treated as a pointer, or will be treated as a pointer to a structure 
with a different layout.

The first step in conforming to these rules is guaranteeing that a 
perlscalar couldn't morph into an intlist or some other complete 
nonsense. So the default for PMCs should be to prohibit morphing. Also, 
morphable classes will have a hard time using struct_val without 
violating the above rules. But for this price, parrot could get 
lock-free, guaranteed crash-proof readers for common data types. But 
note that pmc-cache.pmc_val can be used freely! So if exotic scalars 
wrap their data structures in a PMC 
*cough*perlobject*cough*managedstruct*ahem*, then those PMCs can be part 
of a cluster of morphable PMC classes without violating these rules.

Next, the scalar hierarchy (where morphing strikes me as most important) 
could be adjusted to provide the requisite guarantees, such as: 
perlstring's vtable methods would never look for its struct 
parrot_string_t * in the same memory location that a perlnum vtable 
method might be storing half of a floatval. Right now, that sort of 
guarantee is not made, and so ALL shared PMCs REALLY DO require locking. 
That's bad, and it's solvable.

Specifically, UnionVal with its present set of fields, would have to 
become something more like this:

struct UnionVal {
struct parrot_string_t * string_val;
DPOINTER* struct_val;
PMC* pmc_val;
void *b_bufstart;
union {
INTVAL _int_val;
size_t _buflen;
FLOATVAL _num_val;
} _data_vals;
};
If no scalar types use struct_val or pmc_val or b_bufstart, then those 
fields can go inside the union.

Unconstrained morphing is the only technology that *in all cases* 
*completely* prevents the crash-proof guarantee for lock-free access to 
shared PMCs. Without changes to this, we're stuck with implicit PMC 
locking and what looks like an unusable threading implementation.

This is only the beginning! For example, if parrot can povide type 
stability, mutable strings can be crash-proofed from multithreaded 
access. Wha?!

1. Add to the buffer structure an immutable

Re: More on threads

2004-01-24 Thread Gordon Henriksen
I wrote:

With this vocabulary:
	variable: A memory location which is reachable (i.e., not 
garbage). [*]
	pointer: The address of a variable.
	pointer variable: A variable which contains a pointer.
	access: For a pointer p, any dereference of p*p, p-field, or 
p[i]whether for the purposes of reading or writing to that variable.

And considering:
	any specific pointer variable (ptr), and
	all accesses which parrot might perform[**] on any pointer ever 
stored in ptr (A) [***], and
	any proposed assignment to ptr

Then:
	If any A which once accessed a pointer variable would now access a 
non-pointer variable,
	Then the proposed assignment MUST NOT be performed.
D'oh. This actually has to be recursive.

Considering:
	any specific pointer variable (ptr'), and
	all accesses which parrot might perform on any pointer ever stored 
in ptr,
		and all accesses which parrot might perform on any pointer 
ever stored in those variables,
			...,
... A, and
	any proposed assignment to ptr

else it allows

char * a = ...;
char ** b = a;  
Doesn't change the conclusions I drew at all. (Nor does it require some 
massively recursive algorithm to run at pointer assignment time, just as 
the first one didn't require anything more than pointer assignment at 
pointer assignment time.) Could probably be simplified with the addition 
of pointer type to the definitions section.

Anyhoo.



Gordon Henriksen
[EMAIL PROTECTED]


Re: [RESEND] Q: Array vs SArray

2004-01-24 Thread Gordon Henriksen
On Friday, January 23, 2004, at 11:05 , Tim Bunce wrote:

Here's my preference:

  *) ArrayFLenMixed  - fixed-size, mixed-type array
  *) ArrayVLenPMC- variable-sized PMC array
  *) ArrayFLenPMC- fixed-size PMC array
  *) ArrayVLenString - variable-sized string array
  *) ArrayFLenString - fixed-size string array
(Of course VLen/FLen could be VSize/FSize if preferred, and Mixed
seemed better than Any as I recall it's not truly any type.)
The general scheme is container typequalifierscontained type
Is there something so terribly wrong with English? How about a general 
scheme of adjective* noun? So, respectively,

MixedArray
Array
FixedArray
StringArray
FixedStringArray
Array is what Perl familiars will usually want. General scheme: Need 
something more specific? Type more. Not sure on Fixed, but I like it 
more than FLen. Other option is to flip it around and tag Resizable, but 
that violates my previous pricipal of most useful = most convenient. I 
don't think MixedArray will see much use, so FixedMixedArray doesn't 
worry me too much. :)

I would definitely avoid the words mutable/immutable, as that will 
certainly be read by many (me :) to pertain to the values contained 
within the array.



Gordon Henriksen
[EMAIL PROTECTED]


Re: Embedding vs. extending interface types

2004-01-24 Thread Gordon Henriksen
On Saturday, January 24, 2004, at 11:28 , Mattia Barbon wrote:

I feel I'm becoming annoying, but: the embedding and extending 
interfaces are still using different names for 
Parrot_Interp/Parrot_INTERP. Which one is correct?
Mattia,

Both are correct. Sort of. :) Parrot_INTERP is an opaque type, which is 
a technique for improving binary compatibility. In the core, which is 
always compiled as a unit, the fields of the interpreter structure can 
be accessed directly. But to preserve binary compatibility if the struct 
layout is modified, embedders and extensions (which are built separately 
from the core) must use accessor functions, and in fact do not generally 
even have the struct definition.

Thus, in parrot/extend.h,
For non-core users: typedef void * Parrot_INTERP in non-core users
For core users: typedef struct Parrot_Interp * Parrot_INTERP for core 
users

Looks like Parrot_INTERP is the best name to use in general, though.

This is rather on the unclear side. I would have clarified this by using 
private or opaque on the internal name for the struct, or prefixing 
with an underscore to indicate a private identifierrather than 
differentiating just by capitalization.

... okay, I'm beginning to agree with you. There's another name, Interp, 
for the same structure, defined in parrot/interpreter.h. That, and 
struct Parrot_Interp is a struct while Parrot_Interp is a pointer.



Gordon Henriksen
[EMAIL PROTECTED]


Re: Embedding vs. extending interface types

2004-01-24 Thread Gordon Henriksen
I wrote:

Mattia Barbon wrote:

I feel I'm becoming annoying, but: the embedding and extending 
interfaces are still using different names for 
Parrot_Interp/Parrot_INTERP. Which one is correct?
[blahblahblah]
Spoke too soon. Parrot_INTERP looks unnecessary. Parrot_Interp already 
has the needed opacity guards in place.



Gordon Henriksen
[EMAIL PROTECTED]


Re: More on threads

2004-01-24 Thread Gordon Henriksen
Pete Lomax wrote:

Gordon Henriksen wrote:

snip
It doesn't matter if an int field could read half of a double or v.v.;
it won't crash the program. Only pointers matter.
snip
These rules ensure that dereferencing a pointer will not segfault.
In this model, wouldn't catching the segfault and retrying (once or 
twice) work?
Determining how to retry in the general case would be... much more 
interesting than this proposal. :)

Furthermore, worse than segfaults could potentially result from using 
half of a double as a pointer. There's no assurance that *((caddr_t *) 
double) won't in fact be a valid memory address. In this case, there 
would be no segfault, but memory would be subtly corrupted. There's no 
way to detect that, so there's no way to retry.

The point of all the tweaks and care is to prevent ever dropping 
something else in a particular variable where parrot would, at another 
point in the program, expect a pointer of a particular type.

I think you probably got the following, but I'd just like to elaborate 
more specifically. I think the greatest subtlety of the rules was in the 
interpretation of

accesses which parrot might perform
and the word specific in

any specific pointer variable ptr
Without understanding precisely what I meant there, one might think that 
even a simple polymorphic system like the following is prohibited:

struct eg;
typedef int (func_ptr*)(struct eg*);
struct {
func_ptr fp;
union { int *pointer; int integer; } u;
} eg;

int pointer_meth(struct eg *thiz) { return ++*(thiz-u.pointer); }
int integer_meth(struct eg *thiz) { return ++(thiz-u.integer); }

void main() {
struct eg eg1 = { pointer_meth, NULL };
struct eg eg2 = { integer_meth, 1 };
eg1.u.pointer = malloc(sizeof(int));
*eg1.u.pointer = 0;

print_it(eg1, eg1);
print_it(eg2, eg2);
}
void print_it(char *name, struct eg *some_eg) {
printf(%s says %d\n, some_egfp(eg2));
}
But the program IS allowed. While print_it might behave in any number of 
ways depending on some_eg-fp, it will always access a particular eg.u 
in a consistent fashion, since it always respects the discriminator 
(eg.fp), which the program never changes. By extension of this, C++ 
instances do not violate these rules, either.[*] Were the following line 
added to main(), though, then the program would be in violation:

		eg1.fp = integer_meth;

Because now some other thread could have obvserved eg1.fp == 
pointer_meth and begun invoking pointer_meth. pointer_meth might now 
access u.pointer and, instead of a pointer, see n + (int) u.pointer. 
That probably won't segfault for small values of n, but will certainly 
not do the right thing either.

This is trite tangent, but also note that the type stability rule 
prohibits this:

		eg1.u.pointer = NULL;

But would not if the definition of pointer_meth became:

int pointer_meth(struct eg *thiz) {
int* pointer = this-u.pointer;
return pointer == NULL? -1 : ++*pointer;
}
Because now the program will now not dereference u.pointer if its value 
is NULL. How cute. (But if u.pointer were not copied to a local, then 
bets are off again, because C might perform an extra load and get a 
value inconsistent with the one it received when testing for NULL.)

... But even that extra local copy isn't required if u.pointer begins 
NULL, and can become non-NULL, but will not become NULL again. Why?

	all accesses which parrot MIGHT perform on any pointer ever 
storED in ptr (A)
Note the past tense there. That's why.


If I'm reading you correctly, which is unlikely,
That has little to do with you, but much to do with my burying important 
parts of my message in pages of dense text. :)

this has little to do with program correctness, but about the 
interpreter not crashing because of an unfortunate context switch.. 
which the programmer should have guarded against in the first place...
Yes. Precisely.

no, I think I just lost the plot again ;-)
I think you're pretty close, just missing a few of the subtleties that 
got buried in that long missive. :)



Gordon Henriksen
[EMAIL PROTECTED]
[*] Even though C++ changes the vtable of an instance during 
instantiation, it does so in a broadening fashion, making 
formerly-inaccessible variables accessible. A C++ instance of class 
derived_class : public base_class is not a derived_class until 
base_class's constructor finishes and derived_class's constructor 
begins. (Side-effect: A subclass cannot influence the instantiation 
behavior of a base class.) (Objective C's class methods are wildly 
useful. Static languages tend to ignore them. It's sad.)


Re: [DOCS] C code documentation

2004-01-24 Thread Gordon Henriksen
Dan Sugalski wrote:

Michael Scott wrote:

Perhaps the most controversial feature of all this is that I'm using 
rows of 80 '#'s as visual delimiters to distinguish documentation 
sections from code.
Please don't. If you really, really must, chop it down to 60 or so 
characters. 80 may wrap in some editors under some situations, and 
anything bigger than 72 may trigger wrapping behaviour in mail 
programs. (I think I'd as soon you didn't put in delimiters like this 
at all, but I can live with it if I must)
And more than 71 and messages containing patch snippets will wrap in 
some mail programs.

And more than 69 and replies to messages containing patch snippets will 
wrap in some mail programs.

ad infinitum...



Gordon Henriksen
[EMAIL PROTECTED]


RE: Threads... last call

2004-01-23 Thread Gordon Henriksen
Deven T. Corzine wrote:

 The most novel approach I've seen is the one taken by Project UDI 
 (Uniform Driver Interface).

This is very much the ithreads model which has been discussed. The
problem is that, from a functional perspective, it's not so much
threading as it is forking.

-- 

Gordon Henriksen
IT Manager
ICLUBcentral Inc.
[EMAIL PROTECTED]



Re: Signals and Events

2004-01-23 Thread Gordon Henriksen
On Friday, January 23, 2004, at 09:39 , Dan Sugalski wrote:

At 12:05 PM +0100 1/23/04, Leopold Toetsch wrote:

So my local src/events.c does:

1) block all signals before any thread creation
2) install an event handler for SIGINT
3) start the event handler thread
4) start an IO handler thread, which does:
  - unblock SIGINT
  - select in a while loop
  - if select returns -1, check for EINTR and the sig_atomic_t flag 
set by the signal handler
All this stuff needs to get out of events.c at some point, and we 
probably better do it now rather than later. Not because they're not 
events, but because this behaviour is all very platform-dependent, and 
so ought to go in the platform-local source instead. (It's not even 
Unix-dependent, as all the different unix flavors handle signals and 
threads differently)

What we need to do is get an abstraction in place for this and write 
platform-specific code to get concrete implementations of that 
abstraction in place. Which also means we need to have more complex 
processing of the platform source files.
It may even be important enough to probe this stuff at runtime and 
select the appropriate implementation then, so that a single parrot 
binary can be compatible across different versions of the same operating 
system. For instance: Linux flavors with per-thread PIDs, or different 
versions of Mac OS X with evolving pthreads implementations (or with and 
without poll()). Or Windows 98 vs. Server 2003. Finally, if the most 
performant strategy might differ for uniprocessors and multiprocessors.



Gordon Henriksen
[EMAIL PROTECTED]


Re: Start of thread proposal

2004-01-23 Thread Gordon Henriksen
On Friday, January 23, 2004, at 11:09 , Dan Sugalski wrote:

Ah, OK, I see. The problem comes in where we've got an object in the 
transient root set (basically the processor stack and registers) that 
gets anchored into the base root set (stash, pads, or whatever) after 
the DOD has traced where it's going into and falls out of the transient 
root set before the DOD traces over to it.
(Worse than that. It could come from any untraced locationor possibly 
even be brand new, depending upon memory allocation details.)



Gordon Henriksen
[EMAIL PROTECTED]


More on threads

2004-01-23 Thread Gordon Henriksen
 PMCs (deadlock avoidance!)
- invoke*
- an upwards branch
- reassigning a PMC register (changing reg[n], not reg[n]-something)
- any blocking operation
- anything that checks for events
Bytecode validation can ensure that PMC locks are held before 
operating on a PMC that is:
- not a temporary
- not known to be a threadsafe PMC (I repeat: morph is evil)

Pain in the ass? Maybe not. Here, I think IMCC can pull most of the 
weight: lock* shouldn't even be available through IMCC. Since it's just 
a matter of chugging through the rules, IMCC can apply locking 
automatically. (Hell, to avoid changing PBC, parrot could implement them 
automatically at runtime! Wouldn't want to be there, but the above set 
of rules is darned easy to apply.)

However, I would again repeat that the value provided to user programs 
by atomic PMC operations is negligible (since a user's data structures 
will typically be higher-level, and thus require user-level locking)and 
is certainly not offset by a 400% performance penalty. Locking PMCs is 
the easy way out. If type-stable memory can be provided (morph must 
die), it may be possible to look away from automatic PMC locks in more 
cases. For instance, an Int PMC would require no locks whatsoeverso 
long as its type cannot change. Nor would an immutable string, or a 
fixed-size array. On platforms with 8-word atomic writes, a Number PMC 
could get by without locks, too. morph must die.

Dan Sugalski wrote:

Okay, we're going to mandate that we have read/write locks, each 
interpreter pool has one, and mutating vtable entries must get a read 
lock on the pool read/write lock. Pricey (ick) but isolated to 
mutators. The DOD gets a write lock on it, which'll block all 
read/write access so no mutators can be in process while the pool DOD 
runs.
Adding a reader-writer lock on every pointer mutation will be completely 
and utterly unfeasible from a performance standpoint. There will be 
massive reader contention even on uniprocessors, and the bus pollution 
on multiprocessors will be disastrous. Reader-writer locks are more 
costly than mutexes.

Can I suggest an algorithm to completely eliminate that reader-writer 
lock, replacing it with a form of coordination that's cheaper in 
aggregate, and free in the common case? It's not simple, but I'd rather 
one elephant than a billion mice. Might help with infant mortality, too.



Gordon Henriksen
[EMAIL PROTECTED]
P.S. - morph must die.


Re: Start of thread proposal

2004-01-20 Thread Gordon Henriksen
On Monday, January 19, 2004, at 07:58 , [EMAIL PROTECTED] 
wrote:

Is there any likelyhood that memory allocation will be hidden behind 
macros at two levels:
 - ALLOCPOOL() for allocating large chunks of memory (ppols) that are
   later sub-allocated (and managed) by:

 - SUBALLOC() for sub allocating within a pool
Are you wanting something akin to Apache 2 pools, which are hierarchical 
and designed to reduce path length when freeing blocks of objects? For 
instance, all objects and sub-pools allocated during an HTTP request 
cycle can be deallocated just by free()'ing the top-level request pool.

I don't think parrot could make use of that model, since it can't very 
well guarantee that the user cannot retain references past the lifetime 
of the pool. Apache trusts modules not to make such errors; parrot can't 
trust the byte-code it's executing any further than it can throw it. A 
generational collector is a more likely means by which parrot might 
reduce memory-related overhead.



Gordon Henriksen
[EMAIL PROTECTED]


RE: Shared vs non shared PMC timings

2004-01-20 Thread Gordon Henriksen
Leopold Toetsch wrote: 

 (Overall timings aren't really comparable, the SharedRef also does a 
 LOCK for mark, which slows that down as well)

?? Why'd you do that? Competetive threads MUST be suspended (most likely
with their cooperation, not with an OS suspend call) during the mark
phase.

-- 

Gordon Henriksen
IT Manager
ICLUBcentral Inc.
[EMAIL PROTECTED]



Re: Start of thread proposal

2004-01-20 Thread Gordon Henriksen
On Tuesday, January 20, 2004, at 07:56 , [EMAIL PROTECTED] 
wrote:

I believe that parrot already has the concept of memory pools in it's 
memory management. The idea is that by allocating similarly sized 
objects from separate (large) allocations, you can reduce the 
fragmentation of chunks and reduce the incidences where the memory need 
to be GC'd and compacted.
Don't presume that. General purpose memory allocators tend to handle 
this scenario... generically. Use of custom allocators is usually a 
premature optimization; the best generic memory allocators are very, 
very good.

But the ultimate effect of the overuse of custom allocators or pools is 
to move memory fragmentation to a higher level, preventing the generic 
allocator from addressing it even when the memory allocation patterns 
would otherwise allow it.

If the allocation of pools, and the allocation of bit-of-a-pool, are 
macroised, it makes it possible for OS's where there are multiple APIs 
for memory allocation to bypass the CRT memory allocation routines and 
use which ever native APis are best suited for the type of allocation.
Would much rather see them abstracted, as they are now, beneath an API. 
This reduces the number of ways in which compiled parrot extensions can 
be incompatible with the parrot core.

Personally, I would like to see memory allocation for each class type 
be managed by the class constructor itself. This would theoretically 
allow each class that has a fixed instance size to manage it's own pool 
on OS's where that makes sense. The class would allocate a pool for 
itself when loaded and then allocate instances from that pool on new() 
and deallocate upon DESTROY. If it's memory pool was exhausted when new 
was called, it would invoke the GC on *it's pool only*.
A PMC class is free to do precisely that. Only the PMC header cannot be 
thus managed, and that's already pooled.

This separation would mean that each run of the GC would have a much 
smaller pool of memory to compact and garbage collect when it was 
invoked.
This is false. The mark phase will still need to run over the entire 
process, else it cannot detect all references into the pool. (Unless you 
can provide a type-safety guarantee that your type can only be 
referenced by other instances of itself. In which case, your type is 
necessarily garbage and the best optimization strategy would be 
dead-code elimination. :)

I predict the best overall throughput would be with the sweep or copy 
phase run immediately after the mark phase, across the entire process: 
It would be wasteful to do all that marking and yet leave known garbage 
uncollected.

It would also be less likely to be called, as each allocation from a 
pool of fixed sized sub allocations will only ever need to call the GC 
when it's pool is entirely exhausted.
Statistically, multiple pools will individually exhaust themselves 
*MORE* frequently than a global pool. The ideal case for collection 
frequency is that there is only one pool, or that all pools rise to 
capacity concurrently. In these ideal cases, the segregated pools will 
exhaust themselves precisely *AS* frequently as a global pool. In any 
case, there is no possibility for a decrease in collection events 
through the use of pooled memory. As per above, collection events will 
also not become less expensive. Thus, expect garbage collection to have 
a negative net impact on performance if pooled memory is used.

But that is a radical departure :), so if would just like to see 
separate calls for pool allocation/reallocation and element 
allocation/reallocation, rather than having calls to malloc() scattered 
through out the codebase.
Uh. See memory.c and smallobject.c...

Digression:

Most copying collectors avoid free space fragmentation by design. 
(That's one of their benefits.) An allocator as might be employed by a 
standard compacting, generational system (Java, MS CLR), might resemble 
the following:

#define SYS_ALIGN sizeof(double) /* for instance */

struct generation {
volatile void *next;
void *top;
void *base;
}
struct generation *generation_init(size_t capacity) {
struct generation *g = (struct generation *) malloc(sizeof(struct 
generation));
g-next = g-base = malloc(capacity);
g-top = g-base + capacity;
}

void* generation_alloc(struct generation* p, size_t len) {
len = (len + SYS_ALIGN - 1)  ~(SYS_ALIGN - 1); /* round up */
do {
void *ptr = ATOMIC_ADD(p-next, len);
if (ptr = p-top) {
return ptr - len; /* break the loop */
}
gc();
} while (true); /* try again */
}
+ No free space fragmentation at all.
+ Super-duper fast.
+ Threadsafe.
+ Lock-free unless ATOMIC_ADD cannot be implemented without a mutex.
- There is copying overhead when the generation is exhausted.
- One could say that the generation is fragmented by garbage.
+ It is no more fragmented by garbage than a GC system which uses a 
freelist allocator.



Gordon Henriksen

RE: Start of thread proposal

2004-01-19 Thread Gordon Henriksen
Dan Sugalski wrote:

 [A] copying collector is generally untenable in a threaded
environment.

Can you elaborate upon the reasoning behind this statement?


 The first thing that any vtable function of a shared PMC must do is to

 aquire the mutex of the PMCs in its parameter list, in ascending 
 address order. When the mutexes are released they are not required to 
 be released in any order.

Note that this locking strategy cannot avoid deadlock if the user is 
allowed to acquire these locks--HLL locks must be altogether different
beasts from automatic PMC locks. That's okay. Just a design consequence
worth noting for everyone.

-- 

Gordon Henriksen
IT Manager
ICLUBcentral Inc.
[EMAIL PROTECTED]



RE: Start of thread proposal

2004-01-19 Thread Gordon Henriksen
Dan Sugalski wrote:

 For a copying collector to work, all the mutators must be blocked, 
 and arguably all readers should be blocked as well.

True of non-moving collectors, too. Or, let me put it this way: non-
copying *GC* (the sweep or copy phase) can be threadsafe, but the mark
phase is never threadsafe. The method in which marking is not
threadsafe is a bit more pathological (i.e., it's not the common case
as it is with the copying collector), but a standard tracing DOD 
cannot be correct when competeting with mutators. It WILL collect non-
garbage (those are MUTATORS, remember), and the result WILL be 
Heizenbugs and crashes.

Some of what I've written up addresses why. It's pretty simple to
demonstrate a single case to prove the point, but I don't feel like 
re-creating the ASCII art right now. :) I'll send that section when I 
get out of the office.

parrot will have to be able to suspend all threads in the environment.
Unfortunate, but really quite unavoidable.


 Oh, arguably it can't avoid deadlock at all, what with vtable methods 
 having access to the full environment. I can live with deadlocks, 
 only because there's no real alternative.

But PMC implementations have to fall inside of the trusted environment,
so that's not really a failure. Of course uncooperative code can break
a cooperative algorithm. :)

-- 

Gordon Henriksen
IT Manager
ICLUBcentral Inc.
[EMAIL PROTECTED]



Re: Start of thread proposal

2004-01-19 Thread Gordon Henriksen
On Monday, January 19, 2004, at 06:37 , Gordon Henriksen wrote:

Dan Sugalski wrote:

For a copying collector to work, all the mutators must be blocked,
and arguably all readers should be blocked as well.
True of non-moving collectors, too. [...]

Some of what I've written up addresses why. [...] I'll send that 
section when I get out of the office.
Consider this simple object graph:

Root set = { A, B }

[ A=NULL]
[ B=C  ] --- [ C=]
Collection begins in thread 1 and marks A as reachable before being 
preempted by thread 2:

[xA=NULL]
[ B=C  ] --- [ C=]
Thread 2 sets A to C, and nullifies B before being preempted again by 
thread 1:

[xA=C  ] --- [ C=]
[ B=NULL]
Thread 1 marks B as reachable:

[xA=C  ] --- [ C=]
[xB=NULL]
The mark phase complete, thread 1 sweeps:

[ A=???] --- ???
[ B=NULL]
C was not marked reachable (although it was) and was thus erroneously 
collected, leaving a dangling pointer. This problem applies equally to 
copying and mark-sweep collectors.



Gordon Henriksen
[EMAIL PROTECTED]


Re: Events and JIT

2004-01-17 Thread Gordon Henriksen
On Saturday, January 17, 2004, at 05:53 , Leopold Toetsch wrote:

Gordon Henriksen [EMAIL PROTECTED] wrote:

Other threads than the target could be executing the same chunk of 
JITted code at the same time.
No. JITed (and prederefed) code is thread-specific, because register 
addresses are converted to absolute memory locations.
Ack! Might want that to be configurable for the JIT, to reduce the 
overhead of starting a thread...



Gordon Henriksen
[EMAIL PROTECTED]


Re: Events and JIT

2004-01-17 Thread Gordon Henriksen
On Saturday, January 17, 2004, at 05:51 , Leopold Toetsch wrote:

Jeff Clites [EMAIL PROTECTED] wrote:

... Also, once the handler is entered we'd have to fix all of patched 
locations, which again could be time-consuming for large bytecode.
Please remember: only the current code segment has to be patched, which 
theoretically could be very large, but that's unlikely.
What if control leaves the current code segment before you finish 
patching it? If an event is being delivered from another thread, this is 
very likely to occur if the event delivery thread is preempted by the 
event receiver.



Gordon Henriksen
[EMAIL PROTECTED]


Re: cygwin link failure

2004-01-17 Thread Gordon Henriksen
On Friday, January 16, 2004, at 03:34 , Seiler Thomas wrote:

inet_pton has not yet been implemented in cygwin, but it is being 
worked on...
http://win6.jp/Cygwin/
Indeed, but I think there might be other unix-like environments that 
(do not yet|will never) provide the inet_pton function.
Mac OS X 10.1 does not.



Gordon Henriksen
[EMAIL PROTECTED]


Re: Events and JIT

2004-01-17 Thread Gordon Henriksen
On Saturday, January 17, 2004, at 12:47 , Leopold Toetsch wrote:

Gordon Henriksen [EMAIL PROTECTED] wrote:

What if control leaves the current code segment before you finish 
patching it?
Ops that can leave the code segment have to explicitely check for 
events.
Then no need to patch invoke*.

If the target thread handles the event and unpatches the bytecode before 
the source thread finishes patching?



Gordon Henriksen
[EMAIL PROTECTED]


RE: Events and JIT

2004-01-16 Thread Gordon Henriksen
Leopold Toetsch wrote:

 Event handling currently works for all run cores[1] except JIT.
 
 The JIT core can't use the schemes described below, but we could:
 2) Patch the native opcodes at these places with e.g. int3 (SIG_TRAP, 
 debugger hook) cpu instruction and catch the trap. Running the event 
 handler (sub) from there should be safe, as we are in a 
 consistent state 
 in the run loop.

I don't think that bytecode-modifying versions should fly; they're not
threadsafe, and it would be nice to write-protect the instruction stream
to avert that attack vector.


 1) explicitely insert checks, if events are to be handled
 1a) everywhere or
 1b) in places like described below under [1] c)

I like this (1b). With the JIT, an event check could be inlined to 1
load and 1 conditional branch to the event dispatcher, yes? (So long as
interp is already in a register.) If that's done before blocking and at
upward branches, the hit probably won't be killer for most of code. For
REALLY tight loops (i.e., w/o branches or jumps, and w/ op count less
than a particular threshold), maybe unroll the loop a few times and then
still check on the upward branch.

Those branches will almost always fall straight through, so while there
will be load in the platform's branch prediction cache and a bit of
bloat, there shouldn't be much overhead in terms of pipeline bubbles.
The event ready word (in the interpreter, presumably) will stay in the
L1 or L2 cache, avoiding stalls.

No, it's not zero-overhead, but it's simple and easy enough to do
portably. Crazy platform-specific zero-overhead schemes can come later
as optimizations.

-- 

Gordon Henriksen
IT Manager
ICLUBcentral Inc.
[EMAIL PROTECTED]



RE: Events and JIT

2004-01-16 Thread Gordon Henriksen
Michal,

 But rather than always monitoring for that, I'd want
 to register a listener and then have parrot handle the
 polling for me.

This is precisely what's being discussed.


 This is probably a dumb question but: what if signals
 threw exceptions instead?

I'd hope that the event handler for a signal event could 
elect to throw an exception; it could even be the default.
But the exception has to get into the thread somehow--
exceptions don't autonomously happen, and they require
considerable cooperation from the thread on which the
exception occurs. High-priority events are that mechanism
through which the code which will throw the exception can
interrupt normal program execution.

-- 

Gordon Henriksen
IT Manager
ICLUBcentral Inc.
[EMAIL PROTECTED]



RE: Events and JIT

2004-01-16 Thread Gordon Henriksen
Leopold Toetsch wrote:

 Why? The bytecode is patched by a different thread *if* an 
 event is due (which in CPU cycles is rare). And I don't see a 
 thread safety problem. The (possibly different) CPU reads an 
 opcode and runs it. Somewhere in the meantime, the opcode at 
 that memory position changes to the byte sequence 0xCC (on 
 intel: int3 ) one byte changes, the CPU executes the trap or 
 not (or course changing that memory position is assumed to be 
 atomic, which AFAIK works on i386) - but next time in the 
 loop the trap is honored.

Other threads than the target could be executing the same chunk
of JITted code at the same time.

-- 

Gordon Henriksen
IT Manager
ICLUBcentral Inc.
[EMAIL PROTECTED]



Re: JVM as a threading example (threads proposal)

2004-01-16 Thread Gordon Henriksen
 point with respect to VM-internal state, morph scares me quite 
a bit. Type-stable memory is vital to lock-free (efficient) data access. 
Consider:

a_pmc is of type A
--- thread 1 is executing ---
Thread 1: load a_pmcvtable-whatever
Thread 1: call to a_vtable_whatever begins...
--- thread 2 preempts thread 1 ---
Thread 2: morph PMC to type B
Thread 2: Allocate new B-type pmc_ext structure
Thread 2: update a_pmc-vtable
Thread 2: adjust a_pmc-pmc_ext
--- thread 1 resumes ---
Thread 1: ... finish setting up the call
Thread 1: a_vtable_whatever reads ((A_ext) a_pmc-pmc_ext)-foo; B_ext 
happens to keep some float at the same offset in the struct
Thread 1: chaos

Keeping in mind the reality of delayed writes on SMP systems, there's 
just no way to code around this except to acquire a lock on the entire 
PMC for every read or write. Bye-bye performance: Acquire 2-3 locks to 
add 2 PerlInts together? ... Or bad performance and poor concurrency: 
Acquire 1 global lock whenever performing any PMC operation.

I'm tired



Gordon Henriksen
[EMAIL PROTECTED]


Re: JVM as a threading example (threads proposal)

2004-01-16 Thread Gordon Henriksen
 follow when generating a 
sequence of opcodes from Java source code.

What I think it's really saying, again translated into Parrot terms, is 
this:
What it's really saying is that JVM must be wary of aliasing, a bane of 
optimizing compilers.

store_global foo, P0 # internally, may cache value and not push to 
main memory
Well, might not immediately push to main memory. But, yes, a dirty write 
cache would qualify as an in-flight memory transaction (an uncommitted 
store operation).

find_global P0, foo # internally, can't pull value from main memory 
if above value was not yet pushed there
True, but it's enforced by a different rule:

Let action A be a load or store by thread T on variable V, and let 
action P be the corresponding read or write by the main memory on 
variable V. Similarly, let action B be some other load or store by 
thread T on that same variable V, and let action Q be the corresponding 
read or write by the main memory on variable V. If A precedes B, then P 
must precede Q. (Less formally: operations on the master copy of any 
given variable on behalf of a thread are performed by the main memory in 
exactly the order that the thread requested.)

and I think the point is this:

find_global P0, foo # internally, also caches value in thread-local 
storage
find_global P0, foo # internally, can use cached thread-local value
Don't think of working storage as a cache. Think of it as a necessity: 
The processor can't operate on data unless it has been brought into the 
working storage. The true complexities of caching are encompassed by the 
read and write operations and the orderings imposed on themparticularly 
with respect to the fact that only explicit locking imposes an ordering 
on reads and writes between threads. Caches, the stack, and registers 
all fall under the rubric of working storage in this spec.

And, as mentioned in section 8.6, any time a lock is taken, cached 
values need to be pushed back into main memory, and the local cache 
emptied. This doesn't make any sense if the thread's working memory 
is interpreted as the stack.
It does make sense. The rules says that all thread-local changes must be 
flushed completely to main memory before the thread blocks. It ensures 
that other threads will see changes made by the thread, and visa versa, 
so that data protected by the lock is always viewed in a consistent 
state. On a PowerPC, the JVM just needs to store all 
assigned-but-unstored variables and then execute the PPC sync 
instruction.



Gordon Henriksen
[EMAIL PROTECTED]
[Vocab note: A write-back cache only stores changes to main memory when 
the variable is evicted from the cache (it optimizes both loads and 
stores). Its corollary is a write-through cache, which stores changes to 
main memory on every update (it only optimizes loads). A write-back 
cache prevents implicit SMP cache coherency, because it gives the other 
processor caches no sign that the memory word has been changed until the 
word is evicted naturally or a cache-coherency instruction (like sync) 
forces the issue.]


RE: JVM as a threading example (threads proposal)

2004-01-15 Thread Gordon Henriksen
 -Original Message-
 From: Jeff Clites [mailto:[EMAIL PROTECTED] 
 Sent: Thursday January 15, 2004 01:28
 To: Gordon Henriksen
 Cc: [EMAIL PROTECTED]
 Subject: Re: JVM as a threading example (threads proposal)
 
 
 On Jan 12, 2004, at 10:03 AM, Gordon Henriksen wrote:
 
  On Monday, January 12, 2004, at 04:29 , Jeff Clites wrote:
 
  5) Java seems to use a check-in/check-out model for access 
 to global
  data, in which global data lives in a central store, but 
 is copied  
  back-and-forth to thread-local storage for modification. I don't 
  fully  understand the performance benefit which I assume this 
  provides, but  this is something else we need to understand. It's 
  discussed in detail  in the threads section of the JVM spec,  
  http://java.sun.com/docs/books/vmspec/2nd-edition/html/ 
  Threads.doc.html.
 
  The passage in question being:
 
  Every thread has a working memory in which it keeps its own working
  copy of variables that it must use or assign. As the thread 
 executes a 
  program, it operates on these working copies. The main 
 memory contains 
  the master copy of every variable. There are rules about 
 when a thread 
  is permitted or required to transfer the contents of its 
 working copy 
  of a variable into the master copy or vice versa.
 
 There's that passage, but actually the following sections go 
 into depth 
 about the semantic constraints on how this is supposed to work.
 
  This is very obliquely phrased, but it refers to the 
 register file and
  stack frame. Or, since the Java bytecode is stack-based, it 
 refers to 
  the stack.
 
 You might be right, but that's not exactly how I read it, 
 because later 
 it says, A use action (by a thread) transfers the contents of the 
 thread's working copy of a variable to the thread's execution engine. 
 This action is performed whenever a thread executes a virtual machine 
 instruction that uses the value of a variable.
 
 I assume that the stack would correspond to the execution engine 
 here, rather than to the thread's working copy, but I could read it 
 either way.
 
 In any case, I thought this sounded like an interesting model, but 
 based on the rules in that section about how accesses to data in the 
 thread-local store have to correspond to accesses of the main 
 store, it 
 wasn't apparent to me how there was an advantage over just accessing 
 things directly out of the main store. But I assume I'm overlooking 
 some subtlety, and that there may be an idea here that we 
 could use to 
 our advantage.

The two-level memory model in the spec seems to address, as a group, the
register file, stack (JVM stack and/or system call stack; same
difference), and the cache hierarchy in an SMP system. All in all, it's
a very oblique way of saying that changes might not be immediately
visible to all threads. For example, on the PPC, a sync instruction is
required to ensure that all the processor caches have a consistent view
of main memory. sync and its equivalents are far too expensive to
execute after every change to any variable, so the JVM's spec is written
to allow implementations to avoid it most of the time.

-- 

Gordon Henriksen
IT Manager
ICLUBcentral Inc.
[EMAIL PROTECTED]




Re: JVM as a threading example (threads proposal)

2004-01-12 Thread Gordon Henriksen
On Monday, January 12, 2004, at 04:29 , Jeff Clites wrote:

5) Java seems to use a check-in/check-out model for access to global  
data, in which global data lives in a central store, but is copied  
back-and-forth to thread-local storage for modification. I don't fully  
understand the performance benefit which I assume this provides, but  
this is something else we need to understand. It's discussed in detail  
in the threads section of the JVM spec,  
http://java.sun.com/docs/books/vmspec/2nd-edition/html/ 
Threads.doc.html.
The passage in question being:

Every thread has a working memory in which it keeps its own working copy 
of variables that it must use or assign. As the thread executes a 
program, it operates on these working copies. The main memory contains 
the master copy of every variable. There are rules about when a thread 
is permitted or required to transfer the contents of its working copy of 
a variable into the master copy or vice versa.

This is very obliquely phrased, but it refers to the register file and 
stack frame. Or, since the Java bytecode is stack-based, it refers to 
the stack.



Gordon Henriksen
[EMAIL PROTECTED]


Re: More object stuff

2004-01-12 Thread Gordon Henriksen
On Monday, January 12, 2004, at 11:37 , Dan Sugalski wrote:

At 4:07 PM + 1/12/04, Harry Jackson wrote:
Dan Sugalski wrote:
Well...

What I'd like, I think, is something simple and straightforward. 
Right now we've got to fetch each column for each row one by one, 
which is a pain in the neck if you want to get a full row back. 
Having a fetchrow that returned an Array with the value for column 
one in the 0th slot, column 2 in the 1st slot and so on would be 
about 80% of the solution.
I have done this part.

Having a fetchrow_hash that returned a Hash where the keys are the 
column names and the values are the column values would be most of 
the rest.
I read somewhere that accessing a hash was slightly slower than 
accessing and array which is one reason why I never used it. The other 
reason is that if I name the fileds in the hash then the user needs to 
know the names to access them or perform some magic to get them. With 
an array they come out in the order they are aksed for.
Definitely. However... Having seen code in production, generally the 
fields aren't changeable and are known at compile-time, or folks are 
writing generic code (for better or worse). In the first case people 
use hash access because they know there's a name and city field in 
the results, and in the second case they're iterating across the keys 
and pulling out values.

Since folks are going to wrap the results in a hash regardless of 
whether it's a good idea or not (not going there... :) we might as well 
have it in at the very lowest level where we can get the information 
most efficiently.
fetchrow_hashref is definitely a very useful, but my favorite (and also 
the most efficient) DBI methodology is bind_columns. DBI maintains a 
list of references corresponding to columns in the result set, and when 
the result set is advanced, stores the values into the variables 
referenced. e.g., Perl 5:

my $sth = $dbh-prepare(select a, b, c from tab);
$sth-execute;
$sth-bind_columns(\my($a, $b, $c));

while ($sth-fetch) {
print a: $a, b: $b, c: $c\n;
}
Equivalent to:

my $sth = $dbh-prepare(select a, b, c from tab);
$sth-execute;
$sth-bind_col(0, \my $a);
$sth-bind_col(1, \my $b);
$sth-bind_col(2, \my $c);

while ($sth-fetch) {
print a: $a, b: $b, c: $c\n;
}
So if you're going to basically go all out in emulating DBI's fetch_* 
permutations, don't forget this one. :)



Gordon Henriksen
[EMAIL PROTECTED]


Re: Threads Design. A Win32 perspective.

2004-01-06 Thread Gordon Henriksen
On Sunday, January 4, 2004, at 03:17 , Jeff Clites wrote:

On Jan 3, 2004, at 8:59 PM, Gordon Henriksen wrote:

On Saturday, January 3, 2004, at 04:32 , Nigel Sandever wrote:

Transparent interlocking of VHLL fat structures performed 
automatically by the VM itself. No need for :shared or lock().
Completely specious, and repeatedly proven unwise. Shouldn't even be 
pursued.

Atomic guarantees on collections (or other data structures) are rarely 
meaningful; providing them is simply a waste of time. Witness the 
well-deserved death of Java's synchronized Vector class in favor of 
ArrayList. The interpreter absolutely shouldn't crash due to threading 
errorsit should protect itself using standard techniquesbut it would 
be a mistake for parrot to mandate that all ops and PMCs be 
thread-safe.
What are these standard techniques? The JVM spec does seem to guarantee 
that even in the absence of proper locking by user code, things won't 
go completely haywire, but I can't figure out how this is possible 
without actual locking. (That is, I'm wondering if Java is doing 
something clever.) For instance, inserting something into a collection 
will often require updating more than one memory location (especially 
if the collection is out of space and needs to be grown), and I can't 
figure out how this could be guaranteed not to completely corrupt 
internal state in the absence of locking. (And if it _does_ require 
locking, then it seems that the insertion method would in fact then be 
synchronized.)

So my question is, how do JVMs manage to protect internal state in the 
absence of locking? Or do they?
The JVM won't crash, but individual objects can easily become corrupt. 
Java makes no guarantees of the level you're proposing. All 
synchronization in Java is explicit, using either synchronized methods, 
or synchronized (...) { ... } blocks; the runtime doesn't implicitly 
burn cycles synchronizing objects for the user. It does, however, give 
the user the threading primitives which allow them to write thread-safe 
code. Thread-safety is, indeed, left entirely to the user. This is 
crucial to allowing code to execute quickly and for the optimizer to 
function. The JVM protects itself, ensures that its core is thread-safe, 
and provides a secure operating environment for user code; it is the 
responsibility of the authors of classes to protect instances of their 
classes. Remember, Java's libraries are implemented atop these 
primitives *in Java.* It would be analogous to propose that parrot-based 
languages be primarily implemented atop its primitives in PBC, and that 
the sections which are not so-implemented (the core) must be 
scrutinized carefully for threadsafety.

What are these threadsafe primitives which Java provides? For example:

1. Fixed-size arrays are safe to access concurrently from multiple 
threads.
2. ints, chars, pointers, etc. can be updated atomically.
3. Java's memory allocator is thread-safe.
4. Strings are immutable (and thus sharable without threadsafety 
violations).
5. The JVM does not allow memory to be resized, making bounds-checking 
threadsafe.
6. No objects can be moved (while retaining their identity) except by 
the garbage collector.
7. All threads are suspended during GC.
8. All pointers are traceable by GC.

That parrot is largely implemented in C, and is designed to operate in 
terms of fat data structures, makes it much more difficult to guarantee 
in parrot that segfaults will not occur. I have some ideas which I'll 
share after I sync up with this fast-moving thread (of conversation). 
But one of my premises is that implicitly guaranteeing atomic PMC 
accesses will render threaded parrot dead-on-arrival. Just like the last 
2 abortive attempts at creating a threading Perl implementation. (And 
threaded parrot would be a separate executable, because the 
performance hit will be so staggering.) The sheer overhead of locking is 
an obvious deal-killer, but I think that deadlocks and prohibition of 
optimizations would quickly put a few extra nails in the coffin. I don't 
want to see the Perl community left adrift with another toy threading 
implementation unsuitable for any serious work.



Gordon Henriksen
[EMAIL PROTECTED]


Re: Threads Design. A Win32 perspective.

2004-01-06 Thread Gordon Henriksen
On Sunday, January 4, 2004, at 01:43 , Dan Sugalski wrote:

At 11:59 PM -0500 1/3/04, Gordon Henriksen wrote:
On Saturday, January 3, 2004, at 04:32 , Nigel Sandever wrote:

Transparent interlocking of VHLL fat structures performed 
automatically by the VM itself. No need for :shared or lock().
Completely specious, and repeatedly proven unwise. Shouldn't even be 
pursued.
Erm... that turns out not to be the case. A lot. (Yeah, I know, I said 
I wasn't paying attention)

An interpreter *must* lock any shared data structure, including PMCs, 
when accessing them. Otherwise they may be in an inconsistent state 
when being accessed, which will lead to data corruption or process 
crashing, which is unacceptable.

These locks do not have to correspond to HLL-level locks, though it'd 
be a reasonable argument that they share the same mutex.
Process crashing unacceptable? Absolutely. Complete agreement.

Data corruption unacceptable? I disagree. It depends on the contract put 
forward by the language in question. Notably, Perl makes no such 
guarantees thus far, being as how it doesn't (any longer) run in a 
traditional threaded model. Successfully threaded languages and virtual 
machines explicitly make NO such guarantees. I'm completely okay with 
the potential for inconsistent data where the user doesn't take 
precautions. If the alternative is my code bogging down to half of its 
ideal speed because parrot is wasting time: acquiring three mutexes with 
deadlock detection so that it can execute add $P10, $P11, $P12; 
acquiring a mutex every time it indexes a string register; acquiring a 
mutex so it can examine cache-int_valif those are the alternatives, 
I'm for the potential for inconsistent data. (And I say wasting because 
it's completely unnecessary in a good 99% of cases; the vast majority of 
data is not shared between threads at all.)

I'm not okay with parrot crashing for any reason, ever, though, so where 
locking is not provided, PMC classes *must* be coded *very* carefully so 
as to avoid crashes.



Gordon Henriksen
[EMAIL PROTECTED]


Re: Threads Design. A Win32 perspective.

2004-01-04 Thread Gordon Henriksen
On Saturday, January 3, 2004, at 04:32 , Nigel Sandever wrote:

Transparent interlocking of VHLL fat structures performed automatically 
by the VM itself. No need for :shared or lock().
Completely specious, and repeatedly proven unwise. Shouldn't even be 
pursued.

Atomic guarantees on collections (or other data structures) are rarely 
meaningful; providing them is simply a waste of time. Witness the 
well-deserved death of Java's synchronized Vector class in favor of 
ArrayList. The interpreter absolutely shouldn't crash due to threading 
errorsit should protect itself using standard techniquesbut it would 
be a mistake for parrot to mandate that all ops and PMCs be thread-safe.

The details of threaded programming cannot be hidden from the 
programmer. It's tempting to come up with clever ways to try, but the 
engine really has to take a back seat here. Smart programmers will 
narrow the scope of potential conflicts by reducing sharing of data 
structures in their threaded programs. Having done so, any atomicity 
guarantees on individual objects proves to be wasted effort: It will be 
resented by parrot's users as needless overhead, not praised. Consider 
the potential usage cases.

1. All objects in a non-threaded program.
2. Unshared objects in a threaded program.
3. Shared objects in a threaded program.
The first two cases will easily comprise 99% of all usage. In only the 
third case are synchronized objects even conceivably useful, and even 
then the truth of the matter is that they are of extremely limited 
utility: Their guarantees are more often than not too fine-grained to 
provide the high-level guarantees that the programmer truly needs. In 
light of this, the acquisition of a mutex (even a mutex that's 
relatively cheap to acquire) to push an element onto an array, or to 
access a string's datawell, it stops looking so good.

That said, the interpreter can't be allowed to crash due to threading 
errors. It must protect itself. But should a PerlArray written to 
concurrently from 2 threads guarantee its state make sense at the end of 
the program? I say no based upon precedent; the cost is too high.



Gordon Henriksen
[EMAIL PROTECTED]


Factoring threads friends

2004-01-01 Thread Gordon Henriksen
I just thought I would put forward a summary of how .NET factors its 
thread-related data structures. It's a successful, performant, lock-free 
design, and I think a quite interesting factorization of what parrot 
presently presents as the interpreter. It's the single most successful 
threading design I've encountered to date.

The entities involved are the process, the thread, the app domain. 
These entities take separate responsibility for some of the features of 
the parrot interpreter.

The process is the global-most .NET state, owning threads and app 
domains, and coordinating events such as GC. This is truly global state, 
and there's not a whole lot of it.

.NET threads contain little more than a stack and an instruction pointer.

App domains are lightweight protected execution environments. Code is 
loaded into app domains, and types registered in data structures owned 
by the app domain. Objects are allocated within an app domain. The 
majority of the .NET runtime is a property of the app domain. Individual 
classes and libraries cannot be unloaded in .NET, but entire app domains 
can be.

Stack frames are obviously within a thread's stack, and thus owned by 
that thread. But each stack frame also is attached to a particular app 
domain, and thus knows how to allocate objects, etc. without the 
overhead of an extra pointer in every object; the app domain is .NET's 
implicit argument, akin to parrot's interpreter parameter. If this were 
a relational database, one might say that a stack frame was a 
many-to-many relationship between threads an app domains. So a thread 
does not belong to a single app domain: This is not a hierarchical 
design.

Objects live in one and only one app domain. Since every stack frame 
also knows its app domain, it follows that all visible objects belong to 
the app domain of the executing thread. Thus memory pools can be easily 
identified for memory allocation, and the type registry found, etc. etc. 
etc.in general, the runtime can be utilizedwithout the waste of an 
extra pointer in the object header.

App domains cannot directly reference each others' objects. 
Communication between app domains most resembles RPC. Only through proxy 
objects can one app domain interact with another. The default behavior 
is that objects passed as arguments to proxy methods will be serialized 
and deserialized into the target app domain (although they can specify 
that remote proxies will instead be created in the target app domain). 
These proxies obviously do need to store a pointer to the peer app 
domain, but other objects do not, keeping overhead low.

Objects do not have fine-grained locks. If their methods require 
synchronization, their implementations must request it with a block: 
lock (this) { /* code goes here */ }. Most of the objects in the 
libraries are not safe for multithreaded access (although their static 
methods generally are).

GC affects more than one app domain: It halts all threads. (Certain 
other events do as well, including unloading an app domain, or mucking 
with loaded types, or backing out JIT optimizations.) The garbage 
collector is aware of proxy objects that bridge app domains. Since it 
operates at the process level, it can collect garbage cycles even across 
app domains (where normal RPC proxies would cause reference cycles).

The .NET design doesn't meet all of requirements Dan set forth, but it's 
at least an interesting case study in a successful threading environment 
for a high-performance virtual machine.



Gordon Henriksen
[EMAIL PROTECTED]


Threading design

2003-12-30 Thread Gordon Henriksen
I wish the threading design for parrot would look more toward 
successful, performant multithreaded systems, rather than setting up new 
design experiments based upon the results of failed experiments (in 
particular, all forms of Perl 5 threading). I think that 
environment-cloning and fine-grained locks have both been adequately 
proven antithetical to what is expected from threads: Lightweight, 
low-overhead concurrency. Environment cloning is high-performance, but 
high overhead. Fine-grained locks are low overhead, but low-performance.



Gordon Henriksen
[EMAIL PROTECTED]


Re: Threads and Events (was Re: threads and shared interpreter data structures)

2003-12-30 Thread Gordon Henriksen
On Tuesday, December 23, 2003, at 08:40 , Rod Adams wrote:

- Most treaded code can be converted to an event loop (+async I/O) 
without issue. Esp if we have co-routines.
- For the other stuff, we'd still have Type 2 threads, which gets the 
job done.
(Just got back from vacation and was reviewing this aging thread...)

Not to throw a damper on the events party or anything, but an 
event-based system with asynchronous I/O isn't capable of saturating an 
SMP box's processors. This is one of the major reasons for using threads 
in web servers. It's also a significant reason for using threads in 
desktop applications. Yes, N interpreters for N processors will get you 
there, but at the cost of times-N static memory consumption (for JITted 
code, type registries, vtables, etc.: interpreter overhead), and at the 
cost of fine-grained, lightweight inter-thread communication between the 
segregated threads.

Further, threading implemented as context switches at block time amounts 
to a cooperative multithreading environment. Yes, it may provide 
near-optimal throughput. Despite that, it also has some very bad indeed 
worst-case latency characteristics. If a worker thread fails to block, 
the thread which started it will never (or rarely) run and the program 
will become unresponsive. This makes such a threading model unsuitable 
for use as in a web application host. One misbehaving HTTP request 
handler mustn't block other requests. A worker thread mustn't block the 
UI thread.

Sidenote: Shades of System 7: CPU benchmarks on the old Mac OS do run 
several percentage points faster than on preemptive systems. The 
preemptive model is clearly superior in the general case, though; its 
perceived performance under load is by far superior. Also worth noting: 
parrot will already be paying the preemptive performance penalty on any 
modern OS.

I can only hail core events and asynchronous I/O as great advances in 
parrot. But they are not a general replacement for preemptive 
multithreading. Of course, TMTOWTDI and YMMV, but parrot should support 
both models well, and the above line of thought isn't doing threading 
justice in my opinion.



Gordon Henriksen
[EMAIL PROTECTED]


Re: Threads

2003-12-30 Thread Gordon Henriksen
Leopold Toetsch wrote:

Dan Sugalski wrote:

Leopold Toetsch wrote:

Again, not only strings but all kind of containers using managed
resources suffer from that problem.
All that seems to imply, that we need two locks for shared access: one
for protecting DOD/GC and a second for the PMC. Any container 
(including
PerlStrings) would have to aquire the first (interpreter-global) lock,
while a PerlNum only needs the second per PMC mutex. Ugly.
Yeah, it all potentially gets nasty.
[...]

[3] They can't be suspended inmidst of an arbitrary operation (and 
pthread doesn't even provide suspending) so they would be sent a 
suspend event so that they are in a safe state in the run-loop, or 
better in the event-handler opcode, called from there.
(Just got back from vacation and was reviewing this aging thread...)

Yes, yes! Stopping other threads when a rare condition occurs is a great 
way to avoid penalizing a threaded program's common case with excessive 
synchronization overhead. There are just too many things that can go 
wrong otherwise; fine-grained locking is the alternative, and programs 
will very, very rapidly find themselves spending 40% of their cycles 
acquiring mutexes.

This is definitely the way to go to achieve blistering performance while 
retaining dynamic capabilities. The work is already done to ensure that 
while true { ; } will receive events in a timely fashion. Broadcasting 
parrot events should be an excellent means of implementing inter-thread 
synchronization.



Gordon Henriksen
[EMAIL PROTECTED]


RE: Namespaces

2003-12-11 Thread Gordon Henriksen
Leopold Toetsch [EMAIL PROTECTED] wrote:

 Dan Sugalski [EMAIL PROTECTED] wrote:
 
  Okay, okay, I give -- hierarchic namespaces are the way to go. Makes

  local overrides somewhat interesting, but we'll burn that bridge
when 
  we get to it.
  
find_global P1, ['global', 'namespace', 'hierarchy'], thingname

So (excuse the Perl 5), $::thingie would be this:

find_global P1, [], thingie

(Or [], $thingie.)

Makes it odd to actually name a symbol, since it's broken in one + N.

What's the good of separating the symbol name from the namespace name?


  That is, split the namespace path from the name of the thing, and
  make the namespace path a multidimensional key.
  
  Or I suppose we could just punt and toss the special global access
  entirely and make the global namespace a hash 'o hashes hanging off
  the interpreter and access it like any other variable,
 
 What about:
 
   getinterp P2
   set P1, P2['global';'namespace';'hierarchy';'thingname']
 
 That is get_pmc_keyed() on a ParrotInterpreter PMC with a multi-key,
 straight-forward. The set_pmc_keyed() stores a global.

What if global.namespace happens to be autoloaded or otherwise magic?
Will the get_keyed break down and do something equivalent to this?

getinterp P2
set P1, P2['global';'namespace']
set P1, P1['hierarchy';'thingname']

Meaning the construction of an extra multikey? Yech, maybe.

 Constructing a multy-key by hand isn't that simple (or would need
 hacking imcc) (and Key componenent separator is a semicolon).

YECH.


I can see y'all are already leaning away from this direction, but I
thought
I'd still bring them up as ideas:

 - The nameless root namespace is an easy-to-get-to parrot or 
interpreter global, so there's no need to have a separate interface 
to access the global namespace vs. accessing a namespace in a PMC 
register.

(Though interp-is-a-namespace is cute. Maybe too cute, if namespaces
are subclassable.)

 - Namespaces have methods/ops to look up a contained symbol (just
one level), where any string is a valid symbol. (And there's the
option of not recursing into parent namespaces; i.e., looking only
at declared members.)

 - Namespaces also have methods to traverse a path of symbols, where 
all but the last symbol in the path must itself be a namespace. 
Symbol paths are mangled using a DEAD SIMPLE, absolutely canonical 
encoding, with debug-friendly printable ASCII escapes. e.g.:

# Example only:
# '.' is path delimiter and '%' is escape char
# Using '\' would induce LTS in IMCC  C.
foreach (@path) {
s/\%/\%\%/g;
s/\./\%\./g;
}
$path = join(., @path);

So unless you use a '.' or '%' in your symbol, it won't be mangled
at all, and if it started out printable ASCII, it'll stay that way.
And if you do use one of those reserved characters, the mangled form
won't be too terribly surprising.

This does presume that symbols must be in a charset with '.' and 
'%'. My heart bleeds for those that aren't.

Bad Thought: If the empty symbol were prohibited (or ignored) in paths,
the delimiter . could be its own escape character, e.g.:
[float;1.0] could be float.1..0.

While a strawman symbol path lookup could be implemented in terms of
single-level symbol lookup, smarter namespace implementations might 
optimize away the array (multikey) and extra strings. And this doesn't
require any massive restructuring of IMCC or PIR. (Unless you want them
to just do the mangling internally, rather than storing that [, ,
]
as an array constant. But why bother? .. is shorter than [, , ],
and doesn't suggest to a compiler author's mind keep a struct { char**;
char*; } around for each symbol reference.)


This would make Dan's example into:

find_global P1, global.namespace.hierarchy.thingname

shorthand for:

get_globals Py
find_sym P1, Py, global.namespace.hierarchy.thingname

and functionally equivalent to the wildly pedantic:

get_globals Py
find_onesym Py, Py, global
find_onesym Py, Py, namespace
find_onesym Py, Py, hierarchy
find_onesym P1, Py, thingname

Spelling aside, anyhow. (e.g., where find_onesym yada might be spelled
set yada[].)

--
 
Gordon Henriksen
IT Manager
ICLUBcentral Inc.
[EMAIL PROTECTED]



RE: [CVS ci] object stuff

2003-12-11 Thread Gordon Henriksen
Melvin Smith [EMAIL PROTECTED] wrote:

 my $foo = Oracle::Instance::DEV1::db_block_buffers;
 
 The namespace lookup in Oracle::Init checks the Oracle config 
 parameters which is external code.
 
 All sorts of neat possibilities. :)

It is truly remarkable the lengths that Perl programmers seem to be
willing go to in order to hide a function call or obscure the existence
of an object. :)

--
 
Gordon Henriksen
IT Manager
ICLUBcentral Inc.
[EMAIL PROTECTED]



Re: [RfC] Testing for null

2003-12-08 Thread Gordon Henriksen
On Monday, December 8, 2003, at 10:03 , Dan Sugalski wrote:

At 1:21 PM -0500 12/3/03, Melvin Smith wrote:
We should have 1 recommended  way for testing NULL registers.

If we support get_bool() then lets make sure it works for REAL NULL
pmc registers as well as PMCNULL.
If not, code will appear to work correctly on a safe core
but will seg fault on some other. Also, I see no reason not
to use PMCNULL in all cores now.
Okay, lets do this:

Add an isnull branch op:

  isnull Px, destination
How about this to test if Px is really null?

null Py
eq_addr Px, Py


Gordon Henriksen
[EMAIL PROTECTED]


Re: [RFC] IMCC pending changes request for comments

2003-12-04 Thread Gordon Henriksen
On Tuesday, December 2, 2003, at 11:49 , Melvin Smith wrote:

At 07:59 PM 12/2/2003 -0800, Steve Fink wrote:

Do you really want to generate the extra unused code at the end of all 
the subroutines? I don't think you want to autodetect whether the code 
is guaranteed to return.
Good point. Its easy to detect returns if the code uses high level IMC 
directives, but in cases where it is all low-level PASM, it could get a 
little troublesome. It would also add a few dead instructions here and 
there. Nix that idea.
Maybe just pad the end of the compilation unit with the opcode 
equivalent of PMCNULL, to fire an exception rather than having undefined 
behavior?



Gordon Henriksen
[EMAIL PROTECTED]


RE: Calling conventions. Again

2003-11-15 Thread Gordon Henriksen
Leo,

Consider this (as I'm sure you already have)...

class ClassA;
method meth($i is int)   { ... }

class ClassB;
method meth($f is float) { ... }

module main;
my $obj = (rand(1.0)  0.5? ClassA : ClassB)-new;
$obj-meth(1);

Perl's going not going to be able to bind to a HLL prototype, much less
a low-level one. Even if it could bind to the HLL prototype, it has to
protect against mutation of the method. Either perl6 recompiles the
caller when a new version of the sub is linked in, or perl6 uses a
calling convention that always works: Unprototyped.

Prediction: perl6 winds up using One True Parrot Unprototype for ALL of
its method and sub calls.

The parrot calling conventions thus become rather academic to Perl. The
target languages under consideration just aren't going to get little
mileage out of them.


Leo and Dan,

As for encoding varargs in the parrot calling conventions, parameter
counts are very much useless--they're might as well be a very poor
one-way hash of the prototype. Have you considered using 4 bitfields to
indicate what register parameters are what? E.g.

prototype: intin In+0,
   float  in Nn+1,
   string in Sn+2,
   string in Sn+3,
   float  in Nn+4,
   intin In+5,
   PMCin Pn+6

Iregs = (1  n+0) + (1  n+5) = 0b...011...
Fregs = (1  n+1) + (1  n+4) = 0b...0010010...
Sregs = (1  n+2) + (1  n+3) = 0b...0001100...
Pregs = (1  n+6)  = 0b...100...

This burns no more space in the register file than the 4 parameter
counts, and it doesn't throw away ordering data. Downside: Counting
total number of arguments is harder.

Four 32-bit bitfields match the 4 sets of 32 registers, so even if the
set of registers used for passing parameters grow, this convention is
safe. Overflow parameters... Well, figure something out; there's plenty
of space in the overflow array. (4 binary Sregs with likewise bitfields?
Or just use the PMC type.)

But imposing the overhead of 4 Ireg assignments on the caller and 4 Ireg
compares and branches on the callee at the beginning of every routine,
just to check that the register conventions are right? Don't think
that's a good idea. What's the recovery scenario going to be, anyhow? To
blow up... What a waste of cycles: It's a needless toll for 99.99%
of calls. Check that the prototype is right when the sub is loaded into
the runtime: In effect, throw the exception at link time. Then this
vararg cruft can be cut out of the common case. That is, support 3
parrot calling conventions:

  - unprototyped (your parameters are in an array)
  - prototyped (what you want in the register file is there)
  - vararg (I've documented what I put in the register file)


But, honestly, a vararg prototype string in an Sreg probably makes more
sense than either 4 register counts or 4 register masks. It avoids
burning integer registers--the most useful part of the register file for
the sort of low-level code which will actually USE parrot prototypes. It
can be set up by the caller with a single string constant load. It can
be checked by the callee with a single string compare instruction (if
the vararg list is actually static). It's easy to reflect, too.

--
 
Gordon Henriksen
IT Manager
ICLUBcentral Inc.
[EMAIL PROTECTED]


 -Original Message-
 From: Dan Sugalski [mailto:[EMAIL PROTECTED] 
 Sent: Friday, November 14, 2003 10:34 AM
 To: Leopold Toetsch
 Cc: [EMAIL PROTECTED]
 Subject: Re: Calling conventions. Again
 
 
 On Fri, 14 Nov 2003, Leopold Toetsch wrote:
 
  Dan Sugalski [EMAIL PROTECTED] wrote:
 
   I've seen it with some depressing regularity over the 
 years. It generally
   takes the form of an upgrade to a library that breaks existing
   executables, something we're going to have to deal with 
 as we're looking
   to encourage long-term use of bytecode-compiled programs.
 
  This seems to me the same, as that strcpy(3) should be 
 guarded against
  wrong argument count at runtime. But swapped 
 destination/source can't be
  detected anyway ;)
 
 We can't detect bugs like that, true. But we can detect when 
 someone calls
 us with two arguments and someone has, in the mean time, 
 helpfully added
 an optional length arg to strcpy.
 
   ... But there are
   several issues here:
 
   1) vararg calls with non-pmc registers involved
 
  I already did propose the syntax:
 [Snip]
  at least, so that runtime checks can be omitted for certain cases.
 
 No IMCC syntax that's purely compile-time is of any help 
 here. The code
 doing the calling
 
   2) Runtime modification of sub definitions
 
  are evil, forbidden, disallowed. This just can't work.
 
 True, false, false. It happens, in some cases a *lot*. This is perl,
 python, and ruby we're talking about, where changing the 
 definition of a
 sub is as trivial as a reference assignment into a global 
 hash. It's easy,
 people do it. Often, in some cases. (Heck, I've

RE: Ordered destruction and object graph traversal

2003-10-28 Thread Gordon Henriksen
Dan Sugalski wrote:

 Allow me to haul out this bucket of ice-water I keep around 
 for just such an eventuality. :)
 
 There's a low limit to the complexity of any sort of traversal we can
 provide. We *can't* go recursive in a traversal, if it crosses the
 C-Parrot or Parrot-C boundary as part of the recursion, or stays
 entirely in C. We can only count on a 20-40K stack *total*, 
 and it doesn't
 take too many calls into a recursive procedure to eat that 
 up. That limits
 the mechanisms we can use to traverse the graph of objects 
 pretty badly.
 The linked list mechanism the DOD system is using is one of 
 the few that
 isn't recursive.
 
 There are other mechanisms that can be used for traversal that avoid
 recursion, but they generally trade off pretty heavy memory 
 usage for that
 lack, which makes them unsuitable for general use.


That's what's beautiful about this: -visit isn't providing the
traversal algorithm at all. This vtable is agnostic to the traversal
algorithm. Breadth-first or depth-first; seen hash or mark bit or what
have you; zero-resource or resource-consuming: Whatever is best suited
to the requirements at hand. And it cleanly exposes that core
functionality to HLLs (which may have algorithmic requirements for
traversals that involve queues or stacks).

If parrot is embedded multi-threaded in an RDBMS or web server (which
strikes me as a more likely scenario than parrot embedded in a
resource-constrained embedded environment), then blocking the
interpreter for a serialization on one thread will negatively impact
response time, concurrency, and scalability. That might be considered
more damaging than additional resource consumption. -visit neatly
enables BOTH resource-consuming, threadsafe serialization AND
zero-resource, blocking serialization.

--
 
Gordon Henriksen
IT Manager
ICLUBcentral Inc.
[EMAIL PROTECTED]




Re: Ordered destruction and object graph traversal

2003-10-25 Thread Gordon Henriksen
On Monday, October 20, 2003, at 11:40 , Jeff Clites wrote:

My solution was to define a new vtable method--I've called it visit(), 
though the name's not the important part--to which you pass a callback 
(plus an optional context argument). It's job is to invoke that 
callback on each of it's referenced children (also passing the 
context object with each invocation), and that's it. The PMC doesn't 
know or care what the callback does--in a GC context the callback may 
set a flag on what's passed in and stash it for later processing; in 
another context it may be used inside of an iterator which vends out 
objects one-by-one and guards against loops.
Great! This is exactly the fundamental operation I'd been musing would 
be the best building block to enable serialization and pretty-print 
operations, and I'm sad to see that your post has been Warnocked. :(

This mechanism is excellent in that it enables both breadth-first and 
depth-first traversals, and is neutral to whether a pointer is traversed 
or not: The client (callback) can decide that based upon the live bit or 
the ordered destruction bit or a seen table or the phase of the moon. 
This also doesn't alone imply any resource consumption. And it doesn't 
affect concurrency; threading is preserved. Great!

Serialization is a very natural client of this API, and at least some of 
the arguments surrounding serialization should be lessenedbecause the 
core technology is amenable to use by various possible algorithms, and 
so deciding upon those algorithms early becomes less vital. 
Serialization simply becomes an easier problem with this in place.

I would venture, though, that DoD may well need a separate and heavily 
optimized implementation, purely for efficiency's sake.



Gordon Henriksen
[EMAIL PROTECTED]


RE: cvs commit: parrot/languages/imcc/t/syn pcc.t

2003-09-16 Thread Gordon Henriksen

 * e.g. add_n_i_n = add_n_n_i
 *  div_n_ic_n = div_n_nc_n
 *  div_n_i_n = set_n_i ; div_n_n_n
   + *  ge_n_ic_ic = ge_nc_ic




  -+-+
   | |
   | |
  _|_|
 /   \   |
( X X )  |
 \___/   |
   | |
---+---  |
   | |
   | |
   | |
   A |
  / \|
 /   \   |
/ \  |
   /   \ |
  / \|
 |
 |
 |

| A   C D E   G   I|
| N S T   V|






RE: Next Apocalypse

2003-09-16 Thread Gordon Henriksen
. (A ward against newly-born threads.)

 4. Change the world, firing notifications as per above.

 5. Release the mutex from step 1.

 6. Done.

 - Stalled threads acquire and release the mutex, exit the event
handler, and jump into the frame rewriter if their compilation
was invalidated.

Notes:

  - See any possibility of deadlocks? 3 could loop forever...

  - This has a only very slightly stronger requirements than those of a
copying GC.

--
 
Gordon Henriksen
IT Manager
ICLUBcentral Inc.
[EMAIL PROTECTED]




RE: Pondering argument passing

2003-09-15 Thread Gordon Henriksen
Dan Sugalski wrote:

 On Sun, 14 Sep 2003, Steve Fink wrote:
 
  I suppose that was a question for the language list. But then I'd
have
  to read the language list.
 
 A fate worse than razor burn, to be sure. Possibly one worse than
really 
 bad Mexican food, but either way I'd not wish it on anyone. :)

What's to read?

--
 
Gordon Henriksen
IT Manager
ICLUBcentral Inc.
[EMAIL PROTECTED]




Re: [RFT] File Spec

2003-09-14 Thread Gordon Henriksen
On Sunday, September 14, 2003, at 12:50 , Michael G Schwern wrote:

On Sat, Sep 13, 2003 at 09:55:48PM +0300, Vladimir Lipskiy wrote:

To be clearer:  concat_dirnames(b, /foo) == error.
As long as concat_dirnames() will be taught to divine whether its 
arguments
are absolute paths or relative paths, it could easily rotate its 
arguments
so the above-mentioned call would become concat_dirnames(/foo, b).
That would be really silly.
I must agree. The only reasonable results of that are either (a) an 
error [] or (b) /foo. (I'd go with [b].)



Gordon Henriksen
[EMAIL PROTECTED]


RE: [RfC] vtable-dump

2003-09-10 Thread Gordon Henriksen
Dan Sugalski [EMAIL PROTECTED] wrote:

 On Tue, 9 Sep 2003, Gordon Henriksen wrote:
 
  Random thought
  
  There's some discussion on perl-qa right now about how Test::More
  should implement is_deeply, which executes a code block and tests
  that the return value is equivalent to a particular nested data 
  structure. (The question posed on that list is with regard to how to
  handle tie()'d objects, which is not what I'm addressing here.)
  Result of that discussion's outcome, should the serialization API
  being discussed here enable the following behavior?
  
  ok(freeze($expected) eq freeze($actual));
  
  I bring this up because using object addresses as IDs in the
  serialization entirely prevents this usage.
 
 Good. Having waded through one of the threads on p5p just a minute
 ago, I'm not willing to guarantee this. In fact, I'm willing to 
 explicitly not guarantee this. If we want to compare two frozen
 structures, string equality is *not* the way to go.
 
 Each freeze could, theoretically, choose a different freezing method
 yet still represent the original.

What do you mean by a different freezing method? That key-value pairs
from two externally identical hashes could be frozen in different
orders? I can see that. Sorting large hashes can be expensive, and
certainly requires memory allocation.

Or do you mean that freeze($objA) and freeze($objB)--freezing
(definitionally identical!) object graphs and with no intervening code
between the two calls to freeze--could internally and arbitrarily select
a significantly divergent object graph encoding? I can't see that at
ALL...

Over time (and revisions), I certainly can see a desire not to marry
parrot-freeze to a specific binary representation. That's not the
question I intended to raise--I asked a question only of repeatability,
not of permanent format invariance.


 This is a Good Place for a black-box comparison op, which string
 equality definitely is not.

(At which point do extremely complex routines cease to be operators?)

A black-box comparison of the (live) object graphs, or black-box
comparison of the serializations themselves?

I can see the former--while it's precisely the problem that consistent
traversal outputs avoids, a deep == could have utility and avoid the
serialization overhead. But how do you implement concurrent traversals
without private seen tables? (e.g., if the graphs overlap, one of the
traversals will find the other traversal's visited flag and fail to
visit the entire graph.) Reentrant traversal again. Pathological case:

$aa = [1];
$ab = [1];
%ha = ( a = \$aa, b = \$ab );
%hb = ( a = \$ab, b = \$aa );
# %ha and %hb overlap and are deep-identical,
# but not deeply reference-identical.

Comparing serialized object graphs strikes me as tremendously esoteric,
e.g. a maintenance burden to be used by very few clients. (One of the
few significant uses being that of replacing string-equals for the
testing of the serializer itself.) It also strikes me as very, very,
very complicated should the freeze methods diverge even slightly. I've
never seen any such mechanism in any other environment. To compare
graphs that I had saved in long-term storage, I as a caller would expect
to need to deserialize the graphs and use a deep equals--and I would
expect to implement deep equals (another feature I've never before seen
as a specific feature of any environment) by serializing the
deserialized graphs again and doing a string (or file) comparison. E.g.,
if I had read $a or $b from a file, I would expect to have to:

freeze(thaw($a)) eq freeze(thaw($b))

instead of:

$a eq $b

That synthesizes the functionality from a minimal set of
operations--freeze and thaw--and with a lot less maintenance for parrot.
(At the cost of a bit of memory and runtime speed. But anybody who
performs deep-compares in truly performance-critical code needs to meet
my Clue Bat[tm].)

--
 
Gordon Henriksen
IT Manager
ICLUBcentral Inc.
[EMAIL PROTECTED]




  1   2   >