There have been quite a few discussions on howto dispatch messages
on this board. However I have never seen anyone talk about the one
found in the 'generic.asm' file wich comes with the masm32 pack.
This seems pretty good to me. Anyone know of any disadvantages/
advantages. From other methods like the one seen in Hutch's
'High speed message dispatcher '?

I cant see why this would be any slower then other attempts ive seen.

Example code:
[color=sienna]

;===== SmartJump
;SmartJump is a substitute for the block structure
;switch/case/select and if/elseif/endif.
;Immediately after each "call SmartJump" comes a jump table, in a
;format that you can readily figure out.
...
SmartJump: pop edx;[/@-"Return address" actually points at a jump table.
@@: cmp dword ptr cs:[edx],-1
je @F
cmp eax,cs:[edx]
je @F
add edx,8
jmp @B
@@: jmp near ptr cs:[edx+4]

WndProc proc hWin:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD
mov eax,uMsg
call SmartJump
dd WM_COMMAND,HandleCommand
dd -1,DoDefWindowProc

HandleCommand:
movzx eax,word ptr wParam
call SmartJump
dd ID_New,HandleNew
dd -1,Done0

Done: xor eax,eax
ret

HandleNew:
jmp Done0

DoDefWindowProc:
pop ebp
jmp DefWindowProc
...
[/color]
Posted on 2002-12-16 21:52:00 by natas
Maybe everyone else is using the optimized SWITCH-CASE macros that were posted here some time ago.

--- You may want to search for switch or case topics.

The primary advantage is the ease of editting it. Note: Check out how a C compiler handles switch statements when there are a lot of unused slots in its case list.

* It is much easier to rearrange the table so that more frequently used messages are tested first. With .IF - .ELSEIF, you must move whole blocks of code instead of a single line.

* You do not need to worry about the order in which messages are placed in the table. Compare this with hutch's fast dispatch, where you must know the exact value of the message (not the EQU name).

* Using the dispatch code (or any other compact dispatch code) instead of .IF - .ELSEIF allows you to treat each message handler as independent subroutines, rather than as nested blocks of code.

* Slowness is due to the overhead of looping. In the case of .IF - .ELSEIF, the cost of cache misses might actually make it slower than the loop version. The alternate way of compare-and-jump logic looks like this:
    cmp eax,25

je HandleMessage25
cmp eax,30
je HandleMessage30
cmp eax,43
je HandleMessage43
; ...
cmp eax,10
je HandleMessage10
jmp HandleAllOtherMessages
The question is: Does branch prediction make the loop version faster than the above code? Or are loop overhead and an indirect jump costly enough to defeat branch prediction savings? Is there a break-even point?

* The SmartJump routine is generic. It can be used anywhere you need a multiway branch (switch-case) based on a single integer value. (Except if one of the values you want to test is -1.)
Posted on 2002-12-17 14:59:08 by tenkey
natas,

I confess I have not properly digested you code design here, not quite enough to work it out.

tenkey,

Have I missed something here ? The dispatcher design I posted required no more than the message name as it is usually used. With the macro,


SetMessage MACRO wm_message
mOFFSET CATSTR <OFFSET MSG_>,<wm_message>
mov [eax+wm_message*4], mOFFSET
ENDM

You simply fed in the message name which is an equate and the label is determined after the name is appended to the "MSG_" text. What made it possible was the already known values of the messages from the include file, block fill the array with a default value and overwrite the spacific ones with the label offsets to process each message.

i would agree that in the vast majority of cases that a normal Switch/Case, Select Case, .IF block style of branching does the job fine and it can also be nested within other blocks with no problems. Where I see the use of a dispatcher that uses an array of addresses is if you have a very long and complex WndProc, you can pick up some speed gains there.

The other aside is that a single dispatcher including the code to load the array is generally smaller that the same amount of branch testing code in a normal WndProc style procedure so you get a small gain in code size.

Regards,

hutch@movsd.com
Posted on 2002-12-17 18:29:31 by hutch--
Ack. I've forgotten how you set up the table. I'm thinking speed in all phases, which means defining the jump table completely statically with no setup code.

This is due to extreme familiarity with some assembly code, where the tables are small enough and need to be ROMable.
Posted on 2002-12-17 22:04:32 by tenkey
"I'm thinking speed in all phases, which means defining the jump table
completely statically with no setup code."

It is the best. Pls, explain how to do that when "the tables are not small enough.."

Regards,
Lingo
Posted on 2002-12-17 23:15:39 by lingo12
Tenkey,

I actually did a version that had the block fill done in the initialised data section but it made the exe 4k larger for a non measurable gain in loading speed so I changed it to a block fill at runtime because it was a lot smaller and the speed at load did not matter.

It is handy to be able to load labels at assemble time and there have been times when I have used things like arrays of zero terminated strings that are loaded in this manner.

Lingo12,

I guess there is only 2 ways to load data, statically or dynamically, I would hate to be confined to either. :tongue:

Regards,

hutch@movsd.com
Posted on 2002-12-18 02:42:08 by hutch--
Thanks for all the replys people. Tenkey you made alot of good points.
And I agree with what youre saying. The main reason why I actually posted
the code was so that someone could maybe decipher it for me. ( ;) ) But
a short time after I posted it I started to look into the things it did. And
I know what all the code actually does now. Its actually quite simple.

Thanks
Posted on 2002-12-19 15:54:23 by natas