From 6cdb1e5ddc4af8767e38aa0acda69d05fb0c118e Mon Sep 17 00:00:00 2001 From: Pablo Tesone Date: Mon, 2 Sep 2024 09:56:37 +0200 Subject: [PATCH 01/17] Release of Version v10.3.1 --- CHANGELOG.md | 20 ++++++++++++++++++++ CMakeLists.txt | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 39cc10df07..e967c5297b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,25 @@ # Change log +## What's Changed +* Redo 294 by @guillep in https://github.com/pharo-project/pharo-vm/pull/829 +* Making it loadable in P12 by @guillep in https://github.com/pharo-project/pharo-vm/pull/825 +* Added test on extended store and pop by @guillep in https://github.com/pharo-project/pharo-vm/pull/520 +* Update build version to P12 by @guillep in https://github.com/pharo-project/pharo-vm/pull/826 +* Improving log of old space limit error reporting by @tesonep in https://github.com/pharo-project/pharo-vm/pull/833 +* a better comment support for Slang by @RenaudFondeur in https://github.com/pharo-project/pharo-vm/pull/838 +* a first version of Slang with no type conflict and an exception if one appear by @RenaudFondeur in https://github.com/pharo-project/pharo-vm/pull/819 +* remove unused cast and expression by @RenaudFondeur in https://github.com/pharo-project/pharo-vm/pull/837 +* fix warnings related to multiple include of the same header file by @RenaudFondeur in https://github.com/pharo-project/pharo-vm/pull/840 +* Fix a lot of unused expression by @RenaudFondeur in https://github.com/pharo-project/pharo-vm/pull/832 +* add a comment explaining why declareCVarsIn: is empty in some subclasses by @RenaudFondeur in https://github.com/pharo-project/pharo-vm/pull/842 +* small change in dead code elimination to considers a method with only comments empty by @RenaudFondeur in https://github.com/pharo-project/pharo-vm/pull/843 +* small change in copyWithoutReturn to handle CCoerce by @RenaudFondeur in https://github.com/pharo-project/pharo-vm/pull/836 +* Remove hostname lookup on network initialization by @guillep in https://github.com/pharo-project/pharo-vm/pull/845 +* Update SDL2 version in OSX (Intel & Apple) by @tesonep in https://github.com/pharo-project/pharo-vm/pull/849 +* Adding option for pin behaviour by @tesonep in https://github.com/pharo-project/pharo-vm/pull/844 + +**Full Changelog**: https://github.com/pharo-project/pharo-vm/compare/v10.3.0...v10.3.1 + ## v10.3.0 * New harmonize rule by @RenaudFondeur in https://github.com/pharo-project/pharo-vm/pull/817 diff --git a/CMakeLists.txt b/CMakeLists.txt index 6f981c3d41..956131db43 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -53,7 +53,7 @@ extractVCSInformation(GIT_COMMIT_HASH GIT_DESCRIBE GIT_COMMIT_DATE) set(VERSION_MAJOR 10) set(VERSION_MINOR 3) -set(VERSION_PATCH_NUMBER 0) +set(VERSION_PATCH_NUMBER 1) if(BUILD_IS_RELEASE) set(VERSION_PATCH "${VERSION_PATCH_NUMBER}") From 74ba018ee68df031c241f91ae2411de032937571 Mon Sep 17 00:00:00 2001 From: Pablo Tesone Date: Thu, 19 Sep 2024 09:55:39 +0200 Subject: [PATCH 02/17] - When there was perm space it was allocating more memory on starting for the old space as it was using the total size of the image to allocate, this space was not used but the space was required to the OS - Adding a new field to the header to hold only the old space size. - Making it optional to support older images - In Spur format images the value is set as the whole image size, as there is not perm space. --- smalltalksrc/Slang/SlangStructType.class.st | 6 +++--- smalltalksrc/Slang/TStatementListNode.class.st | 3 ++- smalltalksrc/VMMaker/ComposedImageReader.class.st | 4 ++++ smalltalksrc/VMMaker/SpurImageHeaderStruct.class.st | 13 +++++++++++++ smalltalksrc/VMMaker/SpurImageReader.class.st | 3 +++ smalltalksrc/VMMaker/SpurMemoryManager.class.st | 6 ++++++ smalltalksrc/VMMaker/StackInterpreter.class.st | 3 ++- 7 files changed, 33 insertions(+), 5 deletions(-) diff --git a/smalltalksrc/Slang/SlangStructType.class.st b/smalltalksrc/Slang/SlangStructType.class.st index 4f109c9c3b..33d88eb3a9 100644 --- a/smalltalksrc/Slang/SlangStructType.class.st +++ b/smalltalksrc/Slang/SlangStructType.class.st @@ -216,9 +216,9 @@ SlangStructType class >> voidStructTypeCache [ { #category : 'macros' } SlangStructType >> setField: fieldName to: fieldValue [ - | slot | - slot := self class slotNamed: fieldName. - slot write: fieldValue to: self + self class + slotNamed: fieldName + ifFound: [ :slot | slot write: fieldValue to: self ] ] { #category : 'macros' } diff --git a/smalltalksrc/Slang/TStatementListNode.class.st b/smalltalksrc/Slang/TStatementListNode.class.st index 0540901a10..17183678a6 100644 --- a/smalltalksrc/Slang/TStatementListNode.class.st +++ b/smalltalksrc/Slang/TStatementListNode.class.st @@ -371,7 +371,8 @@ TStatementListNode >> copyWithoutReturn [ newStmtsListNode replaceChild: actualLast with: actualLast copyWithoutReturn ]. - ^ newStmtsListNode] + ^ newStmtsListNode +] { #category : 'declarations' } TStatementListNode >> declarationAt: aString ifPresent: aFullBlockClosure [ diff --git a/smalltalksrc/VMMaker/ComposedImageReader.class.st b/smalltalksrc/VMMaker/ComposedImageReader.class.st index 8590a40e22..9fec6387ae 100644 --- a/smalltalksrc/VMMaker/ComposedImageReader.class.st +++ b/smalltalksrc/VMMaker/ComposedImageReader.class.st @@ -123,6 +123,10 @@ ComposedImageReader >> readHeaderFromImage: imageFileName [ headerPtr := self addressOf: header. self readSTONFrom: file into: headerPtr. + + "If the field is missing, as it was added later" + header hdrOldSpaceSize = 0 + ifTrue: [ header hdrOldSpaceSize: header dataSize ]. self extractImageVersionFrom: (header imageFormat) into: headerPtr. diff --git a/smalltalksrc/VMMaker/SpurImageHeaderStruct.class.st b/smalltalksrc/VMMaker/SpurImageHeaderStruct.class.st index c81120e0e2..35c648e521 100644 --- a/smalltalksrc/VMMaker/SpurImageHeaderStruct.class.st +++ b/smalltalksrc/VMMaker/SpurImageHeaderStruct.class.st @@ -3,6 +3,7 @@ Class { #superclass : 'VMStructType', #instVars : [ 'dataSize', + 'hdrOldSpaceSize', 'oldBaseAddr', 'initialSpecialObjectsOop', 'headerFlags', @@ -159,6 +160,18 @@ SpurImageHeaderStruct >> hdrNumStackPages: anObject [ hdrNumStackPages := anObject ] +{ #category : 'accessing' } +SpurImageHeaderStruct >> hdrOldSpaceSize [ + + ^ hdrOldSpaceSize +] + +{ #category : 'accessing' } +SpurImageHeaderStruct >> hdrOldSpaceSize: anObject [ + + hdrOldSpaceSize := anObject +] + { #category : 'accessing' } SpurImageHeaderStruct >> headerFlags [ diff --git a/smalltalksrc/VMMaker/SpurImageReader.class.st b/smalltalksrc/VMMaker/SpurImageReader.class.st index 6e22512a99..286437cb2f 100644 --- a/smalltalksrc/VMMaker/SpurImageReader.class.st +++ b/smalltalksrc/VMMaker/SpurImageReader.class.st @@ -81,6 +81,9 @@ SpurImageReader >> readHeaderFrom: f startingAt: headerStart [ header imageHeaderSize: (self getWord32FromFile: f swap: header swapBytes). header dataSize: (self getLongFromFile: f swap: header swapBytes). + "In SpurFormat the dataSize is just the oldSpace size" + header hdrOldSpaceSize: header dataSize. + header oldBaseAddr: (self getLongFromFile: f swap: header swapBytes). header initialSpecialObjectsOop: (self getLongFromFile: f swap: header swapBytes). diff --git a/smalltalksrc/VMMaker/SpurMemoryManager.class.st b/smalltalksrc/VMMaker/SpurMemoryManager.class.st index d8f9ee4b21..da0f171e12 100644 --- a/smalltalksrc/VMMaker/SpurMemoryManager.class.st +++ b/smalltalksrc/VMMaker/SpurMemoryManager.class.st @@ -10166,6 +10166,12 @@ SpurMemoryManager >> oldSpaceSize [ ^segmentManager totalBytesInSegments ] +{ #category : 'snapshot' } +SpurMemoryManager >> oldSpaceSizeToWrite [ + + ^segmentManager totalBytesInNonEmptySegments +] + { #category : 'become implementation' } SpurMemoryManager >> outOfPlaceBecome: obj1 and: obj2 copyHashFlag: copyHashFlag [ "in an effort to fix a compiler bug with two-way become post r3427" diff --git a/smalltalksrc/VMMaker/StackInterpreter.class.st b/smalltalksrc/VMMaker/StackInterpreter.class.st index 091e9ca797..4e87019488 100644 --- a/smalltalksrc/VMMaker/StackInterpreter.class.st +++ b/smalltalksrc/VMMaker/StackInterpreter.class.st @@ -2067,7 +2067,7 @@ StackInterpreter >> allocateMemoryForImageHeader: header [ objectMemory getMemoryMap allocationReserve: self interpreterAllocationReserveBytes; - initialOldSpaceSize: header dataSize; + initialOldSpaceSize: header hdrOldSpaceSize; initialNewSpaceSize: objectMemory newSpaceBytes; initialHeadroom: (objectMemory initialHeadroom: extraVMMemory givenFreeOldSpaceInImage: header freeOldSpaceInImage); allocateHeap. @@ -10341,6 +10341,7 @@ StackInterpreter >> newHeader [ sizeToWrite := objectMemory imageSizeToWrite. header dataSize: sizeToWrite. + header hdrOldSpaceSize: objectMemory oldSpaceSizeToWrite. header oldBaseAddr: objectMemory getMemoryMap oldSpaceStart. header initialSpecialObjectsOop: objectMemory specialObjectsOop. From 865c86f6c5abd76a166731b532e0715833fa9416 Mon Sep 17 00:00:00 2001 From: Pablo Tesone Date: Thu, 19 Sep 2024 11:50:51 +0200 Subject: [PATCH 03/17] - Fixing the generation of reflective accessing to structures --- .../CCodeGeneratorGlobalStructure.class.st | 24 ++++++++++++------- smalltalksrc/Slang/SlangStructType.class.st | 10 ++++++++ 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/smalltalksrc/Melchor/CCodeGeneratorGlobalStructure.class.st b/smalltalksrc/Melchor/CCodeGeneratorGlobalStructure.class.st index 1a3c3d09d9..2fa9afda9a 100644 --- a/smalltalksrc/Melchor/CCodeGeneratorGlobalStructure.class.st +++ b/smalltalksrc/Melchor/CCodeGeneratorGlobalStructure.class.st @@ -190,17 +190,26 @@ CCodeGeneratorGlobalStructure >> emitGlobalStructFlagOn: aStream [ { #category : 'CAST translation' } CCodeGeneratorGlobalStructure >> generateCASTSetFieldTo: aTSendNode [ - | structType fieldName fieldVale setFieldStatements | + | structType fieldName fieldVale setFieldStatements structClass | self assert: aTSendNode arguments size = 2. fieldName := aTSendNode arguments first. fieldVale := aTSendNode arguments second. structType := self structTypeFor: aTSendNode receiver. - - - setFieldStatements := (structType asClassInEnvironment: - self class environment) allSlots collect: [ + structClass := structType asClassInEnvironment: self class environment. + + "If the field name is known at compile time, we can just use the accessor, we don't need to compare by the name" + fieldName isConstant + ifTrue: [ + self assert: (structClass hasSlotNamed: fieldName value). + + ^ (TSendNode + receiver: aTSendNode receiver + selector: fieldName value , ':' + arguments: { fieldVale }) asCASTIn: self ]. + + setFieldStatements := structClass allSlots collect: [ :slot | | comparison | comparison := TSendNode @@ -237,7 +246,7 @@ CCodeGeneratorGlobalStructure >> generateCASTWithFieldsDoSeparatedBy: aTSendNode self assert: aTSendNode arguments second arguments size = 0. fieldBlock := aTSendNode arguments first. - blockSeparatorStatements := aTSendNode arguments second statements. + blockSeparatorStatements := aTSendNode arguments second statements reject: [ :e | e isConstant and: [ e value isNil ] ]. structType := self structTypeFor: aTSendNode receiver. @@ -257,8 +266,7 @@ CCodeGeneratorGlobalStructure >> generateCASTWithFieldsDoSeparatedBy: aTSendNode do: [ :fieldArgs | allRewrittenStatements addAll: (self bindBlock: fieldBlock withArgs: fieldArgs) ] - separatedBy: [ - allRewrittenStatements addAll: blockSeparatorStatements ]. + separatedBy: [ allRewrittenStatements addAll: blockSeparatorStatements ]. ^ CCompoundStatementNode statements: (allRewrittenStatements collect: [ :e | e asCASTIn: self ]) diff --git a/smalltalksrc/Slang/SlangStructType.class.st b/smalltalksrc/Slang/SlangStructType.class.st index 33d88eb3a9..2d0ad23646 100644 --- a/smalltalksrc/Slang/SlangStructType.class.st +++ b/smalltalksrc/Slang/SlangStructType.class.st @@ -221,6 +221,16 @@ SlangStructType >> setField: fieldName to: fieldValue [ ifFound: [ :slot | slot write: fieldValue to: self ] ] +{ #category : 'macros' } +SlangStructType >> withFieldsDo: forEachBlock [ + + + + self class allSlots + do: [ :aSlot | forEachBlock value: aSlot name value: (aSlot read: self) ] + separatedBy: [ ] +] + { #category : 'macros' } SlangStructType >> withFieldsDo: forEachBlock separatedBy: separatorBlock [ From 3b4077a6bb934c3cef96d3bfb420a6eb387f8d3b Mon Sep 17 00:00:00 2001 From: Pablo Tesone Date: Thu, 19 Sep 2024 14:09:27 +0200 Subject: [PATCH 04/17] - Improving the reading of STON files so we can handle the lf / crlf differences --- .../AbstractComposedImageAccess.class.st | 65 +++++++++++++++++++ .../VMMaker/ComposedImageReader.class.st | 47 ++++++++++---- 2 files changed, 98 insertions(+), 14 deletions(-) diff --git a/smalltalksrc/VMMaker/AbstractComposedImageAccess.class.st b/smalltalksrc/VMMaker/AbstractComposedImageAccess.class.st index 496ffd0e5b..9505c633de 100644 --- a/smalltalksrc/VMMaker/AbstractComposedImageAccess.class.st +++ b/smalltalksrc/VMMaker/AbstractComposedImageAccess.class.st @@ -168,6 +168,44 @@ AbstractComposedImageAccess >> permSpaceMetadataFileNameInImage: imageFileName [ ^ self permSpaceFileName: 'permSpace.ston' inImage: imageFileName into: buffer bufferSize: 255 ] +{ #category : 'file primitives' } +AbstractComposedImageAccess >> readLineFrom: file into: lineBuffer ofSize: bufferSize [ + + + + + self + cCode: [ + | idx aCharacter | + + idx := 0. + + aCharacter := self fgetc: file. + + [ aCharacter = -1 ] + whileFalse: [ + aCharacter = 10 + ifTrue: [ aCharacter := -1 ] + ifFalse: [ + aCharacter = 13 + ifTrue: [ + aCharacter := self fgetc: file. + aCharacter ~= 13 ifTrue: [ self ungetc: aCharacter _: file ]. + aCharacter := -1 ] + ifFalse: [ + lineBuffer at: idx put: aCharacter. + idx := idx + 1. + bufferSize = (idx + 1) + ifTrue: [ aCharacter := -1 ] + ifFalse: [ aCharacter := self fgetc: file]. + ] + ]]. + + lineBuffer at: idx put: 0. + ] + inSmalltalk: [ lineBuffer contents: file nextLine]. +] + { #category : 'segments' } AbstractComposedImageAccess >> segmentDataFile: segmentIndex inImage: imageFileName [ @@ -209,3 +247,30 @@ AbstractComposedImageAccess >> segmentMetadataFile: segmentIndex inImage: imageF ^ self segmentFileName: segmentIndex withExtension: '.ston' inImage: imageFileName into: buffer bufferSize: 255. ] + +{ #category : 'file primitives' } +AbstractComposedImageAccess >> sscanf: aString _: format _: varHolder [ + + + (format = self headFormat) + ifTrue: [ + ^ varHolder contents: (aString substrings: ' ') first ]. + + self error. +] + +{ #category : 'file primitives' } +AbstractComposedImageAccess >> sscanf: line _: format _: varHolder1 _: varHolder2 [ + + + + ^ (format = self fieldFormat) + ifTrue: [ + | dataArray | + dataArray := line substrings: '#:, '. + dataArray first = '}' ifTrue: [ ^ false ]. + varHolder1 contents: dataArray second. + varHolder2 contents: dataArray third asInteger ]. + + self error +] diff --git a/smalltalksrc/VMMaker/ComposedImageReader.class.st b/smalltalksrc/VMMaker/ComposedImageReader.class.st index 9fec6387ae..25b605a653 100644 --- a/smalltalksrc/VMMaker/ComposedImageReader.class.st +++ b/smalltalksrc/VMMaker/ComposedImageReader.class.st @@ -15,14 +15,15 @@ ComposedImageReader class >> declareCVarsIn: aCCodeGenerator [ { #category : 'reading' } ComposedImageReader >> endOfSTON: file [ - - "This method consume 2 chars from file and return they are equivalent to '\n}'" - - | charLeft charRight | - charLeft := self fgetc: file. - charRight := self fgetc: file. - ^ (self isEndOfLine: charLeft) and: [ charRight = $} ] + ^ self + cCode: [ | aCharacter | + aCharacter := self fgetc: file. + self ungetc: aCharacter _:file. + aCharacter = -1 or: [ aCharacter = $} ]] + inSmalltalk: [ file peek = $} ]. + + ] { #category : 'reading' } @@ -55,10 +56,13 @@ ComposedImageReader >> readFieldsSTONFrom: file into: aStruct [ - | fieldName fieldValue | + + + | fieldName fieldValue lineBuffer | self simulationOnly: [ fieldName := ValueHolder new. - fieldValue := ValueHolder new ]. + fieldValue := ValueHolder new. + lineBuffer := ValueHolder new ]. "Initialize the Struct with zeros" @@ -67,9 +71,14 @@ ComposedImageReader >> readFieldsSTONFrom: file into: aStruct [ separatedBy: [ ]. "This solution does NOT WORK with STON file without fields (empty STON)" - [ + [ + self + readLineFrom: file + into: lineBuffer + ofSize: 1024. + self - fscanf: file + sscanf: (self contentsOf: lineBuffer) _: self fieldFormat _: fieldName _: (self cCoerce: (self addressOf: fieldValue) to: #'sqInt*'). @@ -85,10 +94,20 @@ ComposedImageReader >> readHeadSTONFrom: file into: aStruct [ - | structName | - self simulationOnly: [ structName := ValueHolder new ]. + + + | structName lineBuffer | + + self simulationOnly: [ + lineBuffer := ValueHolder new. + structName := ValueHolder new ]. + + self + readLineFrom: file + into: lineBuffer + ofSize: 1024. - self fscanf: file _: self headFormat _: structName. + self sscanf: (self contentsOf: lineBuffer) _: self headFormat _: structName. self simulationOnly: [ aStruct withStructNameDo: [ :name | From ffd9a86c5e03b890f3a8ca1f1b83254ddc25b148 Mon Sep 17 00:00:00 2001 From: Pablo Tesone Date: Thu, 19 Sep 2024 14:23:56 +0200 Subject: [PATCH 05/17] - Swizzling should be aware that permanent space always is in the same place --- smalltalksrc/VMMaker/SpurSegmentManager.class.st | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/smalltalksrc/VMMaker/SpurSegmentManager.class.st b/smalltalksrc/VMMaker/SpurSegmentManager.class.st index ba07fc3b13..cc1985f9ec 100644 --- a/smalltalksrc/VMMaker/SpurSegmentManager.class.st +++ b/smalltalksrc/VMMaker/SpurSegmentManager.class.st @@ -661,6 +661,11 @@ SpurSegmentManager >> someSegmentContainsPinned [ SpurSegmentManager >> swizzleObj: objOop [ self assert: canSwizzle. + + "The permanent space is always loaded in the same place" + (manager getMemoryMap isPermanentObject: objOop) + ifTrue: [ ^ objOop ]. + numSegments - 1 to: 1 by: -1 do: [:i| objOop >= (segments at: i) segStart ifTrue: From 30574564620815cb3b6bf15d6a09a03bfdc71038 Mon Sep 17 00:00:00 2001 From: Pablo Tesone Date: Thu, 19 Sep 2024 14:58:59 +0200 Subject: [PATCH 06/17] Adjusting the objects that are in the permanent space --- .../VMMaker/SpurMemoryManager.class.st | 33 ++++++++++++------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/smalltalksrc/VMMaker/SpurMemoryManager.class.st b/smalltalksrc/VMMaker/SpurMemoryManager.class.st index da0f171e12..6f1955038c 100644 --- a/smalltalksrc/VMMaker/SpurMemoryManager.class.st +++ b/smalltalksrc/VMMaker/SpurMemoryManager.class.st @@ -1312,18 +1312,27 @@ SpurMemoryManager >> adjustAllOopsBy: bytesToShift [ | obj classIndex | self assert: self newSpaceIsEmpty. self countNumClassPagesPreSwizzle: bytesToShift. - (bytesToShift ~= 0 - or: [segmentManager numSegments > 1]) ifTrue: - [obj := self objectStartingAt: memoryMap oldSpaceStart. - [self oop: obj isLessThan: freeOldSpaceStart] whileTrue: - [classIndex := self classIndexOf: obj. - classIndex >= self isForwardedObjectClassIndexPun - ifTrue: - [self swizzleFieldsOfObject: obj] - ifFalse: - [classIndex = self isFreeObjectClassIndexPun ifTrue: - [self swizzleFieldsOfFreeChunk: obj]]. - obj := self objectAfter: obj limit: memoryMap oldSpaceEnd]] + + (bytesToShift = 0 and: [segmentManager numSegments = 1]) ifTrue:[ ^ self ]. + + obj := self objectStartingAt: memoryMap oldSpaceStart. + [self oop: obj isLessThan: freeOldSpaceStart] whileTrue: + [classIndex := self classIndexOf: obj. + classIndex >= self isForwardedObjectClassIndexPun + ifTrue: + [self swizzleFieldsOfObject: obj] + ifFalse: + [classIndex = self isFreeObjectClassIndexPun ifTrue: + [self swizzleFieldsOfFreeChunk: obj]]. + obj := self objectAfter: obj limit: memoryMap oldSpaceEnd]. + + + "As we know all the permanent space objects that are pointing to the old space, and as the permanent space is always in the same place. + We need only to iterate the remembered set to swizzle the fields of permanent objects" + + self getFromPermToOldSpaceRememberedSet + rememberedSetWithIndexDo: [ :oop :i | self swizzleFieldsOfObject: oop ]. + ] { #category : 'object enumeration' } From 45361b38ebbf5d68177b3bb9064ae637a2dbe03f Mon Sep 17 00:00:00 2001 From: Pablo Tesone Date: Thu, 19 Sep 2024 15:18:06 +0200 Subject: [PATCH 07/17] Fixing error in the return --- smalltalksrc/VMMaker/AbstractComposedImageAccess.class.st | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/smalltalksrc/VMMaker/AbstractComposedImageAccess.class.st b/smalltalksrc/VMMaker/AbstractComposedImageAccess.class.st index 9505c633de..b569358a55 100644 --- a/smalltalksrc/VMMaker/AbstractComposedImageAccess.class.st +++ b/smalltalksrc/VMMaker/AbstractComposedImageAccess.class.st @@ -264,13 +264,14 @@ AbstractComposedImageAccess >> sscanf: line _: format _: varHolder1 _: varHolder - ^ (format = self fieldFormat) + (format = self fieldFormat) ifTrue: [ | dataArray | dataArray := line substrings: '#:, '. - dataArray first = '}' ifTrue: [ ^ false ]. + dataArray first = '}' ifTrue: [ ^ self ]. varHolder1 contents: dataArray second. - varHolder2 contents: dataArray third asInteger ]. + varHolder2 contents: dataArray third asInteger. + ^ self ]. self error ] From 2eb5badbf79e0e0c4a379fe6b2a30d322c5a3f47 Mon Sep 17 00:00:00 2001 From: Pablo Tesone Date: Mon, 23 Sep 2024 14:39:15 +0200 Subject: [PATCH 08/17] Implementing become for Permanent objects --- .../VMMaker/SpurMemoryManager.class.st | 67 +- .../VMMaker/StackInterpreter.class.st | 14 +- ...SpurObjectRepresentationConstants.class.st | 1 + .../VMPermanentSpaceMemoryTest.class.st | 622 +++++++++++++++++- 4 files changed, 670 insertions(+), 34 deletions(-) diff --git a/smalltalksrc/VMMaker/SpurMemoryManager.class.st b/smalltalksrc/VMMaker/SpurMemoryManager.class.st index 6f1955038c..e1909ad213 100644 --- a/smalltalksrc/VMMaker/SpurMemoryManager.class.st +++ b/smalltalksrc/VMMaker/SpurMemoryManager.class.st @@ -914,7 +914,8 @@ SpurMemoryManager class >> initializeSpurObjectRepresentationConstants [ BecamePointerObjectFlag := 1. BecameCompiledMethodFlag := 2. OldBecameNewFlag := 4. - BecameActiveClassFlag := 8 "For flushing method caches" + BecameActiveClassFlag := 8 "For flushing method caches". + BecamePermanentObject := 16. ] { #category : 'class initialization' } @@ -1816,6 +1817,13 @@ SpurMemoryManager >> allPastSpaceObjectsDo: aBlock [ aBlock value: objOop] ] +{ #category : 'perm - space' } +SpurMemoryManager >> allPermSpaceNonForwardedObjectsDo: aBlockClosure [ + + self allPermSpaceObjectsDo: [ :anObj | + (self isForwarded: anObj) ifFalse: [ aBlockClosure value: anObj ] ] +] + { #category : 'perm - space' } SpurMemoryManager >> allPermSpaceObjectsDo: aBlockClosure [ @@ -3960,15 +3968,20 @@ SpurMemoryManager >> clone: objOop [ | numSlots fmt newObj | numSlots := self numSlotsOf: objOop. fmt := self formatOf: objOop. - numSlots > self maxSlotsForNewSpaceAlloc - ifTrue: - [newObj := self allocateSlotsInOldSpace: numSlots - format: fmt - classIndex: (self classIndexOf: objOop)] - ifFalse: - [newObj := self allocateSlots: numSlots - format: fmt - classIndex: (self classIndexOf: objOop)]. + + (memoryMap isPermanentObject: objOop) + ifTrue: [ newObj := self allocateSlotsInPermSpace: numSlots format: fmt classIndex: (self classIndexOf: objOop)] + ifFalse: [ + numSlots > self maxSlotsForNewSpaceAlloc + ifTrue: + [newObj := self allocateSlotsInOldSpace: numSlots + format: fmt + classIndex: (self classIndexOf: objOop)] + ifFalse: + [newObj := self allocateSlots: numSlots + format: fmt + classIndex: (self classIndexOf: objOop)]]. + newObj ifNil: [^0]. (self isPointersFormat: fmt) @@ -4366,6 +4379,9 @@ SpurMemoryManager >> doBecome: obj1 and: obj2 copyHash: copyHashFlag [ (o2ClassIndex ~= 0 and: [(self classAtIndex: o2ClassIndex) ~= obj2]) ifTrue: [o2ClassIndex := 0]. + ((self isPermanent: obj1) or: [ self isPermanent: obj2 ]) + ifTrue: [ becomeEffectsFlags := becomeEffectsFlags bitOr: BecamePermanentObject ]. + "Refuse to do an in-place become on classes since their being forwarded is used in the flush method cache implementations." ((self numSlotsOf: obj1) = (self numSlotsOf: obj2) @@ -4410,12 +4426,20 @@ SpurMemoryManager >> doBecome: obj1 to: obj2 copyHash: copyHashFlag [ then the entry at obj1's hash is valid, otherwise the the existing one at obj2's hash. When all the instances with the old hash have been collected, the GC will discover this and expunge obj2 at the unused index (see markAndTraceClassOf:)." + self forward: obj1 to: obj2. - copyHashFlag ifTrue: [self setHashBitsOf: obj2 to: (self rawHashBitsOf: obj1)]. - ((memoryMap isOldObject: obj1) - and: [self isYoung: obj2]) ifTrue: - [becomeEffectsFlags := becomeEffectsFlags bitOr: OldBecameNewFlag]. - self deny: (self isOopForwarded: obj2) + copyHashFlag ifTrue: [ + self setHashBitsOf: obj2 to: (self rawHashBitsOf: obj1) ]. + + self deny: (self isOopForwarded: obj2). + + (memoryMap isPermanentObject: obj1) + ifTrue: [ becomeEffectsFlags := + becomeEffectsFlags bitOr: BecamePermanentObject ]. + + ((memoryMap isOldObject: obj1) and: [ self isYoung: obj2 ]) + ifTrue: [ + becomeEffectsFlags := becomeEffectsFlags bitOr: OldBecameNewFlag ] ] { #category : 'private - perm space' } @@ -6350,8 +6374,6 @@ SpurMemoryManager >> ifOopInvalidForBecome: oop errorCodeInto: aBlock [ (self isPinned: oop) ifTrue: [^aBlock value: PrimErrObjectIsPinned]. (self isObjImmutable: oop) ifTrue: - [^aBlock value: PrimErrNoModification]. - (memoryMap isPermanentObject: oop) ifTrue: [^aBlock value: PrimErrNoModification] ] @@ -7768,7 +7790,7 @@ SpurMemoryManager >> isPermSpaceRememberedSetSane [ isValid := true. - self allPermSpaceObjectsDo: [ :objOop | + self allPermSpaceNonForwardedObjectsDo: [ :objOop | refersNewSpace := self hasYoungReferents: objOop. refersOldSpace := self hasOldReferents: objOop. @@ -8925,13 +8947,14 @@ SpurMemoryManager >> markLoopFrom: objOop [ [ index > 0 ] whileTrue: [ index := index - 1. field := self fetchPointer: index ofObject: objToScan. - ((self isNonImmediate: field) and: [(self isPermanent: field) not]) ifTrue: [ + (self isNonImmediate: field) ifTrue: [ (self isForwarded: field) ifTrue: [ "fixFollowedField: is /not/ inlined" field := self fixFollowedField: index ofObject: objToScan withInitialValue: field ]. - (self markAndShouldScan: field) ifTrue: [ + ((self isPermanent: field) not and: [self markAndShouldScan: field]) + ifTrue: [ self push: field onObjStack: markStack. ((self rawNumSlotsOf: field) > self traceImmediatelySlotLimit and: [ @@ -9295,7 +9318,7 @@ SpurMemoryManager >> moveToPermSpaceAllOldObjects [ (self isValidToMoveToPermSpace: objOop) ifTrue: [ self doMoveToPermSpace: objOop addToRememberedSet: true ]]]. - self allPermSpaceObjectsDo: [ :permObj | + self allPermSpaceNonForwardedObjectsDo: [ :permObj | self followForwardedObjectFields: permObj toDepth: 0 ]. self recreateFromPermSpaceRememberedSet. @@ -11323,7 +11346,7 @@ SpurMemoryManager >> recreateFromPermSpaceRememberedSet [ self getFromPermToOldSpaceRememberedSet emptyRememberedSet. self getFromPermToNewSpaceRememberedSet emptyRememberedSet. - self allPermSpaceObjectsDo: [ :aPermSpaceObject | + self allPermSpaceNonForwardedObjectsDo: [ :aPermSpaceObject | | slotIndex referenced numPointerSlots refersNewSpace refersOldSpace | "We clear the bit of all remembered objects, it will be recalculated" diff --git a/smalltalksrc/VMMaker/StackInterpreter.class.st b/smalltalksrc/VMMaker/StackInterpreter.class.st index 4e87019488..c5abd40d7f 100644 --- a/smalltalksrc/VMMaker/StackInterpreter.class.st +++ b/smalltalksrc/VMMaker/StackInterpreter.class.st @@ -6453,6 +6453,15 @@ StackInterpreter >> followForwardedMethodsInMethodZone [ "This is just a stub for the CoInterpreter" ] +{ #category : 'object memory support' } +StackInterpreter >> followForwardingPointersInPermSpace [ + + objectMemory allPermSpaceNonForwardedObjectsDo: [ :permObj | + objectMemory followForwardedObjectFields: permObj toDepth: 0 ]. + + objectMemory recreateFromPermSpaceRememberedSet +] + { #category : 'object memory support' } StackInterpreter >> followForwardingPointersInProfileState [ (objectMemory isForwarded: profileProcess) ifTrue: @@ -10813,7 +10822,10 @@ StackInterpreter >> postBecomeAction: theBecomeEffectsFlags [ self followForwardingPointersInSpecialObjectsArray ]. (theBecomeEffectsFlags anyMask: BecamePointerObjectFlag + BecameCompiledMethodFlag) ifTrue: [ - self followForwardingPointersInProfileState ] ]. + self followForwardingPointersInProfileState ]. + (theBecomeEffectsFlags anyMask: BecamePermanentObject) ifTrue: [ + self followForwardingPointersInPermSpace] + ]. self followForwardingPointersInStackZone: theBecomeEffectsFlags ] diff --git a/smalltalksrc/VMMaker/VMSpurObjectRepresentationConstants.class.st b/smalltalksrc/VMMaker/VMSpurObjectRepresentationConstants.class.st index e88e25c2e1..dbbc80739c 100644 --- a/smalltalksrc/VMMaker/VMSpurObjectRepresentationConstants.class.st +++ b/smalltalksrc/VMMaker/VMSpurObjectRepresentationConstants.class.st @@ -4,6 +4,7 @@ Class { #classVars : [ 'BecameActiveClassFlag', 'BecameCompiledMethodFlag', + 'BecamePermanentObject', 'BecamePointerObjectFlag', 'OldBecameNewFlag' ], diff --git a/smalltalksrc/VMMakerTests/VMPermanentSpaceMemoryTest.class.st b/smalltalksrc/VMMakerTests/VMPermanentSpaceMemoryTest.class.st index 81376cf7b0..6f11b9b697 100644 --- a/smalltalksrc/VMMakerTests/VMPermanentSpaceMemoryTest.class.st +++ b/smalltalksrc/VMMakerTests/VMPermanentSpaceMemoryTest.class.st @@ -27,31 +27,631 @@ VMPermanentSpaceMemoryTest >> testAllInstancesReturnsObjectsInPermSpace [ self assert: (memory fetchPointer: 0 ofObject: allInstances) equals: permanentObject. ] -{ #category : 'tests - allocation' } -VMPermanentSpaceMemoryTest >> testBecomingOfPermanentObjectFails [ +{ #category : 'tests - become' } +VMPermanentSpaceMemoryTest >> testBecomingOneWayOfPermanentObjectWithOldObject [ + + | permanentObject oldReplacement arrFrom arrTo ec youngObjectReferencingPermanent oldObjectReferencingPermanent permanentObjectReferencingPermanent | + + permanentObject := self newPermanentObjectWithSlots: 1. + memory storePointer: 0 ofObject: permanentObject withValue: (self newOldSpaceObjectWithSlots: 0). - | permanentObject oldObject youngReplacement arrFrom arrTo ec | + youngObjectReferencingPermanent := self newObjectWithSlots: 1. + memory storePointer: 0 ofObject: youngObjectReferencingPermanent withValue: permanentObject. + self keepObjectInVMVariable1: youngObjectReferencingPermanent. - permanentObject := self newPermanentObjectWithSlots: 1. - oldObject := self newOldSpaceObjectWithSlots: 0. - memory storePointer: 0 ofObject: permanentObject withValue: oldObject. + oldObjectReferencingPermanent := self newOldSpaceObjectWithSlots: 1. + memory storePointer: 0 ofObject: oldObjectReferencingPermanent withValue: permanentObject. + self keepObjectInVMVariable2: oldObjectReferencingPermanent. + + permanentObjectReferencingPermanent := self newPermanentObjectWithSlots: 1. + memory storePointer: 0 ofObject: permanentObjectReferencingPermanent withValue: permanentObject. memory fullGC. + + youngObjectReferencingPermanent := self keptObjectInVMVariable1. + oldObjectReferencingPermanent := self keptObjectInVMVariable2. + self assert: (memory getFromPermToOldSpaceRememberedSet isInRememberedSet: permanentObject). + self assert: (memory fetchPointer: 0 ofObject: oldObjectReferencingPermanent) equals: permanentObject. + self assert: (memory fetchPointer: 0 ofObject: permanentObjectReferencingPermanent) equals: permanentObject. + self assert: (memory fetchPointer: 0 ofObject: youngObjectReferencingPermanent) equals: permanentObject. + + oldReplacement := self newOldSpaceObjectWithSlots: 0. + self keepObjectInVMVariable3: oldReplacement. + + arrFrom := self newArrayWithSlots: 1. + arrTo := self newArrayWithSlots: 1. + + memory storePointer: 0 ofObject: arrFrom withValue: permanentObject. + memory storePointer: 0 ofObject: arrTo withValue: oldReplacement. + ec := memory become: arrFrom with: arrTo twoWay: false copyHash: false. + + self assert: ec equals: PrimNoErr. + + "The initial permanent object is now forwarded" + self assert: (memory isForwarded: permanentObject). + "Old and New objects still points to it" + self assert: (memory fetchPointer: 0 ofObject: oldObjectReferencingPermanent) equals: permanentObject. + self assert: (memory fetchPointer: 0 ofObject: youngObjectReferencingPermanent) equals: permanentObject. + + "Perm objects still points to the result" + self assert: (memory fetchPointer: 0 ofObject: permanentObjectReferencingPermanent) equals: oldReplacement. - youngReplacement := self newObjectWithSlots: 2. - memory storePointer: 0 ofObject: youngReplacement withValue: oldObject. + "The forwarded object is not in any remembered set" + self deny: (memory getFromPermToOldSpaceRememberedSet isInRememberedSet: permanentObject). + self deny: (memory getFromPermToNewSpaceRememberedSet isInRememberedSet: permanentObject). + + self assert: (memory getFromPermToOldSpaceRememberedSet isInRememberedSet: permanentObjectReferencingPermanent). + self deny: (memory getFromPermToNewSpaceRememberedSet isInRememberedSet: permanentObjectReferencingPermanent). + + memory fullGC. + + youngObjectReferencingPermanent := self keptObjectInVMVariable1. + oldObjectReferencingPermanent := self keptObjectInVMVariable2. + oldReplacement := self keptObjectInVMVariable3. + + "After GC nobody points to the forwarded object" + self assert: (memory fetchPointer: 0 ofObject: oldObjectReferencingPermanent) equals: oldReplacement. + self assert: (memory fetchPointer: 0 ofObject: youngObjectReferencingPermanent) equals: oldReplacement. + self assert: (memory fetchPointer: 0 ofObject: permanentObjectReferencingPermanent) equals: oldReplacement. +] + +{ #category : 'tests - become' } +VMPermanentSpaceMemoryTest >> testBecomingOneWayOfPermanentObjectWithPermanentObject [ + + | permanentObject permanentReplacement arrFrom arrTo ec youngObjectReferencingPermanent oldObjectReferencingPermanent permanentObjectReferencingPermanent | + + permanentObject := self newPermanentObjectWithSlots: 1. + memory storePointer: 0 ofObject: permanentObject withValue: (self newOldSpaceObjectWithSlots: 0). + + youngObjectReferencingPermanent := self newObjectWithSlots: 1. + memory storePointer: 0 ofObject: youngObjectReferencingPermanent withValue: permanentObject. + self keepObjectInVMVariable1: youngObjectReferencingPermanent. + + oldObjectReferencingPermanent := self newOldSpaceObjectWithSlots: 1. + memory storePointer: 0 ofObject: oldObjectReferencingPermanent withValue: permanentObject. + self keepObjectInVMVariable2: oldObjectReferencingPermanent. + + permanentObjectReferencingPermanent := self newPermanentObjectWithSlots: 1. + memory storePointer: 0 ofObject: permanentObjectReferencingPermanent withValue: permanentObject. + + memory fullGC. - self keepObjectInVMVariable1: youngReplacement. + youngObjectReferencingPermanent := self keptObjectInVMVariable1. + oldObjectReferencingPermanent := self keptObjectInVMVariable2. + + self assert: (memory getFromPermToOldSpaceRememberedSet isInRememberedSet: permanentObject). + self assert: (memory fetchPointer: 0 ofObject: oldObjectReferencingPermanent) equals: permanentObject. + self assert: (memory fetchPointer: 0 ofObject: permanentObjectReferencingPermanent) equals: permanentObject. + self assert: (memory fetchPointer: 0 ofObject: youngObjectReferencingPermanent) equals: permanentObject. + + permanentReplacement := self newPermanentObjectWithSlots: 0. arrFrom := self newArrayWithSlots: 1. arrTo := self newArrayWithSlots: 1. memory storePointer: 0 ofObject: arrFrom withValue: permanentObject. - memory storePointer: 0 ofObject: arrTo withValue: youngReplacement. + memory storePointer: 0 ofObject: arrTo withValue: permanentReplacement. ec := memory become: arrFrom with: arrTo twoWay: false copyHash: false. - self deny: ec equals: PrimNoErr + self assert: ec equals: PrimNoErr. + + "The initial permanent object is now forwarded" + self assert: (memory isForwarded: permanentObject). + "Old and New objects still points to it" + self assert: (memory fetchPointer: 0 ofObject: oldObjectReferencingPermanent) equals: permanentObject. + self assert: (memory fetchPointer: 0 ofObject: youngObjectReferencingPermanent) equals: permanentObject. + + "Perm objects still points to the result" + self assert: (memory fetchPointer: 0 ofObject: permanentObjectReferencingPermanent) equals: permanentReplacement. + + "The forwarded object is not in any remembered set" + self deny: (memory getFromPermToOldSpaceRememberedSet isInRememberedSet: permanentObject). + self deny: (memory getFromPermToNewSpaceRememberedSet isInRememberedSet: permanentObject). + + memory fullGC. + + youngObjectReferencingPermanent := self keptObjectInVMVariable1. + oldObjectReferencingPermanent := self keptObjectInVMVariable2. + + + "After GC nobody points to the forwarded object" + self assert: (memory fetchPointer: 0 ofObject: oldObjectReferencingPermanent) equals: permanentReplacement. + self assert: (memory fetchPointer: 0 ofObject: youngObjectReferencingPermanent) equals: permanentReplacement. + self assert: (memory fetchPointer: 0 ofObject: permanentObjectReferencingPermanent) equals: permanentReplacement. +] + +{ #category : 'tests - become' } +VMPermanentSpaceMemoryTest >> testBecomingOneWayOfPermanentObjectWithYoungObject [ + + | permanentObject oldReplacement arrFrom arrTo ec youngObjectReferencingPermanent oldObjectReferencingPermanent permanentObjectReferencingPermanent | + + permanentObject := self newPermanentObjectWithSlots: 1. + memory storePointer: 0 ofObject: permanentObject withValue: (self newOldSpaceObjectWithSlots: 0). + + youngObjectReferencingPermanent := self newObjectWithSlots: 1. + memory storePointer: 0 ofObject: youngObjectReferencingPermanent withValue: permanentObject. + self keepObjectInVMVariable1: youngObjectReferencingPermanent. + + oldObjectReferencingPermanent := self newOldSpaceObjectWithSlots: 1. + memory storePointer: 0 ofObject: oldObjectReferencingPermanent withValue: permanentObject. + self keepObjectInVMVariable2: oldObjectReferencingPermanent. + + permanentObjectReferencingPermanent := self newPermanentObjectWithSlots: 1. + memory storePointer: 0 ofObject: permanentObjectReferencingPermanent withValue: permanentObject. + + memory fullGC. + + youngObjectReferencingPermanent := self keptObjectInVMVariable1. + oldObjectReferencingPermanent := self keptObjectInVMVariable2. + + self assert: (memory getFromPermToOldSpaceRememberedSet isInRememberedSet: permanentObject). + self assert: (memory fetchPointer: 0 ofObject: oldObjectReferencingPermanent) equals: permanentObject. + self assert: (memory fetchPointer: 0 ofObject: permanentObjectReferencingPermanent) equals: permanentObject. + self assert: (memory fetchPointer: 0 ofObject: youngObjectReferencingPermanent) equals: permanentObject. + + oldReplacement := self newObjectWithSlots: 0. + self keepObjectInVMVariable3: oldReplacement. + + arrFrom := self newArrayWithSlots: 1. + arrTo := self newArrayWithSlots: 1. + + memory storePointer: 0 ofObject: arrFrom withValue: permanentObject. + memory storePointer: 0 ofObject: arrTo withValue: oldReplacement. + ec := memory become: arrFrom with: arrTo twoWay: false copyHash: false. + + self assert: ec equals: PrimNoErr. + + "The initial permanent object is now forwarded" + self assert: (memory isForwarded: permanentObject). + "Old and New objects still points to it" + self assert: (memory fetchPointer: 0 ofObject: oldObjectReferencingPermanent) equals: permanentObject. + self assert: (memory fetchPointer: 0 ofObject: youngObjectReferencingPermanent) equals: permanentObject. + + "Perm objects still points to the result" + self assert: (memory fetchPointer: 0 ofObject: permanentObjectReferencingPermanent) equals: oldReplacement. + + "The forwarded object is not in any remembered set" + self deny: (memory getFromPermToOldSpaceRememberedSet isInRememberedSet: permanentObject). + self deny: (memory getFromPermToNewSpaceRememberedSet isInRememberedSet: permanentObject). + + self deny: (memory getFromPermToOldSpaceRememberedSet isInRememberedSet: permanentObjectReferencingPermanent). + self assert: (memory getFromPermToNewSpaceRememberedSet isInRememberedSet: permanentObjectReferencingPermanent). + + memory fullGC. + + youngObjectReferencingPermanent := self keptObjectInVMVariable1. + oldObjectReferencingPermanent := self keptObjectInVMVariable2. + oldReplacement := self keptObjectInVMVariable3. + + "After GC nobody points to the forwarded object" + self assert: (memory fetchPointer: 0 ofObject: oldObjectReferencingPermanent) equals: oldReplacement. + self assert: (memory fetchPointer: 0 ofObject: youngObjectReferencingPermanent) equals: oldReplacement. + self assert: (memory fetchPointer: 0 ofObject: permanentObjectReferencingPermanent) equals: oldReplacement. +] + +{ #category : 'tests - become' } +VMPermanentSpaceMemoryTest >> testBecomingTwoWayOfPermanentObjectWithOldObjectLeavingForwarded [ + + | permanentObject oldReplacement arrFrom arrTo ec youngObjectReferencingPermanent oldObjectReferencingPermanent permanentObjectReferencingPermanent | + + permanentObject := self newPermanentObjectWithSlots: 1. + memory storePointer: 0 ofObject: permanentObject withValue: (self newOldSpaceObjectWithSlots: 0). + + youngObjectReferencingPermanent := self newObjectWithSlots: 1. + memory storePointer: 0 ofObject: youngObjectReferencingPermanent withValue: permanentObject. + self keepObjectInVMVariable1: youngObjectReferencingPermanent. + + oldObjectReferencingPermanent := self newOldSpaceObjectWithSlots: 1. + memory storePointer: 0 ofObject: oldObjectReferencingPermanent withValue: permanentObject. + self keepObjectInVMVariable2: oldObjectReferencingPermanent. + + permanentObjectReferencingPermanent := self newPermanentObjectWithSlots: 1. + memory storePointer: 0 ofObject: permanentObjectReferencingPermanent withValue: permanentObject. + + memory fullGC. + + youngObjectReferencingPermanent := self keptObjectInVMVariable1. + oldObjectReferencingPermanent := self keptObjectInVMVariable2. + + self assert: (memory getFromPermToOldSpaceRememberedSet isInRememberedSet: permanentObject). + self assert: (memory fetchPointer: 0 ofObject: oldObjectReferencingPermanent) equals: permanentObject. + self assert: (memory fetchPointer: 0 ofObject: permanentObjectReferencingPermanent) equals: permanentObject. + self assert: (memory fetchPointer: 0 ofObject: youngObjectReferencingPermanent) equals: permanentObject. + + oldReplacement := self newOldSpaceObjectWithSlots: 0. + + arrFrom := self newArrayWithSlots: 1. + arrTo := self newArrayWithSlots: 1. + + memory storePointer: 0 ofObject: arrFrom withValue: permanentObject. + memory storePointer: 0 ofObject: arrTo withValue: oldReplacement. + ec := memory become: arrFrom with: arrTo twoWay: true copyHash: false. + + self assert: ec equals: PrimNoErr. + + self keepObjectInVMVariable3: (memory followForwarded: permanentObject). + self assert: (memory isPermanent: (memory followForwarded: oldReplacement)). + + "The initial permanent object is now forwarded" + self assert: (memory isForwarded: permanentObject). + "Old and New objects still points to it" + self assert: (memory fetchPointer: 0 ofObject: oldObjectReferencingPermanent) equals: permanentObject. + self assert: (memory fetchPointer: 0 ofObject: youngObjectReferencingPermanent) equals: permanentObject. + + "Perm objects still points to the result" + self assert: (memory fetchPointer: 0 ofObject: permanentObjectReferencingPermanent) equals: self keptObjectInVMVariable3. + + "The forwarded object is not in any remembered set" + self deny: (memory getFromPermToOldSpaceRememberedSet isInRememberedSet: permanentObject). + self deny: (memory getFromPermToNewSpaceRememberedSet isInRememberedSet: permanentObject). + + memory fullGC. + + youngObjectReferencingPermanent := self keptObjectInVMVariable1. + oldObjectReferencingPermanent := self keptObjectInVMVariable2. + + + "After GC nobody points to the forwarded object" + self assert: (memory fetchPointer: 0 ofObject: oldObjectReferencingPermanent) equals: self keptObjectInVMVariable3. + self assert: (memory fetchPointer: 0 ofObject: youngObjectReferencingPermanent) equals: self keptObjectInVMVariable3. + self assert: (memory fetchPointer: 0 ofObject: permanentObjectReferencingPermanent) equals: self keptObjectInVMVariable3. + + self assert: memory isPermSpaceRememberedSetSane. +] + +{ #category : 'tests - become' } +VMPermanentSpaceMemoryTest >> testBecomingTwoWayOfPermanentObjectWithOldObjectNotLeavingForwarded [ + + | permanentObject oldReplacement arrFrom arrTo ec youngObjectReferencingPermanent oldObjectReferencingPermanent permanentObjectReferencingPermanent oldValue newValue | + + permanentObject := self newPermanentObjectWithSlots: 1. + memory storePointer: 0 ofObject: permanentObject withValue: (oldValue := self newOldSpaceObjectWithSlots: 0). + + youngObjectReferencingPermanent := self newObjectWithSlots: 1. + memory storePointer: 0 ofObject: youngObjectReferencingPermanent withValue: permanentObject. + self keepObjectInVMVariable1: youngObjectReferencingPermanent. + + oldObjectReferencingPermanent := self newOldSpaceObjectWithSlots: 1. + memory storePointer: 0 ofObject: oldObjectReferencingPermanent withValue: permanentObject. + self keepObjectInVMVariable2: oldObjectReferencingPermanent. + + permanentObjectReferencingPermanent := self newPermanentObjectWithSlots: 1. + memory storePointer: 0 ofObject: permanentObjectReferencingPermanent withValue: permanentObject. + + memory fullGC. + + youngObjectReferencingPermanent := self keptObjectInVMVariable1. + oldObjectReferencingPermanent := self keptObjectInVMVariable2. + + self assert: (memory getFromPermToOldSpaceRememberedSet isInRememberedSet: permanentObject). + self assert: (memory fetchPointer: 0 ofObject: oldObjectReferencingPermanent) equals: permanentObject. + self assert: (memory fetchPointer: 0 ofObject: permanentObjectReferencingPermanent) equals: permanentObject. + self assert: (memory fetchPointer: 0 ofObject: youngObjectReferencingPermanent) equals: permanentObject. + + oldReplacement := self newOldSpaceObjectWithSlots: 1. + memory storePointer: 0 ofObject: oldReplacement withValue: (newValue := self newObjectWithSlots: 0). + + self keepObjectInVMVariable3: oldReplacement. + + arrFrom := self newArrayWithSlots: 1. + arrTo := self newArrayWithSlots: 1. + + memory storePointer: 0 ofObject: arrFrom withValue: permanentObject. + memory storePointer: 0 ofObject: arrTo withValue: oldReplacement. + ec := memory become: arrFrom with: arrTo twoWay: true copyHash: false. + + self assert: ec equals: PrimNoErr. + + "The initial permanent object is in place changed, so it is the same address" + self deny: (memory isForwarded: permanentObject). + "Old and New objects still points to it" + self assert: (memory fetchPointer: 0 ofObject: oldObjectReferencingPermanent) equals: permanentObject. + self assert: (memory fetchPointer: 0 ofObject: youngObjectReferencingPermanent) equals: permanentObject. + + "Perm objects still points to the result" + self assert: (memory fetchPointer: 0 ofObject: permanentObjectReferencingPermanent) equals: permanentObject. + + "The forwarded object is not in any remembered set" + self deny: (memory getFromPermToOldSpaceRememberedSet isInRememberedSet: permanentObject). + self assert: (memory getFromPermToNewSpaceRememberedSet isInRememberedSet: permanentObject). + + self assert: (memory fetchPointer: 0 ofObject: permanentObject) equals: newValue. + + memory fullGC. + + youngObjectReferencingPermanent := self keptObjectInVMVariable1. + oldObjectReferencingPermanent := self keptObjectInVMVariable2. + + "After GC nobody points to the forwarded object" + self assert: (memory fetchPointer: 0 ofObject: oldObjectReferencingPermanent) equals: permanentObject. + self assert: (memory fetchPointer: 0 ofObject: youngObjectReferencingPermanent) equals: permanentObject. + self assert: (memory fetchPointer: 0 ofObject: permanentObjectReferencingPermanent) equals: permanentObject. + + self assert: memory isPermSpaceRememberedSetSane. +] + +{ #category : 'tests - become' } +VMPermanentSpaceMemoryTest >> testBecomingTwoWayOfPermanentObjectWithPermanentObjectLeavingForwarded [ + + | permanentObject permanentReplacement arrFrom arrTo ec youngObjectReferencingPermanent oldObjectReferencingPermanent permanentObjectReferencingPermanent | + + permanentObject := self newPermanentObjectWithSlots: 1. + memory storePointer: 0 ofObject: permanentObject withValue: (self newOldSpaceObjectWithSlots: 0). + + youngObjectReferencingPermanent := self newObjectWithSlots: 1. + memory storePointer: 0 ofObject: youngObjectReferencingPermanent withValue: permanentObject. + self keepObjectInVMVariable1: youngObjectReferencingPermanent. + + oldObjectReferencingPermanent := self newOldSpaceObjectWithSlots: 1. + memory storePointer: 0 ofObject: oldObjectReferencingPermanent withValue: permanentObject. + self keepObjectInVMVariable2: oldObjectReferencingPermanent. + + permanentObjectReferencingPermanent := self newPermanentObjectWithSlots: 1. + memory storePointer: 0 ofObject: permanentObjectReferencingPermanent withValue: permanentObject. + + memory fullGC. + + youngObjectReferencingPermanent := self keptObjectInVMVariable1. + oldObjectReferencingPermanent := self keptObjectInVMVariable2. + + self assert: (memory getFromPermToOldSpaceRememberedSet isInRememberedSet: permanentObject). + self assert: (memory fetchPointer: 0 ofObject: oldObjectReferencingPermanent) equals: permanentObject. + self assert: (memory fetchPointer: 0 ofObject: permanentObjectReferencingPermanent) equals: permanentObject. + self assert: (memory fetchPointer: 0 ofObject: youngObjectReferencingPermanent) equals: permanentObject. + + permanentReplacement := self newPermanentObjectWithSlots: 0. + + arrFrom := self newArrayWithSlots: 1. + arrTo := self newArrayWithSlots: 1. + + memory storePointer: 0 ofObject: arrFrom withValue: permanentObject. + memory storePointer: 0 ofObject: arrTo withValue: permanentReplacement. + ec := memory become: arrFrom with: arrTo twoWay: true copyHash: false. + + self assert: ec equals: PrimNoErr. + + self keepObjectInVMVariable3: (memory followForwarded: permanentObject). + + self assert: (memory isPermanent: (memory followForwarded: permanentReplacement)). + + "The initial permanent object is now forwarded" + self assert: (memory isForwarded: permanentObject). + "Old and New objects still points to it" + self assert: (memory fetchPointer: 0 ofObject: oldObjectReferencingPermanent) equals: permanentObject. + self assert: (memory fetchPointer: 0 ofObject: youngObjectReferencingPermanent) equals: permanentObject. + + "Perm objects still points to the result" + self assert: (memory fetchPointer: 0 ofObject: permanentObjectReferencingPermanent) equals: self keptObjectInVMVariable3. + + "The forwarded object is not in any remembered set" + self deny: (memory getFromPermToOldSpaceRememberedSet isInRememberedSet: permanentObject). + self deny: (memory getFromPermToNewSpaceRememberedSet isInRememberedSet: permanentObject). + + memory fullGC. + + youngObjectReferencingPermanent := self keptObjectInVMVariable1. + oldObjectReferencingPermanent := self keptObjectInVMVariable2. + + + "After GC nobody points to the forwarded object" + self assert: (memory fetchPointer: 0 ofObject: oldObjectReferencingPermanent) equals: self keptObjectInVMVariable3. + self assert: (memory fetchPointer: 0 ofObject: youngObjectReferencingPermanent) equals: self keptObjectInVMVariable3. + self assert: (memory fetchPointer: 0 ofObject: permanentObjectReferencingPermanent) equals: self keptObjectInVMVariable3. + + self assert: memory isPermSpaceRememberedSetSane. +] + +{ #category : 'tests - become' } +VMPermanentSpaceMemoryTest >> testBecomingTwoWayOfPermanentObjectWithPermanentObjectNotLeavingForwarded [ + + | permanentObject oldReplacement arrFrom arrTo ec youngObjectReferencingPermanent oldObjectReferencingPermanent permanentObjectReferencingPermanent oldValue newValue | + + permanentObject := self newPermanentObjectWithSlots: 1. + memory storePointer: 0 ofObject: permanentObject withValue: (oldValue := self newOldSpaceObjectWithSlots: 0). + + youngObjectReferencingPermanent := self newObjectWithSlots: 1. + memory storePointer: 0 ofObject: youngObjectReferencingPermanent withValue: permanentObject. + self keepObjectInVMVariable1: youngObjectReferencingPermanent. + + oldObjectReferencingPermanent := self newOldSpaceObjectWithSlots: 1. + memory storePointer: 0 ofObject: oldObjectReferencingPermanent withValue: permanentObject. + self keepObjectInVMVariable2: oldObjectReferencingPermanent. + + permanentObjectReferencingPermanent := self newPermanentObjectWithSlots: 1. + memory storePointer: 0 ofObject: permanentObjectReferencingPermanent withValue: permanentObject. + + memory fullGC. + + youngObjectReferencingPermanent := self keptObjectInVMVariable1. + oldObjectReferencingPermanent := self keptObjectInVMVariable2. + + self assert: (memory getFromPermToOldSpaceRememberedSet isInRememberedSet: permanentObject). + self assert: (memory fetchPointer: 0 ofObject: oldObjectReferencingPermanent) equals: permanentObject. + self assert: (memory fetchPointer: 0 ofObject: permanentObjectReferencingPermanent) equals: permanentObject. + self assert: (memory fetchPointer: 0 ofObject: youngObjectReferencingPermanent) equals: permanentObject. + + oldReplacement := self newPermanentObjectWithSlots: 1. + memory storePointer: 0 ofObject: oldReplacement withValue: (newValue := self newObjectWithSlots: 0). + + self keepObjectInVMVariable3: oldReplacement. + + arrFrom := self newArrayWithSlots: 1. + arrTo := self newArrayWithSlots: 1. + + memory storePointer: 0 ofObject: arrFrom withValue: permanentObject. + memory storePointer: 0 ofObject: arrTo withValue: oldReplacement. + ec := memory become: arrFrom with: arrTo twoWay: true copyHash: false. + + self assert: ec equals: PrimNoErr. + + "The initial permanent object is in place changed, so it is the same address" + self deny: (memory isForwarded: permanentObject). + "Old and New objects still points to it" + self assert: (memory fetchPointer: 0 ofObject: oldObjectReferencingPermanent) equals: permanentObject. + self assert: (memory fetchPointer: 0 ofObject: youngObjectReferencingPermanent) equals: permanentObject. + + "Perm objects still points to the result" + self assert: (memory fetchPointer: 0 ofObject: permanentObjectReferencingPermanent) equals: permanentObject. + + "The forwarded object is not in any remembered set" + self deny: (memory getFromPermToOldSpaceRememberedSet isInRememberedSet: permanentObject). + self assert: (memory getFromPermToNewSpaceRememberedSet isInRememberedSet: permanentObject). + + self assert: (memory fetchPointer: 0 ofObject: permanentObject) equals: newValue. + + memory fullGC. + + youngObjectReferencingPermanent := self keptObjectInVMVariable1. + oldObjectReferencingPermanent := self keptObjectInVMVariable2. + + "After GC nobody points to the forwarded object" + self assert: (memory fetchPointer: 0 ofObject: oldObjectReferencingPermanent) equals: permanentObject. + self assert: (memory fetchPointer: 0 ofObject: youngObjectReferencingPermanent) equals: permanentObject. + self assert: (memory fetchPointer: 0 ofObject: permanentObjectReferencingPermanent) equals: permanentObject. + + self assert: memory isPermSpaceRememberedSetSane. +] + +{ #category : 'tests - become' } +VMPermanentSpaceMemoryTest >> testBecomingTwoWayOfPermanentObjectWithYoungObjectLeavingForwarded [ + + | permanentObject youngReplacement arrFrom arrTo ec youngObjectReferencingPermanent oldObjectReferencingPermanent permanentObjectReferencingPermanent | + + permanentObject := self newPermanentObjectWithSlots: 1. + memory storePointer: 0 ofObject: permanentObject withValue: (self newOldSpaceObjectWithSlots: 0). + + youngObjectReferencingPermanent := self newObjectWithSlots: 1. + memory storePointer: 0 ofObject: youngObjectReferencingPermanent withValue: permanentObject. + self keepObjectInVMVariable1: youngObjectReferencingPermanent. + + oldObjectReferencingPermanent := self newOldSpaceObjectWithSlots: 1. + memory storePointer: 0 ofObject: oldObjectReferencingPermanent withValue: permanentObject. + self keepObjectInVMVariable2: oldObjectReferencingPermanent. + + permanentObjectReferencingPermanent := self newPermanentObjectWithSlots: 1. + memory storePointer: 0 ofObject: permanentObjectReferencingPermanent withValue: permanentObject. + + memory fullGC. + + youngObjectReferencingPermanent := self keptObjectInVMVariable1. + oldObjectReferencingPermanent := self keptObjectInVMVariable2. + + self assert: (memory getFromPermToOldSpaceRememberedSet isInRememberedSet: permanentObject). + self assert: (memory fetchPointer: 0 ofObject: oldObjectReferencingPermanent) equals: permanentObject. + self assert: (memory fetchPointer: 0 ofObject: permanentObjectReferencingPermanent) equals: permanentObject. + self assert: (memory fetchPointer: 0 ofObject: youngObjectReferencingPermanent) equals: permanentObject. + + youngReplacement := self newObjectWithSlots: 0. + + arrFrom := self newArrayWithSlots: 1. + arrTo := self newArrayWithSlots: 1. + + memory storePointer: 0 ofObject: arrFrom withValue: permanentObject. + memory storePointer: 0 ofObject: arrTo withValue: youngReplacement. + ec := memory become: arrFrom with: arrTo twoWay: true copyHash: false. + + self assert: ec equals: PrimNoErr. + + self keepObjectInVMVariable3: (memory followForwarded: permanentObject). + self assert: (memory isPermanent: (memory followForwarded: youngReplacement)). + + "The initial permanent object is now forwarded" + self assert: (memory isForwarded: permanentObject). + "Old and New objects still points to it" + self assert: (memory fetchPointer: 0 ofObject: oldObjectReferencingPermanent) equals: permanentObject. + self assert: (memory fetchPointer: 0 ofObject: youngObjectReferencingPermanent) equals: permanentObject. + + "Perm objects still points to the result" + self assert: (memory fetchPointer: 0 ofObject: permanentObjectReferencingPermanent) equals: self keptObjectInVMVariable3. + + "The forwarded object is not in any remembered set" + self deny: (memory getFromPermToOldSpaceRememberedSet isInRememberedSet: permanentObject). + self deny: (memory getFromPermToNewSpaceRememberedSet isInRememberedSet: permanentObject). + + memory fullGC. + + youngObjectReferencingPermanent := self keptObjectInVMVariable1. + oldObjectReferencingPermanent := self keptObjectInVMVariable2. + + + "After GC nobody points to the forwarded object" + self assert: (memory fetchPointer: 0 ofObject: oldObjectReferencingPermanent) equals: self keptObjectInVMVariable3. + self assert: (memory fetchPointer: 0 ofObject: youngObjectReferencingPermanent) equals: self keptObjectInVMVariable3. + self assert: (memory fetchPointer: 0 ofObject: permanentObjectReferencingPermanent) equals: self keptObjectInVMVariable3. + + self assert: memory isPermSpaceRememberedSetSane. +] + +{ #category : 'tests - become' } +VMPermanentSpaceMemoryTest >> testBecomingTwoWayOfPermanentObjectWithYoungObjectNotLeavingForwarded [ + + | permanentObject youngReplacement arrFrom arrTo ec youngObjectReferencingPermanent oldObjectReferencingPermanent permanentObjectReferencingPermanent oldValue newValue | + + permanentObject := self newPermanentObjectWithSlots: 1. + memory storePointer: 0 ofObject: permanentObject withValue: (oldValue := self newOldSpaceObjectWithSlots: 0). + + youngObjectReferencingPermanent := self newObjectWithSlots: 1. + memory storePointer: 0 ofObject: youngObjectReferencingPermanent withValue: permanentObject. + self keepObjectInVMVariable1: youngObjectReferencingPermanent. + + oldObjectReferencingPermanent := self newOldSpaceObjectWithSlots: 1. + memory storePointer: 0 ofObject: oldObjectReferencingPermanent withValue: permanentObject. + self keepObjectInVMVariable2: oldObjectReferencingPermanent. + + permanentObjectReferencingPermanent := self newPermanentObjectWithSlots: 1. + memory storePointer: 0 ofObject: permanentObjectReferencingPermanent withValue: permanentObject. + + memory fullGC. + + youngObjectReferencingPermanent := self keptObjectInVMVariable1. + oldObjectReferencingPermanent := self keptObjectInVMVariable2. + + self assert: (memory getFromPermToOldSpaceRememberedSet isInRememberedSet: permanentObject). + self assert: (memory fetchPointer: 0 ofObject: oldObjectReferencingPermanent) equals: permanentObject. + self assert: (memory fetchPointer: 0 ofObject: permanentObjectReferencingPermanent) equals: permanentObject. + self assert: (memory fetchPointer: 0 ofObject: youngObjectReferencingPermanent) equals: permanentObject. + + youngReplacement := self newObjectWithSlots: 1. + memory storePointer: 0 ofObject: youngReplacement withValue: (newValue := self newObjectWithSlots: 0). + + self keepObjectInVMVariable3: youngReplacement. + + arrFrom := self newArrayWithSlots: 1. + arrTo := self newArrayWithSlots: 1. + + memory storePointer: 0 ofObject: arrFrom withValue: permanentObject. + memory storePointer: 0 ofObject: arrTo withValue: youngReplacement. + ec := memory become: arrFrom with: arrTo twoWay: true copyHash: false. + + self assert: ec equals: PrimNoErr. + + "The initial permanent object is in place changed, so it is the same address" + self deny: (memory isForwarded: permanentObject). + "Old and New objects still points to it" + self assert: (memory fetchPointer: 0 ofObject: oldObjectReferencingPermanent) equals: permanentObject. + self assert: (memory fetchPointer: 0 ofObject: youngObjectReferencingPermanent) equals: permanentObject. + + "Perm objects still points to the result" + self assert: (memory fetchPointer: 0 ofObject: permanentObjectReferencingPermanent) equals: permanentObject. + + "The forwarded object is not in any remembered set" + self deny: (memory getFromPermToOldSpaceRememberedSet isInRememberedSet: permanentObject). + self assert: (memory getFromPermToNewSpaceRememberedSet isInRememberedSet: permanentObject). + + self assert: (memory fetchPointer: 0 ofObject: permanentObject) equals: newValue. + + memory fullGC. + + youngObjectReferencingPermanent := self keptObjectInVMVariable1. + oldObjectReferencingPermanent := self keptObjectInVMVariable2. + + "After GC nobody points to the forwarded object" + self assert: (memory fetchPointer: 0 ofObject: oldObjectReferencingPermanent) equals: permanentObject. + self assert: (memory fetchPointer: 0 ofObject: youngObjectReferencingPermanent) equals: permanentObject. + self assert: (memory fetchPointer: 0 ofObject: permanentObjectReferencingPermanent) equals: permanentObject. + + self assert: memory isPermSpaceRememberedSetSane. ] { #category : 'test - moving' } From 8051b6eb2e9c780c7bd71a7519d4819f580c5893 Mon Sep 17 00:00:00 2001 From: Pablo Tesone Date: Wed, 25 Sep 2024 12:06:05 +0200 Subject: [PATCH 09/17] - Fixing the swizzling of objects - Cloning should only create a permanent object if we are in the become, as we are handling the remembered sets --- .../VMMaker/Spur32BitMMLESimulator.class.st | 8 ------ .../VMMaker/Spur64BitMMLESimulator.class.st | 8 ------ .../VMMaker/SpurMemoryManager.class.st | 27 ++++++++++++------- 3 files changed, 18 insertions(+), 25 deletions(-) diff --git a/smalltalksrc/VMMaker/Spur32BitMMLESimulator.class.st b/smalltalksrc/VMMaker/Spur32BitMMLESimulator.class.st index 90674e4a6c..3fd8fb4c6e 100644 --- a/smalltalksrc/VMMaker/Spur32BitMMLESimulator.class.st +++ b/smalltalksrc/VMMaker/Spur32BitMMLESimulator.class.st @@ -85,14 +85,6 @@ Spur32BitMMLESimulator >> fetchFloatAt: floatBitsAddress into: aFloat [ aFloat at: 1 put: (self uint32AtPointer: floatBitsAddress+4) ] -{ #category : 'as yet unclassified' } -Spur32BitMMLESimulator >> fetchPointer: fieldIndex ofObject: objOop [ - self assert: (self isForwarded: objOop) not. - self assert: (fieldIndex >= 0 and: [fieldIndex < (self numSlotsOfAny: objOop) - or: [fieldIndex = 0 "forwarders"]]). - ^super fetchPointer: fieldIndex ofObject: objOop -] - { #category : 'spur bootstrap' } Spur32BitMMLESimulator >> freeLists [ ^freeLists diff --git a/smalltalksrc/VMMaker/Spur64BitMMLESimulator.class.st b/smalltalksrc/VMMaker/Spur64BitMMLESimulator.class.st index 05cf0892e9..27696830de 100644 --- a/smalltalksrc/VMMaker/Spur64BitMMLESimulator.class.st +++ b/smalltalksrc/VMMaker/Spur64BitMMLESimulator.class.st @@ -85,14 +85,6 @@ Spur64BitMMLESimulator >> fetchFloatAt: floatBitsAddress into: aFloat [ aFloat at: 1 put: (self uint32AtPointer: floatBitsAddress+4) ] -{ #category : 'as yet unclassified' } -Spur64BitMMLESimulator >> fetchPointer: fieldIndex ofObject: objOop [ - self assert: (self isForwarded: objOop) not. - self assert: (fieldIndex >= 0 and: [fieldIndex < (self numSlotsOfAny: objOop) - or: [fieldIndex = 0 "forwarders"]]). - ^super fetchPointer: fieldIndex ofObject: objOop -] - { #category : 'spur bootstrap' } Spur64BitMMLESimulator >> freeLists [ ^freeLists diff --git a/smalltalksrc/VMMaker/SpurMemoryManager.class.st b/smalltalksrc/VMMaker/SpurMemoryManager.class.st index e1909ad213..405e784555 100644 --- a/smalltalksrc/VMMaker/SpurMemoryManager.class.st +++ b/smalltalksrc/VMMaker/SpurMemoryManager.class.st @@ -1327,12 +1327,9 @@ SpurMemoryManager >> adjustAllOopsBy: bytesToShift [ [self swizzleFieldsOfFreeChunk: obj]]. obj := self objectAfter: obj limit: memoryMap oldSpaceEnd]. + "We need to iterate all the permSpace, as still we don't have the fromPermToOldSpaceRememberedSet. If we move the initialization of the remembered set before we can use it here or just after the initialization" - "As we know all the permanent space objects that are pointing to the old space, and as the permanent space is always in the same place. - We need only to iterate the remembered set to swizzle the fields of permanent objects" - - self getFromPermToOldSpaceRememberedSet - rememberedSetWithIndexDo: [ :oop :i | self swizzleFieldsOfObject: oop ]. + self allPermSpaceObjectsDo: [ :oop | self swizzleFieldsOfObject: oop ]. ] @@ -3965,12 +3962,23 @@ SpurMemoryManager >> cleverSwapHeaders: obj1 and: obj2 copyHashFlag: copyHashFla { #category : 'allocation' } SpurMemoryManager >> clone: objOop [ + + ^ self clone: objOop shouldAllocateInPermSpace: false +] + +{ #category : 'allocation' } +SpurMemoryManager >> clone: objOop shouldAllocateInPermSpace: shouldAllocateInPermSpace [ + + "Attention: the shouldAllocateInPermSpace is only used by the become, as it handles adding or not the new perm object to the remembered sets" + | numSlots fmt newObj | numSlots := self numSlotsOf: objOop. fmt := self formatOf: objOop. - (memoryMap isPermanentObject: objOop) - ifTrue: [ newObj := self allocateSlotsInPermSpace: numSlots format: fmt classIndex: (self classIndexOf: objOop)] + (shouldAllocateInPermSpace) + ifTrue: [ newObj := self allocateSlotsInPermSpace: numSlots + format: fmt + classIndex: (self classIndexOf: objOop)] ifFalse: [ numSlots > self maxSlotsForNewSpaceAlloc ifTrue: @@ -4014,6 +4022,7 @@ SpurMemoryManager >> clone: objOop [ ((memoryMap isOldObject: newObj) and: [(memoryMap isYoungObject: objOop) or: [self isRemembered: objOop]]) ifTrue: [self getFromOldSpaceRememberedSet remember: newObj]]]. + ^newObj ] @@ -10212,13 +10221,13 @@ SpurMemoryManager >> outOfPlaceBecome: obj1 and: obj2 copyHashFlag: copyHashFlag | clone1 clone2 | clone1 := (self isContextNonImm: obj1) ifTrue: [coInterpreter cloneContext: obj1] - ifFalse: [self clone: obj1]. + ifFalse: [self clone: obj1 shouldAllocateInPermSpace: (memoryMap isPermanentObject: obj1)]. clone1 ifNil: [ self error: 'Not enough space to copy the objects in two-way become. This should have been detected before'. ^ self]. clone2 := (self isContextNonImm: obj2) ifTrue: [coInterpreter cloneContext: obj2] - ifFalse: [self clone: obj2]. + ifFalse: [self clone: obj2 shouldAllocateInPermSpace: (memoryMap isPermanentObject: obj2)]. clone2 ifNil: [ self error: 'Not enough space to copy the objects in two-way become. This should have been detected before'.^ self ]. From e55b958d6135a0b2433da6182e862ef66cab0774 Mon Sep 17 00:00:00 2001 From: Pablo Tesone Date: Mon, 30 Sep 2024 15:03:42 +0200 Subject: [PATCH 10/17] - Adding validations of objects to run during debug - Fixing forwarders in the perm space. --- .../VMMaker/SpurMemoryManager.class.st | 172 ++++++++++++++---- .../VMMaker/StackInterpreter.class.st | 19 ++ smalltalksrc/VMMaker/VMMemoryMap.class.st | 8 + 3 files changed, 163 insertions(+), 36 deletions(-) diff --git a/smalltalksrc/VMMaker/SpurMemoryManager.class.st b/smalltalksrc/VMMaker/SpurMemoryManager.class.st index 405e784555..1b0f433dff 100644 --- a/smalltalksrc/VMMaker/SpurMemoryManager.class.st +++ b/smalltalksrc/VMMaker/SpurMemoryManager.class.st @@ -1814,6 +1814,15 @@ SpurMemoryManager >> allPastSpaceObjectsDo: aBlock [ aBlock value: objOop] ] +{ #category : 'perm - space' } +SpurMemoryManager >> allPermSpaceForwarded: aForwardedBlockClosure ObjectsDo: aBlockClosure [ + + self allPermSpaceObjectsDo: [ :anObj | + (self isForwarded: anObj) + ifTrue: [ aForwardedBlockClosure value: anObj ] + ifFalse: [ aBlockClosure value: anObj ] ] +] + { #category : 'perm - space' } SpurMemoryManager >> allPermSpaceNonForwardedObjectsDo: aBlockClosure [ @@ -4541,6 +4550,40 @@ SpurMemoryManager >> doScavenge: tenuringCriterion [ self resetAllocationAccountingAfterGC ] +{ #category : 'validations' } +SpurMemoryManager >> doValidateObjectMemory [ + + | returnCode | + + returnCode := true. + + self allObjectsDo: [ :anOop | + (self isForwarded: anOop) + ifTrue: [ |referent | + referent := self fetchPointer: 0 ofMaybeForwardedObject: anOop. + (self addressCouldBeObj: referent) + ifFalse: [ + self + logError: 'Error found in object at %p' + _: (self cCoerce: anOop to: 'void*'). + returnCode := false. ] + ] + ifFalse: [ + 0 to: (self numPointerSlotsOf: anOop) - 1 do: [ :idx | + | aReference | + aReference := self fetchPointer: idx ofObject: anOop. + ((self isImmediate: aReference) or: [ + (self addressCouldBeObj: aReference) + or: [ memoryMap isInCodeZone: aReference ] ]) + ifFalse: [ + self + logError: 'Error found in object at %p' + _: (self cCoerce: anOop to: 'void*'). + returnCode := false ] ] ] ]. + + ^ returnCode +] + { #category : 'accessing' } SpurMemoryManager >> edenBytes [ @@ -6075,6 +6118,8 @@ SpurMemoryManager >> globalGarbageCollect [ self assert: (self isEmptyObjStack: markStack). self assert: (self isEmptyObjStack: weaklingStack). + "self validateObjectMemory." + "Mark objects /before/ scavenging, to empty the rememberedTable of unmarked roots." self markObjects: true. gcMarkEndUsecs := coInterpreter ioUTCMicrosecondsNow. @@ -6098,7 +6143,9 @@ SpurMemoryManager >> globalGarbageCollect [ self assert: (self isEmptyObjStack: markStack). self assert: (self isEmptyObjStack: weaklingStack). self assert: self allObjectsUnmarked. - self runLeakCheckerFor: GCModeFull + self runLeakCheckerFor: GCModeFull. + + "self validateObjectMemory" ] { #category : 'object testing' } @@ -7794,48 +7841,74 @@ SpurMemoryManager >> isPermSpaceRememberedSetSane [ - - | refersNewSpace refersOldSpace isInPermToNewRememberedSet isInPermToOldRememberedSet isValid| + | refersNewSpace refersOldSpace isValid | isValid := true. - self allPermSpaceNonForwardedObjectsDo: [ :objOop | - - refersNewSpace := self hasYoungReferents: objOop. - refersOldSpace := self hasOldReferents: objOop. - - isInPermToNewRememberedSet := self getFromPermToNewSpaceRememberedSet isInRememberedSet: objOop. - isInPermToOldRememberedSet := self getFromPermToOldSpaceRememberedSet isInRememberedSet: objOop. + self + allPermSpaceForwarded: [ :aForwardedPermSpaceObject | + | referenced | + referenced := self + fetchPointer: 0 + ofMaybeForwardedObject: aForwardedPermSpaceObject. - (isInPermToNewRememberedSet and: [ refersNewSpace or: refersOldSpace ]) - ifTrue: [ - (self isRemembered: objOop) - ifFalse: [ - isValid := false. - self logError: 'Offending Object: %p' _: objOop. - self error: 'Object should be marked as remembered' ]]. + refersOldSpace := self getMemoryMap isYoungObject: referenced. + refersNewSpace := self getMemoryMap isOldObject: referenced. - (refersNewSpace and: [ isInPermToNewRememberedSet not ]) - ifTrue: [ - isValid := false. - self logError: 'Offending Object: %p' _: objOop. - self error: 'Object should be in remembered set (Perm to New)' ]. + (self + isPermSpaceRememberedSetSaneMember: aForwardedPermSpaceObject + withNewSpaceRefs: refersNewSpace + withOldSpaceRefs: refersOldSpace) + ifFalse: [ isValid := false ] ] + ObjectsDo: [ :objOop | + refersNewSpace := self hasYoungReferents: objOop. + refersOldSpace := self hasOldReferents: objOop. - (isInPermToNewRememberedSet and: [refersNewSpace not and: [ refersOldSpace not ]]) - ifTrue: [ - isValid := false. - self logError: 'Offending Object: %p' _: objOop. - self error: 'Object should not be in remembered set (Perm to New)'. ]. + (self + isPermSpaceRememberedSetSaneMember: objOop + withNewSpaceRefs: refersNewSpace + withOldSpaceRefs: refersOldSpace) + ifFalse: [ isValid := false ] ]. - (refersOldSpace and: [ isInPermToNewRememberedSet not and: [isInPermToOldRememberedSet not] ]) - ifTrue: [ - isValid := false. - self logError: 'Offending Object: %p' _: objOop. - self error: 'Object should not be in remembered set (Perm to Old)'. ]. + ^ isValid +] - ]. +{ #category : 'debug printing' } +SpurMemoryManager >> isPermSpaceRememberedSetSaneMember: objOop withNewSpaceRefs: refersNewSpace withOldSpaceRefs: refersOldSpace [ + + | isInPermToNewRememberedSet isInPermToOldRememberedSet| + + isInPermToNewRememberedSet := self getFromPermToNewSpaceRememberedSet + isInRememberedSet: objOop. + isInPermToOldRememberedSet := self getFromPermToOldSpaceRememberedSet + isInRememberedSet: objOop. + + (isInPermToNewRememberedSet and: [ refersNewSpace or: refersOldSpace ]) + ifTrue: [ + (self isRemembered: objOop) ifFalse: [ + self logError: 'Offending Object: %p' _: objOop. + self error: 'Object should be marked as remembered'. + ^ false ] ]. + + (refersNewSpace and: [ isInPermToNewRememberedSet not ]) ifTrue: [ + self logError: 'Offending Object: %p' _: objOop. + self error: 'Object should be in remembered set (Perm to New)'. + ^ false ]. + + (isInPermToNewRememberedSet and: [ + refersNewSpace not and: [ refersOldSpace not ] ]) ifTrue: [ + self logError: 'Offending Object: %p' _: objOop. + self error: 'Object should not be in remembered set (Perm to New)'. + ^ false ]. + + (refersOldSpace and: [ + isInPermToNewRememberedSet not and: [ + isInPermToOldRememberedSet not ] ]) ifTrue: [ + self logError: 'Offending Object: %p' _: objOop. + self error: 'Object should not be in remembered set (Perm to Old)'. + ^ false ]. - ^ isValid. + ^ true. ] { #category : 'object testing' } @@ -11355,7 +11428,25 @@ SpurMemoryManager >> recreateFromPermSpaceRememberedSet [ self getFromPermToOldSpaceRememberedSet emptyRememberedSet. self getFromPermToNewSpaceRememberedSet emptyRememberedSet. - self allPermSpaceNonForwardedObjectsDo: [ :aPermSpaceObject | + self + allPermSpaceForwarded: [ :aForwardedPermSpaceObject | + | referenced | + referenced := self + fetchPointer: 0 + ofMaybeForwardedObject: aForwardedPermSpaceObject. + + (self isForwarded: referenced) + ifTrue: [ + referenced := self followForwarded: referenced. + self storePointerUnchecked: 0 ofMaybeForwardedObject: aForwardedPermSpaceObject withValue: referenced ]. + + (self getMemoryMap isYoungObject: referenced) + ifTrue: [ self getFromPermToNewSpaceRememberedSet remember: aForwardedPermSpaceObject ] + ifFalse: [ (self getMemoryMap isOldObject: referenced) + ifTrue: [ self getFromPermToOldSpaceRememberedSet rememberWithoutMarkingAsRemembered: aForwardedPermSpaceObject ] ] + + ] + ObjectsDo: [ :aPermSpaceObject | | slotIndex referenced numPointerSlots refersNewSpace refersOldSpace | "We clear the bit of all remembered objects, it will be recalculated" @@ -11367,7 +11458,6 @@ SpurMemoryManager >> recreateFromPermSpaceRememberedSet [ slotIndex := 0. - "If the object already refers to new space, we don't check anymore" [ refersNewSpace not and: [slotIndex < numPointerSlots] ] whileTrue: [ referenced := self fetchPointer: slotIndex ofObject: aPermSpaceObject. @@ -13471,6 +13561,16 @@ SpurMemoryManager >> validObjStacks [ and: [mournQueue = nilObj or: [self isValidObjStack: mournQueue]]] ] +{ #category : 'validations' } +SpurMemoryManager >> validateObjectMemory [ + + + + + self doValidateObjectMemory + ifFalse: [ self logError: 'Error in validating object memory' ]. +] + { #category : 'gc - scavenge/compact' } SpurMemoryManager >> vanillaRemapObj: objOop [ "Scavenge or simply follow objOop. Answer the new location of objOop. diff --git a/smalltalksrc/VMMaker/StackInterpreter.class.st b/smalltalksrc/VMMaker/StackInterpreter.class.st index c5abd40d7f..7ed0d6c47a 100644 --- a/smalltalksrc/VMMaker/StackInterpreter.class.st +++ b/smalltalksrc/VMMaker/StackInterpreter.class.st @@ -12279,6 +12279,25 @@ StackInterpreter >> printPageHeadFrame [ self printFrame: stackPage headFP WithSP: stackPage headSP ] +{ #category : 'debug printing' } +StackInterpreter >> printPointersTo: anAddress [ + + + + | referent | + + objectMemory allObjectsDo: [ :anOop | + (objectMemory isForwarded: anOop) + ifTrue: [ + referent := objectMemory fetchPointer: 0 ofMaybeForwardedObject: anOop. + referent = anAddress ifTrue: [ self shortPrintOop: anOop ]] + ifFalse: [ + 0 to: (objectMemory numPointerSlotsOf: anOop) - 1 do: [ :idx | + referent := objectMemory fetchPointer: idx ofObject: anOop. + referent = anAddress ifTrue: [ self shortPrintOop: anOop ] ]]]. + +] + { #category : 'debug printing' } StackInterpreter >> printProcessStack: aProcess [ diff --git a/smalltalksrc/VMMaker/VMMemoryMap.class.st b/smalltalksrc/VMMaker/VMMemoryMap.class.st index aa5ca681d8..c9414754d9 100644 --- a/smalltalksrc/VMMaker/VMMemoryMap.class.st +++ b/smalltalksrc/VMMaker/VMMemoryMap.class.st @@ -493,6 +493,14 @@ VMMemoryMap >> insufficientMemoryAvailableError [ self error. ] +{ #category : 'testing objects' } +VMMemoryMap >> isInCodeZone: anOop [ + + + + ^ anOop >= codeZoneStart and: [ anOop < codeZoneEnd ] +] + { #category : 'testing objects' } VMMemoryMap >> isOldObject: anOop [ From c8206cdee9d2c47efc2f0ff155f2f17d65a1990e Mon Sep 17 00:00:00 2001 From: Pablo Tesone Date: Tue, 1 Oct 2024 14:32:55 +0200 Subject: [PATCH 11/17] Adding working copy option --- src/parameters/parameters.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/parameters/parameters.c b/src/parameters/parameters.c index 9cf3cfbae8..3eb270c761 100644 --- a/src/parameters/parameters.c +++ b/src/parameters/parameters.c @@ -76,6 +76,7 @@ static VMErrorCode processMaxCodeSpaceSizeOption(const char *argument, VMParamet static VMErrorCode processEdenSizeOption(const char *argument, VMParameters * params); static VMErrorCode processWorkerOption(const char *argument, VMParameters * params); static VMErrorCode processMinPermSpaceSizeOption(const char *argument, VMParameters * params); +static VMErrorCode processWorkingDirectory(const char *argument, VMParameters * params); static VMErrorCode processAvoidSearchingSegmentsWithPinnedObjects(const char *argument, VMParameters * params); static const VMParameterSpec vm_parameters_spec[] = @@ -96,6 +97,8 @@ static const VMParameterSpec vm_parameters_spec[] = {.name = "edenSize", .hasArgument = true, .function = processEdenSizeOption}, {.name = "minPermSpaceSize", .hasArgument = true, .function = processMinPermSpaceSizeOption}, + {.name = "workingDirectory", .hasArgument = true, .function = processWorkingDirectory}, + {.name = "avoidSearchingSegmentsWithPinnedObjects", .hasArgument = false, .function = processAvoidSearchingSegmentsWithPinnedObjects}, #ifdef __APPLE__ // This parameter is passed by the XCode debugger. @@ -439,6 +442,7 @@ vm_printUsageTo(FILE *out) " It is possible to use k(kB), M(MB) and G(GB).\n" " --minPermSpaceSize=[mk] Sets the size of eden\n" " It is possible to use k(kB), M(MB) and G(GB).\n" +" --workingDirectory= It sets the working directory for the running image.\n" "\n" " --avoidSearchingSegmentsWithPinnedObjects\n" " When pinning young objects, the objects are clonned into the old space.\n" @@ -541,6 +545,18 @@ processMinPermSpaceSizeOption(const char* originalArgument, VMParameters * param return VM_SUCCESS; } +static VMErrorCode +processWorkingDirectory(const char* originalArgument, VMParameters * params) +{ + + logDebug("Changing working directory to: %s", originalArgument); + if(chdir(originalArgument)== -1){ + logErrorFromErrno("Error changing directory"); + } + + return VM_SUCCESS; +} + static VMErrorCode processEdenSizeOption(const char* originalArgument, VMParameters * params) { From 404252217d2e486af1f9c3d50bc9fe68256b8d35 Mon Sep 17 00:00:00 2001 From: Pablo Tesone Date: Wed, 16 Oct 2024 11:58:14 +0200 Subject: [PATCH 12/17] Fixing cygpath conversion for newer version of cmake --- CMakeLists.txt | 20 ++------------------ cmake/vmmaker.cmake | 16 ++++++++++++---- macros.cmake | 14 ++++++++++++++ 3 files changed, 28 insertions(+), 22 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 956131db43..34baf23c04 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -198,7 +198,6 @@ if(MSVC) set(OS_TYPE "Win32") get_platform_name(VM_TARGET_OS) message(STATUS "Building for ${VM_TARGET_OS}") - set(CMAKE_CURRENT_SOURCE_DIR_TO_OUT ${CMAKE_CURRENT_SOURCE_DIR}) # Define WIN32_LEAN_AND_MEAN to exclude APIs such as Cryptography, DDE, RPC, Shell, and Windows Sockets # They can be included if needed @@ -212,17 +211,6 @@ elseif(WIN) unset(UNIX) unset(UNIX CACHE) - # transform the path into a windows path with unix backslashes C:/bla/blu - # this is the path required to send as argument to libraries outside of the control of cygwin (like pharo itself) - execute_process( - COMMAND cygpath ${CMAKE_CURRENT_SOURCE_DIR} --mixed - OUTPUT_VARIABLE CMAKE_CURRENT_SOURCE_DIR_TO_OUT - OUTPUT_STRIP_TRAILING_WHITESPACE) - execute_process( - COMMAND cygpath ${CMAKE_CURRENT_BINARY_DIR} --mixed - OUTPUT_VARIABLE CMAKE_CURRENT_BINARY_DIR_TO_OUT - OUTPUT_STRIP_TRAILING_WHITESPACE) - set(CMAKE_SHARED_LIBRARY_PREFIX "") set(CMAKE_SHARED_LIBRARY_SUFFIX ".dll") set(CMAKE_SHARED_MODULE_PREFIX "") @@ -247,10 +235,6 @@ elseif(WIN) elseif(UNIX) - # Use the default path to send as argument of extrernal apps (like pharo itself) - set(CMAKE_CURRENT_SOURCE_DIR_TO_OUT ${CMAKE_CURRENT_SOURCE_DIR}) - set(CMAKE_CURRENT_BINARY_DIR_TO_OUT ${CMAKE_CURRENT_BINARY_DIR}) - set(COMMON_FLAGS "-Wall -Werror=implicit-function-declaration") add_compile_definitions(LSB_FIRST=1) @@ -273,9 +257,9 @@ endif() # If we are generating sources, set the binary dir as the generation source dir, as vmmaker will generate the C files here. (we do not alter the source directory) # Otherwise set it to by default to the current binary dir, parametrizable if(${GENERATE_SOURCES}) - set(GENERATED_SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR_TO_OUT}) + set(GENERATED_SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}) else() - set(GENERATED_SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR_TO_OUT} CACHE STRING "Source directory where to find the generated source. Default value is CMAKE_CURRENT_BINARY_DIR") + set(GENERATED_SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR} CACHE STRING "Source directory where to find the generated source. Default value is CMAKE_CURRENT_BINARY_DIR") endif() if (${FEATURE_COMPILE_INLINE_MEMORY_ACCESSORS}) diff --git a/cmake/vmmaker.cmake b/cmake/vmmaker.cmake index ca1d1cccac..bd8fc92bd9 100644 --- a/cmake/vmmaker.cmake +++ b/cmake/vmmaker.cmake @@ -46,7 +46,7 @@ set(PLUGIN_GENERATED_FILES if(GENERATE_SOURCES) #Setting vmmaker directory and image - set( VMMAKER_DIR "${CMAKE_CURRENT_BINARY_DIR_TO_OUT}/build/vmmaker") + set( VMMAKER_DIR "${CMAKE_CURRENT_BINARY_DIR}/build/vmmaker") # If we are generating the vmmaker image, set a the image path # Otherwise set it with a default, but parametrizable @@ -115,15 +115,23 @@ if(GENERATE_SOURCES) ) endif() + set(IMAGE_PATH ${VMMAKER_DIR}/image/Pharo12.0-SNAPSHOT-64bit-aa50f9c.image) + + convert_cygwin_path_ifNeeded(${IMAGE_PATH} IMAGE_PATH_TO_USE) + convert_cygwin_path_ifNeeded(${VMMAKER_IMAGE} VMMAKER_IMAGE_TO_USE) + convert_cygwin_path_ifNeeded(${CMAKE_CURRENT_SOURCE_DIR} CMAKE_CURRENT_SOURCE_DIR_OUT) + convert_cygwin_path_ifNeeded(${CMAKE_CURRENT_BINARY_DIR} CMAKE_CURRENT_BINARY_DIR_OUT) + if(GENERATE_VMMAKER) #Bootstrap VMMaker.image from downloaded plain Pharo image + ExternalProject_Add( vmmaker URL https://files.pharo.org/image/120/Pharo12.0-SNAPSHOT.build.1519.sha.aa50f9c.arch.64bit.zip URL_HASH SHA256=b12270631ffc0c6adcb0b6449565b9abfd8e88a863a894a7320f660c05a0af1e - BUILD_COMMAND ${VMMAKER_VM} --headless ${VMMAKER_DIR}/image/Pharo12.0-SNAPSHOT-64bit-aa50f9c.image --no-default-preferences save VMMaker - COMMAND ${VMMAKER_VM} --headless ${VMMAKER_IMAGE} --no-default-preferences --save --quit "${CMAKE_CURRENT_SOURCE_DIR_TO_OUT}/scripts/installVMMaker.st" "${CMAKE_CURRENT_SOURCE_DIR_TO_OUT}" "${ICEBERG_DEFAULT_REMOTE}" + BUILD_COMMAND ${VMMAKER_VM} --headless ${IMAGE_PATH_TO_USE} --no-default-preferences save VMMaker + COMMAND ${VMMAKER_VM} --headless ${VMMAKER_IMAGE_TO_USE} --no-default-preferences --save --quit "${CMAKE_CURRENT_SOURCE_DIR_OUT}/scripts/installVMMaker.st" "${CMAKE_CURRENT_SOURCE_DIR_OUT}" "${ICEBERG_DEFAULT_REMOTE}" UPDATE_COMMAND "" CONFIGURE_COMMAND "" INSTALL_COMMAND "" @@ -144,7 +152,7 @@ if(GENERATE_SOURCES) #Custom command that generates the vm source code from VMMaker into the generated folder add_custom_command( OUTPUT ${VMSOURCEFILES} ${PLUGIN_GENERATED_FILES} - COMMAND ${VMMAKER_VM} --headless ${VMMAKER_IMAGE} --no-default-preferences perform PharoVMMaker generate:outputDirectory: ${FLAVOUR} ${CMAKE_CURRENT_BINARY_DIR_TO_OUT} + COMMAND ${VMMAKER_VM} --headless ${VMMAKER_IMAGE_TO_USE} --no-default-preferences perform PharoVMMaker generate:outputDirectory: ${FLAVOUR} ${CMAKE_CURRENT_BINARY_DIR_OUT} VERBATIM DEPENDS vmmaker ${VMMAKER_IMAGE} ${VMMAKER_VM} COMMENT "Generating VM files for flavour: ${FLAVOUR}") diff --git a/macros.cmake b/macros.cmake index 811e496873..469d9bd3b5 100644 --- a/macros.cmake +++ b/macros.cmake @@ -51,6 +51,20 @@ macro(get_full_platform_name_with_osx VARNAME) endif() endmacro() +macro(convert_cygwin_path_ifNeeded INPUT OUTVARNAME) + # transform the path into a windows path with unix backslashes C:/bla/blu + # this is the path required to send as argument to libraries outside of the control of cygwin (like pharo itself) + if(WIN AND NOT MSVC) + execute_process( + COMMAND cygpath ${INPUT} --mixed + OUTPUT_VARIABLE ${OUTVARNAME} + OUTPUT_STRIP_TRAILING_WHITESPACE) + else() + set(${OUTVARNAME} ${INPUT}) + endif() + +endmacro() + # Add a third party dependency taken from the given URL macro(add_third_party_dependency_with_baseurl NAME BASEURL) From dbbf33eaa0bd0e714784eb55998bad629c54c8a3 Mon Sep 17 00:00:00 2001 From: Pablo Tesone Date: Thu, 17 Oct 2024 15:56:04 +0200 Subject: [PATCH 13/17] - Fixing the tests for permanent objects forwarded as they should be in the remembered set. - Cleaning up the forwarders that remains in the permSpace and nobody has references to it - Having the SpurContiguousObjStack --- .../VMMaker/SpurContiguousObjStack.class.st | 142 ++++++++++++- .../VMMaker/SpurMemoryManager.class.st | 189 ++++++++++++++---- .../VMMaker/SpurNewSpaceSpace.class.st | 2 +- smalltalksrc/VMMaker/VMRememberedSet.class.st | 2 +- .../VMPermanentSpaceMemoryTest.class.st | 11 +- 5 files changed, 296 insertions(+), 50 deletions(-) diff --git a/smalltalksrc/VMMaker/SpurContiguousObjStack.class.st b/smalltalksrc/VMMaker/SpurContiguousObjStack.class.st index 696d2a5e09..5975f00027 100644 --- a/smalltalksrc/VMMaker/SpurContiguousObjStack.class.st +++ b/smalltalksrc/VMMaker/SpurContiguousObjStack.class.st @@ -2,13 +2,153 @@ Class { #name : 'SpurContiguousObjStack', #superclass : 'SpurNewSpaceSpace', #instVars : [ - 'top' + 'top', + 'initialSize', + 'memoryManager', + 'objectMemory' ], #category : 'VMMaker-SpurMemoryManager', #package : 'VMMaker', #tag : 'SpurMemoryManager' } +{ #category : 'translation' } +SpurContiguousObjStack class >> filteredInstVarNames [ + + ^ super filteredInstVarNames copyWithoutAll: #(memoryManager objectMemory) +] + +{ #category : 'adding' } +SpurContiguousObjStack >> addToStack: anOop [ + + self top = self limit ifTrue: [ self extendObjStack ]. + + objectMemory longAt: self top put: anOop. + self top: self top + objectMemory bytesPerOop. +] + +{ #category : 'C library simulation' } +SpurContiguousObjStack >> calloc: num _: size [ + + + ^ self malloc: num * size +] + +{ #category : 'adding' } +SpurContiguousObjStack >> extendObjStack [ + + | newTop newSize newStart newLimit | + + "We double the size of the stack" + newSize := ((self limit - self start) / objectMemory wordSize) * 2. + + newStart := objectMemory realloc: self start _: (objectMemory wordSize * newSize). + newStart ifNil: [ + objectMemory error: 'Imposible to extend SpurContiguousObjStack' ]. + + newLimit := newStart asInteger + (newSize * objectMemory wordSize). + + newTop := (self top - self start) + newStart asInteger. + + self + start: newStart asInteger; + limit: newLimit. + + self top: newTop +] + +{ #category : 'C library simulation' } +SpurContiguousObjStack >> free: anAddress [ + + + memoryManager free: anAddress +] + +{ #category : 'freeing' } +SpurContiguousObjStack >> freeObjectStack [ + + objectMemory free: self start. + self start: 0. + self top: 0. +] + +{ #category : 'accessing' } +SpurContiguousObjStack >> initialSize [ + + ^ initialSize +] + +{ #category : 'accessing' } +SpurContiguousObjStack >> initialSize: anObject [ + + initialSize := anObject +] + +{ #category : 'initialization' } +SpurContiguousObjStack >> initializeWithAtLeast: anInitialSizeIfNotProvided onError: onErrorBlock [ + + "Initialize the queue so that + - start points at the beginning of the allocated chunk, + - limit points to the last potential entry + - top is by default the start" + + + + | allocation | + + (self initialSize isNil or: [ self initialSize = 0 ]) + ifTrue: [ self initialSize: anInitialSizeIfNotProvided ]. + + allocation := objectMemory malloc: (objectMemory sizeof: #'void *') * self initialSize. + + allocation ifNil: [ onErrorBlock value ]. + + self + start: allocation asInteger; + limit: allocation asInteger + + ((objectMemory sizeof: #'void *') * self initialSize). + + self top: self start +] + +{ #category : 'C library simulation' } +SpurContiguousObjStack >> malloc: size [ + + | address region | + + size = 0 ifTrue: [ ^ nil ]. + + address := memoryManager allocate: size. + region := memoryManager regionAtAddress: address. + ^ CNewArrayAccessor new + setObject: region; + address: address; + yourself +] + +{ #category : 'accessing' } +SpurContiguousObjStack >> memoryManager: anObject [ + + memoryManager := anObject +] + +{ #category : 'accessing' } +SpurContiguousObjStack >> objectMemory: anObject [ + + objectMemory := anObject +] + +{ #category : 'enumerating' } +SpurContiguousObjStack >> objectStackDo: aFullBlockClosure [ + + + + self start + to: self top - objectMemory bytesPerOop + by: objectMemory bytesPerOop + do: [ :anAddress | aFullBlockClosure value: (objectMemory longAt: anAddress) ] +] + { #category : 'printing' } SpurContiguousObjStack >> printOn: aStream [ diff --git a/smalltalksrc/VMMaker/SpurMemoryManager.class.st b/smalltalksrc/VMMaker/SpurMemoryManager.class.st index 1b0f433dff..df40628176 100644 --- a/smalltalksrc/VMMaker/SpurMemoryManager.class.st +++ b/smalltalksrc/VMMaker/SpurMemoryManager.class.st @@ -614,11 +614,11 @@ Class { 'statShrinkMemory', 'statAllocatedBytes', 'statMaxAllocSegmentTime', - 'unscannedEphemeronsQueueInitialSize', 'permSpaceFreeStart', 'fromOldSpaceRememberedSet', 'fromPermToOldSpaceRememberedSet', 'fromPermToNewSpaceRememberedSet', + 'permSpaceForwardersToCleanUp', 'avoidSearchingSegmentsWithPinnedObjects' ], #classVars : [ @@ -724,9 +724,8 @@ SpurMemoryManager class >> declareCVarsIn: aCCodeGenerator [ aCCodeGenerator var: #freeListsMask type: #usqInt; var: #freeLists type: #'sqInt *'; - var: #unscannedEphemeronsQueueInitialSize declareC: 'int unscannedEphemeronsQueueInitialSize = 10000; /* 10k ephemerons by default */'; var: #objStackInvalidBecause type: #'char *'; - var: #unscannedEphemerons type: #SpurContiguousObjStack; + var: #unscannedEphemerons type: #'SpurContiguousObjStack *'; var: #heapGrowthToSizeGCRatio type: #float; var: #heapSizeAtPreviousGC type: #usqInt; var: #totalFreeOldSpace type: #usqInt; @@ -744,7 +743,9 @@ SpurMemoryManager class >> declareCVarsIn: aCCodeGenerator [ var: #memoryMap type: #'VMMemoryMap *'; var: #fromOldSpaceRememberedSet type: #'VMRememberedSet *'; var: #fromPermToOldSpaceRememberedSet type: #'VMRememberedSet *'; - var: #fromPermToNewSpaceRememberedSet type: #'VMRememberedSet *' + var: #fromPermToNewSpaceRememberedSet type: #'VMRememberedSet *'; + var: #permSpaceForwardersToCleanUp type: #'SpurContiguousObjStack *' + ] { #category : 'translation' } @@ -1839,7 +1840,7 @@ SpurMemoryManager >> allPermSpaceObjectsDo: aBlockClosure [ [ currentObject = permSpaceFreeStart ] whileFalse: [ - aBlockClosure value: currentObject. + (self isFreeObject: currentObject) ifFalse: [aBlockClosure value: currentObject]. currentObject := self objectAfter: currentObject limit: permSpaceFreeStart ]. ] @@ -1960,9 +1961,7 @@ SpurMemoryManager >> allocateMemoryOfSize: memoryBytes newSpaceSize: newSpaceByt newSpaceBytes \\ self allocationUnit = 0 and: [ codeBytes \\ self allocationUnit = 0 ] ]). - memoryManager ifNil: [ - memoryManager := SlangMemoryManager new. - memoryManager wordSize: self wordSize ]. + self ensureMemoryManager. primitiveLogSize ~= 0 ifTrue: [ coInterpreter movePrimTraceLogToMemoryAt: (memoryManager allocate: primitiveLogSize)]. @@ -3887,6 +3886,42 @@ SpurMemoryManager >> classTagForSpecialObjectsIndex: splObjIndex compactClassInd ^compactClassIndex ] +{ #category : 'perm - space' } +SpurMemoryManager >> cleanUpPermSpaceForwarders [ + + permSpaceForwardersToCleanUp objectStackDo: [ :anOop | + self freePermObject: anOop ]. + + permSpaceForwardersToCleanUp freeObjectStack. +] + +{ #category : 'perm - space' } +SpurMemoryManager >> cleanUpPermToNewSpaceRememeberedSet [ + + | destIndex sourceIndex referrer | + + + + sourceIndex := destIndex := 0. + + "We iterate the remembered set to remove the forwarders to the new space that should be cleaned after full GC. The forwarders are unreacheable after full GC" + + [sourceIndex < self getFromPermToNewSpaceRememberedSet rememberedSetSize] whileTrue: + [ referrer := self getFromPermToNewSpaceRememberedSet objectAt: sourceIndex. + + (self isForwarded: referrer) + ifTrue: [ self handleUnreacheablePermanentForwarded: referrer ] + ifFalse:[ + self getFromPermToNewSpaceRememberedSet save: referrer at: destIndex. + destIndex := destIndex + 1]. + sourceIndex := sourceIndex + 1]. + + self getFromPermToNewSpaceRememberedSet setRememberedSetSize: destIndex. + + self getFromPermToNewSpaceRememberedSet shrinkRememberedSet. + +] + { #category : 'perm - space' } SpurMemoryManager >> cleanUpPermToOldSpaceRememeberedSet [ @@ -3904,13 +3939,16 @@ SpurMemoryManager >> cleanUpPermToOldSpaceRememeberedSet [ [sourceIndex < self getFromPermToOldSpaceRememberedSet rememberedSetSize] whileTrue: [ referrer := self getFromPermToOldSpaceRememberedSet objectAt: sourceIndex. - self assert: ((self hasYoungReferents: referrer) not or:[self isRemembered: referrer]). + self assert: ((self isForwarded: referrer) or: [(self hasYoungReferents: referrer) not or:[self isRemembered: referrer]]). - ((self isMarked: referrer) not and: [self hasOldReferents: referrer]) - ifTrue:[ - self getFromPermToOldSpaceRememberedSet save: referrer at: destIndex. - self setIsMarkedOf: referrer to: true. - destIndex := destIndex + 1]. + (self isForwarded: referrer) + ifTrue: [ self handleUnreacheablePermanentForwarded: referrer ] + ifFalse: [ + ((self isMarked: referrer) not and: [ self hasOldReferents: referrer]) + ifTrue:[ + self getFromPermToOldSpaceRememberedSet save: referrer at: destIndex. + self setIsMarkedOf: referrer to: true. + destIndex := destIndex + 1]]. sourceIndex := sourceIndex + 1]. self getFromPermToOldSpaceRememberedSet setRememberedSetSize: destIndex. @@ -4728,6 +4766,17 @@ SpurMemoryManager >> ensureBehaviorHash: aBehavior [ ifFalse: [self rawHashBitsOf: aBehavior]]] ] +{ #category : 'initialization' } +SpurMemoryManager >> ensureMemoryManager [ + + + + memoryManager ifNil: [ + memoryManager := SlangMemoryManager new. + memoryManager wordSize: self wordSize ] + +] + { #category : 'initialization' } SpurMemoryManager >> ensureMemoryMap [ @@ -5893,6 +5942,28 @@ SpurMemoryManager >> freeOldSpaceStart [ ^freeOldSpaceStart ] +{ #category : 'free space' } +SpurMemoryManager >> freePermObject: objOop [ + "Free an object in PermSpace. Coalesce if possible to reduce fragmentation. + Warning: because of coalescion, the original objOop can become an invalid entity pointer. We assume the objects are not in the remembered sets" + + + + | bytes start next | + + self assert: (self isPermanent: objOop). + self assert: (self getFromPermToOldSpaceRememberedSet isInRememberedSet: objOop) not. + self assert: (self getFromPermToNewSpaceRememberedSet isInRememberedSet: objOop) not. + + bytes := self bytesInObject: objOop. + start := self startOfObject: objOop. + next := self objectStartingAt: start + bytes. + (self isFreeObject: next) ifTrue: + [ bytes := bytes + (self bytesInObject: next) ]. + + ^ self initFreeChunkWithBytes: bytes at: start. +] + { #category : 'free space' } SpurMemoryManager >> freeSize [ ^totalFreeOldSpace @@ -6240,6 +6311,13 @@ SpurMemoryManager >> growToAccomodateContainerWithNumSlots: numSlots [ callingOperation: 'growing to accomodate allObjects / allInstances container' ] +{ #category : 'perm - space' } +SpurMemoryManager >> handleUnreacheablePermanentForwarded: anOop [ + + permSpaceForwardersToCleanUp addToStack: anOop. + +] + { #category : 'header access' } SpurMemoryManager >> hasIdentityHash: objOop [ @@ -6719,10 +6797,6 @@ SpurMemoryManager >> initialize [ statGrowMemory := statShrinkMemory := statRootTableCount := statAllocatedBytes := 0. statRootTableOverflows := statMarkCount := statCompactPassCount := statCoalesces := 0. - "We can initialize things that are allocated but are lazily initialized." - unscannedEphemerons := SpurContiguousObjStack new. - unscannedEphemeronsQueueInitialSize := 10000. "10k by default" - "we can initialize things that are virtual in C." fromOldSpaceRememberedSet := VMRememberedSet new manager: self; rootIndex: OldRememberedSetRootIndex; yourself. fromPermToOldSpaceRememberedSet := VMRememberedSet new manager: self; rootIndex: PermToOldRememberedSetRootIndex; yourself. @@ -6955,6 +7029,26 @@ SpurMemoryManager >> initializeOldSpaceFirstFree: startOfFreeOldSpace [ self checkFreeSpace: GCModeFreeSpace ] +{ #category : 'initialization' } +SpurMemoryManager >> initializePermSpaceForwardersToCleanUp [ + + self cCode: [ + permSpaceForwardersToCleanUp ifNil: [ + permSpaceForwardersToCleanUp := self cCoerce: (self calloc: (self sizeof: SpurContiguousObjStack) _: 1) + to: 'SpurContiguousObjStack *']] + inSmalltalk: [ + self ensureMemoryManager. + "We can initialize things that are allocated but are lazily initialized." + permSpaceForwardersToCleanUp ifNil: [permSpaceForwardersToCleanUp := SpurContiguousObjStack new]. + permSpaceForwardersToCleanUp memoryManager: memoryManager. + permSpaceForwardersToCleanUp objectMemory: self ]. + + permSpaceForwardersToCleanUp + initializeWithAtLeast: 512 + onError: [ self error: 'Cannot allocate space for Permanent space Forwarders to clean up' ]. + +] + { #category : 'spur bootstrap' } SpurMemoryManager >> initializePostBootstrap [ "The heap has just been bootstrapped into a modified newSpace occupying all of memory @@ -6970,26 +7064,23 @@ SpurMemoryManager >> initializePostBootstrap [ { #category : 'gc - global' } SpurMemoryManager >> initializeUnscannedEphemerons [ - "Initialize the unscannedEphemerons queue. + self + cCode: [ + unscannedEphemerons ifNil: [ + unscannedEphemerons := self cCoerce: (self calloc: (self sizeof: SpurContiguousObjStack) _: 1) + to: 'SpurContiguousObjStack *']] + inSmalltalk: [ + self ensureMemoryManager. + + "We can initialize things that are allocated but are lazily initialized." + unscannedEphemerons ifNil: [unscannedEphemerons := SpurContiguousObjStack new]. + unscannedEphemerons memoryManager: memoryManager. + unscannedEphemerons objectMemory: self ]. - Allocate by default size for 10K ephemerons in the heap. - Initialize the queue so that - - start points at the beginning of the allocated chunk, - - limit points to the last potential entry - - top is by default the start" - - | allocation | - allocation := self - calloc: (self sizeof: #'void *') - _: unscannedEphemeronsQueueInitialSize. - allocation ifNil: [ - self error: 'Cannot allocate space for unscanned ephemerons' ]. + unscannedEphemerons + initializeWithAtLeast: 10000 + onError: [ self error: 'Cannot allocate space for unscanned ephemerons' ]. - unscannedEphemerons - start: allocation asInteger; - limit: allocation asInteger - + ((self sizeof: #'void *') * unscannedEphemeronsQueueInitialSize). - unscannedEphemerons top: unscannedEphemerons start ] { #category : 'gc - global' } @@ -8853,6 +8944,7 @@ SpurMemoryManager >> markAndTraceHiddenRoots [ self markAndTraceObjStack: mournQueue andContents: true. self cleanUpPermToOldSpaceRememeberedSet. + self cleanUpPermToNewSpaceRememeberedSet. self markAndTraceRememberedSet: self getFromPermToOldSpaceRememberedSet. self markAndTraceRememberedSet: self getFromPermToNewSpaceRememberedSet. @@ -9063,11 +9155,16 @@ SpurMemoryManager >> markObjects: objectsShouldBeUnmarkedAndUnmarkedClassesShoul self initializeMarkStack. self initializeWeaklingStack. self initializeMournQueue. + self initializePermSpaceForwardersToCleanUp. + marking := true. self markAccessibleObjectsAndFireEphemerons. + self expungeDuplicateAndUnmarkedClasses: objectsShouldBeUnmarkedAndUnmarkedClassesShouldBeExpunged. self nilUnmarkedWeaklingSlots. self freeUnscannedEphemerons. + self cleanUpPermSpaceForwarders. + marking := false ] @@ -13399,9 +13496,19 @@ SpurMemoryManager >> unpinObject: objOop [ ] { #category : 'accessing' } -SpurMemoryManager >> unscannedEphemeronsQueueInitialSize: anInteger [ - - unscannedEphemeronsQueueInitialSize := anInteger +SpurMemoryManager >> unscannedEphemeronsQueueInitialSize: anInteger [ + + + + self ensureMemoryManager. + + "We can initialize things that are allocated but are lazily initialized." + unscannedEphemerons ifNil: [ + unscannedEphemerons := SpurContiguousObjStack new ]. + unscannedEphemerons memoryManager: memoryManager. + unscannedEphemerons objectMemory: self. + + unscannedEphemerons initialSize: anInteger ] { #category : 'initialization' } @@ -13663,7 +13770,9 @@ SpurMemoryManager >> withSimulatorFetchPointerMovedAsideDo: aBlock [ while aBlock is running and answer the block's result." | theMethod | theMethod := self class lookupSelector: #fetchPointer:ofObject:. - self deny: (theMethod isNil or: [theMethod methodClass == SpurMemoryManager]). + + theMethod methodClass == SpurMemoryManager ifTrue: [ ^ aBlock value ]. + theMethod methodClass removeSelectorSilently: #fetchPointer:ofObject:. ^aBlock ensure: [theMethod methodClass diff --git a/smalltalksrc/VMMaker/SpurNewSpaceSpace.class.st b/smalltalksrc/VMMaker/SpurNewSpaceSpace.class.st index 0428ba977e..cbf152c56f 100644 --- a/smalltalksrc/VMMaker/SpurNewSpaceSpace.class.st +++ b/smalltalksrc/VMMaker/SpurNewSpaceSpace.class.st @@ -12,7 +12,7 @@ Class { { #category : 'translation' } SpurNewSpaceSpace class >> instVarNamesAndTypesForTranslationDo: aBinaryBlock [ - self allInstVarNames do: + self filteredInstVarNames do: [:ivn| (SpurMemoryManager isNonArgumentImplicitReceiverVariableName: ivn) ifFalse: [aBinaryBlock value: ivn value: #usqInt]] diff --git a/smalltalksrc/VMMaker/VMRememberedSet.class.st b/smalltalksrc/VMMaker/VMRememberedSet.class.st index 4ae3fa980a..92253d4e47 100644 --- a/smalltalksrc/VMMaker/VMRememberedSet.class.st +++ b/smalltalksrc/VMMaker/VMRememberedSet.class.st @@ -340,7 +340,7 @@ VMRememberedSet >> rememberWithoutMarkingAsRemembered: objOop [ - + self assert: (manager isNonImmediate: objOop). self deny: (manager getMemoryMap isYoungObject: objOop). diff --git a/smalltalksrc/VMMakerTests/VMPermanentSpaceMemoryTest.class.st b/smalltalksrc/VMMakerTests/VMPermanentSpaceMemoryTest.class.st index 6f11b9b697..c4eec34ffe 100644 --- a/smalltalksrc/VMMakerTests/VMPermanentSpaceMemoryTest.class.st +++ b/smalltalksrc/VMMakerTests/VMPermanentSpaceMemoryTest.class.st @@ -78,7 +78,7 @@ VMPermanentSpaceMemoryTest >> testBecomingOneWayOfPermanentObjectWithOldObject [ self assert: (memory fetchPointer: 0 ofObject: permanentObjectReferencingPermanent) equals: oldReplacement. "The forwarded object is not in any remembered set" - self deny: (memory getFromPermToOldSpaceRememberedSet isInRememberedSet: permanentObject). + self assert: (memory getFromPermToOldSpaceRememberedSet isInRememberedSet: permanentObject). self deny: (memory getFromPermToNewSpaceRememberedSet isInRememberedSet: permanentObject). self assert: (memory getFromPermToOldSpaceRememberedSet isInRememberedSet: permanentObjectReferencingPermanent). @@ -211,9 +211,8 @@ VMPermanentSpaceMemoryTest >> testBecomingOneWayOfPermanentObjectWithYoungObject "Perm objects still points to the result" self assert: (memory fetchPointer: 0 ofObject: permanentObjectReferencingPermanent) equals: oldReplacement. - "The forwarded object is not in any remembered set" self deny: (memory getFromPermToOldSpaceRememberedSet isInRememberedSet: permanentObject). - self deny: (memory getFromPermToNewSpaceRememberedSet isInRememberedSet: permanentObject). + self assert: (memory getFromPermToNewSpaceRememberedSet isInRememberedSet: permanentObject). self deny: (memory getFromPermToOldSpaceRememberedSet isInRememberedSet: permanentObjectReferencingPermanent). self assert: (memory getFromPermToNewSpaceRememberedSet isInRememberedSet: permanentObjectReferencingPermanent). @@ -282,9 +281,8 @@ VMPermanentSpaceMemoryTest >> testBecomingTwoWayOfPermanentObjectWithOldObjectLe "Perm objects still points to the result" self assert: (memory fetchPointer: 0 ofObject: permanentObjectReferencingPermanent) equals: self keptObjectInVMVariable3. - "The forwarded object is not in any remembered set" self deny: (memory getFromPermToOldSpaceRememberedSet isInRememberedSet: permanentObject). - self deny: (memory getFromPermToNewSpaceRememberedSet isInRememberedSet: permanentObject). + self assert: (memory getFromPermToNewSpaceRememberedSet isInRememberedSet: permanentObject). memory fullGC. @@ -565,9 +563,8 @@ VMPermanentSpaceMemoryTest >> testBecomingTwoWayOfPermanentObjectWithYoungObject "Perm objects still points to the result" self assert: (memory fetchPointer: 0 ofObject: permanentObjectReferencingPermanent) equals: self keptObjectInVMVariable3. - "The forwarded object is not in any remembered set" self deny: (memory getFromPermToOldSpaceRememberedSet isInRememberedSet: permanentObject). - self deny: (memory getFromPermToNewSpaceRememberedSet isInRememberedSet: permanentObject). + self assert: (memory getFromPermToNewSpaceRememberedSet isInRememberedSet: permanentObject). memory fullGC. From 6c38618e15d4918f3c9a62462164aa84072aa1af Mon Sep 17 00:00:00 2001 From: Yubao Liu Date: Sun, 27 Oct 2024 21:07:35 +0800 Subject: [PATCH 14/17] compatible with FreeBSD mmap() FreeBSD mmap() requires MAP_FIXED to map to desired address. --- src/memoryUnix.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/memoryUnix.c b/src/memoryUnix.c index 148c84cad5..5899eeec46 100644 --- a/src/memoryUnix.c +++ b/src/memoryUnix.c @@ -101,9 +101,9 @@ void* allocateJITMemory(usqInt desiredSize, usqInt desiredPosition){ #if __APPLE__ int additionalFlags = MAP_JIT; #else - int additionalFlags = 0; + int additionalFlags = desiredPosition ? MAP_FIXED : 0; #endif - + logDebug("Trying to allocate JIT memory in %p\n", (void* )desiredBaseAddressAligned); if (MAP_FAILED == (result = mmap((void*) desiredBaseAddressAligned, alignedSize, @@ -124,6 +124,12 @@ sqAllocateMemory(usqInt minHeapSize, usqInt desiredHeapSize, usqInt desiredBaseA sqInt heapSize = 0; sqInt heapLimit = 0; +#if __APPLE__ + int additionalFlags = 0; +#else + int additionalFlags = desiredBaseAddress ? MAP_FIXED : 0; +#endif + pageSize = getpagesize(); pageMask = ~(pageSize - 1); @@ -142,7 +148,7 @@ sqAllocateMemory(usqInt minHeapSize, usqInt desiredHeapSize, usqInt desiredBaseA (void* )desiredBaseAddressAligned); while ((!heap) && (heapLimit >= minHeapSize)) { - if (MAP_FAILED == (heap = mmap((void*) desiredBaseAddressAligned, heapLimit, MAP_PROT, MAP_FLAGS, devZero, 0))) { + if (MAP_FAILED == (heap = mmap((void*) desiredBaseAddressAligned, heapLimit, MAP_PROT, MAP_FLAGS | additionalFlags, devZero, 0))) { heap = 0; heapLimit = valign(heapLimit / 4 * 3); } From 809dcc036499fe304d4222a3fcfb8e6b1a6e842f Mon Sep 17 00:00:00 2001 From: Christophe Demarey Date: Fri, 8 Nov 2024 14:46:22 +0100 Subject: [PATCH 15/17] use pharo file server @ inria --- Jenkinsfile | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 6f1f17031b..8b37ed5913 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -84,14 +84,14 @@ def buildGTKBundle(){ archiveArtifacts artifacts: "${gtkBundleName}" if(!isPullRequest() && isMainBranch()){ - sshagent (credentials: ['b5248b59-a193-4457-8459-e28e9eb29ed7']) { + sshagent (credentials: ['files-pharo-org-inria']) { sh "scp -o StrictHostKeyChecking=no \ ${gtkBundleName} \ - pharoorgde@ssh.cluster023.hosting.ovh.net:/home/pharoorgde/files/vm/pharo-spur64-headless/win/${gtkBundleName}" + pharo-ci@files.pharo.org:vm/pharo-spur64-headless/win/${gtkBundleName}" sh "scp -o StrictHostKeyChecking=no \ ${gtkBundleName} \ - pharoorgde@ssh.cluster023.hosting.ovh.net:/home/pharoorgde/files/vm/pharo-spur64-headless/win/latest${mainBranchVersion()}-win64-GTK.zip" + pharo-ci@files.pharo.org:vm/pharo-spur64-headless/win/latest${mainBranchVersion()}-win64-GTK.zip" } } } @@ -303,41 +303,41 @@ def upload(platform, configuration, archiveName, isStableRelease = false) { def expandedCSourceTarName = sh(returnStdout: true, script: "ls build/build/packages/PharoVM-*-${archiveName}-c-src.tar.gz").trim() def expandedHeadersFileName = sh(returnStdout: true, script: "ls build/build/packages/PharoVM-*-${archiveName}-include.zip").trim() - sshagent (credentials: ['b5248b59-a193-4457-8459-e28e9eb29ed7']) { + sshagent (credentials: ['files-pharo-org-inria']) { sh "scp -o StrictHostKeyChecking=no \ ${expandedBinaryFileName} \ - pharoorgde@ssh.cluster023.hosting.ovh.net:/home/pharoorgde/files/vm/pharo-spur${wordSize}-headless/${platform}" + pharo-ci@files.pharo.org:vm/pharo-spur${wordSize}-headless/${platform}" sh "scp -o StrictHostKeyChecking=no \ ${expandedBinaryFileName} \ - pharoorgde@ssh.cluster023.hosting.ovh.net:/home/pharoorgde/files/vm/pharo-spur${wordSize}-headless/${platform}/latest${mainBranchVersion()}.zip" + pharo-ci@files.pharo.org:vm/pharo-spur${wordSize}-headless/${platform}/latest${mainBranchVersion()}.zip" sh "scp -o StrictHostKeyChecking=no \ ${expandedHeadersFileName} \ - pharoorgde@ssh.cluster023.hosting.ovh.net:/home/pharoorgde/files/vm/pharo-spur${wordSize}-headless/${platform}/include" + pharo-ci@files.pharo.org:vm/pharo-spur${wordSize}-headless/${platform}/include" sh "scp -o StrictHostKeyChecking=no \ ${expandedHeadersFileName} \ - pharoorgde@ssh.cluster023.hosting.ovh.net:/home/pharoorgde/files/vm/pharo-spur${wordSize}-headless/${platform}/include/latest${mainBranchVersion()}.zip" + pharo-ci@files.pharo.org:vm/pharo-spur${wordSize}-headless/${platform}/include/latest${mainBranchVersion()}.zip" // Upload Souces ZIP sh "scp -o StrictHostKeyChecking=no \ ${expandedCSourceFileName} \ - pharoorgde@ssh.cluster023.hosting.ovh.net:/home/pharoorgde/files/vm/pharo-spur${wordSize}-headless/${platform}/source" + pharo-ci@files.pharo.org:vm/pharo-spur${wordSize}-headless/${platform}/source" sh "scp -o StrictHostKeyChecking=no \ ${expandedCSourceFileName} \ - pharoorgde@ssh.cluster023.hosting.ovh.net:/home/pharoorgde/files/vm/pharo-spur${wordSize}-headless/${platform}/source/latest${mainBranchVersion()}.zip" + pharo-ci@files.pharo.org:vm/pharo-spur${wordSize}-headless/${platform}/source/latest${mainBranchVersion()}.zip" // Upload Sources TAR.GZ sh "scp -o StrictHostKeyChecking=no \ ${expandedCSourceTarName} \ - pharoorgde@ssh.cluster023.hosting.ovh.net:/home/pharoorgde/files/vm/pharo-spur${wordSize}-headless/${platform}/source" + pharo-ci@files.pharo.org:vm/pharo-spur${wordSize}-headless/${platform}/source" sh "scp -o StrictHostKeyChecking=no \ ${expandedCSourceTarName} \ - pharoorgde@ssh.cluster023.hosting.ovh.net:/home/pharoorgde/files/vm/pharo-spur${wordSize}-headless/${platform}/source/latest${mainBranchVersion()}.tar.gz" + pharo-ci@files.pharo.org:vm/pharo-spur${wordSize}-headless/${platform}/source/latest${mainBranchVersion()}.tar.gz" if(isStableRelease){ sh "scp -o StrictHostKeyChecking=no \ ${expandedBinaryFileName} \ - pharoorgde@ssh.cluster023.hosting.ovh.net:/home/pharoorgde/files/vm/pharo-spur${wordSize}-headless/${platform}/stable${mainBranchVersion()}.zip" + pharo-ci@files.pharo.org:vm/pharo-spur${wordSize}-headless/${platform}/stable${mainBranchVersion()}.zip" } } } @@ -351,18 +351,18 @@ def uploadStockReplacement(platform, configuration, archiveName, isStableRelease def wordSize = is32Bits(platform) ? "32" : "64" def expandedBinaryFileName = sh(returnStdout: true, script: "ls build-stockReplacement/build/packages/PharoVM-*-${archiveName}-bin.zip").trim() - sshagent (credentials: ['b5248b59-a193-4457-8459-e28e9eb29ed7']) { + sshagent (credentials: ['files-pharo-org-inria']) { sh "scp -o StrictHostKeyChecking=no \ ${expandedBinaryFileName} \ - pharoorgde@ssh.cluster023.hosting.ovh.net:/home/pharoorgde/files/vm/pharo-spur${wordSize}/${platform}" + pharo-ci@files.pharo.org:vm/pharo-spur${wordSize}/${platform}" sh "scp -o StrictHostKeyChecking=no \ ${expandedBinaryFileName} \ - pharoorgde@ssh.cluster023.hosting.ovh.net:/home/pharoorgde/files/vm/pharo-spur${wordSize}/${platform}/latestReplacement${mainBranchVersion()}.zip" + pharo-ci@files.pharo.org:vm/pharo-spur${wordSize}/${platform}/latestReplacement${mainBranchVersion()}.zip" if(isStableRelease){ sh "scp -o StrictHostKeyChecking=no \ ${expandedBinaryFileName} \ - pharoorgde@ssh.cluster023.hosting.ovh.net:/home/pharoorgde/files/vm/pharo-spur${wordSize}/${platform}/stable${mainBranchVersion()}.zip" + pharo-ci@files.pharo.org:vm/pharo-spur${wordSize}/${platform}/stable${mainBranchVersion()}.zip" } } } @@ -382,18 +382,18 @@ def uploadStackVM(platform, configuration, archiveName, isStableRelease = false) sh(script: "cp ${oldName} ${expandedBinaryFileName}") - sshagent (credentials: ['b5248b59-a193-4457-8459-e28e9eb29ed7']) { + sshagent (credentials: ['files-pharo-org-inria']) { sh "scp -o StrictHostKeyChecking=no \ ${expandedBinaryFileName} \ - pharoorgde@ssh.cluster023.hosting.ovh.net:/home/pharoorgde/files/vm/pharo-spur${wordSize}-headless/${platform}" + pharo-ci@files.pharo.org:vm/pharo-spur${wordSize}-headless/${platform}" sh "scp -o StrictHostKeyChecking=no \ ${expandedBinaryFileName} \ - pharoorgde@ssh.cluster023.hosting.ovh.net:/home/pharoorgde/files/vm/pharo-spur${wordSize}-headless/${platform}/latestStackVM${mainBranchVersion()}.zip" + pharo-ci@files.pharo.org:vm/pharo-spur${wordSize}-headless/${platform}/latestStackVM${mainBranchVersion()}.zip" if(isStableRelease){ sh "scp -o StrictHostKeyChecking=no \ ${expandedBinaryFileName} \ - pharoorgde@ssh.cluster023.hosting.ovh.net:/home/pharoorgde/files/vm/pharo-spur${wordSize}-headless/${platform}/stableStackVM${mainBranchVersion()}.zip" + pharo-ci@files.pharo.org:vm/pharo-spur${wordSize}-headless/${platform}/stableStackVM${mainBranchVersion()}.zip" } } } From d752b798b3a6998f5563fc1ba7fffbc7e0a68187 Mon Sep 17 00:00:00 2001 From: Guille Polito Date: Fri, 15 Nov 2024 17:45:18 +0100 Subject: [PATCH 16/17] Enhancement(versionning): Extract full semantic version from git Extract Major.Minor.Patch-Suffix from git repository tags --- CMakeLists.txt | 31 ++--- Jenkinsfile | 1 - cmake/Windows.cmake | 2 +- cmake/packaging.cmake | 7 +- cmake/versionExtraction.cmake | 169 ++++++++++++++++++++------- include/pharovm/config.h.in | 6 +- resources/mac/Info.plist.in | 4 +- resources/windows/Pharo.rc.in | 6 +- resources/windows/PharoConsole.rc.in | 6 +- resources/windows/PharoDLL.rc.in | 6 +- 10 files changed, 150 insertions(+), 88 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6f981c3d41..86f0fba640 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,9 +33,10 @@ option(FEATURE_COMPILE_GNUISATION "Use gcc gnu extensions to compile the VM" option(PHARO_DEPENDENCIES_PREFER_DOWNLOAD_BINARIES "Prefer downloading dependencies" OFF) option(FEATURE_COMPILE_INLINE_MEMORY_ACCESSORS "Use inline memory accessors instead of macros" ON) option(PHARO_VM_IN_WORKER_THREAD "Have support for pharo running in a different thread that the main one" ON) -option(BUILD_IS_RELEASE "Is this a release version?" OFF) option(DEPENDENCIES_FORCE_BUILD "Force build libraries" OFF) option(BUILD_WITH_GRAPHVIZ "Generate dependency graphs" ON) +option(VERSION_UPDATE_FROM_GIT "Extract version information from git tags. Default to true. Follow vX.Y.Z-suffix" TRUE) + set(APPNAME "Pharo" CACHE STRING "VM Application name") set(FLAVOUR "CoInterpreter" CACHE STRING "The kind of VM to generate. Possible values: StackVM, CoInterpreter") @@ -47,24 +48,6 @@ if(VERBOSE_BUILD) set(CMAKE_VERBOSE_MAKEFILE TRUE) endif(VERBOSE_BUILD) -# Extract VCS information -include(cmake/versionExtraction.cmake) -extractVCSInformation(GIT_COMMIT_HASH GIT_DESCRIBE GIT_COMMIT_DATE) - -set(VERSION_MAJOR 10) -set(VERSION_MINOR 3) -set(VERSION_PATCH_NUMBER 0) - -if(BUILD_IS_RELEASE) - set(VERSION_PATCH "${VERSION_PATCH_NUMBER}") -else() - set(VERSION_PATCH "${VERSION_PATCH_NUMBER}-${GIT_COMMIT_HASH}") -endif(BUILD_IS_RELEASE) - -message(STATUS "Building version ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}") -message(STATUS "Commit hash ${GIT_COMMIT_HASH} : ${GIT_COMMIT_DATE}") - - # Visual Studio stores user build settings in file 'CmakeSettings.json'. We would like to manage that via a project template. # To push out new template, update 'template_uuid' field in 'template_file' with value from https://www.uuidgenerator.net/ set(user_file "${CMAKE_SOURCE_DIR}/CMakeSettings.json" ) @@ -99,10 +82,6 @@ endif() # Configure CMake to load our modules list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") -#Variable used to set the VM date -set(BUILT_FROM "${GIT_DESCRIBE} - Commit: ${GIT_COMMIT_HASH} - Date: ${GIT_COMMIT_DATE}") -message(STATUS ${BUILT_FROM}) - # Avoid using the d postfix to debug libraries # Otherwise, debug libraries change name and breaks FFI bindings set(CMAKE_DEBUG_POSTFIX "") @@ -126,6 +105,12 @@ endif() #This needs to be at this point, after setting the toolchain configuration project(PharoVM) +include(cmake/versionExtraction.cmake) + +set(BUILT_FROM "${PharoVM_VERSION_STRING_FULL} - Commit: ${PharoVM_VERSION_GIT_SHA} - Date: ${PharoVM_VERSION_GIT_COMMIT_DATE}") +message(STATUS ${BUILT_FROM}) + + # Correctly set the system processor under MSVC # This is required because CMake will set the HOST_PROCESSOR in windows # And not care about our Visual Studio settings diff --git a/Jenkinsfile b/Jenkinsfile index 8b37ed5913..80c0fbb395 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -111,7 +111,6 @@ def runBuild(platformName, configuration, headless = true, someAdditionalParamet def additionalParameters = someAdditionalParameters additionalParameters += headless ? "" : " -DALWAYS_INTERACTIVE=1 " - additionalParameters += isRelease() ? " -DBUILD_IS_RELEASE=ON " : " -DBUILD_IS_RELEASE=OFF " if(configuration == 'StackVM'){ additionalParameters += " -DFEATURE_MESSAGE_COUNT=TRUE " diff --git a/cmake/Windows.cmake b/cmake/Windows.cmake index 715b3b0f63..3082b697c0 100644 --- a/cmake/Windows.cmake +++ b/cmake/Windows.cmake @@ -1,7 +1,7 @@ set(WIN 1) set(VM_EXECUTABLE_CONSOLE_NAME "${VM_EXECUTABLE_NAME}Console") -set(VM_VERSION_FILEVERSION "${APPNAME}VM-${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}-${GIT_COMMIT_HASH}") +set(VM_VERSION_FILEVERSION "${APPNAME}VM-${PharoVM_VERSION_STRING_FULL}") set(Win32ResourcesFolder "${CMAKE_CURRENT_SOURCE_DIR}/resources/windows") diff --git a/cmake/packaging.cmake b/cmake/packaging.cmake index fdf5220811..4727d56e0b 100644 --- a/cmake/packaging.cmake +++ b/cmake/packaging.cmake @@ -79,16 +79,13 @@ install( FILES_MATCHING PATTERN *.h) set(CPACK_PACKAGE_DESCRIPTION "${APPNAME} Headless VM for ${FULL_PLATFORM_NAME}") -set(CPACK_PACKAGE_VERSION_MAJOR "${VERSION_MAJOR}") -set(CPACK_PACKAGE_VERSION_MINOR "${VERSION_MINOR}") -set(CPACK_PACKAGE_VERSION_PATCH "${VERSION_PATCH}") set(CPACK_PACKAGE_VENDOR "${APPNAME}") set(CPACK_PACKAGE_HOMEPAGE_URL "https://pharo.org") if(ALWAYS_INTERACTIVE) - set(CPACK_PACKAGE_FILE_NAME "${APPNAME}VM-${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH_NUMBER}-${GIT_COMMIT_HASH}-${FULL_PLATFORM_NAME}-stockReplacement") + set(CPACK_PACKAGE_FILE_NAME "${APPNAME}VM-${PharoVM_VERSION_STRING_FULL}-${FULL_PLATFORM_NAME}-stockReplacement") else() - set(CPACK_PACKAGE_FILE_NAME "${APPNAME}VM-${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH_NUMBER}-${GIT_COMMIT_HASH}-${FULL_PLATFORM_NAME}") + set(CPACK_PACKAGE_FILE_NAME "${APPNAME}VM-${PharoVM_VERSION_STRING_FULL}-${FULL_PLATFORM_NAME}") endif() set(CPACK_PACKAGE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/build/packages") diff --git a/cmake/versionExtraction.cmake b/cmake/versionExtraction.cmake index 1a45e17807..e186e80489 100644 --- a/cmake/versionExtraction.cmake +++ b/cmake/versionExtraction.cmake @@ -1,44 +1,127 @@ -macro(get_commit_hash VARNAME) - execute_process( - COMMAND git log -1 --format=%h - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - OUTPUT_VARIABLE ${VARNAME} - OUTPUT_STRIP_TRAILING_WHITESPACE) -endmacro() - -macro(get_git_describe VARNAME) - execute_process( - COMMAND git describe --always --tags --first-parent - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - OUTPUT_VARIABLE ${VARNAME} - OUTPUT_STRIP_TRAILING_WHITESPACE) -endmacro() - -macro(get_git_date VARNAME) - execute_process( - COMMAND git log -1 --format=%ai - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - OUTPUT_VARIABLE ${VARNAME} - OUTPUT_STRIP_TRAILING_WHITESPACE) -endmacro() - -macro(extractVCSInformation COMMIT_VARNAME DESCRIBE_VARNAME COMMIT_DATE_VARNAME) - get_commit_hash(${COMMIT_VARNAME}) - get_git_describe(${DESCRIBE_VARNAME}) - get_git_date(${COMMIT_DATE_VARNAME}) - - if("${${COMMIT_VARNAME}}" STREQUAL "") - #If I don't have information I try to get it from the version.info file next to the sources (if one) - message(STATUS "I couldn't get version information from git, using the version.info next to the sources") - file(STRINGS ${CMAKE_CURRENT_SOURCE_DIR}/version.info FILECONTENT LIMIT_COUNT 3) - list(GET FILECONTENT 0 ${COMMIT_VARNAME}) - list(GET FILECONTENT 1 ${DESCRIBE_VARNAME}) - list(GET FILECONTENT 2 ${COMMIT_DATE_VARNAME}) - file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/version.info DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/) - else() - #If I have information for the Commit ID, I store it in the version.info file - file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/version.info ${${COMMIT_VARNAME}}\n) - file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/version.info ${${DESCRIBE_VARNAME}}\n) - file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/version.info ${${COMMIT_DATE_VARNAME}}) +# +# This cmake module sets the project version and partial version +# variables by analysing the git tag and commit history. It expects git +# tags defined with semantic versioning 2.0.0 (http://semver.org/). +# +# The module expects the PROJECT_NAME variable to be set, and recognizes +# the GIT_FOUND, GIT_EXECUTABLE and VERSION_UPDATE_FROM_GIT variables. +# If Git is found and VERSION_UPDATE_FROM_GIT is set to boolean TRUE, +# the project version will be updated using information fetched from the +# most recent git tag and commit. Otherwise, the module will try to read +# a VERSION file containing the full and partial versions. The module +# will update this file each time the project version is updated. +# +# Once done, this module will define the following variables: +# +# ${PROJECT_NAME}_VERSION_STRING - Version string without metadata +# such as "v2.0.0" or "v1.2.41-beta.1". This should correspond to the +# most recent git tag. +# ${PROJECT_NAME}_VERSION_STRING_FULL - Version string with metadata +# such as "v2.0.0+3.a23fbc" or "v1.3.1-alpha.2+4.9c4fd1" +# ${PROJECT_NAME}_VERSION - Same as ${PROJECT_NAME}_VERSION_STRING, +# without the preceding 'v', e.g. "2.0.0" or "1.2.41-beta.1" +# ${PROJECT_NAME}_VERSION_FULL - Same as ${PROJECT_NAME}_VERSION_STRING_FULL, +# such as "2.0.0+3.a23fbc" or "1.3.1-alpha.2+4.9c4fd1" +# ${PROJECT_NAME}_VERSION_MAJOR - Major version integer (e.g. 2 in v2.3.1-RC.2+21.ef12c8) +# ${PROJECT_NAME}_VERSION_MINOR - Minor version integer (e.g. 3 in v2.3.1-RC.2+21.ef12c8) +# ${PROJECT_NAME}_VERSION_PATCH - Patch version integer (e.g. 1 in v2.3.1-RC.2+21.ef12c8) +# ${PROJECT_NAME}_VERSION_TWEAK - Tweak version string (e.g. "RC.2" in v2.3.1-RC.2+21.ef12c8) +# ${PROJECT_NAME}_VERSION_AHEAD - How many commits ahead of last tag (e.g. 21 in v2.3.1-RC.2+21.ef12c8) +# ${PROJECT_NAME}_VERSION_GIT_SHA - The git sha1 of the most recent commit (e.g. the "ef12c8" in v2.3.1-RC.2+21.ef12c8) +# +# This module is public domain, use it as it fits you best. +# +# Author: Nuno Fachada + +# Check if git is found... +if (VERSION_UPDATE_FROM_GIT) + find_package(Git) +endif() + +if (GIT_FOUND AND VERSION_UPDATE_FROM_GIT) + + # Get last tag from git + execute_process(COMMAND ${GIT_EXECUTABLE} describe --abbrev=0 --tags + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + OUTPUT_VARIABLE ${PROJECT_NAME}_VERSION_STRING + OUTPUT_STRIP_TRAILING_WHITESPACE) + + #How many commits since last tag + execute_process(COMMAND ${GIT_EXECUTABLE} rev-list ${${PROJECT_NAME}_VERSION_STRING}^..HEAD --count + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + OUTPUT_VARIABLE ${PROJECT_NAME}_VERSION_AHEAD + OUTPUT_STRIP_TRAILING_WHITESPACE) + + # Get current commit SHA from git + execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + OUTPUT_VARIABLE ${PROJECT_NAME}_VERSION_GIT_SHA + OUTPUT_STRIP_TRAILING_WHITESPACE) + + execute_process(COMMAND ${GIT_EXECUTABLE} log -1 --format=%ai + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + OUTPUT_VARIABLE ${PROJECT_NAME}_VERSION_GIT_COMMIT_DATE + OUTPUT_STRIP_TRAILING_WHITESPACE) + + # Get partial versions into a list + string(REGEX MATCHALL "-.*$|[0-9]+" ${PROJECT_NAME}_PARTIAL_VERSION_LIST + ${${PROJECT_NAME}_VERSION_STRING}) + + # Set the version numbers + list(GET ${PROJECT_NAME}_PARTIAL_VERSION_LIST + 0 ${PROJECT_NAME}_VERSION_MAJOR) + list(GET ${PROJECT_NAME}_PARTIAL_VERSION_LIST + 1 ${PROJECT_NAME}_VERSION_MINOR) + list(GET ${PROJECT_NAME}_PARTIAL_VERSION_LIST + 2 ${PROJECT_NAME}_VERSION_PATCH) + + # The tweak part is optional, so check if the list contains it + list(LENGTH ${PROJECT_NAME}_PARTIAL_VERSION_LIST + ${PROJECT_NAME}_PARTIAL_VERSION_LIST_LEN) + if (${PROJECT_NAME}_PARTIAL_VERSION_LIST_LEN GREATER 3) + list(GET ${PROJECT_NAME}_PARTIAL_VERSION_LIST 3 ${PROJECT_NAME}_VERSION_TWEAK) + string(SUBSTRING ${${PROJECT_NAME}_VERSION_TWEAK} 1 -1 ${PROJECT_NAME}_VERSION_TWEAK) endif() -endmacro() + + # Unset the list + unset(${PROJECT_NAME}_PARTIAL_VERSION_LIST) + + # Set full project version string + set(${PROJECT_NAME}_VERSION_STRING_FULL + ${${PROJECT_NAME}_VERSION_STRING}+${${PROJECT_NAME}_VERSION_AHEAD}.${${PROJECT_NAME}_VERSION_GIT_SHA}) + + # Save version to file (which will be used when Git is not available + # or VERSION_UPDATE_FROM_GIT is disabled) + file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/version.info ${${PROJECT_NAME}_VERSION_STRING_FULL} + "*" ${${PROJECT_NAME}_VERSION_STRING} + "*" ${${PROJECT_NAME}_VERSION_MAJOR} + "*" ${${PROJECT_NAME}_VERSION_MINOR} + "*" ${${PROJECT_NAME}_VERSION_PATCH} + "*" ${${PROJECT_NAME}_VERSION_TWEAK} + "*" ${${PROJECT_NAME}_VERSION_AHEAD} + "*" ${${PROJECT_NAME}_VERSION_GIT_SHA}) + +else() + + # Git not available, get version from file + file(STRINGS ${CMAKE_SOURCE_DIR}/version.info ${PROJECT_NAME}_VERSION_LIST) + string(REPLACE "*" ";" ${PROJECT_NAME}_VERSION_LIST ${${PROJECT_NAME}_VERSION_LIST}) + # Set partial versions + list(GET ${PROJECT_NAME}_VERSION_LIST 0 ${PROJECT_NAME}_VERSION_STRING_FULL) + list(GET ${PROJECT_NAME}_VERSION_LIST 1 ${PROJECT_NAME}_VERSION_STRING) + list(GET ${PROJECT_NAME}_VERSION_LIST 2 ${PROJECT_NAME}_VERSION_MAJOR) + list(GET ${PROJECT_NAME}_VERSION_LIST 3 ${PROJECT_NAME}_VERSION_MINOR) + list(GET ${PROJECT_NAME}_VERSION_LIST 4 ${PROJECT_NAME}_VERSION_PATCH) + list(GET ${PROJECT_NAME}_VERSION_LIST 5 ${PROJECT_NAME}_VERSION_TWEAK) + list(GET ${PROJECT_NAME}_VERSION_LIST 6 ${PROJECT_NAME}_VERSION_AHEAD) + list(GET ${PROJECT_NAME}_VERSION_LIST 7 ${PROJECT_NAME}_VERSION_GIT_SHA) + +endif() + + +# Set project version (without the preceding 'v') +set(${PROJECT_NAME}_VERSION ${${PROJECT_NAME}_VERSION_MAJOR}.${${PROJECT_NAME}_VERSION_MINOR}.${${PROJECT_NAME}_VERSION_PATCH}) +set(${PROJECT_NAME}_VERSION_FULL ${${PROJECT_NAME}_VERSION_MAJOR}.${${PROJECT_NAME}_VERSION_MINOR}.${${PROJECT_NAME}_VERSION_PATCH}) +if (${PROJECT_NAME}_VERSION_TWEAK) + set(${PROJECT_NAME}_VERSION ${${PROJECT_NAME}_VERSION}-${${PROJECT_NAME}_VERSION_TWEAK}) +endif() diff --git a/include/pharovm/config.h.in b/include/pharovm/config.h.in index 9592b58de2..ff0da80901 100644 --- a/include/pharovm/config.h.in +++ b/include/pharovm/config.h.in @@ -53,13 +53,11 @@ #cmakedefine PHARO_VM_IN_WORKER_THREAD -#cmakedefine BUILD_IS_RELEASE - #if defined(_MSC_VER) -#define VM_BUILD_STRING VM_NAME " @VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_PATCH@ built on " __DATE__ " " __TIME__ " Compiler: Visual C" +#define VM_BUILD_STRING VM_NAME " @PharoVM_VERSION_STRING@ built on " __DATE__ " " __TIME__ " Compiler: Visual C" #define COMPILER_VERSION "Visual C" #else -#define VM_BUILD_STRING VM_NAME " @VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_PATCH@ built on " __DATE__ " " __TIME__" Compiler: " __VERSION__ +#define VM_BUILD_STRING VM_NAME " @PharoVM_VERSION_STRING@ built on " __DATE__ " " __TIME__" Compiler: " __VERSION__ #define COMPILER_VERSION __VERSION__ #endif diff --git a/resources/mac/Info.plist.in b/resources/mac/Info.plist.in index 1c6d8a3420..b5dd923c78 100644 --- a/resources/mac/Info.plist.in +++ b/resources/mac/Info.plist.in @@ -17,9 +17,9 @@ CFBundlePackageType APPL CFBundleShortVersionString - @VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_PATCH@ + @PharoVM_VERSION@ CFBundleVersion - @VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_PATCH@-@GIT_COMMIT_HASH@ + @PharoVM_VERSION_FULL@ NSHighResolutionCapable CFBundleDevelopmentRegion diff --git a/resources/windows/Pharo.rc.in b/resources/windows/Pharo.rc.in index 0bd8deffd8..6350dcbf6a 100644 --- a/resources/windows/Pharo.rc.in +++ b/resources/windows/Pharo.rc.in @@ -4,8 +4,8 @@ 100 ICON "@Win32VMExecutableIcon@" VS_VERSION_INFO VERSIONINFO -FILEVERSION @VERSION_MAJOR@,@VERSION_MINOR@,@VERSION_PATCH_NUMBER@,0 -PRODUCTVERSION @VERSION_MAJOR@,@VERSION_MINOR@,@VERSION_PATCH_NUMBER@,0 +FILEVERSION @PharoVM_VERSION_MAJOR@,@PharoVM_VERSION_MINOR@,@PharoVM_VERSION_PATCH@,@PharoVM_VERSION_AHEAD@ +PRODUCTVERSION @PharoVM_VERSION_MAJOR@,@PharoVM_VERSION_MINOR@,@PharoVM_VERSION_PATCH@,@PharoVM_VERSION_AHEAD@ FILEFLAGSMASK VS_FFI_FILEFLAGSMASK FILEFLAGS VS_FF_DEBUG FILEOS VOS__WINDOWS32 @@ -21,7 +21,7 @@ BEGIN VALUE "FileVersion", "@VM_VERSION_FILEVERSION@" VALUE "LegalCopyright", "Copyright \251 https://www.pharo.org 1996-2021\0" // TODO: Check this field VALUE "ProductName", "Pharo\0" - VALUE "ProductVersion", "@VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_PATCH@-@GIT_COMMIT_HASH@\0" + VALUE "ProductVersion", "@PharoVM_VERSION_FULL@\0" END END BLOCK "VarFileInfo" diff --git a/resources/windows/PharoConsole.rc.in b/resources/windows/PharoConsole.rc.in index 0bd8deffd8..6350dcbf6a 100644 --- a/resources/windows/PharoConsole.rc.in +++ b/resources/windows/PharoConsole.rc.in @@ -4,8 +4,8 @@ 100 ICON "@Win32VMExecutableIcon@" VS_VERSION_INFO VERSIONINFO -FILEVERSION @VERSION_MAJOR@,@VERSION_MINOR@,@VERSION_PATCH_NUMBER@,0 -PRODUCTVERSION @VERSION_MAJOR@,@VERSION_MINOR@,@VERSION_PATCH_NUMBER@,0 +FILEVERSION @PharoVM_VERSION_MAJOR@,@PharoVM_VERSION_MINOR@,@PharoVM_VERSION_PATCH@,@PharoVM_VERSION_AHEAD@ +PRODUCTVERSION @PharoVM_VERSION_MAJOR@,@PharoVM_VERSION_MINOR@,@PharoVM_VERSION_PATCH@,@PharoVM_VERSION_AHEAD@ FILEFLAGSMASK VS_FFI_FILEFLAGSMASK FILEFLAGS VS_FF_DEBUG FILEOS VOS__WINDOWS32 @@ -21,7 +21,7 @@ BEGIN VALUE "FileVersion", "@VM_VERSION_FILEVERSION@" VALUE "LegalCopyright", "Copyright \251 https://www.pharo.org 1996-2021\0" // TODO: Check this field VALUE "ProductName", "Pharo\0" - VALUE "ProductVersion", "@VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_PATCH@-@GIT_COMMIT_HASH@\0" + VALUE "ProductVersion", "@PharoVM_VERSION_FULL@\0" END END BLOCK "VarFileInfo" diff --git a/resources/windows/PharoDLL.rc.in b/resources/windows/PharoDLL.rc.in index f3604129bd..4d33ee05a6 100644 --- a/resources/windows/PharoDLL.rc.in +++ b/resources/windows/PharoDLL.rc.in @@ -2,8 +2,8 @@ #include "win/resources.h" 1 VERSIONINFO -FILEVERSION @VERSION_MAJOR@,@VERSION_MINOR@,@VERSION_PATCH_NUMBER@,0 -PRODUCTVERSION @VERSION_MAJOR@,@VERSION_MINOR@,@VERSION_PATCH_NUMBER@,0 +FILEVERSION @PharoVM_VERSION_MAJOR@,@PharoVM_VERSION_MINOR@,@PharoVM_VERSION_PATCH@,@PharoVM_VERSION_AHEAD@ +PRODUCTVERSION @PharoVM_VERSION_MAJOR@,@PharoVM_VERSION_MINOR@,@PharoVM_VERSION_PATCH@,@PharoVM_VERSION_AHEAD@ FILEFLAGSMASK 0x3fL FILEFLAGS 0xaL FILEOS 0x10001L @@ -19,7 +19,7 @@ BEGIN VALUE "FileVersion", "@VM_VERSION_FILEVERSION@" VALUE "LegalCopyright", "Copyright \251 https://www.pharo.org 1996-2021\0" // TODO: Check this field VALUE "ProductName", "Pharo\0" - VALUE "ProductVersion", "@VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_PATCH@-@GIT_COMMIT_HASH@\0" + VALUE "ProductVersion", "@PharoVM_VERSION_FULL@\0" END END BLOCK "VarFileInfo" From 76caa11687c90f90a59a1de28445e38834a3e144 Mon Sep 17 00:00:00 2001 From: Guille Polito Date: Mon, 18 Nov 2024 14:51:51 +0100 Subject: [PATCH 17/17] Enhancement(versionning): store date in version metadata --- cmake/versionExtraction.cmake | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cmake/versionExtraction.cmake b/cmake/versionExtraction.cmake index e186e80489..78aa8b686a 100644 --- a/cmake/versionExtraction.cmake +++ b/cmake/versionExtraction.cmake @@ -99,7 +99,8 @@ if (GIT_FOUND AND VERSION_UPDATE_FROM_GIT) "*" ${${PROJECT_NAME}_VERSION_PATCH} "*" ${${PROJECT_NAME}_VERSION_TWEAK} "*" ${${PROJECT_NAME}_VERSION_AHEAD} - "*" ${${PROJECT_NAME}_VERSION_GIT_SHA}) + "*" ${${PROJECT_NAME}_VERSION_GIT_SHA} + "*" ${${PROJECT_NAME}_VERSION_GIT_COMMIT_DATE}) else() @@ -115,6 +116,7 @@ else() list(GET ${PROJECT_NAME}_VERSION_LIST 5 ${PROJECT_NAME}_VERSION_TWEAK) list(GET ${PROJECT_NAME}_VERSION_LIST 6 ${PROJECT_NAME}_VERSION_AHEAD) list(GET ${PROJECT_NAME}_VERSION_LIST 7 ${PROJECT_NAME}_VERSION_GIT_SHA) + list(GET ${PROJECT_NAME}_VERSION_LIST 8 ${PROJECT_NAME}_VERSION_GIT_COMMIT_DATE) endif()