<div dir="ltr"><div><div><div><div>Hi,<br><br></div>I got a timeout error during the upload because of my slow internet connexion. Hope this won't cause any problem.<br></div>I finally found time to commit this new primitive! If you spot any mistake, contact me!<br><br></div>I have updated the related methods in Squeak (updating previous senders of compare:with:collated so they call this primitive instead) + the tests methods but I can't commit to the repository. I can send the .st files to someone who does have the rights.<br><br></div>Sophie<br></div><div class="gmail_extra"><br><div class="gmail_quote">2018-04-19 12:02 GMT+02:00 <span dir="ltr"><<a href="mailto:commits@source.squeak.org" target="_blank">commits@source.squeak.org</a>></span>:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"> <br>
Sophie Kaleba uploaded a new version of VMMaker to project VM Maker:<br>
<a href="http://source.squeak.org/VMMaker/VMMaker.oscog-sk.2367.mcz" rel="noreferrer" target="_blank">http://source.squeak.org/<wbr>VMMaker/VMMaker.oscog-sk.2367.<wbr>mcz</a><br>
<br>
==================== Summary ====================<br>
<br>
Name: VMMaker.oscog-sk.2367<br>
Author: sk<br>
Time: 19 April 2018, 12:02:35.661622 pm<br>
UUID: 0c2401e3-1450-4f73-8e81-<wbr>958f50171595<br>
Ancestors: VMMaker.oscog- nice.2366<br>
<br>
** new primitive to compare strings (slang + JIT)<br>
answers negative smi, 0 or positive smi (instead of 1, 2 or 3 in the MiscPlugin)<br>
<br>
* Slang (primitiveCompareWith)<br>
order is optionnal. <br>
comparison loop performed in rawCompare: string1 length: strLength1 with: string2 length: strLength2 accessBlock: accessBlock<br>
<br>
* JIT (<wbr>genPrimitiveStringCompareWith)<br>
the JIT primitive does not take order as parameter (assumed asciiOrder)<br>
quick jump if one of the strings is empty<br>
<br>
=============== Diff against VMMaker.oscog- nice.2366 ===============<br>
<br>
Item was added:<br>
+ ----- Method: CogObjectRepresentation>><wbr>genPrimitiveStringCompareWith (in category 'primitive generators') -----<br>
+ genPrimitiveStringCompareWith<br>
+ "subclasses override if they can"<br>
+ ^UnimplementedPrimitive!<br>
<br>
Item was added:<br>
+ ----- Method: CogObjectRepresentationForSpur<wbr>>><wbr>genPrimitiveStringCompareWith (in category 'primitive generators') -----<br>
+ genPrimitiveStringCompareWith<br>
+ "primitiveCompareWith:"<br>
+ <br>
+ | instr jump jumpAbove jumpIncorrectFormat1 jumpIncorrectFormat2 jumpIncorrectFormat3 jumpIncorrectFormat4 jumpMidFailure jumpSuccess minSizeReg string1CharOrByteSizeReg string2CharOrByteSizeReg string1Reg string2Reg |<br>
+ <br>
+ <var: #jumpIncorrectFormat1 type: #'AbstractInstruction *'><br>
+ <var: #jumpIncorrectFormat2 type: #'AbstractInstruction *'><br>
+ <var: #jumpIncorrectFormat3 type: #'AbstractInstruction *'><br>
+ <var: #jumpIncorrectFormat4 type: #'AbstractInstruction *'><br>
+ <var: #jumpAbove type: #'AbstractInstruction *'><br>
+ <var: #jumpSuccess type: #'AbstractInstruction *'><br>
+ <var: #jump type: #'AbstractInstruction *'><br>
+ <var: #jumpMidFailure type: #'AbstractInstruction *'><br>
+ <br>
+ "I redefine those name to ease program comprehension"<br>
+ string1Reg := ReceiverResultReg.<br>
+ string2Reg := Arg0Reg.<br>
+ string1CharOrByteSizeReg := Arg1Reg.<br>
+ string2CharOrByteSizeReg := ClassReg.<br>
+ minSizeReg := SendNumArgsReg.<br>
+ <br>
+ "Load arguments in reg"<br>
+ cogit genLoadArgAtDepth: 0 into: string2Reg.<br>
+ <br>
+ "checks if string1 is a byteobject and get its size in bytes"<br>
+ self genGetFormatOf: string1Reg into: TempReg.<br>
+ cogit CmpCq: objectMemory firstByteFormat R: TempReg.<br>
+ jumpIncorrectFormat1 := cogit JumpLess: 0.<br>
+ cogit CmpCq: objectMemory firstCompiledMethodFormat R: TempReg.<br>
+ jumpIncorrectFormat2 := cogit JumpAboveOrEqual: 0.<br>
+ <br>
+ self genGetNumSlotsOf: string1Reg into: string1CharOrByteSizeReg.<br>
+ (cogit LogicalShiftLeftCq: objectMemory shiftForWord R: string1CharOrByteSizeReg). <br>
+ cogit AndCq: objectMemory wordSize - 1 R: TempReg R: TempReg. <br>
+ cogit SubR: TempReg R: string1CharOrByteSizeReg. <br>
+ <br>
+ "checks if string2 is a byteobject and get its size in bytes"<br>
+ self genGetFormatOf: string2Reg into: TempReg.<br>
+ cogit CmpCq: objectMemory firstByteFormat R: TempReg.<br>
+ jumpIncorrectFormat3 := cogit JumpLess: 0.<br>
+ cogit CmpCq: objectMemory firstCompiledMethodFormat R: TempReg.<br>
+ jumpIncorrectFormat4 := cogit JumpAboveOrEqual: 0.<br>
+ <br>
+ self genGetNumSlotsOf: string2Reg into: string2CharOrByteSizeReg.<br>
+ (cogit LogicalShiftLeftCq: objectMemory shiftForWord R: string2CharOrByteSizeReg).<br>
+ cogit AndCq: objectMemory wordSize - 1 R: TempReg R: TempReg.<br>
+ cogit SubR: TempReg R: string2CharOrByteSizeReg.<br>
+ <br>
+ "Type and number of arguments are correct"<br>
+ "Compute the min" <br>
+ cogit CmpR: string1CharOrByteSizeReg R: string2CharOrByteSizeReg.<br>
+ jumpAbove := cogit JumpBelow: 0. <br>
+ cogit MoveR: string1CharOrByteSizeReg R: minSizeReg. <br>
+ jump := cogit Jump: 0. <br>
+ jumpAbove jmpTarget: (cogit MoveR: string2CharOrByteSizeReg R: minSizeReg). <br>
+ jump jmpTarget: (cogit CmpCq: 0 R: minSizeReg). <br>
+ jumpSuccess := cogit JumpZero: 0. "if one of the string is empty, no need to go through the comparing loop"<br>
+ <br>
+ "Compare the bytes"<br>
+ cogit MoveCq: objectMemory baseHeaderSize R: TempReg.<br>
+ cogit AddCq: objectMemory baseHeaderSize R: minSizeReg.<br>
+ <br>
+ instr := cogit MoveXbr: TempReg R: string1Reg R: string1CharOrByteSizeReg.<br>
+ cogit MoveXbr: TempReg R: string2Reg R: string2CharOrByteSizeReg.<br>
+ cogit SubR: string2CharOrByteSizeReg R: string1CharOrByteSizeReg. <br>
+ jumpMidFailure := cogit JumpNonZero: 0. "the 2 compared characters are different, exit the loop"<br>
+ cogit AddCq: 1 R: TempReg.<br>
+ cogit CmpR: TempReg R: minSizeReg. <br>
+ cogit JumpNonZero: instr.<br>
+ <br>
+ "all bytes from 1 to minSize are equal"<br>
+ self genGetNumBytesOf: string1Reg into: string1CharOrByteSizeReg.<br>
+ self genGetNumBytesOf: string2Reg into: string2CharOrByteSizeReg.<br>
+ jumpSuccess jmpTarget: (cogit SubR: string2CharOrByteSizeReg R: string1CharOrByteSizeReg).<br>
+ jumpMidFailure jmpTarget: (cogit MoveR: string1CharOrByteSizeReg R: ReceiverResultReg). <br>
+ self genConvertIntegerToSmallIntege<wbr>rInReg: ReceiverResultReg.<br>
+ cogit genPrimReturn.<br>
+ <br>
+ jumpIncorrectFormat4 <br>
+ jmpTarget: (jumpIncorrectFormat3 <br>
+ jmpTarget: (jumpIncorrectFormat2 <br>
+ jmpTarget: (jumpIncorrectFormat1 jmpTarget: cogit Label))).<br>
+ <br>
+ ^ CompletePrimitive!<br>
<br>
Item was changed:<br>
----- Method: Interpreter class>><wbr>initializePrimitiveTable (in category 'initialization') -----<br>
(excessive size, no diff calculated)<br>
<br>
Item was added:<br>
+ ----- Method: InterpreterPrimitives>><wbr>primitiveCompareWith (in category 'string primitives') -----<br>
+ primitiveCompareWith<br>
+ "<string1> primitiveCompareWith: string2 [collated: order] "<br>
+ <export: true><br>
+ <br>
+ | string1 string2 order strLength1 strLength2 result |<br>
+ <br>
+ "1 - fetch the parameters from the stack" <br>
+ (argumentCount = 0 or: [argumentCount > 2]) ifTrue:<br>
+ [^self primitiveFailFor: PrimErrBadNumArgs].<br>
+ argumentCount = 1<br>
+ ifFalse: "argCount must be 2"<br>
+ [order := self stackTop.<br>
+ (objectMemory isBytes: order) ifFalse: [^self primitiveFailFor: PrimErrBadArgument]].<br>
+ string1 := self stackValue: argumentCount.<br>
+ string2 := self stackValue: argumentCount - 1. <br>
+ <br>
+ "2 - check their types - all parameters are ByteObject"<br>
+ ((objectMemory isBytes: string1)<br>
+ and: [objectMemory isBytes: string2 ])<br>
+ ifFalse: <br>
+ [^self primitiveFailFor: PrimErrBadArgument].<br>
+ <br>
+ "3 - compare the strings" <br>
+ strLength1 := objectMemory numBytesOfBytes: string1.<br>
+ strLength2 := objectMemory numBytesOfBytes: string2.<br>
+ result := order <br>
+ ifNil: [self rawCompare: string1 length: strLength1 with: string2 length: strLength2 accessBlock: [:str :index | objectMemory fetchByte: index ofObject: str ]]<br>
+ ifNotNil: <br>
+ [self rawCompare: string1 length: strLength1 with: string2 length: strLength2 accessBlock: [:str :index | objectMemory fetchByte: (objectMemory fetchByte: index ofObject: str) +1 ofObject: order ]].<br>
+ self pop: argumentCount + 1 thenPush: (objectMemory integerObjectOf: result)<br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ !<br>
<br>
Item was added:<br>
+ ----- Method: InterpreterPrimitives>><wbr>rawCompare:length:with:length:<wbr>accessBlock: (in category 'string primitives') -----<br>
+ rawCompare: string1 length: strLength1 with: string2 length: strLength2 accessBlock: accessBlock<br>
+ | c1 c2 min |<br>
+ <inline: true> "needs to be forced else slang does not inline it by default"<br>
+ min := strLength1 min: strLength2.<br>
+ 0 to: min-1 do: <br>
+ [:i | c1 := accessBlock value: string1 value: i.<br>
+ c2 := accessBlock value: string2 value: i.<br>
+ c1 = c2 ifFalse: [^c1 - c2]].<br>
+ ^strLength1 - strLength2<br>
+ <br>
+ <br>
+ <br>
+ <br>
+ !<br>
<br>
Item was changed:<br>
----- Method: SimpleStackBasedCogit class>><wbr>initializePrimitiveTableForSqu<wbr>eak (in category 'class initialization') -----<br>
initializePrimitiveTableForSqu<wbr>eak<br>
"Initialize the table of primitive generators. This does not include normal primitives implemented in the coInterpreter.<br>
N.B. primitives that don't have an explicit arg count (the integer following the generator) may be variadic."<br>
"SimpleStackBasedCogit initializePrimitiveTableForSqu<wbr>eak"<br>
MaxCompiledPrimitiveIndex := self objectRepresentationClass wordSize = 8<br>
ifTrue: [555]<br>
ifFalse: [222].<br>
primitiveTable := CArrayAccessor on: (Array new: MaxCompiledPrimitiveIndex + 1).<br>
self table: primitiveTable from: <br>
#( "Integer Primitives (0-19)"<br>
(1 genPrimitiveAdd 1)<br>
(2 genPrimitiveSubtract 1)<br>
(3 genPrimitiveLessThan 1)<br>
(4 genPrimitiveGreaterThan 1)<br>
(5 genPrimitiveLessOrEqual 1)<br>
(6 genPrimitiveGreaterOrEqual 1)<br>
(7 genPrimitiveEqual 1)<br>
(8 genPrimitiveNotEqual 1)<br>
(9 genPrimitiveMultiply 1)<br>
(10 genPrimitiveDivide 1)<br>
(11 genPrimitiveMod 1)<br>
(12 genPrimitiveDiv 1)<br>
(13 genPrimitiveQuo 1)<br>
(14 genPrimitiveBitAnd 1)<br>
(15 genPrimitiveBitOr 1)<br>
(16 genPrimitiveBitXor 1)<br>
(17 genPrimitiveBitShift 1)<br>
"(18 primitiveMakePoint)"<br>
"(19 primitiveFail)" "Guard primitive for simulation -- *must* fail"<br>
<br>
"LargeInteger Primitives (20-39)"<br>
"(20 primitiveFail)"<br>
"(21 primitiveAddLargeIntegers)"<br>
"(22 primitiveSubtractLargeIntegers<wbr>)"<br>
"(23 primitiveLessThanLargeIntegers<wbr>)"<br>
"(24 primitiveGreaterThanLargeInteg<wbr>ers)"<br>
"(25 primitiveLessOrEqualLargeInteg<wbr>ers)"<br>
"(26 primitiveGreaterOrEqualLargeIn<wbr>tegers)"<br>
"(27 primitiveEqualLargeIntegers)"<br>
"(28 primitiveNotEqualLargeIntegers<wbr>)"<br>
"(29 primitiveMultiplyLargeIntegers<wbr>)"<br>
"(30 primitiveDivideLargeIntegers)"<br>
"(31 primitiveModLargeIntegers)"<br>
"(32 primitiveDivLargeIntegers)"<br>
"(33 primitiveQuoLargeIntegers)"<br>
"(34 primitiveBitAndLargeIntegers)"<br>
"(35 primitiveBitOrLargeIntegers)"<br>
"(36 primitiveBitXorLargeIntegers)"<br>
"(37 primitiveBitShiftLargeIntegers<wbr>)"<br>
<br>
"Float Primitives (38-59)"<br>
"(38 genPrimitiveFloatAt)"<br>
"(39 genPrimitiveFloatAtPut)"<br>
(40 genPrimitiveAsFloat 0)<br>
(41 genPrimitiveFloatAdd 1)<br>
(42 genPrimitiveFloatSubtract 1)<br>
(43 genPrimitiveFloatLessThan 1)<br>
(44 genPrimitiveFloatGreaterThan 1)<br>
(45 genPrimitiveFloatLessOrEqual 1)<br>
(46 genPrimitiveFloatGreaterOrEqua<wbr>l 1)<br>
(47 genPrimitiveFloatEqual 1)<br>
(48 genPrimitiveFloatNotEqual 1)<br>
(49 genPrimitiveFloatMultiply 1)<br>
(50 genPrimitiveFloatDivide 1)<br>
"(51 genPrimitiveTruncated)"<br>
"(52 genPrimitiveFractionalPart)"<br>
"(53 genPrimitiveExponent)"<br>
"(54 genPrimitiveTimesTwoPower)"<br>
(55 genPrimitiveFloatSquareRoot 0)<br>
"(56 genPrimitiveSine)"<br>
"(57 genPrimitiveArctan)"<br>
"(58 genPrimitiveLogN)"<br>
"(59 genPrimitiveExp)"<br>
<br>
"Subscript and Stream Primitives (60-67)"<br>
(60 genPrimitiveAt 1)<br>
(61 genPrimitiveAtPut 2)<br>
(62 genPrimitiveSize 0)<br>
(63 genPrimitiveStringAt 1)<br>
(64 genPrimitiveStringAtPut 2)<br>
"The stream primitives no longer pay their way; normal Smalltalk code is faster."<br>
(65 genFastPrimFail)"was primitiveNext"<br>
(66 genFastPrimFail) "was primitiveNextPut"<br>
(67 genFastPrimFail) "was primitiveAtEnd"<br>
<br>
"StorageManagement Primitives (68-79)"<br>
(68 genPrimitiveObjectAt 1) "Good for debugger/InstructionStream performance"<br>
"(69 primitiveObjectAtPut)"<br>
(70 genPrimitiveNew 0)<br>
(71 genPrimitiveNewWithArg 1)<br>
"(72 primitiveArrayBecomeOneWay)" "Blue Book: primitiveBecome"<br>
"(73 primitiveInstVarAt)"<br>
"(74 primitiveInstVarAtPut)"<br>
(75 genPrimitiveIdentityHash 0)<br>
"(76 primitiveStoreStackp)" "Blue Book: primitiveAsObject"<br>
"(77 primitiveSomeInstance)"<br>
"(78 primitiveNextInstance)"<br>
(79 genPrimitiveNewMethod 2)<br>
<br>
"Control Primitives (80-89)"<br>
"(80 primitiveFail)" "Blue Book: primitiveBlockCopy"<br>
"(81 primitiveFail)" "Blue Book: primitiveValue"<br>
"(82 primitiveFail)" "Blue Book: primitiveValueWithArgs"<br>
(83 genPrimitivePerform)<br>
"(84 primitivePerformWithArgs)"<br>
"(85 primitiveSignal)"<br>
"(86 primitiveWait)"<br>
"(87 primitiveResume)"<br>
"(88 primitiveSuspend)"<br>
"(89 primitiveFlushCache)"<br>
<br>
"(90 primitiveMousePoint)"<br>
"(91 primitiveTestDisplayDepth)" "Blue Book: primitiveCursorLocPut"<br>
"(92 primitiveSetDisplayMode)" "Blue Book: primitiveCursorLink"<br>
"(93 primitiveInputSemaphore)"<br>
"(94 primitiveGetNextEvent)" "Blue Book: primitiveSampleInterval"<br>
"(95 primitiveInputWord)"<br>
"(96 primitiveFail)" "primitiveCopyBits"<br>
"(97 primitiveSnapshot)"<br>
"(98 primitiveStoreImageSegment)"<br>
"(99 primitiveLoadImageSegment)"<br>
"(100 primitivePerformInSuperclass)" "Blue Book: primitiveSignalAtTick"<br>
"(101 primitiveBeCursor)"<br>
"(102 primitiveBeDisplay)"<br>
"(103 primitiveScanCharacters)"<br>
"(104 primitiveFail)" "primitiveDrawLoop"<br>
(105 genPrimitiveStringReplace)<br>
"(106 primitiveScreenSize)"<br>
"(107 primitiveMouseButtons)"<br>
"(108 primitiveKbdNext)"<br>
"(109 primitiveKbdPeek)"<br>
<br>
<br>
"System Primitives (110-119)"<br>
(110 genPrimitiveIdentical 1)<br>
(111 genPrimitiveClass) "Support both class and Context>>objectClass:"<br>
"(112 primitiveBytesLeft)"<br>
"(113 primitiveQuit)"<br>
"(114 primitiveExitToDebugger)"<br>
"(115 primitiveChangeClass)" "Blue Book: primitiveOopsLeft"<br>
"(116 primitiveFlushCacheByMethod)"<br>
"(117 primitiveExternalCall)"<br>
"(118 primitiveDoPrimitiveWithArgs)"<br>
"(119 primitiveFlushCacheSelective)"<br>
<br>
(148 genPrimitiveShallowCopy 0) "a.k.a. clone"<br>
<br>
+ (158 genPrimitiveStringCompareWith 1)<br>
(159 genPrimitiveHashMultiply 0)<br>
<br>
(169 genPrimitiveNotIdentical 1)<br>
<br>
(170 genPrimitiveAsCharacter) "SmallInteger>>asCharacter, Character class>>value:"<br>
(171 genPrimitiveImmediateAsInteger 0) "Character>>value SmallFloat64>>asInteger"<br>
<br>
"(173 primitiveSlotAt 1)"<br>
"(174 primitiveSlotAtPut 2)"<br>
(175 genPrimitiveIdentityHash 0) "Behavior>>identityHash"<br>
<br>
"Old closure primitives"<br>
"(186 primitiveFail)" "was primitiveClosureValue"<br>
"(187 primitiveFail)" "was primitiveClosureValueWithArgs"<br>
<br>
"Perform method directly"<br>
"(188 primitiveExecuteMethodArgsArra<wbr>y)"<br>
"(189 primitiveExecuteMethod)"<br>
<br>
"Unwind primitives"<br>
"(195 primitiveFindNextUnwindContext<wbr>)"<br>
"(196 primitiveTerminateTo)"<br>
"(197 primitiveFindHandlerContext)"<br>
(198 genFastPrimFail "primitiveMarkUnwindMethod")<br>
(199 genFastPrimFail "primitiveMarkHandlerMethod")<br>
<br>
"new closure primitives"<br>
"(200 primitiveClosureCopyWithCopied<wbr>Values)"<br>
(201 genPrimitiveClosureValue 0) "value"<br>
(202 genPrimitiveClosureValue 1) "value:"<br>
(203 genPrimitiveClosureValue 2) "value:value:"<br>
(204 genPrimitiveClosureValue 3) "value:value:value:"<br>
(205 genPrimitiveClosureValue 4) "value:value:value:value:"<br>
"(206 genPrimitiveClosureValueWithAr<wbr>gs)" "valueWithArguments:"<br>
<br>
(207 genPrimitiveFullClosureValue) "value[:value:value:value:] et al"<br>
"(208 genPrimitiveFullClosureValueWi<wbr>thArgs)" "valueWithArguments:"<br>
(209 genPrimitiveFullClosureValue) "valueNoContextSwitch[:value:] et al"<br>
<br>
"(210 primitiveContextAt)"<br>
"(211 primitiveContextAtPut)"<br>
"(212 primitiveContextSize)"<br>
<br>
"(218 primitiveDoNamedPrimitiveWithA<wbr>rgs)"<br>
"(219 primitiveFail)" "reserved for Cog primitives"<br>
<br>
"(220 primitiveFail)" "reserved for Cog primitives"<br>
<br>
(221 genPrimitiveClosureValue 0) "valueNoContextSwitch"<br>
(222 genPrimitiveClosureValue 1) "valueNoContextSwitch:"<br>
<br>
"SmallFloat primitives (540-559)"<br>
(541 genPrimitiveSmallFloatAdd 1)<br>
(542 genPrimitiveSmallFloatSubtract 1)<br>
(543 genPrimitiveSmallFloatLessThan 1)<br>
(544 genPrimitiveSmallFloatGreaterT<wbr>han 1)<br>
(545 genPrimitiveSmallFloatLessOrEq<wbr>ual 1)<br>
(546 genPrimitiveSmallFloatGreaterO<wbr>rEqual 1)<br>
(547 genPrimitiveSmallFloatEqual 1)<br>
(548 genPrimitiveSmallFloatNotEqual 1)<br>
(549 genPrimitiveSmallFloatMultiply 1)<br>
(550 genPrimitiveSmallFloatDivide 1)<br>
"(551 genPrimitiveSmallFloatTruncate<wbr>d 0)"<br>
"(552 genPrimitiveSmallFloatFraction<wbr>alPart 0)"<br>
"(553 genPrimitiveSmallFloatExponent 0)"<br>
"(554 genPrimitiveSmallFloatTimesTwo<wbr>Power 1)"<br>
(555 genPrimitiveSmallFloatSquareRo<wbr>ot 0)<br>
"(556 genPrimitiveSmallFloatSine 0)"<br>
"(557 genPrimitiveSmallFloatArctan 0)"<br>
"(558 genPrimitiveSmallFloatLogN 0)"<br>
"(559 genPrimitiveSmallFloatExp 0)"<br>
)!<br>
<br>
Item was changed:<br>
----- Method: StackInterpreter class>><wbr>initializePrimitiveTable (in category 'initialization') -----<br>
(excessive size, no diff calculated)<br>
<br>
</blockquote></div><br></div>