[prev in list] [next in list] [prev in thread] [next in thread] 

List:       squeak-dev
Subject:    [squeak-dev] Re: The Trunk: Kernel-ct.1556.mcz
From:       Eliot Miranda <eliot.miranda () gmail ! com>
Date:       2024-02-26 6:54:41
Message-ID: F7738DD4-7B43-4C72-A9B6-B2EEF54C56ED () gmail ! com
[Download RAW message or body]

Christoph,

    thank you so much! It's lovely to see the simulator fixed like this. Great work!
_,,,^..^,,,_ (phone)

> On Feb 25, 2024, at 11:27 AM, commits@source.squeak.org wrote:
> 
> Christoph Thiede uploaded a new version of Kernel to project The Trunk:
> http://source.squeak.org/trunk/Kernel-ct.1556.mcz
> 
> ==================== Summary ====================
> 
> Name: Kernel-ct.1556
> Author: ct
> Time: 25 February 2024, 8:26:48.901593 pm
> UUID: 929047e6-a708-3540-97c5-aec212d87203
> Ancestors: Kernel-ct.1555, Kernel-ct.1420, Kernel-ct.1451, Kernel-ct.1449, \
> Kernel-ct.1490, Kernel-ct.1546, Kernel-ct.1547, Kernel-ct.1548 
> Merges several simulation fixes from the inbox. As always, please refer to the \
> original versions to read their full messages. 
> Kernel-ct.1420:
> Aligns the error code for primitive 118 (primitiveDoPrimitiveWithArgs) during \
> simulation with what the VM returns. 
> Kernel-ct.1451:
> Revises fallback code for primitive 188 (primitiveExecuteMethodArgsArray) in \
> Object>>#withArgs:executeMethod: to eliminate any side effects to the method \
> dictionary and add support for Objects as Methods. 
> Kernel-ct.1449:
> Fixes arity checks for objects as methods in simulation of primitive 83 \
> (primitivePerform) and primitive 84 (primitivePerformWithArgs). 
> Kernel-ct.1490:
> In code simulation of perform primitives (primitive 83 (primitivePerform) and \
> primitive 84 (primitivePerformWithArgs)), do not check numArgs of the selector or \
> method to align behavior with VM. 
> Revision: Remove the same check from simulation of primitive 100 \
> (primitivePerformInSuperclass) as well. 
> Kernel-ct.1546:
> In the debugger/simulator, fixes stepping through #mustBeBoolean errors and \
> restarting from primitive methods that no longer fail. 
> Kernel-ct.1547:
> When simulating #mustBeBoolean errors, send #mustBeBoolean instead of \
> #mustBeBooleanIn: just like the VM. 
> Kernel-ct.1548:
> Resolves #mustBeBoolean errors for copies or proxies of true and false.
> 
> Revision: Improve documentation.
> 
> =============== Diff against Kernel-ct.1555 ===============
> 
> Item was changed:
> ----- Method: Context>>doPrimitive:method:receiver:args: (in category 'private') \
>                 -----
> doPrimitive: primitiveIndex method: meth receiver: receiver args: arguments
> "Simulate a primitive method whose index is primitiveIndex.  The simulated receiver \
> and arguments are given as arguments to this message. If successful, push result \
> and return resuming context, else ^ {errCode, PrimitiveFailToken}. Any primitive \
> which provokes execution needs to be intercepted and simulated to avoid execution \
> running away." 
> > value |
> "Judicious use of primitive 19 (a null primitive that doesn't do anything) prevents
> the debugger from entering various run-away activities such as spawning a new
> process, etc.  Injudicious use results in the debugger not being able to debug
> interesting code, such as the debugger itself.  Hence use primitive 19 with care \
> :-)" "SystemNavigation new browseAllSelect: [:m| m primitive = 19]"
> primitiveIndex = 19 ifTrue: [
> [self notify: ('The code being simulated is trying to control a process ({1}). \
> Process controlling cannot be simulated. If you proceed, things may happen outside \
>                 the observable area of the simulator.' translated format: {meth \
>                 reference})]
> ifCurtailed: [self push: nil "Cheap fix of the context's internal state"]].
> 
> ((primitiveIndex between: 201 and: 222)
> and: [(self objectClass: receiver) includesBehavior: BlockClosure]) ifTrue:
> [(primitiveIndex = 206
> or: [primitiveIndex = 208]) ifTrue:                        \
> "[Full]BlockClosure>>valueWithArguments:" [^receiver simulateValueWithArguments: \
> arguments first caller: self]. ((primitiveIndex between: 201 and: 209)             \
>                 "[Full]BlockClosure>>value[:value:...]"
> or: [primitiveIndex between: 221 and: 222]) ifTrue: \
> "[Full]BlockClosure>>valueNoContextSwitch[:]" [^receiver \
> simulateValueWithArguments: arguments caller: self]]. 
> primitiveIndex = 83 ifTrue: "afr 9/11/1998 19:50" "Object>>perform:[with:...]"
> [| selector |
> selector := arguments at: 1 ifAbsent:
> [^ self class primitiveFailTokenFor: #'bad argument'].
> -        (selector isSymbol and: [arguments size - 1 ~= selector numArgs]) ifTrue:
> -            [^ self class primitiveFailTokenFor: #'bad number of arguments'].
> ^self send: selector to: receiver with: arguments allButFirst].
> primitiveIndex = 84 ifTrue: "afr 9/11/1998 19:50 & eem 8/18/2009 17:04" \
> "Object>>perform:withArguments:" [| selector args |
> arguments size = 2 ifFalse:
> [^ self class primitiveFailTokenFor: #'bad argument'].
> selector := arguments first.
> args := arguments second.
> args isArray ifFalse:
> [^ self class primitiveFailTokenFor: #'bad argument'].
> -        (selector isSymbol and: [args size ~= selector numArgs]) ifTrue:
> -            [^ self class primitiveFailTokenFor: #'bad number of arguments'].
> ^self send: selector to: receiver with: args].
> primitiveIndex = 100 ifTrue: "eem 8/18/2009 16:57" \
> "Object>>perform:withArguments:inSuperclass:" [| rcvr selector args superclass |
> arguments size
> caseOf: {
> [3] -> [
> rcvr := receiver.
> selector := arguments first.
> args := arguments second.
> superclass := arguments third].
> [4] -> ["mirror primitive"
> rcvr := arguments first.
> selector := arguments second.
> args := arguments third.
> superclass := arguments fourth] }
> otherwise: [^ self class primitiveFailTokenFor: #'bad number of arguments'].
> args isArray ifFalse:
> [^ self class primitiveFailTokenFor: #'bad argument'].
> -        (selector isSymbol and: [args size ~= selector numArgs]) ifTrue:
> -            [^ self class primitiveFailTokenFor: #'bad number of arguments'].
> ((self objectClass: rcvr) includesBehavior: superclass) ifFalse:
> [^ self class primitiveFailTokenFor: #'bad argument'].
> ^self send: selector to: rcvr with: args lookupIn: superclass].
> 
> "Mutex>>primitiveEnterCriticalSection
> Mutex>>primitiveTestAndSetOwnershipOfCriticalSection"
> (primitiveIndex = 186 or: [primitiveIndex = 187]) ifTrue:
> [| effective |
> effective := Processor activeProcess effectiveProcess.
> "active == effective"
> value := primitiveIndex = 186
> ifTrue: [receiver primitiveEnterCriticalSectionOnBehalfOf: effective]
> ifFalse: [receiver primitiveTestAndSetOwnershipOfCriticalSectionOnBehalfOf: \
> effective]. ^(self isPrimFailToken: value)
> ifTrue: [value]
> ifFalse: [self push: value]].
> +    
> +    (primitiveIndex = 188 or: [primitiveIndex = 189]) ifTrue:
> -
> -    primitiveIndex = 188 ifTrue:    "Object>>withArgs:executeMethod:
> -                                    CompiledMethod \
>                 class>>receiver:withArguments:executeMethod:
> -                                    VMMirror>>ifFail:object:with:executeMethod: et \
> al" [| n args methodArg thisReceiver |
> +         primitiveIndex caseOf:
> +            {[188 "primitiveExecuteMethodArgsArray"] ->
> +                ["Object>>withArgs:executeMethod:
> +                  CompiledMethod class>>receiver:withArguments:executeMethod:
> +                  VMMirror>>ifFail:object:with:executeMethod: et al"
> +                 ((n := arguments size) between: 2 and: 4) ifFalse:
> +                    [^self class primitiveFailTokenFor: #'unsupported operation'].
> +                 ((self objectClass: (args := arguments at: n - 1)) == Array
> +                  and: [(self objectClass: (methodArg := arguments at: n)) \
> includesBehavior: CompiledMethod]) ifFalse: +                    [^self class \
> primitiveFailTokenFor: #'bad argument']. +                 thisReceiver := \
> arguments at: n - 2 ifAbsent: [receiver]]. +             [189 \
> "primitiveExecuteMethod"] -> +                ["Object>>executeMethod:
> +                  Object>>with:...executeMethod:"
> +                 (arguments size > 0) ifFalse:
> +                    [^self class primitiveFailTokenFor: #'bad argument'].
> +                 ((self objectClass: (methodArg := arguments atLast: 1)) \
> includesBehavior: CompiledMethod) ifFalse: +                    [^self class \
> primitiveFailTokenFor: #'bad argument']. +                 args := arguments \
> allButLast. +                 thisReceiver := receiver]}.
> -         ((n := arguments size) between: 2 and: 4) ifFalse:
> -            [^self class primitiveFailTokenFor: #'unsupported operation'].
> -         ((self objectClass: (args := arguments at: n - 1)) == Array
> -          and: [(self objectClass: (methodArg := arguments at: n)) \
>                 includesBehavior: CompiledMethod]) ifFalse:
> -            [^self class primitiveFailTokenFor: #'bad argument'].
> methodArg numArgs = args size ifFalse:
> [^self class primitiveFailTokenFor: #'bad number of arguments'].
> -         thisReceiver := arguments at: n - 2 ifAbsent: [receiver].
> methodArg primitive > 0 ifTrue:
> [methodArg isQuick ifTrue:
> [^self push: (methodArg valueWithReceiver: thisReceiver arguments: args)].
> ^self doPrimitive: methodArg primitive method: methodArg receiver: thisReceiver \
> args: args]. ^self
> activateMethod: methodArg
> withArgs: args
> receiver: thisReceiver].
> 
> primitiveIndex = 118 ifTrue: "[receiver:]tryPrimitive:withArgs:; avoid recursing in \
> the VM" [(arguments size = 3
> and: [(self objectClass: arguments second) == SmallInteger
> and: [(self objectClass: arguments last) == Array]]) ifTrue:
> [^self doPrimitive: arguments second method: meth receiver: arguments first args: \
> arguments last]. (arguments size = 2
> and: [(self objectClass: arguments first) == SmallInteger
> and: [(self objectClass: arguments last) == Array]]) ifFalse:
> +            [^self class primitiveFailTokenFor: -3].
> -            [^self class primitiveFailTokenFor: nil].
> ^self doPrimitive: arguments first method: meth receiver: receiver args: arguments \
> last]. 
> value := primitiveIndex = 120 "FFI method"
> ifTrue: [(meth literalAt: 1) tryInvokeWithArguments: arguments]
> ifFalse:
> [primitiveIndex = 117 "named primitives"
> ifTrue: [self tryNamedPrimitiveIn: meth for: receiver withArgs: arguments]
> ifFalse: "should use self receiver: receiver tryPrimitive: primitiveIndex withArgs: \
> arguments but this is only in later VMs (and appears to be broken)" [receiver \
> tryPrimitive: primitiveIndex withArgs: arguments]]. 
> ^(self isPrimFailToken: value)
> ifTrue: [value]
> ifFalse: [self push: value]!
> 
> Item was added:
> + ----- Method: Context>>executeMethod:forSelector:withArgs:receiver: (in category \
> 'controlling') ----- + executeMethod: meth forSelector: selector withArgs: \
> arguments receiver: rcvr +
> +    | primIndex val ctxt |
> +    (self objectClass: meth) isCompiledCodeClass ifFalse:
> +        ["Object as Methods (OaM) protocol: 'The contract is that, when the VM \
> encounters an ordinary object (rather than a compiled method) in the method \
> dictionary during lookup, it sends it the special selector #run:with:in: providing \
> the original selector, arguments, and receiver.'. DOI: 10.1145/2991041.2991062." +  \
> ^self send: #run:with:in: +            to: meth
> +            with: {selector. arguments. rcvr}].
> +    
> +    meth numArgs = arguments size ifFalse:
> +        [^ self class primitiveFailTokenFor: #'bad number of arguments'].
> +    (primIndex := meth primitive) > 0 ifTrue:
> +        [val := self doPrimitive: primIndex method: meth receiver: rcvr args: \
> arguments. +        (self isPrimFailToken: val) ifFalse:
> +            [^val]].
> +    
> +    ctxt := self activateMethod: meth withArgs: arguments receiver: rcvr.
> +    (primIndex isInteger and: [primIndex > 0]) ifTrue:
> +        [ctxt failPrimitiveWith: val].
> +    
> +    ^ctxt!
> 
> Item was changed:
> ----- Method: Context>>jump:if: (in category 'instruction decoding') -----
> jump: distance if: condition
> "Simulate the action of a 'conditional jump' bytecode whose offset is the
> argument, distance, and whose condition is the argument, condition."
> 
> > bool |
> bool := self pop.
> condition == bool
> ifTrue: [self jump: distance]
> ifFalse:
> [(true == bool or: [false == bool]) ifFalse:
> +                [^self send: #mustBeBoolean to: bool with: #()]]!
> -                [^self send: #mustBeBooleanIn: to: bool with: {self}]]!
> 
> Item was changed:
> ----- Method: Context>>send:to:with:lookupIn: (in category 'controlling') -----
> send: selector to: rcvr with: arguments lookupIn: lookupClass
> "Simulate the action of sending a message with selector and arguments to rcvr. The \
> argument, lookupClass, is the class in which to lookup the message. This is the \
> receiver's class for normal messages, but for super messages it will be some \
> specific class related to the source method." 
> +    | meth |
> -    | meth primIndex val ctxt |
> (meth := lookupClass lookupSelector: selector) ifNil:
> [selector == #doesNotUnderstand: ifTrue:
> [self error: 'Recursive message not understood!!' translated].
> ^self send: #doesNotUnderstand:
> to: rcvr
> with: {(Message selector: selector arguments: arguments) lookupClass: lookupClass}
> lookupIn: lookupClass].
> 
> +    ^ self
> +        executeMethod: meth
> +        forSelector: selector
> +        withArgs: arguments
> +        receiver: rcvr!
> -    (self objectClass: meth) isCompiledCodeClass ifFalse:
> -        ["Object as Methods (OaM) protocol: 'The contract is that, when the VM \
> encounters an ordinary object (rather than a compiled method) in the method \
> dictionary during lookup, it sends it the special selector #run:with:in: providing \
>                 the original selector, arguments, and receiver.'. DOI: \
>                 10.1145/2991041.2991062."
> -        ^self send: #run:with:in:
> -            to: meth
> -            with: {selector. arguments. rcvr}].
> -    
> -    meth numArgs = arguments size ifFalse:
> -        [^ self error: ('Wrong number of arguments in simulated message {1}' \
>                 translated format: {selector})].
> -    (primIndex := meth primitive) > 0 ifTrue:
> -        [val := self doPrimitive: primIndex method: meth receiver: rcvr args: \
>                 arguments.
> -        (self isPrimFailToken: val) ifFalse:
> -            [^val]].
> -    
> -    ctxt := self activateMethod: meth withArgs: arguments receiver: rcvr.
> -    (primIndex isInteger and: [primIndex > 0]) ifTrue:
> -        [ctxt failPrimitiveWith: val].
> -    
> -    ^ctxt!
> 
> Item was changed:
> ----- Method: Context>>stepToSendOrReturn (in category 'system simulation') -----
> stepToSendOrReturn
> "Simulate the execution of bytecodes until either sending a message or
> returning a value to the receiver (that is, until switching contexts)."
> 
> > ctxt |
> [self willReallySend or: [self willReturn or: [self willReallyStore]]] whileFalse:
> [ctxt := self step.
> ctxt == self ifFalse:
> +            ["Caused by mustBeBoolean handling or callPrimitive:"
> +             ^ctxt stepToSendOrReturn]]!
> -            [self halt.
> -             "Caused by mustBeBoolean handling"
> -             ^ctxt]]!
> 
> Item was added:
> + ----- Method: False>>mustBeBooleanIn: (in category 'converting') -----
> + mustBeBooleanIn: aContext
> +    "Overwritten to support conditional jumps (ifTrue:/ifFalse:) based on a proxy \
> to true/false. The jump will first fail, send #mustBeBoolean to the proxy, which \
> will forward hither. Here, we correct the context by replacing the proxy on the \
> stack through the canonical instance of ourselves and reattempting the jump. See \
> ObjectTracer>>mustBeBoolean for an example." +
> +    aContext skipBackBeforeJump.
> +    ^ false!
> 
> Item was changed:
> ----- Method: Object>>withArgs:executeMethod: (in category 'message handling') \
>                 -----
> withArgs: argArray executeMethod: compiledMethod
> "Execute compiledMethod against the receiver and args in argArray"
> 
> +    | context |
> -    | selector |
> <primitive: 188>
> +    context := thisContext
> +        executeMethod: compiledMethod
> +        forSelector: Symbol new
> +        withArgs: argArray
> +        receiver: self.
> +    ^ context == thisContext
> +        ifTrue: ["quick return" thisContext top]
> +        ifFalse: [context jump]!
> -    selector := Symbol new.
> -    self class addSelectorSilently: selector withMethod: compiledMethod.
> -    ^ [self perform: selector withArguments: argArray]
> -        ensure: [self class basicRemoveSelector: selector]!
> 
> Item was added:
> + ----- Method: ObjectTracer>>mustBeBoolean (in category 'very few messages') -----
> + mustBeBoolean
> +    "Overwritten to preserve original sender context.
> +    
> +    This is required to support conditional jumps (ifTrue:/ifFalse:) based on \
> traced booleans, e.g.: +        (ObjectTracer on: false) ifTrue: [1] ifFalse: [2]."
> +
> +    ^ self mustBeBooleanIn: thisContext sender!
> 
> Item was added:
> + ----- Method: True>>mustBeBooleanIn: (in category 'converting') -----
> + mustBeBooleanIn: aContext
> +    "Overwritten to support conditional jumps (ifTrue:/ifFalse:) based on a proxy \
> to true/false. The jump will first fail, send #mustBeBoolean to the proxy, which \
> will forward hither. Here, we correct the context by replacing the proxy on the \
> stack through the canonical instance of ourselves and reattempting the jump. See \
> ObjectTracer>>mustBeBoolean for an example." +
> +    aContext skipBackBeforeJump.
> +    ^ true!
> 
> 


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic