Andreas Raab uploaded a new version of Kernel to project The Trunk:
http://source.squeak.org/trunk/Kernel-ar.332.mcz ==================== Summary ==================== Name: Kernel-ar.332 Author: ar Time: 22 December 2009, 12:39:41 pm UUID: 417d4df8-ccf7-484a-8c19-63b0402d4921 Ancestors: Kernel-dtl.331 CompiledMethodTrailer phase 1: Main classes =============== Diff against Kernel-dtl.331 =============== Item was added: + ----- Method: CompiledMethodTrailer>>clear (in category 'initialize-release') ----- + clear + kind := #NoTrailer. + size := 1. + data := encodedData := method := nil! Item was added: + ----- Method: CompiledMethodTrailer>>tempNames: (in category 'accessing') ----- + tempNames: aString + "Embed the temp names string into compiled method trailer, + pick best compression method" + | temp | + self clear. + kind := #TempsNamesQCompress. + data := aString. + + self encode. + temp := encodedData. + + kind := #TempsNamesZip. + self encode. + encodedData size > temp size ifTrue: [ + encodedData := temp. + kind := #TempsNamesQCompress. + size := encodedData size. + ]! Item was added: + ----- Method: CompiledMethodTrailer>>encodeTempsNamesZip (in category 'decoding') ----- + encodeTempsNamesZip + + "data is string with method's temporary names, encode it using zip compression" + self encodeUsingZip + + "data is string with method's source code, encoded using qCompress method" + + + ! Item was added: + ----- Method: CompiledMethodTrailer>>decodeLengthField (in category 'private') ----- + decodeLengthField + + "used in various encodings, where length field is preceeding the last trailer byte. + Two least significant bits in last byte denoting the number of bytes for length field" + + | numBytes pos length | + + pos := method size. + numBytes := ((method at: pos) bitAnd: 3) + 1. + + length := 0. + 1 to: numBytes do: [:i | + length := length << 8 + (method at: pos - i ). + ]. + size := 1 + numBytes + length. + + ^ length! Item was added: + ----- Method: CompiledMethodTrailer>>decodeEmbeddedSourceZip (in category 'decoding') ----- + decodeEmbeddedSourceZip + + "data is string with method's source code, compressed using zip compression" + self decodeZip.! Item was added: + ----- Method: CompiledMethodTrailer>>decodeSourceBySelector (in category 'decoding') ----- + decodeSourceBySelector + + "no data, size = 1" + + size := 1.! Item was added: + CompiledMethodTrailer subclass: #OldMethodTrailer + instanceVariableNames: '' + classVariableNames: '' + poolDictionaries: '' + category: 'Kernel-Methods'! Item was added: + ----- Method: CompiledMethodTrailer>>kind (in category 'accessing') ----- + kind + "Answer a symbolic name of trailer kind. + See #trailerKinds on class side and class comment for details" + + ^ kind! Item was added: + ----- Method: CompiledMethodTrailer>>hasTempNames (in category 'testing') ----- + hasTempNames + ^ kind == #TempsNamesQCompress or: [ kind == #TempsNamesZip ]! Item was added: + ----- Method: CompiledMethodTrailer>>qDecompress (in category 'decoding') ----- + qDecompress + "Trailer is compressed string using qCompress method + length field + 1 byte + + Decompress strings compressed by qCompress:. + Most common 11 chars get values 0-10 packed in one 4-bit nibble; + next most common 52 get values 12-15 (2 bits) * 16 plus next nibble; + escaped chars get three nibbles" + | len str input | + + len := self decodeLengthField. + input := (ReadStream on: method from: method size - size+1 to: method size - size + len). + + str := String streamContents: + [:strm | | nextNibble nibble peek charTable | + charTable := "Character encoding table must match qCompress:" + 'ear tonsilcmbdfghjkpquvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012345[]()'. + peek := true. + nextNibble := [peek + ifTrue: [peek := false. input peek ifNil: [0] ifNotNil: [:b| b // 16]] + ifFalse: [peek := true. input next ifNil: [0] ifNotNil: [:b| b \\ 16]]]. + [input atEnd] whileFalse: + [(nibble := nextNibble value) = 0 + ifTrue: [input atEnd ifFalse: + [strm nextPut: (Character value: nextNibble value * 16 + nextNibble value)]] + ifFalse: + [nibble <= 11 + ifTrue: + [strm nextPut: (charTable at: nibble)] + ifFalse: + [strm nextPut: (charTable at: nibble-12 * 16 + nextNibble value)]]]]. + + data := str convertFromEncoding: 'utf8'! Item was added: + ----- Method: OldMethodTrailer class>>testOldStuffIsFine (in category 'as yet unclassified') ----- + testOldStuffIsFine + "OldMethodTrailer testOldStuffIsFine" + | meth | + CompiledMethod allInstancesDo: [:m | + | trailer | + trailer := self new method: m. + self assert: (m endPC = trailer endPC). + ]. + meth := CompiledMethod toReturnSelf copyWithTempNames: #( a b c d e). + self assert: (self new method: meth) tempNames = meth tempNamesString. + self assert: (CompiledMethod toReturnSelfTrailerBytes: (self new tempNames: 'a b c d e ')) tempNamesString + = meth tempNamesString. + ! Item was added: + ----- Method: CompiledMethodTrailer class>>empty (in category 'as yet unclassified') ----- + empty + "answer the empty trailer" + ^ self new! Item was added: + ----- Method: CompiledMethodTrailer>>encodeTempsNamesQCompress (in category 'encoding') ----- + encodeTempsNamesQCompress + + "data is string with method's temporary names, encode it using qCompress method" + self encodeUsingQCompress + ! Item was added: + ----- Method: CompiledMethodTrailer>>encodeUndefined (in category 'encoding') ----- + encodeUndefined + + self error: 'use of an undefined kind of trailer encoding'! Item was added: + ----- Method: CompiledMethodTrailer>>testEncoding (in category 'testing') ----- + testEncoding + + "Since we are using basic protocol (#at:, #at:put: , #size) for accessing compiled method data, + we can pass the ByteArray instance into #method: accessor and check if encoding/decoding + operations is symmetrical. + Use this method only for unit-testing purposes" + + encodedData ifNil: [ self encode ]. + ^ CompiledMethodTrailer new method: encodedData! Item was added: + ----- Method: CompiledMethodTrailer class>>new (in category 'as yet unclassified') ----- + new + ^ self trailerClass basicNew initialize! Item was added: + ----- Method: CompiledMethodTrailer>>sourceCode (in category 'accessing') ----- + sourceCode + "Answer the source code of compiled method. + Note: it does not attempts to read from source files using sourcePointer, + nor reconstruct the source code using temp names" + + (kind == #EmbeddedSourceQCompress or: [ kind == #EmbeddedSourceZip ]) ifTrue: [ + ^ data ]. + + kind == #SourceBySelector ifTrue: [ + ^ method methodClass getSourceCodeBySelector: method selector ]. + + kind == #SourceByStringIdentifier ifTrue: [ + ^ method methodClass getSourceCodeByIdentifier: data ]. + + ^ nil! Item was added: + ----- Method: CompiledMethodTrailer>>sourceCode: (in category 'accessing') ----- + sourceCode: aString + "Embed the source code into compiled method trailer, + pick best compression method" + | temp | + self clear. + kind := #EmbeddedSourceQCompress. + data := aString. + + self encode. + temp := encodedData. + + kind := #EmbeddedSourceZip. + self encode. + encodedData size > temp size ifTrue: [ + encodedData := temp. + kind := #EmbeddedSourceQCompress. + size := encodedData size. + ]! Item was added: + ----- Method: CompiledMethodTrailer>>encodeClearedTrailer (in category 'encoding') ----- + encodeClearedTrailer + + "A cleared trailer is replaced by #NoTrailer, when used for encoding" + self clear. + kind := #NoTrailer. + + ^ self encode! Item was added: + ----- Method: CompiledMethodTrailer>>method: (in category 'initialize-release') ----- + method: aMethod + + | flagByte | + + data := size := nil. + method := aMethod. + flagByte := method at: (method size). + + "trailer kind encoded in 6 high bits of last byte" + kind := self class trailerKinds at: 1+(flagByte>>2). + + "decode the trailer bytes" + self perform: ('decode' , kind) asSymbol. + + "after decoding the trailer, size must be set" + self assert: (size notNil). + + ! Item was added: + ----- Method: CompiledMethodTrailer class>>trailerClass (in category 'as yet unclassified') ----- + trailerClass + ^ OldMethodTrailer! Item was added: + ----- Method: CompiledMethodTrailer>>sourceIdentifier (in category 'accessing') ----- + sourceIdentifier + "Trailer is used to indicate that method's source code can be retrieved by + sending #getSourceCodeByIdentifier: message to method's class" + + ^ (kind == #SourceByStringIdentifier) ifTrue: [ data ] ifFalse: [ nil ]. + + ! Item was added: + ----- Method: CompiledMethodTrailer>>decodeEmbeddedSourceQCompress (in category 'decoding') ----- + decodeEmbeddedSourceQCompress + + "data is string with method's source code, encoded using qCompress method" + self qDecompress.! Item was added: + ----- Method: CompiledMethodTrailer>>encodeEmbeddedSourceQCompress (in category 'encoding') ----- + encodeEmbeddedSourceQCompress + + "data is string with method's source code, encode it using qCompress method" + self encodeUsingQCompress + ! Item was added: + ----- Method: CompiledMethodTrailer class>>usingNewFormat (in category 'as yet unclassified') ----- + usingNewFormat + ^ self trailerClass == CompiledMethodTrailer! Item was added: + ----- Method: CompiledMethodTrailer>>decodeSourcePointer (in category 'decoding') ----- + decodeSourcePointer + + "Trailer is a source pointer" + | msz | + + size := 4. + msz := method size. + data := (method at: msz) - 251 << 8 + (method at: msz-1) << 8 + + (method at: msz-2) << 8 + (method at: msz-3). + + ! Item was added: + ----- Method: CompiledMethodTrailer class>>convertTrailers (in category 'as yet unclassified') ----- + convertTrailers + | toConvert converted | + "Protect against doing this in already converted image." + self assert: (self usingNewFormat not). + + toConvert := OrderedCollection new. + CompiledMethod allInstancesDo: [:m | + "we need to convert only methods which has no sourcePointer " + m sourcePointer = 0 ifTrue: [ + toConvert add: m. + ]. + ]. + + toConvert := toConvert asArray. + converted := toConvert collect: [:m | + m copyWithTrailerBytes: self basicNew initialize. "clear the trailers" + ]. + + toConvert elementsExchangeIdentityWith: converted asArray. + + "replace the #trailerClass method in CompiledMethodTrailer class" + + self class compile: 'trailerClass + ^ CompiledMethodTrailer' + + ! Item was added: + ----- Method: CompiledMethodTrailer>>decodeNoTrailer (in category 'decoding') ----- + decodeNoTrailer + "Not much to decode here" + size := 1. ! Item was added: + ----- Method: CompiledMethodTrailer>>encodeSourceByStringIdentifier (in category 'encoding') ----- + encodeSourceByStringIdentifier + + "A method source is determined by a class + string identifier" + | utf8str len | + + self assert: (data isString). + + encodedData := ByteArray streamContents: [:str | + utf8str := (data convertToEncoding: 'utf8') asByteArray. + str nextPutAll: utf8str. + len := self encodeLengthField: utf8str size. + str nextPutAll: len. + str nextPut: self kindAsByte + (len size -1) + ]! Item was added: + ----- Method: CompiledMethodTrailer>>kindAsByte (in category 'private') ----- + kindAsByte + | index | + index := self class trailerKinds indexOf: kind. + self assert: (index ~~ 0). + + ^ (index - 1) << 2! Item was added: + ----- Method: OldMethodTrailer>>tempNames (in category 'as yet unclassified') ----- + tempNames + + "Answer the string, containing the temps names or nil " + ^ (kind == #OldTempsNames) + ifTrue: [ data ] ifFalse: [ nil ]! Item was added: + ----- Method: CompiledMethodTrailer>>encodeLengthField: (in category 'private') ----- + encodeLengthField: integer + + | bytes value | + self assert: (integer > 0). + + value := integer. + + bytes := ByteArray streamContents: [:str | + [ value > 0 ] whileTrue: [ + str nextPut: (value bitAnd: 255). + value := value >> 8 ]]. + + "no more than 4 bytes for length field" + self assert: (bytes size <=4). + + ^ bytes! Item was added: + ----- Method: CompiledMethodTrailer>>encodeSourcePointer (in category 'encoding') ----- + encodeSourcePointer + + encodedData := ByteArray new: 4. + encodedData at: 4 put: (data >> 24) + 251. + + 1 to: 3 do: [:i | + encodedData at: 4-i put: ((data bitShift: (i-3)*8) bitAnd: 16rFF)]! Item was added: + ----- Method: OldMethodTrailer>>encodeNoTrailer (in category 'as yet unclassified') ----- + encodeNoTrailer + + encodedData := #(0 0 0 0)! Item was added: + ----- Method: CompiledMethodTrailer>>sourcePointer: (in category 'accessing') ----- + sourcePointer: ptr + + self clear. + data := ptr. + "see if we can encode pointer using 4-byte trailer" + kind := (ptr between: 16r1000000 and: 16r4FFFFFF) + ifTrue: [ #SourcePointer ] ifFalse: [ #VarLengthSourcePointer ]. + ! Item was added: + ----- Method: CompiledMethodTrailer>>decodeSourceByStringIdentifier (in category 'decoding') ----- + decodeSourceByStringIdentifier + + "A method source is determined by a class + string identifier" + | len | + + len := self decodeLengthField. + + data := (ReadStream on: method from: method size - size+1 to: method size - size + len) contents asString convertFromEncoding: 'utf8'! Item was added: + ----- Method: CompiledMethodTrailer>>hasSourcePointer (in category 'testing') ----- + hasSourcePointer + ^ kind == #SourcePointer or: [ kind == #VarLengthSourcePointer ] ! Item was added: + ----- Method: CompiledMethodTrailer>>decodeVarLengthSourcePointer (in category 'decoding') ----- + decodeVarLengthSourcePointer + + | pos shift | + + pos := method size-1. + shift := data := 0. + + [ | value | + value := method at: pos. + data := (value bitAnd: 16r7F) << shift + data. + pos := pos - 1. + shift := shift + 7. + value > 127 ] whileTrue. + + size := method size - pos.! Item was added: + ----- Method: OldMethodTrailer>>tempNames: (in category 'as yet unclassified') ----- + tempNames: aString + "Embed the temp names string into compiled method trailer" + + self clear. + kind := #OldTempsNames. + data := aString. + + self encode. + ! Item was added: + ----- Method: CompiledMethodTrailer class>>trailerKinds (in category 'as yet unclassified') ----- + trailerKinds + " see class comment for description" + ^#( + "000000" #NoTrailer + "000001" #ClearedTrailer + "000010" #TempsNamesQCompress + "000011" #TempsNamesZip + "000100" #SourceBySelector + "000101" #SourceByStringIdentifier + "000110" #EmbeddedSourceQCompress + "000111" #EmbeddedSourceZip + "001000" #VarLengthSourcePointer + "001001" #ExtendedKind + "001010" #Undefined + "001011" #Undefined + "001100" #Undefined + "001101" #Undefined + "001110" #Undefined + "001111" #Undefined + "010000" #Undefined + "010001" #Undefined + "010010" #Undefined + "010011" #Undefined + "010100" #Undefined + "010101" #Undefined + "010110" #Undefined + "010111" #Undefined + "011000" #Undefined + "011001" #Undefined + "011010" #Undefined + "011011" #Undefined + "011100" #Undefined + "011101" #Undefined + "011110" #Undefined + "011111" #Undefined + "100000" #Undefined + "100001" #Undefined + "100010" #Undefined + "100011" #Undefined + "100100" #Undefined + "100101" #Undefined + "100110" #Undefined + "100111" #Undefined + "101000" #Undefined + "101001" #Undefined + "101010" #Undefined + "101011" #Undefined + "101100" #Undefined + "101101" #Undefined + "101110" #Undefined + "101111" #Undefined + "110000" #Undefined + "110001" #Undefined + "110010" #Undefined + "110011" #Undefined + "110100" #Undefined + "110101" #Undefined + "110110" #Undefined + "110111" #Undefined + "111000" #Undefined + "111001" #Undefined + "111010" #Undefined + "111011" #Undefined + "111100" #Undefined + "111101" #Undefined + "111110" #Undefined + "111111" #SourcePointer + )! Item was added: + ----- Method: OldMethodTrailer>>decodeOldEmptyTrailer (in category 'as yet unclassified') ----- + decodeOldEmptyTrailer + + "1 to 4 zero bytes" + size := 0. + [ (method at: (method size - size)) = 0 and: [size <4]] whileTrue: [ size := size + 1]. + ! Item was added: + ----- Method: CompiledMethodTrailer>>encodeEmbeddedSourceZip (in category 'encoding') ----- + encodeEmbeddedSourceZip + + "data is string with method's source code, encode it using Zip compression method" + self encodeUsingZip + ! Item was added: + Object subclass: #CompiledMethodTrailer + instanceVariableNames: 'data encodedData kind size method' + classVariableNames: '' + poolDictionaries: '' + category: 'Kernel-Methods'! + + !CompiledMethodTrailer commentStamp: 'Igor.Stasenko 12/13/2009 12:53' prior: 0! + I am responsible for encoding and decoding various kinds of compiled method trailer data. + I should not expose any binary data outside of myself, so all tools which working with compiled methods + should ask me to encode the meta-data, they want to be added to the compiled method trailer, as well as retrieve it. + + To add a new kind of trailer, you should give it a proper name and define it in the #trailerKinds method at my class side. + Then you need to implement a corresponding #encode<your name> and #decode<your name> methods at instance side. Then add any public accessor methods, which will use a newly introduced trailer kind for communicating with outer layer(s). + + An encodeXXX methods should store result (byte array) into encodedData instance variable. + + A decodeXXX methods should read the data from compiled method instance, held by 'method' ivar, + and always set 'size' ivar (denoting a total length of trailer in compiled method) and optionally 'data' ivar which should keep a decoded data, ready to be used by outer layer(s) using accessor method(s) you providing. + + The kind of compiled method trailer is determined by the last byte of compiled method. + + The byte format used is following: + "2rkkkkkkdd" + + where 'k' bits stands for 'kind' , allowing totally 64 different kinds of method trailer + and 'd' bits is data. + + Following is the list of currently defined trailer kinds: + + NoTrailer , k = 000000, dd unused + method has no trailer, and total trailer size bytes is always 1 + + ClearedTrailer, k = 000001, + method has cleared trailer (it was set to something else, but then cleared) + dd+1 determines the number of bytes for size field, and size is a total length of trailer bytes + So a total length of trailer is: 1 + (dd + 1) + size + + TempsNamesQCompress, k = 000010 + the trailer contains a list of method temp names, compressed using qCompress: method. + dd+1 determines the number of bytes for size field, and size is a number of bytes of compressed buffer. + So a total length of trailer is: 1 + (dd + 1) + size + + TempsNamesZip, k = 000011 + the trailer contains a list of method temp names, compressed using GZIP compression method. + dd+1 determines the number of bytes for size field, and size is a number of bytes of compressed buffer + So a total length of trailer is: 1 + (dd + 1) + size + + SourceBySelector, k = 000100 + the trailer indicates , that method source is determined by a class + selector where it is installed to. + Trailer size = 1. + + SourceByStringIdentifier, k = 000101 + the trailer indicates , that method source is determined by a class + some ByteString identifier. + dd+1 determines the number of bytes for size of ByteString identifier, and size is number of bytes of string. + A total length of trailer is: 1 + (dd + 1) + size + + EmbeddedSourceQCompress, k = 000110 + the trailer contains an utf-8 encoded method source code, compressed using qCompress method + dd+1 determines the number of bytes for size field, and size is a number of bytes of compressed source code + A total length of trailer is: 1 + (dd + 1) + size + + EmbeddedSourceZip, k = 000111 + the trailer contains an utf-8 encoded method source code, comressed using GZIP + dd+1 determines the number of bytes for size field, and size is a number of bytes of compressed buffer + A total length of trailer is: 1 + (dd + 1) + size + + VarLengthSourcePointer, k = 001000 + the trailer is variable-length encoded source pointer. + dd bits is unused. + + ExtendedKind, k = 001001 + the next byte of trailer (one that prepends the last byte of compiled method) + denotes an extended kind of trailer, allowing to use additional 256 kinds of encoding method's trailer in future. + + SourcePointer, k = 111111 + the trailer is encoded source pointer. Total trailer size is 4-bytes + (this kind of encoding is backwards compatible with most of existing compiled methods) + + ! Item was added: + ----- Method: CompiledMethodTrailer>>createMethod:header: (in category 'creating a method') ----- + createMethod: numberOfBytesForAllButTrailer header: headerWord + | meth | + encodedData ifNil: [ self encode ]. + + meth := CompiledMethod newMethod: numberOfBytesForAllButTrailer + size header: headerWord. + + "copy the encoded trailer data" + + 1 to: size do: + [:i | meth at: meth size - size + i put: (encodedData at: i)]. + + ^ meth! Item was added: + ----- Method: OldMethodTrailer>>decodeOldTempsNames (in category 'as yet unclassified') ----- + decodeOldTempsNames + + | sz flagByte | + flagByte := method at: (sz := method size). + (flagByte = 0 or: [flagByte > 251]) ifTrue: [^self error: 'not yet implemented']. + (flagByte = 251 + and: [(1 to: 3) allSatisfy: [:i | (method at: method size - i) = 0]]) ifTrue: + [^self error: 'not yet implemented']. + + size := flagByte <= 127 + ifTrue: [flagByte + 1] + ifFalse: [ (flagByte - 128 * 128) + (method at: sz - 1) + 2]. + + data := self qDecompressFrom: (flagByte <= 127 + ifTrue: + [ReadStream on: method from: sz - flagByte to: sz - 1] + ifFalse: + [ReadStream on: method from: sz - (flagByte - 128 * 128 + (method at: sz - 1)) - 1 to: sz - 2]) + ! Item was added: + ----- Method: CompiledMethodTrailer>>encodeSourceBySelector (in category 'encoding') ----- + encodeSourceBySelector + + "A method source is determined by a class + selector where it is installed to" + encodedData := ByteArray with: self kindAsByte! Item was added: + ----- Method: CompiledMethodTrailer>>qCompress: (in category 'private') ----- + qCompress: string + "A very simple text compression routine designed for method temp names. + Most common 11 chars get values 1-11 packed in one 4-bit nibble; + the next most common get values 12-15 (2 bits) * 16 plus next nibble; + unusual ones get three nibbles, the first being the escape nibble 0. + + Answer the write stream with compressed data inside" + + | utf8str stream ix oddNibble | + + string isEmpty ifTrue: + [^self qCompress: ' ']. + utf8str := string convertToEncoding: 'utf8'. + + stream := WriteStream on: (ByteArray new: utf8str size). + oddNibble := nil. + + utf8str do: [:char | + ix := 'ear tonsilcmbdfghjkpquvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012345[]()' + indexOf: char ifAbsent: 0. + (ix = 0 + ifTrue: + [{ 0. char asInteger // 16. char asInteger \\ 16 }] + ifFalse: + [ix <= 11 + ifTrue: [{ ix }] + ifFalse: [{ ix//16+12. ix\\16 }]]) + do: [:nibble | + oddNibble + ifNotNil: [stream nextPut: oddNibble*16 + nibble. oddNibble := nil] + ifNil: [oddNibble := nibble]]]. + oddNibble ifNotNil: "4 = 'ear tonsil' indexOf: Character space" + [stream nextPut: oddNibble * 16 + 4]. + ^ stream + ! Item was added: + ----- Method: CompiledMethodTrailer>>decodeUndefined (in category 'decoding') ----- + decodeUndefined + self error: 'undefined method encoding'! Item was added: + ----- Method: CompiledMethodTrailer>>initialize (in category 'initialize-release') ----- + initialize + self clear! Item was added: + ----- Method: CompiledMethodTrailer>>encodeVarLengthSourcePointer (in category 'encoding') ----- + encodeVarLengthSourcePointer + + | value | + "source pointer must be >=0" + (self assert: data >= 0). + + value := data. + encodedData := ByteArray streamContents: [:str | + [value > 0] whileTrue: [ + value > 127 ifTrue: [ str nextPut: 128 + (value bitAnd: 16r7F) ] + ifFalse: [ str nextPut: value. ]. + value := value >> 7. + ]. + ]. + encodedData := encodedData reversed copyWith: (self kindAsByte)! Item was added: + ----- Method: OldMethodTrailer>>encodeOldEmptyTrailer (in category 'as yet unclassified') ----- + encodeOldEmptyTrailer + + encodedData := #(0 0 0 0). + ! Item was added: + ----- Method: CompiledMethodTrailer>>encodeUsingQCompress (in category 'encoding') ----- + encodeUsingQCompress + + "data is string, encode it using qCompress method" + | str length encodedLength | + + self assert: data isString. + str := self qCompress: data. + length := str position. + encodedLength := self encodeLengthField: length. + + str nextPutAll: encodedLength. + "trailing byte" + str nextPut: (self kindAsByte + encodedLength size - 1). + + encodedData := str contents + ! Item was added: + ----- Method: CompiledMethodTrailer>>decodeClearedTrailer (in category 'decoding') ----- + decodeClearedTrailer + "Size is set in #decodeLengthField" + + self decodeLengthField. + ! Item was added: + ----- Method: CompiledMethodTrailer>>sourceIdentifier: (in category 'accessing') ----- + sourceIdentifier: aString + + "Trailer is used to indicate that method's source code can be retrieved by + sending #getSourceCodeByIdentifier: message to method's class" + + self clear. + data := aString. + kind := #SourceByStringIdentifier. + self encode. + ! Item was added: + ----- Method: CompiledMethodTrailer>>isEmpty (in category 'testing') ----- + isEmpty + ^ kind == #NoTrailer or: [ kind == #ClearedTrailer ]! Item was added: + ----- Method: CompiledMethodTrailer>>sourcePointer (in category 'accessing') ----- + sourcePointer + + ^ (kind == #SourcePointer or: [ kind == #VarLengthSourcePointer ] ) + ifTrue: [ data ] + ifFalse: [ 0 ] + ! Item was added: + ----- Method: OldMethodTrailer>>encodeOldTempsNames (in category 'as yet unclassified') ----- + encodeOldTempsNames + + + "A very simple text compression routine designed for method temp names. + Most common 11 chars get values 1-11 packed in one 4-bit nibble; + the next most common get values 12-15 (2 bits) * 16 plus next nibble; + unusual ones get three nibbles, the first being the escape nibble 0. + CompiledMethod>>endPC determines the maximum length of encoded + output, which means 1 to (251 - 128) * 128 + 127, or 15871 bytes" + data isEmpty ifTrue: [ data := ' ']. + encodedData := ByteArray streamContents: + [:strm | | ix oddNibble sz | + oddNibble := nil. + data do: + [:char | + ix := 'ear tonsilcmbdfghjkpquvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012345[]()' + indexOf: char ifAbsent: 0. + (ix = 0 + ifTrue: + [char asInteger > 255 ifTrue: [^nil]. "Could use UTF8 here; too lazy right now" + { 0. char asInteger // 16. char asInteger \\ 16 }] + ifFalse: + [ix <= 11 + ifTrue: [{ ix }] + ifFalse: [{ ix//16+12. ix\\16 }]]) + do: [:nibble | + oddNibble + ifNotNil: [strm nextPut: oddNibble*16 + nibble. oddNibble := nil] + ifNil: [oddNibble := nibble]]]. + oddNibble ifNotNil: "4 = 'ear tonsil' indexOf: Character space" + [strm nextPut: oddNibble * 16 + 4]. + (sz := strm position) > ((251 - 128) * 128 + 127) ifTrue: + [^nil]. + sz <= 127 + ifTrue: [strm nextPut: sz] + ifFalse: + [strm nextPut: sz \\ 128; nextPut: sz // 128 + 128]]! Item was added: + ----- Method: CompiledMethodTrailer>>decodeExtendedKind (in category 'encoding') ----- + decodeExtendedKind + + "reserved for future use" + self shouldBeImplemented. + ! Item was added: + ----- Method: OldMethodTrailer>>qDecompressFrom: (in category 'as yet unclassified') ----- + qDecompressFrom: input "<ReadStream on: ByteArray> ^<String>" + "Decompress strings compressed by qCompress:. + Most common 11 chars get values 0-10 packed in one 4-bit nibble; + next most common 52 get values 12-15 (2 bits) * 16 plus next nibble; + escaped chars get three nibbles" + ^ String streamContents: + [:strm | | nextNibble nibble peek charTable char | + charTable := "Character encoding table must match qCompress:" + 'ear tonsilcmbdfghjkpquvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012345[]()'. + peek := true. + nextNibble := [peek + ifTrue: [peek := false. input peek ifNil: [0] ifNotNil: [:b| b // 16]] + ifFalse: [peek := true. input next ifNil: [0] ifNotNil: [:b| b \\ 16]]]. + [input atEnd] whileFalse: + [(nibble := nextNibble value) = 0 + ifTrue: [input atEnd ifFalse: + [strm nextPut: (Character value: nextNibble value * 16 + nextNibble value)]] + ifFalse: + [nibble <= 11 + ifTrue: + [strm nextPut: (charTable at: nibble)] + ifFalse: + [strm nextPut: (charTable at: nibble-12 * 16 + nextNibble value)]]]]! Item was added: + ----- Method: CompiledMethodTrailer>>encode (in category 'encoding') ----- + encode + + encodedData := nil. + + "encode the trailer into byte array" + self perform: ('encode' , kind) asSymbol. + + self assert: (encodedData notNil and: [encodedData size > 0 ]). + + "set the size" + size := encodedData size.! Item was added: + ----- Method: CompiledMethodTrailer>>setSourceBySelector (in category 'accessing') ----- + setSourceBySelector + + "Trailer is used to indicate that method's source code can be retrieved by + sending #getSourceCodeBySelector: message to method's class" + + self clear. + kind := #SourceBySelector! Item was added: + ----- Method: CompiledMethodTrailer>>endPC (in category 'accessing') ----- + endPC + "Answer the index of the last bytecode." + + method ifNil: [ self error: 'Cannot determine the endPC without compiled method' ]. + + "if method set, then size should be set as well" + ^ method size - size! Item was added: + ----- Method: CompiledMethodTrailer>>size (in category 'accessing') ----- + size + "Answer the size of method's trailer , in bytes" + ^ size! Item was added: + ----- Method: CompiledMethodTrailer>>tempNames (in category 'accessing') ----- + tempNames + "Answer the string, containing the temps names or nil " + ^ (kind == #TempsNamesQCompress or: [ kind == #TempsNamesZip ]) + ifTrue: [ data ] ifFalse: [ nil ]! Item was added: + ----- Method: CompiledMethodTrailer>>decodeTempsNamesQCompress (in category 'decoding') ----- + decodeTempsNamesQCompress + + "data is string with method's temporary names, encoded using qCompress method" + self qDecompress.! Item was added: + ----- Method: OldMethodTrailer>>method: (in category 'as yet unclassified') ----- + method: aMethod + "old method trailer format has only 3 kinds: + 0 [ 0 0 0 ] - no trailer + source pointer + temps names + " + | flagByte | + data := size := nil. + method := aMethod. + flagByte := method at: (method size). + + kind := (flagByte = 0) ifTrue: [ #OldEmptyTrailer ] + ifFalse: [ + (flagByte < 252) ifTrue: [ #OldTempsNames ] + ifFalse: [ #SourcePointer ]]. + + "decode the trailer bytes" + self perform: ('decode' , kind) asSymbol. + + "after decoding the trailer, size must be set" + self assert: (size notNil). + + ! Item was added: + ----- Method: CompiledMethodTrailer>>encodeNoTrailer (in category 'encoding') ----- + encodeNoTrailer + + encodedData := ByteArray with: self kindAsByte! Item was added: + ----- Method: CompiledMethodTrailer>>encodeExtendedKind (in category 'encoding') ----- + encodeExtendedKind + + "reserved for future use" + self error: 'Not yet implemented'. + ! Item was added: + ----- Method: CompiledMethodTrailer>>decodeTempsNamesZip (in category 'decoding') ----- + decodeTempsNamesZip + + "data is string with method's temporary names, compressed using zip compression" + self decodeZip.! Item was added: + ----- Method: CompiledMethodTrailer>>decodeZip (in category 'private') ----- + decodeZip + + "data := <trailer> unzip utf8ToSqueak" + | len | + len := self decodeLengthField. + + data := (ZipReadStream on: method from: method size - size+1 to: method size - size + len) contents asString convertFromEncoding: 'utf8'. + + ! Item was added: + ----- Method: CompiledMethodTrailer>>encodeUsingZip (in category 'private') ----- + encodeUsingZip + + "data is string, encode it using gzip compression" + | utf8str stream length encodedLength | + + self assert: (data isString). + utf8str := data convertToEncoding: 'utf8'. + + stream := ((ZipWriteStream on: (ByteArray new: utf8str size)) + nextPutAll: utf8str asByteArray; + close; + encodedStream). + + length := stream position. + encodedLength := self encodeLengthField: length. + + stream nextPutAll: encodedLength. + "trailing byte" + stream nextPut: (self kindAsByte + encodedLength size - 1). + + encodedData := stream contents + ! |
Free forum by Nabble | Edit this page |