Is there a simple way to detect that given method using:
myMethod <primitive: #primFoo module: #moduleBar error: errorCode> but not: myMethod <primitive: #primFoo module: #moduleBar> ? should i use a method's pragmas to see if it has #primitive:module:error: pragma? And if this check is ok, do i remember correctly, that temp which is used for storing an error is first temp in context, i.e.: err := context tempAt: 1 ? (ok i checked, it is actually always last temp), no matter if i declare temps before pragma or not. i.e. the order is same for: myMethod | a b c | <primitive: #primFoo module: #moduleBar error: errorCode> and myMethod <primitive: #primFoo module: #moduleBar error: errorCode> | a b c | -- Best regards, Igor Stasenko. |
On Fri, Feb 10, 2012 at 9:56 AM, Igor Stasenko <[hidden email]> wrote: -- Is there a simple way to detect that given method using: Yes. The first bytecode of a method that contains a primitive error code will be a temp store bytecode, storing the stack top to the error code (*). e.g. in Decompiler>>#decompile:in:method:using: find
"skip primitive error code store if necessary" (method primitive ~= 0 and: [self willStore]) ifTrue:
[pc := pc + 2. tempVars := tempVars asOrderedCollection]. ... method primitive > 0 ifTrue: [node removeAndRenameLastTempIfErrorCode].
So (InstructionStream on: aMethod) willStore is nearly it. However, quick methods confuse InstructionStream, so one needs aMethod isQuick not and: [(InstructionStream on: aMethod) willStore]
and so (SystemNavigation new allSelect: [:m| m primitiveErrorVariableName notNil]) = (SystemNavigation new allSelect: [:m| m isQuick not and: [(InstructionStream on: m) willStore]]) true
and | m | m := Alien >> #sizeFieldPut:. { Time millisecondsToRun: [1 to: 1000000 do: [:i| m primitiveErrorVariableName notNil]]. Time millisecondsToRun: [1 to: 1000000 do: [:i| m isQuick not and: [(InstructionStream on: m) willStore]]]. } #(3516 161)
If you're searching, e.g. via browseAllSelect: then you'll save time by adding a primitive > 0 guard, so { [:m| m primitiveErrorVariableName notNil].
[:m| m primitive > 0 and: [m primitiveErrorVariableName notNil]]. [:m| m isQuick not and: [(InstructionStream on: m) willStore]]. [:m| m primitive > 0 and: [m isQuick not and: [(InstructionStream on: m) willStore]]] } collect:
[:b| Time millisecondsToRun: [10 timesRepeat: [SystemNavigation new allSelect: b]]]
#(478 468 513 382)
No, its always the last. The first temp is reserved for the first argument, if any.
Right. (*) the scheme is to have a no-op store to "store" the error code. The store is always a store of the stack top to the last temp, but on entry to a method the stack top *is* the last temp. So on old VMs this store has no effect, and on new VMs the store is taken as an indication that the last temp holds the primitive error code and that on failing a primitive the error code should be stored into the last temp.
-- best, Eliot |
On 10 February 2012 19:21, Eliot Miranda <[hidden email]> wrote:
> > > On Fri, Feb 10, 2012 at 9:56 AM, Igor Stasenko <[hidden email]> wrote: >> >> Is there a simple way to detect that given method using: >> >> >> myMethod >> <primitive: #primFoo module: #moduleBar error: errorCode> >> >> but not: >> >> myMethod >> <primitive: #primFoo module: #moduleBar> >> >> ? > > > Yes. The first bytecode of a method that contains a primitive error code > will be a temp store bytecode, storing the stack top to the error code (*). > e.g. in Decompiler>>#decompile:in:method:using: find > > "skip primitive error code store if necessary" > (method primitive ~= 0 and: [self willStore]) ifTrue: > [pc := pc + 2. > tempVars := tempVars asOrderedCollection]. > > ... > > method primitive > 0 ifTrue: > [node removeAndRenameLastTempIfErrorCode]. > > So (InstructionStream on: aMethod) willStore is nearly it. However, quick > methods confuse InstructionStream, so one needs aMethod isQuick not and: > [(InstructionStream on: aMethod) willStore] > > and so > > (SystemNavigation new allSelect: [:m| m primitiveErrorVariableName notNil]) > = (SystemNavigation new allSelect: [:m| m isQuick not and: > [(InstructionStream on: m) willStore]]) true > > and > > | m | > m := Alien >> #sizeFieldPut:. > { Time millisecondsToRun: [1 to: 1000000 do: [:i| m > primitiveErrorVariableName notNil]]. > Time millisecondsToRun: [1 to: 1000000 do: [:i| m isQuick not and: > [(InstructionStream on: m) willStore]]]. } #(3516 161) > > If you're searching, e.g. via browseAllSelect: then you'll save time by > adding a primitive > 0 guard, so > > { [:m| m primitiveErrorVariableName notNil]. > [:m| m primitive > 0 and: [m primitiveErrorVariableName notNil]]. > [:m| m isQuick not and: [(InstructionStream on: m) willStore]]. > [:m| m primitive > 0 and: [m isQuick not and: [(InstructionStream on: m) > willStore]]] } collect: > [:b| > Time millisecondsToRun: [10 timesRepeat: [SystemNavigation new allSelect: > b]]] > #(478 468 513 382) > No, i just writing a common handler for errors. In my case, in NativeBoost many methods using same primitive, in a form that you can do it like: myMethod <primitive: #primitiveNativeCall module: #.. error: errorcode> CommonErrorHandler handleError like that i need to extract error code from a context state (a context which is sender of #handleError), not from parameter which user should always pass directly.. because forcing users to also pass the error code producing a lot of extra code, which not necessary since i can access this stuff via reflection. Apparently, for making it work, first i need to know if primitive uses that form of pragma or not, and then read the error code at right place, and of course i don't really care if it fast or quick or not :) Thanks for clearing the fog :) Just wanted to know if i do it right. >> >> should i use a method's pragmas to see if it has >> #primitive:module:error: pragma? >> >> And if this check is ok, do i remember correctly, that temp which is >> used for storing an error is first temp in context, i.e.: >> >> err := context tempAt: 1 >> >> ? > > > No, its always the last. The first temp is reserved for the first argument, > if any. > >> >> >> (ok i checked, it is actually always last temp), no matter if i >> declare temps before pragma or not. >> >> i.e. the order is same for: >> >> myMethod >> | a b c | >> <primitive: #primFoo module: #moduleBar error: errorCode> >> >> and >> >> myMethod >> <primitive: #primFoo module: #moduleBar error: errorCode> >> | a b c | > > > Right. > > (*) the scheme is to have a no-op store to "store" the error code. The > store is always a store of the stack top to the last temp, but on entry to a > method the stack top *is* the last temp. So on old VMs this store has no > effect, and on new VMs the store is taken as an indication that the last > temp holds the primitive error code and that on failing a primitive the > error code should be stored into the last temp. > >> -- >> Best regards, >> Igor Stasenko. > > -- > best, > Eliot > > > > -- Best regards, Igor Stasenko. |
Free forum by Nabble | Edit this page |