Re: Next Apocalypse

2003-09-16 Thread Jonathan Scott Duff
On Mon, Sep 15, 2003 at 03:30:06PM -0600, Luke Palmer wrote:
 The focus here, I think, is the following problem class:
 
 sub twenty_five() { 25 }# Optimized to inline
 sub foo() {
 print twenty_five;  # Inlined
 twenty_five := { 36 };
 print twenty_five;  # Uh oh, inlined from before
 }
 
 The problem is we need to somehow un-optimize while we're running.  That
 is most likely a very very hard thing to do, so another solution is
 probably needed.

A naive approach would be to cache the names and positions of things
that are optimized such that when one of the cached things are
modified, the optimization could be replaced with either another
optimization (as in the case above) or an instruction to execute some
other code (when we can't optimize the change).

-Scott
-- 
Jonathan Scott Duff
[EMAIL PROTECTED]


Re: Next Apocalypse

2003-09-16 Thread Dan Sugalski
On Tue, 16 Sep 2003 [EMAIL PROTECTED] wrote:

 On Mon, 15 Sep 2003, Dan Sugalski wrote:
   Great. But will it also be possible to add methods (or modify them)
   to an existing class at runtime?
 
  Unless the class has been explicitly closed, yes.
 
 That strikes me as back-to-front.
 
 The easy-to-optimise case should be the easy-to-type case; otherwise a lot
 of optimisation that should be possible isn't because the programmers are
 too inexperienced/lazy/confused to put the closed tags in.

It would, in fact, be back-to-front if performance was the primary 
goal. And, while it is *a* goal, it is not *the* goal.

From Parrot's standpoint, it doesn't make much difference--once you start 
spitting out assembly you can be expected to be explicit, so it's a matter 
of what the language designer wants. While Larry's the ultimate arbiter, 
and I am *not* Larry, generally he favors flexibility over speed as the 
default, especially when you can get it at the current speed (that is, 
perl 5's speed) or faster. You don't lose anything over what you have now 
with that flexibility enabled, and if you want to restrict yourself for 
the extra boost, you can explicitly do that.

Then again, he may also decide that things are open until the end of 
primary compilation, at which point things are closed--you never know... 
:)

Dan



Re: Next Apocalypse

2003-09-16 Thread Robin Berjon
My, is this a conspiracy to drag -internals onto -language to make it look alive? :)

You guys almost made me drop my coffee mug...

--
Robin Berjon [EMAIL PROTECTED]
Research Scientist, Expway  http://expway.com/
7FC0 6F5F D864 EFB8 08CE  8E74 58E6 D5DB 4889 2488


Re: This week's summary

2003-09-16 Thread Leopold Toetsch
Piers Cawley [EMAIL PROTECTED] wrote:
 ... spending the morning of your 36th birthday

Happy birthday to you and us.
l - A full year has passed, hasn't it? - eo


Re: Next Apocalypse

2003-09-16 Thread Dan Sugalski
On Tue, 16 Sep 2003, Ph. Marek wrote:

  You can, of course, stop even potential optimization once the first I can
  change the rules operation is found, but since even assignment can change
  the rules that's where we are right now. We'd like to get better by
  optimizing based on what we can see at compile time, but that's a very,
  very difficult thing to do.

 How about retaining some debug info, (line number come to mind), but only at 
 expression level??

This is insufficient, since many (potentially most) optimizations result 
in reordered, refactored, moved, and/or mangled code that doesn't have a 
line-for-line, or expression-for-expression, correspondence to the 
original. If it did, this would all be much easier.

The alternative, of course, is to not apply those transforms, but then 
you're left with pretty much no optimizations.

Dan



Re: Next Apocalypse

2003-09-16 Thread David Storrs
On Mon, Sep 15, 2003 at 11:49:52AM -0400, Gordon Henriksen wrote:
 Austin Hastings wrote:
 
  Given that threads are present, and given the continuation based
  nature of the interpreter, I assume that code blocks can be closured.
  So why not allocate JITed methods on the heap and manage them as first
  class closures, so that the stackref will hold them until the stack
  exits?
 
 
 Austin,
 
 That's a fine and dandy way to do some things, like progressive
 optimization ala HotSpot. (e.g., Oh! I've been called 10,000 times.
 Maybe you should bother to run a peephole analyzer over me?) But when
 an assumption made by the already-executing routine is actually
 violated, it causes incorrect behavior. Here's an example:
 
 class My::PluginBase;
 
 method say_hi() {
 # Default implementation.
 print Hello, world.\n;
 }
 
 
 package main;
 
 load_plugin($filepath) { ... }
 
 my $plugin is My::PluginBase;
 $plugin = load_plugin($ARGV[0]);
 $plugin.SayHi();
 
 Now, while it would obviously seem a bad idea to you, it would be
 reasonable for perl to initially optimize the method call
 $plugin.say_hi() to the function call My::PluginBase::say_hi($plugin).
 But when load_plugin loads a subclass of My::PluginBase from the file
 specified in $ARGV[0], then that assumption is violated. Now, the
 optimization has to be backed out, or the program will never call the
 subclass's say_hi. Letting the GC clean up the old version of main when
 the notification is received isn't enough--the existing stack frame must
 actually be rewritten to use the newly-compiled version.


This discussion seems to contain two separate problems, and I'm not
always sure which one is being addressed.  The components I see are:

1) Detecting when the assumptions have been violated and the code has
   to be changed; and,

2) Actually making the change after we know that we need to.


I have at least a vague idea of why #1 would be difficult.  As to
#2...assuming that the original source is available (or can be
recovered), then regenerating the expression does not seem difficult.
Or am I missing something?


--Dks


RE: Next Apocalypse

2003-09-16 Thread Gordon Henriksen
David Storrs wrote:

 This discussion seems to contain two separate problems, and I'm not
 always sure which one is being addressed.  The components I see are:
 
 1) Detecting when the assumptions have been violated and the code has
to be changed; and,
 
 2) Actually making the change after we know that we need to.
 
 
 I have at least a vague idea of why #1 would be difficult.  As to
 #2...assuming that the original source is available (or can be
 recovered), then regenerating the expression does not seem difficult.
 Or am I missing something?

David,

Recompiling isn't hard (assuming that compiling is already implemented).
Nor is notification of changes truly very difficult.

What you're missing is what I was trying to demonstrate with my plugin
example, and what Dan also pointed out with his mutating a subroutine
that returns a constant (and was presumably inlined). If the routine is
RUNNING at the time an assumption made by the optimizer becomes invalid,
then the stack frame needs to be munged from the old, optimized version
compilation to the new, pessimized version. THAT is the hard
problem--one of register  variable remapping and PC mutation--and it is
impossible to solve after code motion optimizations, for the same reason
that C++ debuggers get horribly confused when running over -O3 code.

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




RE: Next Apocalypse

2003-09-16 Thread Austin Hastings

--- Gordon Henriksen [EMAIL PROTECTED] wrote:
 David Storrs wrote:
 
  This discussion seems to contain two separate problems, and I'm not
  always sure which one is being addressed.  The components I see
 are:
  
  1) Detecting when the assumptions have been violated and the code
 has
 to be changed; and,
  
  2) Actually making the change after we know that we need to.
  
  
  I have at least a vague idea of why #1 would be difficult.  As to
  #2...assuming that the original source is available (or can be
  recovered), then regenerating the expression does not seem
 difficult.
  Or am I missing something?
 
 David,
 
 Recompiling isn't hard (assuming that compiling is already
 implemented).
 Nor is notification of changes truly very difficult.
 

Let's try again:

 1: sub othersub {...}
 2:
 3: sub foo {
 4:   my $a = 13;
 5:   my $b = 12;
 6: 
 7:othersub;
 8:my $c = $a + $b;
 9: 
10:print $c;
11: }
12:
13: eval sub othersub { ::infix+ := ::infix-; };
14: foo;

In theory, we should get Object(1) as a result.

So let's compile that:

4: temp_a = 13;
5: temp_b = 12;
7: call othersub
8: push temp_b
8: push temp_a
8: call ::infix+
9: call print

Now let's optimize it:

; temp_a, temp_b are MY, so suppress them.
7:  call othersub
 ; We do CSE at compile time
 ; We don't use C after the print, so drop it
9:  push 25
9:  call print

So when we execute othersub, and notice that the world has shifted
beneath our feet, what do we do?

We don't even have the right registers laying about. There are no a
and b values to pass to the operator+ routine. (An advantage,
actually: losing an intermediate value would be a worse scenario.)

Two possibilities:

1- Some classes of optimization could be forced to occupy a certain
minimum size. The act of breaking the optimization assumptions could
replace the optimization (e.g., CSE) with a thunk.

  Example:
cse: push 25
 call print

  Becomes:
cse: push 25
 branch $+3
 nop
 nop
 call print

  So that we could replace it with:
cse: call undo_cse
 call print

  Where presumably undo_cse performed the operations in source code
order. (What's more, it would make perl binaries *very* compressible
:-)

2- In the living dangerously category, go with my original
suggestion: GC the compiled code blocks, and just keep executing what
you've got until you leave the block. Arguably, sequence points could
be used here to partition the blocks into smaller elements.

This tends to make event loops act really stupid, but ...

=Austin



Re: This week's summary

2003-09-16 Thread Piers Cawley
Leopold Toetsch [EMAIL PROTECTED] writes:

 Piers Cawley [EMAIL PROTECTED] wrote:
 ... spending the morning of your 36th birthday

 Happy birthday to you and us.

Thanks.