Re: [perl #20315] [PATCH] eval - inter code segment branches
Jason Gloudon wrote: On Tue, Jan 21, 2003 at 08:21:42PM +0100, Leopold Toetsch wrote: # #!/usr/bin/perl -w # my $i= 5; # LAB: #$i++; #eval(goto LAB if ($i==6)); Ok. Having inter_cs call DO_OP just seems more involved than it has to be. Yep. How about a single self-contained inter-segment jump instruction. Since the compiler knows when a branch is non-local it can always break a non-local conditional branch into a conditional local branch to a non-local branch instruction. This would mean to rewrite the branch target to point to a location after the end of the current sub (or end of program). if i, non_local1 would become if i, taken1 ... end/ret # whatever taken1: inter_cs_jump non_local1 ... Yep. Seems really much simpler. I'll try this approach. Thanks for your input, leo
Re: [perl #20315] [PATCH] eval - inter code segment branches
On Tue, Jan 21, 2003 at 12:08:29AM +0100, Leopold Toetsch wrote: Here is a proposal for inter code segment jumps: The assembler (imcc) can recognize when a branch ins goes to a different code segment. For such a branch, imcc generates this opcode seqence: inter_cs if i, ic # or whatever Why do we need branches to go to different code segments ? I think the expectation has been that control transfers between segments would have their own op, because separate code segments would generally coincide with subs, closures or at least blocks, that have specific entry points. Maybe Dan could give us a hint about the closure/block/byte code segment relationship. -- Jason
Re: [perl #20315] [PATCH] eval - inter code segment branches
Jason Gloudon wrote: On Tue, Jan 21, 2003 at 12:08:29AM +0100, Leopold Toetsch wrote: Here is a proposal for inter code segment jumps: The assembler (imcc) can recognize when a branch ins goes to a different code segment. For such a branch, imcc generates this opcode seqence: inter_cs if i, ic # or whatever Why do we need branches to go to different code segments ? Because of this nasty piece of little code: t/syn/eval_3.imc: # #!/usr/bin/perl -w # my $i= 5; # LAB: #$i++; #eval(goto LAB if ($i==6)); #print $i\n; # # 7 # .sub _test I1 = 5 $S0 = .sub _e\nif I1 == 6 goto LAB\nend\n.end\n compreg P2, PIR compile P0, P2, $S0 LAB: inc I1 invoke print I1 print \n end .end ... I think the expectation has been that control transfers between segments would have their own op, because separate code segments would generally coincide with subs, closures or at least blocks, that have specific entry points. The problem is, that the invoke calls a different code segment, which eventually branches back. Parsing the eval code into the same code segment in not possible, we can't expand code segments, or let's say not easily, except (if even possible) with invalidating prederef and JIT code, and restarting. This is IMHO too expensive to go that road. The proposed inter_cs op is such a special op, but suitable for all branches. E.g. inter_cs ; bsr _somewhere Maybe Dan could give us a hint about the closure/block/byte code segment relationship. I just can tell you from imcc's POV. Everything compiled in one sequence (e.g. all subs of all files) could be one code segment. As soon as you start running the code, and you want to compile again, produced bytecode has to go into a different code segment. Of course, it could be more fine grained, but not less. leo
Re: [perl #20315] [PATCH] eval - inter code segment branches
On Tue, Jan 21, 2003 at 08:21:42PM +0100, Leopold Toetsch wrote: For such a branch, imcc generates this opcode seqence: inter_cs if i, ic # or whatever Why do we need branches to go to different code segments ? Because of this nasty piece of little code: t/syn/eval_3.imc: # #!/usr/bin/perl -w # my $i= 5; # LAB: #$i++; #eval(goto LAB if ($i==6)); Ok. Having inter_cs call DO_OP just seems more involved than it has to be. How about a single self-contained inter-segment jump instruction. Since the compiler knows when a branch is non-local it can always break a non-local conditional branch into a conditional local branch to a non-local branch instruction. For example if i, nonlocal ... not taken can be expressed as if i, TAKEN ... not taken ... TAKEN: inter_jump nonlocal -- Jason
Re: [perl #20315] [PATCH] eval - inter code segment branches
Leopold Toetsch wrote: I have it ready. It's based on the packfile patch #18056 by Juergen Boemmels. On top of this patch, it was quite easy to implement multiple code segments. And yet another f'up me. Here is a proposal for inter code segment jumps: The assembler (imcc) can recognize when a branch ins goes to a different code segment. For such a branch, imcc generates this opcode seqence: inter_cs if i, ic # or whatever The branch location ic is the index[1] into the fixuptable, which contains codesegment/offset pairs. The inter_cs instruction looks like: opcode_t *cur = cur_opcode; /* remember current */ // = CUR_OPCODE opcode_t *pc; DO_OP(pc, interpreter); /* pc is new pc now */ if (pc_is_outof_bounds) { /* branch taken */ index = (pc-code_start)/(sizeof opcode_t) ~0x8000; interp-resume_code_seg = fixup_table[index].code_seg; interp-resume_offset = fixup_table[index].offs; //= restart OFFSET(x) return 0; /* do a resume in new cs */ } cur_opcode = pc; /* branch not taken */ // = goto ADDRESS(pc); [1] the branch offsets are with the hight bit set, to allow recognition of out_of_bounds. Some help to translate this to OpsFile macros as well as of course always comments are welcome, leo
Re: [perl #20315] [PATCH] eval
Leopold Toetsch wrote: I have it ready. - code is ready for debug information, I'll first do it in imcc, which could generate file/line info on the fly. Next would then be to extend the PBC format. And this is working too in imcc, including gdb-stepping into evaled code segments. Does anyone want to have a look at the patch, or should I put it in? Tomorrow is dead time, I really don't like to have 30 files different to CVS :) leo me2
Re: [perl #20315] [PATCH] eval
Leopold Toetsch wrote: So it seems, that for multiple code segments, we'll have to take the PackFile_ConstTable out of the structure and include file/line/debug/whatever information. This would look like: packfile aka interpreter-code: - constants - code_segment[] - byte_code - byte_code_size - [ more of current packfile ] - filename - lines[] - [ more aditional stuff ] - prederefed_code - jit_info (jitted code) - fixups The debug stuff should have its own segment, linked to the corresponding code segment. The return value of Bcompile would then be a pointer to such a code_segment. BTW a PackFile_Constant should be a union IMHO, currently each type has its own storage. As a first step towards multiple code segments I did apply locally Juergen Boemmels Patch #18056. With little rediffing and twigging, this runs all tests, imcc's packout() for writing pbc files is working too. Only packdump is broken, but this didn't do very much anyway. So people please have a look at this patch and the description. With this patch in place, it shouldn't be too hard, to have multiple code segments, currently only in memory and with extending the PBC file also external. leo
Re: [perl #20315] [PATCH] eval
Leopold Toetsch (via RT) wrote: # New Ticket Created by Leopold Toetsch # Please include the string: [perl #20315] # in the subject line of all future correspondence about this issue. # URL: http://rt.perl.org/rt2/Ticket/Display.html?id=20315 Attached is a first try towards eval. I have now eval/compile also running inside imcc. There are two registered compregs: PASM and PIR aka .imc, e.g. set S0, 'set S1, 42\n' concat S0, \n concat S0, print S1\nend\n compile P1, S0, PASM print \n end I still would like to have some design advice. 1) The call function to the compiler/assembler is kept as a NCI. Better would be a subclass of NCI (Compiler.pmc or so), which provides invoke_keyed(key, next) This would look up the compreg key and prepare the registers for calling the compiler function. I think such a vtable method would also be handy for the OO stuff: callmethod P1, foo which would translate too a invoke_keyed() on the object. For methods known at compile time, the HL could spit out callmethod P1, n which would then be invoke_keyed_int(). 2) The return value of the compile ops should be a pointer to a bytecode segment, already in the interpreter and ready for calling. So how should a code_segment_PMC look like and how should the structure in the packfile be defined? Just an array of code pointers containing byte_code and byte_code_size? The code_segment_PMC would probably be a [subclass of]? Sub.pmc, which can then be invoked for actually evalling the code. Comments welcome, leo
Re: [perl #20315] [PATCH] eval
Leopold Toetsch wrote: 1) The call function to the compiler/assembler is kept as a NCI. Better would be a subclass of NCI (Compiler.pmc or so), which provides invoke_keyed(key, next) Hmm, I don't know what a NCI is. Where (which files) can I find information about them? Jerome -- [EMAIL PROTECTED]
Re: [perl #20315] [PATCH] eval
At 8:27 PM + 1/14/03, Leopold Toetsch (via RT) wrote: # New Ticket Created by Leopold Toetsch # Please include the string: [perl #20315] # in the subject line of all future correspondence about this issue. # URL: http://rt.perl.org/rt2/Ticket/Display.html?id=20315 Attached is a first try towards eval. - interpreter has a new data member Parrot_compreg_hash - parrot registers the PASM1 type i.e. what PDB_eval can parse - the new Bcompile opcode (ab)uses nci to build a function for calling PDB_eval - nci is extended (jit/i386 only), to understand an 'I' param as interpreter - the string is evaled immediately, we don't have multiple byte code segments yet No registers, which nci uses, are preserved, no error checking and so on, but works ;-) Yow, Cool! We *have* to get IMCC built into parrot now. Some questions arise here: - Should the Bcompreg opcode also have a form with a label to build PASM compilers, ook? I think you've confused me here. (No, I'm wrong--you've definitely confused me here) More explanation? - is using the NCI interface ok for evals purpose? Sure. We can rejig it later if we need to, but I expect most compilers will involve a trip into C code, so that's fine. - how should a byte code segment (PMC) look like? Ah, the big question. I'm not quite sure yet--let's try and work that out while I'm churning over objects. -- Dan --it's like this--- Dan Sugalski even samurai [EMAIL PROTECTED] have teddy bears and even teddy bears get drunk
Re: [perl #20315] [PATCH] eval
In perl.perl6.internals, you wrote: Leopold Toetsch wrote: 1) The call function to the compiler/assembler is kept as a NCI. Better would be a subclass of NCI (Compiler.pmc or so), which provides invoke_keyed(key, next) Hmm, I don't know what a NCI is. Where (which files) can I find information about them? Native Call Interface. s. nci.c, build_nativecall.pl, classes/nci.pmc, the docs and Dan's announcement on the list. Jerome HTH leo
Re: [perl #20315] [PATCH] eval
Dan Sugalski wrote: At 8:27 PM + 1/14/03, Leopold Toetsch (via RT) wrote: Yow, Cool! We *have* to get IMCC built into parrot now. You do get this wrong - always ;-) imcc = parrot + assemble.pl - pre-processor + PIR-assembler + optimizer/10#yet now already With the help of assemble.pl -E (preprocess only, spitting out PASM) imcc runs *all* parrot tests. - Should the Bcompreg opcode also have a form with a label to build PASM compilers, ook? I think you've confused me here. (No, I'm wrong--you've definitely confused me here) More explanation? I was thinking of assembler/compilers implemented in PASM, as languages/ook/ook.pasm is a ook compiler. It could register a compreg with type Ook, which uses the registered PASM compiler to run ook code ;-) - is using the NCI interface ok for evals purpose? Sure. We can rejig it later if we need to, but I expect most compilers will involve a trip into C code, so that's fine. Ok, then this needs some twigging. I did use signature 'I' for pushing a Parrot_Interp. The return value needs still work. - how should a byte code segment (PMC) look like? Ah, the big question. I'm not quite sure yet--let's try and work that out while I'm churning over objects. I did have a closer look at struct PackFile. I think we have some possiblities to actually eval()/invoke() the code, depending on the HL: - new interpreter, nothing shared (unlikely) - new interpreter, context shared - meaning also constants - same interpreter, everything shared So it seems, that for multiple code segments, we'll have to take the PackFile_ConstTable out of the structure and include file/line/debug/whatever information. This would look like: packfile aka interpreter-code: - constants - code_segment[] - byte_code - byte_code_size - [ more of current packfile ] - filename - lines[] - [ more aditional stuff ] - prederefed_code - jit_info (jitted code) - fixups The return value of Bcompile would then be a pointer to such a code_segment. BTW a PackFile_Constant should be a union IMHO, currently each type has its own storage. leo
[perl #20315] [PATCH] eval
# New Ticket Created by Leopold Toetsch # Please include the string: [perl #20315] # in the subject line of all future correspondence about this issue. # URL: http://rt.perl.org/rt2/Ticket/Display.html?id=20315 Attached is a first try towards eval. - interpreter has a new data member Parrot_compreg_hash - parrot registers the PASM1 type i.e. what PDB_eval can parse - the new Bcompile opcode (ab)uses nci to build a function for calling PDB_eval - nci is extended (jit/i386 only), to understand an 'I' param as interpreter - the string is evaled immediately, we don't have multiple byte code segments yet No registers, which nci uses, are preserved, no error checking and so on, but works ;-) Some questions arise here: - Should the Bcompreg opcode also have a form with a label to build PASM compilers, ook? - is using the NCI interface ok for evals purpose? - how should a byte code segment (PMC) look like? Comment welcome leo -- attachment 1 -- url: http://rt.perl.org/rt2/attach/48556/37739/ade5a5/eval.patch --- parrot/classes/csub.pmc Fri Jan 10 18:05:02 2003 +++ parrot-leo/classes/csub.pmc Tue Jan 14 19:06:24 2003 @@ -49,7 +49,7 @@ return SELF-cache.struct_val != NULL; } -void * invoke (void * next) { +void* invoke (void * next) { Parrot_csub_t func = (Parrot_csub_t)SELF-cache.struct_val; func(INTERP, SELF); return next; --- parrot/core.ops Tue Jan 14 09:09:55 2003 +++ parrot-leo/core.ops Tue Jan 14 19:25:19 2003 @@ -4485,6 +4485,10 @@ Call the subroutine in P0, as described in PDD03. +=item Bcompile(out PMC, in STR, in STR) + +Compile source code $2 of a registered source type $3 into PMC $1. + =cut inline op loadext(in STR, in STR) { @@ -4547,6 +4551,19 @@ goto ADDRESS(dest); } + +inline op compile(OUT PMC, in STR, in STR) { + opcode_t *dest; + PMC *key = key_new_string(interpreter, $3); + PMC *func = interpreter-Parrot_compreg_hash-vtable-get_pmc_keyed( +interpreter, interpreter-Parrot_compreg_hash, key); + /* XXX undef */ + interpreter-ctx.string_reg.registers[5] = $2; /* XXX */ + dest = (opcode_t *)func-vtable-invoke(interpreter, func, expr NEXT()); + /* XXX retval */ + goto ADDRESS(dest); +} + =item Bfind_method(out PMC, in PMC, in STR) --- parrot/dod.cTue Jan 14 09:09:55 2003 +++ parrot-leo/dod.cTue Jan 14 18:51:15 2003 @@ -104,6 +104,8 @@ /* mark it as used */ pobject_lives(interpreter, (PObj *)current); +if (interpreter-Parrot_compreg_hash) +pobject_lives(interpreter, (PObj *)interpreter-Parrot_compreg_hash); /* Now, go run through the PMC registers and mark them as live */ /* First mark the current set. */ for (i = 0; i NUM_REGISTERS; i++) { --- parrot/include/parrot/interpreter.h Sat Jan 4 12:35:22 2003 +++ parrot-leo/include/parrot/interpreter.h Tue Jan 14 18:13:08 2003 @@ -169,6 +169,7 @@ INTVAL world_inited;/* Parrot_init is done */ PMC *mark_ptr; /* last PMC marked used in DOD runs */ PMC *Parrot_base_classname_hash;/* hash containing name-base_type */ +PMC *Parrot_compreg_hash; /* hash containing assembler/compilers */ } Interp; #define PCONST(i) PF_CONST(interpreter-code, (i)) @@ -189,6 +190,7 @@ VAR_SCOPE opcode_t *(*run_native)(struct Parrot_Interp * interpreter, opcode_t * cur_opcode, opcode_t * start_code); +void Parrot_compreg(Parrot_Interp interpreter, STRING *type, PMC *func); #endif /* Parrot core */ --- parrot/interpreter.cSat Jan 11 09:39:08 2003 +++ parrot-leo/interpreter.cTue Jan 14 19:21:00 2003 @@ -21,11 +21,13 @@ #ifdef HAVE_COMPUTED_GOTO # include parrot/oplib/core_ops_cg.h #endif +#include parrot/method_util.h #define ATEXIT_DESTROY extern op_lib_t *PARROT_CORE_PREDEREF_OPLIB_INIT(void); +static void setup_default_compreg(Parrot_Interp interpreter); /*=for api interpreter runops_generic * TODO: Not really part of the API, but here's the docs. @@ -512,6 +514,10 @@ SET_NULL_P(interpreter-prederef_code, void **); SET_NULL(interpreter-jit_info); +SET_NULL_P(interpreter-Parrot_compreg_hash, PMC *); +/* register assembler/compilers */ +setup_default_compreg(interpreter); + /* Done. Return and be done with it */ /* Okay, we've finished doing anything that might trigger GC. @@ -686,6 +692,42 @@ } return ret; } + +/*=for api interpreter Parrot_compreg + * register a parser/compiler function + */ + +void Parrot_compreg(Parrot_Interp interpreter, STRING *type, PMC *func) +{ +PMC* key, *hash; +if (!interpreter-Parrot_compreg_hash) { +hash = interpreter-Parrot_compreg_hash = +pmc_new_noinit(interpreter, enum_class_PerlHash); +hash-vtable-init(interpreter, hash); +} +key = key_new_string(interpreter, type); +