The Trunk: Kernel-ar.332.mcz

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

The Trunk: Kernel-ar.332.mcz

commits-2
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
+ !