From 3c5b276f1f0a66f848e21b4d4bdfe3693d7b3e7f Mon Sep 17 00:00:00 2001 From: Gwenael Casaccio Date: Fri, 13 Dec 2013 14:42:40 +0100 Subject: [PATCH] Remove the bytecode decoding, dispatching and printing methods from CompiledCode class. Instead they are moved to they related BytecodeDispatcher and ByteodePrinter classes. It makes the bytecode handling code nicer, smaller, reusable and extendable. --- ChangeLog | 8 + kernel/BytecodeDispatcher.st | 207 ++++++++++++++++++++ kernel/BytecodePrinter.st | 284 +++++++++++++++++++++++++++ kernel/CompildCode.st | 448 +------------------------------------------ libgst/files.c | 3 + packages.xml | 2 + 6 files changed, 507 insertions(+), 445 deletions(-) create mode 100644 kernel/BytecodeDispatcher.st create mode 100644 kernel/BytecodePrinter.st diff --git a/ChangeLog b/ChangeLog index f13c48b..9ba7e79 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2013-12-13 Gwenael Casaccio + + * kernel/CompildCode.st: Remove the bytecode decoding and printing and + use the corresponding classes. + * kernel/BytecodeDispatcher.st: Decode and dispatch the bytecode from a + compiled code object. + * kernel/BytecodePrinter.st: Pretty print the bytecode. + 2013-10-21 Gwenael Casaccio * kernel/ContextPart.st: Print the instruction pointer value in the diff --git a/kernel/BytecodeDispatcher.st b/kernel/BytecodeDispatcher.st new file mode 100644 index 0000000..7b39d12 --- /dev/null +++ b/kernel/BytecodeDispatcher.st @@ -0,0 +1,207 @@ +"====================================================================== +| +| CompiledCode Method Definitions +| +| + ======================================================================" + +"====================================================================== +| +| Copyright 2000,2001,2002,2003,2004,2005,2007,2008,2009 +| Free Software Foundation, Inc. +| Written by Paolo Bonzini. +| +| This file is part of the GNU Smalltalk class library. +| +| The GNU Smalltalk class library is free software; you can redistribute it +| and/or modify it under the terms of the GNU Lesser General Public License +| as published by the Free Software Foundation; either version 2.1, or (at +| your option) any later version. +| +| The GNU Smalltalk class library is distributed in the hope that it will be +| useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser +| General Public License for more details. +| +| You should have received a copy of the GNU Lesser General Public License +| along with the GNU Smalltalk class library; see the file COPYING.LIB. +| If not, write to the Free Software Foundation, 59 Temple Place - Suite +| 330, Boston, MA 02110-1301, USA. +| + ======================================================================" + + + +Object subclass: BytecodeDispatcher [ + + | code | + + BytecodeDispatcher class >> specialSelectors [ + + + ^ #(#+ #- #< #> #<= #>= #= #~= #* #/ #\\ #bitXor: #bitShift: #// #bitAnd: #bitOr: #at: #at:put: #size #class #isNil #notNil #value #value: #== #javaAsInt #javaAsLong nil nil nil nil nil #new: #thisContext #callInto: #narrow #nextPutAll: #yourself #, #on: #subclassResponsibility #add: #nl #printString #contents #name #isEmpty #properties #container #error: #first #tclEval: #collect: #tclResult #key #asTkString #abs #basicNew #negated #not #close #includes: #at:ifAbsent: #asSymbol #with: #copy #copyFrom:to: #print: #last #initialize #tclEval:with:with: #assert: #primitiveFailed #initialize: #asString #cr #should: #arguments #x #readStream #y #tclEval:with:with:with: #asInteger #space #new #shouldNotImplement #-> #numArgs #with:with: #species #blox #step #signal #parent #selector #at:ifPresent: #to: #addLast: #squared #generality #signalOn:mustBe: #ensure: #body #max: #keysAndValuesDo: #printOn: #isKindOf: #visitNode: #addAll: #isInteger #name: #hash #sqrt #beep #primAt: #environment #position #at:ifAbsentPut: #signal: #postCopy #readFrom: #coefficients: #clientPI #flush #value:value: #asFloatD #on:do: #basicAt:put: #primSize #evaluate #connected #reset #copyEmpty: #start #signalOn: #basicAt: #asClass #ln #implementation #checkResponse #average #upTo: #receiver #peek #basicSize #x:y: #foregroundColor: #rows: #text #exp #statements #body: #| #sizeof #includesKey: #pi #completedSuccessfully #writeStream #superclass #arguments: #state #truncated #inject:into: #replaceFrom:to:with:startingAt: #current #between:and: #retryRelationalOp:coercing: #connectIfClosed #detect:ifNone: #checkError #executeAndWait:arguments: #min: #width #parentContext #removeLast #zero #bindWith:with: #temporaries #asOop #width:height: #methodDictionary #accumulate: #count #asLowercase #asArray #exists #signalOn:what: #select: #parent: #selector: #signalOn:withIndex: #bind:to:of:parameters: #return: #~~ #changeState: #sign #variance #asVector #getResponse #wait #instanceClass #asOrderedCollection #keys #asFloat #random #origin #superspace #stop #perform: #backgroundColor: #login #data: #nextToken #primAt:put: #method #allSatisfy: #position: #default #atAllPut: #asSortedCollection #invalidArgsError: #nameIn: #allSubclassesDo: #signalError #height #source #asNumber #primitive #store: #updateViews #errorContents: #displayString #skipSeparators #origin:corner: #activeProcess #bindWith: #beConsistent #at:type: #skip: #days #tclEval:with: #fromSeconds: #& #upToEnd #variable #become: #with:do: #findIndexOrNil: #asSeconds #copyWith: #background #status #selectors:receiver:argument: #create: #coerce: #bytecodeAt:) + ] + + BytecodeDispatcher class >> specialSelectorsNumArgs [ + + + ^ #[1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 0 0 0 0 0 1 1 0 0 255 255 255 255 255 1 0 1 0 1 0 1 1 0 1 0 0 0 0 0 0 0 1 0 1 1 0 0 0 0 0 0 0 0 1 2 0 1 0 2 1 0 0 3 1 0 1 0 0 1 0 0 0 0 4 0 0 0 0 1 0 2 0 0 0 0 0 0 2 1 1 0 0 2 1 0 1 1 1 1 1 1 0 1 0 0 0 1 0 0 2 1 0 1 1 0 0 2 0 2 2 0 0 0 0 1 0 1 1 0 0 0 0 0 1 0 0 0 2 1 1 0 0 0 1 1 0 1 0 0 0 0 1 0 0 2 4 0 2 2 0 2 0 2 1 0 0 0 0 2 0 0 2 0 1 0 0 0 0 2 1 1 1 2 4 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 1 0 2 0 1 1 0 1 0 1 1 1 0 0 0 0 0 1 0 1 0 0 2 0 1 0 2 1 0 2 1 1 0 0 1 2 1 0 1 0 0 3 1 1 1] + ] + + BytecodeDispatcher class >> bytecodeInfoTable [ + + + ^ #[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 128 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 55 28 1 1 55 28 0 1 56 51 0 0 54 56 0 129 54 48 0 129 54 32 0 129 46 49 0 1 55 28 2 1 48 52 0 0 32 30 0 0 56 65 0 0 45 51 0 1 56 30 0 0 55 33 1 1 36 48 0 1 56 32 0 0 39 66 0 1 44 0 0 1 54 34 0 129 32 32 0 0 32 28 0 0 54 32 1 129 20 43 0 0 44 6 0 1 55 28 3 1 32 64 0 0 67 28 0 129 32 51 0 1 46 30 36 1 24 43 0 0 46 64 1 1 68 56 0 129 72 54 0 128 32 65 0 0 32 30 1 0 46 6 0 1 44 1 0 1 52 43 0 0 48 54 0 128 44 30 32 1 32 18 0 1 56 28 0 0 54 32 2 129 48 30 0 0 32 81 1 1 54 35 0 129 46 30 38 1 44 16 0 1 54 35 1 129 32 46 0 0 52 42 0 0 32 16 0 1 32 30 2 0 46 30 49 1 36 68 1 128 32 64 1 0 39 48 0 1 55 37 1 1 44 30 96 1 48 32 0 0 35 51 0 1 68 32 1 129 68 32 0 129 67 46 0 129 46 51 0 1 56 18 0 0 20 42 0 0 32 17 0 1 54 34 1 129 32 0 0 1 48 40 0 0 48 34 0 0 44 36 1 0 46 64 2 1 54 32 3 129 54 33 1 129 35 28 0 1 44 3 0 1 32 22 0 1 32 1 0 1 46 64 3 1 45 93 0 0 36 68 2 128 24 42 0 0 44 8 0 1 54 35 2 129 44 2 0 1 46 17 0 1 55 33 2 1 67 84 1 129 79 64 0 0 67 30 40 129 32 32 3 1 36 54 1 128 69 28 0 129 44 14 0 1 32 65 2 0 83 28 1 0 67 32 0 129 54 35 3 129 32 64 2 0 21 43 0 0 36 54 2 128 36 68 3 128 46 30 1 0 32 6 0 1 72 108 0 0 56 64 0 0 36 68 0 128 52 54 0 128 56 117 0 0 48 35 0 0 67 30 84 129 54 34 2 129 70 64 3 1 54 46 0 129 52 92 0 0 54 77 1 129 44 13 0 1 70 30 1 0 32 30 3 0 54 75 0 129 54 35 5 129 70 64 2 1 32 23 0 1 44 51 0 1 32 71 0 0 32 100 1 1 56 46 0 0 54 35 4 129 33 30 1 0 67 65 1 129 33 64 1 0 32 30 4 0 44 30 41 1 55 28 4 1 32 32 2 1 56 19 0 0 32 28 1 0 79 64 1 0 46 64 4 1 44 28 1 1 35 18 0 1 32 71 1 0 83 71 1 0 32 47 0 1 70 64 5 1 55 29 1 1 70 64 4 1 35 30 1 0 121 51 0 1 102 30 37 129 67 19 0 129 32 65 1 0 67 30 130 129 35 30 0 0 32 34 0 0 36 54 0 128 35 30 2 0 67 65 2 129 68 32 2 129 70 64 6 1 45 50 0 1 44 5 0 1 68 35 1 129 54 34 3 129 46 30 2 0 55 29 0 1 45 39 0 0 79 28 1 1 68 91 0 129 46 24 0 1 70 64 1 1 68 32 3 129 72 30 0 0 46 131 0 1 52 108 0 0 54 32 4 129 102 34 1 129 52 94 0 0 47 64 1 0 68 91 1 129 36 54 3 128 52 65 0 0 39 51 0 1 67 65 3 129 21 101 0 0 52 46 0 0 69 51 0 129 44 17 0 1 32 19 0 1 54 77 2 129] + ] + + BytecodeDispatcher class >> for: aCompiledCode dispatchTo: anObject [ + + + self new + for: aCompiledCode dispatchTo: anObject + ] + + BytecodeDispatcher class >> for: aCompiledCode do: aThreeArgsBlock [ + + + self new + for: aCompiledCode do: aThreeArgsBlock + ] + + for: aCompiledCode dispatchTo: anObject [ + + + | lastOfs | + code := aCompiledCode. + self allByteCodeIndicesDo: [ :i :byte :arg | + lastOfs = i ifFalse: [ + anObject bytecodeIndex: i. + lastOfs := i. + ]. + self dispatchByte: byte with: arg at: i to: anObject ] + ] + + for: aCompiledCode do: aThreeArgsBlock [ + + + code := aCompiledCode. + self allByteCodeIndicesDo: aThreeArgsBlock + ] + + dispatchByte: byte with: operand at: anIndex to: anObject [ + + + byte <= 26 ifTrue: [ ^ self dispatchSend: 30 with: byte to: anObject ]. + byte < 32 ifTrue: [ ^ self dispatchSend: byte with: operand to: anObject ]. + byte < 40 ifTrue: [ ^ self dispatchVariableOp: byte with: operand to: anObject ]. + byte < 44 ifTrue: [ ^ self dispatchJump: byte at: anIndex to: anObject ]. + byte < 48 ifTrue: [ ^ self dispatchOtherStack: byte with: operand to: anObject ]. + byte < 54 ifTrue: [ ^ self dispatchOneByte: byte to: anObject ]. + byte = 54 ifTrue: [ ^ anObject lineNo: operand ]. + byte = 56 ifTrue: [ ^ anObject pushSelf ]. + ^ anObject invalidOpcode + ] + + dispatchSuperoperator: byte with: operand at: ofs to: aBlock [ + + + | index bc1 bc2 arg1 arg2 arg kind | + index := byte * 4. + bc1 := self class bytecodeInfoTable at: index + 1. + bc2 := self class bytecodeInfoTable at: index + 2. + arg := self class bytecodeInfoTable at: index + 3. + kind := self class bytecodeInfoTable at: index + 4. + kind \\ 2 = 0 ifTrue: [ + arg1 := arg. + arg2 := operand + ] + ifFalse: [ + arg1 := operand. + arg2 := arg + ]. + bc1 = 55 ifTrue: [ arg2 := arg1 * 256 + arg2 ] + ifFalse: [ + bc1 < 64 ifTrue: [ aBlock value: ofs value: bc1 value: arg1 ] + ifFalse: [ self dispatchSuperoperator: bc1 with: arg1 at: ofs to: aBlock ] + ]. + bc2 < 64 ifTrue: [ aBlock value: ofs value: bc2 value: arg2 ] + ifFalse: [ self dispatchSuperoperator: bc2 with: arg2 at: ofs to: aBlock ] + ] + + dispatchSend: byte with: operand to: anObject [ + + + byte = 28 ifTrue: [ ^ anObject send: (code literalAt: operand // 256 + 1) numArgs: operand \\ 256 ]. + byte = 29 ifTrue: [ ^ anObject superSend: (code literalAt: operand // 256 + 1) numArgs: operand \\ 256 ]. + byte = 30 ifTrue: [ ^ anObject send: (self class specialSelectors at: operand + 1) numArgs: (self class specialSelectorsNumArgs at: operand + 1) ]. + byte = 31 ifTrue: [ ^ anObject superSend: (self class specialSelectors at: operand + 1) numArgs: (self class specialSelectorsNumArgs at: operand + 1) ]. + ^ anObject invalidOpcode + ] + + dispatchVariableOp: byte with: operand to: anObject [ + + + byte = 32 ifTrue: [ ^ anObject pushTemporary: operand ]. + byte = 33 ifTrue: [ ^ anObject pushTemporary: operand // 256 outer: operand \\ 256 ]. + byte = 34 ifTrue: [ ^ anObject pushGlobal: (code literalAt: operand + 1) ]. + byte = 35 ifTrue: [ ^ anObject pushInstVar: operand ]. + byte = 36 ifTrue: [ ^ anObject storeTemporary: operand ]. + byte = 37 ifTrue: [ ^ anObject storeTemporary: operand // 256 outer: operand \\ 256 ]. + byte = 38 ifTrue: [ ^ anObject storeGlobal: (code literalAt: operand + 1) ]. + byte = 39 ifTrue: [ ^ anObject storeInstVar: operand ] + ] + + dispatchOneByte: byte to: anObject [ + + + byte == 48 ifTrue: [ ^ anObject popStackTop ]. + byte == 49 ifTrue: [ ^ anObject makeDirtyBlock ]. + byte == 50 ifTrue: [ ^ anObject returnFromMethod ]. + byte == 51 ifTrue: [ ^ anObject returnFromContext ]. + byte == 52 ifTrue: [ ^ anObject dupStackTop ]. + byte == 53 ifTrue: [ ^ anObject exitInterpreter ] + ] + + dispatchOtherStack: byte with: operand to: anObject [ + + + byte = 44 ifTrue: [ ^ anObject pushLiteral: operand ]. + byte = 46 ifTrue: [ ^ anObject pushLiteral: (code literalAt: operand + 1) ]. + byte = 47 ifTrue: [ ^ anObject popIntoArray: operand ]. + operand = 0 ifTrue: [ ^ anObject pushLiteral: nil ]. + operand = 1 ifTrue: [ ^ anObject pushLiteral: true ]. + operand = 2 ifTrue: [ ^ anObject pushLiteral: false ]. + ^ anObject invalidOpcode + ] + + dispatchJump: byte at: anIndex to: anObject [ + + + | destination | + destination := self jumpDestinationAt: anIndex forward: byte > 40. + byte < 42 ifTrue: [ ^ anObject jumpTo: destination ]. + byte = 42 ifTrue: [ ^ anObject popJumpIfTrueTo: destination ]. + byte = 43 ifTrue: [ ^ anObject popJumpIfFalseTo: destination ] + ] + + allByteCodeIndicesDo: aBlock [ + + + | numBytes i byte operand ofs | + i := 1. + numBytes := code numBytecodes. + [ i <= numBytes ] whileTrue: [ + ofs := i. + operand := 0. + + [ + byte := code bytecodeAt: i. + operand := operand * 256 + (code bytecodeAt: i + 1). + i := i + 2. + byte = 55 + ] whileTrue. + byte >= 64 ifTrue: [ self dispatchSuperoperator: byte with: operand at: ofs to: aBlock ] + ifFalse: [ aBlock value: ofs value: byte value: operand ] ] + ] +] + diff --git a/kernel/BytecodePrinter.st b/kernel/BytecodePrinter.st new file mode 100644 index 0000000..4e3b270 --- /dev/null +++ b/kernel/BytecodePrinter.st @@ -0,0 +1,284 @@ +Object subclass: BytecodePrinter [ + + | stream | + + BytecodePrinter class >> print: aCompiledCode on: aStream [ + + + ^ self new + initialize: aStream; + print: aCompiledCode; + yourself + ] + + BytecodePrinter class >> print: aCompiledCode [ + + + ^ self print: aCompiledCode on: (WriteStream on: String new) + ] + + initialize: aStream [ + + + stream := aStream + ] + + contents [ + + + ^ stream contents + ] + + print: aCompiledCode [ + + + BytecodeDispatcher for: aCompiledCode dispatchTo: self + ] + + bytecodeIndex: byte [ + + + | s | + s := byte printString. + stream + space: 5 - s size; + nextPut: $[; + nextPutAll: s; + nextPut: $] + ] + + invalidOpcode [ + + + stream + tab; + nextPutAll: 'invalid opcode'; + nl + ] + + pushInstVar: anIndex [ + + + stream + tab; + nextPutAll: 'push Instance Variable[%1]' % {anIndex}; + nl + ] + + storeInstVar: anIndex [ + + + stream + tab; + nextPutAll: 'store into Instance Variable[%1]' % {anIndex}; + nl + ] + + popIntoArray: anIndex [ + + stream + tab; + nextPutAll: 'pop and store into array element[%1]' % {anIndex}; + nl + ] + + pushTemporary: anIndex outer: scopes [ + + + stream + tab; + nextPutAll: 'push Temporary[%1] from outer context #%2' % + {anIndex. + scopes}; + nl + ] + + storeTemporary: anIndex outer: scopes [ + + + stream + tab; + nextPutAll: 'store into Temporary[%1] from outer context #%2' % + {anIndex. + scopes}; + nl + ] + + pushTemporary: anIndex [ + + + stream + tab; + nextPutAll: 'push Temporary[%1]' % {anIndex}; + nl + ] + + storeTemporary: anIndex [ + + + stream + tab; + nextPutAll: 'store into Temporary[%1]' % {anIndex}; + nl + ] + + pushLiteral: anObject [ + + + | printString | + printString := anObject printString. + (anObject isClass not and: [printString size > 30]) + ifTrue: [ printString := '%1 %2' % {anObject class article. anObject class name asString} ]. + stream + tab; + nextPutAll: 'push '; + nextPutAll: printString; + nl + ] + + pushGlobal: anObject [ + + + stream + tab; + nextPutAll: 'push Global Variable '; + print: anObject; + nl + ] + + storeGlobal: anObject [ + + + stream + tab; + nextPutAll: 'store into Global Variable '; + print: anObject; + nl + ] + + pushSelf [ + + + stream + tab; + nextPutAll: 'push self'; + nl + ] + + popStackTop [ + + + stream + tab; + nextPutAll: 'pop stack top'; + nl + ] + + makeDirtyBlock [ + + + stream + tab; + nextPutAll: 'make dirty block'; + nl + ] + + lineNo: n [ + + + stream + tab; + nextPutAll: 'source code line number '; + print: n; + nl + ] + + dupStackTop [ + + + stream + tab; + nextPutAll: 'dup stack top'; + nl + ] + + exitInterpreter [ + + + stream + tab; + nextPutAll: 'exit interpreter'; + nl + ] + + returnFromContext [ + + + stream + tab; + nextPutAll: 'return stack top'; + nl + ] + + returnFromMethod [ + + + stream + tab; + nextPutAll: 'return from method'; + nl + ] + + popJumpIfFalseTo: destination [ + + + stream + tab; + nextPutAll: 'pop and if false jump to '; + print: destination; + nl + ] + + popJumpIfTrueTo: destination [ + + + stream + tab; + nextPutAll: 'pop and if true jump to '; + print: destination; + nl + ] + + jumpTo: destination [ + + + stream + tab; + nextPutAll: 'jump to '; + print: destination; + nl + ] + + superSend: aSymbol numArgs: anInteger [ + + + stream + tab; + nextPutAll: 'send %2 args message %1 to super' % + {aSymbol. + anInteger}; + nl + ] + + send: aSymbol numArgs: anInteger [ + + + stream + tab; + nextPutAll: 'send %2 args message %1' % + {aSymbol. + anInteger}; + nl + ] +] + diff --git a/kernel/CompildCode.st b/kernel/CompildCode.st index fd3f1b8..dd46701 100644 --- a/kernel/CompildCode.st +++ b/kernel/CompildCode.st @@ -548,209 +548,6 @@ superclass for blocks and methods'> ^false ] - dispatchTo: anObject with: param [ - "Disassemble the bytecodes and tell anObject about them in the form - of message sends. param is given as an argument to every message - send." - - - | lastOfs | - self allByteCodeIndicesDo: - [:i :byte :arg | - lastOfs = i - ifFalse: - [anObject bytecodeIndex: i with: param. - lastOfs := i]. - self - dispatchByte: byte - with: arg - at: i - to: anObject - with: param] - ] - - dispatchByte: byte with: operand at: anIndex to: anObject with: param [ - "Private - Print the byte bytecode (starting at anIndex) on param" - - - byte <= 26 - ifTrue: - [^self - dispatchSend: 30 - with: byte - to: anObject - with: param]. - byte < 32 - ifTrue: - [^self - dispatchSend: byte - with: operand - to: anObject - with: param]. - byte < 40 - ifTrue: - [^self - dispatchVariableOp: byte - with: operand - to: anObject - with: param]. - byte < 44 - ifTrue: - [^self - dispatchJump: byte - at: anIndex - to: anObject - with: param]. - byte < 48 - ifTrue: - [^self - dispatchOtherStack: byte - with: operand - to: anObject - with: param]. - byte < 54 - ifTrue: - [^self - dispatchOneByte: byte - to: anObject - with: param]. - byte = 54 ifTrue: [^anObject lineNo: operand with: param]. - byte = 56 ifTrue: [^anObject pushSelf: param]. - ^anObject invalidOpcode: param - ] - - dispatchSuperoperator: byte with: operand at: ofs to: aBlock [ - "Private - Split the superoperator and call back to aBlock for - the two components (recursive calls are possible to several - levels)." - - - | index bc1 bc2 arg1 arg2 arg kind | - index := byte * 4. - bc1 := self class bytecodeInfoTable at: index + 1. - bc2 := self class bytecodeInfoTable at: index + 2. - arg := self class bytecodeInfoTable at: index + 3. - kind := self class bytecodeInfoTable at: index + 4. - kind \\ 2 = 0 - ifTrue: - [arg1 := arg. - arg2 := operand] - ifFalse: - [arg1 := operand. - arg2 := arg]. - bc1 = 55 - ifTrue: [arg2 := arg1 * 256 + arg2] - ifFalse: - [bc1 < 64 - ifTrue: - [aBlock - value: ofs - value: bc1 - value: arg1] - ifFalse: - [self - dispatchSuperoperator: bc1 - with: arg1 - at: ofs - to: aBlock]]. - bc2 < 64 - ifTrue: - [aBlock - value: ofs - value: bc2 - value: arg2] - ifFalse: - [self - dispatchSuperoperator: bc2 - with: arg2 - at: ofs - to: aBlock] - ] - - dispatchSend: byte with: operand to: anObject with: param [ - - byte = 28 - ifTrue: - [^anObject - send: (self literalAt: operand // 256 + 1) - numArgs: operand \\ 256 - with: param]. - byte = 29 - ifTrue: - [^anObject - superSend: (self literalAt: operand // 256 + 1) - numArgs: operand \\ 256 - with: param]. - byte = 30 - ifTrue: - [^anObject - send: (self class specialSelectors at: operand + 1) - numArgs: (self class specialSelectorsNumArgs at: operand + 1) - with: param]. - byte = 31 - ifTrue: - [^anObject - superSend: (self class specialSelectors at: operand + 1) - numArgs: (self class specialSelectorsNumArgs at: operand + 1) - with: param]. - ^anObject invalidOpcode: param - ] - - dispatchVariableOp: byte with: operand to: anObject with: param [ - - byte = 32 ifTrue: [^anObject pushTemporary: operand with: param]. - byte = 33 - ifTrue: - [^anObject - pushTemporary: operand // 256 - outer: operand \\ 256 - with: param]. - byte = 34 - ifTrue: [^anObject pushGlobal: (self literalAt: operand + 1) with: param]. - byte = 35 ifTrue: [^anObject pushInstVar: operand with: param]. - byte = 36 ifTrue: [^anObject storeTemporary: operand with: param]. - byte = 37 - ifTrue: - [^anObject - storeTemporary: operand // 256 - outer: operand \\ 256 - with: param]. - byte = 38 - ifTrue: [^anObject storeGlobal: (self literalAt: operand + 1) with: param]. - byte = 39 ifTrue: [^anObject storeInstVar: operand with: param] - ] - - dispatchOneByte: byte to: anObject with: param [ - - byte == 48 ifTrue: [^anObject popStackTop: param]. - byte == 49 ifTrue: [^anObject makeDirtyBlock: param]. - byte == 50 ifTrue: [^anObject returnFromMethod: param]. - byte == 51 ifTrue: [^anObject returnFromContext: param]. - byte == 52 ifTrue: [^anObject dupStackTop: param]. - byte == 53 ifTrue: [^anObject exitInterpreter: param] - ] - - dispatchOtherStack: byte with: operand to: anObject with: param [ - - byte = 44 ifTrue: [^anObject pushLiteral: operand with: param]. - byte = 46 - ifTrue: [^anObject pushLiteral: (self literalAt: operand + 1) with: param]. - byte = 47 ifTrue: [^anObject popIntoArray: operand with: param]. - operand = 0 ifTrue: [^anObject pushLiteral: nil with: param]. - operand = 1 ifTrue: [^anObject pushLiteral: true with: param]. - operand = 2 ifTrue: [^anObject pushLiteral: false with: param]. - ^anObject invalidOpcode: param - ] - - dispatchJump: byte at: anIndex to: anObject with: param [ - - | destination | - destination := self jumpDestinationAt: anIndex forward: byte > 40. - byte < 42 ifTrue: [^anObject jumpTo: destination with: param]. - byte = 42 ifTrue: [^anObject popJumpIfTrueTo: destination with: param]. - byte = 43 ifTrue: [^anObject popJumpIfFalseTo: destination with: param] - ] - printHeaderOn: aStream [ "Private - Disassemble the method header to aStream" @@ -762,221 +559,7 @@ superclass for blocks and methods'> "Private - Disassemble the bytecode instructions to aStream" - self dispatchTo: self with: aStream - ] - - invalidOpcode: aStream [ - - aStream - tab; - nextPutAll: 'invalid opcode'; - nl - ] - - pushInstVar: anIndex with: aStream [ - - aStream - tab; - nextPutAll: 'push Instance Variable[%1]' % {anIndex}; - nl - ] - - storeInstVar: anIndex with: aStream [ - - aStream - tab; - nextPutAll: 'store into Instance Variable[%1]' % {anIndex}; - nl - ] - - popIntoArray: anIndex with: aStream [ - - aStream - tab; - nextPutAll: 'pop and store into array element[%1]' % {anIndex}; - nl - ] - - pushTemporary: anIndex outer: scopes with: aStream [ - - aStream - tab; - nextPutAll: 'push Temporary[%1] from outer context #%2' % - {anIndex. - scopes}; - nl - ] - - storeTemporary: anIndex outer: scopes with: aStream [ - - aStream - tab; - nextPutAll: 'store into Temporary[%1] from outer context #%2' % - {anIndex. - scopes}; - nl - ] - - pushTemporary: anIndex with: aStream [ - - aStream - tab; - nextPutAll: 'push Temporary[%1]' % {anIndex}; - nl - ] - - storeTemporary: anIndex with: aStream [ - - aStream - tab; - nextPutAll: 'store into Temporary[%1]' % {anIndex}; - nl - ] - - pushLiteral: anObject with: aStream [ - - | printString | - printString := anObject printString. - (anObject isClass not and: [printString size > 30]) - ifTrue: - [printString := '%1 %2' % - {anObject class article. - anObject class name asString}]. - aStream - tab; - nextPutAll: 'push '; - nextPutAll: printString; - nl - ] - - pushGlobal: anObject with: aStream [ - - aStream - tab; - nextPutAll: 'push Global Variable '; - print: anObject; - nl - ] - - storeGlobal: anObject with: aStream [ - - aStream - tab; - nextPutAll: 'store into Global Variable '; - print: anObject; - nl - ] - - pushSelf: aStream [ - - aStream - tab; - nextPutAll: 'push self'; - nl - ] - - popStackTop: aStream [ - - aStream - tab; - nextPutAll: 'pop stack top'; - nl - ] - - makeDirtyBlock: aStream [ - - aStream - tab; - nextPutAll: 'make dirty block'; - nl - ] - - lineNo: n with: aStream [ - - aStream - tab; - nextPutAll: 'source code line number '; - print: n; - nl - ] - - dupStackTop: aStream [ - - aStream - tab; - nextPutAll: 'dup stack top'; - nl - ] - - exitInterpreter: aStream [ - - aStream - tab; - nextPutAll: 'exit interpreter'; - nl - ] - - returnFromContext: aStream [ - - aStream - tab; - nextPutAll: 'return stack top'; - nl - ] - - returnFromMethod: aStream [ - - aStream - tab; - nextPutAll: 'return from method'; - nl - ] - - popJumpIfFalseTo: destination with: aStream [ - - aStream - tab; - nextPutAll: 'pop and if false jump to '; - print: destination; - nl - ] - - popJumpIfTrueTo: destination with: aStream [ - - aStream - tab; - nextPutAll: 'pop and if true jump to '; - print: destination; - nl - ] - - jumpTo: destination with: aStream [ - - aStream - tab; - nextPutAll: 'jump to '; - print: destination; - nl - ] - - superSend: aSymbol numArgs: anInteger with: aStream [ - - aStream - tab; - nextPutAll: 'send %2 args message %1 to super' % - {aSymbol. - anInteger}; - nl - ] - - send: aSymbol numArgs: anInteger with: aStream [ - - aStream - tab; - nextPutAll: 'send %2 args message %1' % - {aSymbol. - anInteger}; - nl + BytecodePrinter print: self on: aStream. ] bytecodeIndex: byte with: aStream [ @@ -1007,34 +590,9 @@ superclass for blocks and methods'> ] allByteCodeIndicesDo: aBlock [ - "Private - Evaluate aBlock passing each of the index where a - new bytecode instruction starts" - - | numBytes i byte operand ofs | - i := 1. - numBytes := self numBytecodes. - [i <= numBytes] whileTrue: - [ofs := i. - operand := 0. - - [byte := self bytecodeAt: i. - operand := operand * 256 + (self bytecodeAt: i + 1). - i := i + 2. - byte = 55] - whileTrue. - byte >= 64 - ifTrue: - [self - dispatchSuperoperator: byte - with: operand - at: ofs - to: aBlock] - ifFalse: - [aBlock - value: ofs - value: byte - value: operand]] + + BytecodeDispatcher for: self do: aBlock ] bytecodeSizeAt: anIndex [ diff --git a/libgst/files.c b/libgst/files.c index a38fb1a..34dc16c 100644 --- a/libgst/files.c +++ b/libgst/files.c @@ -291,6 +291,9 @@ static const char standard_files[] = { "PkgLoader.st\0" "DirPackage.st\0" "Autoload.st\0" + + "BytecodeDispatcher.st\0" + "BytecodePrinter.st\0" }; /* The argc and argv that are passed to libgst via gst_smalltalk_args. diff --git a/packages.xml b/packages.xml index 2c8ad6c..87253a7 100644 --- a/packages.xml +++ b/packages.xml @@ -207,6 +207,8 @@ Getopt.st Regex.st StreamOps.st + BytecodeDispatcher.st + BytecodePrinter.st -- 1.8.3.2