[Vm-dev] VM Maker: VMMaker.oscog-eem.141.mcz
commits at source.squeak.org
commits at source.squeak.org
Tue Jan 24 22:51:29 UTC 2012
Eliot Miranda uploaded a new version of VMMaker to project VM Maker:
http://source.squeak.org/VMMaker/VMMaker.oscog-eem.141.mcz
==================== Summary ====================
Name: VMMaker.oscog-eem.141
Author: eem
Time: 24 January 2012, 2:49:19.653 pm
UUID: 8dc3fa63-a227-4a8b-9f98-ba759064d001
Ancestors: VMMaker.oscog-eem.140
Add some coverage analysis to check for unimplemented opcodes
in the Cogit. Implement AndCwR & OrCwR in CogIA32Compiler.
=============== Diff against VMMaker.oscog-eem.140 ===============
Item was added:
+ ----- Method: CogAbstractInstruction class>>specificOpcodes (in category 'verification') -----
+ specificOpcodes
+ ^self subclassResponsibility!
Item was added:
+ ----- Method: CogAbstractInstruction class>>unimplementedOpcodes (in category 'verification') -----
+ unimplementedOpcodes
+ "Check computeMaximumSize and dispatchConcretize for unimplemented opcodes."
+ "self subclasses collect: [:compiler| {compiler. compiler unimplementedOpcodes}]"
+ | opcodes cmsLiterals dcLiterals |
+ opcodes := CogRTLOpcodes opcodes, self specificOpcodes.
+ cmsLiterals := (self >> #computeMaximumSize) literals
+ select: [:l| l isVariableBinding]
+ thenCollect: [:l| l key].
+ dcLiterals := (self >> #dispatchConcretize) literals
+ select: [:l| l isVariableBinding]
+ thenCollect: [:l| l key].
+ ^Dictionary new
+ at: #computeMaximumSize put: (opcodes reject: [:opcode| cmsLiterals includes: opcode]);
+ at: #dispatchConcretize put: (opcodes reject: [:opcode| dcLiterals includes: opcode]);
+ yourself!
Item was added:
+ ----- Method: CogAbstractInstruction class>>usedUnimplementedOpcodes (in category 'verification') -----
+ usedUnimplementedOpcodes
+ "Check for uses of unimplemented opcodes"
+ "self subclasses collect: [:compiler| {compiler. compiler usedUnimplementedOpcodes}]"
+ | genericUnimplementedOpcodeBindings specificUnimplementedOpcodeBindings |
+ genericUnimplementedOpcodeBindings := Set new.
+ specificUnimplementedOpcodeBindings := Set new.
+ self unimplementedOpcodes do:
+ [:arrayOfOpcodes|
+ arrayOfOpcodes do:
+ [:opcode|
+ (self bindingOf: opcode)
+ ifNotNil: [:b| specificUnimplementedOpcodeBindings add: b]
+ ifNil: [genericUnimplementedOpcodeBindings add: (CogRTLOpcodes bindingOf: opcode)]]].
+ ^ { (SystemNavigation new allCallsOn: genericUnimplementedOpcodeBindings localToPackage: #VMMaker)
+ inject: Set new
+ into: [:them :methodRef| "These should be in Cogit's abstract instructions category"
+ them
+ addAll: (SystemNavigation new allCallsOn: methodRef method selector localToPackage: #VMMaker);
+ yourself].
+ SystemNavigation new allCallsOn: specificUnimplementedOpcodeBindings localToPackage: #VMMaker }!
Item was added:
+ ----- Method: CogIA32Compiler class>>specificOpcodes (in category 'verification') -----
+ specificOpcodes
+ "Answer the processor-specific opcodes for this class.
+ They're all in an Array literal in the initialize method."
+ ^(self class >> #initialize) literals detect: [:l| l isArray and: [l includes: #LOCK]]!
Item was changed:
----- Method: CogIA32Compiler>>computeMaximumSize (in category 'generate machine code') -----
computeMaximumSize
"Compute the maximum size for each opcode. This allows jump offsets to
be determined, provided that all backward branches are long branches."
"N.B. The ^maxSize := N forms are to get around the compiler's long branch
limits which are exceeded when each case jumps around the otherwise."
opcode caseOf: {
"Noops & Pseudo Ops"
[Label] -> [^maxSize := 0].
[AlignmentNops] -> [^maxSize := (operands at: 0) - 1].
[Fill16] -> [^maxSize := 2].
[Fill32] -> [^maxSize := 4].
[FillFromWord] -> [^maxSize := 4].
[Nop] -> [^maxSize := 1].
"Specific Control/Data Movement"
[CDQ] -> [^maxSize := 1].
[IDIVR] -> [^maxSize := 2].
[IMULRR] -> [^maxSize := 3].
[CPUID] -> [^maxSize := 2].
[CMPXCHGAwR] -> [^maxSize := 7].
[CMPXCHGMwrR] -> [^maxSize := 8].
[LFENCE] -> [^maxSize := 3].
[MFENCE] -> [^maxSize := 3].
[SFENCE] -> [^maxSize := 3].
[LOCK] -> [^maxSize := 1].
[XCHGAwR] -> [^maxSize := 6].
[XCHGMwrR] -> [^maxSize := 7].
[XCHGRR] -> [^maxSize := 2].
"Control"
[Call] -> [^maxSize := 5].
[JumpR] -> [^maxSize := 2].
[Jump] -> [self resolveJumpTarget. ^maxSize := 5].
[JumpLong] -> [self resolveJumpTarget. ^maxSize := 5].
[JumpZero] -> [self resolveJumpTarget. ^maxSize := 6].
[JumpNonZero] -> [self resolveJumpTarget. ^maxSize := 6].
[JumpNegative] -> [self resolveJumpTarget. ^maxSize := 6].
[JumpNonNegative] -> [self resolveJumpTarget. ^maxSize := 6].
[JumpOverflow] -> [self resolveJumpTarget. ^maxSize := 6].
[JumpNoOverflow] -> [self resolveJumpTarget. ^maxSize := 6].
[JumpCarry] -> [self resolveJumpTarget. ^maxSize := 6].
[JumpNoCarry] -> [self resolveJumpTarget. ^maxSize := 6].
[JumpLess] -> [self resolveJumpTarget. ^maxSize := 6].
[JumpGreaterOrEqual] -> [self resolveJumpTarget. ^maxSize := 6].
[JumpGreater] -> [self resolveJumpTarget. ^maxSize := 6].
[JumpLessOrEqual] -> [self resolveJumpTarget. ^maxSize := 6].
[JumpBelow] -> [self resolveJumpTarget. ^maxSize := 6].
[JumpAboveOrEqual] -> [self resolveJumpTarget. ^maxSize := 6].
[JumpAbove] -> [self resolveJumpTarget. ^maxSize := 6].
[JumpBelowOrEqual] -> [self resolveJumpTarget. ^maxSize := 6].
[JumpLongZero] -> [self resolveJumpTarget. ^maxSize := 6].
[JumpLongNonZero] -> [self resolveJumpTarget. ^maxSize := 6].
[JumpFPEqual] -> [self resolveJumpTarget. ^maxSize := 6].
[JumpFPNotEqual] -> [self resolveJumpTarget. ^maxSize := 6].
[JumpFPLess] -> [self resolveJumpTarget. ^maxSize := 6].
[JumpFPGreaterOrEqual] -> [self resolveJumpTarget. ^maxSize := 6].
[JumpFPGreater] -> [self resolveJumpTarget. ^maxSize := 6].
[JumpFPLessOrEqual] -> [self resolveJumpTarget. ^maxSize := 6].
[JumpFPOrdered] -> [self resolveJumpTarget. ^maxSize := 6].
[JumpFPUnordered] -> [self resolveJumpTarget. ^maxSize := 6].
[RetN] -> [^maxSize := (operands at: 0) = 0
ifTrue: [1]
ifFalse: [3]].
"Arithmetic"
[AddCqR] -> [^maxSize := (self isQuick: (operands at: 0))
ifTrue: [3]
ifFalse: [(self concreteRegister: (operands at: 1)) = EAX
ifTrue: [5]
ifFalse: [6]]].
[AndCqR] -> [^maxSize := (self isQuick: (operands at: 0))
ifTrue: [3]
ifFalse: [(self concreteRegister: (operands at: 1)) = EAX
ifTrue: [5]
ifFalse: [6]]].
[CmpCqR] -> [^maxSize := (self isQuick: (operands at: 0))
ifTrue: [3]
ifFalse: [(self concreteRegister: (operands at: 1)) = EAX
ifTrue: [5]
ifFalse: [6]]].
[OrCqR] -> [^maxSize := (self isQuick: (operands at: 0))
ifTrue: [3]
ifFalse: [(self concreteRegister: (operands at: 1)) = EAX
ifTrue: [5]
ifFalse: [6]]].
[SubCqR] -> [^maxSize := (self isQuick: (operands at: 0))
ifTrue: [3]
ifFalse: [(self concreteRegister: (operands at: 1)) = EAX
ifTrue: [5]
ifFalse: [6]]].
[AddCwR] -> [^maxSize := (self concreteRegister: (operands at: 1)) = EAX
ifTrue: [5]
ifFalse: [6]].
+ [AndCwR] -> [^maxSize := (self concreteRegister: (operands at: 1)) = EAX
+ ifTrue: [5]
+ ifFalse: [6]].
[CmpCwR] -> [^maxSize := (self concreteRegister: (operands at: 1)) = EAX
ifTrue: [5]
ifFalse: [6]].
+ [OrCwR] -> [^maxSize := (self concreteRegister: (operands at: 1)) = EAX
+ ifTrue: [5]
+ ifFalse: [6]].
[SubCwR] -> [^maxSize := (self concreteRegister: (operands at: 1)) = EAX
ifTrue: [5]
ifFalse: [6]].
[XorCwR] -> [^maxSize := (self concreteRegister: (operands at: 1)) = EAX
ifTrue: [5]
ifFalse: [6]].
[AddRR] -> [^maxSize := 2].
[AndRR] -> [^maxSize := 2].
[CmpRR] -> [^maxSize := 2].
[OrRR] -> [^maxSize := 2].
[XorRR] -> [^maxSize := 2].
[SubRR] -> [^maxSize := 2].
[NegateR] -> [^maxSize := 2].
[LoadEffectiveAddressMwrR]
-> [^maxSize := ((self isQuick: (operands at: 0))
ifTrue: [3]
ifFalse: [6])
+ ((self concreteRegister: (operands at: 1)) = ESP
ifTrue: [1]
ifFalse: [0])].
[LogicalShiftLeftCqR] -> [^maxSize := (operands at: 0) = 1
ifTrue: [2]
ifFalse: [3]].
[LogicalShiftRightCqR] -> [^maxSize := (operands at: 0) = 1
ifTrue: [2]
ifFalse: [3]].
[ArithmeticShiftRightCqR] -> [^maxSize := (operands at: 0) = 1
ifTrue: [2]
ifFalse: [3]].
[LogicalShiftLeftRR] -> [self computeShiftRRSize].
[LogicalShiftRightRR] -> [self computeShiftRRSize].
[ArithmeticShiftRightRR] -> [self computeShiftRRSize].
[AddRdRd] -> [^maxSize := 4].
[CmpRdRd] -> [^maxSize := 4].
[SubRdRd] -> [^maxSize := 4].
[MulRdRd] -> [^maxSize := 4].
[DivRdRd] -> [^maxSize := 4].
[SqrtRd] -> [^maxSize := 4].
"Data Movement"
[MoveCqR] -> [^maxSize := (operands at: 0) = 0 ifTrue: [2] ifFalse: [5]].
[MoveCwR] -> [^maxSize := 5].
[MoveRR] -> [^maxSize := 2].
+ [MoveRdRd] -> [^maxSize := 4].
[MoveAwR] -> [^maxSize := (self concreteRegister: (operands at: 1)) = EAX
ifTrue: [5]
ifFalse: [6]].
[MoveRAw] -> [^maxSize := (self concreteRegister: (operands at: 0)) = EAX
ifTrue: [5]
ifFalse: [6]].
[MoveRMwr] -> [^maxSize := ((self isQuick: (operands at: 1))
ifTrue: [3]
ifFalse: [6])
+ ((self concreteRegister: (operands at: 2)) = ESP
ifTrue: [1]
ifFalse: [0])].
[MoveRdM64r] -> [^maxSize := ((self isQuick: (operands at: 1))
ifTrue: [5]
ifFalse: [8])
+ ((self concreteRegister: (operands at: 2)) = ESP
ifTrue: [1]
ifFalse: [0])].
[MoveMbrR] -> [^maxSize := ((self isQuick: (operands at: 0))
ifTrue: [3]
ifFalse: [6])
+ ((self concreteRegister: (operands at: 1)) = ESP
ifTrue: [1]
ifFalse: [0])].
[MoveRMbr] -> [^maxSize := ((self isQuick: (operands at: 1))
ifTrue: [3]
ifFalse: [6])
+ ((self concreteRegister: (operands at: 2)) = ESP
ifTrue: [1]
ifFalse: [0])].
[MoveM16rR] -> [^maxSize := ((self isQuick: (operands at: 0))
ifTrue: [4]
ifFalse: [7])
+ ((self concreteRegister: (operands at: 1)) = ESP
ifTrue: [1]
ifFalse: [0])].
[MoveM64rRd] -> [^maxSize := ((self isQuick: (operands at: 0))
ifTrue: [5]
ifFalse: [8])
+ ((self concreteRegister: (operands at: 1)) = ESP
ifTrue: [1]
ifFalse: [0])].
[MoveMwrR] -> [^maxSize := ((self isQuick: (operands at: 0))
ifTrue: [3]
ifFalse: [6])
+ ((self concreteRegister: (operands at: 1)) = ESP
ifTrue: [1]
ifFalse: [0])].
[MoveXbrRR] -> [self assert: (self concreteRegister: (operands at: 0)) ~= ESP.
^maxSize := (self concreteRegister: (operands at: 1)) = EBP
ifTrue: [5]
ifFalse: [4]].
[MoveXwrRR] -> [self assert: (self concreteRegister: (operands at: 0)) ~= ESP.
^maxSize := (self concreteRegister: (operands at: 1)) = EBP
ifTrue: [4]
ifFalse: [3]].
[MoveRXwrR] -> [self assert: (self concreteRegister: (operands at: 1)) ~= ESP.
^maxSize := (self concreteRegister: (operands at: 2)) = EBP
ifTrue: [4]
ifFalse: [3]].
[PopR] -> [^maxSize := 1].
[PushR] -> [^maxSize := 1].
[PushCw] -> [^maxSize := 5].
[PrefetchAw] -> [^maxSize := self hasSSEInstructions ifTrue: [7] ifFalse: [0]].
"Conversion"
[ConvertRRd] -> [^maxSize := 4] }.
^0 "to keep C compiler quiet"!
Item was added:
+ ----- Method: CogIA32Compiler>>concretizeAndCwR (in category 'generate machine code') -----
+ concretizeAndCwR
+ "Will get inlined into concretizeAt: switch."
+ <inline: true>
+ | value reg |
+ value := operands at: 0.
+ reg := self concreteRegister: (operands at: 1).
+ reg = EAX ifTrue:
+ [machineCode
+ at: 0 put: 16r25;
+ at: 1 put: (value bitAnd: 16rFF);
+ at: 2 put: (value >> 8 bitAnd: 16rFF);
+ at: 3 put: (value >> 16 bitAnd: 16rFF);
+ at: 4 put: (value >> 24 bitAnd: 16rFF).
+ ^machineCodeSize := 5].
+ machineCode
+ at: 0 put: 16r83;
+ at: 1 put: (self mod: ModReg RM: reg RO: 4);
+ at: 2 put: (value bitAnd: 16rFF);
+ at: 3 put: (value >> 8 bitAnd: 16rFF);
+ at: 4 put: (value >> 16 bitAnd: 16rFF);
+ at: 5 put: (value >> 24 bitAnd: 16rFF).
+ ^machineCodeSize := 6!
Item was added:
+ ----- Method: CogIA32Compiler>>concretizeOrCwR (in category 'generate machine code') -----
+ concretizeOrCwR
+ "Will get inlined into concretizeAt: switch."
+ <inline: true>
+ | value reg |
+ value := operands at: 0.
+ reg := self concreteRegister: (operands at: 1).
+ reg = EAX ifTrue:
+ [machineCode
+ at: 0 put: 16r0D;
+ at: 1 put: (value bitAnd: 16rFF);
+ at: 2 put: (value >> 8 bitAnd: 16rFF);
+ at: 3 put: (value >> 16 bitAnd: 16rFF);
+ at: 4 put: (value >> 24 bitAnd: 16rFF).
+ ^machineCodeSize := 5].
+ machineCode
+ at: 0 put: 16r83;
+ at: 1 put: (self mod: ModReg RM: reg RO: 1);
+ at: 2 put: (value bitAnd: 16rFF);
+ at: 3 put: (value >> 8 bitAnd: 16rFF);
+ at: 4 put: (value >> 16 bitAnd: 16rFF);
+ at: 5 put: (value >> 24 bitAnd: 16rFF).
+ ^machineCodeSize := 6!
Item was changed:
----- Method: CogIA32Compiler>>dispatchConcretize (in category 'generate machine code') -----
dispatchConcretize
"Attempt to generate concrete machine code for the instruction at address.
This is the inner dispatch of concretizeAt: actualAddress which exists only
to get around the branch size limits in the SqueakV3 (blue book derived)
bytecode set."
opcode caseOf: {
"Noops & Pseudo Ops"
[Label] -> [^self concretizeLabel].
[AlignmentNops] -> [^self concretizeAlignmentNops].
[Fill16] -> [^self concretizeFill16].
[Fill32] -> [^self concretizeFill32].
[FillFromWord] -> [^self concretizeFillFromWord].
[Nop] -> [^self concretizeNop].
"Specific Control/Data Movement"
[CDQ] -> [^self concretizeCDQ].
[IDIVR] -> [^self concretizeIDIVR].
[IMULRR] -> [^self concretizeMulRR].
[CPUID] -> [^self concretizeCPUID].
[CMPXCHGAwR] -> [^self concretizeCMPXCHGAwR].
[CMPXCHGMwrR] -> [^self concretizeCMPXCHGMwrR].
[LFENCE] -> [^self concretizeFENCE: 5].
[MFENCE] -> [^self concretizeFENCE: 6].
[SFENCE] -> [^self concretizeFENCE: 7].
[LOCK] -> [^self concretizeLOCK].
[XCHGAwR] -> [^self concretizeXCHGAwR].
[XCHGMwrR] -> [^self concretizeXCHGMwrR].
[XCHGRR] -> [^self concretizeXCHGRR].
"Control"
[Call] -> [^self concretizeCall].
[JumpR] -> [^self concretizeJumpR].
[JumpLong] -> [^self concretizeJumpLong].
[JumpLongZero] -> [^self concretizeConditionalJumpLong: 16r4].
[JumpLongNonZero] -> [^self concretizeConditionalJumpLong: 16r5].
[Jump] -> [^self concretizeJump].
"Table B-1 Intel® 64 and IA-32 Architectures Software Developer's Manual Volume 1: Basic Architecture"
[JumpZero] -> [^self concretizeConditionalJump: 16r4].
[JumpNonZero] -> [^self concretizeConditionalJump: 16r5].
[JumpNegative] -> [^self concretizeConditionalJump: 16r8].
[JumpNonNegative] -> [^self concretizeConditionalJump: 16r9].
[JumpOverflow] -> [^self concretizeConditionalJump: 16r0].
[JumpNoOverflow] -> [^self concretizeConditionalJump: 16r1].
[JumpCarry] -> [^self concretizeConditionalJump: 16r2].
[JumpNoCarry] -> [^self concretizeConditionalJump: 16r3].
[JumpLess] -> [^self concretizeConditionalJump: 16rC].
[JumpGreaterOrEqual] -> [^self concretizeConditionalJump: 16rD].
[JumpGreater] -> [^self concretizeConditionalJump: 16rF].
[JumpLessOrEqual] -> [^self concretizeConditionalJump: 16rE].
[JumpBelow] -> [^self concretizeConditionalJump: 16r2].
[JumpAboveOrEqual] -> [^self concretizeConditionalJump: 16r3].
[JumpAbove] -> [^self concretizeConditionalJump: 16r7].
[JumpBelowOrEqual] -> [^self concretizeConditionalJump: 16r6].
[JumpFPEqual] -> [^self concretizeConditionalJump: 16r4].
[JumpFPNotEqual] -> [^self concretizeConditionalJump: 16r5].
[JumpFPLess] -> [^self concretizeConditionalJump: 16r2].
[JumpFPGreaterOrEqual] -> [^self concretizeConditionalJump: 16r3].
[JumpFPGreater] -> [^self concretizeConditionalJump: 16r7].
[JumpFPLessOrEqual] -> [^self concretizeConditionalJump: 16r6].
[JumpFPOrdered] -> [^self concretizeConditionalJump: 16rB].
[JumpFPUnordered] -> [^self concretizeConditionalJump: 16rA].
[RetN] -> [^self concretizeRetN].
"Arithmetic"
[AddCqR] -> [^self concretizeAddCqR].
[AddCwR] -> [^self concretizeAddCwR].
[AddRR] -> [^self concretizeAddRR].
[AddRdRd] -> [^self concretizeSEE2OpRdRd: 16r58].
[AndCqR] -> [^self concretizeAndCqR].
+ [AndCwR] -> [^self concretizeAndCwR].
[AndRR] -> [^self concretizeAndRR].
[CmpCqR] -> [^self concretizeCmpCqR].
[CmpCwR] -> [^self concretizeCmpCwR].
[CmpRR] -> [^self concretizeCmpRR].
[CmpRdRd] -> [^self concretizeCmpRdRd].
[DivRdRd] -> [^self concretizeSEE2OpRdRd: 16r5E].
[MulRdRd] -> [^self concretizeSEE2OpRdRd: 16r59].
[OrCqR] -> [^self concretizeOrCqR].
+ [OrCwR] -> [^self concretizeOrCwR].
[OrRR] -> [^self concretizeOrRR].
[SubCqR] -> [^self concretizeSubCqR].
[SubCwR] -> [^self concretizeSubCwR].
[SubRR] -> [^self concretizeSubRR].
[SubRdRd] -> [^self concretizeSEE2OpRdRd: 16r5C].
[SqrtRd] -> [^self concretizeSqrtRd].
[XorCwR] -> [^self concretizeXorCwR].
[XorRR] -> [^self concretizeXorRR].
[NegateR] -> [^self concretizeNegateR].
[LoadEffectiveAddressMwrR] -> [^self concretizeLoadEffectiveAddressMwrR].
[ArithmeticShiftRightCqR] -> [^self concretizeArithmeticShiftRightCqR].
[LogicalShiftRightCqR] -> [^self concretizeLogicalShiftRightCqR].
[LogicalShiftLeftCqR] -> [^self concretizeLogicalShiftLeftCqR].
[ArithmeticShiftRightRR] -> [^self concretizeArithmeticShiftRightRR].
[LogicalShiftLeftRR] -> [^self concretizeLogicalShiftLeftRR].
"Data Movement"
[MoveCqR] -> [^self concretizeMoveCqR].
[MoveCwR] -> [^self concretizeMoveCwR].
[MoveRR] -> [^self concretizeMoveRR].
[MoveAwR] -> [^self concretizeMoveAwR].
[MoveRAw] -> [^self concretizeMoveRAw].
[MoveMbrR] -> [^self concretizeMoveMbrR].
[MoveRMbr] -> [^self concretizeMoveRMbr].
[MoveM16rR] -> [^self concretizeMoveM16rR].
[MoveM64rRd] -> [^self concretizeMoveM64rRd].
[MoveMwrR] -> [^self concretizeMoveMwrR].
[MoveXbrRR] -> [^self concretizeMoveXbrRR].
[MoveXwrRR] -> [^self concretizeMoveXwrRR].
[MoveRXwrR] -> [^self concretizeMoveRXwrR].
[MoveRMwr] -> [^self concretizeMoveRMwr].
[MoveRdM64r] -> [^self concretizeMoveRdM64r].
[PopR] -> [^self concretizePopR].
[PushR] -> [^self concretizePushR].
[PushCw] -> [^self concretizePushCw].
[PrefetchAw] -> [^self concretizePrefetchAw].
"Conversion"
[ConvertRRd] -> [^self concretizeConvertRRd] }!
Item was added:
+ ----- Method: CogRTLOpcodes class>>opcodes (in category 'accessing') -----
+ opcodes
+ "CogRTLOpcodes opcodes"
+ "CogRTLOpcodes opcodes select:
+ [:opcode|
+ (Cogit organization listAtCategoryNamed: #'abstract instructions') noneSatisfy:
+ [:s|
+ (Cogit compiledMethodAt: s) literals anySatisfy:
+ [:l|
+ l isVariableBinding and: [l key = opcode]]]]"
+ ^(classPool keys reject:
+ [:k|
+ (#('First' 'Last' 'DPFP') anySatisfy: [:prefix| k beginsWith: prefix])
+ or: [#('Reg' 'Min' 'Max') anySatisfy: [:postfix| k endsWith: postfix]]]) asArray sort!
More information about the Vm-dev
mailing list