Hi Eliot. 2016-06-06 1:13 GMT+02:00 Eliot Miranda <[email protected]>:
> That's simply not true. In fact the amount known of the VM in both the > bytecode debugger and the AST debugger is the same; both use VM primitives > that aren't specified at the image level. > > Both the AST interpreter and the bytecode interpreter include the > interpreter in Smalltalk in the image. Look at Context and > InstructionStream to find the Smalktalk definitions of both the interpreter > routines and the implementations of the bytecodes. > > > So my question is why our debuggers are not based on AST interpreter? Why > it is bad idea? (if it is bad). > > > One area where you'll find the AST debugger worse is in performance. The > bytecode debugger uses perform: to execute at full speed when possible (it > does interpret when doing step into or through, but not when doing over). > In fact this part of the system, because it has to catch no local returns > and exceptions, is the most complex, but it's not because of VM details, > it's because of the use of perform: to run code being debugged to run at > full speed. > > Not to mention, if it isn't broke don't fix it. > > But seriously, the system is based on bytecode, and that bytecode is > pretty straightforward and easy to learn. Why not put in the effort of > learning it? > > Criticizing something in ignorance is not wise IMO. > I just put this method here: InstructionStream >>interpretNextV3PlusClosureInstructionFor: client > "Send to the argument, client, a message that specifies the type of the > next instruction." > | byte type offset method | > method := self method. > byte := method at: pc. > type := byte // 16. > offset := byte \\ 16. > pc := pc+1. > "We do an inline binary search on each of the possible 16 values of type: > The old, cleaner but slowe code is retained as a comment below" > type < 8 > ifTrue: [type < 4 > ifTrue: [type < 2 > ifTrue: [type < 1 > ifTrue: ["type = 0" > ^ client pushReceiverVariable: offset] > ifFalse: ["type = 1" > ^ client pushTemporaryVariable: offset]] > ifFalse: [type < 3 > ifTrue: ["type = 2" > ^ client > pushConstant: (method literalAt: offset + 1)] > ifFalse: ["type = 3" > ^ client > pushConstant: (method literalAt: offset + 17)]]] > ifFalse: [type < 6 > ifTrue: [type < 5 > ifTrue: ["type = 4" > ^ client > pushLiteralVariable: (method literalAt: offset + 1)] > ifFalse: ["type = 5" > ^ client > pushLiteralVariable: (method literalAt: offset + 17)]] > ifFalse: [type < 7 > ifTrue: ["type = 6" > offset < 8 > ifTrue: [^ client popIntoReceiverVariable: offset] > ifFalse: [^ client popIntoTemporaryVariable: offset - 8]] > ifFalse: ["type = 7" > offset = 0 > ifTrue: [^ client pushReceiver]. > offset < 8 > ifTrue: [^ client > pushConstant: (SpecialConstants at: offset)]. > offset = 8 > ifTrue: [^ client methodReturnReceiver]. > offset < 12 > ifTrue: [^ client > methodReturnConstant: (SpecialConstants at: offset - 8)]. > offset = 12 > ifTrue: [^ client methodReturnTop]. > offset = 13 > ifTrue: [^ client blockReturnTop]. > offset > 13 > ifTrue: [^ self unusedBytecode: client at: pc - 1 ]]]]] > ifFalse: [type < 12 > ifTrue: [type < 10 > ifTrue: [type < 9 > ifTrue: ["type = 8" > ^ self > interpretV3PlusClosureExtension: offset > in: method > for: client] > ifFalse: ["type = 9 (short jumps)" > offset < 8 > ifTrue: [^ client jump: offset + 1]. > ^ client jump: offset - 8 + 1 if: false]] > ifFalse: [type < 11 > ifTrue: ["type = 10 (long jumps)" > byte := method at: pc. > pc := pc + 1. > offset < 8 > ifTrue: [^ client jump: offset - 4 * 256 + byte]. > ^ client jump: (offset bitAnd: 3) > * 256 + byte if: offset < 12] > ifFalse: ["type = 11" > ^ client > send: (Smalltalk specialSelectorAt: offset + 1) > super: false > numArgs: (Smalltalk specialNargsAt: offset + 1)]]] > ifFalse: [type = 12 > ifTrue: [^ client > send: (Smalltalk specialSelectorAt: offset + 17) > super: false > numArgs: (Smalltalk specialNargsAt: offset + 17)] > ifFalse: ["type = 13, 14 or 15" > ^ client > send: (method literalAt: offset + 1) > super: false > numArgs: type - 13]]]. > > " old code > type=0 ifTrue: [^client pushReceiverVariable: offset]. > type=1 ifTrue: [^client pushTemporaryVariable: offset]. > type=2 ifTrue: [^client pushConstant: (method literalAt: offset+1)]. > type=3 ifTrue: [^client pushConstant: (method literalAt: offset+17)]. > type=4 ifTrue: [^client pushLiteralVariable: (method literalAt: offset+1)]. > type=5 ifTrue: [^client pushLiteralVariable: (method literalAt: > offset+17)]. > type=6 > ifTrue: [offset<8 > ifTrue: [^client popIntoReceiverVariable: offset] > ifFalse: [^client popIntoTemporaryVariable: offset-8]]. > type=7 > ifTrue: [offset=0 ifTrue: [^client pushReceiver]. > offset<8 ifTrue: [^client pushConstant: (SpecialConstants at: offset)]. > offset=8 ifTrue: [^client methodReturnReceiver]. > offset<12 ifTrue: [^client methodReturnConstant: > (SpecialConstants at: offset-8)]. > offset=12 ifTrue: [^client methodReturnTop]. > offset=13 ifTrue: [^client blockReturnTop]. > offset>13 ifTrue: [^self error: 'unusedBytecode']]. > type=8 ifTrue: [^self interpretExtension: offset in: method for: client]. > type=9 > ifTrue: short jumps > [offset<8 ifTrue: [^client jump: offset+1]. > ^client jump: offset-8+1 if: false]. > type=10 > ifTrue: long jumps > [byte:= method at: pc. pc:= pc+1. > offset<8 ifTrue: [^client jump: offset-4*256 + byte]. > ^client jump: (offset bitAnd: 3)*256 + byte if: offset<12]. > type=11 > ifTrue: > [^client > send: (Smalltalk specialSelectorAt: offset+1) > super: false > numArgs: (Smalltalk specialNargsAt: offset+1)]. > type=12 > ifTrue: > [^client > send: (Smalltalk specialSelectorAt: offset+17) > super: false > numArgs: (Smalltalk specialNargsAt: offset+17)]. > type>12 > ifTrue: > [^client send: (method literalAt: offset+1) > super: false > numArgs: type-13]"
