This question might seem wrong for this group but I'm thinking of
integrating Assembler into Smalltalk. As my experience with Assembler comes from a m68k background I'm used to the source/destination syntax (AT&T style) and not to the Intel style syntax (destination/source). On the other hand I assume most people today use MASM (either directly or through inline assembler). Which syntax do you prefer? Regards, Udo |
Oh!! Hat's Good and difficaul project for Smalltalk.
Personally, I prefer and comfortable with Intel sytle because I started Z80, the advanced over 8080. IMHO, [Destination/Source] is comfortable and understandable since almost programming language(inclue Smalltalk) accept assignment is right to left, not left to right. Udo, however, Smalltalk is pure-OOPL, so you should consider how embed assembler in Smalltalk. If you accomplish that, that is so greate way to spped up Smalltalk like in Delphi's inline assembler. Good luck! |
> Udo, however, Smalltalk is pure-OOPL, so you should consider how embed
> assembler in Smalltalk. If you accomplish that, that is so greate way > to spped up Smalltalk like in Delphi's inline assembler. The current plann is to provide something like ExternalLibraries with the difference that the actual methods do not call a function but instead execute some opcodes. This would allow me to develop small asm routines in smalltalk without the "exit DST, make asm change, assemble, start DST, test" cycle. Another idea is to provide an additional possibility to export all asm functions once the Library is complete and to make a stand alone dll out of it .... but that's just food for thought. Currently I'm getting crazy over this $!ยง&"$% x86 opcodes. CU, Udo ChanHong Kim wrote: > Oh!! Hat's Good and difficaul project for Smalltalk. > Personally, I prefer and comfortable with Intel sytle because I started > Z80, the advanced over 8080. > > IMHO, [Destination/Source] is comfortable and understandable since > almost programming language(inclue Smalltalk) accept assignment is > right to left, not left to right. > > Udo, however, Smalltalk is pure-OOPL, so you should consider how embed > assembler in Smalltalk. If you accomplish that, that is so greate way > to spped up Smalltalk like in Delphi's inline assembler. > > Good luck! > |
Udo,
> > Udo, however, Smalltalk is pure-OOPL, so you should consider how embed > > assembler in Smalltalk. If you accomplish that, that is so greate way > > to spped up Smalltalk like in Delphi's inline assembler. > The current plann is to provide something like ExternalLibraries with > the difference that the actual methods do not call a function but > instead execute some opcodes. > > This would allow me to develop small asm routines in smalltalk without > the "exit DST, make asm change, assemble, start DST, test" cycle. An external library like approach could be very different from "inline xyz" [*]. I say "inline xyz" vs. "inline asm" because I suspect that if you go to the trouble of inlining, then it makes sense to make it generic. To do that, I suspect one might need to enlist help from OA. A useful (I think??) start would be a framework for driving compilers. The result would be useful with mingw, nasm, InnoSetup, MIDL, etc., a further subclass of it handling the compilers that make callable functions. Running the compiler and reviewing its output is important. It would be ideal to have it able to run reasonably silently, perhaps signalling and error or simply entering an associated IDE if there are problems during the build. Another concept is binding to the functions. That could be done manually, by creating IDL and running MIDL and the TLA, etc. IIRC, Smalltalk/X does something like this??? Have a good one, Bill [*] Pardon me, INLine(TM) Visual(R) X#.Net ;) -- Wilhelm K. Schwab, Ph.D. [hidden email] |
Bill,
> An external library like approach could be very different from "inline > xyz" [*]. I say "inline xyz" vs. "inline asm" because I suspect that if > you go to the trouble of inlining, then it makes sense to make it > generic. To do that, I suspect one might need to enlist help from OA. Actually the concept of "inlining" turned out to be very simple. My current code emmits ExternalMethods whose address is not determined from DLL exports (using getProcAddress and friends) but is explicitly set. I decided to extend (wrap) the Smalltalk compiler to understand a special asm inline syntax. E.g. something like this: AsmLibrary asmAdd: add1 with: add2 _asm{' <stdcall: sdword integerAdd sdword sdword> mov eax, add1 add eax, add2'} ^self invalidCall Please notice that this approach uses a familiar external call definition and regular smalltalk code (if the "primitive" fails). The actual Smalltalk code given to the Smalltalk compiler becomes AsmLibrary asmAdd: add1 with: add2 <stdcall: sdword integerAdd sdword sdword> ^self invalidCall So the Smalltalk Compiler takes care of creating the ExternalMethod and call/return type conversions. As this method was never called yet the ExternalProcAddress is null. This is where the Assembler comes in. The code gets's compiled and it's address is set within the ExternalMethod. The actual assembler code assembled has a (dynamic) stub for variable definitions. So the code above becomes: equ add1 [ebp+8] equ add2 [ebp+12] push ebp mov ebp, esp ----- Start of user routine --- mov eax, add1 add eax, add2 ------ End of user routine --- pop ebp ret Volia! There is of course more going on behind the scenes. To Dos here are things like where to store the object code (references), refresh/clearing during Image Startup, runtim dependencies and so on. But all these things are more or less (more more than less :-) working in my workspace with preassembled code. The *big* thing missing is a "thingy" able to assemble mnenomics to object code .... That's where I'm stuck now. I thought about using an external assembler (either as DLL or via a command) .... but this introduces a lot of dependencies. So I've decided to write a minimalistic Assembler in Smalltalk. And to be honest I'm starting to *hate* x86 opcodes (this would be so easy on ARM :-( ). But that's my problem. Another idea I'm having is an "automagical" conversion into a stand alone DLL. If you are finished with all your AssemblerMethods I'm imagining a tool which emmits the DLL boilerplate code in asm and appends each inline asm method as asm proc (including export statements). This file sould then be assembled using a regular assembler generating a DLL. As the tool also knows the caller (Dolphin) side it should be possible to create an ExternalLibrary subclass automagically with complete and correct method definitions including external call statements. > A useful (I think??) start would be a framework for driving compilers. > The result would be useful with mingw, nasm, InnoSetup, MIDL, etc., a > further subclass of it handling the compilers that make callable functions. I agree that a more general approach would be desirable. However I decided to start "small" and to keep everything within the Smalltalk environment. I thought about this especially for resources. E.g. building a resoure dll using rc/link from within Dolphin with all resources needed for specific packages including some dolpin boilerplate code .... but that's just in my head at the moment :-( > Running the compiler and reviewing its output is important. It would be > ideal to have it able to run reasonably silently, perhaps signalling and > error or simply entering an associated IDE if there are problems during > the build. My first approach was to integrate an external compiler .... but I found that dependencies (configuration/path issues) are a problem. In addition external assemblers are *too* powerfull for inline assembly. I'll never want to produce a segemented 16 bit binary with it's own heap and other segments. The assembler I intended does nothing more than generating _32bit_ object code from mnenomics with alias (equ) and label handling. Everything else is too much. > Another concept is binding to the functions. That could be done > manually, by creating IDL and running MIDL and the TLA, etc. Maybe I got you wrong. I intend to keep everything within Dolphin. The possibilty to create a standalone DLL is just an Add-on. > IIRC, Smalltalk/X does something like this??? To be honest ... no idea. Maybe I'm totally wrong but AFAIK Smalltalk/X has something like "inline C". You could however use inline ASM within inline C .... not sure about that. CU, Udo PS: Please ignore the syntax (st and asm) .... it's just an example. |
In reply to this post by Schwab,Wilhelm K
Bill,
> An external library like approach could be very different from "inline > xyz" [*]. I say "inline xyz" vs. "inline asm" because I suspect that if > you go to the trouble of inlining, then it makes sense to make it > generic. To do that, I suspect one might need to enlist help from OA. I was typing to fast ..... I think I didn't get the sense of what you were saing. With my current approach all you need to inline "xyz" is a "thingy" which produces callable code from xyz code. Everything else is allready in place (thanks to OA) or can be easily added. Once you find out that you can easily set the proc address in ExternalMethods the world becomes yours :-) To implement an "xyz" inliner you'll have to create your own parser which seperates xyz from smalltalk code (this is where compilerClass and friend come in). The Smalltalk code gets compiles by the Smalltalk Compiler and becomes an ExternalMethod. Your xyz Compiler creates object code and sets the address in the ExternalMethod. At the moment I'm seeing on thing where I have to work around OAs implementation. During Image Startup all addresses of all external methods of all external libraries are set to null. If an external method is executed and the address is null than (that's my assumption) the VM does a getProcAddress to fill in the address. So it's not possible to catch this in ST and enter the objectcode address directly. Instead I choosed to hook up to the cleaning proccess and instead of setting the address to nul after Startup I'll set it to the actual address. Regards, udo |
In reply to this post by Udo Schneider
Udo Schneider wrote:
> The current plann is to provide something like ExternalLibraries with > the difference that the actual methods do not call a function but > instead execute some opcodes. This all sounds very interesting. I hope it goes well (despite the opcodes). One suggestion (I hope you don't mind suggestions) would be to expose the underlying assembler in a form that made it possible to create dynamic code too. Something like (assuming that ExternalValuable is a kind of <*adicValuable>, and based blindly on your own example): descriptor := ExternalDescriptor fromString: 'stdcall: sdword integerAdd sdword sdword'. asm := 'mov eax, add1; add eax, add2'. valuable := ExternalValuable asm: asm. descriptor: descriptor. to create a <triadicValuable> on-the-fly. -- chris |
Chris Uppal wrote:
> One suggestion (I hope you don't mind suggestions) would be to expose the > underlying assembler in a form that made it possible to create dynamic code > too. Something like (assuming that ExternalValuable is a kind of > <*adicValuable>, and based blindly on your own example): > > descriptor := ExternalDescriptor fromString: > 'stdcall: sdword integerAdd sdword sdword'. > asm := 'mov eax, add1; add eax, add2'. > valuable := ExternalValuable > asm: asm. > descriptor: descriptor. > > to create a <triadicValuable> on-the-fly. Excellent idea! Thanks for the feedback. I even got this working very quickly (if you ignore the object code generation ... that's still done by an external assembler). I saw that you specified the variables as add1 and add2. My first thought was "let's name them value1 and value2" .... but then this would be against the smalltalk style of naming. So the question I'm having is how to provide meaningfull names to ExternalValuable. Would something like this be allright for you? valuable := ExternalValuable asm: asm descriptor: descriptor variableNames: 'add1 add2' I even thought of a possible shortcut to use it more like regular blocks: valuable := ExternalValuable fromString: 'sdword sdword sdword | add1 add2 | mov eax, add1; add eax, add2'. Remeber that the var names are not neccessary. If you know the stack layout the call creates you could allways refer to your vars with something like [ebp+8] etc. On the other hand I do not think this would be very "smaltalkish". Please note note that you can ommit the calling convention and the proc name in this case. I also decided to only support stdcall: for the first version (So I don't have to care about stack cleaning within asm). Regards, Udo |
Udo Schneider wrote:
[skip] > So the question I'm having is how to provide meaningfull names to > ExternalValuable. Would something like this be allright for you? > > valuable := ExternalValuable asm: asm > descriptor: descriptor > variableNames: 'add1 add2' > [skip] > On the other hand I do not think this would be very "smaltalkish". > May be something like .net's System.Reflection.Emit.ILGenerator will be better? -- wbr, ps |
In reply to this post by Udo Schneider
Udo,
> I saw that you specified the variables as add1 and add2. My first > thought was "let's name them value1 and value2" .... but then this would > be against the smalltalk style of naming. Actually, I'd just copied that from your example without really thinking about it.... > So the question I'm having is how to provide meaningfull names to > ExternalValuable. Would something like this be allright for you? > > valuable := ExternalValuable asm: asm > descriptor: descriptor > variableNames: 'add1 add2' Why not make #variableNames: be optional, defaulting to something internally generated like $1, $2, ... (or arg1, arg2, ... if you prefer). > I even thought of a possible shortcut to use it more like regular blocks: > > valuable := ExternalValuable fromString: 'sdword sdword sdword | add1 > add2 | mov eax, add1; add eax, add2'. Perhaps that would be a bit misleading; to me it makes add1 and add2 look like locals rather than parameters. I think I'd just stick with something that was easy to parse, and not /too/ difficult to use. The interesting and difficult bit about using this stuff will be thinking out the assembler code itself. I don't think that shortcuts for creating them will actually make much (incremental) difference. The job of typing the expression in won't be the bottleneck, if you see what I mean, so there's not a lot to gain by optimising it. > Please note note that you can ommit the calling convention and the proc > name in this case. I also decided to only support stdcall: for the first > version (So I don't have to care about stack cleaning within asm). Very reasonable. The point of having both stdcall and cdecl is to be able to interface to externally defined APIs, but a block-like construction is obviously intended for internal use, and so has no need of the distinction. But, OTOH, it would be nice (as a /further/ enhancement if you happen to feel like it) to be able to create something like an ExternalCallback that could be passed to an external API as a "function pointer" (although creating a BlockCallback that invoked a BlockClosure which in turn invoked the ExternalValuable would serve as a substitute -- albeit somewhat indirect ;-) -- chris PS, and /completely/ off-topic: Udo, I noticed a small bug in one of your Treemap layout strategies some time ago which I've been meaning to tell you about, but never got around to :-( To reproduce (unless you've already fixed it) try: tm := (TreeModel new) add: 0 asChildOf: nil; add: 10516 asChildOf: 0; add: 2267 asChildOf: 0; add: 71581 asChildOf: 0; yourself. p := TreePresenter show: 'Treemap view'. p view renderer nodeSizeBlock: [:each | each]; layoutStrategy: OrderedSquarifiedTreeMapStrategy new. p model: tm. Which causes OrderedSquarifiedTreeMapStrategy>>layout:in: to go into an infinite loop (which can easily be broken out of). -- c |
Free forum by Nabble | Edit this page |