[LLVMdev] Dynamic updates of current executed code

Anders Alexandersson anders.alexandersson at student.htu.se
Tue Apr 20 03:51:11 PDT 2004


Thanks!

Problem is though, that the Ruby compiler is integrated in the compilation of the program being executed, to be able to parse & compile dynamic code at run-time. Therefore the calls to ExecutionEngine::getPointerToGlobal(F) need to be made in LLVM code. Here is a detailed simplistic example in pseudocode of what we want to do:

First Ruby code is entered at run-time, received as a string, parsed and compiled into the following code:

%-----------------------------------------------------
; External function
declare int %printf(sbyte*, ...)

; Custom function
int %puts_kernel( sbyte* %string )
{
        %tmp.0 = call int (sbyte*, ...)* %printf( sbyte* %string )
        ret int 0
}
%-----------------------------------------------------
 
This code is represented in the string variable 
%dynamically_compiled_function_code below:

%-----------------------------------------------------
%dynamically_compiled_function_code  = internal constant [LENGTH x sbyte] c"--String with the function code--\0A\00"

; Table of function pointer(s)
%kernel  = type {  int ( sbyte* )*  }


int %main() {

        ; Create the kernel in memory, and get pointer to first function pointer
        %theKernel = malloc %kernel
        %FirstFunctionPTR = getelementptr %kernel* %theKernel, long 0, ubyte 0
        ;Load code
        %myNewFunction = %getPointerToGlobal(%dynamically_compiled_function_code)

        ; Write memory address of myNewFunction() into kernel struct
        store RETURNTYPE (PARAMTYPE*)* %myNewFunction, RETURNTYPE (PARAMTYPE*)** %FirstFunctionPTR

        ;Any code using first function element in %kernel is now_
        ;using dynamically updated function!?

        ret int 0
}

%-----------------------------------------------------

The questionmark is at this pseudocode row:
%myNewFunction = %getPointerToGlobal(%dynamically_compiled_function_code)

Is there an llvm version of the getPointerToGlobal() function as outlined, and can the %myNewFunction pointer be used as described? 
Also, does the getPointerToGlobal() take human readable code (.ll) or only binary byte code (.bc)? Is there a specification of how to write binary byte code directly, so we do not have to externally call the llvm-as utility?

Best regards
Anders


-----Original Message-----
From: Chris Lattner <sabre at nondot.org>
To: llvmdev at cs.uiuc.edu
Date: Mon, 19 Apr 2004 01:56:12 -0500 (CDT)
Subject: Re: [LLVMdev] Dynamic updates of current executed code

On Mon, 19 Apr 2004, Anders Alexandersson wrote:

> Hello!
>
> I saw that you just got the recent llvm paper published in IEEE!
> Congratulations! :-)

Thanks!

> More issues regarding the Ruby compiler:
>
> Ruby supports the possibility of the user to enter new Ruby code during
> execution, after which it is executed. Also, all classes are open,
> meaning that a user is able to redefine a class overriding or replacing
> methods therein at run-time (this is deep...).

Sure, many dynamic languages are like this...

> My question is how the llvm-jitter works on a low level. Say for example
> that a user redefines a method during execution. My compiler (in llvm
> code form) takes care of compiling that code into llvm code dynamically.

Okay, at the low-level, your class will have a hash-table or vtable or
something that represents the methods in the class.  This vtable or hash
table is a global LLVM variable.  In the case of our C++ front-end, each
object with a virtual method has a pointer to a class descriptor global,
and the class descriptor global has a pointer to the vtable for the class.

> Now, how do the mechanisms work that loads new llvm code and lets it
> co-exist with the code already running? In this case I want to update a
> function pointer in the struct in the already running code representing
> the changed class, to point to the newly compiled code representing the
> newly entered method instead.

In this case, just don't mark the ruby vtables/hash-tables as "constant",
and update the pointers in the global at runtime.  All code will
automatically start executing the new method that you defined.

> Is this functionality at all accessible by an executing llvm program?

Sure.  There are multiple ways of doing this.  First, you want to codegen
the new method that was added, by creating an LLVM function for it and
adding it to the current module being run.  You then call
ExecutionEngine::getPointerToGlobal(F), passing in the LLVM Function
object that you compiled.  This will cause the function to be code
generated and give you a pointer to it.

Next, ask the execution engine for a pointer to the vtable or whatever you
are using for method dispatch, using the same method.  Once you have the
pointer to the global in memory, and a pointer to the function you want to
stick into it, go ahead and do it.  :)

The other option for *replacing* a method that has already been code
generated is to use the ExecutionEngine::recompileAndRelinkFunction
method, which tells the JIT to discard the previously compiled version of
an LLVM function and recompile it from scratch.

A lot of the details depend intrinsically on how you are representing Ruby
objects and method dispatch in general.  That said, all of the needed LLVM
functionality should be in place.

Feel free to ask if you have any other questions.  :)

-Chris

-- 
http://llvm.cs.uiuc.edu/
http://www.nondot.org/~sabre/Projects/

_______________________________________________
LLVM Developers mailing list
LLVMdev at cs.uiuc.edu         http://llvm.cs.uiuc.edu
http://mail.cs.uiuc.edu/mailman/listinfo/llvmdev



----------------------------------------------------------------
Anders Alexandersson
Masters student at the special year of Software Engineering, HTU Trollhättan
E-mail: anders.alexandersson at student.htu.se




More information about the llvm-dev mailing list