From b3bbf6d2ed63e42ae6b22d5073d79531e4ede4b1 Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Sat, 16 Sep 2023 20:12:11 +0300 Subject: [PATCH 01/78] Fixed `indexOf` and `lastIndexOf` methods in `ArrayList` and `LinkedList` + Minor comparision optimizations --- spec/java/util/ArrayList.Spliterator.lsl | 4 +- .../util/ArrayList.SubList.Spliterator.lsl | 4 +- spec/java/util/ArrayList.SubList.lsl | 42 ++++++++++++++---- spec/java/util/ArrayList.main.lsl | 43 ++++++++++--------- spec/java/util/LinkedList.automata.lsl | 9 ++-- 5 files changed, 65 insertions(+), 37 deletions(-) diff --git a/spec/java/util/ArrayList.Spliterator.lsl b/spec/java/util/ArrayList.Spliterator.lsl index 1d0317ec..ae244d93 100644 --- a/spec/java/util/ArrayList.Spliterator.lsl +++ b/spec/java/util/ArrayList.Spliterator.lsl @@ -64,7 +64,7 @@ automaton ArrayList_SpliteratorAutomaton proc _getFence (): int { // JDK comment: initialize fence to size on first use - if (this.fence < 0) + if (this.fence == -1) { action ASSUME(this.parent != null); this.expectedModCount = ArrayListAutomaton(this.parent).modCount; @@ -115,7 +115,7 @@ automaton ArrayList_SpliteratorAutomaton var hi: int = this.fence; var mc: int = this.expectedModCount; - if (hi < 0) + if (hi == -1) { hi = ArrayListAutomaton(this.parent).length; mc = ArrayListAutomaton(this.parent).modCount; diff --git a/spec/java/util/ArrayList.SubList.Spliterator.lsl b/spec/java/util/ArrayList.SubList.Spliterator.lsl index d1055e9b..b9114210 100644 --- a/spec/java/util/ArrayList.SubList.Spliterator.lsl +++ b/spec/java/util/ArrayList.SubList.Spliterator.lsl @@ -59,7 +59,7 @@ automaton ArrayList_SubList_SpliteratorAutomaton proc _getFence (): int { // JDK comment: initialize fence to size on first use - if (this.fence < 0) + if (this.fence == -1) { action ASSUME(this.parent != null); this.expectedModCount = ArrayList_SubListAutomaton(this.parent).modCount; @@ -102,7 +102,7 @@ automaton ArrayList_SubList_SpliteratorAutomaton var hi: int = this.fence; var mc: int = this.expectedModCount; - if (hi < 0) + if (hi == -1) { hi = ArrayList_SubListAutomaton(this.parent).length; mc = ArrayList_SubListAutomaton(this.parent).modCount; diff --git a/spec/java/util/ArrayList.SubList.lsl b/spec/java/util/ArrayList.SubList.lsl index 05380629..eed79eb6 100644 --- a/spec/java/util/ArrayList.SubList.lsl +++ b/spec/java/util/ArrayList.SubList.lsl @@ -135,10 +135,9 @@ automaton ArrayList_SubListAutomaton ArrayListAutomaton(this.root)._checkForComodification(this.modCount); val parentStorage: list = ArrayListAutomaton(this.root).storage; - val parentLength: int = ArrayListAutomaton(this.root).length; - val index: int = action LIST_FIND(parentStorage, o, 0, parentLength); - if (index >= 0) + val index: int = action LIST_FIND(parentStorage, o, this.offset, this.offset + this.length); + if (index != -1) result = index - this.offset; else result = -1; @@ -220,7 +219,7 @@ automaton ArrayList_SubListAutomaton fun *.contains (@target self: ArrayList_SubList, o: Object): boolean { - result = _indexOfElement(o) >= 0; + result = _indexOfElement(o) != -1; } @@ -269,7 +268,7 @@ automaton ArrayList_SubListAutomaton @Phantom proc containsAll_loop_optimized (rootStorage: list, end: int, otherStorage: list, i: int, result: boolean): void { val item: Object = action LIST_GET(otherStorage, i); - result = action LIST_FIND(rootStorage, item, this.offset, end) >= 0; + result = action LIST_FIND(rootStorage, item, this.offset, end) != -1; i += 1; } @@ -277,7 +276,7 @@ automaton ArrayList_SubListAutomaton @Phantom proc containsAll_loop_regular (rootStorage: list, end: int, iter: Iterator, result: boolean): void { val item: Object = action CALL_METHOD(iter, "next", []); - result = action LIST_FIND(rootStorage, item, this.offset, end) >= 0; + result = action LIST_FIND(rootStorage, item, this.offset, end) != -1; } @@ -400,7 +399,34 @@ automaton ArrayList_SubListAutomaton fun *.lastIndexOf (@target self: ArrayList_SubList, o: Object): int { - action TODO(); + action ASSUME(this.root != null); + ArrayListAutomaton(this.root)._checkForComodification(this.modCount); + + if (this.length == 0) + { + result = -1; + } + else + { + action ASSUME(this.length > 0); + + val end: int = this.offset + this.length; + val rootStorage: list = ArrayListAutomaton(this.root).storage; + + result = action LIST_FIND(rootStorage, o, this.offset, end); + if (result != -1) + { + // there should be no elements to the right of the previously found position + val nextIndex: int = result + 1; + if (nextIndex < end) + { + val rightIndex: int = action LIST_FIND(rootStorage, o, nextIndex, end); + action ASSUME(rightIndex == -1); + } + + result -= this.offset; + } + } } @@ -433,7 +459,7 @@ automaton ArrayList_SubListAutomaton val rootStorage: list = ArrayListAutomaton(this.root).storage; val index: int = action LIST_FIND(rootStorage, o, this.offset, end); - result = index >= 0; + result = index != -1; if (result) { diff --git a/spec/java/util/ArrayList.main.lsl b/spec/java/util/ArrayList.main.lsl index 3385223c..9f8fb067 100644 --- a/spec/java/util/ArrayList.main.lsl +++ b/spec/java/util/ArrayList.main.lsl @@ -455,7 +455,7 @@ automaton ArrayListAutomaton fun *.contains (@target self: ArrayList, o: Object): boolean { - result = action LIST_FIND(this.storage, o, 0, this.length) >= 0; + result = action LIST_FIND(this.storage, o, 0, this.length) != -1; } @@ -491,7 +491,7 @@ automaton ArrayListAutomaton @Phantom proc containsAll_loop_optimized (otherStorage: list, i: int, result: boolean): void { val item: Object = action LIST_GET(otherStorage, i); - result = action LIST_FIND(this.storage, item, 0, this.length) >= 0; + result = action LIST_FIND(this.storage, item, 0, this.length) != -1; i += 1; } @@ -499,7 +499,7 @@ automaton ArrayListAutomaton @Phantom proc containsAll_loop_regular (iter: Iterator, result: boolean): void { val item: Object = action CALL_METHOD(iter, "next", []); - result = action LIST_FIND(this.storage, item, 0, this.length) >= 0; + result = action LIST_FIND(this.storage, item, 0, this.length) != -1; } @@ -605,15 +605,24 @@ automaton ArrayListAutomaton fun *.lastIndexOf (@target self: ArrayList, o: Object): int { - result = action LIST_FIND(this.storage, o, 0, this.length); - if (result != -1) + if (this.length == 0) + { + result = -1; + } + else { - // there should be no elements to the right of the previously found position - val nextIndex: int = result + 1; - if (nextIndex < this.length) + action ASSUME(this.length > 0); + + result = action LIST_FIND(this.storage, o, 0, this.length); + if (result != -1) { - val rightIndex: int = action LIST_FIND(this.storage, o, nextIndex, this.length); - action ASSUME(rightIndex == -1); + // there should be no elements to the right of the previously found position + val nextIndex: int = result + 1; + if (nextIndex < this.length) + { + val rightIndex: int = action LIST_FIND(this.storage, o, nextIndex, this.length); + action ASSUME(rightIndex == -1); + } } } } @@ -651,9 +660,7 @@ automaton ArrayListAutomaton fun *.remove (@target self: ArrayList, o: Object): boolean { val index: int = action LIST_FIND(this.storage, o, 0, this.length); - - result = index >= 0; - + result = index != -1; if (result) _deleteElement(index); } @@ -699,8 +706,7 @@ automaton ArrayListAutomaton { val o: Object = action LIST_GET(otherStorage, i); val index: int = action LIST_FIND(this.storage, o, 0, this.length); - - if (index >= 0) + if (index != -1) _deleteElement(index); } @@ -708,8 +714,7 @@ automaton ArrayListAutomaton { val o: Object = action CALL_METHOD(iter, "next", []); val index: int = action LIST_FIND(this.storage, o, 0, this.length); - - if (index >= 0) + if (index != -1) _deleteElement(index); } @@ -762,8 +767,7 @@ automaton ArrayListAutomaton @Phantom proc retainAll_loop_optimized (i: int, otherStorage: list, otherLength: int): void { val item: Object = action LIST_GET(this.storage, i); - val otherHasItem: boolean = action LIST_FIND(otherStorage, item, 0, otherLength) >= 0; - + val otherHasItem: boolean = action LIST_FIND(otherStorage, item, 0, otherLength) != -1; if (!otherHasItem) _deleteElement(i); } @@ -772,7 +776,6 @@ automaton ArrayListAutomaton { val item: Object = action LIST_GET(this.storage, i); val otherHasItem: boolean = action CALL_METHOD(c, "contains", [item]); - if (!otherHasItem) _deleteElement(i); } diff --git a/spec/java/util/LinkedList.automata.lsl b/spec/java/util/LinkedList.automata.lsl index 89e84ed9..54fb1ba4 100644 --- a/spec/java/util/LinkedList.automata.lsl +++ b/spec/java/util/LinkedList.automata.lsl @@ -172,8 +172,7 @@ automaton LinkedListAutomaton proc _unlinkByFirstEqualsObject (o: Object): boolean { val index: int = action LIST_FIND(this.storage, o, 0, this.size); - - result = index >= 0; + result = index != -1; if (result) { action LIST_REMOVE(this.storage, index); @@ -310,7 +309,7 @@ automaton LinkedListAutomaton fun *.contains (@target self: LinkedList, o: Object): boolean { - result = action LIST_FIND(this.storage, o, 0, this.size) >= 0; + result = action LIST_FIND(this.storage, o, 0, this.size) != -1; } @@ -346,7 +345,7 @@ automaton LinkedListAutomaton @Phantom proc containsAll_loop_optimized (otherStorage: list, i: int, result: boolean): void { val item: Object = action LIST_GET(otherStorage, i); - result = action LIST_FIND(this.storage, item, 0, this.size) >= 0; + result = action LIST_FIND(this.storage, item, 0, this.size) != -1; i += 1; } @@ -354,7 +353,7 @@ automaton LinkedListAutomaton @Phantom proc containsAll_loop_regular (iter: Iterator, result: boolean): void { val item: Object = action CALL_METHOD(iter, "next", []); - result = action LIST_FIND(this.storage, item, 0, this.size) >= 0; + result = action LIST_FIND(this.storage, item, 0, this.size) != -1; } From 49fb61aae129e2aefd2afccc7ef742113819ecde Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Thu, 21 Sep 2023 12:30:04 +0300 Subject: [PATCH 02/78] Added implementation for `ArrayList.SubList.ListIterator` --- .../util/ArrayList.SubList.ListIterator.lsl | 247 ++++++++++++++++++ spec/java/util/ArrayList.SubList.lsl | 29 +- spec/java/util/ArrayList.lsl | 9 + 3 files changed, 282 insertions(+), 3 deletions(-) create mode 100644 spec/java/util/ArrayList.SubList.ListIterator.lsl diff --git a/spec/java/util/ArrayList.SubList.ListIterator.lsl b/spec/java/util/ArrayList.SubList.ListIterator.lsl new file mode 100644 index 00000000..03797543 --- /dev/null +++ b/spec/java/util/ArrayList.SubList.ListIterator.lsl @@ -0,0 +1,247 @@ +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/util/ArrayList.java"; + +// imports + +import java/util/ArrayList; + + +// automata + +automaton ArrayList_SubList_ListIteratorAutomaton +( + var root: ArrayList, + var sublist: ArrayList_SubList, + var cursor: int, + var expectedModCount: int, + var offset: int, + var size: int, +) +: ArrayList_SubList_ListIterator +{ + // states and shifts + + initstate Initialized; + + shift Initialized -> self by [ + add, + forEachRemaining, + hasNext, + hasPrevious, + next, + nextIndex, + previous, + previousIndex, + remove, + set, + ]; + + + // local variables + + var lastRet: int = -1; + + + // utilities + + @AutoInline @Phantom proc _throwCME (): void + { + action THROW_NEW("java.util.ConcurrentModificationException", []); + } + + + proc _checkForComodification (): void + { + val modCount: int = ArrayListAutomaton(this.root).modCount; + if (modCount != this.expectedModCount) + _throwCME(); + } + + + // methods + + fun *.hasPrevious (@target self: ArrayList_SubList_ListIterator): boolean + { + result = this.cursor != 0; + } + + + fun *.nextIndex (@target self: ArrayList_SubList_ListIterator): int + { + result = this.cursor; + } + + + fun *.previousIndex (@target self: ArrayList_SubList_ListIterator): int + { + result = this.cursor - 1; + } + + + fun *.hasNext (@target self: ArrayList_SubList_ListIterator): boolean + { + result = this.cursor != this.size; + } + + + fun *.next (@target self: ArrayList_SubList_ListIterator): Object + { + // relax state/error discovery process + action ASSUME(this.root != null); + + _checkForComodification(); + + val i: int = this.offset + this.cursor; + if (i >= ArrayListAutomaton(this.root).length) + action THROW_NEW("java.util.NoSuchElementException", []); + + // iterrator validity check + val rootStorage: list = ArrayListAutomaton(this.root).storage; + if (i >= action LIST_SIZE(rootStorage)) + _throwCME(); + + this.lastRet = this.cursor; + this.cursor += 1; + + result = action LIST_GET(rootStorage, i); + } + + + fun *.previous (@target self: ArrayList_SubList_ListIterator): Object + { + // relax state/error discovery process + action ASSUME(this.root != null); + + _checkForComodification(); + + val i: int = this.offset + this.cursor - 1; + if (i < this.offset) + action THROW_NEW("java.util.NoSuchElementException", []); + + // iterrator validity check + val rootStorage: list = ArrayListAutomaton(this.root).storage; + if (i >= action LIST_SIZE(rootStorage)) + _throwCME(); + + this.cursor -= 1; + this.lastRet = this.cursor; + + result = action LIST_GET(rootStorage, i); + } + + + fun *.remove (@target self: ArrayList_SubList_ListIterator): void + { + // relax state/error discovery process + action ASSUME(this.root != null); + + if (this.lastRet < 0) + action THROW_NEW("java.lang.IllegalStateException", []); + + _checkForComodification(); + + if (this.lastRet >= this.size) + { + _throwCME(); + } + else + { + ArrayListAutomaton(this.root)._deleteElement(this.offset + this.lastRet); + + ArrayList_SubListAutomaton(this.sublist)._updateSizeAndModCount(-1); + this.expectedModCount = ArrayListAutomaton(this.root).modCount; + this.size -= 1; + } + + this.cursor = this.lastRet; + this.lastRet = -1; + } + + + fun *.set (@target self: ArrayList_SubList_ListIterator, e: Object): void + { + // relax state/error discovery process + action ASSUME(this.root != null); + + if (this.lastRet < 0) + action THROW_NEW("java.lang.IllegalStateException", []); + + _checkForComodification(); + + val index: int = this.offset + this.lastRet; + if (index >= ArrayListAutomaton(this.root).length) + _throwCME(); + else + action LIST_SET(ArrayListAutomaton(this.root).storage, index, e); + } + + + fun *.add (@target self: ArrayList_SubList_ListIterator, e: Object): void + { + // relax state/error discovery process + action ASSUME(this.root != null); + + _checkForComodification(); + + val i: int = this.offset + this.cursor; + + if (this.offset + this.lastRet > ArrayListAutomaton(this.root).length) + { + _throwCME(); + } + else + { + ArrayListAutomaton(this.root)._addElement(i, e); + + ArrayList_SubListAutomaton(this.sublist)._updateSizeAndModCount(+1); + this.expectedModCount = ArrayListAutomaton(this.root).modCount; + this.size += 1; + } + + this.cursor += 1; + this.lastRet = -1; + } + + + fun *.forEachRemaining (@target self: ArrayList_SubList_ListIterator, userAction: Consumer): void + { + // relax state/error discovery process + action ASSUME(this.root != null); + + if (userAction == null) + action THROW_NEW("java.lang.NullPointerException", []); + + var i: int = this.cursor; + if (i < this.size) + { + i += this.offset; + val es: list = ArrayListAutomaton(this.root).storage; + + if (i >= action LIST_SIZE(es)) + _throwCME(); + + val end: int = this.offset + this.size; + + action LOOP_FOR( + i, i, end, +1, + forEachRemaining_loop(userAction, es, i) + ); + + // JDK NOTE: "update once at end to reduce heap write traffic" + this.cursor = i - this.offset; + this.lastRet = this.cursor - 1; + _checkForComodification(); + } + } + + @Phantom proc forEachRemaining_loop (userAction: Consumer, es: list, i: int): void + { + val item: Object = action LIST_GET(es, i); + action CALL(userAction, [item]); + } + +} diff --git a/spec/java/util/ArrayList.SubList.lsl b/spec/java/util/ArrayList.SubList.lsl index eed79eb6..54e8b8b7 100644 --- a/spec/java/util/ArrayList.SubList.lsl +++ b/spec/java/util/ArrayList.SubList.lsl @@ -104,7 +104,7 @@ automaton ArrayList_SubListAutomaton } - proc _updateSizeAndModCount (sizeChange: int): void + @KeepVisible proc _updateSizeAndModCount (sizeChange: int): void { action ASSUME(this.root != null); @@ -393,7 +393,14 @@ automaton ArrayList_SubListAutomaton fun *.iterator (@target self: ArrayList_SubList): Iterator { - action TODO(); + result = new ArrayList_SubList_ListIteratorAutomaton(state = Initialized, + root = this.root, + sublist = self, + cursor = 0, + expectedModCount = this.modCount, + offset = this.offset, + size = this.length, + ); } @@ -433,13 +440,29 @@ automaton ArrayList_SubListAutomaton // within java.util.AbstractList fun *.listIterator (@target self: ArrayList_SubList): ListIterator { - action TODO(); + result = new ArrayList_SubList_ListIteratorAutomaton(state = Initialized, + root = this.root, + sublist = self, + cursor = 0, + expectedModCount = this.modCount, + offset = this.offset, + size = this.length, + ); } fun *.listIterator (@target self: ArrayList_SubList, index: int): ListIterator { action TODO(); + + result = new ArrayList_SubList_ListIteratorAutomaton(state = Initialized, + root = this.root, + sublist = self, + cursor = index, + expectedModCount = this.modCount, + offset = this.offset, + size = this.length, + ); } diff --git a/spec/java/util/ArrayList.lsl b/spec/java/util/ArrayList.lsl index c06028ba..f4ad8a34 100644 --- a/spec/java/util/ArrayList.lsl +++ b/spec/java/util/ArrayList.lsl @@ -70,3 +70,12 @@ import java/util/stream/_interfaces; for Spliterator { } + + +@GenerateMe +@implements("java.util.ListIterator") +@public @final type ArrayList_SubList_ListIterator + is java.util.ArrayList_SubList$ListIterator // NOTE: do not use inner classes + for ListIterator +{ +} From a745ad91b722d10ca606219dce14c7bf1e3bf8c7 Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Sat, 23 Sep 2023 12:29:26 +0300 Subject: [PATCH 03/78] Fixed variable access in `HashSet.Spliterator` --- spec/java/util/HashSet.Spliterator.lsl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/java/util/HashSet.Spliterator.lsl b/spec/java/util/HashSet.Spliterator.lsl index 1df4a038..3e337d0f 100644 --- a/spec/java/util/HashSet.Spliterator.lsl +++ b/spec/java/util/HashSet.Spliterator.lsl @@ -157,7 +157,7 @@ automaton HashSet_KeySpliteratorAutomaton @Phantom proc forEachRemaining_loop (userAction: Consumer, i: int): void { - val key: Object = keysStorage[i]; + val key: Object = this.keysStorage[i]; action CALL(userAction, [key]); i += 1; } @@ -175,7 +175,7 @@ automaton HashSet_KeySpliteratorAutomaton if(i < hi) { - val key: Object = keysStorage[i]; + val key: Object = this.keysStorage[i]; action CALL(userAction, [key]); this.index += 1; From 2905a1608fc4c016caf7c23901d87200e95295aa Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Mon, 25 Sep 2023 13:59:34 +0300 Subject: [PATCH 04/78] Added draft implementation for `java.lang.SecurityManager` + More type definitions --- spec/java/io/FileDescriptor.lsl | 24 ++ spec/java/lang/SecurityManager.lsl | 20 ++ spec/java/lang/SecurityManager.main.lsl | 321 ++++++++++++++++++ spec/java/lang/Thread.lsl | 20 ++ spec/java/lang/ThreadGroup.lsl | 20 ++ spec/java/lang/_interfaces.lsl | 8 +- spec/java/net/InetAddress.lsl | 20 ++ spec/java/security/_interfaces.lsl | 27 ++ .../util/ArrayList.SubList.ListIterator.lsl | 8 + 9 files changed, 466 insertions(+), 2 deletions(-) create mode 100644 spec/java/io/FileDescriptor.lsl create mode 100644 spec/java/lang/SecurityManager.lsl create mode 100644 spec/java/lang/SecurityManager.main.lsl create mode 100644 spec/java/lang/Thread.lsl create mode 100644 spec/java/lang/ThreadGroup.lsl create mode 100644 spec/java/net/InetAddress.lsl create mode 100644 spec/java/security/_interfaces.lsl diff --git a/spec/java/io/FileDescriptor.lsl b/spec/java/io/FileDescriptor.lsl new file mode 100644 index 00000000..99b91239 --- /dev/null +++ b/spec/java/io/FileDescriptor.lsl @@ -0,0 +1,24 @@ +//#! pragma: non-synthesizable +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/io/FileDescriptor.java"; + +// imports + +import java.common; + + +// primary semantic types + +@public type FileDescriptor + is java.io.FileDescriptor + for Object +{ + fun valid(): boolean; + + @throws(["java.io.SyncFailedException"]) + fun sync(): void; +} diff --git a/spec/java/lang/SecurityManager.lsl b/spec/java/lang/SecurityManager.lsl new file mode 100644 index 00000000..92ee1060 --- /dev/null +++ b/spec/java/lang/SecurityManager.lsl @@ -0,0 +1,20 @@ +//#! pragma: non-synthesizable +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/lang/SecurityManager.java"; + +// imports + +import java.common; + + +// primary semantic types + +@public type SecurityManager + is java.lang.SecurityManager + for Object +{ +} diff --git a/spec/java/lang/SecurityManager.main.lsl b/spec/java/lang/SecurityManager.main.lsl new file mode 100644 index 00000000..ac94e083 --- /dev/null +++ b/spec/java/lang/SecurityManager.main.lsl @@ -0,0 +1,321 @@ +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/lang/SecurityManager.java"; + +// imports + +import java.common; +import java/io/FileDescriptor; +import java/lang/Thread; +import java/lang/ThreadGroup; +import java/lang/SecurityManager; +import java/net/InetAddress; +import java/security/_interfaces; + + +// local semantic types + +@public type LSLSecurityManager + is java.lang.SecurityManager + for SecurityManager +{ +} + + +// automata + +automaton LSLSecurityManagerAutomaton +( +) +: LSLSecurityManager +{ + // states and shifts + + initstate Allocated; + state Initialized; + + shift Allocated -> Initialized by [ + // constructors + LSLSecurityManager, + ]; + + shift Initialized -> self by [ + // instance methods + checkAccept, + checkAccess (LSLSecurityManager, Thread), + checkAccess (LSLSecurityManager, ThreadGroup), + checkConnect (LSLSecurityManager, String, int), + checkConnect (LSLSecurityManager, String, int, Object), + checkCreateClassLoader, + checkDelete, + checkExec, + checkExit, + checkLink, + checkListen, + checkMulticast (LSLSecurityManager, InetAddress), + checkMulticast (LSLSecurityManager, InetAddress, byte), + checkPackageAccess, + checkPackageDefinition, + checkPermission (LSLSecurityManager, Permission), + checkPermission (LSLSecurityManager, Permission, Object), + checkPrintJobAccess, + checkPropertiesAccess, + checkPropertyAccess, + checkRead (LSLSecurityManager, FileDescriptor), + checkRead (LSLSecurityManager, String), + checkRead (LSLSecurityManager, String, Object), + checkSecurityAccess, + checkSetFactory, + checkWrite (LSLSecurityManager, FileDescriptor), + checkWrite (LSLSecurityManager, String), + getSecurityContext, + getThreadGroup, + ]; + + // internal variables + + // utilities + + @AutoInline @Phantom proc _throwNPE (): void + { + action THROW_NEW("java.lang.NullPointerException", []); + } + + + @AutoInline @Phantom proc _throwSE (): void + { + action THROW_NEW("java.lang.SecurityException", []); + } + + + // constructors + + constructor *.LSLSecurityManager (@target self: LSLSecurityManager) + { + if (action SYMBOLIC("boolean")) + _throwSE(); + } + + + // static methods + + // methods + + fun *.checkAccept (@target self: LSLSecurityManager, host: String, port: int): void + { + if (host == null) + _throwNPE(); + + action TODO(); // check host correctness + + if (action SYMBOLIC("boolean")) + _throwSE(); + } + + + fun *.checkAccess (@target self: LSLSecurityManager, t: Thread): void + { + if (action SYMBOLIC("boolean")) + _throwSE(); + } + + + fun *.checkAccess (@target self: LSLSecurityManager, g: ThreadGroup): void + { + if (action SYMBOLIC("boolean")) + _throwSE(); + } + + + fun *.checkConnect (@target self: LSLSecurityManager, host: String, port: int): void + { + if (action SYMBOLIC("boolean")) + _throwSE(); + } + + + fun *.checkConnect (@target self: LSLSecurityManager, host: String, port: int, context: Object): void + { + if (action SYMBOLIC("boolean")) + _throwSE(); + } + + + fun *.checkCreateClassLoader (@target self: LSLSecurityManager): void + { + if (action SYMBOLIC("boolean")) + _throwSE(); + } + + + fun *.checkDelete (@target self: LSLSecurityManager, file: String): void + { + if (action SYMBOLIC("boolean")) + _throwSE(); + } + + + fun *.checkExec (@target self: LSLSecurityManager, cmd: String): void + { + if (cmd == null) + _throwNPE(); + + if (action SYMBOLIC("boolean")) + _throwSE(); + } + + + fun *.checkExit (@target self: LSLSecurityManager, status: int): void + { + if (action SYMBOLIC("boolean")) + _throwSE(); + } + + + fun *.checkLink (@target self: LSLSecurityManager, lib: String): void + { + if (action SYMBOLIC("boolean")) + _throwSE(); + } + + + fun *.checkListen (@target self: LSLSecurityManager, port: int): void + { + if (action SYMBOLIC("boolean")) + _throwSE(); + } + + + fun *.checkMulticast (@target self: LSLSecurityManager, maddr: InetAddress): void + { + if (action SYMBOLIC("boolean")) + _throwSE(); + } + + + fun *.checkMulticast (@target self: LSLSecurityManager, maddr: InetAddress, ttl: byte): void + { + if (action SYMBOLIC("boolean")) + _throwSE(); + } + + + fun *.checkPackageAccess (@target self: LSLSecurityManager, pkg: String): void + { + if (action SYMBOLIC("boolean")) + _throwSE(); + } + + + fun *.checkPackageDefinition (@target self: LSLSecurityManager, pkg: String): void + { + if (action SYMBOLIC("boolean")) + _throwSE(); + } + + + fun *.checkPermission (@target self: LSLSecurityManager, perm: Permission): void + { + if (action SYMBOLIC("boolean")) + _throwSE(); + } + + + fun *.checkPermission (@target self: LSLSecurityManager, perm: Permission, context: Object): void + { + if (action SYMBOLIC("boolean")) + _throwSE(); + } + + + fun *.checkPrintJobAccess (@target self: LSLSecurityManager): void + { + if (action SYMBOLIC("boolean")) + _throwSE(); + } + + + fun *.checkPropertiesAccess (@target self: LSLSecurityManager): void + { + if (action SYMBOLIC("boolean")) + _throwSE(); + } + + + fun *.checkPropertyAccess (@target self: LSLSecurityManager, key: String): void + { + if (action SYMBOLIC("boolean")) + _throwSE(); + } + + + fun *.checkRead (@target self: LSLSecurityManager, fd: FileDescriptor): void + { + if (action SYMBOLIC("boolean")) + _throwSE(); + } + + + fun *.checkRead (@target self: LSLSecurityManager, file: String): void + { + if (action SYMBOLIC("boolean")) + _throwSE(); + } + + + fun *.checkRead (@target self: LSLSecurityManager, file: String, context: Object): void + { + if (action SYMBOLIC("boolean")) + _throwSE(); + } + + + fun *.checkSecurityAccess (@target self: LSLSecurityManager, _target: String): void + { + if (_target == null) + _throwNPE(); + + if (action CALL_METHOD(_target, "isEmpty", [])) + action THROW_NEW("java.lang.IllegalArgumentException", []); + + if (action SYMBOLIC("boolean")) + _throwSE(); + } + + + fun *.checkSetFactory (@target self: LSLSecurityManager): void + { + if (action SYMBOLIC("boolean")) + _throwSE(); + } + + + fun *.checkWrite (@target self: LSLSecurityManager, fd: FileDescriptor): void + { + if (action SYMBOLIC("boolean")) + _throwSE(); + } + + + fun *.checkWrite (@target self: LSLSecurityManager, file: String): void + { + if (action SYMBOLIC("boolean")) + _throwSE(); + } + + + fun *.getSecurityContext (@target self: LSLSecurityManager): Object + { + result = action SYMBOLIC("java.lang.Object"); + } + + + @Phantom fun *.getThreadGroup (@target self: LSLSecurityManager): ThreadGroup + { + // NOTE: using the original method + } + +} diff --git a/spec/java/lang/Thread.lsl b/spec/java/lang/Thread.lsl new file mode 100644 index 00000000..ae7b356e --- /dev/null +++ b/spec/java/lang/Thread.lsl @@ -0,0 +1,20 @@ +//#! pragma: non-synthesizable +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/lang/Thread.java"; + +// imports + +import java.common; + + +// primary semantic types + +@public type Thread + is java.lang.Thread + for Object +{ +} diff --git a/spec/java/lang/ThreadGroup.lsl b/spec/java/lang/ThreadGroup.lsl new file mode 100644 index 00000000..f453b92a --- /dev/null +++ b/spec/java/lang/ThreadGroup.lsl @@ -0,0 +1,20 @@ +//#! pragma: non-synthesizable +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/lang/ThreadGroup.java"; + +// imports + +import java.common; + + +// primary semantic types + +@public type ThreadGroup + is java.lang.ThreadGroup + for Object +{ +} diff --git a/spec/java/lang/_interfaces.lsl b/spec/java/lang/_interfaces.lsl index 51ded93e..17995f8d 100644 --- a/spec/java/lang/_interfaces.lsl +++ b/spec/java/lang/_interfaces.lsl @@ -41,9 +41,13 @@ type String is java.lang.String for CharSequence, string { - fun compareTo(anotherString: string): int; // #problem: self-reference + fun compareTo(anotherString: string): int; - fun indexOf(anotherString: string, fromIndex: int): int; // #problem: self-reference + fun indexOf(anotherString: string, fromIndex: int): int; + + fun isBlank(): boolean; + + fun isEmpty(): boolean; fun toCharArray(): array; } diff --git a/spec/java/net/InetAddress.lsl b/spec/java/net/InetAddress.lsl new file mode 100644 index 00000000..dd22202e --- /dev/null +++ b/spec/java/net/InetAddress.lsl @@ -0,0 +1,20 @@ +//#! pragma: non-synthesizable +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/net/InetAddress.java"; + +// imports + +import java.common; + + +// primary semantic types + +@public type InetAddress + is java.net.InetAddress + for Object +{ +} diff --git a/spec/java/security/_interfaces.lsl b/spec/java/security/_interfaces.lsl new file mode 100644 index 00000000..5e3ea504 --- /dev/null +++ b/spec/java/security/_interfaces.lsl @@ -0,0 +1,27 @@ +//#! pragma: non-synthesizable +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "https://github.com/openjdk/jdk11/tree/master/src/java.base/share/classes/java/io"; + +// imports + +import java.common; +import java/lang/_interfaces; + + +// semantic types + +type Permission + is java.security.Permission + for Object +{ + fun getName(): String; + + fun getActions(): String; + + // #problem: cyclic reference + //fun newPermissionCollection(): PermissionCollection; +} diff --git a/spec/java/util/ArrayList.SubList.ListIterator.lsl b/spec/java/util/ArrayList.SubList.ListIterator.lsl index 03797543..89aee1ae 100644 --- a/spec/java/util/ArrayList.SubList.ListIterator.lsl +++ b/spec/java/util/ArrayList.SubList.ListIterator.lsl @@ -62,6 +62,14 @@ automaton ArrayList_SubList_ListIteratorAutomaton } + proc qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq(a: boolean, b: boolean): boolean + { + result = !a || !b; + result = !a && !b; + result = !a ^ !b; + } + + // methods fun *.hasPrevious (@target self: ArrayList_SubList_ListIterator): boolean From 85da62a59c581c235cffdfbe70bd42d32abff564 Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Tue, 26 Sep 2023 10:46:35 +0300 Subject: [PATCH 05/78] Improvements to `SecurityManager` + More type declarations --- spec/java/lang/SecurityManager.main.lsl | 137 +++++++++++++++----- spec/java/security/AccessControlContext.lsl | 20 +++ 2 files changed, 123 insertions(+), 34 deletions(-) create mode 100644 spec/java/security/AccessControlContext.lsl diff --git a/spec/java/lang/SecurityManager.main.lsl b/spec/java/lang/SecurityManager.main.lsl index ac94e083..b03b8019 100644 --- a/spec/java/lang/SecurityManager.main.lsl +++ b/spec/java/lang/SecurityManager.main.lsl @@ -14,6 +14,7 @@ import java/lang/ThreadGroup; import java/lang/SecurityManager; import java/net/InetAddress; import java/security/_interfaces; +import java/security/AccessControlContext; // local semantic types @@ -85,9 +86,15 @@ automaton LSLSecurityManagerAutomaton } - @AutoInline @Phantom proc _throwSE (): void + @AutoInline @Phantom proc _throwIAE (): void { - action THROW_NEW("java.lang.SecurityException", []); + action THROW_NEW("java.lang.IllegalArgumentException", []); + } + + + @AutoInline @Phantom proc _throwACE (): void + { + action THROW_NEW("java.security.AccessControlException", []); } @@ -96,7 +103,7 @@ automaton LSLSecurityManagerAutomaton constructor *.LSLSecurityManager (@target self: LSLSecurityManager) { if (action SYMBOLIC("boolean")) - _throwSE(); + _throwACE(); } @@ -109,52 +116,83 @@ automaton LSLSecurityManagerAutomaton if (host == null) _throwNPE(); - action TODO(); // check host correctness + // 'host' correctness check is too complex + if (action SYMBOLIC("boolean")) + _throwIAE(); if (action SYMBOLIC("boolean")) - _throwSE(); + _throwACE(); } fun *.checkAccess (@target self: LSLSecurityManager, t: Thread): void { + if (t == null) + action THROW_NEW("java.lang.NullPointerException", ["thread can't be null"]); + + // #todo: check thread group? + if (action SYMBOLIC("boolean")) - _throwSE(); + _throwACE(); } fun *.checkAccess (@target self: LSLSecurityManager, g: ThreadGroup): void { + if (g == null) + action THROW_NEW("java.lang.NullPointerException", ["thread group can't be null"]); + + // #todo: check thread group? + if (action SYMBOLIC("boolean")) - _throwSE(); + _throwACE(); } fun *.checkConnect (@target self: LSLSecurityManager, host: String, port: int): void { + if (host == null) + action THROW_NEW("java.lang.NullPointerException", ["host can't be null"]); + + // host correctness check is too complex if (action SYMBOLIC("boolean")) - _throwSE(); + _throwIAE(); + + if (action SYMBOLIC("boolean")) + _throwACE(); } fun *.checkConnect (@target self: LSLSecurityManager, host: String, port: int, context: Object): void { + if (host == null) + _throwNPE(); + + // host correctness check is too complex + if (action SYMBOLIC("boolean")) + _throwIAE(); + if (action SYMBOLIC("boolean")) - _throwSE(); + _throwACE(); } fun *.checkCreateClassLoader (@target self: LSLSecurityManager): void { if (action SYMBOLIC("boolean")) - _throwSE(); + _throwACE(); } fun *.checkDelete (@target self: LSLSecurityManager, file: String): void { + if (file == null) + _throwNPE(); + + // 'action' check during construction of a FilePermission object does not throw an exception + if (action SYMBOLIC("boolean")) - _throwSE(); + _throwACE(); } @@ -163,113 +201,143 @@ automaton LSLSecurityManagerAutomaton if (cmd == null) _throwNPE(); + // 'action' check during construction of a FilePermission object does not throw an exception + if (action SYMBOLIC("boolean")) - _throwSE(); + _throwACE(); } fun *.checkExit (@target self: LSLSecurityManager, status: int): void { if (action SYMBOLIC("boolean")) - _throwSE(); + _throwACE(); } fun *.checkLink (@target self: LSLSecurityManager, lib: String): void { + if (lib == null) + _throwNPE(); + if (action SYMBOLIC("boolean")) - _throwSE(); + _throwACE(); } fun *.checkListen (@target self: LSLSecurityManager, port: int): void { if (action SYMBOLIC("boolean")) - _throwSE(); + _throwACE(); } fun *.checkMulticast (@target self: LSLSecurityManager, maddr: InetAddress): void { + if (maddr == null) + _throwNPE(); + if (action SYMBOLIC("boolean")) - _throwSE(); + _throwACE(); } fun *.checkMulticast (@target self: LSLSecurityManager, maddr: InetAddress, ttl: byte): void { + if (maddr == null) + _throwNPE(); + if (action SYMBOLIC("boolean")) - _throwSE(); + _throwACE(); } fun *.checkPackageAccess (@target self: LSLSecurityManager, pkg: String): void { + if (pkg == null) + _throwNPE(); + if (action SYMBOLIC("boolean")) - _throwSE(); + _throwACE(); } fun *.checkPackageDefinition (@target self: LSLSecurityManager, pkg: String): void { + if (pkg == null) + _throwNPE(); + if (action SYMBOLIC("boolean")) - _throwSE(); + _throwACE(); } fun *.checkPermission (@target self: LSLSecurityManager, perm: Permission): void { + if (perm == null) + _throwNPE(); + if (action SYMBOLIC("boolean")) - _throwSE(); + _throwACE(); } fun *.checkPermission (@target self: LSLSecurityManager, perm: Permission, context: Object): void { - if (action SYMBOLIC("boolean")) - _throwSE(); + if (context is AccessControlContext) + { + if (perm == null) + _throwNPE(); + + if (action SYMBOLIC("boolean")) + _throwACE(); + } + else + { + action THROW_NEW("java.lang.SecurityException", []); + } } fun *.checkPrintJobAccess (@target self: LSLSecurityManager): void { if (action SYMBOLIC("boolean")) - _throwSE(); + _throwACE(); } fun *.checkPropertiesAccess (@target self: LSLSecurityManager): void { if (action SYMBOLIC("boolean")) - _throwSE(); + _throwACE(); } fun *.checkPropertyAccess (@target self: LSLSecurityManager, key: String): void { if (action SYMBOLIC("boolean")) - _throwSE(); + _throwACE(); } fun *.checkRead (@target self: LSLSecurityManager, fd: FileDescriptor): void { if (action SYMBOLIC("boolean")) - _throwSE(); + _throwACE(); } fun *.checkRead (@target self: LSLSecurityManager, file: String): void { if (action SYMBOLIC("boolean")) - _throwSE(); + _throwACE(); } fun *.checkRead (@target self: LSLSecurityManager, file: String, context: Object): void { if (action SYMBOLIC("boolean")) - _throwSE(); + _throwACE(); } @@ -279,37 +347,38 @@ automaton LSLSecurityManagerAutomaton _throwNPE(); if (action CALL_METHOD(_target, "isEmpty", [])) - action THROW_NEW("java.lang.IllegalArgumentException", []); + _throwIAE(); if (action SYMBOLIC("boolean")) - _throwSE(); + _throwACE(); } fun *.checkSetFactory (@target self: LSLSecurityManager): void { if (action SYMBOLIC("boolean")) - _throwSE(); + _throwACE(); } fun *.checkWrite (@target self: LSLSecurityManager, fd: FileDescriptor): void { if (action SYMBOLIC("boolean")) - _throwSE(); + _throwACE(); } fun *.checkWrite (@target self: LSLSecurityManager, file: String): void { if (action SYMBOLIC("boolean")) - _throwSE(); + _throwACE(); } fun *.getSecurityContext (@target self: LSLSecurityManager): Object { - result = action SYMBOLIC("java.lang.Object"); + result = action SYMBOLIC("java.security.AccessControlContext"); + action ASSUME(result != null); } diff --git a/spec/java/security/AccessControlContext.lsl b/spec/java/security/AccessControlContext.lsl new file mode 100644 index 00000000..16c22755 --- /dev/null +++ b/spec/java/security/AccessControlContext.lsl @@ -0,0 +1,20 @@ +//#! pragma: non-synthesizable +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/security/AccessControlContext.java"; + +// imports + +import java.common; + + +// primary semantic types + +@public type AccessControlContext + is java.security.AccessControlContext + for Object +{ +} From 5a4175c43cc580a65a81d4f95fb55638b7538fac Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Tue, 26 Sep 2023 12:02:32 +0300 Subject: [PATCH 06/78] Improvements to `SecurityManager` --- spec/java/lang/SecurityManager.main.lsl | 98 ++++++++++--------------- 1 file changed, 39 insertions(+), 59 deletions(-) diff --git a/spec/java/lang/SecurityManager.main.lsl b/spec/java/lang/SecurityManager.main.lsl index b03b8019..d7aa974c 100644 --- a/spec/java/lang/SecurityManager.main.lsl +++ b/spec/java/lang/SecurityManager.main.lsl @@ -28,7 +28,7 @@ import java/security/AccessControlContext; // automata -automaton LSLSecurityManagerAutomaton +automaton SecurityManagerAutomaton ( ) : LSLSecurityManager @@ -92,9 +92,13 @@ automaton LSLSecurityManagerAutomaton } - @AutoInline @Phantom proc _throwACE (): void + proc _do_checkPermission (perm: Permission): void { - action THROW_NEW("java.security.AccessControlException", []); + if (action SYMBOLIC("boolean")) + action THROW_NEW("java.security.AccessControlException", [ + "access denied" /* + perm */, + perm + ]); } @@ -102,8 +106,10 @@ automaton LSLSecurityManagerAutomaton constructor *.LSLSecurityManager (@target self: LSLSecurityManager) { - if (action SYMBOLIC("boolean")) - _throwACE(); + val a: String = "createSecurityManager"; + _do_checkPermission( + action DEBUG_DO("new RuntimePermission(a)") + ); } @@ -120,8 +126,7 @@ automaton LSLSecurityManagerAutomaton if (action SYMBOLIC("boolean")) _throwIAE(); - if (action SYMBOLIC("boolean")) - _throwACE(); + _do_checkPermission(null); // #todo } @@ -132,8 +137,7 @@ automaton LSLSecurityManagerAutomaton // #todo: check thread group? - if (action SYMBOLIC("boolean")) - _throwACE(); + _do_checkPermission(null); // #todo } @@ -144,8 +148,7 @@ automaton LSLSecurityManagerAutomaton // #todo: check thread group? - if (action SYMBOLIC("boolean")) - _throwACE(); + _do_checkPermission(null); // #todo } @@ -158,8 +161,7 @@ automaton LSLSecurityManagerAutomaton if (action SYMBOLIC("boolean")) _throwIAE(); - if (action SYMBOLIC("boolean")) - _throwACE(); + _do_checkPermission(null); // #todo } @@ -172,15 +174,13 @@ automaton LSLSecurityManagerAutomaton if (action SYMBOLIC("boolean")) _throwIAE(); - if (action SYMBOLIC("boolean")) - _throwACE(); + _do_checkPermission(null); // #todo } fun *.checkCreateClassLoader (@target self: LSLSecurityManager): void { - if (action SYMBOLIC("boolean")) - _throwACE(); + _do_checkPermission(null); // #todo } @@ -191,8 +191,7 @@ automaton LSLSecurityManagerAutomaton // 'action' check during construction of a FilePermission object does not throw an exception - if (action SYMBOLIC("boolean")) - _throwACE(); + _do_checkPermission(null); // #todo } @@ -203,15 +202,13 @@ automaton LSLSecurityManagerAutomaton // 'action' check during construction of a FilePermission object does not throw an exception - if (action SYMBOLIC("boolean")) - _throwACE(); + _do_checkPermission(null); // #todo } fun *.checkExit (@target self: LSLSecurityManager, status: int): void { - if (action SYMBOLIC("boolean")) - _throwACE(); + _do_checkPermission(null); // #todo } @@ -220,15 +217,13 @@ automaton LSLSecurityManagerAutomaton if (lib == null) _throwNPE(); - if (action SYMBOLIC("boolean")) - _throwACE(); + _do_checkPermission(null); // #todo } fun *.checkListen (@target self: LSLSecurityManager, port: int): void { - if (action SYMBOLIC("boolean")) - _throwACE(); + _do_checkPermission(null); // #todo } @@ -237,8 +232,7 @@ automaton LSLSecurityManagerAutomaton if (maddr == null) _throwNPE(); - if (action SYMBOLIC("boolean")) - _throwACE(); + _do_checkPermission(null); // #todo } @@ -247,8 +241,7 @@ automaton LSLSecurityManagerAutomaton if (maddr == null) _throwNPE(); - if (action SYMBOLIC("boolean")) - _throwACE(); + _do_checkPermission(null); // #todo } @@ -257,8 +250,7 @@ automaton LSLSecurityManagerAutomaton if (pkg == null) _throwNPE(); - if (action SYMBOLIC("boolean")) - _throwACE(); + _do_checkPermission(null); // #todo } @@ -267,8 +259,7 @@ automaton LSLSecurityManagerAutomaton if (pkg == null) _throwNPE(); - if (action SYMBOLIC("boolean")) - _throwACE(); + _do_checkPermission(null); // #todo } @@ -277,8 +268,7 @@ automaton LSLSecurityManagerAutomaton if (perm == null) _throwNPE(); - if (action SYMBOLIC("boolean")) - _throwACE(); + _do_checkPermission(perm); } @@ -289,8 +279,7 @@ automaton LSLSecurityManagerAutomaton if (perm == null) _throwNPE(); - if (action SYMBOLIC("boolean")) - _throwACE(); + _do_checkPermission(perm); } else { @@ -301,43 +290,37 @@ automaton LSLSecurityManagerAutomaton fun *.checkPrintJobAccess (@target self: LSLSecurityManager): void { - if (action SYMBOLIC("boolean")) - _throwACE(); + _do_checkPermission(null); // #todo } fun *.checkPropertiesAccess (@target self: LSLSecurityManager): void { - if (action SYMBOLIC("boolean")) - _throwACE(); + _do_checkPermission(null); // #todo } fun *.checkPropertyAccess (@target self: LSLSecurityManager, key: String): void { - if (action SYMBOLIC("boolean")) - _throwACE(); + _do_checkPermission(null); // #todo } fun *.checkRead (@target self: LSLSecurityManager, fd: FileDescriptor): void { - if (action SYMBOLIC("boolean")) - _throwACE(); + _do_checkPermission(null); // #todo } fun *.checkRead (@target self: LSLSecurityManager, file: String): void { - if (action SYMBOLIC("boolean")) - _throwACE(); + _do_checkPermission(null); // #todo } fun *.checkRead (@target self: LSLSecurityManager, file: String, context: Object): void { - if (action SYMBOLIC("boolean")) - _throwACE(); + _do_checkPermission(null); // #todo } @@ -349,34 +332,31 @@ automaton LSLSecurityManagerAutomaton if (action CALL_METHOD(_target, "isEmpty", [])) _throwIAE(); - if (action SYMBOLIC("boolean")) - _throwACE(); + _do_checkPermission(null); // #todo } fun *.checkSetFactory (@target self: LSLSecurityManager): void { - if (action SYMBOLIC("boolean")) - _throwACE(); + _do_checkPermission(null); // #todo } fun *.checkWrite (@target self: LSLSecurityManager, fd: FileDescriptor): void { - if (action SYMBOLIC("boolean")) - _throwACE(); + _do_checkPermission(null); // #todo } fun *.checkWrite (@target self: LSLSecurityManager, file: String): void { - if (action SYMBOLIC("boolean")) - _throwACE(); + _do_checkPermission(null); // #todo } fun *.getSecurityContext (@target self: LSLSecurityManager): Object { + // #problem: type clash with 'Object' result = action SYMBOLIC("java.security.AccessControlContext"); action ASSUME(result != null); } From bf4bfea71b014b9a89e77c49011d6278dcccb1c6 Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Tue, 26 Sep 2023 13:21:46 +0300 Subject: [PATCH 07/78] Fixed conflict during `HASHSET_VALUE` initialization --- spec/java/lang/Object.lsl | 120 +----------------------------- spec/java/lang/Object.main.lsl | 129 +++++++++++++++++++++++++++++++++ spec/java/util/HashSet.lsl | 3 +- 3 files changed, 132 insertions(+), 120 deletions(-) create mode 100644 spec/java/lang/Object.main.lsl diff --git a/spec/java/lang/Object.lsl b/spec/java/lang/Object.lsl index 69a88bbf..227874dc 100644 --- a/spec/java/lang/Object.lsl +++ b/spec/java/lang/Object.lsl @@ -10,128 +10,10 @@ library std import java.common; -// local semantic types +// public semantic types @public type LSLObject is java.lang.Object for Object { } - - -// automata - -automaton ObjectAutomaton -( -) -: LSLObject -{ - // states and shifts - - initstate Initialized; - - shift Initialized -> self by [ - // constructors - LSLObject, - - // instance methods - equals, - clone, - getClass, - hashCode, - notify, - notifyAll, - toString, - wait (LSLObject), - wait (LSLObject, long), - wait (LSLObject, long, int), - ]; - - // internal variables - - // utilities - - // constructors - - @Phantom constructor *.LSLObject (@target self: LSLObject) - { - // NOTE: using the original method - } - - - // static methods - - // methods - - fun *.equals (@target self: LSLObject, obj: Object): boolean - { - result = self == obj; - } - - - @Phantom @protected fun *.clone (@target self: LSLObject): Object - { - // NOTE: using the original method - } - - - @Phantom @final fun *.getClass (@target self: LSLObject): Class - { - // NOTE: using the original method - } - - - fun *.hashCode (@target self: LSLObject): int - { - result = action SYMBOLIC("int"); - } - - - @Phantom @final fun *.notify (@target self: LSLObject): void - { - // NOTE: using the original method - } - - - @Phantom @final fun *.notifyAll (@target self: LSLObject): void - { - // NOTE: using the original method - } - - - fun *.toString (@target self: LSLObject): String - { - result = action SYMBOLIC("java.lang.String"); - action ASSUME(result != null); - } - - - @throws(["java.lang.InterruptedException"]) - @Phantom @final fun *.wait (@target self: LSLObject): void - { - // NOTE: using the original method - } - - - @throws(["java.lang.InterruptedException"]) - @Phantom @final fun *.wait (@target self: LSLObject, timeoutMillis: long): void - { - // NOTE: using the original method - } - - - @throws(["java.lang.InterruptedException"]) - @Phantom @final fun *.wait (@target self: LSLObject, timeoutMillis: long, nanos: int): void - { - // NOTE: using the original method - } - - - // special: static initialization - - @Phantom fun *.__clinit__ (): void - { - action DO_NOTHING(); - } - -} diff --git a/spec/java/lang/Object.main.lsl b/spec/java/lang/Object.main.lsl new file mode 100644 index 00000000..dae7e70b --- /dev/null +++ b/spec/java/lang/Object.main.lsl @@ -0,0 +1,129 @@ +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/lang/Object.java"; + +// imports + +import java.common; +import java/lang/Object; + + +// automata + +automaton ObjectAutomaton +( +) +: LSLObject +{ + // states and shifts + + initstate Initialized; + + shift Initialized -> self by [ + // constructors + LSLObject, + + // instance methods + equals, + clone, + getClass, + hashCode, + notify, + notifyAll, + toString, + wait (LSLObject), + wait (LSLObject, long), + wait (LSLObject, long, int), + ]; + + // internal variables + + // utilities + + // constructors + + @Phantom constructor *.LSLObject (@target self: LSLObject) + { + // NOTE: using the original method + } + + + // static methods + + // methods + + fun *.equals (@target self: LSLObject, obj: Object): boolean + { + result = self == obj; + } + + + @Phantom @protected fun *.clone (@target self: LSLObject): Object + { + // NOTE: using the original method + } + + + @Phantom @final fun *.getClass (@target self: LSLObject): Class + { + // NOTE: using the original method + } + + + fun *.hashCode (@target self: LSLObject): int + { + result = action SYMBOLIC("int"); + } + + + @Phantom @final fun *.notify (@target self: LSLObject): void + { + // NOTE: using the original method + } + + + @Phantom @final fun *.notifyAll (@target self: LSLObject): void + { + // NOTE: using the original method + } + + + fun *.toString (@target self: LSLObject): String + { + result = action SYMBOLIC("java.lang.String"); + action ASSUME(result != null); + } + + + @throws(["java.lang.InterruptedException"]) + @Phantom @final fun *.wait (@target self: LSLObject): void + { + // NOTE: using the original method + } + + + @throws(["java.lang.InterruptedException"]) + @Phantom @final fun *.wait (@target self: LSLObject, timeoutMillis: long): void + { + // NOTE: using the original method + } + + + @throws(["java.lang.InterruptedException"]) + @Phantom @final fun *.wait (@target self: LSLObject, timeoutMillis: long, nanos: int): void + { + // NOTE: using the original method + } + + + // special: static initialization + + @Phantom fun *.__clinit__ (): void + { + action DO_NOTHING(); + } + +} diff --git a/spec/java/util/HashSet.lsl b/spec/java/util/HashSet.lsl index 05a4844f..84b1a4f2 100644 --- a/spec/java/util/HashSet.lsl +++ b/spec/java/util/HashSet.lsl @@ -10,6 +10,7 @@ library std import java.common; import java/lang/_interfaces; +import java/lang/Object; import java/io/_interfaces; import java/util/_interfaces; import java/util/function/_interfaces; @@ -18,7 +19,7 @@ import java/util/HashMap; // === CONSTANTS === -val HASHSET_VALUE: Object = 0; +val HASHSET_VALUE: Object = new ObjectAutomaton(state = Initialized); // primary types From e80bd84dc0453f01cc76bfe67d1f994aefe51e8a Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Wed, 27 Sep 2023 13:44:37 +0300 Subject: [PATCH 08/78] Added `java.lang.Integer` + Minor improvements to `SecurityManager` --- spec/java/lang/Integer.lsl | 431 ++++++++++++++++++++++++ spec/java/lang/SecurityManager.main.lsl | 11 +- 2 files changed, 436 insertions(+), 6 deletions(-) create mode 100644 spec/java/lang/Integer.lsl diff --git a/spec/java/lang/Integer.lsl b/spec/java/lang/Integer.lsl new file mode 100644 index 00000000..00e67af0 --- /dev/null +++ b/spec/java/lang/Integer.lsl @@ -0,0 +1,431 @@ +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/lang/Integer.java"; + +// imports + +import java.common; +import java/lang/_interfaces; + + +// public semantic types + +//@extends("java.lang.Number") +//@implements("java.lang.Comparable") +@public @final type LSLInteger + is java.lang.Integer + for Integer +{ +} + + +// automata + +automaton IntegerAutomaton +( + @private val value: int // WARNING: do not rename! +) +: LSLInteger +{ + // states and shifts + + initstate Initialized; + + shift Initialized -> self by [ + // constructors + Integer (LSLInteger, String), + Integer (LSLInteger, int), + + // static operations + bitCount, + compare, + compareUnsigned, + decode, + divideUnsigned, + getInteger (String), + getInteger (String, Integer), + getInteger (String, int), + hashCode (int), + highestOneBit, + lowestOneBit, + max, + min, + numberOfLeadingZeros, + numberOfTrailingZeros, + parseInt (CharSequence, int, int, int), + parseInt (String), + parseInt (String, int), + parseUnsignedInt (CharSequence, int, int, int), + parseUnsignedInt (String), + parseUnsignedInt (String, int), + remainderUnsigned, + reverse, + reverseBytes, + rotateLeft, + rotateRight, + signum, + sum, + toBinaryString, + toHexString, + toOctalString, + toString (int), + toString (int, int), + toUnsignedLong, + toUnsignedString (int), + toUnsignedString (int, int), + valueOf (String), + valueOf (String, int), + valueOf (int), + + // instance methods + byteValue, + compareTo, + doubleValue, + equals, + floatValue, + hashCode (LSLInteger), + intValue, + longValue, + shortValue, + toString (LSLInteger), + ]; + + // internal variables + + // utilities + + // constructors + + @throws(["java.lang.NumberFormatException"]) + @Phantom constructor *.Integer (@target self: LSLInteger, s: String) + { + // NOTE: using the original method + } + + + @Phantom constructor *.Integer (@target self: LSLInteger, value: int) + { + // NOTE: using the original method + } + + + // static methods + + @Phantom @static fun *.bitCount (i: int): int + { + // NOTE: using the original method + } + + + @Phantom @static fun *.compare (x: int, y: int): int + { + // NOTE: using the original method + } + + + @Phantom @static fun *.compareUnsigned (x: int, y: int): int + { + // NOTE: using the original method + } + + + @throws(["java.lang.NumberFormatException"]) + @Phantom @static fun *.decode (nm: String): LSLInteger + { + // NOTE: using the original method + } + + + @Phantom @static fun *.divideUnsigned (dividend: int, divisor: int): int + { + // NOTE: using the original method + } + + + @Phantom @static fun *.getInteger (nm: String): LSLInteger + { + // NOTE: using the original method + } + + + @Phantom @static fun *.getInteger (nm: String, _val: Integer): LSLInteger + { + // NOTE: using the original method + } + + + @Phantom @static fun *.getInteger (nm: String, _val: int): LSLInteger + { + // NOTE: using the original method + } + + + @Phantom @static fun *.hashCode (value: int): int + { + // NOTE: using the original method + } + + + @Phantom @static fun *.highestOneBit (i: int): int + { + // NOTE: using the original method + } + + + @Phantom @static fun *.lowestOneBit (i: int): int + { + // NOTE: using the original method + } + + + @Phantom @static fun *.max (a: int, b: int): int + { + // NOTE: using the original method + } + + + @Phantom @static fun *.min (a: int, b: int): int + { + // NOTE: using the original method + } + + + @Phantom @static fun *.numberOfLeadingZeros (i: int): int + { + // NOTE: using the original method + } + + + @Phantom @static fun *.numberOfTrailingZeros (i: int): int + { + // NOTE: using the original method + } + + + @throws(["java.lang.NumberFormatException"]) + @Phantom @static fun *.parseInt (s: CharSequence, beginIndex: int, endIndex: int, radix: int): int + { + // NOTE: using the original method + } + + + @throws(["java.lang.NumberFormatException"]) + @Phantom @static fun *.parseInt (s: String): int + { + // NOTE: using the original method + } + + + @throws(["java.lang.NumberFormatException"]) + @Phantom @static fun *.parseInt (s: String, radix: int): int + { + // NOTE: using the original method + } + + + @throws(["java.lang.NumberFormatException"]) + @Phantom @static fun *.parseUnsignedInt (s: CharSequence, beginIndex: int, endIndex: int, radix: int): int + { + // NOTE: using the original method + } + + + @throws(["java.lang.NumberFormatException"]) + @Phantom @static fun *.parseUnsignedInt (s: String): int + { + // NOTE: using the original method + } + + + @throws(["java.lang.NumberFormatException"]) + @Phantom @static fun *.parseUnsignedInt (s: String, radix: int): int + { + // NOTE: using the original method + } + + + @Phantom @static fun *.remainderUnsigned (dividend: int, divisor: int): int + { + // NOTE: using the original method + } + + + @Phantom @static fun *.reverse (i: int): int + { + // NOTE: using the original method + } + + + @Phantom @static fun *.reverseBytes (i: int): int + { + // NOTE: using the original method + } + + + @Phantom @static fun *.rotateLeft (i: int, distance: int): int + { + // NOTE: using the original method + } + + + @Phantom @static fun *.rotateRight (i: int, distance: int): int + { + // NOTE: using the original method + } + + + @Phantom @static fun *.signum (i: int): int + { + // NOTE: using the original method + } + + + @Phantom @static fun *.sum (a: int, b: int): int + { + // NOTE: using the original method + } + + + @Phantom @static fun *.toBinaryString (i: int): String + { + // NOTE: using the original method + } + + + @Phantom @static fun *.toHexString (i: int): String + { + // NOTE: using the original method + } + + + @Phantom @static fun *.toOctalString (i: int): String + { + // NOTE: using the original method + } + + + @Phantom @static fun *.toString (i: int): String + { + // NOTE: using the original method + } + + + @Phantom @static fun *.toString (i: int, radix: int): String + { + // NOTE: using the original method + } + + + @Phantom @static fun *.toUnsignedLong (x: int): long + { + // NOTE: using the original method + } + + + @Phantom @static fun *.toUnsignedString (i: int): String + { + // NOTE: using the original method + } + + + @Phantom @static fun *.toUnsignedString (i: int, radix: int): String + { + // NOTE: using the original method + } + + + @throws(["java.lang.NumberFormatException"]) + @Phantom @static fun *.valueOf (s: String): LSLInteger + { + // NOTE: using the original method + } + + + @throws(["java.lang.NumberFormatException"]) + @Phantom @static fun *.valueOf (s: String, radix: int): LSLInteger + { + // NOTE: using the original method + } + + + @static fun *.valueOf (i: int): LSLInteger + { + result = new IntegerAutomaton(state = Initialized, + value = i + ); + } + + + // methods + + @Phantom fun *.byteValue (@target self: LSLInteger): byte + { + // NOTE: using the original method + } + + + @Phantom fun *.compareTo (@target self: LSLInteger, anotherInteger: Integer): int + { + // NOTE: using the original method + } + + + @Phantom fun *.doubleValue (@target self: LSLInteger): double + { + // NOTE: using the original method + } + + + @Phantom fun *.equals (@target self: LSLInteger, obj: Object): boolean + { + // NOTE: using the original method + } + + + @Phantom fun *.floatValue (@target self: LSLInteger): float + { + // NOTE: using the original method + } + + + @Phantom fun *.hashCode (@target self: LSLInteger): int + { + // NOTE: using the original method + } + + + @Phantom fun *.intValue (@target self: LSLInteger): int + { + // NOTE: using the original method + } + + + @Phantom fun *.longValue (@target self: LSLInteger): long + { + // NOTE: using the original method + } + + + @Phantom fun *.shortValue (@target self: LSLInteger): short + { + // NOTE: using the original method + } + + + @Phantom fun *.toString (@target self: LSLInteger): String + { + // NOTE: using the original method + } + + + // special: class initialization + + @Phantom fun *.__clinit__ (): void + { + // WARNING: this should be empty, do not change! + } + +} diff --git a/spec/java/lang/SecurityManager.main.lsl b/spec/java/lang/SecurityManager.main.lsl index d7aa974c..ba9645d9 100644 --- a/spec/java/lang/SecurityManager.main.lsl +++ b/spec/java/lang/SecurityManager.main.lsl @@ -96,7 +96,7 @@ automaton SecurityManagerAutomaton { if (action SYMBOLIC("boolean")) action THROW_NEW("java.security.AccessControlException", [ - "access denied" /* + perm */, + "access denied " /* + action OBJECT_TO_STRING(perm) */, perm ]); } @@ -106,9 +106,9 @@ automaton SecurityManagerAutomaton constructor *.LSLSecurityManager (@target self: LSLSecurityManager) { - val a: String = "createSecurityManager"; + val actionName: String = "createSecurityManager"; _do_checkPermission( - action DEBUG_DO("new RuntimePermission(a)") + action DEBUG_DO("new RuntimePermission(actionName)") ); } @@ -168,9 +168,9 @@ automaton SecurityManagerAutomaton fun *.checkConnect (@target self: LSLSecurityManager, host: String, port: int, context: Object): void { if (host == null) - _throwNPE(); + action THROW_NEW("java.lang.NullPointerException", ["host can't be null"]); - // host correctness check is too complex + // 'host' correctness check is too complex if (action SYMBOLIC("boolean")) _throwIAE(); @@ -356,7 +356,6 @@ automaton SecurityManagerAutomaton fun *.getSecurityContext (@target self: LSLSecurityManager): Object { - // #problem: type clash with 'Object' result = action SYMBOLIC("java.security.AccessControlContext"); action ASSUME(result != null); } From 139e4cce4fb09043a6cf34e46a916847af752e7b Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Wed, 27 Sep 2023 15:20:18 +0300 Subject: [PATCH 09/78] Minor corrections to `Throwable` "implementation" --- spec/java/lang/Throwable.lsl | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/spec/java/lang/Throwable.lsl b/spec/java/lang/Throwable.lsl index f377d606..275cb0a2 100644 --- a/spec/java/lang/Throwable.lsl +++ b/spec/java/lang/Throwable.lsl @@ -74,21 +74,18 @@ automaton ThrowableAutomaton @Phantom constructor *.Throwable (@target self: LSLThrowable) { // Note: using the original method - action TODO(); } @Phantom constructor *.Throwable (@target self: LSLThrowable, message: String) { // Note: using the original method - action TODO(); } @Phantom constructor *.Throwable (@target self: LSLThrowable, message: String, cause: Throwable) { // Note: using the original method - action TODO(); } @@ -96,14 +93,12 @@ automaton ThrowableAutomaton message: String, cause: Throwable, enableSuppression: boolean, writableStackTrace: boolean) { // Note: using the original method - action TODO(); } @Phantom constructor *.Throwable (@target self: LSLThrowable, cause: Throwable) { // Note: using the original method - action TODO(); } @@ -126,21 +121,18 @@ automaton ThrowableAutomaton @Phantom @synchronized fun *.getCause (@target self: LSLThrowable): Throwable { // Note: using the original method - action TODO(); } @Phantom fun *.getLocalizedMessage (@target self: LSLThrowable): String { // Note: using the original method - action TODO(); } @Phantom fun *.getMessage (@target self: LSLThrowable): String { // Note: using the original method - action TODO(); } @@ -167,7 +159,6 @@ automaton ThrowableAutomaton @Phantom @synchronized fun *.initCause (@target self: LSLThrowable, cause: Throwable): Throwable { // Note: using the original method - action TODO(); } @@ -180,14 +171,12 @@ automaton ThrowableAutomaton @Phantom fun *.printStackTrace (@target self: LSLThrowable, s: PrintStream): void { // Note: using the original method - action TODO(); } @Phantom fun *.printStackTrace (@target self: LSLThrowable, s: PrintWriter): void { // Note: using the original method - action TODO(); } @@ -200,7 +189,6 @@ automaton ThrowableAutomaton @Phantom fun *.toString (@target self: LSLThrowable): String { // Note: using the original method - action TODO(); } } From b9a0edb7bfb8ccc39c2593f271e7a1bf953a083e Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Fri, 29 Sep 2023 15:59:18 +0300 Subject: [PATCH 10/78] Minor formatting improvement to `SecurityManager` --- spec/java/lang/SecurityManager.main.lsl | 100 ++++++++++++++++++------ 1 file changed, 75 insertions(+), 25 deletions(-) diff --git a/spec/java/lang/SecurityManager.main.lsl b/spec/java/lang/SecurityManager.main.lsl index ba9645d9..8fa5b357 100644 --- a/spec/java/lang/SecurityManager.main.lsl +++ b/spec/java/lang/SecurityManager.main.lsl @@ -126,7 +126,9 @@ automaton SecurityManagerAutomaton if (action SYMBOLIC("boolean")) _throwIAE(); - _do_checkPermission(null); // #todo + _do_checkPermission( + null // #todo + ); } @@ -137,7 +139,9 @@ automaton SecurityManagerAutomaton // #todo: check thread group? - _do_checkPermission(null); // #todo + _do_checkPermission( + null // #todo + ); } @@ -148,7 +152,9 @@ automaton SecurityManagerAutomaton // #todo: check thread group? - _do_checkPermission(null); // #todo + _do_checkPermission( + null // #todo + ); } @@ -161,7 +167,9 @@ automaton SecurityManagerAutomaton if (action SYMBOLIC("boolean")) _throwIAE(); - _do_checkPermission(null); // #todo + _do_checkPermission( + null // #todo + ); } @@ -174,13 +182,17 @@ automaton SecurityManagerAutomaton if (action SYMBOLIC("boolean")) _throwIAE(); - _do_checkPermission(null); // #todo + _do_checkPermission( + null // #todo + ); } fun *.checkCreateClassLoader (@target self: LSLSecurityManager): void { - _do_checkPermission(null); // #todo + _do_checkPermission( + null // #todo + ); } @@ -191,7 +203,9 @@ automaton SecurityManagerAutomaton // 'action' check during construction of a FilePermission object does not throw an exception - _do_checkPermission(null); // #todo + _do_checkPermission( + null // #todo + ); } @@ -202,13 +216,17 @@ automaton SecurityManagerAutomaton // 'action' check during construction of a FilePermission object does not throw an exception - _do_checkPermission(null); // #todo + _do_checkPermission( + null // #todo + ); } fun *.checkExit (@target self: LSLSecurityManager, status: int): void { - _do_checkPermission(null); // #todo + _do_checkPermission( + null // #todo + ); } @@ -217,13 +235,17 @@ automaton SecurityManagerAutomaton if (lib == null) _throwNPE(); - _do_checkPermission(null); // #todo + _do_checkPermission( + null // #todo + ); } fun *.checkListen (@target self: LSLSecurityManager, port: int): void { - _do_checkPermission(null); // #todo + _do_checkPermission( + null // #todo + ); } @@ -232,7 +254,9 @@ automaton SecurityManagerAutomaton if (maddr == null) _throwNPE(); - _do_checkPermission(null); // #todo + _do_checkPermission( + null // #todo + ); } @@ -241,7 +265,9 @@ automaton SecurityManagerAutomaton if (maddr == null) _throwNPE(); - _do_checkPermission(null); // #todo + _do_checkPermission( + null // #todo + ); } @@ -250,7 +276,9 @@ automaton SecurityManagerAutomaton if (pkg == null) _throwNPE(); - _do_checkPermission(null); // #todo + _do_checkPermission( + null // #todo + ); } @@ -259,7 +287,9 @@ automaton SecurityManagerAutomaton if (pkg == null) _throwNPE(); - _do_checkPermission(null); // #todo + _do_checkPermission( + null // #todo + ); } @@ -290,37 +320,49 @@ automaton SecurityManagerAutomaton fun *.checkPrintJobAccess (@target self: LSLSecurityManager): void { - _do_checkPermission(null); // #todo + _do_checkPermission( + null // #todo + ); } fun *.checkPropertiesAccess (@target self: LSLSecurityManager): void { - _do_checkPermission(null); // #todo + _do_checkPermission( + null // #todo + ); } fun *.checkPropertyAccess (@target self: LSLSecurityManager, key: String): void { - _do_checkPermission(null); // #todo + _do_checkPermission( + null // #todo + ); } fun *.checkRead (@target self: LSLSecurityManager, fd: FileDescriptor): void { - _do_checkPermission(null); // #todo + _do_checkPermission( + null // #todo + ); } fun *.checkRead (@target self: LSLSecurityManager, file: String): void { - _do_checkPermission(null); // #todo + _do_checkPermission( + null // #todo + ); } fun *.checkRead (@target self: LSLSecurityManager, file: String, context: Object): void { - _do_checkPermission(null); // #todo + _do_checkPermission( + null // #todo + ); } @@ -332,25 +374,33 @@ automaton SecurityManagerAutomaton if (action CALL_METHOD(_target, "isEmpty", [])) _throwIAE(); - _do_checkPermission(null); // #todo + _do_checkPermission( + null // #todo + ); } fun *.checkSetFactory (@target self: LSLSecurityManager): void { - _do_checkPermission(null); // #todo + _do_checkPermission( + null // #todo + ); } fun *.checkWrite (@target self: LSLSecurityManager, fd: FileDescriptor): void { - _do_checkPermission(null); // #todo + _do_checkPermission( + null // #todo + ); } fun *.checkWrite (@target self: LSLSecurityManager, file: String): void { - _do_checkPermission(null); // #todo + _do_checkPermission( + null // #todo + ); } From 07ae9a87fe59c732cc064ef666284f92a4478b42 Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Fri, 29 Sep 2023 16:34:32 +0300 Subject: [PATCH 11/78] Import cleanup --- spec/java/lang/AutoCloseable.lsl | 2 +- spec/java/lang/Integer.lsl | 1 - spec/java/lang/Object.main.lsl | 1 - spec/java/lang/SecurityManager.lsl | 2 +- spec/java/lang/SecurityManager.main.lsl | 1 - spec/java/lang/Thread.lsl | 2 +- spec/java/lang/ThreadGroup.lsl | 2 +- spec/java/lang/Throwable.lsl | 1 - spec/java/net/InetAddress.lsl | 2 +- spec/java/security/_interfaces.lsl | 1 - 10 files changed, 5 insertions(+), 10 deletions(-) diff --git a/spec/java/lang/AutoCloseable.lsl b/spec/java/lang/AutoCloseable.lsl index 3fcacb67..6910b694 100644 --- a/spec/java/lang/AutoCloseable.lsl +++ b/spec/java/lang/AutoCloseable.lsl @@ -7,7 +7,7 @@ library std // imports -import java.common; +import java/lang/_interfaces; // local semantic types diff --git a/spec/java/lang/Integer.lsl b/spec/java/lang/Integer.lsl index 00e67af0..236c873a 100644 --- a/spec/java/lang/Integer.lsl +++ b/spec/java/lang/Integer.lsl @@ -7,7 +7,6 @@ library std // imports -import java.common; import java/lang/_interfaces; diff --git a/spec/java/lang/Object.main.lsl b/spec/java/lang/Object.main.lsl index dae7e70b..ad184da1 100644 --- a/spec/java/lang/Object.main.lsl +++ b/spec/java/lang/Object.main.lsl @@ -7,7 +7,6 @@ library std // imports -import java.common; import java/lang/Object; diff --git a/spec/java/lang/SecurityManager.lsl b/spec/java/lang/SecurityManager.lsl index 92ee1060..11940eab 100644 --- a/spec/java/lang/SecurityManager.lsl +++ b/spec/java/lang/SecurityManager.lsl @@ -8,7 +8,7 @@ library std // imports -import java.common; +import java/lang/_interfaces; // primary semantic types diff --git a/spec/java/lang/SecurityManager.main.lsl b/spec/java/lang/SecurityManager.main.lsl index 8fa5b357..ce33647d 100644 --- a/spec/java/lang/SecurityManager.main.lsl +++ b/spec/java/lang/SecurityManager.main.lsl @@ -7,7 +7,6 @@ library std // imports -import java.common; import java/io/FileDescriptor; import java/lang/Thread; import java/lang/ThreadGroup; diff --git a/spec/java/lang/Thread.lsl b/spec/java/lang/Thread.lsl index ae7b356e..17985e44 100644 --- a/spec/java/lang/Thread.lsl +++ b/spec/java/lang/Thread.lsl @@ -8,7 +8,7 @@ library std // imports -import java.common; +import java/lang/_interfaces; // primary semantic types diff --git a/spec/java/lang/ThreadGroup.lsl b/spec/java/lang/ThreadGroup.lsl index f453b92a..a2172807 100644 --- a/spec/java/lang/ThreadGroup.lsl +++ b/spec/java/lang/ThreadGroup.lsl @@ -8,7 +8,7 @@ library std // imports -import java.common; +import java/lang/_interfaces; // primary semantic types diff --git a/spec/java/lang/Throwable.lsl b/spec/java/lang/Throwable.lsl index 275cb0a2..96f22f98 100644 --- a/spec/java/lang/Throwable.lsl +++ b/spec/java/lang/Throwable.lsl @@ -8,7 +8,6 @@ library std // imports -import java.common; import java/io/_interfaces; import java/lang/_interfaces; diff --git a/spec/java/net/InetAddress.lsl b/spec/java/net/InetAddress.lsl index dd22202e..c4b109b7 100644 --- a/spec/java/net/InetAddress.lsl +++ b/spec/java/net/InetAddress.lsl @@ -8,7 +8,7 @@ library std // imports -import java.common; +import java/lang/_interfaces; // primary semantic types diff --git a/spec/java/security/_interfaces.lsl b/spec/java/security/_interfaces.lsl index 5e3ea504..766dc834 100644 --- a/spec/java/security/_interfaces.lsl +++ b/spec/java/security/_interfaces.lsl @@ -8,7 +8,6 @@ library std // imports -import java.common; import java/lang/_interfaces; From 77b5ca990444be4fbafb8537243938f2b7f0d4f6 Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Sat, 30 Sep 2023 12:57:41 +0300 Subject: [PATCH 12/78] Added basic implementation for `ArrayList.SubList#clear` method + Removed parser test function --- .../util/ArrayList.SubList.ListIterator.lsl | 8 ---- spec/java/util/ArrayList.SubList.lsl | 45 +++++++++++++++---- 2 files changed, 36 insertions(+), 17 deletions(-) diff --git a/spec/java/util/ArrayList.SubList.ListIterator.lsl b/spec/java/util/ArrayList.SubList.ListIterator.lsl index 89aee1ae..03797543 100644 --- a/spec/java/util/ArrayList.SubList.ListIterator.lsl +++ b/spec/java/util/ArrayList.SubList.ListIterator.lsl @@ -62,14 +62,6 @@ automaton ArrayList_SubList_ListIteratorAutomaton } - proc qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq(a: boolean, b: boolean): boolean - { - result = !a || !b; - result = !a && !b; - result = !a ^ !b; - } - - // methods fun *.hasPrevious (@target self: ArrayList_SubList_ListIterator): boolean diff --git a/spec/java/util/ArrayList.SubList.lsl b/spec/java/util/ArrayList.SubList.lsl index 54e8b8b7..6e5dbede 100644 --- a/spec/java/util/ArrayList.SubList.lsl +++ b/spec/java/util/ArrayList.SubList.lsl @@ -178,8 +178,9 @@ automaton ArrayList_SubListAutomaton { action ASSUME(this.root != null); - val effectiveIndex: int = this.offset + this.length; ArrayListAutomaton(this.root)._checkForComodification(this.modCount); + + val effectiveIndex: int = this.offset + this.length; ArrayListAutomaton(this.root)._addElement(effectiveIndex, e); _updateSizeAndModCount(+1); @@ -190,8 +191,9 @@ automaton ArrayList_SubListAutomaton { action ASSUME(this.root != null); - val effectiveIndex: int = this.offset + index; ArrayListAutomaton(this.root)._checkForComodification(this.modCount); + + val effectiveIndex: int = this.offset + index; ArrayListAutomaton(this.root)._addElement(effectiveIndex, element); _updateSizeAndModCount(+1); @@ -213,7 +215,34 @@ automaton ArrayList_SubListAutomaton // within java.util.AbstractList fun *.clear (@target self: ArrayList_SubList): void { - action TODO(); + action ASSUME(this.root != null); + ArrayListAutomaton(this.root)._checkForComodification(this.modCount); + + val size: int = this.length; + if (size != 0) + { + action ASSUME(size > 0); + val end: int = this.offset - 1; + val start: int = end + size; + + val rootStorage: list = ArrayListAutomaton(this.root).storage; + + var i: int = 0; + action LOOP_FOR( + i, start, end, -1, + clear_loop(i, rootStorage) + ); + + ArrayListAutomaton(this.root).length -= size; + ArrayListAutomaton(this.root).modCount += 1; + + _updateSizeAndModCount(-size); + } + } + + @Phantom proc clear_loop (i: int, rootStorage: list): void + { + action LIST_REMOVE(rootStorage, i); } @@ -343,10 +372,10 @@ automaton ArrayList_SubListAutomaton { action ASSUME(this.root != null); - val effectiveIndex: int = this.offset + index; ArrayListAutomaton(this.root)._checkValidIndex(index, this.length); ArrayListAutomaton(this.root)._checkForComodification(this.modCount); + val effectiveIndex: int = this.offset + index; result = action LIST_GET(ArrayListAutomaton(this.root).storage, effectiveIndex); } @@ -453,8 +482,6 @@ automaton ArrayList_SubListAutomaton fun *.listIterator (@target self: ArrayList_SubList, index: int): ListIterator { - action TODO(); - result = new ArrayList_SubList_ListIteratorAutomaton(state = Initialized, root = this.root, sublist = self, @@ -498,10 +525,10 @@ automaton ArrayList_SubListAutomaton { action ASSUME(this.root != null); - val effectiveIndex: int = this.offset + index; - ArrayListAutomaton(this.root)._checkValidIndex(index, this.length); ArrayListAutomaton(this.root)._checkForComodification(this.modCount); + + val effectiveIndex: int = this.offset + index; result = ArrayListAutomaton(this.root)._deleteElement(effectiveIndex); _updateSizeAndModCount(-1); @@ -541,11 +568,11 @@ automaton ArrayList_SubListAutomaton { action ASSUME(this.root != null); - val effectiveIndex: int = this.offset + index; ArrayListAutomaton(this.root)._checkValidIndex(index, this.length); ArrayListAutomaton(this.root)._checkForComodification(this.modCount); val parentStorage: list = ArrayListAutomaton(this.root).storage; + val effectiveIndex: int = this.offset + index; result = action LIST_GET(parentStorage, effectiveIndex); action LIST_SET(parentStorage, effectiveIndex, element); } From 9bb4c13297aa7986733043ebdba905300bc8685a Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Sun, 1 Oct 2023 02:48:09 +0300 Subject: [PATCH 13/78] Added implementation to `removeAll` and `replaceAll` methods in `ArrayList.SubList` + Minor simplification via inlining --- spec/java/util/ArrayList.SubList.lsl | 133 ++++++++++++++++++++++----- 1 file changed, 111 insertions(+), 22 deletions(-) diff --git a/spec/java/util/ArrayList.SubList.lsl b/spec/java/util/ArrayList.SubList.lsl index 6e5dbede..aa6cecf3 100644 --- a/spec/java/util/ArrayList.SubList.lsl +++ b/spec/java/util/ArrayList.SubList.lsl @@ -81,6 +81,12 @@ automaton ArrayList_SubListAutomaton } + @AutoInline @Phantom proc _checkForComodification(): void + { + ArrayListAutomaton(this.root)._checkForComodification(this.modCount); + } + + proc _addAllElements (index: int, c: Collection): boolean { action ASSUME(this.root != null); @@ -97,7 +103,7 @@ automaton ArrayList_SubListAutomaton { result = true; - ArrayListAutomaton(this.root)._checkForComodification(this.modCount); + _checkForComodification(); ArrayListAutomaton(this.root)._addAllElements(effectiveIndex, c); _updateSizeAndModCount(collectionSize); } @@ -133,7 +139,7 @@ automaton ArrayList_SubListAutomaton { action ASSUME(this.root != null); - ArrayListAutomaton(this.root)._checkForComodification(this.modCount); + _checkForComodification(); val parentStorage: list = ArrayListAutomaton(this.root).storage; val index: int = action LIST_FIND(parentStorage, o, this.offset, this.offset + this.length); @@ -178,7 +184,7 @@ automaton ArrayList_SubListAutomaton { action ASSUME(this.root != null); - ArrayListAutomaton(this.root)._checkForComodification(this.modCount); + _checkForComodification(); val effectiveIndex: int = this.offset + this.length; ArrayListAutomaton(this.root)._addElement(effectiveIndex, e); @@ -191,7 +197,7 @@ automaton ArrayList_SubListAutomaton { action ASSUME(this.root != null); - ArrayListAutomaton(this.root)._checkForComodification(this.modCount); + _checkForComodification(); val effectiveIndex: int = this.offset + index; ArrayListAutomaton(this.root)._addElement(effectiveIndex, element); @@ -216,7 +222,7 @@ automaton ArrayList_SubListAutomaton fun *.clear (@target self: ArrayList_SubList): void { action ASSUME(this.root != null); - ArrayListAutomaton(this.root)._checkForComodification(this.modCount); + _checkForComodification(); val size: int = this.length; if (size != 0) @@ -329,7 +335,7 @@ automaton ArrayList_SubListAutomaton if (result) { result = ArrayListAutomaton(this.root)._equalsRange(o as List, this.offset, this.offset + this.length); - ArrayListAutomaton(this.root)._checkForComodification(this.modCount); + _checkForComodification(); } } } @@ -373,7 +379,7 @@ automaton ArrayList_SubListAutomaton action ASSUME(this.root != null); ArrayListAutomaton(this.root)._checkValidIndex(index, this.length); - ArrayListAutomaton(this.root)._checkForComodification(this.modCount); + _checkForComodification(); val effectiveIndex: int = this.offset + index; result = action LIST_GET(ArrayListAutomaton(this.root).storage, effectiveIndex); @@ -396,7 +402,7 @@ automaton ArrayList_SubListAutomaton hashCode_loop(i, rootStorage, result) ); - ArrayListAutomaton(this.root)._checkForComodification(this.modCount); + _checkForComodification(); } } @@ -436,7 +442,7 @@ automaton ArrayList_SubListAutomaton fun *.lastIndexOf (@target self: ArrayList_SubList, o: Object): int { action ASSUME(this.root != null); - ArrayListAutomaton(this.root)._checkForComodification(this.modCount); + _checkForComodification(); if (this.length == 0) { @@ -513,7 +519,7 @@ automaton ArrayList_SubListAutomaton if (result) { - ArrayListAutomaton(this.root)._checkForComodification(this.modCount); + _checkForComodification(); ArrayListAutomaton(this.root)._deleteElement(index); _updateSizeAndModCount(-1); @@ -526,7 +532,7 @@ automaton ArrayList_SubListAutomaton action ASSUME(this.root != null); ArrayListAutomaton(this.root)._checkValidIndex(index, this.length); - ArrayListAutomaton(this.root)._checkForComodification(this.modCount); + _checkForComodification(); val effectiveIndex: int = this.offset + index; result = ArrayListAutomaton(this.root)._deleteElement(effectiveIndex); @@ -537,24 +543,107 @@ automaton ArrayList_SubListAutomaton fun *.removeAll (@target self: ArrayList_SubList, c: Collection): boolean { - result = true; - - if (this.length != 0) + val size: int = this.length; + if (size != 0) { + action ASSUME(size > 0); + action ASSUME(this.root != null); + + val rootStorage: list = ArrayListAutomaton(this.root).storage; action TODO(); + + result = this.length != size; + } + else + { + result = false; } } fun *.removeIf (@target self: ArrayList_SubList, filter: Predicate): boolean { - action TODO(); + action ASSUME(this.root != null); + _checkForComodification(); + + if (filter == null) + _throwNPE(); + + val size: int = this.length; + if (size != 0) + { + action ASSUME(size > 0); + + val expectedModCount: int = this.modCount; + val rootStorage: list = ArrayListAutomaton(this.root).storage; + + val end: int = this.offset - 1; + val start: int = end + size; + var delta: int = 0; + + var i: int = 0; + action LOOP_FOR( + i, start, end, -1, + removeIf_loop(i, rootStorage, filter, delta) + ); + + ArrayListAutomaton(this.root)._checkForComodification(expectedModCount); + + ArrayListAutomaton(this.root).length += delta; + ArrayListAutomaton(this.root).modCount += 1; + _updateSizeAndModCount(delta); + + result = delta != 0; + } + else + { + result = false; + } + } + + @Phantom proc removeIf_loop (i: int, rootStorage: list, filter: Predicate, delta: int): void + { + val item: Object = action LIST_GET(rootStorage, i); + if (action CALL(filter, [item])) + { + action LIST_REMOVE(rootStorage, i); + delta -= 1; + } } fun *.replaceAll (@target self: ArrayList_SubList, operator: UnaryOperator): void { - action TODO(); + action ASSUME(this.root != null); + _checkForComodification(); + + if (operator == null) + _throwNPE(); + + val size: int = this.length; + if (size != 0) + { + action ASSUME(size > 0); + + val expectedModCount: int = this.modCount; + val rootStorage: list = ArrayListAutomaton(this.root).storage; + + val end: int = this.offset + size; + var i: int = 0; + action LOOP_FOR( + i, this.offset, end, +1, + replaceAll_loop(i, rootStorage, operator) + ); + + ArrayListAutomaton(this.root)._checkForComodification(expectedModCount); + } + } + + @Phantom proc replaceAll_loop (i: int, rootStorage: list, operator: UnaryOperator): void + { + var item: Object = action LIST_GET(rootStorage, i); + item = action CALL(operator, [item]); + action LIST_SET(rootStorage, i, item); } @@ -569,7 +658,7 @@ automaton ArrayList_SubListAutomaton action ASSUME(this.root != null); ArrayListAutomaton(this.root)._checkValidIndex(index, this.length); - ArrayListAutomaton(this.root)._checkForComodification(this.modCount); + _checkForComodification(); val parentStorage: list = ArrayListAutomaton(this.root).storage; val effectiveIndex: int = this.offset + index; @@ -582,7 +671,7 @@ automaton ArrayList_SubListAutomaton { action ASSUME(this.root != null); - ArrayListAutomaton(this.root)._checkForComodification(this.modCount); + _checkForComodification(); result = this.length; } @@ -596,7 +685,7 @@ automaton ArrayList_SubListAutomaton action ASSUME(this.length > 0); action ASSUME(this.root != null); - ArrayListAutomaton(this.root)._checkForComodification(this.modCount); + _checkForComodification(); val rootStorage: list = ArrayListAutomaton(this.root).storage; // prepare common variables @@ -714,7 +803,7 @@ automaton ArrayList_SubListAutomaton fun *.toArray (@target self: ArrayList_SubList): array { action ASSUME(this.root != null); - ArrayListAutomaton(this.root)._checkForComodification(this.modCount); + _checkForComodification(); result = action ARRAY_NEW("java.lang.Object", this.length); @@ -743,7 +832,7 @@ automaton ArrayList_SubListAutomaton val aSize: int = action ARRAY_SIZE(a); action ASSUME(this.root != null); - ArrayListAutomaton(this.root)._checkForComodification(this.modCount); + _checkForComodification(); result = action ARRAY_NEW("java.lang.Object", this.length); @@ -761,7 +850,7 @@ automaton ArrayList_SubListAutomaton fun *.toArray (@target self: ArrayList_SubList, a: array): array { action ASSUME(this.root != null); - ArrayListAutomaton(this.root)._checkForComodification(this.modCount); + _checkForComodification(); val aSize: int = action ARRAY_SIZE(a); if (aSize < this.length) From 0ae960dd27b0278e907c686f61f4b23fc92f03d0 Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Mon, 2 Oct 2023 13:40:37 +0300 Subject: [PATCH 14/78] Added implementation for `ArrayList.SubList#removeAll` + Minor improvements to `ArrayList#removeAll` --- spec/java/util/ArrayList.SubList.lsl | 38 ++++++++++++++++++++++--- spec/java/util/ArrayList.main.lsl | 42 ++++++++++++++++------------ 2 files changed, 58 insertions(+), 22 deletions(-) diff --git a/spec/java/util/ArrayList.SubList.lsl b/spec/java/util/ArrayList.SubList.lsl index aa6cecf3..414b73d0 100644 --- a/spec/java/util/ArrayList.SubList.lsl +++ b/spec/java/util/ArrayList.SubList.lsl @@ -347,6 +347,7 @@ automaton ArrayList_SubListAutomaton { if (this.length != 0) { + action ASSUME(this.length > 0); action ASSUME(this.root != null); val rootStorage: list = ArrayListAutomaton(this.root).storage; @@ -392,6 +393,7 @@ automaton ArrayList_SubListAutomaton if (this.length != 0) { + action ASSUME(this.length > 0); action ASSUME(this.root != null); val rootStorage: list = ArrayListAutomaton(this.root).storage; @@ -543,16 +545,29 @@ automaton ArrayList_SubListAutomaton fun *.removeAll (@target self: ArrayList_SubList, c: Collection): boolean { + action ASSUME(this.root != null); + _checkForComodification(); + val size: int = this.length; if (size != 0) { action ASSUME(size > 0); - action ASSUME(this.root != null); + + // #todo: add optimized version based on automata checks val rootStorage: list = ArrayListAutomaton(this.root).storage; - action TODO(); + var end: int = this.offset + size; + var delta: int = 0; + + val iter: Iterator = action CALL_METHOD(c, "iterator", []); + action LOOP_WHILE( + action CALL_METHOD(iter, "hasNext", []), + removeAll_loop(iter, rootStorage, end, delta) + ); - result = this.length != size; + result = delta != 0; + if (result) + _updateSizeAndModCount(delta); } else { @@ -560,6 +575,20 @@ automaton ArrayList_SubListAutomaton } } + @Phantom proc removeAll_loop (iter: Iterator, rootStorage: list, end: int, delta: int): void + { + val item: Object = action CALL_METHOD(iter, "next", []); + val idx: int = action LIST_FIND(rootStorage, item, this.offset, end); + if (idx != -1) + { + action LIST_REMOVE(rootStorage, idx); + end -= 1; + delta -= 1; + + ArrayListAutomaton(this.rootStorage).length -= 1; + } + } + fun *.removeIf (@target self: ArrayList_SubList, filter: Predicate): boolean { @@ -591,9 +620,10 @@ automaton ArrayList_SubListAutomaton ArrayListAutomaton(this.root).length += delta; ArrayListAutomaton(this.root).modCount += 1; - _updateSizeAndModCount(delta); result = delta != 0; + if (result) + _updateSizeAndModCount(delta); } else { diff --git a/spec/java/util/ArrayList.main.lsl b/spec/java/util/ArrayList.main.lsl index 9f8fb067..a3a655ad 100644 --- a/spec/java/util/ArrayList.main.lsl +++ b/spec/java/util/ArrayList.main.lsl @@ -675,31 +675,37 @@ automaton ArrayListAutomaton fun *.removeAll (@target self: ArrayList, c: Collection): boolean { val oldLength: int = this.length; - - if (c has ArrayListAutomaton) + if (oldLength != 0) { - val otherStorage: list = ArrayListAutomaton(c).storage; - val otherLength: int = ArrayListAutomaton(c).length; + if (c has ArrayListAutomaton) + { + val otherStorage: list = ArrayListAutomaton(c).storage; + val otherLength: int = ArrayListAutomaton(c).length; - action ASSUME(otherStorage != null); - action ASSUME(otherLength >= 0); + action ASSUME(otherStorage != null); + action ASSUME(otherLength >= 0); - var i: int = 0; - action LOOP_FOR( - i, 0, otherLength, +1, - removeAll_loop_optimized(i, otherStorage) - ); + var i: int = 0; + action LOOP_FOR( + i, 0, otherLength, +1, + removeAll_loop_optimized(i, otherStorage) + ); + } + else + { + val iter: Iterator = action CALL_METHOD(c, "iterator", []); + action LOOP_WHILE( + action CALL_METHOD(iter, "hasNext", []), + removeAll_loop_regular(iter) + ); + } + + result = oldLength != this.length; } else { - val iter: Iterator = action CALL_METHOD(c, "iterator", []); - action LOOP_WHILE( - action CALL_METHOD(iter, "hasNext", []), - removeAll_loop_regular(iter) - ); + result = false; } - - result = oldLength != this.length; } @Phantom proc removeAll_loop_optimized (i: int, otherStorage: list): void From 0d8d072521af4314f54b1497132f3ca70f31a3ac Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Sat, 7 Oct 2023 14:49:45 +0300 Subject: [PATCH 15/78] Improvements to element-removal-focused methods in `ArrayList` and its `SubList` --- spec/java/util/ArrayList.SubList.lsl | 158 +++++++-------------------- spec/java/util/ArrayList.main.lsl | 156 +++++++++++--------------- 2 files changed, 107 insertions(+), 207 deletions(-) diff --git a/spec/java/util/ArrayList.SubList.lsl b/spec/java/util/ArrayList.SubList.lsl index 414b73d0..905b6b63 100644 --- a/spec/java/util/ArrayList.SubList.lsl +++ b/spec/java/util/ArrayList.SubList.lsl @@ -159,6 +159,29 @@ automaton ArrayList_SubListAutomaton } + proc _batchRemove (c: Collection, complement: boolean): boolean + { + action ASSUME(this.root != null); + _checkForComodification(); + + if (this.length != 0) + { + val oldRootLength: int = ArrayListAutomaton(this.root).length; + + result = ArrayListAutomaton(this.root)._batchRemove(c, complement, this.offset, this.offset + this.length); + if (result) + { + val newRootLength: int = ArrayListAutomaton(this.root).length; + _updateSizeAndModCount(newRootLength - oldRootLength); + } + } + else + { + result = false; + } + } + + // constructors constructor *.SubList (@target self: ArrayList_SubList, root: ArrayList, fromIndex: int, toIndex: int) @@ -545,48 +568,7 @@ automaton ArrayList_SubListAutomaton fun *.removeAll (@target self: ArrayList_SubList, c: Collection): boolean { - action ASSUME(this.root != null); - _checkForComodification(); - - val size: int = this.length; - if (size != 0) - { - action ASSUME(size > 0); - - // #todo: add optimized version based on automata checks - - val rootStorage: list = ArrayListAutomaton(this.root).storage; - var end: int = this.offset + size; - var delta: int = 0; - - val iter: Iterator = action CALL_METHOD(c, "iterator", []); - action LOOP_WHILE( - action CALL_METHOD(iter, "hasNext", []), - removeAll_loop(iter, rootStorage, end, delta) - ); - - result = delta != 0; - if (result) - _updateSizeAndModCount(delta); - } - else - { - result = false; - } - } - - @Phantom proc removeAll_loop (iter: Iterator, rootStorage: list, end: int, delta: int): void - { - val item: Object = action CALL_METHOD(iter, "next", []); - val idx: int = action LIST_FIND(rootStorage, item, this.offset, end); - if (idx != -1) - { - action LIST_REMOVE(rootStorage, idx); - end -= 1; - delta -= 1; - - ArrayListAutomaton(this.rootStorage).length -= 1; - } + _batchRemove(c, false); } @@ -595,35 +577,17 @@ automaton ArrayList_SubListAutomaton action ASSUME(this.root != null); _checkForComodification(); - if (filter == null) - _throwNPE(); - val size: int = this.length; if (size != 0) { - action ASSUME(size > 0); + val oldRootLength: int = ArrayListAutomaton(this.root).length; - val expectedModCount: int = this.modCount; - val rootStorage: list = ArrayListAutomaton(this.root).storage; - - val end: int = this.offset - 1; - val start: int = end + size; - var delta: int = 0; - - var i: int = 0; - action LOOP_FOR( - i, start, end, -1, - removeIf_loop(i, rootStorage, filter, delta) - ); - - ArrayListAutomaton(this.root)._checkForComodification(expectedModCount); - - ArrayListAutomaton(this.root).length += delta; - ArrayListAutomaton(this.root).modCount += 1; - - result = delta != 0; + result = ArrayListAutomaton(this.root)._removeIf(filter, this.offset, this.offset + this.length); if (result) - _updateSizeAndModCount(delta); + { + val newRootLength: int = ArrayListAutomaton(this.root).length; + _updateSizeAndModCount(newRootLength - oldRootLength); + } } else { @@ -631,55 +595,17 @@ automaton ArrayList_SubListAutomaton } } - @Phantom proc removeIf_loop (i: int, rootStorage: list, filter: Predicate, delta: int): void - { - val item: Object = action LIST_GET(rootStorage, i); - if (action CALL(filter, [item])) - { - action LIST_REMOVE(rootStorage, i); - delta -= 1; - } - } - fun *.replaceAll (@target self: ArrayList_SubList, operator: UnaryOperator): void { action ASSUME(this.root != null); - _checkForComodification(); - - if (operator == null) - _throwNPE(); - - val size: int = this.length; - if (size != 0) - { - action ASSUME(size > 0); - - val expectedModCount: int = this.modCount; - val rootStorage: list = ArrayListAutomaton(this.root).storage; - - val end: int = this.offset + size; - var i: int = 0; - action LOOP_FOR( - i, this.offset, end, +1, - replaceAll_loop(i, rootStorage, operator) - ); - - ArrayListAutomaton(this.root)._checkForComodification(expectedModCount); - } - } - - @Phantom proc replaceAll_loop (i: int, rootStorage: list, operator: UnaryOperator): void - { - var item: Object = action LIST_GET(rootStorage, i); - item = action CALL(operator, [item]); - action LIST_SET(rootStorage, i, item); + ArrayListAutomaton(this.root)._replaceAllRange(operator, this.offset, this.offset + this.length); } fun *.retainAll (@target self: ArrayList_SubList, c: Collection): boolean { - action TODO(); + _batchRemove(c, true); } @@ -709,19 +635,19 @@ automaton ArrayList_SubListAutomaton // within java.util.List fun *.sort (@target self: ArrayList_SubList, c: Comparator): void { - if (this.length != 0) + val size: int = this.length; + if (size != 0) { // Java has no unsigned primitive data types - action ASSUME(this.length > 0); + action ASSUME(size > 0); action ASSUME(this.root != null); _checkForComodification(); val rootStorage: list = ArrayListAutomaton(this.root).storage; // prepare common variables - val baseLimit: int = this.offset + this.length; + val baseLimit: int = this.offset + size; val outerLimit: int = baseLimit - 1; - var innerLimit: int = 0; var i: int = 0; var j: int = 0; @@ -733,7 +659,7 @@ automaton ArrayList_SubListAutomaton // plain bubble sorting algorithm action LOOP_FOR( i, this.offset, outerLimit, +1, - sort_loop_outer_noComparator(i, j, baseLimit, innerLimit, rootStorage) + sort_loop_outer_noComparator(i, j, baseLimit, rootStorage) ); } else @@ -743,7 +669,7 @@ automaton ArrayList_SubListAutomaton // plain bubble sorting algorithm (with a comparator) action LOOP_FOR( i, this.offset, outerLimit, +1, - sort_loop_outer(i, j, baseLimit, innerLimit, rootStorage, c) + sort_loop_outer(i, j, baseLimit, rootStorage, c) ); } @@ -751,9 +677,9 @@ automaton ArrayList_SubListAutomaton } } - @Phantom proc sort_loop_outer_noComparator (i: int, j: int, baseLimit: int, innerLimit: int, rootStorage: list): void + @Phantom proc sort_loop_outer_noComparator (i: int, j: int, baseLimit: int, rootStorage: list): void { - innerLimit = baseLimit - i - 1; + val innerLimit: int = baseLimit - i - 1; action LOOP_FOR( j, this.offset, innerLimit, +1, sort_loop_inner_noComparator(j, rootStorage) @@ -774,9 +700,9 @@ automaton ArrayList_SubListAutomaton } } - @Phantom proc sort_loop_outer (i: int, j: int, baseLimit: int, innerLimit: int, rootStorage: list, c: Comparator): void + @Phantom proc sort_loop_outer (i: int, j: int, baseLimit: int, rootStorage: list, c: Comparator): void { - innerLimit = baseLimit - i - 1; + val innerLimit: int = baseLimit - i - 1; action LOOP_FOR( j, this.offset, innerLimit, +1, sort_loop_inner(j, rootStorage, c) diff --git a/spec/java/util/ArrayList.main.lsl b/spec/java/util/ArrayList.main.lsl index a3a655ad..fea4e280 100644 --- a/spec/java/util/ArrayList.main.lsl +++ b/spec/java/util/ArrayList.main.lsl @@ -226,7 +226,7 @@ automaton ArrayListAutomaton } - proc _replaceAllRange (i: int, end: int, op: UnaryOperator): void + @KeepVisible proc _replaceAllRange (op: UnaryOperator, i: int, end: int): void { val expectedModCount: int = this.modCount; @@ -257,6 +257,7 @@ automaton ArrayListAutomaton val expectedModCount: int = this.modCount; // remove elements from the back first + action ASSUME(start <= end); var i: int = 0; action LOOP_FOR( i, end - 1, start, -1, @@ -368,6 +369,66 @@ automaton ArrayListAutomaton } + @KeepVisible proc _batchRemove (c: Collection, complement: boolean, start: int, end: int): boolean + { + val oldLength: int = this.length; + if (oldLength == 0 || start >= end) + { + result = false; + } + else + { + val otherLength: int = action CALL_METHOD(c, "size", []); + if (otherLength == 0) + { + result = false; + } + else + { + action ASSUME(otherLength > 0); + + var i: int = 0; + start -= 1; + end -= 1; + + if (c has ArrayListAutomaton) + { + val otherStorage: list = ArrayListAutomaton(c).storage; + action ASSUME(otherStorage != null); + + action LOOP_FOR( + i, end, start, -1, + _batchRemove_loop_optimized(i, otherStorage, complement) + ); + } + else + { + action LOOP_FOR( + i, end, start, -1, + _batchRemove_loop_regular(i, c, complement) + ); + } + + result = oldLength != this.length; + } + } + } + + @Phantom proc _batchRemove_loop_optimized (i: int, otherStorage: list, complement: boolean): void + { + val item: Object = action LIST_GET(this.storage, i); + if ((action LIST_FIND(otherStorage, item, 0, this.length) == -1) == complement) + _deleteElement(i); + } + + @Phantom proc _batchRemove_loop_regular (i: int, c: Collection, complement: boolean): void + { + val item: Object = action LIST_GET(this.storage, i); + if (action CALL_METHOD(c, "contains", [item]) != complement) + _deleteElement(i); + } + + // constructors constructor *.ArrayList (@target self: ArrayList) @@ -674,54 +735,7 @@ automaton ArrayListAutomaton fun *.removeAll (@target self: ArrayList, c: Collection): boolean { - val oldLength: int = this.length; - if (oldLength != 0) - { - if (c has ArrayListAutomaton) - { - val otherStorage: list = ArrayListAutomaton(c).storage; - val otherLength: int = ArrayListAutomaton(c).length; - - action ASSUME(otherStorage != null); - action ASSUME(otherLength >= 0); - - var i: int = 0; - action LOOP_FOR( - i, 0, otherLength, +1, - removeAll_loop_optimized(i, otherStorage) - ); - } - else - { - val iter: Iterator = action CALL_METHOD(c, "iterator", []); - action LOOP_WHILE( - action CALL_METHOD(iter, "hasNext", []), - removeAll_loop_regular(iter) - ); - } - - result = oldLength != this.length; - } - else - { - result = false; - } - } - - @Phantom proc removeAll_loop_optimized (i: int, otherStorage: list): void - { - val o: Object = action LIST_GET(otherStorage, i); - val index: int = action LIST_FIND(this.storage, o, 0, this.length); - if (index != -1) - _deleteElement(index); - } - - @Phantom proc removeAll_loop_regular (iter: Iterator): void - { - val o: Object = action CALL_METHOD(iter, "next", []); - val index: int = action LIST_FIND(this.storage, o, 0, this.length); - if (index != -1) - _deleteElement(index); + result = _batchRemove(c, false, 0, this.length); } @@ -736,54 +750,14 @@ automaton ArrayListAutomaton if (op == null) _throwNPE(); - _replaceAllRange(0, this.length, op); + _replaceAllRange(op, 0, this.length); this.modCount += 1; } fun *.retainAll (@target self: ArrayList, c: Collection): boolean { - val oldLength: int = this.length; - var i: int = 0; - - if (c has ArrayListAutomaton) - { - val otherStorage: list = ArrayListAutomaton(c).storage; - val otherLength: int = ArrayListAutomaton(c).length; - - action ASSUME(otherStorage != null); - action ASSUME(otherLength >= 0); - - action LOOP_FOR( - i, this.length - 1, 0, -1, - retainAll_loop_optimized(i, otherStorage, otherLength) - ); - } - else - { - action LOOP_FOR( - i, this.length - 1, 0, -1, - retainAll_loop_regular(i, c) - ); - } - - result = oldLength != this.length; - } - - @Phantom proc retainAll_loop_optimized (i: int, otherStorage: list, otherLength: int): void - { - val item: Object = action LIST_GET(this.storage, i); - val otherHasItem: boolean = action LIST_FIND(otherStorage, item, 0, otherLength) != -1; - if (!otherHasItem) - _deleteElement(i); - } - - @Phantom proc retainAll_loop_regular (i: int, c: Collection): void - { - val item: Object = action LIST_GET(this.storage, i); - val otherHasItem: boolean = action CALL_METHOD(c, "contains", [item]); - if (!otherHasItem) - _deleteElement(i); + result = _batchRemove(c, true, 0, this.length); } From 7429fdda3b615cd45754b48493d66d37ec0bdcc8 Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Sun, 8 Oct 2023 13:07:55 +0300 Subject: [PATCH 16/78] Added basic implementations for `InputStream` and `OutputStream` "null" class implementations + Added relevant type declarations --- spec/java/io/VoidInputStream.lsl | 22 +++ spec/java/io/VoidInputStream.main.lsl | 195 +++++++++++++++++++++++++ spec/java/io/VoidOutputStream.lsl | 22 +++ spec/java/io/VoidOutputStream.main.lsl | 99 +++++++++++++ spec/java/io/_interfaces.lsl | 77 +++++++++- spec/java/lang/_interfaces.lsl | 9 ++ 6 files changed, 422 insertions(+), 2 deletions(-) create mode 100644 spec/java/io/VoidInputStream.lsl create mode 100644 spec/java/io/VoidInputStream.main.lsl create mode 100644 spec/java/io/VoidOutputStream.lsl create mode 100644 spec/java/io/VoidOutputStream.main.lsl diff --git a/spec/java/io/VoidInputStream.lsl b/spec/java/io/VoidInputStream.lsl new file mode 100644 index 00000000..b99808ba --- /dev/null +++ b/spec/java/io/VoidInputStream.lsl @@ -0,0 +1,22 @@ +//#! pragma: non-synthesizable +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/io/InputStream.java#L81"; + +// imports + +import java/io/_interfaces; + + +// primary semantic types + +@GenerateMe +@extends("java.io.InputStream") +@public @final type VoidInputStream + is java.io.InputStream$1 + for InputStream +{ +} diff --git a/spec/java/io/VoidInputStream.main.lsl b/spec/java/io/VoidInputStream.main.lsl new file mode 100644 index 00000000..2085a761 --- /dev/null +++ b/spec/java/io/VoidInputStream.main.lsl @@ -0,0 +1,195 @@ +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/io/InputStream.java#L81"; + +// imports + +import java/io/VoidInputStream; + + +// automata + +automaton VoidInputStreamAutomaton +( + @volatile var closed: boolean = false, +) +: VoidInputStream +{ + // states and shifts + + initstate Initialized; + + shift Initialized -> self by [ + // instance methods + available, + close, + mark, + markSupported, + read (VoidInputStream), + read (VoidInputStream, array), + read (VoidInputStream, array, int, int), + readAllBytes, + readNBytes (VoidInputStream, array, int, int), + readNBytes (VoidInputStream, int), + reset, + skip, + transferTo, + ]; + + // internal variables + + // utilities + + @throws(["java.io.IOException"]) // NOTE: useful for enhanced auto-inlining + @AutoInline @Phantom proc _ensureOpen (): void + { + if (this.closed) + action THROW_NEW("java.io.IOException", ["Stream closed"]); + } + + + proc _checkFromIndexSize (fromIndex: int, size: int, length: int): void + { + // source: jdk.internal.util.Preconditions#checkFromIndexSize + if ((length | fromIndex | size) < 0 || size > length - fromIndex) + action THROW_NEW("java.lang.IndexOutOfBoundsException", ["Range [%s, %): int + { + if (action ARRAY_SIZE(b) == 0) + { + result = 0; + } + else + { + _ensureOpen(); + result = -1; + } + } + + + @throws(["java.io.IOException"]) + fun *.read (@target self: VoidInputStream, b: array, off: int, len: int): int + { + _checkFromIndexSize(off, len, action ARRAY_SIZE(b)); + if (len == 0) + { + result = 0; + } + else + { + _ensureOpen(); + result = -1; + } + } + + + @throws(["java.io.IOException"]) + fun *.readAllBytes (@target self: VoidInputStream): array + { + _ensureOpen(); + result = action ARRAY_NEW("byte", 0); + } + + + @throws(["java.io.IOException"]) + fun *.readNBytes (@target self: VoidInputStream, b: array, off: int, len: int): int + { + _checkFromIndexSize(off, len, action ARRAY_SIZE(b)); + _ensureOpen(); + result = 0; + } + + + @throws(["java.io.IOException"]) + fun *.readNBytes (@target self: VoidInputStream, len: int): array + { + if (len < 0) + { + action THROW_NEW("java.lang.IllegalArgumentException", ["len < 0"]); + } + else + { + _ensureOpen(); + result = action ARRAY_NEW("byte", 0); + } + } + + + @throws(["java.io.IOException"]) + // within java.io.InputStream + @synchronized fun *.reset (@target self: VoidInputStream): void + { + action THROW_NEW("java.io.IOException", ["mark/reset not supported"]); + } + + + @throws(["java.io.IOException"]) + fun *.skip (@target self: VoidInputStream, n: long): long + { + _ensureOpen(); + result = 0L; + } + + + @throws(["java.io.IOException"]) + fun *.transferTo (@target self: VoidInputStream, out: OutputStream): long + { + if (out == null) + action THROW_NEW("java.lang.NullPointerException", []); + + _ensureOpen(); + result = 0L; + } + +} diff --git a/spec/java/io/VoidOutputStream.lsl b/spec/java/io/VoidOutputStream.lsl new file mode 100644 index 00000000..7035dca0 --- /dev/null +++ b/spec/java/io/VoidOutputStream.lsl @@ -0,0 +1,22 @@ +//#! pragma: non-synthesizable +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/io/OutputStream.java#L67"; + +// imports + +import java/io/_interfaces; + + +// primary semantic types + +@GenerateMe +@extends("java.io.OutputStream") +@public @final type VoidOutputStream + is java.io.OutputStream$1 + for OutputStream +{ +} diff --git a/spec/java/io/VoidOutputStream.main.lsl b/spec/java/io/VoidOutputStream.main.lsl new file mode 100644 index 00000000..75c2c330 --- /dev/null +++ b/spec/java/io/VoidOutputStream.main.lsl @@ -0,0 +1,99 @@ +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/io/OutputStream.java#L67"; + +// imports + +import java/io/VoidOutputStream; + + +// automata + +automaton VoidOutputStreamAutomaton +( + @volatile var closed: boolean = false, +) +: VoidOutputStream +{ + // states and shifts + + initstate Initialized; + + shift Initialized -> self by [ + // instance methods + close, + flush, + write (VoidOutputStream, array), + write (VoidOutputStream, array, int, int), + write (VoidOutputStream, int), + ]; + + // internal variables + + // utilities + + @throws(["java.io.IOException"]) // NOTE: useful for enhanced auto-inlining + @AutoInline @Phantom proc _ensureOpen (): void + { + if (this.closed) + action THROW_NEW("java.io.IOException", ["Stream closed"]); + } + + + proc _checkFromIndexSize (fromIndex: int, size: int, length: int): void + { + // source: jdk.internal.util.Preconditions#checkFromIndexSize + if ((length | fromIndex | size) < 0 || size > length - fromIndex) + action THROW_NEW("java.lang.IndexOutOfBoundsException", ["Range [%s, %): void + { + if (b == null) + action THROW_NEW("java.lang.NullPointerException", []); + + _ensureOpen(); + } + + + @throws(["java.io.IOException"]) + fun *.write (@target self: VoidOutputStream, b: array, off: int, len: int): void + { + _checkFromIndexSize(off, len, action ARRAY_SIZE(b)); + _ensureOpen(); + } + + + @throws(["java.io.IOException"]) + fun *.write (@target self: VoidOutputStream, b: int): void + { + _ensureOpen(); + } + +} diff --git a/spec/java/io/_interfaces.lsl b/spec/java/io/_interfaces.lsl index d480a294..8679a049 100644 --- a/spec/java/io/_interfaces.lsl +++ b/spec/java/io/_interfaces.lsl @@ -13,16 +13,89 @@ import java/lang/_interfaces; // semantic types +@interface type Closeable + is java.io.Closeable + for AutoCloseable +{ + @throws(["java.io.IOException"]) + fun *.close(): void; +} + + +@interface type Flushable + is java.io.Flushable + for Object +{ + @throws(["java.io.IOException"]) + fun *.flush(): void; +} + + +type OutputStream + is java.io.OutputStream + for Closeable, Flushable +{ + @throws(["java.io.IOException"]) + fun *.write(b: array): void; + + @throws(["java.io.IOException"]) + fun *.write(b: array, off: int, len: int): void; + + @throws(["java.io.IOException"]) + fun *.write(b: int): void; +} + + +type InputStream + is java.io.InputStream + for Closeable +{ + @throws(["java.io.IOException"]) + fun *.available(): int; + + fun *.mark(readlimit: int): void; + + fun *.markSupported(): boolean; + + @throws(["java.io.IOException"]) + fun *.read(): int; + + @throws(["java.io.IOException"]) + fun *.read(b: array): int; + + @throws(["java.io.IOException"]) + fun *.read(b: array, off: int, len: int): int; + + @throws(["java.io.IOException"]) + fun *.readAllBytes(): array; + + @throws(["java.io.IOException"]) + fun *.readNBytes(b: array, off: int, len: int): int; + + @throws(["java.io.IOException"]) + fun *.readNBytes(len: int): array; + + @throws(["java.io.IOException"]) + fun *.reset(): void; + + @throws(["java.io.IOException"]) + fun *.skip(n: long): long; + + @throws(["java.io.IOException"]) + fun *.transferTo(out: OutputStream): long; +} + + type ObjectInputStream is java.io.ObjectInputStream - for Object + for InputStream { } type ObjectOutputStream is java.io.ObjectOutputStream - for Object + for OutputStream { } diff --git a/spec/java/lang/_interfaces.lsl b/spec/java/lang/_interfaces.lsl index b2a46a7e..2868ee00 100644 --- a/spec/java/lang/_interfaces.lsl +++ b/spec/java/lang/_interfaces.lsl @@ -176,6 +176,15 @@ val MIN_SUPPLEMENTARY_CODE_POINT: int = 65536; // general interfaces +type AutoCloseable + is java.lang.AutoCloseable + for Object +{ + @throws(["java.lang.Exception"]) + fun *.close(); +} + + type Runnable is java.lang.Runnable for Object From 4757e3e03bedb605707ab2f96542a29a1932f767 Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Mon, 9 Oct 2023 09:07:24 +0300 Subject: [PATCH 17/78] Added ignore rule for IntelliJ-Idea project files --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 2bf55c97..6649eebd 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,9 @@ *.tar.gz *.rar +# IntelliJ IDEA project settings +/.idea + # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml hs_err_pid* From 4e46c5ac11f401c2070f297893190ae91a9f0b90 Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Wed, 11 Oct 2023 05:14:43 +0300 Subject: [PATCH 18/78] Minor import adjustments + Name changes for `VoidInput(Output)Stream` --- spec/java/io/FileDescriptor.lsl | 2 +- spec/java/io/VoidInputStream.lsl | 4 ++-- spec/java/io/VoidOutputStream.lsl | 4 ++-- spec/java/lang/SecurityManager.main.lsl | 15 ++++----------- 4 files changed, 9 insertions(+), 16 deletions(-) diff --git a/spec/java/io/FileDescriptor.lsl b/spec/java/io/FileDescriptor.lsl index 99b91239..66920edb 100644 --- a/spec/java/io/FileDescriptor.lsl +++ b/spec/java/io/FileDescriptor.lsl @@ -8,7 +8,7 @@ library std // imports -import java.common; +import java/lang/Object; // primary semantic types diff --git a/spec/java/io/VoidInputStream.lsl b/spec/java/io/VoidInputStream.lsl index b99808ba..fa46ae6a 100644 --- a/spec/java/io/VoidInputStream.lsl +++ b/spec/java/io/VoidInputStream.lsl @@ -8,7 +8,7 @@ library std // imports -import java/io/_interfaces; +import java/io/InputStream; // primary semantic types @@ -16,7 +16,7 @@ import java/io/_interfaces; @GenerateMe @extends("java.io.InputStream") @public @final type VoidInputStream - is java.io.InputStream$1 + is java.io.InputStream$Void for InputStream { } diff --git a/spec/java/io/VoidOutputStream.lsl b/spec/java/io/VoidOutputStream.lsl index 7035dca0..dd52e7b6 100644 --- a/spec/java/io/VoidOutputStream.lsl +++ b/spec/java/io/VoidOutputStream.lsl @@ -8,7 +8,7 @@ library std // imports -import java/io/_interfaces; +import java/io/OutputStream; // primary semantic types @@ -16,7 +16,7 @@ import java/io/_interfaces; @GenerateMe @extends("java.io.OutputStream") @public @final type VoidOutputStream - is java.io.OutputStream$1 + is java.io.OutputStream$Void for OutputStream { } diff --git a/spec/java/lang/SecurityManager.main.lsl b/spec/java/lang/SecurityManager.main.lsl index ce33647d..21a3d70c 100644 --- a/spec/java/lang/SecurityManager.main.lsl +++ b/spec/java/lang/SecurityManager.main.lsl @@ -8,23 +8,16 @@ library std // imports import java/io/FileDescriptor; +import java/lang/Object; +import java/lang/SecurityManager; +import java/lang/String; import java/lang/Thread; import java/lang/ThreadGroup; -import java/lang/SecurityManager; import java/net/InetAddress; -import java/security/_interfaces; +import java/security/Permission; import java/security/AccessControlContext; -// local semantic types - -@public type LSLSecurityManager - is java.lang.SecurityManager - for SecurityManager -{ -} - - // automata automaton SecurityManagerAutomaton From d1adf1e1f349c6e0128a6870f749ea199a6a7e6d Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Thu, 12 Oct 2023 14:19:08 +0300 Subject: [PATCH 19/78] Added lost spec for `Integer` --- spec/java/lang/Integer.lsl | 7 + spec/java/lang/Integer.main.lsl | 423 ++++++++++++++++++++++++++++++++ 2 files changed, 430 insertions(+) create mode 100644 spec/java/lang/Integer.main.lsl diff --git a/spec/java/lang/Integer.lsl b/spec/java/lang/Integer.lsl index ebc02c09..c3c8a5c4 100644 --- a/spec/java/lang/Integer.lsl +++ b/spec/java/lang/Integer.lsl @@ -24,3 +24,10 @@ import java/lang/Number; // global aliases and type overrides +@extends("java.lang.Number") +@implements("java.lang.Comparable") +@public @final type LSLInteger + is java.lang.Integer + for Integer +{ +} diff --git a/spec/java/lang/Integer.main.lsl b/spec/java/lang/Integer.main.lsl new file mode 100644 index 00000000..036ad494 --- /dev/null +++ b/spec/java/lang/Integer.main.lsl @@ -0,0 +1,423 @@ +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/lang/Integer.java"; + +// imports + +import java/lang/CharSequence; +import java/lang/Object; +import java/lang/String; + +import java/lang/Integer; + + +// automata + +automaton IntegerAutomaton +( + @private val value: int // WARNING: do not rename! +) +: LSLInteger +{ + // states and shifts + + initstate Initialized; + + shift Initialized -> self by [ + // constructors + Integer (LSLInteger, String), + Integer (LSLInteger, int), + + // static operations + bitCount, + compare, + compareUnsigned, + decode, + divideUnsigned, + getInteger (String), + getInteger (String, Integer), + getInteger (String, int), + hashCode (int), + highestOneBit, + lowestOneBit, + max, + min, + numberOfLeadingZeros, + numberOfTrailingZeros, + parseInt (CharSequence, int, int, int), + parseInt (String), + parseInt (String, int), + parseUnsignedInt (CharSequence, int, int, int), + parseUnsignedInt (String), + parseUnsignedInt (String, int), + remainderUnsigned, + reverse, + reverseBytes, + rotateLeft, + rotateRight, + signum, + sum, + toBinaryString, + toHexString, + toOctalString, + toString (int), + toString (int, int), + toUnsignedLong, + toUnsignedString (int), + toUnsignedString (int, int), + valueOf (String), + valueOf (String, int), + valueOf (int), + + // instance methods + byteValue, + compareTo, + doubleValue, + equals, + floatValue, + hashCode (LSLInteger), + intValue, + longValue, + shortValue, + toString (LSLInteger), + ]; + + // internal variables + + // utilities + + // constructors + + @throws(["java.lang.NumberFormatException"]) + @Phantom constructor *.Integer (@target self: LSLInteger, s: String) + { + // NOTE: using the original method + } + + + @Phantom constructor *.Integer (@target self: LSLInteger, value: int) + { + // NOTE: using the original method + } + + + // static methods + + @Phantom @static fun *.bitCount (i: int): int + { + // NOTE: using the original method + } + + + @Phantom @static fun *.compare (x: int, y: int): int + { + // NOTE: using the original method + } + + + @Phantom @static fun *.compareUnsigned (x: int, y: int): int + { + // NOTE: using the original method + } + + + @throws(["java.lang.NumberFormatException"]) + @Phantom @static fun *.decode (nm: String): LSLInteger + { + // NOTE: using the original method + } + + + @Phantom @static fun *.divideUnsigned (dividend: int, divisor: int): int + { + // NOTE: using the original method + } + + + @Phantom @static fun *.getInteger (nm: String): LSLInteger + { + // NOTE: using the original method + } + + + @Phantom @static fun *.getInteger (nm: String, _val: Integer): LSLInteger + { + // NOTE: using the original method + } + + + @Phantom @static fun *.getInteger (nm: String, _val: int): LSLInteger + { + // NOTE: using the original method + } + + + @Phantom @static fun *.hashCode (value: int): int + { + // NOTE: using the original method + } + + + @Phantom @static fun *.highestOneBit (i: int): int + { + // NOTE: using the original method + } + + + @Phantom @static fun *.lowestOneBit (i: int): int + { + // NOTE: using the original method + } + + + @Phantom @static fun *.max (a: int, b: int): int + { + // NOTE: using the original method + } + + + @Phantom @static fun *.min (a: int, b: int): int + { + // NOTE: using the original method + } + + + @Phantom @static fun *.numberOfLeadingZeros (i: int): int + { + // NOTE: using the original method + } + + + @Phantom @static fun *.numberOfTrailingZeros (i: int): int + { + // NOTE: using the original method + } + + + @throws(["java.lang.NumberFormatException"]) + @Phantom @static fun *.parseInt (s: CharSequence, beginIndex: int, endIndex: int, radix: int): int + { + // NOTE: using the original method + } + + + @throws(["java.lang.NumberFormatException"]) + @Phantom @static fun *.parseInt (s: String): int + { + // NOTE: using the original method + } + + + @throws(["java.lang.NumberFormatException"]) + @Phantom @static fun *.parseInt (s: String, radix: int): int + { + // NOTE: using the original method + } + + + @throws(["java.lang.NumberFormatException"]) + @Phantom @static fun *.parseUnsignedInt (s: CharSequence, beginIndex: int, endIndex: int, radix: int): int + { + // NOTE: using the original method + } + + + @throws(["java.lang.NumberFormatException"]) + @Phantom @static fun *.parseUnsignedInt (s: String): int + { + // NOTE: using the original method + } + + + @throws(["java.lang.NumberFormatException"]) + @Phantom @static fun *.parseUnsignedInt (s: String, radix: int): int + { + // NOTE: using the original method + } + + + @Phantom @static fun *.remainderUnsigned (dividend: int, divisor: int): int + { + // NOTE: using the original method + } + + + @Phantom @static fun *.reverse (i: int): int + { + // NOTE: using the original method + } + + + @Phantom @static fun *.reverseBytes (i: int): int + { + // NOTE: using the original method + } + + + @Phantom @static fun *.rotateLeft (i: int, distance: int): int + { + // NOTE: using the original method + } + + + @Phantom @static fun *.rotateRight (i: int, distance: int): int + { + // NOTE: using the original method + } + + + @Phantom @static fun *.signum (i: int): int + { + // NOTE: using the original method + } + + + @Phantom @static fun *.sum (a: int, b: int): int + { + // NOTE: using the original method + } + + + @Phantom @static fun *.toBinaryString (i: int): String + { + // NOTE: using the original method + } + + + @Phantom @static fun *.toHexString (i: int): String + { + // NOTE: using the original method + } + + + @Phantom @static fun *.toOctalString (i: int): String + { + // NOTE: using the original method + } + + + @Phantom @static fun *.toString (i: int): String + { + // NOTE: using the original method + } + + + @Phantom @static fun *.toString (i: int, radix: int): String + { + // NOTE: using the original method + } + + + @Phantom @static fun *.toUnsignedLong (x: int): long + { + // NOTE: using the original method + } + + + @Phantom @static fun *.toUnsignedString (i: int): String + { + // NOTE: using the original method + } + + + @Phantom @static fun *.toUnsignedString (i: int, radix: int): String + { + // NOTE: using the original method + } + + + @throws(["java.lang.NumberFormatException"]) + @Phantom @static fun *.valueOf (s: String): LSLInteger + { + // NOTE: using the original method + } + + + @throws(["java.lang.NumberFormatException"]) + @Phantom @static fun *.valueOf (s: String, radix: int): LSLInteger + { + // NOTE: using the original method + } + + + @static fun *.valueOf (i: int): LSLInteger + { + result = new IntegerAutomaton(state = Initialized, + value = i + ); + } + + + // methods + + @Phantom fun *.byteValue (@target self: LSLInteger): byte + { + // NOTE: using the original method + } + + + @Phantom fun *.compareTo (@target self: LSLInteger, anotherInteger: Integer): int + { + // NOTE: using the original method + } + + + @Phantom fun *.doubleValue (@target self: LSLInteger): double + { + // NOTE: using the original method + } + + + @Phantom fun *.equals (@target self: LSLInteger, obj: Object): boolean + { + // NOTE: using the original method + } + + + @Phantom fun *.floatValue (@target self: LSLInteger): float + { + // NOTE: using the original method + } + + + @Phantom fun *.hashCode (@target self: LSLInteger): int + { + // NOTE: using the original method + } + + + @Phantom fun *.intValue (@target self: LSLInteger): int + { + // NOTE: using the original method + } + + + @Phantom fun *.longValue (@target self: LSLInteger): long + { + // NOTE: using the original method + } + + + @Phantom fun *.shortValue (@target self: LSLInteger): short + { + // NOTE: using the original method + } + + + @Phantom fun *.toString (@target self: LSLInteger): String + { + // NOTE: using the original method + } + + + // special: class initialization + + @Phantom fun *.__clinit__ (): void + { + // WARNING: this should be empty, do not change! + } + +} From 40ad85b46e738cdcc8ffb18e96d46902d570d749 Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Thu, 12 Oct 2023 17:16:25 +0300 Subject: [PATCH 20/78] Added very basic implementations for some `System` methods and standard input + More type declarations --- spec/java/io/Console.lsl | 24 ++ spec/java/lang/System.StdIn.lsl | 225 +++++++++++++++++ spec/java/lang/System.StdOut.lsl | 378 +++++++++++++++++++++++++++++ spec/java/lang/System.lsl | 73 ++++++ spec/java/lang/System.main.lsl | 284 ++++++++++++++++++++++ spec/java/nio/channels/Channel.lsl | 24 ++ spec/java/util/Hashtable.lsl | 24 ++ spec/java/util/Properties.lsl | 24 ++ spec/java/util/ResourceBundle.lsl | 24 ++ 9 files changed, 1080 insertions(+) create mode 100644 spec/java/io/Console.lsl create mode 100644 spec/java/lang/System.StdIn.lsl create mode 100644 spec/java/lang/System.StdOut.lsl create mode 100644 spec/java/lang/System.lsl create mode 100644 spec/java/lang/System.main.lsl create mode 100644 spec/java/nio/channels/Channel.lsl create mode 100644 spec/java/util/Hashtable.lsl create mode 100644 spec/java/util/Properties.lsl create mode 100644 spec/java/util/ResourceBundle.lsl diff --git a/spec/java/io/Console.lsl b/spec/java/io/Console.lsl new file mode 100644 index 00000000..b2506c46 --- /dev/null +++ b/spec/java/io/Console.lsl @@ -0,0 +1,24 @@ +//#! pragma: non-synthesizable +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/io/Console.java"; + +// imports + +import java/io/Flushable; + + +// primary semantic types + +@final type Console + is java.io.Console + for Flushable +{ +} + + +// global aliases and type overrides + diff --git a/spec/java/lang/System.StdIn.lsl b/spec/java/lang/System.StdIn.lsl new file mode 100644 index 00000000..f99e03b5 --- /dev/null +++ b/spec/java/lang/System.StdIn.lsl @@ -0,0 +1,225 @@ +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/io/InputStream.java#L81"; + +// imports + +import java/lang/System; + + +// automata + +automaton System_InputStreamAutomaton +( + val maxSize: int = 10000, +) +: System_InputStream +{ + // states and shifts + + initstate Initialized; + + shift Initialized -> self by [ + // instance methods + available, + close, + mark, + markSupported, + read (System_InputStream), + read (System_InputStream, array), + read (System_InputStream, array, int, int), + readAllBytes, + readNBytes (System_InputStream, array, int, int), + readNBytes (System_InputStream, int), + reset, + skip, + transferTo, + ]; + + // internal variables + + @volatile var dataSize: int = -1; + @volatile var data: array = null; + @volatile var closed: boolean = false; + + + // utilities + + @AutoInline @Phantom proc _initBuffer (): void + { + action ASSUME(this.maxSize > 0); + + // choose a new size + val newSize: int = action SYMBOLIC("int"); + action ASSUME(0 <= newSize); + action ASSUME(newSize < this.maxSize); + this.dataSize = newSize; + + // "allocating" memory and "filling" it up with fake data + if (newSize == 0) + this.data = action ARRAY_NEW("byte", 0); + else + this.data = action SYMBOLIC_ARRAY("byte", newSize); + } + + @AutoInline @Phantom proc _checkBuffer (): void + { + if (this.data == null) + _initBuffer(); + } + + + @throws(["java.io.IOException"]) // NOTE: useful for enhanced auto-inlining + @AutoInline @Phantom proc _ensureOpen (): void + { + if (this.closed) + action THROW_NEW("java.io.IOException", ["Stream closed"]); + + _checkBuffer(); + } + + + proc _checkFromIndexSize (fromIndex: int, size: int, length: int): void + { + if ((length | fromIndex | size) < 0 || size > length - fromIndex) + action THROW_NEW("java.lang.IndexOutOfBoundsException", ["Range [%s, %): int + { + if (action ARRAY_SIZE(b) == 0) + { + result = 0; + } + else + { + _ensureOpen(); + result = -1; + } + } + + + @throws(["java.io.IOException"]) + fun *.read (@target self: System_InputStream, b: array, off: int, len: int): int + { + _checkFromIndexSize(off, len, action ARRAY_SIZE(b)); + if (len == 0) + { + result = 0; + } + else + { + _ensureOpen(); + result = -1; + } + } + + + @throws(["java.io.IOException"]) + fun *.readAllBytes (@target self: System_InputStream): array + { + _ensureOpen(); + result = action ARRAY_NEW("byte", 0); + } + + + @throws(["java.io.IOException"]) + fun *.readNBytes (@target self: System_InputStream, b: array, off: int, len: int): int + { + _checkFromIndexSize(off, len, action ARRAY_SIZE(b)); + _ensureOpen(); + result = 0; + } + + + @throws(["java.io.IOException"]) + fun *.readNBytes (@target self: System_InputStream, len: int): array + { + if (len < 0) + { + action THROW_NEW("java.lang.IllegalArgumentException", ["len < 0"]); + } + else + { + _ensureOpen(); + result = action ARRAY_NEW("byte", 0); + } + } + + + @throws(["java.io.IOException"]) + // within java.io.InputStream + @synchronized fun *.reset (@target self: System_InputStream): void + { + action THROW_NEW("java.io.IOException", ["mark/reset not supported"]); + } + + + @throws(["java.io.IOException"]) + fun *.skip (@target self: System_InputStream, n: long): long + { + _ensureOpen(); + result = 0L; + } + + + @throws(["java.io.IOException"]) + fun *.transferTo (@target self: System_InputStream, out: OutputStream): long + { + if (out == null) + action THROW_NEW("java.lang.NullPointerException", []); + + _ensureOpen(); + result = 0L; + } + +} diff --git a/spec/java/lang/System.StdOut.lsl b/spec/java/lang/System.StdOut.lsl new file mode 100644 index 00000000..20199774 --- /dev/null +++ b/spec/java/lang/System.StdOut.lsl @@ -0,0 +1,378 @@ +//#! pragma: non-synthesizable +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/io/PrintStream.java"; + +// imports + +import java.common; +import java/io/File; +import java/io/FilterOutputStream; +import java/io/_interfaces; +import java/lang/_interfaces; +import java/nio/charset/_interfaces; +import java/util/Locale; + + +// local semantic types + +@extends("java.io.FilterOutputStream") +@implements("java.lang.Appendable") +@implements("java.io.Closeable") +@public type PrintStream + is java.io.PrintStream + for Object +{ +} + + +// automata + +automaton PrintStreamAutomaton +( +) +: PrintStream +{ + // states and shifts + + initstate Allocated; + state Initialized; + + shift Allocated -> Initialized by [ + // constructors + PrintStream (PrintStream, File), + PrintStream (PrintStream, File, Charset), + PrintStream (PrintStream, File, String), + PrintStream (PrintStream, OutputStream), + PrintStream (PrintStream, OutputStream, boolean), + PrintStream (PrintStream, OutputStream, boolean, Charset), + PrintStream (PrintStream, OutputStream, boolean, String), + PrintStream (PrintStream, String), + PrintStream (PrintStream, String, Charset), + PrintStream (PrintStream, String, String), + PrintStream (PrintStream, boolean, Charset, OutputStream), + PrintStream (PrintStream, boolean, OutputStream), + ]; + + shift Initialized -> self by [ + // instance methods + append (PrintStream, CharSequence), + append (PrintStream, CharSequence, int, int), + append (PrintStream, char), + checkError, + close, + flush, + format (PrintStream, Locale, String, array), + format (PrintStream, String, array), + print (PrintStream, Object), + print (PrintStream, String), + print (PrintStream, boolean), + print (PrintStream, char), + print (PrintStream, array), + print (PrintStream, double), + print (PrintStream, float), + print (PrintStream, int), + print (PrintStream, long), + printf (PrintStream, Locale, String, array), + printf (PrintStream, String, array), + println (PrintStream), + println (PrintStream, Object), + println (PrintStream, String), + println (PrintStream, boolean), + println (PrintStream, char), + println (PrintStream, array), + println (PrintStream, double), + println (PrintStream, float), + println (PrintStream, int), + println (PrintStream, long), + write (PrintStream, array), + write (PrintStream, array, int, int), + write (PrintStream, int), + ]; + + // internal variables + + // utilities + + // constructors + + @throws(["java.io.FileNotFoundException"]) + constructor *.PrintStream (@target self: PrintStream, file: File) + { + action TODO(); + } + + + @throws(["java.io.IOException"]) + constructor *.PrintStream (@target self: PrintStream, file: File, charset: Charset) + { + action TODO(); + } + + + @throws(["java.io.FileNotFoundException", "java.io.UnsupportedEncodingException"]) + constructor *.PrintStream (@target self: PrintStream, file: File, csn: String) + { + action TODO(); + } + + + constructor *.PrintStream (@target self: PrintStream, out: OutputStream) + { + action TODO(); + } + + + constructor *.PrintStream (@target self: PrintStream, out: OutputStream, autoFlush: boolean) + { + action TODO(); + } + + + constructor *.PrintStream (@target self: PrintStream, out: OutputStream, autoFlush: boolean, charset: Charset) + { + action TODO(); + } + + + @throws(["java.io.UnsupportedEncodingException"]) + constructor *.PrintStream (@target self: PrintStream, out: OutputStream, autoFlush: boolean, encoding: String) + { + action TODO(); + } + + + @throws(["java.io.FileNotFoundException"]) + constructor *.PrintStream (@target self: PrintStream, fileName: String) + { + action TODO(); + } + + + @throws(["java.io.IOException"]) + constructor *.PrintStream (@target self: PrintStream, fileName: String, charset: Charset) + { + action TODO(); + } + + + @throws(["java.io.FileNotFoundException", "java.io.UnsupportedEncodingException"]) + constructor *.PrintStream (@target self: PrintStream, fileName: String, csn: String) + { + action TODO(); + } + + + @private constructor *.PrintStream (@target self: PrintStream, autoFlush: boolean, charset: Charset, out: OutputStream) + { + action TODO(); + } + + + @private constructor *.PrintStream (@target self: PrintStream, autoFlush: boolean, out: OutputStream) + { + action TODO(); + } + + + // static methods + + // methods + + fun *.append (@target self: PrintStream, csq: CharSequence): PrintStream + { + action TODO(); + } + + + fun *.append (@target self: PrintStream, csq: CharSequence, start: int, end: int): PrintStream + { + action TODO(); + } + + + fun *.append (@target self: PrintStream, c: char): PrintStream + { + action TODO(); + } + + + fun *.checkError (@target self: PrintStream): boolean + { + action TODO(); + } + + + fun *.close (@target self: PrintStream): void + { + action TODO(); + } + + + fun *.flush (@target self: PrintStream): void + { + action TODO(); + } + + + @varargs fun *.format (@target self: PrintStream, l: Locale, format: String, args: array): PrintStream + { + action TODO(); + } + + + @varargs fun *.format (@target self: PrintStream, format: String, args: array): PrintStream + { + action TODO(); + } + + + fun *.print (@target self: PrintStream, obj: Object): void + { + action TODO(); + } + + + fun *.print (@target self: PrintStream, s: String): void + { + action TODO(); + } + + + fun *.print (@target self: PrintStream, b: boolean): void + { + action TODO(); + } + + + fun *.print (@target self: PrintStream, c: char): void + { + action TODO(); + } + + + fun *.print (@target self: PrintStream, s: array): void + { + action TODO(); + } + + + fun *.print (@target self: PrintStream, d: double): void + { + action TODO(); + } + + + fun *.print (@target self: PrintStream, f: float): void + { + action TODO(); + } + + + fun *.print (@target self: PrintStream, i: int): void + { + action TODO(); + } + + + fun *.print (@target self: PrintStream, l: long): void + { + action TODO(); + } + + + @varargs fun *.printf (@target self: PrintStream, l: Locale, format: String, args: array): PrintStream + { + action TODO(); + } + + + @varargs fun *.printf (@target self: PrintStream, format: String, args: array): PrintStream + { + action TODO(); + } + + + fun *.println (@target self: PrintStream): void + { + action TODO(); + } + + + fun *.println (@target self: PrintStream, x: Object): void + { + action TODO(); + } + + + fun *.println (@target self: PrintStream, x: String): void + { + action TODO(); + } + + + fun *.println (@target self: PrintStream, x: boolean): void + { + action TODO(); + } + + + fun *.println (@target self: PrintStream, x: char): void + { + action TODO(); + } + + + fun *.println (@target self: PrintStream, x: array): void + { + action TODO(); + } + + + fun *.println (@target self: PrintStream, x: double): void + { + action TODO(); + } + + + fun *.println (@target self: PrintStream, x: float): void + { + action TODO(); + } + + + fun *.println (@target self: PrintStream, x: int): void + { + action TODO(); + } + + + fun *.println (@target self: PrintStream, x: long): void + { + action TODO(); + } + + + @throws(["java.io.IOException"]) + // within java.io.OutputStream + fun *.write (@target self: PrintStream, b: array): void + { + action TODO(); + } + + + fun *.write (@target self: PrintStream, buf: array, off: int, len: int): void + { + action TODO(); + } + + + fun *.write (@target self: PrintStream, b: int): void + { + action TODO(); + } + +} diff --git a/spec/java/lang/System.lsl b/spec/java/lang/System.lsl new file mode 100644 index 00000000..05a7ff30 --- /dev/null +++ b/spec/java/lang/System.lsl @@ -0,0 +1,73 @@ +//#! pragma: non-synthesizable +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/lang/System.java"; + +// imports + +import java/io/InputStream; +import java/io/PrintStream; +import java/lang/Object; +import java/lang/String; +import java/lang/Throwable; + + +// primary semantic types + +@final type System + is java.lang.System + for Object +{ +} + + +type System_Logger_Level + is java.lang.System.Logger.Level + for Object +{ + // #problem: enum constants +} + + +@interface type System_Logger + is java.lang.System.Logger + for Object +{ + fun *.getName(): String; + + fun *.isLoggable(level: System_Logger_Level): boolean; + + fun *.log(level: System_Logger_Level, msg: String): void; + + fun *.log(level: System_Logger_Level, obj: Object): void; + + fun *.log(level: System_Logger_Level, msg: String, thrown: Throwable): void; +} + + +// global aliases and type overrides + +@final type LSLSystem + is java.lang.System + for System +{ + @public @static var in: InputStream = null; // WARNING: do not rename! + @public @static var out: PrintStream = null; // WARNING: do not rename! + @public @static var err: PrintStream = null; // WARNING: do not rename! + + @private @static val NANOTIME_BEGINNING_OF_TIME: long = 1000L; + @private @static val NANOTIME_WARP_MAX: long = 1000L; +} + +val SYSTEM_IS_WINDOWS: boolean = action SYMBOLIC("boolean"); + + +@GenerateMe +@final type System_InputStream + is java.lang.System_InputStream + for InputStream +{ +} diff --git a/spec/java/lang/System.main.lsl b/spec/java/lang/System.main.lsl new file mode 100644 index 00000000..cc8045e0 --- /dev/null +++ b/spec/java/lang/System.main.lsl @@ -0,0 +1,284 @@ +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/lang/System.java"; + +// imports + +import java/io/Console; +import java/io/InputStream; +import java/io/PrintStream; +import java/lang/Object; +import java/lang/SecurityManager; +import java/lang/String; +import java/nio/channels/Channel; +import java/util/Map; +import java/util/Properties; +import java/util/ResourceBundle; + +import java/lang/System; + + +// automata + +automaton SystemAutomaton +( +) +: LSLSystem +{ + // states and shifts + + initstate Initialized; + + shift Initialized -> self by [ + // constructors + LSLSystem, + + // static operations + arraycopy, + clearProperty, + console, + currentTimeMillis, + exit, + gc, + getLogger (String), + getLogger (String, ResourceBundle), + getProperties, + getProperty (String), + getProperty (String, String), + getSecurityManager, + getenv (), + getenv (String), + identityHashCode, + inheritedChannel, + lineSeparator, + load, + loadLibrary, + mapLibraryName, + nanoTime, + runFinalization, + setErr, + setIn, + setOut, + setProperties, + setProperty, + setSecurityManager, + ]; + + // internal variables + + // utilities + + // constructors + + @private constructor *.LSLSystem (@target self: LSLSystem) + { + // doing nothing - this is a (singleton) utility class + } + + + // static methods + + @Phantom @static fun *.arraycopy (arg0: Object, arg1: int, arg2: Object, arg3: int, arg4: int): void + { + // NOTE: using the original method + } + + + @Phantom @static fun *.clearProperty (key: String): String + { + // NOTE: using the original method + } + + + @static fun *.console (): Console + { + action TODO(); + } + + + @Phantom @static fun *.currentTimeMillis (): long + { + // #todo: use NANOTIME_WARP_MAX and NANOTIME_BEGINNING_OF_TIME + action TODO(); + } + + + @static fun *.exit (status: int): void + { + // #problem: not way to forcebly shutdown the program execution + action ERROR("Unexpected shutdown"); + } + + + @static fun *.gc (): void + { + // this have no effect during symbolic execution + } + + + @Phantom @static fun *.getLogger (name: String): System_Logger + { + // NOTE: using the original method + } + + + @Phantom @static fun *.getLogger (name: String, bundle: ResourceBundle): System_Logger + { + // NOTE: using the original method + } + + + @Phantom @static fun *.getProperties (): Properties + { + // NOTE: using the original method + } + + + @Phantom @static fun *.getProperty (key: String): String + { + // NOTE: using the original method + } + + + @Phantom @static fun *.getProperty (key: String, def: String): String + { + // NOTE: using the original method + } + + + @Phantom @static fun *.getSecurityManager (): SecurityManager + { + // NOTE: using the original method + } + + + @Phantom @static fun *.getenv (): Map + { + // NOTE: using the original method + } + + + @static fun *.getenv (name: String): String + { + result = action SYMBOLIC("java.lang.String"); + action ASSUME(result != null); + } + + + @static fun *.identityHashCode (x: Object): int + { + // #problem: there are no ways of converting a reference to a "memory address" yet + result = action SYMBOLIC("int"); + } + + + @throws(["java.io.IOException"]) + @Phantom @static fun *.inheritedChannel (): Channel + { + // NOTE: using the original method + } + + + @static fun *.lineSeparator (): String + { + if (SYSTEM_IS_WINDOWS) + result = "\r\n"; + else + result = "\n"; + } + + + @Phantom @static fun *.load (filename: String): void + { + // NOTE: using the original method + } + + + @Phantom @static fun *.loadLibrary (libname: String): void + { + // NOTE: using the original method + } + + + @Phantom @static fun *.mapLibraryName (arg0: String): String + { + // NOTE: using the original method + } + + + @Phantom @static fun *.nanoTime (): long + { + // #todo: use NANOTIME_WARP_MAX and NANOTIME_BEGINNING_OF_TIME + action TODO(); + } + + + @Phantom @static fun *.runFinalization (): void + { + // #problem: what do we need to do here? + action TODO(); + } + + + @static fun *.setErr (newErr: PrintStream): void + { + // #todo: add checks and exceptions + err = newErr; + } + + + @static fun *.setIn (newIn: InputStream): void + { + // #todo: add checks and exceptions + in = newIn; + } + + + @static fun *.setOut (newOut: PrintStream): void + { + // #todo: add checks and exceptions + out = newOut; + } + + + @Phantom @static fun *.setProperties (props: Properties): void + { + // NOTE: using the original method + } + + + @Phantom @static fun *.setProperty (key: String, value: String): String + { + // NOTE: using the original method + } + + + @Phantom @static fun *.setSecurityManager (s: SecurityManager): void + { + // NOTE: using the original method + } + + + // methods + + // special: static initialization + + @Phantom fun *.__clinit__ (): void + { + // configure the standard input stream + val newInput: InputStream = new System_InputStreamAutomaton(state = Initialized, + maxSize = 1000 + ); + in = action DEBUG_DO("new java.io.BufferedInputStream(newInput)"); + + // configure the standard output stream + action TODO(); + + // configure the standard error stream + action TODO(); + } + +} diff --git a/spec/java/nio/channels/Channel.lsl b/spec/java/nio/channels/Channel.lsl new file mode 100644 index 00000000..8606ba73 --- /dev/null +++ b/spec/java/nio/channels/Channel.lsl @@ -0,0 +1,24 @@ +//#! pragma: non-synthesizable +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/nio/channels/Channel.java"; + +// imports + +import java/io/Closeable; + + +// primary semantic types + +@interface type Channel + is java.nio.channels.Channel + for Closeable +{ +} + + +// global aliases and type overrides + diff --git a/spec/java/util/Hashtable.lsl b/spec/java/util/Hashtable.lsl new file mode 100644 index 00000000..73125b2a --- /dev/null +++ b/spec/java/util/Hashtable.lsl @@ -0,0 +1,24 @@ +//#! pragma: non-synthesizable +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/util/Hashtable.java"; + +// imports + +import java/util/Map; + + +// primary semantic types + +type Hashtable + is java.util.Hashtable + for Map // #todo: add Dictionary and other things +{ +} + + +// global aliases and type overrides + diff --git a/spec/java/util/Properties.lsl b/spec/java/util/Properties.lsl new file mode 100644 index 00000000..1582e65d --- /dev/null +++ b/spec/java/util/Properties.lsl @@ -0,0 +1,24 @@ +//#! pragma: non-synthesizable +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/util/Properties.java"; + +// imports + +import java/util/Hashtable; + + +// primary semantic types + +type Properties + is java.util.Properties + for Hashtable +{ +} + + +// global aliases and type overrides + diff --git a/spec/java/util/ResourceBundle.lsl b/spec/java/util/ResourceBundle.lsl new file mode 100644 index 00000000..2dc65a97 --- /dev/null +++ b/spec/java/util/ResourceBundle.lsl @@ -0,0 +1,24 @@ +//#! pragma: non-synthesizable +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/util/ResourceBundle.java"; + +// imports + +import java/lang/Object; + + +// primary semantic types + +@abstract type ResourceBundle + is java.util.ResourceBundle + for Object +{ +} + + +// global aliases and type overrides + From ccc487b1edd594ff0b723e619824a928707e680f Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Sat, 14 Oct 2023 14:26:30 +0300 Subject: [PATCH 21/78] Added draft implementation for a "symbolic" `InputStream` + Relocating utility "void" I/O stream implementations to a separate package --- spec/java/lang/System.lsl | 2 +- spec/runtime/utils/SymbolicInputStream.lsl | 21 ++ .../utils/SymbolicInputStream.main.lsl | 304 ++++++++++++++++++ .../io => runtime/utils}/VoidInputStream.lsl | 0 .../utils}/VoidInputStream.main.lsl | 2 +- .../io => runtime/utils}/VoidOutputStream.lsl | 0 .../utils}/VoidOutputStream.main.lsl | 2 +- 7 files changed, 328 insertions(+), 3 deletions(-) create mode 100644 spec/runtime/utils/SymbolicInputStream.lsl create mode 100644 spec/runtime/utils/SymbolicInputStream.main.lsl rename spec/{java/io => runtime/utils}/VoidInputStream.lsl (100%) rename spec/{java/io => runtime/utils}/VoidInputStream.main.lsl (99%) rename spec/{java/io => runtime/utils}/VoidOutputStream.lsl (100%) rename spec/{java/io => runtime/utils}/VoidOutputStream.main.lsl (98%) diff --git a/spec/java/lang/System.lsl b/spec/java/lang/System.lsl index 05a7ff30..e6b3b558 100644 --- a/spec/java/lang/System.lsl +++ b/spec/java/lang/System.lsl @@ -24,7 +24,7 @@ import java/lang/Throwable; } -type System_Logger_Level +@final type System_Logger_Level is java.lang.System.Logger.Level for Object { diff --git a/spec/runtime/utils/SymbolicInputStream.lsl b/spec/runtime/utils/SymbolicInputStream.lsl new file mode 100644 index 00000000..0cea4c2e --- /dev/null +++ b/spec/runtime/utils/SymbolicInputStream.lsl @@ -0,0 +1,21 @@ +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "-"; + +// imports + +import java/io/InputStream; + + +// primary semantic types + +@GenerateMe +@extends("java.io.InputStream") +@public @final type SymbolicInputStream + is runtime.utils.SymbolicInputStream + for InputStream +{ +} diff --git a/spec/runtime/utils/SymbolicInputStream.main.lsl b/spec/runtime/utils/SymbolicInputStream.main.lsl new file mode 100644 index 00000000..d3c75f1b --- /dev/null +++ b/spec/runtime/utils/SymbolicInputStream.main.lsl @@ -0,0 +1,304 @@ +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "-"; + +// imports + +import runtime/utils/SymbolicInputStream; + + +// automata + +automaton SymbolicInputStreamAutomaton +( + val maxSize: int = 10000, + val supportMarks: boolean = false, +) +: SymbolicInputStream +{ + // states and shifts + + initstate Initialized; + + shift Initialized -> self by [ + // instance methods + available, + close, + mark, + markSupported, + read (SymbolicInputStream), + read (SymbolicInputStream, array), + read (SymbolicInputStream, array, int, int), + readAllBytes, + readNBytes (SymbolicInputStream, array, int, int), + readNBytes (SymbolicInputStream, int), + reset, + skip, + transferTo, + ]; + + // internal variables + + @volatile var dataSize: int = -1; + @volatile var data: array = null; + @volatile var closed: boolean = false; + @volatile var pos: int = 0; + var markPos: int = -1; + var markLimit: int = 0; + + + // utilities + + @synchronized proc _initBuffer (): void + { + if (this.data == null) + { + action ASSUME(this.maxSize > 0); + + // choose a new size + val newSize: int = action SYMBOLIC("int"); + action ASSUME(0 <= newSize); + action ASSUME(newSize < this.maxSize); + this.dataSize = newSize; + + // "allocating" memory and "filling" it up with fake data + if (newSize == 0) + this.data = action ARRAY_NEW("byte", 0); + else + this.data = action SYMBOLIC_ARRAY("byte", newSize); + action ASSUME(this.data != null); + } + } + + @AutoInline @Phantom proc _checkBuffer (): void + { + if (this.data == null) + _initBuffer(); // this should be a call because we do not have synchronization blocks yet + } + + + @throws(["java.io.IOException"]) // NOTE: useful for enhanced auto-inlining + @AutoInline @Phantom proc _ensureOpen (): void + { + if (this.closed) + action THROW_NEW("java.io.IOException", ["Stream closed"]); + + _checkBuffer(); + } + + + proc _checkFromIndexSize (fromIndex: int, size: int, length: int): void + { + if ((length | fromIndex | size) < 0 || size > length - fromIndex) + action THROW_NEW("java.lang.IndexOutOfBoundsException", ["Range [%s, %= this.markLimit) + this.markPos = -1; + } + + + proc _moveDataTo (dest: array, offset: int, count: int): int + { + result = 0; + + val available: int = this.dataSize - this.pos; + if (available != 0) + { + action ASSUME(available > 0); + // transfer everything if there are not enougth bytes left + if (available < count) + count = available; + + action ARRAY_COPY(this.data, this.pos, dest, offset, count); + _updatePosition(count); + + result = count; + } + } + + + // constructors + + // static methods + + // methods + + @throws(["java.io.IOException"]) + fun *.available (@target self: SymbolicInputStream): int + { + _ensureOpen(); + result = this.dataSize - this.pos; + } + + + @throws(["java.io.IOException"]) + fun *.close (@target self: SymbolicInputStream): void + { + this.closed = true; + } + + + // within java.io.InputStream + fun *.mark (@target self: SymbolicInputStream, readlimit: int): void + { + if (this.supportMarks) + { + this.markPos = this.pos; + this.markLimit = readlimit; + } + } + + + // within java.io.InputStream + fun *.markSupported (@target self: SymbolicInputStream): boolean + { + result = this.supportMarks; + } + + + @throws(["java.io.IOException"]) + fun *.read (@target self: SymbolicInputStream): int + { + _ensureOpen(); + result = -1; + } + + + @throws(["java.io.IOException"]) + // within java.io.InputStream + fun *.read (@target self: SymbolicInputStream, b: array): int + { + val len: int = action ARRAY_SIZE(b); + if (len == 0) + { + result = 0; + } + else + { + _ensureOpen(); + result = _moveDataTo(b, 0, len); + } + } + + + @throws(["java.io.IOException"]) + fun *.read (@target self: SymbolicInputStream, b: array, off: int, len: int): int + { + _checkFromIndexSize(off, len, action ARRAY_SIZE(b)); + if (len == 0) + { + result = 0; + } + else + { + _ensureOpen(); + result = _moveDataTo(b, off, len); + } + } + + + @throws(["java.io.IOException"]) + fun *.readAllBytes (@target self: SymbolicInputStream): array + { + _ensureOpen(); + + if (this.pos == 0) + { + result = this.data; + _updatePosition(this.dataSize); + } + else if (this.pos == this.dataSize) + { + result = action ARRAY_NEW("byte", 0); + } + else + { + val len: int = this.dataSize - this.pos; + action ASSUME(len > 0); + + result = action ARRAY_NEW("byte", len); + _moveDataTo(result, 0, len); + } + } + + + @throws(["java.io.IOException"]) + fun *.readNBytes (@target self: SymbolicInputStream, b: array, off: int, len: int): int + { + _checkFromIndexSize(off, len, action ARRAY_SIZE(b)); + _ensureOpen(); + + if (len == 0) + result = 0; + else + result = _moveDataTo(b, off, len); + } + + + @throws(["java.io.IOException"]) + fun *.readNBytes (@target self: SymbolicInputStream, len: int): array + { + if (len < 0) + action THROW_NEW("java.lang.IllegalArgumentException", ["len < 0"]); + + _ensureOpen(); + if (len == 0) + { + result = action ARRAY_NEW("byte", 0); + } + else + { + result = action ARRAY_NEW("byte", len); + _moveDataTo(result, 0, len); + } + } + + + @throws(["java.io.IOException"]) + // within java.io.InputStream + fun *.reset (@target self: SymbolicInputStream): void + { + if (this.supportMarks) + { + _ensureOpen(); + if (this.markPos < 0) + action THROW_NEW("java.io.IOException", ["Resetting to invalid mark"]); + + this.pos = this.markPos; + } + else + { + action THROW_NEW("java.io.IOException", ["mark/reset not supported"]); + } + } + + + @throws(["java.io.IOException"]) + fun *.skip (@target self: SymbolicInputStream, n: long): long + { + _ensureOpen(); + result = 0L; + } + + + @throws(["java.io.IOException"]) + fun *.transferTo (@target self: SymbolicInputStream, out: OutputStream): long + { + if (out == null) + action THROW_NEW("java.lang.NullPointerException", []); + + _ensureOpen(); + result = 0L; + } + +} diff --git a/spec/java/io/VoidInputStream.lsl b/spec/runtime/utils/VoidInputStream.lsl similarity index 100% rename from spec/java/io/VoidInputStream.lsl rename to spec/runtime/utils/VoidInputStream.lsl diff --git a/spec/java/io/VoidInputStream.main.lsl b/spec/runtime/utils/VoidInputStream.main.lsl similarity index 99% rename from spec/java/io/VoidInputStream.main.lsl rename to spec/runtime/utils/VoidInputStream.main.lsl index 2085a761..0e7d2a42 100644 --- a/spec/java/io/VoidInputStream.main.lsl +++ b/spec/runtime/utils/VoidInputStream.main.lsl @@ -7,7 +7,7 @@ library std // imports -import java/io/VoidInputStream; +import runtime/utils/VoidInputStream; // automata diff --git a/spec/java/io/VoidOutputStream.lsl b/spec/runtime/utils/VoidOutputStream.lsl similarity index 100% rename from spec/java/io/VoidOutputStream.lsl rename to spec/runtime/utils/VoidOutputStream.lsl diff --git a/spec/java/io/VoidOutputStream.main.lsl b/spec/runtime/utils/VoidOutputStream.main.lsl similarity index 98% rename from spec/java/io/VoidOutputStream.main.lsl rename to spec/runtime/utils/VoidOutputStream.main.lsl index 75c2c330..aeb2c3fd 100644 --- a/spec/java/io/VoidOutputStream.main.lsl +++ b/spec/runtime/utils/VoidOutputStream.main.lsl @@ -7,7 +7,7 @@ library std // imports -import java/io/VoidOutputStream; +import runtime/utils/VoidOutputStream; // automata From 331b0da7ed6f0c8d4fde4c50d6d26c483648fb62 Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Sun, 15 Oct 2023 10:53:36 +0300 Subject: [PATCH 22/78] Minor improvements to `SymbolicInputStream` --- spec/runtime/utils/SymbolicInputStream.main.lsl | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/spec/runtime/utils/SymbolicInputStream.main.lsl b/spec/runtime/utils/SymbolicInputStream.main.lsl index d3c75f1b..646912a0 100644 --- a/spec/runtime/utils/SymbolicInputStream.main.lsl +++ b/spec/runtime/utils/SymbolicInputStream.main.lsl @@ -52,7 +52,8 @@ automaton SymbolicInputStreamAutomaton // utilities - @synchronized proc _initBuffer (): void + // #todo: enable synchronization when parallel execution will be added + /* @synchronized */ proc _initBuffer (): void { if (this.data == null) { @@ -69,7 +70,9 @@ automaton SymbolicInputStreamAutomaton this.data = action ARRAY_NEW("byte", 0); else this.data = action SYMBOLIC_ARRAY("byte", newSize); + action ASSUME(this.data != null); + action ASSUME(this.dataSize == action ARRAY_SIZE(this.data)); } } @@ -77,6 +80,8 @@ automaton SymbolicInputStreamAutomaton { if (this.data == null) _initBuffer(); // this should be a call because we do not have synchronization blocks yet + + action ASSUME(this.dataSize >= 0); } @@ -92,6 +97,7 @@ automaton SymbolicInputStreamAutomaton proc _checkFromIndexSize (fromIndex: int, size: int, length: int): void { + // source: jdk.internal.util.Preconditions#checkFromIndexSize if ((length | fromIndex | size) < 0 || size > length - fromIndex) action THROW_NEW("java.lang.IndexOutOfBoundsException", ["Range [%s, % 0); _ensureOpen(); result = _moveDataTo(b, 0, len); } From 21a430160377ef1b6f1d7192e8992fd1814443fd Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Tue, 17 Oct 2023 12:52:33 +0300 Subject: [PATCH 23/78] Using `SymbolicInputStream` as standard input for `System` --- spec/java/lang/System.StdIn.lsl | 225 -------------------------------- spec/java/lang/System.lsl | 7 - spec/java/lang/System.main.lsl | 7 +- 3 files changed, 5 insertions(+), 234 deletions(-) delete mode 100644 spec/java/lang/System.StdIn.lsl diff --git a/spec/java/lang/System.StdIn.lsl b/spec/java/lang/System.StdIn.lsl deleted file mode 100644 index f99e03b5..00000000 --- a/spec/java/lang/System.StdIn.lsl +++ /dev/null @@ -1,225 +0,0 @@ -libsl "1.1.0"; - -library std - version "11" - language "Java" - url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/io/InputStream.java#L81"; - -// imports - -import java/lang/System; - - -// automata - -automaton System_InputStreamAutomaton -( - val maxSize: int = 10000, -) -: System_InputStream -{ - // states and shifts - - initstate Initialized; - - shift Initialized -> self by [ - // instance methods - available, - close, - mark, - markSupported, - read (System_InputStream), - read (System_InputStream, array), - read (System_InputStream, array, int, int), - readAllBytes, - readNBytes (System_InputStream, array, int, int), - readNBytes (System_InputStream, int), - reset, - skip, - transferTo, - ]; - - // internal variables - - @volatile var dataSize: int = -1; - @volatile var data: array = null; - @volatile var closed: boolean = false; - - - // utilities - - @AutoInline @Phantom proc _initBuffer (): void - { - action ASSUME(this.maxSize > 0); - - // choose a new size - val newSize: int = action SYMBOLIC("int"); - action ASSUME(0 <= newSize); - action ASSUME(newSize < this.maxSize); - this.dataSize = newSize; - - // "allocating" memory and "filling" it up with fake data - if (newSize == 0) - this.data = action ARRAY_NEW("byte", 0); - else - this.data = action SYMBOLIC_ARRAY("byte", newSize); - } - - @AutoInline @Phantom proc _checkBuffer (): void - { - if (this.data == null) - _initBuffer(); - } - - - @throws(["java.io.IOException"]) // NOTE: useful for enhanced auto-inlining - @AutoInline @Phantom proc _ensureOpen (): void - { - if (this.closed) - action THROW_NEW("java.io.IOException", ["Stream closed"]); - - _checkBuffer(); - } - - - proc _checkFromIndexSize (fromIndex: int, size: int, length: int): void - { - if ((length | fromIndex | size) < 0 || size > length - fromIndex) - action THROW_NEW("java.lang.IndexOutOfBoundsException", ["Range [%s, %): int - { - if (action ARRAY_SIZE(b) == 0) - { - result = 0; - } - else - { - _ensureOpen(); - result = -1; - } - } - - - @throws(["java.io.IOException"]) - fun *.read (@target self: System_InputStream, b: array, off: int, len: int): int - { - _checkFromIndexSize(off, len, action ARRAY_SIZE(b)); - if (len == 0) - { - result = 0; - } - else - { - _ensureOpen(); - result = -1; - } - } - - - @throws(["java.io.IOException"]) - fun *.readAllBytes (@target self: System_InputStream): array - { - _ensureOpen(); - result = action ARRAY_NEW("byte", 0); - } - - - @throws(["java.io.IOException"]) - fun *.readNBytes (@target self: System_InputStream, b: array, off: int, len: int): int - { - _checkFromIndexSize(off, len, action ARRAY_SIZE(b)); - _ensureOpen(); - result = 0; - } - - - @throws(["java.io.IOException"]) - fun *.readNBytes (@target self: System_InputStream, len: int): array - { - if (len < 0) - { - action THROW_NEW("java.lang.IllegalArgumentException", ["len < 0"]); - } - else - { - _ensureOpen(); - result = action ARRAY_NEW("byte", 0); - } - } - - - @throws(["java.io.IOException"]) - // within java.io.InputStream - @synchronized fun *.reset (@target self: System_InputStream): void - { - action THROW_NEW("java.io.IOException", ["mark/reset not supported"]); - } - - - @throws(["java.io.IOException"]) - fun *.skip (@target self: System_InputStream, n: long): long - { - _ensureOpen(); - result = 0L; - } - - - @throws(["java.io.IOException"]) - fun *.transferTo (@target self: System_InputStream, out: OutputStream): long - { - if (out == null) - action THROW_NEW("java.lang.NullPointerException", []); - - _ensureOpen(); - result = 0L; - } - -} diff --git a/spec/java/lang/System.lsl b/spec/java/lang/System.lsl index e6b3b558..696383e2 100644 --- a/spec/java/lang/System.lsl +++ b/spec/java/lang/System.lsl @@ -64,10 +64,3 @@ import java/lang/Throwable; val SYSTEM_IS_WINDOWS: boolean = action SYMBOLIC("boolean"); - -@GenerateMe -@final type System_InputStream - is java.lang.System_InputStream - for InputStream -{ -} diff --git a/spec/java/lang/System.main.lsl b/spec/java/lang/System.main.lsl index cc8045e0..36b08d7b 100644 --- a/spec/java/lang/System.main.lsl +++ b/spec/java/lang/System.main.lsl @@ -20,6 +20,8 @@ import java/util/ResourceBundle; import java/lang/System; +import runtime/utils/SymbolicInputStream; + // automata @@ -269,8 +271,9 @@ automaton SystemAutomaton @Phantom fun *.__clinit__ (): void { // configure the standard input stream - val newInput: InputStream = new System_InputStreamAutomaton(state = Initialized, - maxSize = 1000 + val newInput: InputStream = new SymbolicInputStreamAutomaton(state = Initialized, + maxSize = 1000, + supportMarks = false, ); in = action DEBUG_DO("new java.io.BufferedInputStream(newInput)"); From 116d7365db737e3c7c68ffc2eac807e24f37dca9 Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Wed, 18 Oct 2023 07:59:39 +0300 Subject: [PATCH 24/78] Fix build for `Integer` --- spec/java/lang/Integer.lsl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/spec/java/lang/Integer.lsl b/spec/java/lang/Integer.lsl index c3c8a5c4..455c8424 100644 --- a/spec/java/lang/Integer.lsl +++ b/spec/java/lang/Integer.lsl @@ -24,8 +24,9 @@ import java/lang/Number; // global aliases and type overrides -@extends("java.lang.Number") -@implements("java.lang.Comparable") +// note: this is a partial implementation, no need for additional constraints (abstract class) and synthetic methods (Comparable) +// @extends("java.lang.Number") +// @implements("java.lang.Comparable") @public @final type LSLInteger is java.lang.Integer for Integer From fb327b20ce552f57c03bb5323ad69e4bf77b19d4 Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Sat, 21 Oct 2023 13:52:00 +0300 Subject: [PATCH 25/78] Minor improvements to `System` and `LinkedList` --- spec/java/lang/System.lsl | 10 +++++-- spec/java/lang/System.main.lsl | 31 ++++++++++++++------ spec/java/util/LinkedList.automata.lsl | 40 +++++++++++++++++++++++--- 3 files changed, 66 insertions(+), 15 deletions(-) diff --git a/spec/java/lang/System.lsl b/spec/java/lang/System.lsl index 696383e2..e502f9d4 100644 --- a/spec/java/lang/System.lsl +++ b/spec/java/lang/System.lsl @@ -8,6 +8,7 @@ library std // imports +import java/io/Console; import java/io/InputStream; import java/io/PrintStream; import java/lang/Object; @@ -54,9 +55,12 @@ import java/lang/Throwable; is java.lang.System for System { - @public @static var in: InputStream = null; // WARNING: do not rename! - @public @static var out: PrintStream = null; // WARNING: do not rename! - @public @static var err: PrintStream = null; // WARNING: do not rename! + // #todo: attach I/O streams from this + @private @static var ioConsole: Console = null; + + @public @static var in: InputStream = null; // WARNING: do not change! + @public @static var out: PrintStream = null; // WARNING: do not change! + @public @static var err: PrintStream = null; // WARNING: do not change! @private @static val NANOTIME_BEGINNING_OF_TIME: long = 1000L; @private @static val NANOTIME_WARP_MAX: long = 1000L; diff --git a/spec/java/lang/System.main.lsl b/spec/java/lang/System.main.lsl index 36b08d7b..780e703b 100644 --- a/spec/java/lang/System.main.lsl +++ b/spec/java/lang/System.main.lsl @@ -73,6 +73,12 @@ automaton SystemAutomaton // utilities + @AutoInline @Phantom proc _throwNPE (): void + { + action THROW_NEW("java.lang.NullPointerException", []); + } + + // constructors @private constructor *.LSLSystem (@target self: LSLSystem) @@ -97,7 +103,7 @@ automaton SystemAutomaton @static fun *.console (): Console { - action TODO(); + result = ioConsole; } @@ -225,24 +231,33 @@ automaton SystemAutomaton } - @static fun *.setErr (newErr: PrintStream): void + @static fun *.setErr (stream: PrintStream): void { + if (stream == null) + _throwNPE(); + // #todo: add checks and exceptions - err = newErr; + err = stream; } - @static fun *.setIn (newIn: InputStream): void + @static fun *.setIn (stream: InputStream): void { + if (stream == null) + _throwNPE(); + // #todo: add checks and exceptions - in = newIn; + in = stream; } - @static fun *.setOut (newOut: PrintStream): void + @static fun *.setOut (stream: PrintStream): void { + if (stream == null) + _throwNPE(); + // #todo: add checks and exceptions - out = newOut; + out = stream; } @@ -268,7 +283,7 @@ automaton SystemAutomaton // special: static initialization - @Phantom fun *.__clinit__ (): void + @Phantom @static fun *.__clinit__ (): void { // configure the standard input stream val newInput: InputStream = new SymbolicInputStreamAutomaton(state = Initialized, diff --git a/spec/java/util/LinkedList.automata.lsl b/spec/java/util/LinkedList.automata.lsl index 54fb1ba4..54110d55 100644 --- a/spec/java/util/LinkedList.automata.lsl +++ b/spec/java/util/LinkedList.automata.lsl @@ -98,6 +98,12 @@ automaton LinkedListAutomaton // utilities + @AutoInline @Phantom proc _throwNPE (): void + { + action THROW_NEW("java.lang.NullPointerException", []); + } + + @KeepVisible proc _checkForComodification (expectedModCount: int): void { if (this.modCount != expectedModCount) @@ -217,6 +223,28 @@ automaton LinkedListAutomaton } + @KeepVisible proc _replaceAllRange (op: UnaryOperator, i: int, end: int): void + { + val expectedModCount: int = this.modCount; + + action LOOP_WHILE( + this.modCount == expectedModCount && i < end, + _replaceAllRange_loop(i, op) + ); + + _checkForComodification(expectedModCount); + } + + @Phantom proc _replaceAllRange_loop (i: int, op: UnaryOperator): void + { + val oldItem: Object = action LIST_GET(this.storage, i); + val newItem: Object = action CALL(op, [oldItem]); + action LIST_SET(this.storage, i, newItem); + + i += 1; + } + + proc _makeStream (parallel: boolean): Stream { // #todo: use custom stream implementation @@ -238,7 +266,7 @@ automaton LinkedListAutomaton constructor *.LinkedList (@target self: LinkedList, c: Collection) { if (c == null) - action THROW_NEW("java.lang.NullPointerException", []); + _throwNPE(); this.storage = action LIST_NEW(); this.size = 0; @@ -415,7 +443,7 @@ automaton LinkedListAutomaton fun *.forEach (@target self: LinkedList, _action: Consumer): void { if (_action == null) - action THROW_NEW("java.lang.NullPointerException", []); + _throwNPE(); val expectedModCount: int = this.modCount; val length: int = this.size; @@ -715,9 +743,13 @@ automaton LinkedListAutomaton // within java.util.List - fun *.replaceAll (@target self: LinkedList, operator: UnaryOperator): void + fun *.replaceAll (@target self: LinkedList, op: UnaryOperator): void { - action TODO(); + if (op == null) + _throwNPE(); + + _replaceAllRange(op, 0, this.size); + this.modCount += 1; } From ce813d948cc20a65c0038ab76a99bda9ba8bd02e Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Sat, 28 Oct 2023 15:01:36 +0300 Subject: [PATCH 26/78] Fixed incorrect operation order in `LinkedList#set` method --- spec/java/util/LinkedList.automata.lsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/java/util/LinkedList.automata.lsl b/spec/java/util/LinkedList.automata.lsl index 54110d55..bfb1c844 100644 --- a/spec/java/util/LinkedList.automata.lsl +++ b/spec/java/util/LinkedList.automata.lsl @@ -763,8 +763,8 @@ automaton LinkedListAutomaton fun *.set (@target self: LinkedList, index: int, element: Object): Object { _checkElementIndex(index); - action LIST_SET(this.storage, index, element); result = action LIST_GET(this.storage, index); + action LIST_SET(this.storage, index, element); } From a57681d0c3e9201be91e9b9515dfe363c7b61500 Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Sun, 29 Oct 2023 15:49:34 +0300 Subject: [PATCH 27/78] Simplified sorting within `ArrayList` and `LinkedList` (and sublists) + Added `Console`-specific symbolic flag --- spec/java/io/Console.lsl | 3 + spec/java/util/ArrayList.SubList.lsl | 89 +------------ spec/java/util/ArrayList.main.lsl | 178 +++++++++++++------------ spec/java/util/LinkedList.automata.lsl | 177 ++++++++++++------------ 4 files changed, 191 insertions(+), 256 deletions(-) diff --git a/spec/java/io/Console.lsl b/spec/java/io/Console.lsl index b2506c46..67899f46 100644 --- a/spec/java/io/Console.lsl +++ b/spec/java/io/Console.lsl @@ -19,6 +19,9 @@ import java/io/Flushable; { } +// see java.io.Console#istty +val CONSOLE_ISTTY: boolean = action SYMBOLIC("boolean"); + // global aliases and type overrides diff --git a/spec/java/util/ArrayList.SubList.lsl b/spec/java/util/ArrayList.SubList.lsl index 905b6b63..db3bc538 100644 --- a/spec/java/util/ArrayList.SubList.lsl +++ b/spec/java/util/ArrayList.SubList.lsl @@ -635,92 +635,9 @@ automaton ArrayList_SubListAutomaton // within java.util.List fun *.sort (@target self: ArrayList_SubList, c: Comparator): void { - val size: int = this.length; - if (size != 0) - { - // Java has no unsigned primitive data types - action ASSUME(size > 0); - action ASSUME(this.root != null); - - _checkForComodification(); - val rootStorage: list = ArrayListAutomaton(this.root).storage; - - // prepare common variables - val baseLimit: int = this.offset + size; - val outerLimit: int = baseLimit - 1; - var i: int = 0; - var j: int = 0; - - // check the comparator - if (c == null) - { - // using Comparable::compareTo as a comparator - - // plain bubble sorting algorithm - action LOOP_FOR( - i, this.offset, outerLimit, +1, - sort_loop_outer_noComparator(i, j, baseLimit, rootStorage) - ); - } - else - { - // using the provided comparator - - // plain bubble sorting algorithm (with a comparator) - action LOOP_FOR( - i, this.offset, outerLimit, +1, - sort_loop_outer(i, j, baseLimit, rootStorage, c) - ); - } - - this.modCount = ArrayListAutomaton(this.root).modCount; - } - } - - @Phantom proc sort_loop_outer_noComparator (i: int, j: int, baseLimit: int, rootStorage: list): void - { - val innerLimit: int = baseLimit - i - 1; - action LOOP_FOR( - j, this.offset, innerLimit, +1, - sort_loop_inner_noComparator(j, rootStorage) - ); - } - - @Phantom proc sort_loop_inner_noComparator (j: int, rootStorage: list): void - { - val idxA: int = j; - val idxB: int = j + 1; - val a: Object = action LIST_GET(rootStorage, idxA); - val b: Object = action LIST_GET(rootStorage, idxB); - - if (action CALL_METHOD(a as Comparable, "compareTo", [b]) > 0) - { - action LIST_SET(rootStorage, idxA, b); - action LIST_SET(rootStorage, idxB, a); - } - } - - @Phantom proc sort_loop_outer (i: int, j: int, baseLimit: int, rootStorage: list, c: Comparator): void - { - val innerLimit: int = baseLimit - i - 1; - action LOOP_FOR( - j, this.offset, innerLimit, +1, - sort_loop_inner(j, rootStorage, c) - ); - } - - @Phantom proc sort_loop_inner (j: int, rootStorage: list, c: Comparator): void - { - val idxA: int = j; - val idxB: int = j + 1; - val a: Object = action LIST_GET(rootStorage, idxA); - val b: Object = action LIST_GET(rootStorage, idxB); - - if (action CALL(c, [a, b]) > 0) - { - action LIST_SET(rootStorage, idxA, b); - action LIST_SET(rootStorage, idxB, a); - } + action ASSUME(this.root != null); + ArrayListAutomaton(this.root)._do_sort(this.offset, this.offset + this.length, c); + this.modCount = ArrayListAutomaton(this.root).modCount; } diff --git a/spec/java/util/ArrayList.main.lsl b/spec/java/util/ArrayList.main.lsl index fea4e280..37855600 100644 --- a/spec/java/util/ArrayList.main.lsl +++ b/spec/java/util/ArrayList.main.lsl @@ -429,6 +429,98 @@ automaton ArrayListAutomaton } + // sort every item in the list within [start, end) range + @KeepVisible proc _do_sort (start: int, end: int, c: Comparator): void + { + if (start < end) + { + val expectedModCount: int = this.modCount; + + // Java has no unsigned primitive data types + action ASSUME(start >= 0); + action ASSUME(end > 0); + + // plain bubble sorting algorithm + val outerLimit: int = end - 1; + var innerLimit: int = 0; + var i: int = 0; + var j: int = 0; + + // check the comparator + if (c == null) + { + // using Comparable::compareTo as a comparator + + // plain bubble sorting algorithm + action LOOP_FOR( + i, start, outerLimit, +1, + sort_loop_outer_noComparator(i, j, innerLimit, start, end) + ); + } + else + { + // using the provided comparator + + // plain bubble sorting algorithm (with a comparator) + action LOOP_FOR( + i, start, outerLimit, +1, + sort_loop_outer(i, j, innerLimit, start, end, c) + ); + } + + _checkForComodification(expectedModCount); + } + + this.modCount += 1; + } + + @Phantom proc sort_loop_outer_noComparator (i: int, j: int, innerLimit: int, start: int, end: int): void + { + innerLimit = end - i - 1; + action LOOP_FOR( + j, start, innerLimit, +1, + sort_loop_inner_noComparator(j) + ); + } + + @Phantom proc sort_loop_inner_noComparator (j: int): void + { + val idxA: int = j; + val idxB: int = j + 1; + val a: Object = action LIST_GET(this.storage, idxA); + val b: Object = action LIST_GET(this.storage, idxB); + + if (action CALL_METHOD(a as Comparable, "compareTo", [b]) > 0) + { + action LIST_SET(this.storage, idxA, b); + action LIST_SET(this.storage, idxB, a); + } + } + + @Phantom proc sort_loop_outer (i: int, j: int, innerLimit: int, start: int, end: int, c: Comparator): void + { + innerLimit = end - i - 1; + action LOOP_FOR( + j, start, innerLimit, +1, + sort_loop_inner(j, c) + ); + } + + @Phantom proc sort_loop_inner (j: int, c: Comparator): void + { + val idxA: int = j; + val idxB: int = j + 1; + val a: Object = action LIST_GET(this.storage, idxA); + val b: Object = action LIST_GET(this.storage, idxB); + + if (action CALL(c, [a, b]) > 0) + { + action LIST_SET(this.storage, idxA, b); + action LIST_SET(this.storage, idxB, a); + } + } + + // constructors constructor *.ArrayList (@target self: ArrayList) @@ -775,91 +867,7 @@ automaton ArrayListAutomaton fun *.sort (@target self: ArrayList, c: Comparator): void { - if (this.length != 0) - { - val expectedModCount: int = this.modCount; - - // Java has no unsigned primitive data types - action ASSUME(this.length > 0); - - // plain bubble sorting algorithm - val outerLimit: int = this.length - 1; - var innerLimit: int = 0; - var i: int = 0; - var j: int = 0; - - // check the comparator - if (c == null) - { - // using Comparable::compareTo as a comparator - - // plain bubble sorting algorithm - action LOOP_FOR( - i, 0, outerLimit, +1, - sort_loop_outer_noComparator(i, j, innerLimit) - ); - } - else - { - // using the provided comparator - - // plain bubble sorting algorithm (with a comparator) - action LOOP_FOR( - i, 0, outerLimit, +1, - sort_loop_outer(i, j, innerLimit, c) - ); - } - - _checkForComodification(expectedModCount); - } - - this.modCount += 1; - } - - @Phantom proc sort_loop_outer_noComparator (i: int, j: int, innerLimit: int): void - { - innerLimit = this.length - i - 1; - action LOOP_FOR( - j, 0, innerLimit, +1, - sort_loop_inner_noComparator(j) - ); - } - - @Phantom proc sort_loop_inner_noComparator (j: int): void - { - val idxA: int = j; - val idxB: int = j + 1; - val a: Object = action LIST_GET(this.storage, idxA); - val b: Object = action LIST_GET(this.storage, idxB); - - if (action CALL_METHOD(a as Comparable, "compareTo", [b]) > 0) - { - action LIST_SET(this.storage, idxA, b); - action LIST_SET(this.storage, idxB, a); - } - } - - @Phantom proc sort_loop_outer (i: int, j: int, innerLimit: int, c: Comparator): void - { - innerLimit = this.length - i - 1; - action LOOP_FOR( - j, 0, innerLimit, +1, - sort_loop_inner(j, c) - ); - } - - @Phantom proc sort_loop_inner (j: int, c: Comparator): void - { - val idxA: int = j; - val idxB: int = j + 1; - val a: Object = action LIST_GET(this.storage, idxA); - val b: Object = action LIST_GET(this.storage, idxB); - - if (action CALL(c, [a, b]) > 0) - { - action LIST_SET(this.storage, idxA, b); - action LIST_SET(this.storage, idxB, a); - } + _do_sort(0, this.length, c); } diff --git a/spec/java/util/LinkedList.automata.lsl b/spec/java/util/LinkedList.automata.lsl index bfb1c844..97f5ddfa 100644 --- a/spec/java/util/LinkedList.automata.lsl +++ b/spec/java/util/LinkedList.automata.lsl @@ -254,6 +254,97 @@ automaton LinkedListAutomaton } + @KeepVisible proc _do_sort (start: int, end: int, c: Comparator): void + { + if (start < end) + { + val expectedModCount: int = this.modCount; + + // Java has no unsigned primitive data types + action ASSUME(start >= 0); + action ASSUME(end > 0); + + // plain bubble sorting algorithm + val outerLimit: int = end - 1; + var innerLimit: int = 0; + var i: int = 0; + var j: int = 0; + + // check the comparator + if (c == null) + { + // using Comparable::compareTo as a comparator + + // plain bubble sorting algorithm + action LOOP_FOR( + i, start, outerLimit, +1, + sort_loop_outer_noComparator(i, j, innerLimit, start, end) + ); + } + else + { + // using the provided comparator + + // plain bubble sorting algorithm (with a comparator) + action LOOP_FOR( + i, start, outerLimit, +1, + sort_loop_outer(i, j, innerLimit, start, end, c) + ); + } + + _checkForComodification(expectedModCount); + } + + this.modCount += 1; + } + + @Phantom proc sort_loop_outer_noComparator (i: int, j: int, innerLimit: int, start: int, end: int): void + { + innerLimit = end - i - 1; + action LOOP_FOR( + j, start, innerLimit, +1, + sort_loop_inner_noComparator(j) + ); + } + + @Phantom proc sort_loop_inner_noComparator (j: int): void + { + val idxA: int = j; + val idxB: int = j + 1; + val a: Object = action LIST_GET(this.storage, idxA); + val b: Object = action LIST_GET(this.storage, idxB); + + if (action CALL_METHOD(a as Comparable, "compareTo", [b]) > 0) + { + action LIST_SET(this.storage, idxA, b); + action LIST_SET(this.storage, idxB, a); + } + } + + @Phantom proc sort_loop_outer (i: int, j: int, innerLimit: int, start: int, end: int, c: Comparator): void + { + innerLimit = end - i - 1; + action LOOP_FOR( + j, start, innerLimit, +1, + sort_loop_inner(j, c) + ); + } + + @Phantom proc sort_loop_inner (j: int, c: Comparator): void + { + val idxA: int = j; + val idxB: int = j + 1; + val a: Object = action LIST_GET(this.storage, idxA); + val b: Object = action LIST_GET(this.storage, idxB); + + if (action CALL(c, [a, b]) > 0) + { + action LIST_SET(this.storage, idxA, b); + action LIST_SET(this.storage, idxB, a); + } + } + + // constructors constructor *.LinkedList (@target self: LinkedList) @@ -777,91 +868,7 @@ automaton LinkedListAutomaton // within java.util.List fun *.sort (@target self: LinkedList, c: Comparator): void { - if (this.size != 0) - { - val expectedModCount: int = this.modCount; - - // Java has no unsigned primitive data types - action ASSUME(this.size > 0); - - // plain bubble sorting algorithm - val outerLimit: int = this.size - 1; - var innerLimit: int = 0; - var i: int = 0; - var j: int = 0; - - // check the comparator - if (c == null) - { - // using Comparable::compareTo as a comparator - - // plain bubble sorting algorithm - action LOOP_FOR( - i, 0, outerLimit, +1, - sort_loop_outer_noComparator(i, j, innerLimit) - ); - } - else - { - // using the provided comparator - - // plain bubble sorting algorithm (with a comparator) - action LOOP_FOR( - i, 0, outerLimit, +1, - sort_loop_outer(i, j, innerLimit, c) - ); - } - - _checkForComodification(expectedModCount); - } - - this.modCount += 1; - } - - @Phantom proc sort_loop_outer_noComparator (i: int, j: int, innerLimit: int): void - { - innerLimit = this.size - i - 1; - action LOOP_FOR( - j, 0, innerLimit, +1, - sort_loop_inner_noComparator(j) - ); - } - - @Phantom proc sort_loop_inner_noComparator (j: int): void - { - val idxA: int = j; - val idxB: int = j + 1; - val a: Object = action LIST_GET(this.storage, idxA); - val b: Object = action LIST_GET(this.storage, idxB); - - if (action CALL_METHOD(a as Comparable, "compareTo", [b]) > 0) - { - action LIST_SET(this.storage, idxA, b); - action LIST_SET(this.storage, idxB, a); - } - } - - @Phantom proc sort_loop_outer (i: int, j: int, innerLimit: int, c: Comparator): void - { - innerLimit = this.size - i - 1; - action LOOP_FOR( - j, 0, innerLimit, +1, - sort_loop_inner(j, c) - ); - } - - @Phantom proc sort_loop_inner (j: int, c: Comparator): void - { - val idxA: int = j; - val idxB: int = j + 1; - val a: Object = action LIST_GET(this.storage, idxA); - val b: Object = action LIST_GET(this.storage, idxB); - - if (action CALL(c, [a, b]) > 0) - { - action LIST_SET(this.storage, idxA, b); - action LIST_SET(this.storage, idxB, a); - } + _do_sort(0, this.size, c); } From 8208f07609112f3b194826edf9a8332adca0521a Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Mon, 30 Oct 2023 15:20:49 +0300 Subject: [PATCH 28/78] Improved `System` IO + Improvements to `LinkedList` + Added `java.util.Locale` type description (basic) --- spec/java/io/Console.lsl | 2 +- spec/java/lang/Integer.main.lsl | 2 +- spec/java/lang/Object.main.lsl | 2 +- spec/java/lang/System.StdOut.lsl | 346 +++++++++++-------------- spec/java/lang/System.lsl | 12 +- spec/java/lang/System.main.lsl | 13 +- spec/java/util/ArrayList.main.lsl | 4 +- spec/java/util/LinkedList.automata.lsl | 181 ++++++++++++- spec/java/util/Locale.lsl | 24 ++ 9 files changed, 379 insertions(+), 207 deletions(-) create mode 100644 spec/java/util/Locale.lsl diff --git a/spec/java/io/Console.lsl b/spec/java/io/Console.lsl index 67899f46..8651deef 100644 --- a/spec/java/io/Console.lsl +++ b/spec/java/io/Console.lsl @@ -20,7 +20,7 @@ import java/io/Flushable; } // see java.io.Console#istty -val CONSOLE_ISTTY: boolean = action SYMBOLIC("boolean"); +val CONSOLE_IS_TTY: boolean = action SYMBOLIC("boolean"); // global aliases and type overrides diff --git a/spec/java/lang/Integer.main.lsl b/spec/java/lang/Integer.main.lsl index 036ad494..6664345f 100644 --- a/spec/java/lang/Integer.main.lsl +++ b/spec/java/lang/Integer.main.lsl @@ -415,7 +415,7 @@ automaton IntegerAutomaton // special: class initialization - @Phantom fun *.__clinit__ (): void + @Phantom @static fun *.__clinit__ (): void { // WARNING: this should be empty, do not change! } diff --git a/spec/java/lang/Object.main.lsl b/spec/java/lang/Object.main.lsl index 4ea34a4d..97f4f10a 100644 --- a/spec/java/lang/Object.main.lsl +++ b/spec/java/lang/Object.main.lsl @@ -122,7 +122,7 @@ automaton ObjectAutomaton // special: static initialization - @Phantom fun *.__clinit__ (): void + @Phantom @static fun *.__clinit__ (): void { action DO_NOTHING(); } diff --git a/spec/java/lang/System.StdOut.lsl b/spec/java/lang/System.StdOut.lsl index 20199774..d9f17e67 100644 --- a/spec/java/lang/System.StdOut.lsl +++ b/spec/java/lang/System.StdOut.lsl @@ -1,4 +1,3 @@ -//#! pragma: non-synthesizable libsl "1.1.0"; library std @@ -8,371 +7,340 @@ library std // imports -import java.common; -import java/io/File; -import java/io/FilterOutputStream; -import java/io/_interfaces; -import java/lang/_interfaces; -import java/nio/charset/_interfaces; +import java/lang/CharSequence; +import java/lang/Object; +import java/lang/String; import java/util/Locale; - -// local semantic types - -@extends("java.io.FilterOutputStream") -@implements("java.lang.Appendable") -@implements("java.io.Closeable") -@public type PrintStream - is java.io.PrintStream - for Object -{ -} +import java/lang/System; +import runtime/utils/VoidOutputStream; // automata -automaton PrintStreamAutomaton +automaton System_PrintStreamAutomaton ( ) -: PrintStream +: System_PrintStream { // states and shifts - initstate Allocated; - state Initialized; - - shift Allocated -> Initialized by [ - // constructors - PrintStream (PrintStream, File), - PrintStream (PrintStream, File, Charset), - PrintStream (PrintStream, File, String), - PrintStream (PrintStream, OutputStream), - PrintStream (PrintStream, OutputStream, boolean), - PrintStream (PrintStream, OutputStream, boolean, Charset), - PrintStream (PrintStream, OutputStream, boolean, String), - PrintStream (PrintStream, String), - PrintStream (PrintStream, String, Charset), - PrintStream (PrintStream, String, String), - PrintStream (PrintStream, boolean, Charset, OutputStream), - PrintStream (PrintStream, boolean, OutputStream), - ]; + initstate Initialized; shift Initialized -> self by [ // instance methods - append (PrintStream, CharSequence), - append (PrintStream, CharSequence, int, int), - append (PrintStream, char), + append (System_PrintStream, CharSequence), + append (System_PrintStream, CharSequence, int, int), + append (System_PrintStream, char), checkError, close, flush, - format (PrintStream, Locale, String, array), - format (PrintStream, String, array), - print (PrintStream, Object), - print (PrintStream, String), - print (PrintStream, boolean), - print (PrintStream, char), - print (PrintStream, array), - print (PrintStream, double), - print (PrintStream, float), - print (PrintStream, int), - print (PrintStream, long), - printf (PrintStream, Locale, String, array), - printf (PrintStream, String, array), - println (PrintStream), - println (PrintStream, Object), - println (PrintStream, String), - println (PrintStream, boolean), - println (PrintStream, char), - println (PrintStream, array), - println (PrintStream, double), - println (PrintStream, float), - println (PrintStream, int), - println (PrintStream, long), - write (PrintStream, array), - write (PrintStream, array, int, int), - write (PrintStream, int), + format (System_PrintStream, Locale, String, array), + format (System_PrintStream, String, array), + print (System_PrintStream, Object), + print (System_PrintStream, String), + print (System_PrintStream, boolean), + print (System_PrintStream, char), + print (System_PrintStream, array), + print (System_PrintStream, double), + print (System_PrintStream, float), + print (System_PrintStream, int), + print (System_PrintStream, long), + printf (System_PrintStream, Locale, String, array), + printf (System_PrintStream, String, array), + println (System_PrintStream), + println (System_PrintStream, Object), + println (System_PrintStream, String), + println (System_PrintStream, boolean), + println (System_PrintStream, char), + println (System_PrintStream, array), + println (System_PrintStream, double), + println (System_PrintStream, float), + println (System_PrintStream, int), + println (System_PrintStream, long), + write (System_PrintStream, array), + write (System_PrintStream, array, int, int), + write (System_PrintStream, int), ]; // internal variables - // utilities - - // constructors + var closed: boolean = false; + var error: boolean = false; - @throws(["java.io.FileNotFoundException"]) - constructor *.PrintStream (@target self: PrintStream, file: File) - { - action TODO(); - } + // utilities - @throws(["java.io.IOException"]) - constructor *.PrintStream (@target self: PrintStream, file: File, charset: Charset) + @AutoInline @Phantom proc _throwNPE (): void { - action TODO(); + action THROW_NEW("java.lang.NullPointerException", []); } - @throws(["java.io.FileNotFoundException", "java.io.UnsupportedEncodingException"]) - constructor *.PrintStream (@target self: PrintStream, file: File, csn: String) + @AutoInline @Phantom proc _checkOpen (): void { - action TODO(); + if (this.closed) + this.error = true; } - constructor *.PrintStream (@target self: PrintStream, out: OutputStream) - { - action TODO(); - } + // constructors + // static methods + + // methods - constructor *.PrintStream (@target self: PrintStream, out: OutputStream, autoFlush: boolean) + fun *.append (@target self: System_PrintStream, csq: CharSequence): PrintStream { - action TODO(); - } + if (csq == null) + _throwNPE(); + _checkOpen(); - constructor *.PrintStream (@target self: PrintStream, out: OutputStream, autoFlush: boolean, charset: Charset) - { - action TODO(); + result = self; } - @throws(["java.io.UnsupportedEncodingException"]) - constructor *.PrintStream (@target self: PrintStream, out: OutputStream, autoFlush: boolean, encoding: String) + fun *.append (@target self: System_PrintStream, csq: CharSequence, start: int, end: int): PrintStream { - action TODO(); - } + if (csq == null) + _throwNPE(); + val size: int = action CALL_METHOD(csq, "length", []); + if (start < 0 || end >= size) + action THROW_NEW("java.lang.IndexOutOfBoundsException", []); - @throws(["java.io.FileNotFoundException"]) - constructor *.PrintStream (@target self: PrintStream, fileName: String) - { - action TODO(); + _checkOpen(); + + result = self; } - @throws(["java.io.IOException"]) - constructor *.PrintStream (@target self: PrintStream, fileName: String, charset: Charset) + fun *.append (@target self: System_PrintStream, c: char): PrintStream { - action TODO(); + _checkOpen(); + + result = self; } - @throws(["java.io.FileNotFoundException", "java.io.UnsupportedEncodingException"]) - constructor *.PrintStream (@target self: PrintStream, fileName: String, csn: String) + fun *.checkError (@target self: System_PrintStream): boolean { - action TODO(); + result = this.error; } - @private constructor *.PrintStream (@target self: PrintStream, autoFlush: boolean, charset: Charset, out: OutputStream) + fun *.close (@target self: System_PrintStream): void { - action TODO(); + this.closed = true; } - @private constructor *.PrintStream (@target self: PrintStream, autoFlush: boolean, out: OutputStream) + fun *.flush (@target self: System_PrintStream): void { - action TODO(); + _checkOpen(); } - // static methods - - // methods - - fun *.append (@target self: PrintStream, csq: CharSequence): PrintStream + @varargs fun *.format (@target self: System_PrintStream, l: Locale, format: String, args: array): PrintStream { - action TODO(); - } + if (l == null || format == null || args == null) + _throwNPE(); + _checkOpen(); - fun *.append (@target self: PrintStream, csq: CharSequence, start: int, end: int): PrintStream - { - action TODO(); + result = self; } - fun *.append (@target self: PrintStream, c: char): PrintStream + @varargs fun *.format (@target self: System_PrintStream, format: String, args: array): PrintStream { - action TODO(); - } + if (format == null || args == null) + _throwNPE(); + _checkOpen(); - fun *.checkError (@target self: PrintStream): boolean - { - action TODO(); + result = self; } - fun *.close (@target self: PrintStream): void + fun *.print (@target self: System_PrintStream, obj: Object): void { - action TODO(); + _checkOpen(); } - fun *.flush (@target self: PrintStream): void + fun *.print (@target self: System_PrintStream, s: String): void { - action TODO(); + _checkOpen(); } - @varargs fun *.format (@target self: PrintStream, l: Locale, format: String, args: array): PrintStream + fun *.print (@target self: System_PrintStream, b: boolean): void { - action TODO(); + _checkOpen(); } - @varargs fun *.format (@target self: PrintStream, format: String, args: array): PrintStream + fun *.print (@target self: System_PrintStream, c: char): void { - action TODO(); + _checkOpen(); } - fun *.print (@target self: PrintStream, obj: Object): void + fun *.print (@target self: System_PrintStream, s: array): void { - action TODO(); + if (s == null) + _throwNPE(); + + _checkOpen(); } - fun *.print (@target self: PrintStream, s: String): void + fun *.print (@target self: System_PrintStream, d: double): void { - action TODO(); + _checkOpen(); } - fun *.print (@target self: PrintStream, b: boolean): void + fun *.print (@target self: System_PrintStream, f: float): void { - action TODO(); + _checkOpen(); } - fun *.print (@target self: PrintStream, c: char): void + fun *.print (@target self: System_PrintStream, i: int): void { - action TODO(); + _checkOpen(); } - fun *.print (@target self: PrintStream, s: array): void + fun *.print (@target self: System_PrintStream, l: long): void { - action TODO(); + _checkOpen(); } - fun *.print (@target self: PrintStream, d: double): void + @varargs fun *.printf (@target self: System_PrintStream, l: Locale, format: String, args: array): PrintStream { - action TODO(); - } + if (l == null || format == null || args == null) + _throwNPE(); + _checkOpen(); - fun *.print (@target self: PrintStream, f: float): void - { - action TODO(); + result = self; } - fun *.print (@target self: PrintStream, i: int): void + @varargs fun *.printf (@target self: System_PrintStream, format: String, args: array): PrintStream { - action TODO(); - } + if (format == null || args == null) + _throwNPE(); + _checkOpen(); - fun *.print (@target self: PrintStream, l: long): void - { - action TODO(); + result = self; } - @varargs fun *.printf (@target self: PrintStream, l: Locale, format: String, args: array): PrintStream + fun *.println (@target self: System_PrintStream): void { - action TODO(); + _checkOpen(); } - @varargs fun *.printf (@target self: PrintStream, format: String, args: array): PrintStream + fun *.println (@target self: System_PrintStream, x: Object): void { - action TODO(); + _checkOpen(); } - fun *.println (@target self: PrintStream): void + fun *.println (@target self: System_PrintStream, x: String): void { - action TODO(); + _checkOpen(); } - fun *.println (@target self: PrintStream, x: Object): void + fun *.println (@target self: System_PrintStream, x: boolean): void { - action TODO(); + _checkOpen(); } - fun *.println (@target self: PrintStream, x: String): void + fun *.println (@target self: System_PrintStream, x: char): void { - action TODO(); + _checkOpen(); } - fun *.println (@target self: PrintStream, x: boolean): void + fun *.println (@target self: System_PrintStream, x: array): void { - action TODO(); + if (x == null) + _throwNPE(); + + _checkOpen(); } - fun *.println (@target self: PrintStream, x: char): void + fun *.println (@target self: System_PrintStream, x: double): void { - action TODO(); + _checkOpen(); } - fun *.println (@target self: PrintStream, x: array): void + fun *.println (@target self: System_PrintStream, x: float): void { - action TODO(); + _checkOpen(); } - fun *.println (@target self: PrintStream, x: double): void + fun *.println (@target self: System_PrintStream, x: int): void { - action TODO(); + _checkOpen(); } - fun *.println (@target self: PrintStream, x: float): void + fun *.println (@target self: System_PrintStream, x: long): void { - action TODO(); + _checkOpen(); } - fun *.println (@target self: PrintStream, x: int): void + @throws(["java.io.IOException"]) + // within java.io.OutputStream + fun *.write (@target self: System_PrintStream, b: array): void { - action TODO(); + if (b == null) + _throwNPE(); + + _checkOpen(); } - fun *.println (@target self: PrintStream, x: long): void + fun *.write (@target self: System_PrintStream, buf: array, off: int, len: int): void { - action TODO(); - } + if (buf == null) + _throwNPE(); + val size: int = action ARRAY_SIZE(buf); + if (off < 0 || off + len > size) + action THROW_NEW("java.lang.IndexOutOfBoundsException", []); - @throws(["java.io.IOException"]) - // within java.io.OutputStream - fun *.write (@target self: PrintStream, b: array): void - { - action TODO(); + _checkOpen(); } - fun *.write (@target self: PrintStream, buf: array, off: int, len: int): void + fun *.write (@target self: System_PrintStream, b: int): void { - action TODO(); + _checkOpen(); } - fun *.write (@target self: PrintStream, b: int): void + // special methods + + @Phantom @static fun *.__super__ (): array { - action TODO(); + result = [new VoidOutputStreamAutomaton(state = Initialized, closed = false)]; } } diff --git a/spec/java/lang/System.lsl b/spec/java/lang/System.lsl index e502f9d4..1ff09bd4 100644 --- a/spec/java/lang/System.lsl +++ b/spec/java/lang/System.lsl @@ -56,9 +56,9 @@ import java/lang/Throwable; for System { // #todo: attach I/O streams from this - @private @static var ioConsole: Console = null; + @private @static var console: Console = null; - @public @static var in: InputStream = null; // WARNING: do not change! + @public @static var in: InputStream = null; // WARNING: do not change! @public @static var out: PrintStream = null; // WARNING: do not change! @public @static var err: PrintStream = null; // WARNING: do not change! @@ -68,3 +68,11 @@ import java/lang/Throwable; val SYSTEM_IS_WINDOWS: boolean = action SYMBOLIC("boolean"); + +@GenerateMe +@extends("java.io.PrintStream") +@public @final type System_PrintStream + is java.lang.System_PrintStream + for PrintStream +{ +} diff --git a/spec/java/lang/System.main.lsl b/spec/java/lang/System.main.lsl index 780e703b..372ed2bb 100644 --- a/spec/java/lang/System.main.lsl +++ b/spec/java/lang/System.main.lsl @@ -103,7 +103,7 @@ automaton SystemAutomaton @static fun *.console (): Console { - result = ioConsole; + result = console; } @@ -285,18 +285,19 @@ automaton SystemAutomaton @Phantom @static fun *.__clinit__ (): void { - // configure the standard input stream + // configure the standard stream val newInput: InputStream = new SymbolicInputStreamAutomaton(state = Initialized, maxSize = 1000, supportMarks = false, ); in = action DEBUG_DO("new java.io.BufferedInputStream(newInput)"); - // configure the standard output stream - action TODO(); + // configure the standard stream + val o1: System_PrintStream = new System_PrintStreamAutomaton(state = Initialized); + out = o1 as PrintStream; - // configure the standard error stream - action TODO(); + // configure the standard stream + //err = new System_PrintStreamAutomaton(state = Initialized) as PrintStream; } } diff --git a/spec/java/util/ArrayList.main.lsl b/spec/java/util/ArrayList.main.lsl index 37855600..5f773904 100644 --- a/spec/java/util/ArrayList.main.lsl +++ b/spec/java/util/ArrayList.main.lsl @@ -827,7 +827,7 @@ automaton ArrayListAutomaton fun *.removeAll (@target self: ArrayList, c: Collection): boolean { - result = _batchRemove(c, false, 0, this.length); + result = _batchRemove(c, /* complement = */false, 0, this.length); } @@ -849,7 +849,7 @@ automaton ArrayListAutomaton fun *.retainAll (@target self: ArrayList, c: Collection): boolean { - result = _batchRemove(c, true, 0, this.length); + result = _batchRemove(c, /* complement = */true, 0, this.length); } diff --git a/spec/java/util/LinkedList.automata.lsl b/spec/java/util/LinkedList.automata.lsl index 97f5ddfa..9c1d4eb8 100644 --- a/spec/java/util/LinkedList.automata.lsl +++ b/spec/java/util/LinkedList.automata.lsl @@ -245,6 +245,118 @@ automaton LinkedListAutomaton } + @KeepVisible proc _removeIf (filter: Predicate, start: int, end: int): boolean + { + if (filter == null) + _throwNPE(); + + val oldSize: int = this.size; + val expectedModCount: int = this.modCount; + + // remove elements from the back first + action ASSUME(start <= end); + var i: int = 0; + action LOOP_FOR( + i, end - 1, start, -1, + _removeIf_loop(i, filter) + ); + + _checkForComodification(expectedModCount); + + result = oldSize != this.size; + } + + @Phantom proc _removeIf_loop (i: int, filter: Predicate): void + { + val item: Object = action LIST_GET(this.storage, i); + if (action CALL(filter, [item])) + { + action LIST_REMOVE(this.storage, i); + this.size -= 1; + } + } + + + @KeepVisible proc _equalsRange (other: List, from: int, to: int): boolean + { + result = true; + var i: int = from; + + var otherLength: int = 0; + var otherStorage: list = null; + + if (other has LinkedListAutomaton) + { + otherLength = LinkedListAutomaton(other).size; + action ASSUME(otherLength >= 0); + + // assumptions: no multithreading, from == 0 + result = to == otherLength; + if (result) + { + otherStorage = LinkedListAutomaton(other).storage; + action ASSUME(otherStorage != null); + + action LOOP_WHILE( + result && i < to, + _equalsRange_loop_optimized(i, otherStorage, result) + ); + } + } + /*else if (other has LinkedList_SubListAutomaton) + { + otherLength = LinkedList_SubListAutomaton(other).size; + action ASSUME(otherLength >= 0); + + // assumptions: no multithreading, from >= 0 + result = to == otherLength; + if (result) + { + val otherRoot: LinkedList = LinkedList_SubListAutomaton(other).root; + action ASSUME(otherRoot != null); + + otherStorage = LinkedListAutomaton(otherRoot).storage; + action ASSUME(otherStorage != null); + + action LOOP_WHILE( + result && i < to, + _equalsRange_loop_optimized(i, otherStorage, result) + ); + } + }*/ + else + { + val iter: Iterator = action CALL_METHOD(other, "iterator", []); + action LOOP_WHILE( + result && i < to && action CALL_METHOD(iter, "hasNext", []), + _equalsRange_loop_regular(iter, i, result) + ); + + result &= !action CALL_METHOD(iter, "hasNext", []); + } + } + + @Phantom proc _equalsRange_loop_optimized (i: int, otherStorage: list, result: boolean): void + { + val a: Object = action LIST_GET(otherStorage, i); + val b: Object = action LIST_GET(this.storage, i); + + result = action OBJECT_EQUALS(a, b); + + i += 1; + } + + @Phantom proc _equalsRange_loop_regular (iter: Iterator, i: int, result: boolean): void + { + val a: Object = action CALL_METHOD(iter, "next", []); + val b: Object = action LIST_GET(this.storage, i); + + result = action OBJECT_EQUALS(a, b); + + i += 1; + } + + proc _makeStream (parallel: boolean): Stream { // #todo: use custom stream implementation @@ -254,6 +366,66 @@ automaton LinkedListAutomaton } + @KeepVisible proc _batchRemove (c: Collection, complement: boolean, start: int, end: int): boolean + { + val oldSize: int = this.size; + if (oldSize == 0 || start >= end) + { + result = false; + } + else + { + val otherLength: int = action CALL_METHOD(c, "size", []); + if (otherLength == 0) + { + result = false; + } + else + { + action ASSUME(otherLength > 0); + + var i: int = 0; + start -= 1; + end -= 1; + + if (c has LinkedListAutomaton) + { + val otherStorage: list = LinkedListAutomaton(c).storage; + action ASSUME(otherStorage != null); + + action LOOP_FOR( + i, end, start, -1, + _batchRemove_loop_optimized(i, otherStorage, complement) + ); + } + else + { + action LOOP_FOR( + i, end, start, -1, + _batchRemove_loop_regular(i, c, complement) + ); + } + + result = oldSize != this.size; + } + } + } + + @Phantom proc _batchRemove_loop_optimized (i: int, otherStorage: list, complement: boolean): void + { + val item: Object = action LIST_GET(this.storage, i); + if ((action LIST_FIND(otherStorage, item, 0, this.size) == -1) == complement) + _unlinkAny(i); + } + + @Phantom proc _batchRemove_loop_regular (i: int, c: Collection, complement: boolean): void + { + val item: Object = action LIST_GET(this.storage, i); + if (action CALL_METHOD(c, "contains", [item]) != complement) + _unlinkAny(i); + } + + @KeepVisible proc _do_sort (start: int, end: int, c: Comparator): void { if (start < end) @@ -537,11 +709,10 @@ automaton LinkedListAutomaton _throwNPE(); val expectedModCount: int = this.modCount; - val length: int = this.size; var i: int = 0; action LOOP_WHILE( - this.modCount == expectedModCount && i < length, + this.modCount == expectedModCount && i < this.size, forEach_loop(i, _action) ); @@ -774,7 +945,7 @@ automaton LinkedListAutomaton // within java.util.AbstractCollection fun *.removeAll (@target self: LinkedList, c: Collection): boolean { - action TODO(); + result = _batchRemove(c, /* complement = */false, 0, this.size); } @@ -793,7 +964,7 @@ automaton LinkedListAutomaton // within java.util.Collection fun *.removeIf (@target self: LinkedList, filter: Predicate): boolean { - action TODO(); + result = _removeIf(filter, 0, this.size); } @@ -847,7 +1018,7 @@ automaton LinkedListAutomaton // within java.util.AbstractCollection fun *.retainAll (@target self: LinkedList, c: Collection): boolean { - action TODO(); + result = _batchRemove(c, /* complement = */true, 0, this.size); } diff --git a/spec/java/util/Locale.lsl b/spec/java/util/Locale.lsl new file mode 100644 index 00000000..5b9e85dc --- /dev/null +++ b/spec/java/util/Locale.lsl @@ -0,0 +1,24 @@ +//#! pragma: non-synthesizable +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/util/Locale.java"; + +// imports + +import java/io/Serializable; +import java/lang/Cloneable; + + +// primary semantic types + +@final type Locale + is java.util.Locale + for Cloneable, Serializable +{ +} + + +// global aliases and type overrides From e3cdf1ba6daea7017f2c1f4b72156eba892c3412 Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Tue, 31 Oct 2023 09:26:34 +0300 Subject: [PATCH 29/78] Enabled back `System.err` initialization + Disabled `BufferedInputStream` used as wraper for `System.in` --- spec/java/lang/System.main.lsl | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/spec/java/lang/System.main.lsl b/spec/java/lang/System.main.lsl index 372ed2bb..5b408797 100644 --- a/spec/java/lang/System.main.lsl +++ b/spec/java/lang/System.main.lsl @@ -290,14 +290,13 @@ automaton SystemAutomaton maxSize = 1000, supportMarks = false, ); - in = action DEBUG_DO("new java.io.BufferedInputStream(newInput)"); + in = newInput;//action DEBUG_DO("new java.io.BufferedInputStream(newInput)"); // configure the standard stream - val o1: System_PrintStream = new System_PrintStreamAutomaton(state = Initialized); - out = o1 as PrintStream; + out = new System_PrintStreamAutomaton(state = Initialized); // configure the standard stream - //err = new System_PrintStreamAutomaton(state = Initialized) as PrintStream; + err = new System_PrintStreamAutomaton(state = Initialized); } } From b8dd86c14fb53da4bfa1514e20b55cbe1f51deca Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Thu, 2 Nov 2023 13:56:44 +0300 Subject: [PATCH 30/78] Added implementation for `AtomicBoolean` --- .../util/concurrent/atomic/AtomicBoolean.lsl | 35 ++ .../concurrent/atomic/AtomicBoolean.main.lsl | 343 ++++++++++++++++++ 2 files changed, 378 insertions(+) create mode 100644 spec/java/util/concurrent/atomic/AtomicBoolean.lsl create mode 100644 spec/java/util/concurrent/atomic/AtomicBoolean.main.lsl diff --git a/spec/java/util/concurrent/atomic/AtomicBoolean.lsl b/spec/java/util/concurrent/atomic/AtomicBoolean.lsl new file mode 100644 index 00000000..baa8394b --- /dev/null +++ b/spec/java/util/concurrent/atomic/AtomicBoolean.lsl @@ -0,0 +1,35 @@ +//#! pragma: non-synthesizable +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/util/concurrent/atomic/AtomicBoolean.java"; + +// imports + +import java/io/Serializable; + + +// primary semantic types + +type AtomicBoolean + is java.util.concurrent.atomic.AtomicBoolean + for Serializable +{ +} + + +// global aliases and type overrides + +@implements("java.io.Serializable") +type LSLAtomicBoolean + is java.util.concurrent.atomic.AtomicBoolean + for AtomicBoolean +{ + @private @static val serialVersionUID: long = 4654671469794556979L; + + @private @static val FALSE: int = 0; + @private @static val TRUE: int = 1; +} + diff --git a/spec/java/util/concurrent/atomic/AtomicBoolean.main.lsl b/spec/java/util/concurrent/atomic/AtomicBoolean.main.lsl new file mode 100644 index 00000000..a22a1e28 --- /dev/null +++ b/spec/java/util/concurrent/atomic/AtomicBoolean.main.lsl @@ -0,0 +1,343 @@ +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/util/concurrent/atomic/AtomicBoolean.java"; + +// imports + +import java/lang/String; +import java/util/concurrent/atomic/AtomicBoolean; + + +// automata + +automaton AtomicBooleanAutomaton +( + @private @volatile var value: int = 0, // WARNING: do not rename or change the type! +) +: LSLAtomicBoolean +{ + // states and shifts + + initstate Allocated; + state Initialized; + + shift Allocated -> Initialized by [ + // constructors + LSLAtomicBoolean (LSLAtomicBoolean), + LSLAtomicBoolean (LSLAtomicBoolean, boolean), + ]; + + shift Initialized -> self by [ + // instance methods + compareAndExchange, + compareAndExchangeAcquire, + compareAndExchangeRelease, + compareAndSet, + get, + getAcquire, + getAndSet, + getOpaque, + getPlain, + lazySet, + set, + setOpaque, + setPlain, + setRelease, + toString, + weakCompareAndSet, + weakCompareAndSetAcquire, + weakCompareAndSetPlain, + weakCompareAndSetRelease, + weakCompareAndSetVolatile, + ]; + + // internal variables + + // utilities + + // constructors + + constructor *.LSLAtomicBoolean (@target self: LSLAtomicBoolean) + { + this.value = FALSE; + } + + + constructor *.LSLAtomicBoolean (@target self: LSLAtomicBoolean, initialValue: boolean) + { + if (initialValue) + this.value = TRUE; + else + this.value = FALSE; + } + + + // static methods + + // methods + + @final fun *.compareAndExchange (@target self: LSLAtomicBoolean, expectedValue: boolean, newValue: boolean): boolean + { + val currentValue: boolean = this.value != FALSE; + result = currentValue; + + if (currentValue == expectedValue) + { + if (newValue) + this.value = TRUE; + else + this.value = FALSE; + } + } + + + @final fun *.compareAndExchangeAcquire (@target self: LSLAtomicBoolean, expectedValue: boolean, newValue: boolean): boolean + { + // #problem: unable to model memory effects here + val currentValue: boolean = this.value != FALSE; + result = currentValue; + + if (currentValue == expectedValue) + { + if (newValue) + this.value = TRUE; + else + this.value = FALSE; + } + } + + + @final fun *.compareAndExchangeRelease (@target self: LSLAtomicBoolean, expectedValue: boolean, newValue: boolean): boolean + { + // #problem: unable to model memory effects here + val currentValue: boolean = this.value != FALSE; + result = currentValue; + + if (currentValue == expectedValue) + { + if (newValue) + this.value = TRUE; + else + this.value = FALSE; + } + } + + + @final fun *.compareAndSet (@target self: LSLAtomicBoolean, expectedValue: boolean, newValue: boolean): boolean + { + val currentValue: boolean = this.value != FALSE; + if (currentValue == expectedValue) + { + result = true; + + if (newValue) + this.value = TRUE; + else + this.value = FALSE; + } + else + { + result = false; + } + } + + + @final fun *.get (@target self: LSLAtomicBoolean): boolean + { + // NOTE: same as in the original + result = this.value != FALSE; + } + + + @final fun *.getAcquire (@target self: LSLAtomicBoolean): boolean + { + // #problem: unable to model memory effects here + result = this.value != FALSE; + } + + + @final fun *.getAndSet (@target self: LSLAtomicBoolean, newValue: boolean): boolean + { + result = this.value != FALSE; + + if (newValue) + this.value = TRUE; + else + this.value = FALSE; + } + + + @final fun *.getOpaque (@target self: LSLAtomicBoolean): boolean + { + // #problem: unable to model memory effects here + result = this.value != FALSE; + } + + + @final fun *.getPlain (@target self: LSLAtomicBoolean): boolean + { + result = this.value != FALSE; + } + + + @final fun *.lazySet (@target self: LSLAtomicBoolean, newValue: boolean): void + { + // #problem: delayed assignment in multithreaded environment + if (newValue) + this.value = TRUE; + else + this.value = FALSE; + } + + + @final fun *.set (@target self: LSLAtomicBoolean, newValue: boolean): void + { + if (newValue) + this.value = TRUE; + else + this.value = FALSE; + } + + + @final fun *.setOpaque (@target self: LSLAtomicBoolean, newValue: boolean): void + { + // #problem: unable to model memory effects here + if (newValue) + this.value = TRUE; + else + this.value = FALSE; + } + + + @final fun *.setPlain (@target self: LSLAtomicBoolean, newValue: boolean): void + { + // #problem: unable to model memory effects here + if (newValue) + this.value = TRUE; + else + this.value = FALSE; + } + + + @final fun *.setRelease (@target self: LSLAtomicBoolean, newValue: boolean): void + { + // #problem: unable to model memory effects here + if (newValue) + this.value = TRUE; + else + this.value = FALSE; + } + + + fun *.toString (@target self: LSLAtomicBoolean): String + { + if (this.value == FALSE) + result = "false"; + else + result = "true"; + } + + + fun *.weakCompareAndSet (@target self: LSLAtomicBoolean, expectedValue: boolean, newValue: boolean): boolean + { + // #problem: delayed assignment in multithreaded environment + val currentValue: boolean = this.value != FALSE; + if (currentValue == expectedValue) + { + result = true; + + if (newValue) + this.value = TRUE; + else + this.value = FALSE; + } + else + { + result = false; + } + } + + + @final fun *.weakCompareAndSetAcquire (@target self: LSLAtomicBoolean, expectedValue: boolean, newValue: boolean): boolean + { + // #problem: delayed assignment in multithreaded environment + val currentValue: boolean = this.value != FALSE; + if (currentValue == expectedValue) + { + result = true; + + if (newValue) + this.value = TRUE; + else + this.value = FALSE; + } + else + { + result = false; + } + } + + + fun *.weakCompareAndSetPlain (@target self: LSLAtomicBoolean, expectedValue: boolean, newValue: boolean): boolean + { + // #problem: delayed assignment in multithreaded environment + val currentValue: boolean = this.value != FALSE; + if (currentValue == expectedValue) + { + result = true; + + if (newValue) + this.value = TRUE; + else + this.value = FALSE; + } + else + { + result = false; + } + } + + + @final fun *.weakCompareAndSetRelease (@target self: LSLAtomicBoolean, expectedValue: boolean, newValue: boolean): boolean + { + // #problem: delayed assignment in multithreaded environment + val currentValue: boolean = this.value != FALSE; + if (currentValue == expectedValue) + { + result = true; + + if (newValue) + this.value = TRUE; + else + this.value = FALSE; + } + else + { + result = false; + } + } + + + @final fun *.weakCompareAndSetVolatile (@target self: LSLAtomicBoolean, expectedValue: boolean, newValue: boolean): boolean + { + // #problem: delayed assignment in multithreaded environment + val currentValue: boolean = this.value != FALSE; + if (currentValue == expectedValue) + { + result = true; + + if (newValue) + this.value = TRUE; + else + this.value = FALSE; + } + else + { + result = false; + } + } + +} From 7aeddc79839b9997390c1d69cd521642f3480770 Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Fri, 3 Nov 2023 08:31:23 +0300 Subject: [PATCH 31/78] Added implementation for `AtomicInteger` --- .../util/concurrent/atomic/AtomicInteger.lsl | 33 ++ .../concurrent/atomic/AtomicInteger.main.lsl | 411 ++++++++++++++++++ 2 files changed, 444 insertions(+) create mode 100644 spec/java/util/concurrent/atomic/AtomicInteger.lsl create mode 100644 spec/java/util/concurrent/atomic/AtomicInteger.main.lsl diff --git a/spec/java/util/concurrent/atomic/AtomicInteger.lsl b/spec/java/util/concurrent/atomic/AtomicInteger.lsl new file mode 100644 index 00000000..84e81a32 --- /dev/null +++ b/spec/java/util/concurrent/atomic/AtomicInteger.lsl @@ -0,0 +1,33 @@ +//#! pragma: non-synthesizable +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/util/concurrent/atomic/AtomicInteger.java"; + +// imports + +import java/io/Serializable; +import java/lang/Number; + + +// primary semantic types + +type AtomicInteger + is java.util.concurrent.atomic.AtomicInteger + for Number, Serializable +{ +} + + +// global aliases and type overrides + +@extends("java.lang.Number") +@implements("java.io.Serializable") +type LSLAtomicInteger + is java.util.concurrent.atomic.AtomicInteger + for AtomicInteger +{ + @private @static val serialVersionUID: long = 6214790243416807050L; +} diff --git a/spec/java/util/concurrent/atomic/AtomicInteger.main.lsl b/spec/java/util/concurrent/atomic/AtomicInteger.main.lsl new file mode 100644 index 00000000..9dcc8174 --- /dev/null +++ b/spec/java/util/concurrent/atomic/AtomicInteger.main.lsl @@ -0,0 +1,411 @@ +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/util/concurrent/atomic/AtomicInteger.java"; + +// imports + +import java/lang/String; +import java/util/function/IntBinaryOperator; +import java/util/function/IntUnaryOperator; + +import java/util/concurrent/atomic/AtomicInteger; + + +// automata + +automaton AtomicIntegerAutomaton +( + @private @volatile var value: int = 0, // WARNING: do not rename! +) +: LSLAtomicInteger +{ + // states and shifts + + initstate Allocated; + state Initialized; + + shift Allocated -> Initialized by [ + // constructors + LSLAtomicInteger (LSLAtomicInteger), + LSLAtomicInteger (LSLAtomicInteger, int), + ]; + + shift Initialized -> self by [ + // instance methods + accumulateAndGet, + addAndGet, + byteValue, + compareAndExchange, + compareAndExchangeAcquire, + compareAndExchangeRelease, + compareAndSet, + decrementAndGet, + doubleValue, + floatValue, + get, + getAcquire, + getAndAccumulate, + getAndAdd, + getAndDecrement, + getAndIncrement, + getAndSet, + getAndUpdate, + getOpaque, + getPlain, + incrementAndGet, + intValue, + lazySet, + longValue, + set, + setOpaque, + setPlain, + setRelease, + shortValue, + toString, + updateAndGet, + weakCompareAndSet, + weakCompareAndSetAcquire, + weakCompareAndSetPlain, + weakCompareAndSetRelease, + weakCompareAndSetVolatile, + ]; + + // internal variables + + // utilities + + // constructors + + constructor *.LSLAtomicInteger (@target self: LSLAtomicInteger) + { + this.value = 0; + } + + + constructor *.LSLAtomicInteger (@target self: LSLAtomicInteger, initialValue: int) + { + this.value = initialValue; + } + + + // static methods + + // methods + + @final fun *.accumulateAndGet (@target self: LSLAtomicInteger, x: int, accumulatorFunction: IntBinaryOperator): int + { + val newValue: int = action CALL(accumulatorFunction, [this.value, x]); + result = newValue; + this.value = newValue; + } + + + @final fun *.addAndGet (@target self: LSLAtomicInteger, delta: int): int + { + val newValue: int = this.value + delta; + result = newValue; + this.value = newValue; + } + + + // within java.lang.Number + fun *.byteValue (@target self: LSLAtomicInteger): byte + { + result = this.value as byte; + } + + + @final fun *.compareAndExchange (@target self: LSLAtomicInteger, expectedValue: int, newValue: int): int + { + val currentValue: int = this.value; + if (currentValue == expectedValue) + this.value = newValue; + + result = currentValue; + } + + + @final fun *.compareAndExchangeAcquire (@target self: LSLAtomicInteger, expectedValue: int, newValue: int): int + { + // #problem: unable to model memory side-effects + val currentValue: int = this.value; + if (currentValue == expectedValue) + this.value = newValue; + + result = currentValue; + } + + + @final fun *.compareAndExchangeRelease (@target self: LSLAtomicInteger, expectedValue: int, newValue: int): int + { + // #problem: unable to model memory side-effects + val currentValue: int = this.value; + if (currentValue == expectedValue) + this.value = newValue; + + result = currentValue; + } + + + @final fun *.compareAndSet (@target self: LSLAtomicInteger, expectedValue: int, newValue: int): boolean + { + val currentValue: int = this.value; + if (currentValue == expectedValue) + { + result = true; + this.value = newValue; + } + else + { + result = false; + } + } + + + @final fun *.decrementAndGet (@target self: LSLAtomicInteger): int + { + val newValue: int = this.value - 1; + result = newValue; + this.value = newValue; + } + + + fun *.doubleValue (@target self: LSLAtomicInteger): double + { + result = this.value as double; + } + + + fun *.floatValue (@target self: LSLAtomicInteger): float + { + result = this.value as float; + } + + + @final fun *.get (@target self: LSLAtomicInteger): int + { + result = this.value; + } + + + @final fun *.getAcquire (@target self: LSLAtomicInteger): int + { + // #problem: unable to model memory side-effects + result = this.value; + } + + + @final fun *.getAndAccumulate (@target self: LSLAtomicInteger, x: int, accumulatorFunction: IntBinaryOperator): int + { + result = this.value; + this.value = action CALL(accumulatorFunction, [result, x]); + } + + + @final fun *.getAndAdd (@target self: LSLAtomicInteger, delta: int): int + { + result = this.value; + this.value = result + delta; + } + + + @final fun *.getAndDecrement (@target self: LSLAtomicInteger): int + { + result = this.value; + this.value = result - 1; + } + + + @final fun *.getAndIncrement (@target self: LSLAtomicInteger): int + { + result = this.value; + this.value = result + 1; + } + + + @final fun *.getAndSet (@target self: LSLAtomicInteger, newValue: int): int + { + result = this.value; + this.value = newValue; + } + + + @final fun *.getAndUpdate (@target self: LSLAtomicInteger, updateFunction: IntUnaryOperator): int + { + result = this.value; + this.value = action CALL(updateFunction, [result]); + } + + + @final fun *.getOpaque (@target self: LSLAtomicInteger): int + { + // #problem: unable to model memory side-effects + result = this.value; + } + + + @final fun *.getPlain (@target self: LSLAtomicInteger): int + { + // #problem: unable to model memory side-effects + result = this.value; + } + + + @final fun *.incrementAndGet (@target self: LSLAtomicInteger): int + { + val newValue: int = this.value + 1; + result = newValue; + this.value = newValue; + } + + + fun *.intValue (@target self: LSLAtomicInteger): int + { + result = this.value; + } + + + @final fun *.lazySet (@target self: LSLAtomicInteger, newValue: int): void + { + // #problem: unable to delay variable update + this.value = newValue; + } + + + fun *.longValue (@target self: LSLAtomicInteger): long + { + result = this.value as long; + } + + + @final fun *.set (@target self: LSLAtomicInteger, newValue: int): void + { + this.value = newValue; + } + + + @final fun *.setOpaque (@target self: LSLAtomicInteger, newValue: int): void + { + // #problem: unable to model memory side-effects + this.value = newValue; + } + + + @final fun *.setPlain (@target self: LSLAtomicInteger, newValue: int): void + { + // #problem: unable to model memory side-effects + this.value = newValue; + } + + + @final fun *.setRelease (@target self: LSLAtomicInteger, newValue: int): void + { + // #problem: unable to model memory side-effects + this.value = newValue; + } + + + // within java.lang.Number + fun *.shortValue (@target self: LSLAtomicInteger): short + { + result = this.value as short; + } + + + fun *.toString (@target self: LSLAtomicInteger): String + { + result = action OBJECT_TO_STRING(this.value); + } + + + @final fun *.updateAndGet (@target self: LSLAtomicInteger, updateFunction: IntUnaryOperator): int + { + val newValue: int = action CALL(updateFunction, [this.value]); + result = newValue; + this.value = newValue; + } + + + @final fun *.weakCompareAndSet (@target self: LSLAtomicInteger, expectedValue: int, newValue: int): boolean + { + // #problem: unable to delay variable update + val currentValue: int = this.value; + if (currentValue == expectedValue) + { + result = true; + this.value = newValue; + } + else + { + result = false; + } + } + + + @final fun *.weakCompareAndSetAcquire (@target self: LSLAtomicInteger, expectedValue: int, newValue: int): boolean + { + // #problem: unable to model memory side-effects + val currentValue: int = this.value; + if (currentValue == expectedValue) + { + result = true; + this.value = newValue; + } + else + { + result = false; + } + } + + + @final fun *.weakCompareAndSetPlain (@target self: LSLAtomicInteger, expectedValue: int, newValue: int): boolean + { + // #problem: unable to model memory side-effects + val currentValue: int = this.value; + if (currentValue == expectedValue) + { + result = true; + this.value = newValue; + } + else + { + result = false; + } + } + + + @final fun *.weakCompareAndSetRelease (@target self: LSLAtomicInteger, expectedValue: int, newValue: int): boolean + { + // #problem: unable to model memory side-effects + val currentValue: int = this.value; + if (currentValue == expectedValue) + { + result = true; + this.value = newValue; + } + else + { + result = false; + } + } + + + @final fun *.weakCompareAndSetVolatile (@target self: LSLAtomicInteger, expectedValue: int, newValue: int): boolean + { + // #problem: unable to model memory side-effects + val currentValue: int = this.value; + if (currentValue == expectedValue) + { + result = true; + this.value = newValue; + } + else + { + result = false; + } + } + +} From 6289ca52f82563255ae4e702fa51052cc16e7b69 Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Fri, 3 Nov 2023 08:33:51 +0300 Subject: [PATCH 32/78] Minor formatting changes for `System#in` --- spec/java/lang/System.StdOut.lsl | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/spec/java/lang/System.StdOut.lsl b/spec/java/lang/System.StdOut.lsl index d9f17e67..734012f9 100644 --- a/spec/java/lang/System.StdOut.lsl +++ b/spec/java/lang/System.StdOut.lsl @@ -340,7 +340,11 @@ automaton System_PrintStreamAutomaton @Phantom @static fun *.__super__ (): array { - result = [new VoidOutputStreamAutomaton(state = Initialized, closed = false)]; + result = [ + new VoidOutputStreamAutomaton(state = Initialized, + closed = false + ) + ]; } } From 44cb3a73cfb4f062c6b4f60d5fa693e8c6a9a5f0 Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Fri, 3 Nov 2023 10:02:31 +0300 Subject: [PATCH 33/78] Added `AtomicLong` + Minor simplifications for `AtomicInteger` and `AtomicBoolean` --- .../concurrent/atomic/AtomicBoolean.main.lsl | 18 +- .../concurrent/atomic/AtomicInteger.main.lsl | 109 ++---- .../util/concurrent/atomic/AtomicLong.lsl | 34 ++ .../concurrent/atomic/AtomicLong.main.lsl | 358 ++++++++++++++++++ 4 files changed, 426 insertions(+), 93 deletions(-) create mode 100644 spec/java/util/concurrent/atomic/AtomicLong.lsl create mode 100644 spec/java/util/concurrent/atomic/AtomicLong.main.lsl diff --git a/spec/java/util/concurrent/atomic/AtomicBoolean.main.lsl b/spec/java/util/concurrent/atomic/AtomicBoolean.main.lsl index a22a1e28..ce088ef3 100644 --- a/spec/java/util/concurrent/atomic/AtomicBoolean.main.lsl +++ b/spec/java/util/concurrent/atomic/AtomicBoolean.main.lsl @@ -81,10 +81,8 @@ automaton AtomicBooleanAutomaton @final fun *.compareAndExchange (@target self: LSLAtomicBoolean, expectedValue: boolean, newValue: boolean): boolean { - val currentValue: boolean = this.value != FALSE; - result = currentValue; - - if (currentValue == expectedValue) + result = this.value != FALSE; + if (result == expectedValue) { if (newValue) this.value = TRUE; @@ -97,10 +95,8 @@ automaton AtomicBooleanAutomaton @final fun *.compareAndExchangeAcquire (@target self: LSLAtomicBoolean, expectedValue: boolean, newValue: boolean): boolean { // #problem: unable to model memory effects here - val currentValue: boolean = this.value != FALSE; - result = currentValue; - - if (currentValue == expectedValue) + result = this.value != FALSE; + if (result == expectedValue) { if (newValue) this.value = TRUE; @@ -113,10 +109,8 @@ automaton AtomicBooleanAutomaton @final fun *.compareAndExchangeRelease (@target self: LSLAtomicBoolean, expectedValue: boolean, newValue: boolean): boolean { // #problem: unable to model memory effects here - val currentValue: boolean = this.value != FALSE; - result = currentValue; - - if (currentValue == expectedValue) + result = this.value != FALSE; + if (result == expectedValue) { if (newValue) this.value = TRUE; diff --git a/spec/java/util/concurrent/atomic/AtomicInteger.main.lsl b/spec/java/util/concurrent/atomic/AtomicInteger.main.lsl index 9dcc8174..6c67a3b9 100644 --- a/spec/java/util/concurrent/atomic/AtomicInteger.main.lsl +++ b/spec/java/util/concurrent/atomic/AtomicInteger.main.lsl @@ -97,17 +97,15 @@ automaton AtomicIntegerAutomaton @final fun *.accumulateAndGet (@target self: LSLAtomicInteger, x: int, accumulatorFunction: IntBinaryOperator): int { - val newValue: int = action CALL(accumulatorFunction, [this.value, x]); - result = newValue; - this.value = newValue; + result = action CALL(accumulatorFunction, [this.value, x]); + this.value = result; } @final fun *.addAndGet (@target self: LSLAtomicInteger, delta: int): int { - val newValue: int = this.value + delta; - result = newValue; - this.value = newValue; + result = this.value + delta; + this.value = result; } @@ -120,56 +118,42 @@ automaton AtomicIntegerAutomaton @final fun *.compareAndExchange (@target self: LSLAtomicInteger, expectedValue: int, newValue: int): int { - val currentValue: int = this.value; - if (currentValue == expectedValue) + result = this.value; + if (result == expectedValue) this.value = newValue; - - result = currentValue; } @final fun *.compareAndExchangeAcquire (@target self: LSLAtomicInteger, expectedValue: int, newValue: int): int { // #problem: unable to model memory side-effects - val currentValue: int = this.value; - if (currentValue == expectedValue) + result = this.value; + if (result == expectedValue) this.value = newValue; - - result = currentValue; } @final fun *.compareAndExchangeRelease (@target self: LSLAtomicInteger, expectedValue: int, newValue: int): int { // #problem: unable to model memory side-effects - val currentValue: int = this.value; - if (currentValue == expectedValue) + result = this.value; + if (result == expectedValue) this.value = newValue; - - result = currentValue; } @final fun *.compareAndSet (@target self: LSLAtomicInteger, expectedValue: int, newValue: int): boolean { - val currentValue: int = this.value; - if (currentValue == expectedValue) - { - result = true; + result = this.value == expectedValue; + if (result) this.value = newValue; - } - else - { - result = false; - } } @final fun *.decrementAndGet (@target self: LSLAtomicInteger): int { - val newValue: int = this.value - 1; - result = newValue; - this.value = newValue; + result = this.value - 1; + this.value = result; } @@ -256,9 +240,8 @@ automaton AtomicIntegerAutomaton @final fun *.incrementAndGet (@target self: LSLAtomicInteger): int { - val newValue: int = this.value + 1; - result = newValue; - this.value = newValue; + result = this.value + 1; + this.value = result; } @@ -323,89 +306,53 @@ automaton AtomicIntegerAutomaton @final fun *.updateAndGet (@target self: LSLAtomicInteger, updateFunction: IntUnaryOperator): int { - val newValue: int = action CALL(updateFunction, [this.value]); - result = newValue; - this.value = newValue; + result = action CALL(updateFunction, [this.value]); + this.value = result; } @final fun *.weakCompareAndSet (@target self: LSLAtomicInteger, expectedValue: int, newValue: int): boolean { // #problem: unable to delay variable update - val currentValue: int = this.value; - if (currentValue == expectedValue) - { - result = true; + result = this.value == expectedValue; + if (result) this.value = newValue; - } - else - { - result = false; - } } @final fun *.weakCompareAndSetAcquire (@target self: LSLAtomicInteger, expectedValue: int, newValue: int): boolean { // #problem: unable to model memory side-effects - val currentValue: int = this.value; - if (currentValue == expectedValue) - { - result = true; + result = this.value == expectedValue; + if (result) this.value = newValue; - } - else - { - result = false; - } } @final fun *.weakCompareAndSetPlain (@target self: LSLAtomicInteger, expectedValue: int, newValue: int): boolean { // #problem: unable to model memory side-effects - val currentValue: int = this.value; - if (currentValue == expectedValue) - { - result = true; + result = this.value == expectedValue; + if (result) this.value = newValue; - } - else - { - result = false; - } } @final fun *.weakCompareAndSetRelease (@target self: LSLAtomicInteger, expectedValue: int, newValue: int): boolean { // #problem: unable to model memory side-effects - val currentValue: int = this.value; - if (currentValue == expectedValue) - { - result = true; + result = this.value == expectedValue; + if (result) this.value = newValue; - } - else - { - result = false; - } } @final fun *.weakCompareAndSetVolatile (@target self: LSLAtomicInteger, expectedValue: int, newValue: int): boolean { // #problem: unable to model memory side-effects - val currentValue: int = this.value; - if (currentValue == expectedValue) - { - result = true; + result = this.value == expectedValue; + if (result) this.value = newValue; - } - else - { - result = false; - } } } diff --git a/spec/java/util/concurrent/atomic/AtomicLong.lsl b/spec/java/util/concurrent/atomic/AtomicLong.lsl new file mode 100644 index 00000000..81a82525 --- /dev/null +++ b/spec/java/util/concurrent/atomic/AtomicLong.lsl @@ -0,0 +1,34 @@ +//#! pragma: non-synthesizable +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/util/concurrent/atomic/AtomicLong.java"; + +// imports + +import java/io/Serializable; +import java/lang/Number; + + +// primary semantic types + +type AtomicLong + is java.util.concurrent.atomic.AtomicLong + for Number, Serializable +{ +} + + +// automata + +@extends("java.lang.Number") +@implements("java.io.Serializable") +type LSLAtomicLong + is java.util.concurrent.atomic.AtomicLong + for AtomicLong +{ + @private @static val serialVersionUID: long = 1927816293512124184L; +} + diff --git a/spec/java/util/concurrent/atomic/AtomicLong.main.lsl b/spec/java/util/concurrent/atomic/AtomicLong.main.lsl new file mode 100644 index 00000000..3a33ecae --- /dev/null +++ b/spec/java/util/concurrent/atomic/AtomicLong.main.lsl @@ -0,0 +1,358 @@ +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/util/concurrent/atomic/AtomicLong.java"; + +// imports + +import java/lang/String; +import java/util/function/LongBinaryOperator; +import java/util/function/LongUnaryOperator; + +import java/util/concurrent/atomic/AtomicLong; + + +// automata + +automaton AtomicLongAutomaton +( + @private @volatile var value: long = 0L, // WARNING: do not rename! +) +: LSLAtomicLong +{ + // states and shifts + + initstate Allocated; + state Initialized; + + shift Allocated -> Initialized by [ + // constructors + LSLAtomicLong (LSLAtomicLong), + LSLAtomicLong (LSLAtomicLong, long), + ]; + + shift Initialized -> self by [ + // instance methods + accumulateAndGet, + addAndGet, + byteValue, + compareAndExchange, + compareAndExchangeAcquire, + compareAndExchangeRelease, + compareAndSet, + decrementAndGet, + doubleValue, + floatValue, + get, + getAcquire, + getAndAccumulate, + getAndAdd, + getAndDecrement, + getAndIncrement, + getAndSet, + getAndUpdate, + getOpaque, + getPlain, + incrementAndGet, + intValue, + lazySet, + longValue, + set, + setOpaque, + setPlain, + setRelease, + shortValue, + toString, + updateAndGet, + weakCompareAndSet, + weakCompareAndSetAcquire, + weakCompareAndSetPlain, + weakCompareAndSetRelease, + weakCompareAndSetVolatile, + ]; + + // internal variables + + // utilities + + // constructors + + constructor *.LSLAtomicLong (@target self: LSLAtomicLong) + { + this.value = 0L; + } + + + constructor *.LSLAtomicLong (@target self: LSLAtomicLong, initialValue: long) + { + this.value = initialValue; + } + + + // static methods + + // methods + + @final fun *.accumulateAndGet (@target self: LSLAtomicLong, x: long, accumulatorFunction: LongBinaryOperator): long + { + result = action CALL(accumulatorFunction, [this.value, x]); + this.value = result; + } + + + @final fun *.addAndGet (@target self: LSLAtomicLong, delta: long): long + { + result = this.value + delta; + this.value = result; + } + + + // within java.lang.Number + fun *.byteValue (@target self: LSLAtomicLong): byte + { + result = this.value as byte; + } + + + @final fun *.compareAndExchange (@target self: LSLAtomicLong, expectedValue: long, newValue: long): long + { + result = this.value; + if (result == expectedValue) + this.value = newValue; + } + + + @final fun *.compareAndExchangeAcquire (@target self: LSLAtomicLong, expectedValue: long, newValue: long): long + { + // #problem: unable to model memory side-effects + result = this.value; + if (result == expectedValue) + this.value = newValue; + } + + + @final fun *.compareAndExchangeRelease (@target self: LSLAtomicLong, expectedValue: long, newValue: long): long + { + // #problem: unable to model memory side-effects + result = this.value; + if (result == expectedValue) + this.value = newValue; + } + + + @final fun *.compareAndSet (@target self: LSLAtomicLong, expectedValue: long, newValue: long): boolean + { + result = this.value == expectedValue; + if (result) + this.value = newValue; + } + + + @final fun *.decrementAndGet (@target self: LSLAtomicLong): long + { + result = this.value - 1L; + this.value = result; + } + + + fun *.doubleValue (@target self: LSLAtomicLong): double + { + result = this.value as double; + } + + + fun *.floatValue (@target self: LSLAtomicLong): float + { + result = this.value as float; + } + + + @final fun *.get (@target self: LSLAtomicLong): long + { + result = this.value; + } + + + @final fun *.getAcquire (@target self: LSLAtomicLong): long + { + // #problem: unable to model memory side-effects + result = this.value; + } + + + @final fun *.getAndAccumulate (@target self: LSLAtomicLong, x: long, accumulatorFunction: LongBinaryOperator): long + { + result = this.value; + this.value = action CALL(accumulatorFunction, [result, x]); + } + + + @final fun *.getAndAdd (@target self: LSLAtomicLong, delta: long): long + { + result = this.value; + this.value = result + delta; + } + + + @final fun *.getAndDecrement (@target self: LSLAtomicLong): long + { + result = this.value; + this.value = result - 1L; + } + + + @final fun *.getAndIncrement (@target self: LSLAtomicLong): long + { + result = this.value; + this.value = result + 1L; + } + + + @final fun *.getAndSet (@target self: LSLAtomicLong, newValue: long): long + { + result = this.value; + this.value = newValue; + } + + + @final fun *.getAndUpdate (@target self: LSLAtomicLong, updateFunction: LongUnaryOperator): long + { + result = this.value; + this.value = action CALL(updateFunction, [result]); + } + + + @final fun *.getOpaque (@target self: LSLAtomicLong): long + { + // #problem: unable to model memory side-effects + result = this.value; + } + + + @final fun *.getPlain (@target self: LSLAtomicLong): long + { + // #problem: unable to model memory side-effects + result = this.value; + } + + + @final fun *.incrementAndGet (@target self: LSLAtomicLong): long + { + result = this.value + 1L; + this.value = result; + } + + + fun *.intValue (@target self: LSLAtomicLong): int + { + result = this.value as int; + } + + + @final fun *.lazySet (@target self: LSLAtomicLong, newValue: long): void + { + // #problem: unable to delay variable update + this.value = newValue; + } + + + fun *.longValue (@target self: LSLAtomicLong): long + { + result = this.value; + } + + + @final fun *.set (@target self: LSLAtomicLong, newValue: long): void + { + this.value = newValue; + } + + + @final fun *.setOpaque (@target self: LSLAtomicLong, newValue: long): void + { + // #problem: unable to model memory side-effects + this.value = newValue; + } + + + @final fun *.setPlain (@target self: LSLAtomicLong, newValue: long): void + { + // #problem: unable to model memory side-effects + this.value = newValue; + } + + + @final fun *.setRelease (@target self: LSLAtomicLong, newValue: long): void + { + // #problem: unable to model memory side-effects + this.value = newValue; + } + + + // within java.lang.Number + fun *.shortValue (@target self: LSLAtomicLong): short + { + result = this.value as short; + } + + + fun *.toString (@target self: LSLAtomicLong): String + { + result = action OBJECT_TO_STRING(this.value); + } + + + @final fun *.updateAndGet (@target self: LSLAtomicLong, updateFunction: LongUnaryOperator): long + { + result = action CALL(updateFunction, [this.value]); + this.value = result; + } + + + @final fun *.weakCompareAndSet (@target self: LSLAtomicLong, expectedValue: long, newValue: long): boolean + { + // #problem: unable to model memory side-effects + result = this.value == expectedValue; + if (result) + this.value = newValue; + } + + + @final fun *.weakCompareAndSetAcquire (@target self: LSLAtomicLong, expectedValue: long, newValue: long): boolean + { + // #problem: unable to model memory side-effects + result = this.value == expectedValue; + if (result) + this.value = newValue; + } + + + @final fun *.weakCompareAndSetPlain (@target self: LSLAtomicLong, expectedValue: long, newValue: long): boolean + { + // #problem: unable to model memory side-effects + result = this.value == expectedValue; + if (result) + this.value = newValue; + } + + + @final fun *.weakCompareAndSetRelease (@target self: LSLAtomicLong, expectedValue: long, newValue: long): boolean + { + // #problem: unable to model memory side-effects + result = this.value == expectedValue; + if (result) + this.value = newValue; + } + + + @final fun *.weakCompareAndSetVolatile (@target self: LSLAtomicLong, expectedValue: long, newValue: long): boolean + { + // #problem: unable to model memory side-effects + result = this.value == expectedValue; + if (result) + this.value = newValue; + } + +} From a77550c5181d4d2cf4dd155735d530b07beec92c Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Fri, 3 Nov 2023 14:39:05 +0300 Subject: [PATCH 34/78] Added implementation for `AtomicReference` + Minor comment fixes for `AtomicLong` --- .../util/concurrent/atomic/AtomicLong.lsl | 2 +- .../concurrent/atomic/AtomicReference.lsl | 32 +++ .../atomic/AtomicReference.main.lsl | 267 ++++++++++++++++++ 3 files changed, 300 insertions(+), 1 deletion(-) create mode 100644 spec/java/util/concurrent/atomic/AtomicReference.lsl create mode 100644 spec/java/util/concurrent/atomic/AtomicReference.main.lsl diff --git a/spec/java/util/concurrent/atomic/AtomicLong.lsl b/spec/java/util/concurrent/atomic/AtomicLong.lsl index 81a82525..aeeb4622 100644 --- a/spec/java/util/concurrent/atomic/AtomicLong.lsl +++ b/spec/java/util/concurrent/atomic/AtomicLong.lsl @@ -21,7 +21,7 @@ type AtomicLong } -// automata +// global aliases and type overrides @extends("java.lang.Number") @implements("java.io.Serializable") diff --git a/spec/java/util/concurrent/atomic/AtomicReference.lsl b/spec/java/util/concurrent/atomic/AtomicReference.lsl new file mode 100644 index 00000000..75eb3004 --- /dev/null +++ b/spec/java/util/concurrent/atomic/AtomicReference.lsl @@ -0,0 +1,32 @@ +//#! pragma: non-synthesizable +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/util/concurrent/atomic/AtomicReference.java"; + +// imports + +import java/io/Serializable; + + +// primary semantic types + +type AtomicReference + is java.util.concurrent.atomic.AtomicReference + for Serializable +{ +} + + +// global aliases and type overrides + +@implements("java.io.Serializable") +@public type LSLAtomicReference + is java.util.concurrent.atomic.AtomicReference + for AtomicReference +{ + @private @static @final var serialVersionUID: long = -1848883965231344442L; +} + diff --git a/spec/java/util/concurrent/atomic/AtomicReference.main.lsl b/spec/java/util/concurrent/atomic/AtomicReference.main.lsl new file mode 100644 index 00000000..290639f4 --- /dev/null +++ b/spec/java/util/concurrent/atomic/AtomicReference.main.lsl @@ -0,0 +1,267 @@ +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/util/concurrent/atomic/AtomicReference.java"; + +// imports + +import java/lang/Object; +import java/lang/String; +import java/util/function/BinaryOperator; +import java/util/function/UnaryOperator; + +import java/util/concurrent/atomic/AtomicReference; + + +// automata + +automaton AtomicReferenceAutomaton +( + @private @volatile var value: Object = null, // WARNING: do not rename! +) +: LSLAtomicReference +{ + // states and shifts + + initstate Allocated; + state Initialized; + + shift Allocated -> Initialized by [ + // constructors + LSLAtomicReference (LSLAtomicReference), + LSLAtomicReference (LSLAtomicReference, Object), + ]; + + shift Initialized -> self by [ + // instance methods + accumulateAndGet, + compareAndExchange, + compareAndExchangeAcquire, + compareAndExchangeRelease, + compareAndSet, + get, + getAcquire, + getAndAccumulate, + getAndSet, + getAndUpdate, + getOpaque, + getPlain, + lazySet, + set, + setOpaque, + setPlain, + setRelease, + toString, + updateAndGet, + weakCompareAndSet, + weakCompareAndSetAcquire, + weakCompareAndSetPlain, + weakCompareAndSetRelease, + weakCompareAndSetVolatile, + ]; + + // internal variables + + // utilities + + // constructors + + constructor *.LSLAtomicReference (@target self: LSLAtomicReference) + { + this.value = null; + } + + + constructor *.LSLAtomicReference (@target self: LSLAtomicReference, initialValue: Object) + { + this.value = initialValue; + } + + + // static methods + + // methods + + @final fun *.accumulateAndGet (@target self: LSLAtomicReference, x: Object, accumulatorFunction: BinaryOperator): Object + { + result = action CALL(accumulatorFunction, [this.value, x]); + this.value = result; + } + + + @final fun *.compareAndExchange (@target self: LSLAtomicReference, expectedValue: Object, newValue: Object): Object + { + result = this.value; + if (result == expectedValue) + this.value = newValue; + } + + + @final fun *.compareAndExchangeAcquire (@target self: LSLAtomicReference, expectedValue: Object, newValue: Object): Object + { + // #problem: unable to model memory side-effects + result = this.value; + if (result == expectedValue) + this.value = newValue; + } + + + @final fun *.compareAndExchangeRelease (@target self: LSLAtomicReference, expectedValue: Object, newValue: Object): Object + { + // #problem: unable to model memory side-effects + result = this.value; + if (result == expectedValue) + this.value = newValue; + } + + + @final fun *.compareAndSet (@target self: LSLAtomicReference, expectedValue: Object, newValue: Object): boolean + { + result = this.value == expectedValue; + if (result) + this.value = newValue; + } + + + @final fun *.get (@target self: LSLAtomicReference): Object + { + result = this.value; + } + + + @final fun *.getAcquire (@target self: LSLAtomicReference): Object + { + // #problem: unable to model memory side-effects + result = this.value; + } + + + @final fun *.getAndAccumulate (@target self: LSLAtomicReference, x: Object, accumulatorFunction: BinaryOperator): Object + { + result = this.value; + this.value = action CALL(accumulatorFunction, [result, x]); + } + + + @final fun *.getAndSet (@target self: LSLAtomicReference, newValue: Object): Object + { + result = this.value; + this.value = newValue; + } + + + @final fun *.getAndUpdate (@target self: LSLAtomicReference, updateFunction: UnaryOperator): Object + { + result = this.value; + this.value = action CALL(updateFunction, [result]); + } + + + @final fun *.getOpaque (@target self: LSLAtomicReference): Object + { + // #problem: unable to model memory side-effects + result = this.value; + } + + + @final fun *.getPlain (@target self: LSLAtomicReference): Object + { + // #problem: unable to model memory side-effects + result = this.value; + } + + + @final fun *.lazySet (@target self: LSLAtomicReference, newValue: Object): void + { + // #problem: unable to delay variable update + this.value = newValue; + } + + + @final fun *.set (@target self: LSLAtomicReference, newValue: Object): void + { + this.value = newValue; + } + + + @final fun *.setOpaque (@target self: LSLAtomicReference, newValue: Object): void + { + // #problem: unable to model memory side-effects + this.value = newValue; + } + + + @final fun *.setPlain (@target self: LSLAtomicReference, newValue: Object): void + { + // #problem: unable to model memory side-effects + this.value = newValue; + } + + + @final fun *.setRelease (@target self: LSLAtomicReference, newValue: Object): void + { + // #problem: unable to model memory side-effects + this.value = newValue; + } + + + fun *.toString (@target self: LSLAtomicReference): String + { + result = action OBJECT_TO_STRING(this.value); + } + + + @final fun *.updateAndGet (@target self: LSLAtomicReference, updateFunction: UnaryOperator): Object + { + result = action CALL(updateFunction, [this.value]); + this.value = result; + } + + + @final fun *.weakCompareAndSet (@target self: LSLAtomicReference, expectedValue: Object, newValue: Object): boolean + { + // #problem: unable to delay variable update + result = this.value == expectedValue; + if (result) + this.value = newValue; + } + + + @final fun *.weakCompareAndSetAcquire (@target self: LSLAtomicReference, expectedValue: Object, newValue: Object): boolean + { + // #problem: unable to model memory side-effects + result = this.value == expectedValue; + if (result) + this.value = newValue; + } + + + @final fun *.weakCompareAndSetPlain (@target self: LSLAtomicReference, expectedValue: Object, newValue: Object): boolean + { + // #problem: unable to model memory side-effects + result = this.value == expectedValue; + if (result) + this.value = newValue; + } + + + @final fun *.weakCompareAndSetRelease (@target self: LSLAtomicReference, expectedValue: Object, newValue: Object): boolean + { + // #problem: unable to model memory side-effects + result = this.value == expectedValue; + if (result) + this.value = newValue; + } + + + @final fun *.weakCompareAndSetVolatile (@target self: LSLAtomicReference, expectedValue: Object, newValue: Object): boolean + { + // #problem: unable to model memory side-effects + result = this.value == expectedValue; + if (result) + this.value = newValue; + } + +} From a893a4b2766640607a67d93cc6298c2db201ca66 Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Fri, 3 Nov 2023 15:12:28 +0300 Subject: [PATCH 35/78] Removed redundant annotation for `AtomicReference` --- spec/java/util/concurrent/atomic/AtomicReference.lsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/java/util/concurrent/atomic/AtomicReference.lsl b/spec/java/util/concurrent/atomic/AtomicReference.lsl index 75eb3004..525f1e92 100644 --- a/spec/java/util/concurrent/atomic/AtomicReference.lsl +++ b/spec/java/util/concurrent/atomic/AtomicReference.lsl @@ -23,7 +23,7 @@ type AtomicReference // global aliases and type overrides @implements("java.io.Serializable") -@public type LSLAtomicReference +type LSLAtomicReference is java.util.concurrent.atomic.AtomicReference for AtomicReference { From 4920b6f10114434112e62a5e6e502d43c93318bc Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Sun, 5 Nov 2023 09:31:59 +0300 Subject: [PATCH 36/78] Minor improvements to `System` + Barebones declaration for `VM` and `Charset` classes --- spec/java/lang/ClassLoader.lsl | 26 +++ spec/java/lang/System.lsl | 5 +- spec/java/lang/System.main.lsl | 85 +++++++- spec/java/nio/charset/Charset.lsl | 195 ++++++++++++++++++ spec/jdk/internal/misc/VM.lsl | 58 ++++++ spec/jdk/internal/misc/VM.main.lsl | 235 ++++++++++++++++++++++ spec/jdk/internal/util/StaticProperty.lsl | 34 ++++ 7 files changed, 629 insertions(+), 9 deletions(-) create mode 100644 spec/java/lang/ClassLoader.lsl create mode 100644 spec/java/nio/charset/Charset.lsl create mode 100644 spec/jdk/internal/misc/VM.lsl create mode 100644 spec/jdk/internal/misc/VM.main.lsl create mode 100644 spec/jdk/internal/util/StaticProperty.lsl diff --git a/spec/java/lang/ClassLoader.lsl b/spec/java/lang/ClassLoader.lsl new file mode 100644 index 00000000..01d9c75b --- /dev/null +++ b/spec/java/lang/ClassLoader.lsl @@ -0,0 +1,26 @@ +//#! pragma: non-synthesizable +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/lang/ClassLoader.java"; + +// imports + +import java/io/Serializable; +import java/lang/String; + + +// primary semantic types + +@final type ClassLoader + is java.lang.ClassLoader + // #problem: no reflection support + for Serializable //, GenericDeclaration, Type, AnnotatedElement +{ +} + + +// global aliases and type overrides + diff --git a/spec/java/lang/System.lsl b/spec/java/lang/System.lsl index 1ff09bd4..64745bc3 100644 --- a/spec/java/lang/System.lsl +++ b/spec/java/lang/System.lsl @@ -14,6 +14,7 @@ import java/io/PrintStream; import java/lang/Object; import java/lang/String; import java/lang/Throwable; +import java/util/Properties; // primary semantic types @@ -55,10 +56,12 @@ import java/lang/Throwable; is java.lang.System for System { + @private @static var props: Properties = null; // WARNING: do not change! + // #todo: attach I/O streams from this @private @static var console: Console = null; - @public @static var in: InputStream = null; // WARNING: do not change! + @public @static var in: InputStream = null; // WARNING: do not change! @public @static var out: PrintStream = null; // WARNING: do not change! @public @static var err: PrintStream = null; // WARNING: do not change! diff --git a/spec/java/lang/System.main.lsl b/spec/java/lang/System.main.lsl index 5b408797..3a6a2d87 100644 --- a/spec/java/lang/System.main.lsl +++ b/spec/java/lang/System.main.lsl @@ -17,6 +17,7 @@ import java/nio/channels/Channel; import java/util/Map; import java/util/Properties; import java/util/ResourceBundle; +import jdk/internal/misc/VM; import java/lang/System; @@ -79,6 +80,14 @@ automaton SystemAutomaton } + @static proc _initProperties (): void + { + // #problem: no approximation for Properties + props = null;//new Properties(84); + // #todo + } + + // constructors @private constructor *.LSLSystem (@target self: LSLSystem) @@ -91,7 +100,7 @@ automaton SystemAutomaton @Phantom @static fun *.arraycopy (arg0: Object, arg1: int, arg2: Object, arg3: int, arg4: int): void { - // NOTE: using the original method + // WARNING: do not approximate this method - infinite recursion! } @@ -281,22 +290,82 @@ automaton SystemAutomaton // methods - // special: static initialization + // special: internal class initialization by the JRE - @Phantom @static fun *.__clinit__ (): void + @private @static proc initPhase1 (): void // WARNING: do not rename! { - // configure the standard stream + _initProperties(); + + //action CALL_METHOD(null as VM, "saveAndRemoveProperties", [props]); + + //action CALL_METHOD(null as StaticProperty, "javaHome", []); + //VersionProps.init(); + + // configure the standard streams val newInput: InputStream = new SymbolicInputStreamAutomaton(state = Initialized, maxSize = 1000, supportMarks = false, ); + // #todo: unsafe operations in BufferedInputStream in = newInput;//action DEBUG_DO("new java.io.BufferedInputStream(newInput)"); - - // configure the standard stream out = new System_PrintStreamAutomaton(state = Initialized); - - // configure the standard stream err = new System_PrintStreamAutomaton(state = Initialized); + + // #problem: no OS signal support + //Terminator.setup(); + + // JDK comment: system is fully initialized + action CALL_METHOD(null as VM, "initializeOSEnvironment", []); + + // #problem: no thread support + //val current: Thread = action CALL_METHOD(null as Thread, "currentThread", []); + //val threadGroup: ThreadGroup = action CALL_METHOD(current, "getThreadGroup", []); + //action CALL_METHOD(threadGroup, "add", [current]); + + // #todo + //setJavaLangAccess(); + + // #problem: too complex, package-private + //action CALL_METHOD(null as ClassLoader, "initLibraryPaths", []); + + // JDK comment: IMPORTANT: Ensure that this remains the last initialization action! + action CALL_METHOD(null as VM, "initLevel", [1]); + } + + + @private @static proc initPhase2 (): int // WARNING: do not change! + { + // #problem: java.lang.System#bootLayer initialization + + // JDK comment: module system initialized + action CALL_METHOD(null as VM, "initLevel", [2]); + + // JDK comment: JNI_OK + result = 0; + } + + + @private @static proc initPhase3 (): void // WARNING: do not rename! + { + // #todo + + // JDK comment: initializing the system class loader + action CALL_METHOD(null as VM, "initLevel", [3]); + + // #todo + + // JDK comment: system is fully initialized + action CALL_METHOD(null as VM, "initLevel", [4]); + } + + + // special: static initialization + + @Phantom @static fun *.__clinit__ (): void + { + initPhase1(); + initPhase2(); + initPhase3(); } } diff --git a/spec/java/nio/charset/Charset.lsl b/spec/java/nio/charset/Charset.lsl new file mode 100644 index 00000000..1a20566d --- /dev/null +++ b/spec/java/nio/charset/Charset.lsl @@ -0,0 +1,195 @@ +//#! pragma: non-synthesizable +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/nio/charset/Charset.java"; + +// imports + +import java/lang/Comparable; +import java/lang/Object; +import java/lang/String; +import java/nio/ByteBuffer; +import java/nio/CharBuffer; +import java/util/Locale; +import java/util/Set; +import java/util/SortedMap; + + +// local semantic types + +@implements("java.lang.Comparable") +@public @abstract type Charset + is java.nio.charset.Charset + for Object +{ +} + + +// automata + +automaton CharsetAutomaton +( +) +: Charset +{ + // states and shifts + + initstate Allocated; + state Initialized; + + shift Allocated -> Initialized by [ + // constructors + Charset, + // static operations + availableCharsets, + defaultCharset, + forName, + isSupported, + ]; + + shift Initialized -> self by [ + // instance methods + aliases, + canEncode, + compareTo (Charset, Charset), + compareTo (Charset, Object), + decode, + displayName (Charset), + displayName (Charset, Locale), + encode (Charset, CharBuffer), + encode (Charset, String), + equals, + hashCode, + isRegistered, + name, + toString, + ]; + + // internal variables + + // utilities + + // constructors + + @protected constructor *.Charset (@target self: Charset, canonicalName: String, aliases: array) + { + action TODO(); + } + + + // static methods + + @static fun *.availableCharsets (): SortedMap + { + action TODO(); + } + + + @static fun *.defaultCharset (): Charset + { + action TODO(); + } + + + @static fun *.forName (charsetName: String): Charset + { + action TODO(); + } + + + @static fun *.isSupported (charsetName: String): boolean + { + action TODO(); + } + + + // methods + + @final fun *.aliases (@target self: Charset): Set + { + action TODO(); + } + + + fun *.canEncode (@target self: Charset): boolean + { + action TODO(); + } + + + @final fun *.compareTo (@target self: Charset, that: Charset): int + { + action TODO(); + } + + + // within java.lang.Comparable + fun *.compareTo (@target self: Charset, arg0: Object): int + { + action TODO(); + } + + + @final fun *.decode (@target self: Charset, bb: ByteBuffer): CharBuffer + { + action TODO(); + } + + + fun *.displayName (@target self: Charset): String + { + action TODO(); + } + + + fun *.displayName (@target self: Charset, locale: Locale): String + { + action TODO(); + } + + + @final fun *.encode (@target self: Charset, cb: CharBuffer): ByteBuffer + { + action TODO(); + } + + + @final fun *.encode (@target self: Charset, str: String): ByteBuffer + { + action TODO(); + } + + + @final fun *.equals (@target self: Charset, ob: Object): boolean + { + action TODO(); + } + + + @final fun *.hashCode (@target self: Charset): int + { + action TODO(); + } + + + @final fun *.isRegistered (@target self: Charset): boolean + { + action TODO(); + } + + + @final fun *.name (@target self: Charset): String + { + action TODO(); + } + + + @final fun *.toString (@target self: Charset): String + { + action TODO(); + } + +} diff --git a/spec/jdk/internal/misc/VM.lsl b/spec/jdk/internal/misc/VM.lsl new file mode 100644 index 00000000..734ea298 --- /dev/null +++ b/spec/jdk/internal/misc/VM.lsl @@ -0,0 +1,58 @@ +//#! pragma: non-synthesizable +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/jdk/internal/misc/VM.java"; + +// imports + +import java/lang/Object; +import java/lang/String; +import java/util/Map; +import java/util/Properties; + + +// primary semantic types + +type VM + is jdk.internal.misc.VM + for Object +{ + @static fun *.initLevel(): int; + @static fun *.initLevel(value: int): void; + + @static fun *.isModuleSystemInited(): boolean; + @static fun *.isBooted(): boolean; + @static fun *.isShutdown(): boolean; + + @static fun *.shutdown(): boolean; + + @static fun *.getSavedProperty(key: String): String; + @static fun *.getSavedProperties(): Map; + + @static fun *.saveAndRemoveProperties(props: Properties); + + @static fun *.initializeOSEnvironment(): void; + + @static fun *.getRuntimeArguments(): array; +} + + +val VM_JAVA_LANG_SYSTEM_INITED: int = 1; +val VM_MODULE_SYSTEM_INITED: int = 2; +val VM_SYSTEM_LOADER_INITIALIZING: int = 3; +val VM_SYSTEM_BOOTED: int = 4; +val VM_SYSTEM_SHUTDOWN: int = 5; + + +// global aliases and type overrides + +type LSLVM + is jdk.internal.misc.VM + for VM +{ + @private @static @volatile var initLevel: int = 0; // WARNING: do not rename or change the type! +} + diff --git a/spec/jdk/internal/misc/VM.main.lsl b/spec/jdk/internal/misc/VM.main.lsl new file mode 100644 index 00000000..23b8cea4 --- /dev/null +++ b/spec/jdk/internal/misc/VM.main.lsl @@ -0,0 +1,235 @@ +//#! pragma: non-synthesizable +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/jdk/internal/misc/VM.java"; + +// imports + +import java/lang/Class; +import java/lang/ClassLoader; +import java/lang/Object; +import java/lang/String; +import java/util/Map; +import java/util/Properties; + +import jdk/internal/misc/VM; + + +// automata + +automaton VMAutomaton +( +) +: LSLVM +{ + // states and shifts + + initstate Initialized; + + shift Initialized -> self by [ + // static operations + addFinalRefCount, + awaitInitLevel, + getFinalRefCount, + getNanoTimeAdjustment, + getPeakFinalRefCount, + getRuntimeArguments, + getSavedProperties, + getSavedProperty, + getegid, + geteuid, + getgid, + getuid, + initLevel (), + initLevel (int), + initializeFromArchive, + initializeOSEnvironment, + isBooted, + isDirectMemoryPageAligned, + isModuleSystemInited, + isSetUID, + isShutdown, + isSystemDomainLoader, + latestUserDefinedLoader, + maxDirectMemory, + saveAndRemoveProperties, + shutdown, + toThreadState, + ]; + + // internal variables + + // utilities + + // constructors + + // static methods + + @static fun *.addFinalRefCount (n: int): void + { + action TODO(); + } + + + @throws(["java.lang.InterruptedException"]) + @static fun *.awaitInitLevel (value: int): void + { + action TODO(); + } + + + @static fun *.getFinalRefCount (): int + { + action TODO(); + } + + + @static fun *.getNanoTimeAdjustment (arg0: long): long + { + action TODO(); + } + + + @static fun *.getPeakFinalRefCount (): int + { + action TODO(); + } + + + @static fun *.getRuntimeArguments (): array + { + action TODO(); + } + + + @static fun *.getSavedProperties (): Map + { + action TODO(); + } + + + @static fun *.getSavedProperty (key: String): String + { + action TODO(); + } + + + @static fun *.getegid (): long + { + action TODO(); + } + + + @static fun *.geteuid (): long + { + action TODO(); + } + + + @static fun *.getgid (): long + { + action TODO(); + } + + + @static fun *.getuid (): long + { + action TODO(); + } + + + @static fun *.initLevel (): int + { + action TODO(); + } + + + @static fun *.initLevel (value: int): void + { + action TODO(); + } + + + @static fun *.initializeFromArchive (arg0: Class): void + { + action TODO(); + } + + + @static fun *.initializeOSEnvironment (): void + { + // doing nothing + } + + + @static fun *.isBooted (): boolean + { + action TODO(); + } + + + @static fun *.isDirectMemoryPageAligned (): boolean + { + action TODO(); + } + + + @static fun *.isModuleSystemInited (): boolean + { + action TODO(); + } + + + @static fun *.isSetUID (): boolean + { + action TODO(); + } + + + @static fun *.isShutdown (): boolean + { + action TODO(); + } + + + @static fun *.isSystemDomainLoader (loader: ClassLoader): boolean + { + action TODO(); + } + + + @static fun *.latestUserDefinedLoader (): ClassLoader + { + action TODO(); + } + + + @static fun *.maxDirectMemory (): long + { + action TODO(); + } + + + @static fun *.saveAndRemoveProperties (props: Properties): void + { + action TODO(); + } + + + @static fun *.shutdown (): void + { + action TODO(); + } + + + @static fun *.toThreadState (threadStatus: int): Thread_State + { + action TODO(); + } + + + // methods +} diff --git a/spec/jdk/internal/util/StaticProperty.lsl b/spec/jdk/internal/util/StaticProperty.lsl new file mode 100644 index 00000000..c7dcf78b --- /dev/null +++ b/spec/jdk/internal/util/StaticProperty.lsl @@ -0,0 +1,34 @@ +//#! pragma: non-synthesizable +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/jdk/internal/util/StaticProperty.java"; + +// imports + +import java/lang/Object; +import java/lang/String; + + +// primary semantic types + +type StaticProperty + is jdk.internal.util.StaticProperty + for Object +{ + @static fun *.javaHome(): String; + + @static fun *.jdkSerialFilter(): String; + + @static fun *.userDir(): String; + + @static fun *.userHome(): String; + + @static fun *.userName(): String; +} + + +// global aliases and type overrides + From d5dd7ecce0454f847f02270ec00f0744d9b6df33 Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Tue, 7 Nov 2023 13:48:32 +0300 Subject: [PATCH 37/78] Prepared `Charset` approximation skeleton for the translator + Added more type declarations --- spec/java/lang/Readable.lsl | 26 ++++ spec/java/nio/CharBuffer.lsl | 27 ++++ spec/java/nio/charset/Charset.lsl | 181 ++----------------------- spec/java/nio/charset/Charset.main.lsl | 179 ++++++++++++++++++++++++ spec/java/util/SortedMap.lsl | 24 ++++ 5 files changed, 264 insertions(+), 173 deletions(-) create mode 100644 spec/java/lang/Readable.lsl create mode 100644 spec/java/nio/CharBuffer.lsl create mode 100644 spec/java/nio/charset/Charset.main.lsl create mode 100644 spec/java/util/SortedMap.lsl diff --git a/spec/java/lang/Readable.lsl b/spec/java/lang/Readable.lsl new file mode 100644 index 00000000..4d2ab23d --- /dev/null +++ b/spec/java/lang/Readable.lsl @@ -0,0 +1,26 @@ +//#! pragma: non-synthesizable +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/lang/Readable.java"; + +// imports + +import java/lang/Object; +import java/nio/Buffer; + + +// primary semantic types + +@interface type Readable + is java.lang.Readable + for Object +{ + @throws(["java.io.IOException"]) + fun *.read(cb: Buffer): int; // #problem: cyclic dependency +} + + +// global aliases and type overrides diff --git a/spec/java/nio/CharBuffer.lsl b/spec/java/nio/CharBuffer.lsl new file mode 100644 index 00000000..5a1c2dbf --- /dev/null +++ b/spec/java/nio/CharBuffer.lsl @@ -0,0 +1,27 @@ +//#! pragma: non-synthesizable +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/nio/CharBuffer.java"; + +// imports + +import java/lang/Appendable; +import java/lang/CharSequence; +import java/lang/Comparable; +import java/lang/Readable; +import java/nio/Buffer; + + +// primary semantic types + +@abstract type CharBuffer + is java.nio.CharBuffer + for Buffer, Comparable, Appendable, CharSequence, Readable +{ +} + + +// global aliases and type overrides diff --git a/spec/java/nio/charset/Charset.lsl b/spec/java/nio/charset/Charset.lsl index 1a20566d..757522f9 100644 --- a/spec/java/nio/charset/Charset.lsl +++ b/spec/java/nio/charset/Charset.lsl @@ -9,187 +9,22 @@ library std // imports import java/lang/Comparable; -import java/lang/Object; -import java/lang/String; -import java/nio/ByteBuffer; -import java/nio/CharBuffer; -import java/util/Locale; -import java/util/Set; -import java/util/SortedMap; -// local semantic types +// primary semantic types -@implements("java.lang.Comparable") -@public @abstract type Charset +@abstract type Charset is java.nio.charset.Charset - for Object + for Comparable { } -// automata +// global aliases and type overrides -automaton CharsetAutomaton -( -) -: Charset +@implements("java.lang.Comparable") +@abstract type LSLCharset + is java.nio.charset.Charset + for Charset { - // states and shifts - - initstate Allocated; - state Initialized; - - shift Allocated -> Initialized by [ - // constructors - Charset, - // static operations - availableCharsets, - defaultCharset, - forName, - isSupported, - ]; - - shift Initialized -> self by [ - // instance methods - aliases, - canEncode, - compareTo (Charset, Charset), - compareTo (Charset, Object), - decode, - displayName (Charset), - displayName (Charset, Locale), - encode (Charset, CharBuffer), - encode (Charset, String), - equals, - hashCode, - isRegistered, - name, - toString, - ]; - - // internal variables - - // utilities - - // constructors - - @protected constructor *.Charset (@target self: Charset, canonicalName: String, aliases: array) - { - action TODO(); - } - - - // static methods - - @static fun *.availableCharsets (): SortedMap - { - action TODO(); - } - - - @static fun *.defaultCharset (): Charset - { - action TODO(); - } - - - @static fun *.forName (charsetName: String): Charset - { - action TODO(); - } - - - @static fun *.isSupported (charsetName: String): boolean - { - action TODO(); - } - - - // methods - - @final fun *.aliases (@target self: Charset): Set - { - action TODO(); - } - - - fun *.canEncode (@target self: Charset): boolean - { - action TODO(); - } - - - @final fun *.compareTo (@target self: Charset, that: Charset): int - { - action TODO(); - } - - - // within java.lang.Comparable - fun *.compareTo (@target self: Charset, arg0: Object): int - { - action TODO(); - } - - - @final fun *.decode (@target self: Charset, bb: ByteBuffer): CharBuffer - { - action TODO(); - } - - - fun *.displayName (@target self: Charset): String - { - action TODO(); - } - - - fun *.displayName (@target self: Charset, locale: Locale): String - { - action TODO(); - } - - - @final fun *.encode (@target self: Charset, cb: CharBuffer): ByteBuffer - { - action TODO(); - } - - - @final fun *.encode (@target self: Charset, str: String): ByteBuffer - { - action TODO(); - } - - - @final fun *.equals (@target self: Charset, ob: Object): boolean - { - action TODO(); - } - - - @final fun *.hashCode (@target self: Charset): int - { - action TODO(); - } - - - @final fun *.isRegistered (@target self: Charset): boolean - { - action TODO(); - } - - - @final fun *.name (@target self: Charset): String - { - action TODO(); - } - - - @final fun *.toString (@target self: Charset): String - { - action TODO(); - } - } diff --git a/spec/java/nio/charset/Charset.main.lsl b/spec/java/nio/charset/Charset.main.lsl new file mode 100644 index 00000000..b9b26846 --- /dev/null +++ b/spec/java/nio/charset/Charset.main.lsl @@ -0,0 +1,179 @@ +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/nio/charset/Charset.java"; + +// imports + +import java/lang/Object; +import java/lang/String; +import java/nio/ByteBuffer; +import java/nio/CharBuffer; +import java/util/Locale; +import java/util/Set; +import java/util/SortedMap; + +import java/nio/charset/Charset; + + +// automata + +automaton CharsetAutomaton +( +) +: LSLCharset +{ + // states and shifts + + initstate Allocated; + state Initialized; + + shift Allocated -> Initialized by [ + // constructors + LSLCharset, + + // static operations + availableCharsets, + defaultCharset, + forName, + isSupported, + ]; + + shift Initialized -> self by [ + // instance methods + aliases, + canEncode, + compareTo, + decode, + displayName (LSLCharset), + displayName (LSLCharset, Locale), + encode (LSLCharset, CharBuffer), + encode (LSLCharset, String), + equals, + hashCode, + isRegistered, + name, + toString, + ]; + + // internal variables + + // utilities + + // constructors + + @protected constructor *.LSLCharset (@target self: LSLCharset, canonicalName: String, aliases: array) + { + action TODO(); + } + + + // static methods + + @static fun *.availableCharsets (): SortedMap + { + action TODO(); + } + + + @static fun *.defaultCharset (): Charset + { + action TODO(); + } + + + @static fun *.forName (charsetName: String): Charset + { + action TODO(); + } + + + @static fun *.isSupported (charsetName: String): boolean + { + action TODO(); + } + + + // methods + + @final fun *.aliases (@target self: LSLCharset): Set + { + action TODO(); + } + + + fun *.canEncode (@target self: LSLCharset): boolean + { + // just like the original + result = true; + } + + + @final fun *.compareTo (@target self: LSLCharset, that: Charset): int + { + action TODO(); + } + + + @final fun *.decode (@target self: LSLCharset, bb: ByteBuffer): CharBuffer + { + action TODO(); + } + + + fun *.displayName (@target self: LSLCharset): String + { + action TODO(); + } + + + fun *.displayName (@target self: LSLCharset, locale: Locale): String + { + action TODO(); + } + + + @final fun *.encode (@target self: LSLCharset, cb: CharBuffer): ByteBuffer + { + action TODO(); + } + + + @final fun *.encode (@target self: LSLCharset, str: String): ByteBuffer + { + action TODO(); + } + + + @final fun *.equals (@target self: LSLCharset, ob: Object): boolean + { + action TODO(); + } + + + @final fun *.hashCode (@target self: LSLCharset): int + { + action TODO(); + } + + + @final fun *.isRegistered (@target self: LSLCharset): boolean + { + action TODO(); + } + + + @final fun *.name (@target self: LSLCharset): String + { + action TODO(); + } + + + @final fun *.toString (@target self: LSLCharset): String + { + action TODO(); + } + +} diff --git a/spec/java/util/SortedMap.lsl b/spec/java/util/SortedMap.lsl new file mode 100644 index 00000000..414f8ca4 --- /dev/null +++ b/spec/java/util/SortedMap.lsl @@ -0,0 +1,24 @@ +//#! pragma: non-synthesizable +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/util/SortedMap.java"; + +// imports + +import java/util/Map; + + +// primary semantic types + +@interface type SortedMap + is java.util.SortedMap + for Map +{ +} + + +// global aliases and type overrides + From 3ef1c1583bc00b2e9a2bb8170863990a9d1fe70a Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Wed, 8 Nov 2023 16:14:17 +0300 Subject: [PATCH 38/78] Corrections for experimental type conversion --- spec/java/lang/Integer.main.lsl | 14 ++++---- spec/java/lang/StringBuffer.main.lsl | 5 +-- spec/java/lang/System.StdOut.lsl | 18 +++++----- spec/java/nio/charset/Charset.main.lsl | 4 +-- spec/java/util/ArrayList.Spliterator.lsl | 2 +- .../util/ArrayList.SubList.Spliterator.lsl | 2 +- spec/java/util/HashSet.Spliterator.lsl | 2 +- spec/java/util/LinkedHashSet.Spliterator.lsl | 2 +- spec/java/util/Optional.automata.lsl | 35 +++++++++---------- spec/java/util/OptionalDouble.automata.lsl | 6 ++-- spec/java/util/OptionalInt.automata.lsl | 6 ++-- spec/java/util/OptionalLong.automata.lsl | 6 ++-- 12 files changed, 49 insertions(+), 53 deletions(-) diff --git a/spec/java/lang/Integer.main.lsl b/spec/java/lang/Integer.main.lsl index 6664345f..fb44d568 100644 --- a/spec/java/lang/Integer.main.lsl +++ b/spec/java/lang/Integer.main.lsl @@ -125,7 +125,7 @@ automaton IntegerAutomaton @throws(["java.lang.NumberFormatException"]) - @Phantom @static fun *.decode (nm: String): LSLInteger + @Phantom @static fun *.decode (nm: String): Integer { // NOTE: using the original method } @@ -137,19 +137,19 @@ automaton IntegerAutomaton } - @Phantom @static fun *.getInteger (nm: String): LSLInteger + @Phantom @static fun *.getInteger (nm: String): Integer { // NOTE: using the original method } - @Phantom @static fun *.getInteger (nm: String, _val: Integer): LSLInteger + @Phantom @static fun *.getInteger (nm: String, _val: Integer): Integer { // NOTE: using the original method } - @Phantom @static fun *.getInteger (nm: String, _val: int): LSLInteger + @Phantom @static fun *.getInteger (nm: String, _val: int): Integer { // NOTE: using the original method } @@ -330,20 +330,20 @@ automaton IntegerAutomaton @throws(["java.lang.NumberFormatException"]) - @Phantom @static fun *.valueOf (s: String): LSLInteger + @Phantom @static fun *.valueOf (s: String): Integer { // NOTE: using the original method } @throws(["java.lang.NumberFormatException"]) - @Phantom @static fun *.valueOf (s: String, radix: int): LSLInteger + @Phantom @static fun *.valueOf (s: String, radix: int): Integer { // NOTE: using the original method } - @static fun *.valueOf (i: int): LSLInteger + @static fun *.valueOf (i: int): Integer { result = new IntegerAutomaton(state = Initialized, value = i diff --git a/spec/java/lang/StringBuffer.main.lsl b/spec/java/lang/StringBuffer.main.lsl index 64d81365..c9b6d9ee 100644 --- a/spec/java/lang/StringBuffer.main.lsl +++ b/spec/java/lang/StringBuffer.main.lsl @@ -385,12 +385,13 @@ automaton StringBufferAutomaton @synchronized fun *.append (@target self: StringBuffer, sb: StringBuffer): StringBuffer { - if (sb == null) + val s: Object = sb; + if (s == null) { this.storage += "null"; this.length += 4; } - else if (sb has StringBufferAutomaton) + else if (s has StringBufferAutomaton) { this.storage += StringBufferAutomaton(sb).storage; this.length += StringBufferAutomaton(sb).length; diff --git a/spec/java/lang/System.StdOut.lsl b/spec/java/lang/System.StdOut.lsl index 734012f9..32a0501b 100644 --- a/spec/java/lang/System.StdOut.lsl +++ b/spec/java/lang/System.StdOut.lsl @@ -97,7 +97,7 @@ automaton System_PrintStreamAutomaton _checkOpen(); - result = self; + result = self as Object as PrintStream; } @@ -112,7 +112,7 @@ automaton System_PrintStreamAutomaton _checkOpen(); - result = self; + result = self as Object as PrintStream; } @@ -120,7 +120,7 @@ automaton System_PrintStreamAutomaton { _checkOpen(); - result = self; + result = self as Object as PrintStream; } @@ -149,7 +149,7 @@ automaton System_PrintStreamAutomaton _checkOpen(); - result = self; + result = self as Object as PrintStream; } @@ -160,7 +160,7 @@ automaton System_PrintStreamAutomaton _checkOpen(); - result = self; + result = self as Object as PrintStream; } @@ -228,7 +228,7 @@ automaton System_PrintStreamAutomaton _checkOpen(); - result = self; + result = self as Object as PrintStream; } @@ -239,7 +239,7 @@ automaton System_PrintStreamAutomaton _checkOpen(); - result = self; + result = self as Object as PrintStream; } @@ -341,9 +341,7 @@ automaton System_PrintStreamAutomaton @Phantom @static fun *.__super__ (): array { result = [ - new VoidOutputStreamAutomaton(state = Initialized, - closed = false - ) + null as OutputStream, ]; } diff --git a/spec/java/nio/charset/Charset.main.lsl b/spec/java/nio/charset/Charset.main.lsl index b9b26846..0bb1507c 100644 --- a/spec/java/nio/charset/Charset.main.lsl +++ b/spec/java/nio/charset/Charset.main.lsl @@ -78,13 +78,13 @@ automaton CharsetAutomaton } - @static fun *.defaultCharset (): Charset + @static fun *.defaultCharset (): LSLCharset { action TODO(); } - @static fun *.forName (charsetName: String): Charset + @static fun *.forName (charsetName: String): LSLCharset { action TODO(); } diff --git a/spec/java/util/ArrayList.Spliterator.lsl b/spec/java/util/ArrayList.Spliterator.lsl index ae244d93..101905ee 100644 --- a/spec/java/util/ArrayList.Spliterator.lsl +++ b/spec/java/util/ArrayList.Spliterator.lsl @@ -193,7 +193,7 @@ automaton ArrayList_SpliteratorAutomaton } - fun *.trySplit (@target self: ArrayList_Spliterator): ArrayList_Spliterator + fun *.trySplit (@target self: ArrayList_Spliterator): Spliterator { val hi: int = _getFence(); val lo: int = this.index; diff --git a/spec/java/util/ArrayList.SubList.Spliterator.lsl b/spec/java/util/ArrayList.SubList.Spliterator.lsl index b9114210..ee63f1e9 100644 --- a/spec/java/util/ArrayList.SubList.Spliterator.lsl +++ b/spec/java/util/ArrayList.SubList.Spliterator.lsl @@ -180,7 +180,7 @@ automaton ArrayList_SubList_SpliteratorAutomaton } - fun *.trySplit (@target self: ArrayList_SubList_Spliterator): ArrayList_SubList_Spliterator + fun *.trySplit (@target self: ArrayList_SubList_Spliterator): Spliterator { val hi: int = _getFence(); val lo: int = this.index; diff --git a/spec/java/util/HashSet.Spliterator.lsl b/spec/java/util/HashSet.Spliterator.lsl index 0eb64ad2..597191d1 100644 --- a/spec/java/util/HashSet.Spliterator.lsl +++ b/spec/java/util/HashSet.Spliterator.lsl @@ -191,7 +191,7 @@ automaton HashSet_KeySpliteratorAutomaton } - fun *.trySplit (@target self: HashSet_KeySpliterator): HashSet_KeySpliterator + fun *.trySplit (@target self: HashSet_KeySpliterator): Spliterator { action ASSUME(this.parent != null); diff --git a/spec/java/util/LinkedHashSet.Spliterator.lsl b/spec/java/util/LinkedHashSet.Spliterator.lsl index 846aadc1..f356fbc5 100644 --- a/spec/java/util/LinkedHashSet.Spliterator.lsl +++ b/spec/java/util/LinkedHashSet.Spliterator.lsl @@ -186,7 +186,7 @@ automaton LinkedHashSet_KeySpliteratorAutomaton } - fun *.trySplit (@target self: LinkedHashSet_KeySpliterator): LinkedHashSet_KeySpliterator + fun *.trySplit (@target self: LinkedHashSet_KeySpliterator): Spliterator { action ASSUME(this.parent != null); diff --git a/spec/java/util/Optional.automata.lsl b/spec/java/util/Optional.automata.lsl index ad78ee8f..0ece893e 100644 --- a/spec/java/util/Optional.automata.lsl +++ b/spec/java/util/Optional.automata.lsl @@ -18,7 +18,10 @@ import java/util/Optional; // globals // #problem: type parameter is missing -val EMPTY_OPTIONAL: LSLOptional = new OptionalAutomaton(state=Initialized, value=null); +val EMPTY_OPTIONAL: Optional + = new OptionalAutomaton(state = Initialized, + value = null + ); // automata @@ -70,12 +73,6 @@ automaton OptionalAutomaton // utilities - @static proc _makeEmpty (): LSLOptional - { - result = EMPTY_OPTIONAL; - } - - @AutoInline @Phantom proc _throwNPE (): void { action THROW_NEW("java.lang.NullPointerException", []); @@ -112,15 +109,15 @@ automaton OptionalAutomaton @Parameterized(["T"]) @ParameterizedResult(["T"]) - @static fun *.empty (): LSLOptional + @static fun *.empty (): Optional { - result = _makeEmpty(); + result = EMPTY_OPTIONAL; } @Parameterized(["T"]) @ParameterizedResult(["T"]) - @static fun *.of (obj: Object): LSLOptional + @static fun *.of (obj: Object): Optional { requires obj != null; @@ -135,10 +132,10 @@ automaton OptionalAutomaton @Parameterized(["T"]) @ParameterizedResult(["T"]) - @static fun *.ofNullable (obj: Object): LSLOptional + @static fun *.ofNullable (obj: Object): Optional { if (obj == null) - result = _makeEmpty(); + result = EMPTY_OPTIONAL; else result = new OptionalAutomaton(state = Initialized, value = obj @@ -191,7 +188,7 @@ automaton OptionalAutomaton if (sat) result = self; else - result = _makeEmpty(); + result = EMPTY_OPTIONAL as Object as LSLOptional; } } @@ -200,7 +197,7 @@ automaton OptionalAutomaton @ParameterizedResult(["U"]) // #problem fun *.flatMap (@target @Parameterized(["T"]) self: LSLOptional, - @Parameterized(["? super T", "? extends LSLOptional"]) mapper: Function): LSLOptional + @Parameterized(["? super T", "? extends LSLOptional"]) mapper: Function): Optional { requires mapper != null; @@ -209,12 +206,12 @@ automaton OptionalAutomaton if (this.value == null) { - result = _makeEmpty(); + result = EMPTY_OPTIONAL; } else { // #problem: cast action return value to LSLOptional - result = action CALL(mapper, [this.value]) as LSLOptional; + result = action CALL(mapper, [this.value]) as Optional; if (result == null) _throwNPE(); @@ -292,7 +289,7 @@ automaton OptionalAutomaton @Parameterized(["U"]) @ParameterizedResult(["U"]) fun *.map (@target @Parameterized(["T"]) self: LSLOptional, - @Parameterized(["? super T", "? extends U"]) mapper: Function): LSLOptional + @Parameterized(["? super T", "? extends U"]) mapper: Function): Optional { requires mapper != null; @@ -301,7 +298,7 @@ automaton OptionalAutomaton if (this.value == null) { - result = _makeEmpty(); + result = EMPTY_OPTIONAL; } else { @@ -309,7 +306,7 @@ automaton OptionalAutomaton val mappedValue: Object = action CALL(mapper, [this.value]); if (mappedValue == null) - result = _makeEmpty(); + result = EMPTY_OPTIONAL; else // #problem: how to parameterize the result? result = new OptionalAutomaton(state = Initialized, diff --git a/spec/java/util/OptionalDouble.automata.lsl b/spec/java/util/OptionalDouble.automata.lsl index ab09955b..3112617b 100644 --- a/spec/java/util/OptionalDouble.automata.lsl +++ b/spec/java/util/OptionalDouble.automata.lsl @@ -17,7 +17,7 @@ import java/util/OptionalDouble; // globals -val EMPTY_OPTIONAL_DOUBLE: LSLOptionalDouble +val EMPTY_OPTIONAL_DOUBLE: OptionalDouble = new OptionalDoubleAutomaton(state = Initialized, value = 0.0, present = false @@ -90,13 +90,13 @@ automaton OptionalDoubleAutomaton // static methods - @static fun *.empty (): LSLOptionalDouble + @static fun *.empty (): OptionalDouble { result = EMPTY_OPTIONAL_DOUBLE; } - @static fun *.of (x: double): LSLOptionalDouble + @static fun *.of (x: double): OptionalDouble { result = new OptionalDoubleAutomaton(state = Initialized, value = x, diff --git a/spec/java/util/OptionalInt.automata.lsl b/spec/java/util/OptionalInt.automata.lsl index 0bef4254..a5a92523 100644 --- a/spec/java/util/OptionalInt.automata.lsl +++ b/spec/java/util/OptionalInt.automata.lsl @@ -17,7 +17,7 @@ import java/util/OptionalInt; // globals -val EMPTY_OPTIONAL_INT: LSLOptionalInt +val EMPTY_OPTIONAL_INT: OptionalInt = new OptionalIntAutomaton(state = Initialized, value = 0, present = false @@ -90,13 +90,13 @@ automaton OptionalIntAutomaton // static methods - @static fun *.empty (): LSLOptionalInt + @static fun *.empty (): OptionalInt { result = EMPTY_OPTIONAL_INT; } - @static fun *.of (x: int): LSLOptionalInt + @static fun *.of (x: int): OptionalInt { result = new OptionalIntAutomaton(state = Initialized, value = x, diff --git a/spec/java/util/OptionalLong.automata.lsl b/spec/java/util/OptionalLong.automata.lsl index e8af3b29..353a33ed 100644 --- a/spec/java/util/OptionalLong.automata.lsl +++ b/spec/java/util/OptionalLong.automata.lsl @@ -17,7 +17,7 @@ import java/util/OptionalLong; // globals -val EMPTY_OPTIONAL_LONG: LSLOptionalLong +val EMPTY_OPTIONAL_LONG: OptionalLong = new OptionalLongAutomaton(state = Initialized, value = 0L, present = false @@ -90,13 +90,13 @@ automaton OptionalLongAutomaton // static methods - @static fun *.empty (): LSLOptionalLong + @static fun *.empty (): OptionalLong { result = EMPTY_OPTIONAL_LONG; } - @static fun *.of (x: long): LSLOptionalLong + @static fun *.of (x: long): OptionalLong { result = new OptionalLongAutomaton(state = Initialized, value = x, From 2f191d31b3d9dfb11f6aa9481759bf2992ca0e38 Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Wed, 8 Nov 2023 16:58:45 +0300 Subject: [PATCH 39/78] Temporarily disabled error initialization in `System::initPhase1` due to `NullPointerException` --- spec/java/lang/System.main.lsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/java/lang/System.main.lsl b/spec/java/lang/System.main.lsl index 3a6a2d87..85003547 100644 --- a/spec/java/lang/System.main.lsl +++ b/spec/java/lang/System.main.lsl @@ -315,7 +315,7 @@ automaton SystemAutomaton //Terminator.setup(); // JDK comment: system is fully initialized - action CALL_METHOD(null as VM, "initializeOSEnvironment", []); + //action CALL_METHOD(null as VM, "initializeOSEnvironment", []); <- NPE // #problem: no thread support //val current: Thread = action CALL_METHOD(null as Thread, "currentThread", []); From 2a47a5bba7c88bcb79a040c203d288c7aec5bb83 Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Thu, 9 Nov 2023 23:51:30 +0300 Subject: [PATCH 40/78] Improvements to `System` --- spec/java/lang/System.lsl | 5 +++- spec/java/lang/System.main.lsl | 54 ++++++++++++++++++++++++---------- 2 files changed, 43 insertions(+), 16 deletions(-) diff --git a/spec/java/lang/System.lsl b/spec/java/lang/System.lsl index 64745bc3..b207c9d6 100644 --- a/spec/java/lang/System.lsl +++ b/spec/java/lang/System.lsl @@ -12,6 +12,7 @@ import java/io/Console; import java/io/InputStream; import java/io/PrintStream; import java/lang/Object; +import java/lang/SecurityManager; import java/lang/String; import java/lang/Throwable; import java/util/Properties; @@ -56,7 +57,8 @@ import java/util/Properties; is java.lang.System for System { - @private @static var props: Properties = null; // WARNING: do not change! + @private @static @volatile var security: SecurityManager = null; // WARNING: do not change! + @private @static var props: Properties = null; // WARNING: do not change! // #todo: attach I/O streams from this @private @static var console: Console = null; @@ -70,6 +72,7 @@ import java/util/Properties; } val SYSTEM_IS_WINDOWS: boolean = action SYMBOLIC("boolean"); +val SYSTEM_IS_MAC: boolean = !SYSTEM_IS_WINDOWS && action SYMBOLIC("boolean"); @GenerateMe diff --git a/spec/java/lang/System.main.lsl b/spec/java/lang/System.main.lsl index 85003547..041e18b1 100644 --- a/spec/java/lang/System.main.lsl +++ b/spec/java/lang/System.main.lsl @@ -98,7 +98,7 @@ automaton SystemAutomaton // static methods - @Phantom @static fun *.arraycopy (arg0: Object, arg1: int, arg2: Object, arg3: int, arg4: int): void + @Phantom @static fun *.arraycopy (src: Object, srcPos: int, dest: Object, destPos: int, length: int): void { // WARNING: do not approximate this method - infinite recursion! } @@ -125,7 +125,7 @@ automaton SystemAutomaton @static fun *.exit (status: int): void { - // #problem: not way to forcebly shutdown the program execution + // #problem: not way to forcibly shutdown the program execution action ERROR("Unexpected shutdown"); } @@ -175,13 +175,21 @@ automaton SystemAutomaton @Phantom @static fun *.getenv (): Map { // NOTE: using the original method + + // #todo: provide an actual map with symbolic values } @static fun *.getenv (name: String): String { - result = action SYMBOLIC("java.lang.String"); - action ASSUME(result != null); + val symbolCount: int = action SYMBOLIC("int"); + action ASSUME(symbolCount >= 0); + action ASSUME(symbolCount < 256); + + val symbols: array = action SYMBOLIC_ARRAY("char", symbolCount); + action ASSUME(symbols != null); + + result = action OBJECT_TO_STRING(symbols); } @@ -220,9 +228,20 @@ automaton SystemAutomaton } - @Phantom @static fun *.mapLibraryName (arg0: String): String + @static fun *.mapLibraryName (libname: String): String { - // NOTE: using the original method + if (libname == null) + _throwNPE(); + + // https://hg.openjdk.org/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/native/java/lang/System.c#l466 + val len: int = action CALL_METHOD(libname, "length", []); + if (len > 240) + action THROW_NEW("java.lang.IllegalArgumentException", ["name too long"]); + + if (SYSTEM_IS_WINDOWS) + result = libname + ".dll"; + else + result = "lib" + libname + ".so"; } @@ -233,10 +252,9 @@ automaton SystemAutomaton } - @Phantom @static fun *.runFinalization (): void + @static fun *.runFinalization (): void { - // #problem: what do we need to do here? - action TODO(); + // #problem: it is not possible to call finalizer method on an arbitrary object } @@ -270,15 +288,19 @@ automaton SystemAutomaton } - @Phantom @static fun *.setProperties (props: Properties): void + @static fun *.setProperties (p: Properties): void { - // NOTE: using the original method + // #todo: improve after there will be some implementation for Properties + props = p; } - @Phantom @static fun *.setProperty (key: String, value: String): String + @static fun *.setProperty (key: String, value: String): String { - // NOTE: using the original method + if (key == null) + _throwNPE(); + + // #todo: change the property } @@ -347,12 +369,14 @@ automaton SystemAutomaton @private @static proc initPhase3 (): void // WARNING: do not rename! { - // #todo + // #problem: reflective access during security manager initialization + // #todo: check property 'java.security.manager' + security = null;//new SecurityManagerAutomaton(state = Initialized); // JDK comment: initializing the system class loader action CALL_METHOD(null as VM, "initLevel", [3]); - // #todo + // #problem: java.lang.ClassLoader#initSystemClassLoader is package-private // JDK comment: system is fully initialized action CALL_METHOD(null as VM, "initLevel", [4]); From f4319e89d94eee4a5146ebb4869edb51e0bb8470 Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Thu, 9 Nov 2023 23:54:30 +0300 Subject: [PATCH 41/78] Minor fixes to `System` --- spec/java/lang/System.lsl | 5 +++-- spec/java/lang/System.main.lsl | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/spec/java/lang/System.lsl b/spec/java/lang/System.lsl index b207c9d6..df98aac0 100644 --- a/spec/java/lang/System.lsl +++ b/spec/java/lang/System.lsl @@ -71,8 +71,9 @@ import java/util/Properties; @private @static val NANOTIME_WARP_MAX: long = 1000L; } -val SYSTEM_IS_WINDOWS: boolean = action SYMBOLIC("boolean"); -val SYSTEM_IS_MAC: boolean = !SYSTEM_IS_WINDOWS && action SYMBOLIC("boolean"); +// WARNING: declaration order is important! +val SYSTEM_IS_MAC: boolean = action SYMBOLIC("boolean"); +val SYSTEM_IS_WINDOWS: boolean = !SYSTEM_IS_MAC && action SYMBOLIC("boolean"); @GenerateMe diff --git a/spec/java/lang/System.main.lsl b/spec/java/lang/System.main.lsl index 041e18b1..eca43eff 100644 --- a/spec/java/lang/System.main.lsl +++ b/spec/java/lang/System.main.lsl @@ -240,6 +240,8 @@ automaton SystemAutomaton if (SYSTEM_IS_WINDOWS) result = libname + ".dll"; + else if (SYSTEM_IS_MAC) + result = "lib" + libname + ".dylib"; else result = "lib" + libname + ".so"; } From a067c802af8a0afa2a11706e5e325cdb72de88a7 Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Fri, 10 Nov 2023 03:10:23 +0300 Subject: [PATCH 42/78] Added basic collection of properties within `System` --- spec/java/lang/System.lsl | 2 + spec/java/lang/System.main.lsl | 141 ++++++++++++++++++++++++++++++--- 2 files changed, 133 insertions(+), 10 deletions(-) diff --git a/spec/java/lang/System.lsl b/spec/java/lang/System.lsl index df98aac0..69d31ced 100644 --- a/spec/java/lang/System.lsl +++ b/spec/java/lang/System.lsl @@ -57,6 +57,8 @@ import java/util/Properties; is java.lang.System for System { + @private @static val propsMap: map = action MAP_NEW(); + @private @static @volatile var security: SecurityManager = null; // WARNING: do not change! @private @static var props: Properties = null; // WARNING: do not change! diff --git a/spec/java/lang/System.main.lsl b/spec/java/lang/System.main.lsl index eca43eff..920ab157 100644 --- a/spec/java/lang/System.main.lsl +++ b/spec/java/lang/System.main.lsl @@ -82,9 +82,118 @@ automaton SystemAutomaton @static proc _initProperties (): void { + // prepare raw values + + val javaVersion: int = action SYMBOLIC("int"); + action ASSUME(javaVersion >= 8); + action ASSUME(javaVersion <= 11); + + val userName: String = action SYMBOLIC("java.lang.String"); + action ASSUME(userName != null); + + // convert it into properties + + action MAP_SET(propsMap, "file.encoding", "Cp1251"); + action MAP_SET(propsMap, "sun.io.unicode.encoding", "UnicodeLittle"); + action MAP_SET(propsMap, "sun.jnu.encoding", "Cp1251"); + action MAP_SET(propsMap, "sun.stderr.encoding", "cp866"); + action MAP_SET(propsMap, "sun.stdout.encoding", "cp866"); + + val versionStrings: array = [ + "0", "1", "2", "3", "4", "5", "6", "7", + "8", + "9", + "10", + "11", + "12", "13", "14", "15", + ]; + val versionString: String = versionStrings[javaVersion]; + + action MAP_SET(propsMap, "java.specification.name", "Java Platform API Specification"); + action MAP_SET(propsMap, "java.specification.vendor", "Oracle Corporation"); + action MAP_SET(propsMap, "java.specification.version", versionString); + action MAP_SET(propsMap, "java.vm.info", "mixed mode"); + action MAP_SET(propsMap, "java.vm.name", "OpenJDK 64-Bit Server VM"); + action MAP_SET(propsMap, "java.vm.specification.name", "Java Virtual Machine Specification"); + action MAP_SET(propsMap, "java.vm.specification.vendor", "Oracle Corporation"); + action MAP_SET(propsMap, "java.vm.specification.version", versionString); + action MAP_SET(propsMap, "java.vm.vendor", "Eclipse Adoptium"); + action MAP_SET(propsMap, "java.vm.version", versionString + ".0.362+9"); + + action MAP_SET(propsMap, "java.library.path", "C:\\Program Files\\Eclipse Adoptium\\jdk-8.0.362.9-hotspot\\bin;C:\\Windows\\Sun\\Java\\bin;C:\\Windows\\system32;."); + action MAP_SET(propsMap, "java.home", "C:\\Program Files\\Eclipse Adoptium\\jdk-8.0.362.9-hotspot"); + action MAP_SET(propsMap, "sun.boot.library.path", "C:\\Program Files\\Eclipse Adoptium\\jdk-8.0.362.9-hotspot\\bin"); + action MAP_SET(propsMap, "java.io.tmpdir", "T:\\Temp\\"); + action MAP_SET(propsMap, "java.class.path", "."); + + if (SYSTEM_IS_WINDOWS) + { + action MAP_SET(propsMap, "file.separator", "\\"); + action MAP_SET(propsMap, "line.separator", "\r\n"); + action MAP_SET(propsMap, "path.separator", ";"); + } + else + { + action MAP_SET(propsMap, "file.separator", "/"); + action MAP_SET(propsMap, "line.separator", "\n"); + action MAP_SET(propsMap, "path.separator", ":"); + } + + action MAP_SET(propsMap, "user.country", "RU"); + action MAP_SET(propsMap, "user.country.format", "US"); + action MAP_SET(propsMap, "user.language", "ru"); + + val bytecodeVersions: array = [ + "?", /* 0? */ + "?", /* 1? */ + "?", /* 2? */ + "?", /* 3? */ + "?", /* 4? */ + "49.0", /* Java SE 5 */ + "50.0", /* Java SE 6 */ + "51.0", /* Java SE 7 */ + "52.0", /* Java SE 8 */ + "53.0", /* Java SE 9 */ + "54.0", /* Java SE 10 */ + "55.0", /* Java SE 11 */ + "?", /* 12? */ + "?", /* 13? */ + "?", /* 14? */ + "?", /* 15? */ + ]; + action MAP_SET(propsMap, "java.class.version", bytecodeVersions[javaVersion]); + + action MAP_SET(propsMap, "os.arch", "amd64"); + action MAP_SET(propsMap, "os.name", "Windows 10"); + action MAP_SET(propsMap, "os.version", "10.0"); + action MAP_SET(propsMap, "sun.arch.data.model", "64"); + action MAP_SET(propsMap, "sun.cpu.endian", "little"); + action MAP_SET(propsMap, "sun.cpu.isalist", "amd64"); + action MAP_SET(propsMap, "sun.desktop", "windows"); + + action MAP_SET(propsMap, "user.dir", "D:\\Company\\Prod\\Service"); + action MAP_SET(propsMap, "user.home", "C:\\Users\\" + userName); + action MAP_SET(propsMap, "user.name", userName); + action MAP_SET(propsMap, "user.script", ""); + action MAP_SET(propsMap, "user.timezone", ""); + action MAP_SET(propsMap, "user.variant", ""); + + // unknown misc stuff + action MAP_SET(propsMap, "sun.java.command", "org.example.MainClass"); // #problem: main class + action MAP_SET(propsMap, "awt.toolkit", "sun.awt.windows.WToolkit"); + action MAP_SET(propsMap, "java.awt.graphicsenv", "sun.awt.Win32GraphicsEnvironment"); + action MAP_SET(propsMap, "java.awt.printerjob", "sun.awt.windows.WPrinterJob"); + action MAP_SET(propsMap, "sun.java.launcher", "SUN_STANDARD"); + action MAP_SET(propsMap, "sun.management.compiler", "HotSpot 64-Bit Tiered Compilers"); + action MAP_SET(propsMap, "sun.nio.MaxDirectMemorySize", "-1"); + action MAP_SET(propsMap, "sun.os.patch.level", ""); + action MAP_SET(propsMap, "java.vm.compressedOopsMode", "Zero based"); + action MAP_SET(propsMap, "jdk.boot.class.path.append", ""); + action MAP_SET(propsMap, "jdk.debug", "release"); + // #problem: no approximation for Properties props = null;//new Properties(84); - // #todo + // #todo: init 'props' from the map above } @@ -148,15 +257,23 @@ automaton SystemAutomaton } - @Phantom @static fun *.getProperties (): Properties + @static fun *.getProperties (): Properties { - // NOTE: using the original method + // #todo: throw SecurityException + result = props; } - @Phantom @static fun *.getProperty (key: String): String + @static fun *.getProperty (key: String): String { - // NOTE: using the original method + if (key == null) + _throwNPE(); + + // #todo: throw SecurityException + if (action MAP_HAS_KEY(propsMap, key)) + result = action MAP_GET(propsMap, key); + else + result = null; } @@ -209,10 +326,7 @@ automaton SystemAutomaton @static fun *.lineSeparator (): String { - if (SYSTEM_IS_WINDOWS) - result = "\r\n"; - else - result = "\n"; + result = action MAP_GET(propsMap, "line.separator"); } @@ -302,7 +416,14 @@ automaton SystemAutomaton if (key == null) _throwNPE(); - // #todo: change the property + // #todo: update 'props' + + if (action MAP_HAS_KEY(propsMap, key)) + result = action MAP_GET(propsMap, key); + else + result = null; + + action MAP_SET(propsMap, key, value); } From db75b85edad2d6450a226b8f87ee71d67dca0ffa Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Fri, 10 Nov 2023 05:22:53 +0300 Subject: [PATCH 43/78] Added symbolic string construction utils to `Stream` --- spec/java/lang/System.main.lsl | 61 ++++++++++++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 2 deletions(-) diff --git a/spec/java/lang/System.main.lsl b/spec/java/lang/System.main.lsl index 920ab157..0c62c123 100644 --- a/spec/java/lang/System.main.lsl +++ b/spec/java/lang/System.main.lsl @@ -80,6 +80,64 @@ automaton SystemAutomaton } + @static proc _makeValidString (minLen: int, maxLen: int): String + { + val len: int = action SYMBOLIC("int"); + action ASSUME(len >= minLen); + action ASSUME(len < maxLen); + val lastCharIdx: int = len - 1; + + val chars: array = action ARRAY_NEW("char", len); + val forbidenLetters: String = ":/\\*\"'?<>|"; + var spaces: int = 0; + + var i: int = 0; + action LOOP_FOR( + i, 0, len, +1, + _makeValidString_loop(i, chars, spaces, forbidenLetters) + ); + + // there should be at least a single character + action ASSUME(spaces + 1 < maxLen); + // last character cannot be space (Win-specific) + action ASSUME(chars[lastCharIdx] != 20); + + result = action OBJECT_TO_STRING(chars); + } + + @Phantom proc _makeValidString_loop (i: int, chars: array, spaces: int, forbidenLetters: String): void + { + val c: char = action SYMBOLIC("char"); + action ASSUME(c >= 20); + action ASSUME(action CALL_METHOD(forbidenLetters, "indexOf", [c]) == -1); + // #problem: Unicode symbols? + + if (c == 20) + spaces += 1; + + chars[i] = c; + } + + + proc _getRandomDriveLetter (): String + { + val letters: array = [ + "A", "B", "C", "D", "E", + "F", "G", "H", "I", "J", + "K", "L", "M", "N", "O", + "P", "Q", "R", "S", "T", + "U", "V", "W", "X", "Y", + "Z", + ]; + + val idx: int = action SYMBOLIC("int"); + action ASSUME(idx >= 0); + action ASSUME(idx < action ARRAY_SIZE(letters)); + + result = letters[idx]; + } + + @static proc _initProperties (): void { // prepare raw values @@ -88,8 +146,7 @@ automaton SystemAutomaton action ASSUME(javaVersion >= 8); action ASSUME(javaVersion <= 11); - val userName: String = action SYMBOLIC("java.lang.String"); - action ASSUME(userName != null); + val userName: String = _makeValidString(1, 25); // convert it into properties From 1c12c376efe0f6e7101d9bfc3eb61d95f90b9b35 Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Fri, 10 Nov 2023 08:27:30 +0300 Subject: [PATCH 44/78] Minor property-focused fixes within `System` --- spec/java/lang/System.main.lsl | 41 +++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/spec/java/lang/System.main.lsl b/spec/java/lang/System.main.lsl index 0c62c123..203102da 100644 --- a/spec/java/lang/System.main.lsl +++ b/spec/java/lang/System.main.lsl @@ -80,6 +80,16 @@ automaton SystemAutomaton } + @AutoInline @Phantom proc _checkKey (key: String): void + { + if (key == null) + action THROW_NEW("java.lang.NullPointerException", ["key can't be null"]); + + if (action CALL_METHOD(key, "length", []) == 0) + action THROW_NEW("java.lang.NullPointerException", ["key can't be empty"]); + } + + @static proc _makeValidString (minLen: int, maxLen: int): String { val len: int = action SYMBOLIC("int"); @@ -270,9 +280,20 @@ automaton SystemAutomaton } - @Phantom @static fun *.clearProperty (key: String): String + @static fun *.clearProperty (key: String): String { - // NOTE: using the original method + _checkKey(key); + + // #todo: check permission + + if (action MAP_HAS_KEY(propsMap, key)) + { + result = action MAP_GET(propsMap, key); + + // #todo: remove key from 'props' + + action MAP_REMOVE(propsMap, key); + } } @@ -323,8 +344,7 @@ automaton SystemAutomaton @static fun *.getProperty (key: String): String { - if (key == null) - _throwNPE(); + _checkKey(key); // #todo: throw SecurityException if (action MAP_HAS_KEY(propsMap, key)) @@ -334,9 +354,15 @@ automaton SystemAutomaton } - @Phantom @static fun *.getProperty (key: String, def: String): String + @static fun *.getProperty (key: String, def: String): String { - // NOTE: using the original method + _checkKey(key); + + // #todo: throw SecurityException + if (action MAP_HAS_KEY(propsMap, key)) + result = action MAP_GET(propsMap, key); + else + result = def; } @@ -470,8 +496,7 @@ automaton SystemAutomaton @static fun *.setProperty (key: String, value: String): String { - if (key == null) - _throwNPE(); + _checkKey(key); // #todo: update 'props' From 25684a432e4d9e3296774f09d0cb952d82b7d045 Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Fri, 10 Nov 2023 14:01:00 +0300 Subject: [PATCH 45/78] Simplification for some properties in `System` --- spec/java/lang/System.main.lsl | 78 ++++------------------------------ 1 file changed, 9 insertions(+), 69 deletions(-) diff --git a/spec/java/lang/System.main.lsl b/spec/java/lang/System.main.lsl index 203102da..e42dc993 100644 --- a/spec/java/lang/System.main.lsl +++ b/spec/java/lang/System.main.lsl @@ -90,73 +90,15 @@ automaton SystemAutomaton } - @static proc _makeValidString (minLen: int, maxLen: int): String - { - val len: int = action SYMBOLIC("int"); - action ASSUME(len >= minLen); - action ASSUME(len < maxLen); - val lastCharIdx: int = len - 1; - - val chars: array = action ARRAY_NEW("char", len); - val forbidenLetters: String = ":/\\*\"'?<>|"; - var spaces: int = 0; - - var i: int = 0; - action LOOP_FOR( - i, 0, len, +1, - _makeValidString_loop(i, chars, spaces, forbidenLetters) - ); - - // there should be at least a single character - action ASSUME(spaces + 1 < maxLen); - // last character cannot be space (Win-specific) - action ASSUME(chars[lastCharIdx] != 20); - - result = action OBJECT_TO_STRING(chars); - } - - @Phantom proc _makeValidString_loop (i: int, chars: array, spaces: int, forbidenLetters: String): void - { - val c: char = action SYMBOLIC("char"); - action ASSUME(c >= 20); - action ASSUME(action CALL_METHOD(forbidenLetters, "indexOf", [c]) == -1); - // #problem: Unicode symbols? - - if (c == 20) - spaces += 1; - - chars[i] = c; - } - - - proc _getRandomDriveLetter (): String - { - val letters: array = [ - "A", "B", "C", "D", "E", - "F", "G", "H", "I", "J", - "K", "L", "M", "N", "O", - "P", "Q", "R", "S", "T", - "U", "V", "W", "X", "Y", - "Z", - ]; - - val idx: int = action SYMBOLIC("int"); - action ASSUME(idx >= 0); - action ASSUME(idx < action ARRAY_SIZE(letters)); - - result = letters[idx]; - } - - @static proc _initProperties (): void { // prepare raw values - val javaVersion: int = action SYMBOLIC("int"); - action ASSUME(javaVersion >= 8); - action ASSUME(javaVersion <= 11); + // NOTE: symbolic JRE version is too expensive to use + val javaVersion: int = 8; - val userName: String = _makeValidString(1, 25); + // NOTE: valid symbolic name is too expensive to use and construct + val userName: String = "Admin"; // convert it into properties @@ -382,14 +324,12 @@ automaton SystemAutomaton @static fun *.getenv (name: String): String { - val symbolCount: int = action SYMBOLIC("int"); - action ASSUME(symbolCount >= 0); - action ASSUME(symbolCount < 256); - - val symbols: array = action SYMBOLIC_ARRAY("char", symbolCount); - action ASSUME(symbols != null); + result = action SYMBOLIC("java.lang.String"); + action ASSUME(result != null); - result = action OBJECT_TO_STRING(symbols); + val len: int = action CALL_METHOD(result, "length", []); + action ASSUME(len >= 0); + action ASSUME(len < 250); } From 30f6fbd56a79b9119721b780bd5fcdc441ad177a Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Sun, 12 Nov 2023 08:07:08 +0300 Subject: [PATCH 46/78] Improvements and implementations for `java.lang.Integer` --- spec/java/lang/Integer.lsl | 53 ++++++++ spec/java/lang/Integer.main.lsl | 206 ++++++++++++++++++++++---------- 2 files changed, 196 insertions(+), 63 deletions(-) diff --git a/spec/java/lang/Integer.lsl b/spec/java/lang/Integer.lsl index 455c8424..89fab447 100644 --- a/spec/java/lang/Integer.lsl +++ b/spec/java/lang/Integer.lsl @@ -8,6 +8,7 @@ library std // imports +import java/lang/Class; import java/lang/Comparable; import java/lang/Number; @@ -31,4 +32,56 @@ import java/lang/Number; is java.lang.Integer for Integer { + @private @static val serialVersionUID: long = 1360826667806852920L; + + @public @static val MIN_VALUE: int = -2147483648; + @public @static val MAX_VALUE: int = 2147483647; + + @public @static val TYPE: Class = action DEBUG_DO("int.class"); + + @public @static val SIZE: int = 32; + @public @static val BYTES: int = 4; + + // WARNING: do not change! + @static val digits: array = [ + '0' , '1' , '2' , '3' , '4' , '5' , + '6' , '7' , '8' , '9' , 'a' , 'b' , + 'c' , 'd' , 'e' , 'f' , 'g' , 'h' , + 'i' , 'j' , 'k' , 'l' , 'm' , 'n' , + 'o' , 'p' , 'q' , 'r' , 's' , 't' , + 'u' , 'v' , 'w' , 'x' , 'y' , 'z' , + ]; + + // WARNING: do not change! + @static val DigitTens: array = [ + '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', + '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', + '2', '2', '2', '2', '2', '2', '2', '2', '2', '2', + '3', '3', '3', '3', '3', '3', '3', '3', '3', '3', + '4', '4', '4', '4', '4', '4', '4', '4', '4', '4', + '5', '5', '5', '5', '5', '5', '5', '5', '5', '5', + '6', '6', '6', '6', '6', '6', '6', '6', '6', '6', + '7', '7', '7', '7', '7', '7', '7', '7', '7', '7', + '8', '8', '8', '8', '8', '8', '8', '8', '8', '8', + '9', '9', '9', '9', '9', '9', '9', '9', '9', '9', + ]; + + // WARNING: do not change! + @static val DigitOnes: array = [ + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + ]; + + // WARNING: do not change! + @static val sizeTable: array = [ + 9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999, 2147483647 + ]; } diff --git a/spec/java/lang/Integer.main.lsl b/spec/java/lang/Integer.main.lsl index fb44d568..ff3cb21f 100644 --- a/spec/java/lang/Integer.main.lsl +++ b/spec/java/lang/Integer.main.lsl @@ -18,7 +18,7 @@ import java/lang/Integer; automaton IntegerAutomaton ( - @private val value: int // WARNING: do not rename! + @private var value: int // WARNING: do not rename! ) : LSLInteger { @@ -98,29 +98,58 @@ automaton IntegerAutomaton } - @Phantom constructor *.Integer (@target self: LSLInteger, value: int) + constructor *.Integer (@target self: LSLInteger, v: int) { - // NOTE: using the original method + this.value = v; } // static methods - @Phantom @static fun *.bitCount (i: int): int + @static fun *.bitCount (i: int): int { - // NOTE: using the original method + // direct adaptation from the JDK + i = i - ((i >>> 1) & 1431655765); + i = (i & 858993459) + ((i >>> 2) & 858993459); + i = (i + (i >>> 4)) & 252645135; + i = i + (i >>> 8); + i = i + (i >>> 16); + result = i & 63; } - @Phantom @static fun *.compare (x: int, y: int): int + @static fun *.compare (x: int, y: int): int { - // NOTE: using the original method + if (x == y) + { + result = 0; + } + else + { + if (x < y) + result = -1; + else + result = +1; + } } - @Phantom @static fun *.compareUnsigned (x: int, y: int): int + @static fun *.compareUnsigned (x: int, y: int): int { - // NOTE: using the original method + x += MIN_VALUE; + y += MIN_VALUE; + + if (x == y) + { + result = 0; + } + else + { + if (x < y) + result = -1; + else + result = +1; + } } @@ -155,45 +184,89 @@ automaton IntegerAutomaton } - @Phantom @static fun *.hashCode (value: int): int + @static fun *.hashCode (value: int): int { - // NOTE: using the original method + result = value; } - @Phantom @static fun *.highestOneBit (i: int): int + @static fun *.highestOneBit (i: int): int { - // NOTE: using the original method + // direct adaptation from the JDK + i |= (i >> 1); + i |= (i >> 2); + i |= (i >> 4); + i |= (i >> 8); + i |= (i >> 16); + result = i - (i >>> 1); } - @Phantom @static fun *.lowestOneBit (i: int): int + @static fun *.lowestOneBit (i: int): int { - // NOTE: using the original method + // direct adaptation from the JDK + result = i & -i; } - @Phantom @static fun *.max (a: int, b: int): int + @static fun *.max (a: int, b: int): int { - // NOTE: using the original method + if (a > b) + result = a; + else + result = b; } - @Phantom @static fun *.min (a: int, b: int): int + @static fun *.min (a: int, b: int): int { - // NOTE: using the original method + if (a < b) + result = a; + else + result = b; } - @Phantom @static fun *.numberOfLeadingZeros (i: int): int + @static fun *.numberOfLeadingZeros (i: int): int { - // NOTE: using the original method + if (i == 0) + { + result = 32; + } + else + { + // direct adaptation from the JDK + result = 1; + + if (i >>> 16 == 0) { result += 16; i <<= 16; } + if (i >>> 24 == 0) { result += 8; i <<= 8; } + if (i >>> 28 == 0) { result += 4; i <<= 4; } + if (i >>> 30 == 0) { result += 2; i <<= 2; } + + result -= i >>> 31; + } } - @Phantom @static fun *.numberOfTrailingZeros (i: int): int + @static fun *.numberOfTrailingZeros (i: int): int { - // NOTE: using the original method + if (i == 0) + { + result = 32; + } + else + { + // direct adaptation from the JDK + var y: int = 0; + var n: int = 31; + + y = i << 16; if (y != 0) { n -= 16; i = y; } + y = i << 8; if (y != 0) { n -= 8; i = y; } + y = i << 4; if (y != 0) { n -= 4; i = y; } + y = i << 2; if (y != 0) { n -= 2; i = y; } + + result = n - ((i << 1) >>> 31); + } } @@ -245,39 +318,53 @@ automaton IntegerAutomaton } - @Phantom @static fun *.reverse (i: int): int + @static fun *.reverse (i: int): int { - // NOTE: using the original method + // direct adaptation from the JDK + i = (i & 1431655765) << 1 | (i >>> 1) & 1431655765; + i = (i & 858993459) << 2 | (i >>> 2) & 858993459; + i = (i & 252645135) << 4 | (i >>> 4) & 252645135; + i = (i << 24) | ((i & 65280) << 8) | + ((i >>> 8) & 65280) | (i >>> 24); + + result = i; } - @Phantom @static fun *.reverseBytes (i: int): int + @static fun *.reverseBytes (i: int): int { - // NOTE: using the original method + // direct adaptation from the JDK + result = ((i >>> 24) ) | + ((i >> 8) & 65280) | + ((i << 8) & 16711680) | + ((i << 24)); } - @Phantom @static fun *.rotateLeft (i: int, distance: int): int + @static fun *.rotateLeft (i: int, distance: int): int { - // NOTE: using the original method + // direct adaptation from the JDK + result = (i << distance) | (i >>> -distance); } - @Phantom @static fun *.rotateRight (i: int, distance: int): int + @static fun *.rotateRight (i: int, distance: int): int { - // NOTE: using the original method + // direct adaptation from the JDK + result = (i >>> distance) | (i << -distance); } - @Phantom @static fun *.signum (i: int): int + @static fun *.signum (i: int): int { - // NOTE: using the original method + // direct adaptation from the JDK + result = (i >> 31) | (-i >>> 31); } - @Phantom @static fun *.sum (a: int, b: int): int + @static fun *.sum (a: int, b: int): int { - // NOTE: using the original method + result = a + b; } @@ -299,9 +386,9 @@ automaton IntegerAutomaton } - @Phantom @static fun *.toString (i: int): String + @static fun *.toString (i: int): String { - // NOTE: using the original method + result = action OBJECT_TO_STRING(i); } @@ -311,9 +398,10 @@ automaton IntegerAutomaton } - @Phantom @static fun *.toUnsignedLong (x: int): long + @static fun *.toUnsignedLong (x: int): long { - // NOTE: using the original method + // direct adaptation from the JDK + result = x as long & 4294967295L; } @@ -353,9 +441,9 @@ automaton IntegerAutomaton // methods - @Phantom fun *.byteValue (@target self: LSLInteger): byte + fun *.byteValue (@target self: LSLInteger): byte { - // NOTE: using the original method + result = this.value as byte; } @@ -365,9 +453,9 @@ automaton IntegerAutomaton } - @Phantom fun *.doubleValue (@target self: LSLInteger): double + fun *.doubleValue (@target self: LSLInteger): double { - // NOTE: using the original method + result = this.value as double; } @@ -377,47 +465,39 @@ automaton IntegerAutomaton } - @Phantom fun *.floatValue (@target self: LSLInteger): float + fun *.floatValue (@target self: LSLInteger): float { - // NOTE: using the original method + result = this.value as float; } - @Phantom fun *.hashCode (@target self: LSLInteger): int + fun *.hashCode (@target self: LSLInteger): int { - // NOTE: using the original method + result = this.value; } - @Phantom fun *.intValue (@target self: LSLInteger): int + fun *.intValue (@target self: LSLInteger): int { - // NOTE: using the original method + result = this.value; } - @Phantom fun *.longValue (@target self: LSLInteger): long + fun *.longValue (@target self: LSLInteger): long { - // NOTE: using the original method + result = this.value as long; } - @Phantom fun *.shortValue (@target self: LSLInteger): short + fun *.shortValue (@target self: LSLInteger): short { - // NOTE: using the original method + result = this.value as short; } - @Phantom fun *.toString (@target self: LSLInteger): String - { - // NOTE: using the original method - } - - - // special: class initialization - - @Phantom @static fun *.__clinit__ (): void + fun *.toString (@target self: LSLInteger): String { - // WARNING: this should be empty, do not change! + result = action OBJECT_TO_STRING(this.value); } } From f0f8b08a62f8ddf318449614df77289d2d7e951c Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Sun, 12 Nov 2023 17:39:09 +0300 Subject: [PATCH 47/78] Disabled synthesis for `Charset` + Added approximation for `Float` (and a draft for `Double`) + Minor improvements to `System` and `Integer` --- spec/java/lang/Double.main.lsl | 284 ++++++++++++++++++++ spec/java/lang/Float.lsl | 29 ++ spec/java/lang/Float.main.lsl | 349 +++++++++++++++++++++++++ spec/java/lang/Integer.lsl | 6 +- spec/java/lang/Integer.main.lsl | 19 +- spec/java/lang/System.lsl | 3 + spec/java/lang/System.main.lsl | 40 ++- spec/java/nio/charset/Charset.main.lsl | 1 + 8 files changed, 716 insertions(+), 15 deletions(-) create mode 100644 spec/java/lang/Double.main.lsl create mode 100644 spec/java/lang/Float.main.lsl diff --git a/spec/java/lang/Double.main.lsl b/spec/java/lang/Double.main.lsl new file mode 100644 index 00000000..ca2462dc --- /dev/null +++ b/spec/java/lang/Double.main.lsl @@ -0,0 +1,284 @@ +//#! pragma: non-synthesizable +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/lang/Double.java"; + +// imports + +import java/lang/Comparable; +import java/lang/Number; +import java/lang/Object; +import java/lang/String; + + +// local semantic types + +@extends("java.lang.Number") +@implements("java.lang.Comparable") +@public @final type Double + is java.lang.Double + for Object +{ + @private @static @final var serialVersionUID: long = -9172774392245257468; + + @static @final @public var BYTES: int = 8; + @static @final @public var MAX_EXPONENT: int = 1023; + @static @final @public var MAX_VALUE: double = 1.7976931348623157E308; + @static @final @public var MIN_EXPONENT: int = -1022; + @static @final @public var MIN_NORMAL: double = 2.2250738585072014E-308; + @static @final @public var MIN_VALUE: double = 4.9E-324; + @static @final @public var NEGATIVE_INFINITY: double = -Infinity; + @static @final @public var NaN: double = NaN; + @static @final @public var POSITIVE_INFINITY: double = Infinity; + @static @final @public var SIZE: int = 64; + @static @final @public var TYPE: Class = double; +} + + +// automata + +automaton DoubleAutomaton +( +) +: Double +{ + // states and shifts + + initstate Allocated; + state Initialized; + + shift Allocated -> Initialized by [ + // constructors + Double (Double, String), + Double (Double, double), + // static operations + compare, + doubleToLongBits, + doubleToRawLongBits, + hashCode (double), + isFinite, + isInfinite (double), + isNaN (double), + longBitsToDouble, + max, + min, + parseDouble, + sum, + toHexString, + toString (double), + valueOf (String), + valueOf (double), + ]; + + shift Initialized -> self by [ + // instance methods + byteValue, + compareTo, + doubleValue, + equals, + floatValue, + hashCode (Double), + intValue, + isInfinite (Double), + isNaN (Double), + longValue, + shortValue, + toString (Double), + ]; + + // internal variables + + // utilities + + // constructors + + @throws(["java.lang.NumberFormatException"]) + constructor *.Double (@target self: Double, s: String) + { + action TODO(); + } + + + constructor *.Double (@target self: Double, value: double) + { + action TODO(); + } + + + // static methods + + @static fun *.compare (d1: double, d2: double): int + { + action TODO(); + } + + + @static fun *.doubleToLongBits (value: double): long + { + action TODO(); + } + + + @static fun *.doubleToRawLongBits (arg0: double): long + { + action TODO(); + } + + + @static fun *.hashCode (value: double): int + { + action TODO(); + } + + + @static fun *.isFinite (d: double): boolean + { + action TODO(); + } + + + @static fun *.isInfinite (v: double): boolean + { + action TODO(); + } + + + @static fun *.isNaN (v: double): boolean + { + action TODO(); + } + + + @static fun *.longBitsToDouble (arg0: long): double + { + action TODO(); + } + + + @static fun *.max (a: double, b: double): double + { + action TODO(); + } + + + @static fun *.min (a: double, b: double): double + { + action TODO(); + } + + + @throws(["java.lang.NumberFormatException"]) + @static fun *.parseDouble (s: String): double + { + action TODO(); + } + + + @static fun *.sum (a: double, b: double): double + { + action TODO(); + } + + + @static fun *.toHexString (d: double): String + { + action TODO(); + } + + + @static fun *.toString (d: double): String + { + action TODO(); + } + + + @throws(["java.lang.NumberFormatException"]) + @static fun *.valueOf (s: String): Double + { + action TODO(); + } + + + @static fun *.valueOf (d: double): Double + { + action TODO(); + } + + + // methods + + fun *.byteValue (@target self: Double): byte + { + action TODO(); + } + + + fun *.compareTo (@target self: Double, anotherDouble: Double): int + { + action TODO(); + } + + + fun *.doubleValue (@target self: Double): double + { + action TODO(); + } + + + fun *.equals (@target self: Double, obj: Object): boolean + { + action TODO(); + } + + + fun *.floatValue (@target self: Double): float + { + action TODO(); + } + + + fun *.hashCode (@target self: Double): int + { + action TODO(); + } + + + fun *.intValue (@target self: Double): int + { + action TODO(); + } + + + fun *.isInfinite (@target self: Double): boolean + { + action TODO(); + } + + + fun *.isNaN (@target self: Double): boolean + { + action TODO(); + } + + + fun *.longValue (@target self: Double): long + { + action TODO(); + } + + + fun *.shortValue (@target self: Double): short + { + action TODO(); + } + + + fun *.toString (@target self: Double): String + { + action TODO(); + } + +} diff --git a/spec/java/lang/Float.lsl b/spec/java/lang/Float.lsl index 08001ca6..739167c0 100644 --- a/spec/java/lang/Float.lsl +++ b/spec/java/lang/Float.lsl @@ -9,6 +9,7 @@ library std // imports import java/lang/Comparable; +import java/lang/Class; import java/lang/Number; @@ -24,3 +25,31 @@ import java/lang/Number; // global aliases and type overrides +// note: this is a partial implementation, no need for additional constraints (abstract class) and synthetic methods (Comparable) +// @extends("java.lang.Number") +// @implements("java.lang.Comparable") +@public @final type LSLFloat + is java.lang.Float + for Float +{ + @private @static val serialVersionUID: long = -2671257302660747028L; + + @public @static val BYTES: int = 4; + @public @static val SIZE: int = 32; + + @public @static val MAX_EXPONENT: int = 127; + @public @static val MIN_EXPONENT: int = -126; + + // #problem: no "scientific" notation support + @public @static val MAX_VALUE: float = action DEBUG_DO("3.4028235e+38f"); + @public @static val MIN_VALUE: float = action DEBUG_DO("1.4e-45f"); + + @public @static val MIN_NORMAL: float = action DEBUG_DO("1.17549435e-38f"); + + @public @static val NEGATIVE_INFINITY: float = -1.0f / 0.0f; + @public @static val POSITIVE_INFINITY: float = 1.0f / 0.0f; + @public @static val NaN: float = 0.0f / 0.0f; + + // #problem: unable to get reference to primitive type + @public @static val TYPE: Class = action DEBUG_DO("Float.class"); // preventing recursion +} diff --git a/spec/java/lang/Float.main.lsl b/spec/java/lang/Float.main.lsl new file mode 100644 index 00000000..fcb7ca60 --- /dev/null +++ b/spec/java/lang/Float.main.lsl @@ -0,0 +1,349 @@ +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/lang/Float.java"; + +// imports + +import java/lang/String; + +import java/lang/Float; + + +// automata + +automaton FloatAutomaton +( + var value: float = 0.0f, +) +: LSLFloat +{ + // states and shifts + + initstate Allocated; + state Initialized; + + shift Allocated -> Initialized by [ + // constructors + LSLFloat (LSLFloat, String), + LSLFloat (LSLFloat, double), + LSLFloat (LSLFloat, float), + + // static operations + compare, + floatToIntBits, + floatToRawIntBits, + hashCode (float), + intBitsToFloat, + isFinite, + isInfinite (float), + isNaN (float), + max, + min, + parseFloat, + sum, + toHexString, + toString (float), + valueOf (String), + valueOf (float), + ]; + + shift Initialized -> self by [ + // instance methods + byteValue, + compareTo, + doubleValue, + equals, + floatValue, + hashCode (LSLFloat), + intValue, + isInfinite (LSLFloat), + isNaN (LSLFloat), + longValue, + shortValue, + toString (LSLFloat), + ]; + + // internal variables + + // utilities + + @static proc _getRawBits (v: float): int + { + if (v != v) // a NaN? + result = 2143289344; + else if (1.0f / v == NEGATIVE_INFINITY) // is it a "-0.0" ? + result = -2147483648; + else if (v == 0.0f) + result = 0; + else if (v == POSITIVE_INFINITY) + result = 2139095040; + else if (v == NEGATIVE_INFINITY) + result = -8388608; + else + { + // #todo: find more sophisticated approach + result = action SYMBOLIC("int"); + + action ASSUME(result != 2143289344); + action ASSUME(result != -2147483648); + action ASSUME(result != 0); + action ASSUME(result != 2139095040); + action ASSUME(result != -8388608); + } + } + + + // constructors + + @throws(["java.lang.NumberFormatException"]) + @Phantom constructor *.LSLFloat (@target self: LSLFloat, s: String) + { + // NOTE: using the original method + } + + + constructor *.LSLFloat (@target self: LSLFloat, v: double) + { + this.value = v as float; + } + + + constructor *.LSLFloat (@target self: LSLFloat, v: float) + { + this.value = v; + } + + + // static methods + + @static fun *.compare (a: float, b: float): int + { + // #problem: does not catch (-0.0, 0.0) + if (a == b) + { + result = 0; + } + else + { + if (a < b) + result = -1; + else + result = +1; + } + } + + + @static fun *.floatToIntBits (value: float): int + { + result = _getRawBits(value); + } + + + @static fun *.floatToRawIntBits (value: float): int + { + result = _getRawBits(value); + } + + + @static fun *.hashCode (value: float): int + { + result = _getRawBits(value); + } + + + @static fun *.intBitsToFloat (value: int): float + { + if (value == 2143289344) + result = 0.0f / 0.0f; + else if (value == -2147483648) + result = -0.0f; + else if (value == 0) + result = 0.0f; + else if (value == 2139095040) + result = POSITIVE_INFINITY; + else if (value == -8388608) + result = NEGATIVE_INFINITY; + else + { + // #todo: find more sophisticated approach + result = action SYMBOLIC("float"); + + action ASSUME(result != 0.0f); + action ASSUME(result == result); + action ASSUME(result != POSITIVE_INFINITY); + action ASSUME(result != NEGATIVE_INFINITY); + } + } + + + @static fun *.isFinite (f: float): boolean + { + result = (f != POSITIVE_INFINITY) && + (f != NEGATIVE_INFINITY); + } + + + @static fun *.isInfinite (v: float): boolean + { + result = (v == POSITIVE_INFINITY) || + (v == NEGATIVE_INFINITY); + } + + + @static fun *.isNaN (v: float): boolean + { + result = v != v; + } + + + @static fun *.max (a: float, b: float): float + { + if (a > b) + result = a; + else + result = b; + } + + + @static fun *.min (a: float, b: float): float + { + if (a < b) + result = a; + else + result = b; + } + + + @throws(["java.lang.NumberFormatException"]) + @Phantom @static fun *.parseFloat (s: String): float + { + // NOTE: using the original method + } + + + @static fun *.sum (a: float, b: float): float + { + result = a + b; + } + + + @static fun *.toHexString (f: float): String + { + if (f != f) result = "NaN"; + else if (f == POSITIVE_INFINITY) result = "Infinity"; + else if (f == NEGATIVE_INFINITY) result = "-Infinity"; + else if (1.0f / f == NEGATIVE_INFINITY) result = "-0x0.0p0"; + else if (f == 0.0f) result = "0x0.0p0"; + else if (f == 1.0f) result = "0x1.0p0"; + else if (f == -1.0f) result = "-0x1.0p0"; + else + { + // #todo: add implementation if necessary + result = action SYMBOLIC("java.lang.String"); + action ASSUME(result != null); + val len: int = action CALL_METHOD(result, "length", []); + action ASSUME(len >= 7); // 0x1.0p0 + action ASSUME(len <= 14); // 0x1.fffffep127 + } + } + + + @static fun *.toString (f: float): String + { + result = action OBJECT_TO_STRING(f); + } + + + @throws(["java.lang.NumberFormatException"]) + @Phantom @static fun *.valueOf (s: String): LSLFloat + { + // NOTE: using the original version + } + + + @static fun *.valueOf (f: float): LSLFloat + { + result = new FloatAutomaton(state = Initialized, + value = f + ); + } + + + // methods + + fun *.byteValue (@target self: LSLFloat): byte + { + result = this.value as byte; + } + + + fun *.compareTo (@target self: LSLFloat, anotherFloat: LSLFloat): int + { + action TODO(); + } + + + fun *.doubleValue (@target self: LSLFloat): double + { + result = this.value as double; + } + + + fun *.equals (@target self: LSLFloat, obj: Object): boolean + { + action TODO(); + } + + + fun *.floatValue (@target self: LSLFloat): float + { + result = this.value; + } + + + fun *.hashCode (@target self: LSLFloat): int + { + result = _getRawBits(this.value); + } + + + fun *.intValue (@target self: LSLFloat): int + { + result = this.value as int; + } + + + fun *.isInfinite (@target self: LSLFloat): boolean + { + result = (this.value == POSITIVE_INFINITY) || + (this.value == NEGATIVE_INFINITY); + } + + + fun *.isNaN (@target self: LSLFloat): boolean + { + result = this.value != this.value; + } + + + fun *.longValue (@target self: LSLFloat): long + { + result = this.value as long; + } + + + fun *.shortValue (@target self: LSLFloat): short + { + result = this.value as short; + } + + + fun *.toString (@target self: LSLFloat): String + { + result = action OBJECT_TO_STRING(this.value); + } + +} diff --git a/spec/java/lang/Integer.lsl b/spec/java/lang/Integer.lsl index 89fab447..0c0a15b6 100644 --- a/spec/java/lang/Integer.lsl +++ b/spec/java/lang/Integer.lsl @@ -20,6 +20,7 @@ import java/lang/Number; is java.lang.Integer for Comparable, Number, int { + @static fun *.valueOf(x: int): Number; // #problem: self-reference } @@ -28,7 +29,7 @@ import java/lang/Number; // note: this is a partial implementation, no need for additional constraints (abstract class) and synthetic methods (Comparable) // @extends("java.lang.Number") // @implements("java.lang.Comparable") -@public @final type LSLInteger +@final type LSLInteger is java.lang.Integer for Integer { @@ -37,7 +38,8 @@ import java/lang/Number; @public @static val MIN_VALUE: int = -2147483648; @public @static val MAX_VALUE: int = 2147483647; - @public @static val TYPE: Class = action DEBUG_DO("int.class"); + // #problem: unable to get reference to primitive type + @public @static val TYPE: Class = action DEBUG_DO("java.lang.Integer.class"); // preventing recursion @public @static val SIZE: int = 32; @public @static val BYTES: int = 4; diff --git a/spec/java/lang/Integer.main.lsl b/spec/java/lang/Integer.main.lsl index ff3cb21f..05fb75bb 100644 --- a/spec/java/lang/Integer.main.lsl +++ b/spec/java/lang/Integer.main.lsl @@ -160,9 +160,11 @@ automaton IntegerAutomaton } - @Phantom @static fun *.divideUnsigned (dividend: int, divisor: int): int + @static fun *.divideUnsigned (dividend: int, divisor: int): int { - // NOTE: using the original method + val unsignedDividend: long = dividend as long & 4294967295L; + val unsignedDivisor: long = divisor as long & 4294967295L; + result = (unsignedDividend / unsignedDivisor) as int; } @@ -312,9 +314,11 @@ automaton IntegerAutomaton } - @Phantom @static fun *.remainderUnsigned (dividend: int, divisor: int): int + @static fun *.remainderUnsigned (dividend: int, divisor: int): int { - // NOTE: using the original method + val unsignedDividend: long = dividend as long & 4294967295L; + val unsignedDivisor: long = divisor as long & 4294967295L; + result = (unsignedDividend % unsignedDivisor) as int; } @@ -459,9 +463,12 @@ automaton IntegerAutomaton } - @Phantom fun *.equals (@target self: LSLInteger, obj: Object): boolean + fun *.equals (@target self: LSLInteger, obj: Object): boolean { - // NOTE: using the original method + if (obj is Integer) + result = this.value == IntegerAutomaton(obj).value; + else + result = false; } diff --git a/spec/java/lang/System.lsl b/spec/java/lang/System.lsl index 69d31ced..54ca6299 100644 --- a/spec/java/lang/System.lsl +++ b/spec/java/lang/System.lsl @@ -11,6 +11,7 @@ library std import java/io/Console; import java/io/InputStream; import java/io/PrintStream; +import java/lang/Integer; import java/lang/Object; import java/lang/SecurityManager; import java/lang/String; @@ -71,6 +72,8 @@ import java/util/Properties; @private @static val NANOTIME_BEGINNING_OF_TIME: long = 1000L; @private @static val NANOTIME_WARP_MAX: long = 1000L; + + @private @static val identityHashCodeMap: map = action IDENTITY_MAP_NEW(); } // WARNING: declaration order is important! diff --git a/spec/java/lang/System.main.lsl b/spec/java/lang/System.main.lsl index e42dc993..15499010 100644 --- a/spec/java/lang/System.main.lsl +++ b/spec/java/lang/System.main.lsl @@ -335,8 +335,24 @@ automaton SystemAutomaton @static fun *.identityHashCode (x: Object): int { - // #problem: there are no ways of converting a reference to a "memory address" yet - result = action SYMBOLIC("int"); + if (x == null) + { + result = 0; + } + else if (action MAP_HAS_KEY(identityHashCodeMap, x)) + { + val value: Integer = action MAP_GET(identityHashCodeMap, x); + action ASSUME(value != null); + result = action CALL_METHOD(value, "intValue", []); + } + else + { + // sequential unique numbers + result = action MAP_SIZE(identityHashCodeMap); + + val hash: Integer = action CALL_METHOD(null as Integer, "valueOf", [result]); + action MAP_SET(identityHashCodeMap, x, hash); + } } @@ -353,15 +369,25 @@ automaton SystemAutomaton } - @Phantom @static fun *.load (filename: String): void + @static fun *.load (filename: String): void { - // NOTE: using the original method + if (filename == null) + _throwNPE(); + + // faking underlying checks and loading procedures + if (action SYMBOLIC("boolean")) action THROW_NEW("java.lang.SecurityException", [""]); + if (action SYMBOLIC("boolean")) action THROW_NEW("java.lang.UnsatisfiedLinkError", [""]); } - @Phantom @static fun *.loadLibrary (libname: String): void + @static fun *.loadLibrary (libname: String): void { - // NOTE: using the original method + if (libname == null) + _throwNPE(); + + // faking underlying checks and loading procedures + if (action SYMBOLIC("boolean")) action THROW_NEW("java.lang.SecurityException", [""]); + if (action SYMBOLIC("boolean")) action THROW_NEW("java.lang.UnsatisfiedLinkError", [""]); } @@ -370,7 +396,7 @@ automaton SystemAutomaton if (libname == null) _throwNPE(); - // https://hg.openjdk.org/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/native/java/lang/System.c#l466 + // https://github.com/openjdk/jdk8/blob/master/jdk/src/share/native/java/lang/System.c#L466 val len: int = action CALL_METHOD(libname, "length", []); if (len > 240) action THROW_NEW("java.lang.IllegalArgumentException", ["name too long"]); diff --git a/spec/java/nio/charset/Charset.main.lsl b/spec/java/nio/charset/Charset.main.lsl index 0bb1507c..47d9a0f7 100644 --- a/spec/java/nio/charset/Charset.main.lsl +++ b/spec/java/nio/charset/Charset.main.lsl @@ -1,3 +1,4 @@ +//#! pragma: non-synthesizable libsl "1.1.0"; library std From c4a6e573cfc07c79376e9f733b4dad44dce5aacf Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Mon, 13 Nov 2023 22:30:44 +0300 Subject: [PATCH 48/78] Improvements to `Float` and `Integer` --- spec/java/lang/Float.main.lsl | 39 ++++++++++++++++++++++++++++++--- spec/java/lang/Integer.main.lsl | 12 ++++++++++ 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/spec/java/lang/Float.main.lsl b/spec/java/lang/Float.main.lsl index fcb7ca60..668f4671 100644 --- a/spec/java/lang/Float.main.lsl +++ b/spec/java/lang/Float.main.lsl @@ -96,12 +96,24 @@ automaton FloatAutomaton } + @throws(["java.lang.NumberFormatException"]) + @static proc _parse (str: String): float + { + if (str == null) + action THROW_NEW("java.lang.NullPointerException", []); + + // #todo: add implementation if necessary + action TODO(); + } + + // constructors @throws(["java.lang.NumberFormatException"]) @Phantom constructor *.LSLFloat (@target self: LSLFloat, s: String) { // NOTE: using the original method + this.value = _parse(s); } @@ -122,7 +134,7 @@ automaton FloatAutomaton @static fun *.compare (a: float, b: float): int { // #problem: does not catch (-0.0, 0.0) - if (a == b) + if (a == b || a != a || b != b) // include NaN's { result = 0; } @@ -221,6 +233,7 @@ automaton FloatAutomaton @Phantom @static fun *.parseFloat (s: String): float { // NOTE: using the original method + result = _parse(s); } @@ -261,6 +274,9 @@ automaton FloatAutomaton @Phantom @static fun *.valueOf (s: String): LSLFloat { // NOTE: using the original version + result = new FloatAutomaton(state = Initialized, + value = _parse(s) + ); } @@ -282,7 +298,21 @@ automaton FloatAutomaton fun *.compareTo (@target self: LSLFloat, anotherFloat: LSLFloat): int { - action TODO(); + val a: float = this.value; + val b: float = anotherFloat; + + // #problem: does not catch (-0.0, 0.0) + if (a == b || a != a || b != b) // include NaN's + { + result = 0; + } + else + { + if (a < b) + result = -1; + else + result = +1; + } } @@ -294,7 +324,10 @@ automaton FloatAutomaton fun *.equals (@target self: LSLFloat, obj: Object): boolean { - action TODO(); + if (obj is Float) + result = this.value == FloatAutomaton(obj).value; + else + result = false; } diff --git a/spec/java/lang/Integer.main.lsl b/spec/java/lang/Integer.main.lsl index 05fb75bb..8569ac49 100644 --- a/spec/java/lang/Integer.main.lsl +++ b/spec/java/lang/Integer.main.lsl @@ -89,12 +89,24 @@ automaton IntegerAutomaton // utilities + @throws(["java.lang.NumberFormatException"]) + @static proc _parse (str: String): int + { + if (str == null) + action THROW_NEW("java.lang.NullPointerException", []); + + // #todo: add implementation if necessary + action TODO(); + } + + // constructors @throws(["java.lang.NumberFormatException"]) @Phantom constructor *.Integer (@target self: LSLInteger, s: String) { // NOTE: using the original method + this.value = _parse(s); } From ec9e387f9aaf97b6eb45e86e13e470cf0dac48f5 Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Mon, 13 Nov 2023 22:50:08 +0300 Subject: [PATCH 49/78] Minor fixes for `Float` --- spec/java/lang/Float.main.lsl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/spec/java/lang/Float.main.lsl b/spec/java/lang/Float.main.lsl index 668f4671..cb2737e9 100644 --- a/spec/java/lang/Float.main.lsl +++ b/spec/java/lang/Float.main.lsl @@ -169,7 +169,7 @@ automaton FloatAutomaton @static fun *.intBitsToFloat (value: int): float { if (value == 2143289344) - result = 0.0f / 0.0f; + result = NaN; else if (value == -2147483648) result = -0.0f; else if (value == 0) @@ -271,7 +271,7 @@ automaton FloatAutomaton @throws(["java.lang.NumberFormatException"]) - @Phantom @static fun *.valueOf (s: String): LSLFloat + @Phantom @static fun *.valueOf (s: String): Float { // NOTE: using the original version result = new FloatAutomaton(state = Initialized, @@ -280,7 +280,7 @@ automaton FloatAutomaton } - @static fun *.valueOf (f: float): LSLFloat + @static fun *.valueOf (f: float): Float { result = new FloatAutomaton(state = Initialized, value = f @@ -296,10 +296,10 @@ automaton FloatAutomaton } - fun *.compareTo (@target self: LSLFloat, anotherFloat: LSLFloat): int + fun *.compareTo (@target self: LSLFloat, anotherFloat: Float): int { val a: float = this.value; - val b: float = anotherFloat; + val b: float = action CALL_METHOD(anotherFloat, "floatValue", []); // #problem: does not catch (-0.0, 0.0) if (a == b || a != a || b != b) // include NaN's From 5dc83f134a4f11c362249f28ff1770a4fe37a7f9 Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Tue, 14 Nov 2023 14:46:12 +0300 Subject: [PATCH 50/78] Fixed incorrect package name for `Stream` spliterators --- spec/java/util/stream/DoubleStream.lsl | 2 +- spec/java/util/stream/IntStream.lsl | 2 +- spec/java/util/stream/LongStream.lsl | 2 +- spec/java/util/stream/Stream.lsl | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/spec/java/util/stream/DoubleStream.lsl b/spec/java/util/stream/DoubleStream.lsl index 7c472ae9..a8aebed2 100644 --- a/spec/java/util/stream/DoubleStream.lsl +++ b/spec/java/util/stream/DoubleStream.lsl @@ -45,7 +45,7 @@ import java/util/Spliterator; @GenerateMe @implements("java.util.Spliterator.OfDouble") @public type DoubleStreamLSLSpliterator - is java.util.DoubleStreamLSLSpliterator + is java.util.stream.DoubleStreamLSLSpliterator for Spliterator_OfDouble { } \ No newline at end of file diff --git a/spec/java/util/stream/IntStream.lsl b/spec/java/util/stream/IntStream.lsl index 785dc0f5..4aaf4677 100644 --- a/spec/java/util/stream/IntStream.lsl +++ b/spec/java/util/stream/IntStream.lsl @@ -45,7 +45,7 @@ import java/util/Spliterator; @GenerateMe @implements("java.util.Spliterator.OfInt") @public type IntStreamLSLSpliterator - is java.util.IntStreamLSLSpliterator + is java.util.stream.IntStreamLSLSpliterator for Spliterator_OfInt { } \ No newline at end of file diff --git a/spec/java/util/stream/LongStream.lsl b/spec/java/util/stream/LongStream.lsl index bc12db95..9dd84e8b 100644 --- a/spec/java/util/stream/LongStream.lsl +++ b/spec/java/util/stream/LongStream.lsl @@ -45,7 +45,7 @@ import java/util/Spliterator; @GenerateMe @implements("java.util.Spliterator.OfLong") @public type LongStreamLSLSpliterator - is java.util.LongStreamLSLSpliterator + is java.util.stream.LongStreamLSLSpliterator for Spliterator_OfLong { } \ No newline at end of file diff --git a/spec/java/util/stream/Stream.lsl b/spec/java/util/stream/Stream.lsl index 7506963d..e6f35384 100644 --- a/spec/java/util/stream/Stream.lsl +++ b/spec/java/util/stream/Stream.lsl @@ -53,7 +53,7 @@ import java/util/Spliterator; @GenerateMe @implements("java.util.Spliterator") @public type StreamLSLSpliterator - is java.util.StreamLSLSpliterator + is java.util.stream.StreamLSLSpliterator for Spliterator { } \ No newline at end of file From a0d94df11488b46114c021bdb6638b0e00fad8c1 Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Tue, 14 Nov 2023 19:38:31 +0300 Subject: [PATCH 51/78] Added implementation for `java.lang.Double` --- spec/java/lang/Double.lsl | 32 +++- spec/java/lang/Double.main.lsl | 255 +++++++++++++++++-------- spec/java/lang/Float.lsl | 2 +- spec/java/util/stream/DoubleStream.lsl | 4 + 4 files changed, 206 insertions(+), 87 deletions(-) diff --git a/spec/java/lang/Double.lsl b/spec/java/lang/Double.lsl index d4ddcc40..d5b5238e 100644 --- a/spec/java/lang/Double.lsl +++ b/spec/java/lang/Double.lsl @@ -9,6 +9,7 @@ library std // imports import java/lang/Comparable; +import java/lang/Class; import java/lang/Number; @@ -21,10 +22,33 @@ import java/lang/Number; { } -val DOUBLE_POSITIVE_INFINITY: double = 1.0 / 0.0; -val DOUBLE_NEGATIVE_INFINITY: double = -1.0 / 0.0; -val DOUBLE_NAN: double = 0.0 / 0.0; - // global aliases and type overrides +// note: this is a partial implementation, no need for additional constraints (abstract class) and synthetic methods (Comparable) +// @extends("java.lang.Number") +// @implements("java.lang.Comparable") +@final type LSLDouble + is java.lang.Double + for Double +{ + @private @static val serialVersionUID: long = -9172774392245257468L; + + @public @static val BYTES: int = 8; + @public @static val SIZE: int = 64; + + @public @static val MAX_EXPONENT: int = 1023; + @public @static val MIN_EXPONENT: int = -1022; + + // #problem: no support for scientific notation + @public @static val MAX_VALUE: double = action DEBUG_DO("1.7976931348623157E308"); + @public @static val MIN_VALUE: double = action DEBUG_DO("4.9E-324"); + @public @static val MIN_NORMAL: double = action DEBUG_DO("2.2250738585072014E-308"); + + @public @static val POSITIVE_INFINITY: double = 1.0 / 0.0; + @public @static val NEGATIVE_INFINITY: double = -1.0 / 0.0; + + @public @static val NaN: double = 0.0 / 0.0; + + @public @static val TYPE: Class = action DEBUG_DO("Double.class"); +} diff --git a/spec/java/lang/Double.main.lsl b/spec/java/lang/Double.main.lsl index ca2462dc..8a6d5f91 100644 --- a/spec/java/lang/Double.main.lsl +++ b/spec/java/lang/Double.main.lsl @@ -1,4 +1,3 @@ -//#! pragma: non-synthesizable libsl "1.1.0"; library std @@ -8,42 +7,19 @@ library std // imports -import java/lang/Comparable; -import java/lang/Number; import java/lang/Object; import java/lang/String; - -// local semantic types - -@extends("java.lang.Number") -@implements("java.lang.Comparable") -@public @final type Double - is java.lang.Double - for Object -{ - @private @static @final var serialVersionUID: long = -9172774392245257468; - - @static @final @public var BYTES: int = 8; - @static @final @public var MAX_EXPONENT: int = 1023; - @static @final @public var MAX_VALUE: double = 1.7976931348623157E308; - @static @final @public var MIN_EXPONENT: int = -1022; - @static @final @public var MIN_NORMAL: double = 2.2250738585072014E-308; - @static @final @public var MIN_VALUE: double = 4.9E-324; - @static @final @public var NEGATIVE_INFINITY: double = -Infinity; - @static @final @public var NaN: double = NaN; - @static @final @public var POSITIVE_INFINITY: double = Infinity; - @static @final @public var SIZE: int = 64; - @static @final @public var TYPE: Class = double; -} +import java/lang/Double; // automata automaton DoubleAutomaton ( + var value: double = 0.0, ) -: Double +: LSLDouble { // states and shifts @@ -52,8 +28,9 @@ automaton DoubleAutomaton shift Allocated -> Initialized by [ // constructors - Double (Double, String), - Double (Double, double), + Double (LSLDouble, String), + Double (LSLDouble, double), + // static operations compare, doubleToLongBits, @@ -80,205 +57,319 @@ automaton DoubleAutomaton doubleValue, equals, floatValue, - hashCode (Double), + hashCode (LSLDouble), intValue, - isInfinite (Double), - isNaN (Double), + isInfinite (LSLDouble), + isNaN (LSLDouble), longValue, shortValue, - toString (Double), + toString (LSLDouble), ]; // internal variables // utilities - // constructors + @static proc _getRawBits (v: double): long + { + if (v != v) // a NaN? + result = 9221120237041090560L; + else if (1.0 / v == NEGATIVE_INFINITY) // is it a "-0.0" ? + result = -9223372036854775808L; + else if (v == 0.0) + result = 0L; + else if (v == POSITIVE_INFINITY) + result = 9218868437227405312L; + else if (v == NEGATIVE_INFINITY) + result = -4503599627370496L; + else + { + // #todo: find more sophisticated approach + result = action SYMBOLIC("long"); + + action ASSUME(result != 9221120237041090560L); + action ASSUME(result != -9223372036854775808L); + action ASSUME(result != 0L); + action ASSUME(result != 9218868437227405312L); + action ASSUME(result != -4503599627370496L); + } + } + @throws(["java.lang.NumberFormatException"]) - constructor *.Double (@target self: Double, s: String) + @static proc _parse (str: String): double { + if (str == null) + action THROW_NEW("java.lang.NullPointerException", []); + + // #todo: add implementation if necessary action TODO(); } - constructor *.Double (@target self: Double, value: double) + // constructors + + @throws(["java.lang.NumberFormatException"]) + @Phantom constructor *.Double (@target self: LSLDouble, s: String) { - action TODO(); + // NOTE: using original method + } + + + constructor *.Double (@target self: LSLDouble, v: double) + { + this.value = v; } // static methods - @static fun *.compare (d1: double, d2: double): int + @static fun *.compare (a: double, b: double): int { - action TODO(); + // #problem: does not catch (-0.0, 0.0) + if (a == b || a != a || b != b) // include NaN's + { + result = 0; + } + else + { + if (a < b) + result = -1; + else + result = +1; + } } @static fun *.doubleToLongBits (value: double): long { - action TODO(); + result = _getRawBits(value); } - @static fun *.doubleToRawLongBits (arg0: double): long + @static fun *.doubleToRawLongBits (value: double): long { - action TODO(); + result = _getRawBits(value); } @static fun *.hashCode (value: double): int { - action TODO(); + result = _getRawBits(value) as int; } @static fun *.isFinite (d: double): boolean { - action TODO(); + result = (d != POSITIVE_INFINITY) && + (d != NEGATIVE_INFINITY); } @static fun *.isInfinite (v: double): boolean { - action TODO(); + result = (v == POSITIVE_INFINITY) || + (v == NEGATIVE_INFINITY); } @static fun *.isNaN (v: double): boolean { - action TODO(); + result = v != v; } - @static fun *.longBitsToDouble (arg0: long): double + @static fun *.longBitsToDouble (value: long): double { - action TODO(); + if (value == 9221120237041090560L) + result = NaN; + else if (value == -9223372036854775808L) + result = -0.0; + else if (value == 0L) + result = 0.0; + else if (value == 9218868437227405312L) + result = POSITIVE_INFINITY; + else if (value == -4503599627370496L) + result = NEGATIVE_INFINITY; + else + { + // #todo: find more sophisticated approach + result = action SYMBOLIC("double"); + + action ASSUME(result != 0.0); + action ASSUME(result == result); + action ASSUME(result != POSITIVE_INFINITY); + action ASSUME(result != NEGATIVE_INFINITY); + } } @static fun *.max (a: double, b: double): double { - action TODO(); + if (a > b) + result = a; + else + result = b; } @static fun *.min (a: double, b: double): double { - action TODO(); + if (a < b) + result = a; + else + result = b; } @throws(["java.lang.NumberFormatException"]) - @static fun *.parseDouble (s: String): double + @Phantom @static fun *.parseDouble (s: String): double { - action TODO(); + // NOTE: using original method + result = _parse(s); } @static fun *.sum (a: double, b: double): double { - action TODO(); + result = a + b; } @static fun *.toHexString (d: double): String { - action TODO(); + if (d != d) result = "NaN"; + else if (d == POSITIVE_INFINITY) result = "Infinity"; + else if (d == NEGATIVE_INFINITY) result = "-Infinity"; + else if (1.0 / d == NEGATIVE_INFINITY) result = "-0x0.0p0"; + else if (d == 0.0f) result = "0x0.0p0"; + else if (d == 1.0f) result = "0x1.0p0"; + else if (d == -1.0f) result = "-0x1.0p0"; + else + { + // #todo: add implementation if necessary + result = action SYMBOLIC("java.lang.String"); + action ASSUME(result != null); + val len: int = action CALL_METHOD(result, "length", []); + action ASSUME(len >= 7); // 0x1.0p0 + action ASSUME(len <= 22); // 0x1.fffffffffffffp1023 + } } @static fun *.toString (d: double): String { - action TODO(); + result = action OBJECT_TO_STRING(d); } @throws(["java.lang.NumberFormatException"]) - @static fun *.valueOf (s: String): Double + @Phantom @static fun *.valueOf (s: String): Double { - action TODO(); + // NOTE: using original method + result = new DoubleAutomaton(state = Initialized, + value = _parse(s) + ); } @static fun *.valueOf (d: double): Double { - action TODO(); + result = new DoubleAutomaton(state = Initialized, + value = d + ); } // methods - fun *.byteValue (@target self: Double): byte + fun *.byteValue (@target self: LSLDouble): byte { - action TODO(); + result = this.value as byte; } - fun *.compareTo (@target self: Double, anotherDouble: Double): int + fun *.compareTo (@target self: LSLDouble, anotherDouble: Double): int { - action TODO(); + val a: double = this.value; + val b: double = DoubleAutomaton(anotherDouble).value; + + // #problem: does not catch (-0.0, 0.0) + if (a == b || a != a || b != b) // include NaN's + { + result = 0; + } + else + { + if (a < b) + result = -1; + else + result = +1; + } } - fun *.doubleValue (@target self: Double): double + fun *.doubleValue (@target self: LSLDouble): double { - action TODO(); + result = this.value; } - fun *.equals (@target self: Double, obj: Object): boolean + fun *.equals (@target self: LSLDouble, obj: Object): boolean { - action TODO(); + if (obj is Double) + result = this.value == DoubleAutomaton(obj).value; + else + result = false; } - fun *.floatValue (@target self: Double): float + fun *.floatValue (@target self: LSLDouble): float { - action TODO(); + result = this.value as float; } - fun *.hashCode (@target self: Double): int + fun *.hashCode (@target self: LSLDouble): int { - action TODO(); + result = _getRawBits(this.value) as int; } - fun *.intValue (@target self: Double): int + fun *.intValue (@target self: LSLDouble): int { - action TODO(); + result = this.value as int; } - fun *.isInfinite (@target self: Double): boolean + fun *.isInfinite (@target self: LSLDouble): boolean { - action TODO(); + result = (this.value == POSITIVE_INFINITY) || + (this.value == NEGATIVE_INFINITY); } - fun *.isNaN (@target self: Double): boolean + fun *.isNaN (@target self: LSLDouble): boolean { - action TODO(); + result = this.value != this.value; } - fun *.longValue (@target self: Double): long + fun *.longValue (@target self: LSLDouble): long { - action TODO(); + result = this.value as long; } - fun *.shortValue (@target self: Double): short + fun *.shortValue (@target self: LSLDouble): short { - action TODO(); + result = this.value as short; } - fun *.toString (@target self: Double): String + fun *.toString (@target self: LSLDouble): String { - action TODO(); + result = action OBJECT_TO_STRING(this.value); } } diff --git a/spec/java/lang/Float.lsl b/spec/java/lang/Float.lsl index 739167c0..3f3acc46 100644 --- a/spec/java/lang/Float.lsl +++ b/spec/java/lang/Float.lsl @@ -28,7 +28,7 @@ import java/lang/Number; // note: this is a partial implementation, no need for additional constraints (abstract class) and synthetic methods (Comparable) // @extends("java.lang.Number") // @implements("java.lang.Comparable") -@public @final type LSLFloat +@final type LSLFloat is java.lang.Float for Float { diff --git a/spec/java/util/stream/DoubleStream.lsl b/spec/java/util/stream/DoubleStream.lsl index a8aebed2..b44384b9 100644 --- a/spec/java/util/stream/DoubleStream.lsl +++ b/spec/java/util/stream/DoubleStream.lsl @@ -30,6 +30,10 @@ import java/util/Spliterator; is java.util.stream.DoubleStreamLSL for DoubleStream { + @private @static val DOUBLE_POSITIVE_INFINITY: double = 1.0 / 0.0; + @private @static val DOUBLE_NEGATIVE_INFINITY: double = -1.0 / 0.0; + + @private @static val DOUBLE_NAN: double = 0.0 / 0.0; } From f03947be1b3b1eeba2b3967f93292c8a33f538c3 Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Wed, 15 Nov 2023 13:40:42 +0300 Subject: [PATCH 52/78] Added action `TYPE_OF` --- spec/java/lang/Byte.lsl | 3 ++- spec/java/lang/Double.lsl | 5 +++-- spec/java/lang/Float.lsl | 5 +++-- spec/java/lang/Integer.lsl | 6 ++++-- spec/java/lang/Long.lsl | 3 ++- spec/java/lang/Short.lsl | 3 ++- spec/translator.actions.lsl | 7 +++++++ 7 files changed, 23 insertions(+), 9 deletions(-) diff --git a/spec/java/lang/Byte.lsl b/spec/java/lang/Byte.lsl index ac5ee8ac..5319da67 100644 --- a/spec/java/lang/Byte.lsl +++ b/spec/java/lang/Byte.lsl @@ -17,8 +17,9 @@ import java/lang/Number; @FunctionalInterface("byteValue") @final type Byte is java.lang.Byte - for Comparable, Number, byte + for Comparable, Number { + // WARNING: use 'byteValue' to get primitive value } diff --git a/spec/java/lang/Double.lsl b/spec/java/lang/Double.lsl index d5b5238e..e91a45be 100644 --- a/spec/java/lang/Double.lsl +++ b/spec/java/lang/Double.lsl @@ -18,8 +18,9 @@ import java/lang/Number; @FunctionalInterface("doubleValue") @final type Double is java.lang.Double - for Comparable, Number, double + for Comparable, Number { + // WARNING: use 'doubleValue' to get primitive value } @@ -50,5 +51,5 @@ import java/lang/Number; @public @static val NaN: double = 0.0 / 0.0; - @public @static val TYPE: Class = action DEBUG_DO("Double.class"); + @public @static val TYPE: Class = action TYPE_OF("Double"); } diff --git a/spec/java/lang/Float.lsl b/spec/java/lang/Float.lsl index 3f3acc46..e3ca52ff 100644 --- a/spec/java/lang/Float.lsl +++ b/spec/java/lang/Float.lsl @@ -18,8 +18,9 @@ import java/lang/Number; @FunctionalInterface("floatValue") @final type Float is java.lang.Float - for Comparable, Number, float, double + for Comparable, Number { + // WARNING: use 'floatValue' to get primitive value } @@ -51,5 +52,5 @@ import java/lang/Number; @public @static val NaN: float = 0.0f / 0.0f; // #problem: unable to get reference to primitive type - @public @static val TYPE: Class = action DEBUG_DO("Float.class"); // preventing recursion + @public @static val TYPE: Class = action TYPE_OF("Float"); // preventing recursion } diff --git a/spec/java/lang/Integer.lsl b/spec/java/lang/Integer.lsl index 0c0a15b6..eae93433 100644 --- a/spec/java/lang/Integer.lsl +++ b/spec/java/lang/Integer.lsl @@ -18,8 +18,10 @@ import java/lang/Number; @FunctionalInterface("intValue") @final type Integer is java.lang.Integer - for Comparable, Number, int + for Comparable, Number { + // WARNING: use 'intValue' to get primitive value + @static fun *.valueOf(x: int): Number; // #problem: self-reference } @@ -39,7 +41,7 @@ import java/lang/Number; @public @static val MAX_VALUE: int = 2147483647; // #problem: unable to get reference to primitive type - @public @static val TYPE: Class = action DEBUG_DO("java.lang.Integer.class"); // preventing recursion + @public @static val TYPE: Class = action TYPE_OF("Integer"); // preventing recursion @public @static val SIZE: int = 32; @public @static val BYTES: int = 4; diff --git a/spec/java/lang/Long.lsl b/spec/java/lang/Long.lsl index ce483d9a..6511945c 100644 --- a/spec/java/lang/Long.lsl +++ b/spec/java/lang/Long.lsl @@ -17,8 +17,9 @@ import java/lang/Number; @FunctionalInterface("longValue") @final type Long is java.lang.Long - for Comparable, Number, long + for Comparable, Number { + // WARNING: use 'longValue' to get primitive value } diff --git a/spec/java/lang/Short.lsl b/spec/java/lang/Short.lsl index de8647e6..43346d5d 100644 --- a/spec/java/lang/Short.lsl +++ b/spec/java/lang/Short.lsl @@ -17,8 +17,9 @@ import java/lang/Number; @FunctionalInterface("shortValue") @final type Short is java.lang.Short - for Comparable, Number, short + for Comparable, Number { + // WARNING: use 'shortValue' to get primitive value } diff --git a/spec/translator.actions.lsl b/spec/translator.actions.lsl index 38167284..8373c84a 100644 --- a/spec/translator.actions.lsl +++ b/spec/translator.actions.lsl @@ -62,3 +62,10 @@ define action TODO (): void; // do nothing explicitly but detectable by the translator if needed define action DO_NOTHING (): void; + + +// usage example: action TYPE_OF("int") +// usage example: action TYPE_OF(obj) +define action TYPE_OF ( + valueOrName: any // string literal or a variable + ): any; From e64603cdd2ae2f18386909e594e5f5fbb01904b6 Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Wed, 15 Nov 2023 15:16:45 +0300 Subject: [PATCH 53/78] Added missing declaration for `@abstract` annotation + Added static method declarations to some types + Replaced `DEBUG_DO` by `CALL_METHOD` wherever possible --- spec/java.common.lsl | 2 ++ spec/java/lang/Character.lsl | 3 +++ spec/java/lang/Double.lsl | 29 +++++++++++++-------- spec/java/lang/Float.lsl | 29 +++++++++++++-------- spec/java/util/HashSet.main.lsl | 2 +- spec/java/util/LinkedHashSet.main.lsl | 2 +- spec/java/util/Random.main.lsl | 2 +- spec/java/util/stream/DoubleStream.main.lsl | 22 ++++++++-------- spec/java/util/stream/IntStream.main.lsl | 24 ++++++++--------- spec/java/util/stream/LongStream.main.lsl | 24 ++++++++--------- spec/java/util/stream/Stream.main.lsl | 16 ++++++------ 11 files changed, 87 insertions(+), 68 deletions(-) diff --git a/spec/java.common.lsl b/spec/java.common.lsl index a2a6349b..b25ed6c0 100644 --- a/spec/java.common.lsl +++ b/spec/java.common.lsl @@ -28,6 +28,8 @@ annotation packageprivate (); annotation public (); +annotation abstract (); + annotation extends ( canonicalClassName: string, ); diff --git a/spec/java/lang/Character.lsl b/spec/java/lang/Character.lsl index 7a8b5f47..4e764532 100644 --- a/spec/java/lang/Character.lsl +++ b/spec/java/lang/Character.lsl @@ -9,6 +9,7 @@ library std // imports import java/io/Serializable; +import java/lang/CharSequence; import java/lang/Comparable; @@ -20,6 +21,8 @@ import java/lang/Comparable; for Comparable, Serializable, char { fun *.charValue(): char; + + @static fun *.offsetByCodePoints(seq: CharSequence, index: int, codePointOffset: int): int; } diff --git a/spec/java/lang/Double.lsl b/spec/java/lang/Double.lsl index e91a45be..9c314d43 100644 --- a/spec/java/lang/Double.lsl +++ b/spec/java/lang/Double.lsl @@ -21,6 +21,13 @@ import java/lang/Number; for Comparable, Number { // WARNING: use 'doubleValue' to get primitive value + + @static fun *.isNaN(x: double): boolean; + + @static fun *.isFinite(x: double): boolean; + @static fun *.isInfinite(x: double): boolean; + + @static fun *.valueOf(x: double): Number; // #problem: self-reference } @@ -35,21 +42,21 @@ import java/lang/Number; { @private @static val serialVersionUID: long = -9172774392245257468L; - @public @static val BYTES: int = 8; - @public @static val SIZE: int = 64; + @static val BYTES: int = 8; + @static val SIZE: int = 64; - @public @static val MAX_EXPONENT: int = 1023; - @public @static val MIN_EXPONENT: int = -1022; + @static val MAX_EXPONENT: int = 1023; + @static val MIN_EXPONENT: int = -1022; // #problem: no support for scientific notation - @public @static val MAX_VALUE: double = action DEBUG_DO("1.7976931348623157E308"); - @public @static val MIN_VALUE: double = action DEBUG_DO("4.9E-324"); - @public @static val MIN_NORMAL: double = action DEBUG_DO("2.2250738585072014E-308"); + @static val MAX_VALUE: double = action DEBUG_DO("1.7976931348623157E308"); + @static val MIN_VALUE: double = action DEBUG_DO("4.9E-324"); + @static val MIN_NORMAL: double = action DEBUG_DO("2.2250738585072014E-308"); - @public @static val POSITIVE_INFINITY: double = 1.0 / 0.0; - @public @static val NEGATIVE_INFINITY: double = -1.0 / 0.0; + @static val POSITIVE_INFINITY: double = 1.0 / 0.0; + @static val NEGATIVE_INFINITY: double = -1.0 / 0.0; - @public @static val NaN: double = 0.0 / 0.0; + @static val NaN: double = 0.0 / 0.0; - @public @static val TYPE: Class = action TYPE_OF("Double"); + @static val TYPE: Class = action TYPE_OF("Double"); } diff --git a/spec/java/lang/Float.lsl b/spec/java/lang/Float.lsl index e3ca52ff..0eef245f 100644 --- a/spec/java/lang/Float.lsl +++ b/spec/java/lang/Float.lsl @@ -21,6 +21,13 @@ import java/lang/Number; for Comparable, Number { // WARNING: use 'floatValue' to get primitive value + + @static fun *.isNaN(x: float): boolean; + + @static fun *.isFinite(x: float): boolean; + @static fun *.isInfinite(x: float): boolean; + + @static fun *.valueOf(x: float): Number; // #problem: self-reference } @@ -35,22 +42,22 @@ import java/lang/Number; { @private @static val serialVersionUID: long = -2671257302660747028L; - @public @static val BYTES: int = 4; - @public @static val SIZE: int = 32; + @static val BYTES: int = 4; + @static val SIZE: int = 32; - @public @static val MAX_EXPONENT: int = 127; - @public @static val MIN_EXPONENT: int = -126; + @static val MAX_EXPONENT: int = 127; + @static val MIN_EXPONENT: int = -126; // #problem: no "scientific" notation support - @public @static val MAX_VALUE: float = action DEBUG_DO("3.4028235e+38f"); - @public @static val MIN_VALUE: float = action DEBUG_DO("1.4e-45f"); + @static val MAX_VALUE: float = action DEBUG_DO("3.4028235e+38f"); + @static val MIN_VALUE: float = action DEBUG_DO("1.4e-45f"); - @public @static val MIN_NORMAL: float = action DEBUG_DO("1.17549435e-38f"); + @static val MIN_NORMAL: float = action DEBUG_DO("1.17549435e-38f"); - @public @static val NEGATIVE_INFINITY: float = -1.0f / 0.0f; - @public @static val POSITIVE_INFINITY: float = 1.0f / 0.0f; - @public @static val NaN: float = 0.0f / 0.0f; + @static val NEGATIVE_INFINITY: float = -1.0f / 0.0f; + @static val POSITIVE_INFINITY: float = 1.0f / 0.0f; + @static val NaN: float = 0.0f / 0.0f; // #problem: unable to get reference to primitive type - @public @static val TYPE: Class = action TYPE_OF("Float"); // preventing recursion + @static val TYPE: Class = action TYPE_OF("Float"); // preventing recursion } diff --git a/spec/java/util/HashSet.main.lsl b/spec/java/util/HashSet.main.lsl index 28a16561..c2fde70f 100644 --- a/spec/java/util/HashSet.main.lsl +++ b/spec/java/util/HashSet.main.lsl @@ -172,7 +172,7 @@ automaton HashSetAutomaton action THROW_NEW("java.lang.IllegalArgumentException", []); } - if (loadFactor <= 0 || action DEBUG_DO("Float.isNaN(loadFactor)")) + if (loadFactor <= 0 || loadFactor != loadFactor /* NaN */) { // val loadFactorStr: String = "Illegal load factor: " + action OBJECT_TO_STRING(loadFactor); action THROW_NEW("java.lang.IllegalArgumentException", []); diff --git a/spec/java/util/LinkedHashSet.main.lsl b/spec/java/util/LinkedHashSet.main.lsl index 13b595ce..61eaadb1 100644 --- a/spec/java/util/LinkedHashSet.main.lsl +++ b/spec/java/util/LinkedHashSet.main.lsl @@ -169,7 +169,7 @@ automaton LinkedHashSetAutomaton action THROW_NEW("java.lang.IllegalArgumentException", []); } - if (loadFactor <= 0 || action DEBUG_DO("Float.isNaN(loadFactor)")) + if (loadFactor <= 0 || loadFactor != loadFactor /* NaN */) { // val loadFactorStr: String = "Illegal load factor: " + action OBJECT_TO_STRING(loadFactor); action THROW_NEW("java.lang.IllegalArgumentException", []); diff --git a/spec/java/util/Random.main.lsl b/spec/java/util/Random.main.lsl index f1716784..cd7b9811 100644 --- a/spec/java/util/Random.main.lsl +++ b/spec/java/util/Random.main.lsl @@ -221,7 +221,7 @@ automaton RandomAutomaton @synchronized fun *.nextGaussian (@target self: Random): double { result = action SYMBOLIC("double"); - val isNaN: boolean = action DEBUG_DO("Double.isNaN(result)"); + val isNaN: boolean = result != result; action ASSUME(isNaN == false); } diff --git a/spec/java/util/stream/DoubleStream.main.lsl b/spec/java/util/stream/DoubleStream.main.lsl index f30f09d4..80fef2a7 100644 --- a/spec/java/util/stream/DoubleStream.main.lsl +++ b/spec/java/util/stream/DoubleStream.main.lsl @@ -134,12 +134,12 @@ automaton DoubleStreamAutomaton { if (this.length == 0) { - result = action DEBUG_DO("OptionalDouble.empty()"); + result = action CALL_METHOD(null as OptionalDouble, "empty", []); } else { val first: double = this.storage[0]; - result = action DEBUG_DO("OptionalDouble.of(first)"); + result = action CALL_METHOD(null as OptionalDouble, "of", [first]); } } @@ -178,7 +178,7 @@ automaton DoubleStreamAutomaton val element: double = this.storage[i]; result += element; - if (action DEBUG_DO("Double.isNaN(element)")) + if (element != element /* NaN */) anyNaN = true; if (element == DOUBLE_POSITIVE_INFINITY) @@ -684,7 +684,7 @@ automaton DoubleStreamAutomaton if (this.length == 0) { - result = action DEBUG_DO("OptionalDouble.empty()"); + result = action CALL_METHOD(null as OptionalDouble, "empty", []); } else if (this.length > 0) { @@ -696,7 +696,7 @@ automaton DoubleStreamAutomaton _accumulate_optional_loop(i, accumulator, value) ); - result = action DEBUG_DO("OptionalDouble.of(value)"); + result = action CALL_METHOD(null as OptionalDouble, "of", [value]); } _consume(); @@ -747,7 +747,7 @@ automaton DoubleStreamAutomaton if (this.length == 0) { - result = action DEBUG_DO("OptionalDouble.empty()"); + result = action CALL_METHOD(null as OptionalDouble, "empty", []); } else { @@ -759,7 +759,7 @@ automaton DoubleStreamAutomaton _find_min_loop(i, min) ); - result = action DEBUG_DO("OptionalDouble.of(min)"); + result = action CALL_METHOD(null as OptionalDouble, "of", [min]); } _consume(); @@ -779,7 +779,7 @@ automaton DoubleStreamAutomaton if (this.length == 0) { - result = action DEBUG_DO("OptionalDouble.empty()"); + result = action CALL_METHOD(null as OptionalDouble, "empty", []); } else { @@ -791,7 +791,7 @@ automaton DoubleStreamAutomaton _find_max_loop(i, max) ); - result = action DEBUG_DO("OptionalDouble.of(max)"); + result = action CALL_METHOD(null as OptionalDouble, "of", [max]); } _consume(); @@ -1178,13 +1178,13 @@ automaton DoubleStreamAutomaton if (this.length == 0) { - result = action DEBUG_DO("OptionalDouble.empty()"); + result = action CALL_METHOD(null as OptionalDouble, "empty", []); } else { var curSum: double = _sum(); var divisionResult: double = curSum / this.length; - result = action DEBUG_DO("OptionalDouble.of(divisionResult)"); + result = action CALL_METHOD(null as OptionalDouble, "of", [divisionResult]); } _consume(); diff --git a/spec/java/util/stream/IntStream.main.lsl b/spec/java/util/stream/IntStream.main.lsl index dc6b6dcb..0dee2557 100644 --- a/spec/java/util/stream/IntStream.main.lsl +++ b/spec/java/util/stream/IntStream.main.lsl @@ -86,8 +86,8 @@ automaton IntStreamAutomaton var isParallel: boolean = false; var linkedOrConsumed: boolean = false; - // utilities - + // utilities + @AutoInline @Phantom proc _checkConsumed (): void { if (this.linkedOrConsumed) @@ -136,12 +136,12 @@ automaton IntStreamAutomaton { if (this.length == 0) { - result = action DEBUG_DO("OptionalInt.empty()"); + result = action CALL_METHOD(null as OptionalInt, "empty", []); } else { val first: int = this.storage[0]; - result = action DEBUG_DO("OptionalInt.of(first)"); + result = action CALL_METHOD(null as OptionalInt, "of", [first]); } } @@ -660,7 +660,7 @@ automaton IntStreamAutomaton if (this.length == 0) { - result = action DEBUG_DO("OptionalInt.empty()"); + result = action CALL_METHOD(null as OptionalInt, "empty", []); } else if (this.length > 0) { @@ -672,7 +672,7 @@ automaton IntStreamAutomaton _accumulate_optional_loop(i, accumulator, value) ); - result = action DEBUG_DO("OptionalInt.of(value)"); + result = action CALL_METHOD(null as OptionalInt, "of", [value]); } _consume(); @@ -723,7 +723,7 @@ automaton IntStreamAutomaton if (this.length == 0) { - result = action DEBUG_DO("OptionalInt.empty()"); + result = action CALL_METHOD(null as OptionalInt, "empty", []); } else { @@ -735,7 +735,7 @@ automaton IntStreamAutomaton _find_min_loop(i, min) ); - result = action DEBUG_DO("OptionalInt.of(min)"); + result = action CALL_METHOD(null as OptionalInt, "of", [min]); } _consume(); @@ -755,7 +755,7 @@ automaton IntStreamAutomaton if (this.length == 0) { - result = action DEBUG_DO("OptionalInt.empty()"); + result = action CALL_METHOD(null as OptionalInt, "empty", []); } else { @@ -767,7 +767,7 @@ automaton IntStreamAutomaton _find_max_loop(i, max) ); - result = action DEBUG_DO("OptionalInt.of(max)"); + result = action CALL_METHOD(null as OptionalInt, "of", [max]); } _consume(); @@ -1238,13 +1238,13 @@ automaton IntStreamAutomaton if (this.length == 0) { - result = action DEBUG_DO("OptionalDouble.empty()"); + result = action CALL_METHOD(null as OptionalDouble, "empty", []); } else { var curSum: double = _sum(); var divisionResult: double = curSum / this.length; - result = action DEBUG_DO("OptionalDouble.of(divisionResult)"); + result = action CALL_METHOD(null as OptionalDouble, "of", [divisionResult]); } _consume(); diff --git a/spec/java/util/stream/LongStream.main.lsl b/spec/java/util/stream/LongStream.main.lsl index 5209f990..a8aba97d 100644 --- a/spec/java/util/stream/LongStream.main.lsl +++ b/spec/java/util/stream/LongStream.main.lsl @@ -87,7 +87,7 @@ automaton LongStreamAutomaton var linkedOrConsumed: boolean = false; // utilities - + @AutoInline @Phantom proc _checkConsumed (): void { if (this.linkedOrConsumed) @@ -99,7 +99,7 @@ automaton LongStreamAutomaton { this.linkedOrConsumed = true; } - + @AutoInline @Phantom proc _throwNPE (): void { @@ -136,12 +136,12 @@ automaton LongStreamAutomaton { if (this.length == 0) { - result = action DEBUG_DO("OptionalLong.empty()"); + result = action CALL_METHOD(null as OptionalLong, "empty", []); } else { val first: long = this.storage[0]; - result = action DEBUG_DO("OptionalLong.of(first)"); + result = action CALL_METHOD(null as OptionalLong, "of", [first]); } } @@ -661,7 +661,7 @@ automaton LongStreamAutomaton if (this.length == 0) { - result = action DEBUG_DO("OptionalLong.empty()"); + result = action CALL_METHOD(null as OptionalLong, "empty", []); } else if (this.length > 0) { @@ -673,7 +673,7 @@ automaton LongStreamAutomaton _accumulate_optional_loop(i, accumulator, value) ); - result = action DEBUG_DO("OptionalLong.of(value)"); + result = action CALL_METHOD(null as OptionalLong, "of", [value]); } _consume(); @@ -724,7 +724,7 @@ automaton LongStreamAutomaton if (this.length == 0) { - result = action DEBUG_DO("OptionalLong.empty()"); + result = action CALL_METHOD(null as OptionalLong, "empty", []); } else { @@ -736,7 +736,7 @@ automaton LongStreamAutomaton _find_min_loop(i, min) ); - result = action DEBUG_DO("OptionalLong.of(min)"); + result = action CALL_METHOD(null as OptionalLong, "of", [min]); } _consume(); @@ -756,7 +756,7 @@ automaton LongStreamAutomaton if (this.length == 0) { - result = action DEBUG_DO("OptionalLong.empty()"); + result = action CALL_METHOD(null as OptionalLong, "empty", []); } else { @@ -768,7 +768,7 @@ automaton LongStreamAutomaton _find_max_loop(i, max) ); - result = action DEBUG_DO("OptionalLong.of(max)"); + result = action CALL_METHOD(null as OptionalLong, "of", [max]); } _consume(); @@ -1197,13 +1197,13 @@ automaton LongStreamAutomaton if (this.length == 0) { - result = action DEBUG_DO("OptionalDouble.empty()"); + result = action CALL_METHOD(null as OptionalDouble, "empty", []); } else { var curSum: double = _sum(); var divisionResult: double = curSum / this.length; - result = action DEBUG_DO("OptionalDouble.of(divisionResult)"); + result = action CALL_METHOD(null as OptionalDouble, "of", [divisionResult]); } _consume(); diff --git a/spec/java/util/stream/Stream.main.lsl b/spec/java/util/stream/Stream.main.lsl index a93ebb89..5dd4c08d 100644 --- a/spec/java/util/stream/Stream.main.lsl +++ b/spec/java/util/stream/Stream.main.lsl @@ -151,12 +151,12 @@ automaton StreamAutomaton { if (this.length == 0) { - result = action DEBUG_DO("Optional.empty()"); + result = action CALL_METHOD(null as Optional, "empty", []); } else { val first: Object = this.storage[0]; - result = action DEBUG_DO("Optional.ofNullable(first)"); + result = action CALL_METHOD(null as Optional, "ofNullable", [first]); } } @@ -791,7 +791,7 @@ automaton StreamAutomaton if (this.length == 0) { - result = action DEBUG_DO("Optional.empty()"); + result = action CALL_METHOD(null as Optional, "empty", []); } else if (this.length > 0) { @@ -803,7 +803,7 @@ automaton StreamAutomaton _accumulate_optional_loop(i, accumulator, value) ); - result = action DEBUG_DO("Optional.ofNullable(value)"); + result = action CALL_METHOD(null as Optional, "ofNullable", [value]); } _consume(); @@ -908,7 +908,7 @@ automaton StreamAutomaton if (this.length == 0) { - result = action DEBUG_DO("Optional.empty()"); + result = action CALL_METHOD(null as Optional, "empty", []); } else { @@ -920,7 +920,7 @@ automaton StreamAutomaton _find_min_loop(i, comparator, min) ); - result = action DEBUG_DO("Optional.ofNullable(min)"); + result = action CALL_METHOD(null as Optional, "ofNullable", [min]); } _consume(); @@ -943,7 +943,7 @@ automaton StreamAutomaton if (this.length == 0) { - result = action DEBUG_DO("Optional.empty()"); + result = action CALL_METHOD(null as Optional, "empty", []); } else { @@ -955,7 +955,7 @@ automaton StreamAutomaton _find_max_loop(i, comparator, max) ); - result = action DEBUG_DO("Optional.ofNullable(max)"); + result = action CALL_METHOD(null as Optional, "ofNullable", [max]); } _consume(); From dd3f7ef7fbbf821000b4ed2e6e65f4690e106394 Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Wed, 22 Nov 2023 11:39:11 +0300 Subject: [PATCH 54/78] Minor improvements to `double/float` to `long/int` conversion modelling --- spec/java/lang/Double.main.lsl | 10 ++++++++++ spec/java/lang/Float.main.lsl | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/spec/java/lang/Double.main.lsl b/spec/java/lang/Double.main.lsl index 8a6d5f91..a8aed3c4 100644 --- a/spec/java/lang/Double.main.lsl +++ b/spec/java/lang/Double.main.lsl @@ -92,6 +92,11 @@ automaton DoubleAutomaton action ASSUME(result != 0L); action ASSUME(result != 9218868437227405312L); action ASSUME(result != -4503599627370496L); + + if (v < 0.0) + action ASSUME(result < 0L); + else + action ASSUME(result > 0L); } } @@ -200,6 +205,11 @@ automaton DoubleAutomaton action ASSUME(result == result); action ASSUME(result != POSITIVE_INFINITY); action ASSUME(result != NEGATIVE_INFINITY); + + if (value < 0L) + action ASSUME(result < 0.0); + else + action ASSUME(result > 0.0); } } diff --git a/spec/java/lang/Float.main.lsl b/spec/java/lang/Float.main.lsl index cb2737e9..751751ef 100644 --- a/spec/java/lang/Float.main.lsl +++ b/spec/java/lang/Float.main.lsl @@ -92,6 +92,11 @@ automaton FloatAutomaton action ASSUME(result != 0); action ASSUME(result != 2139095040); action ASSUME(result != -8388608); + + if (v < 0.0f) + action ASSUME(result < 0); + else + action ASSUME(result > 0); } } @@ -187,6 +192,11 @@ automaton FloatAutomaton action ASSUME(result == result); action ASSUME(result != POSITIVE_INFINITY); action ASSUME(result != NEGATIVE_INFINITY); + + if (value < 0) + action ASSUME(result < 0.0f); + else + action ASSUME(result > 0.0f); } } From ea079839fbf8ad7b834f703975842d7d8d753303 Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Thu, 23 Nov 2023 14:12:17 +0300 Subject: [PATCH 55/78] Minor field access optimization for `java.lang.System` --- spec/java/lang/System.main.lsl | 115 +++++++++++++++++---------------- 1 file changed, 58 insertions(+), 57 deletions(-) diff --git a/spec/java/lang/System.main.lsl b/spec/java/lang/System.main.lsl index 15499010..ad0f70f1 100644 --- a/spec/java/lang/System.main.lsl +++ b/spec/java/lang/System.main.lsl @@ -93,6 +93,7 @@ automaton SystemAutomaton @static proc _initProperties (): void { // prepare raw values + val pm: map = propsMap; // NOTE: avoiding unwanted frequent static field access // NOTE: symbolic JRE version is too expensive to use val javaVersion: int = 8; @@ -102,11 +103,11 @@ automaton SystemAutomaton // convert it into properties - action MAP_SET(propsMap, "file.encoding", "Cp1251"); - action MAP_SET(propsMap, "sun.io.unicode.encoding", "UnicodeLittle"); - action MAP_SET(propsMap, "sun.jnu.encoding", "Cp1251"); - action MAP_SET(propsMap, "sun.stderr.encoding", "cp866"); - action MAP_SET(propsMap, "sun.stdout.encoding", "cp866"); + action MAP_SET(pm, "file.encoding", "Cp1251"); + action MAP_SET(pm, "sun.io.unicode.encoding", "UnicodeLittle"); + action MAP_SET(pm, "sun.jnu.encoding", "Cp1251"); + action MAP_SET(pm, "sun.stderr.encoding", "cp866"); + action MAP_SET(pm, "sun.stdout.encoding", "cp866"); val versionStrings: array = [ "0", "1", "2", "3", "4", "5", "6", "7", @@ -118,39 +119,39 @@ automaton SystemAutomaton ]; val versionString: String = versionStrings[javaVersion]; - action MAP_SET(propsMap, "java.specification.name", "Java Platform API Specification"); - action MAP_SET(propsMap, "java.specification.vendor", "Oracle Corporation"); - action MAP_SET(propsMap, "java.specification.version", versionString); - action MAP_SET(propsMap, "java.vm.info", "mixed mode"); - action MAP_SET(propsMap, "java.vm.name", "OpenJDK 64-Bit Server VM"); - action MAP_SET(propsMap, "java.vm.specification.name", "Java Virtual Machine Specification"); - action MAP_SET(propsMap, "java.vm.specification.vendor", "Oracle Corporation"); - action MAP_SET(propsMap, "java.vm.specification.version", versionString); - action MAP_SET(propsMap, "java.vm.vendor", "Eclipse Adoptium"); - action MAP_SET(propsMap, "java.vm.version", versionString + ".0.362+9"); - - action MAP_SET(propsMap, "java.library.path", "C:\\Program Files\\Eclipse Adoptium\\jdk-8.0.362.9-hotspot\\bin;C:\\Windows\\Sun\\Java\\bin;C:\\Windows\\system32;."); - action MAP_SET(propsMap, "java.home", "C:\\Program Files\\Eclipse Adoptium\\jdk-8.0.362.9-hotspot"); - action MAP_SET(propsMap, "sun.boot.library.path", "C:\\Program Files\\Eclipse Adoptium\\jdk-8.0.362.9-hotspot\\bin"); - action MAP_SET(propsMap, "java.io.tmpdir", "T:\\Temp\\"); - action MAP_SET(propsMap, "java.class.path", "."); + action MAP_SET(pm, "java.specification.name", "Java Platform API Specification"); + action MAP_SET(pm, "java.specification.vendor", "Oracle Corporation"); + action MAP_SET(pm, "java.specification.version", versionString); + action MAP_SET(pm, "java.vm.info", "mixed mode"); + action MAP_SET(pm, "java.vm.name", "OpenJDK 64-Bit Server VM"); + action MAP_SET(pm, "java.vm.specification.name", "Java Virtual Machine Specification"); + action MAP_SET(pm, "java.vm.specification.vendor", "Oracle Corporation"); + action MAP_SET(pm, "java.vm.specification.version", versionString); + action MAP_SET(pm, "java.vm.vendor", "Eclipse Adoptium"); + action MAP_SET(pm, "java.vm.version", versionString + ".0.362+9"); + + action MAP_SET(pm, "java.library.path", "C:\\Program Files\\Eclipse Adoptium\\jdk-8.0.362.9-hotspot\\bin;C:\\Windows\\Sun\\Java\\bin;C:\\Windows\\system32;."); + action MAP_SET(pm, "java.home", "C:\\Program Files\\Eclipse Adoptium\\jdk-8.0.362.9-hotspot"); + action MAP_SET(pm, "sun.boot.library.path", "C:\\Program Files\\Eclipse Adoptium\\jdk-8.0.362.9-hotspot\\bin"); + action MAP_SET(pm, "java.io.tmpdir", "T:\\Temp\\"); + action MAP_SET(pm, "java.class.path", "."); if (SYSTEM_IS_WINDOWS) { - action MAP_SET(propsMap, "file.separator", "\\"); - action MAP_SET(propsMap, "line.separator", "\r\n"); - action MAP_SET(propsMap, "path.separator", ";"); + action MAP_SET(pm, "file.separator", "\\"); + action MAP_SET(pm, "line.separator", "\r\n"); + action MAP_SET(pm, "path.separator", ";"); } else { - action MAP_SET(propsMap, "file.separator", "/"); - action MAP_SET(propsMap, "line.separator", "\n"); - action MAP_SET(propsMap, "path.separator", ":"); + action MAP_SET(pm, "file.separator", "/"); + action MAP_SET(pm, "line.separator", "\n"); + action MAP_SET(pm, "path.separator", ":"); } - action MAP_SET(propsMap, "user.country", "RU"); - action MAP_SET(propsMap, "user.country.format", "US"); - action MAP_SET(propsMap, "user.language", "ru"); + action MAP_SET(pm, "user.country", "RU"); + action MAP_SET(pm, "user.country.format", "US"); + action MAP_SET(pm, "user.language", "ru"); val bytecodeVersions: array = [ "?", /* 0? */ @@ -170,35 +171,35 @@ automaton SystemAutomaton "?", /* 14? */ "?", /* 15? */ ]; - action MAP_SET(propsMap, "java.class.version", bytecodeVersions[javaVersion]); - - action MAP_SET(propsMap, "os.arch", "amd64"); - action MAP_SET(propsMap, "os.name", "Windows 10"); - action MAP_SET(propsMap, "os.version", "10.0"); - action MAP_SET(propsMap, "sun.arch.data.model", "64"); - action MAP_SET(propsMap, "sun.cpu.endian", "little"); - action MAP_SET(propsMap, "sun.cpu.isalist", "amd64"); - action MAP_SET(propsMap, "sun.desktop", "windows"); - - action MAP_SET(propsMap, "user.dir", "D:\\Company\\Prod\\Service"); - action MAP_SET(propsMap, "user.home", "C:\\Users\\" + userName); - action MAP_SET(propsMap, "user.name", userName); - action MAP_SET(propsMap, "user.script", ""); - action MAP_SET(propsMap, "user.timezone", ""); - action MAP_SET(propsMap, "user.variant", ""); + action MAP_SET(pm, "java.class.version", bytecodeVersions[javaVersion]); + + action MAP_SET(pm, "os.arch", "amd64"); + action MAP_SET(pm, "os.name", "Windows 10"); + action MAP_SET(pm, "os.version", "10.0"); + action MAP_SET(pm, "sun.arch.data.model", "64"); + action MAP_SET(pm, "sun.cpu.endian", "little"); + action MAP_SET(pm, "sun.cpu.isalist", "amd64"); + action MAP_SET(pm, "sun.desktop", "windows"); + + action MAP_SET(pm, "user.dir", "D:\\Company\\Prod\\Service"); + action MAP_SET(pm, "user.home", "C:\\Users\\" + userName); + action MAP_SET(pm, "user.name", userName); + action MAP_SET(pm, "user.script", ""); + action MAP_SET(pm, "user.timezone", ""); + action MAP_SET(pm, "user.variant", ""); // unknown misc stuff - action MAP_SET(propsMap, "sun.java.command", "org.example.MainClass"); // #problem: main class - action MAP_SET(propsMap, "awt.toolkit", "sun.awt.windows.WToolkit"); - action MAP_SET(propsMap, "java.awt.graphicsenv", "sun.awt.Win32GraphicsEnvironment"); - action MAP_SET(propsMap, "java.awt.printerjob", "sun.awt.windows.WPrinterJob"); - action MAP_SET(propsMap, "sun.java.launcher", "SUN_STANDARD"); - action MAP_SET(propsMap, "sun.management.compiler", "HotSpot 64-Bit Tiered Compilers"); - action MAP_SET(propsMap, "sun.nio.MaxDirectMemorySize", "-1"); - action MAP_SET(propsMap, "sun.os.patch.level", ""); - action MAP_SET(propsMap, "java.vm.compressedOopsMode", "Zero based"); - action MAP_SET(propsMap, "jdk.boot.class.path.append", ""); - action MAP_SET(propsMap, "jdk.debug", "release"); + action MAP_SET(pm, "sun.java.command", "org.example.MainClass"); // #problem: main class + action MAP_SET(pm, "awt.toolkit", "sun.awt.windows.WToolkit"); + action MAP_SET(pm, "java.awt.graphicsenv", "sun.awt.Win32GraphicsEnvironment"); + action MAP_SET(pm, "java.awt.printerjob", "sun.awt.windows.WPrinterJob"); + action MAP_SET(pm, "sun.java.launcher", "SUN_STANDARD"); + action MAP_SET(pm, "sun.management.compiler", "HotSpot 64-Bit Tiered Compilers"); + action MAP_SET(pm, "sun.nio.MaxDirectMemorySize", "-1"); + action MAP_SET(pm, "sun.os.patch.level", ""); + action MAP_SET(pm, "java.vm.compressedOopsMode", "Zero based"); + action MAP_SET(pm, "jdk.boot.class.path.append", ""); + action MAP_SET(pm, "jdk.debug", "release"); // #problem: no approximation for Properties props = null;//new Properties(84); From fe5b76f9d8e3ddb6921e48908e94e770f73b40db Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Fri, 24 Nov 2023 11:13:52 +0300 Subject: [PATCH 56/78] Fix some issues found by the reviewer --- spec/java/lang/Character.lsl | 4 ++- spec/java/lang/ClassLoader.lsl | 6 ++-- spec/java/lang/Double.lsl | 5 ++- spec/java/lang/Double.main.lsl | 21 ++++++++++--- spec/java/lang/Float.lsl | 5 ++- spec/java/lang/Float.main.lsl | 23 ++++++++++---- spec/java/lang/Integer.lsl | 5 ++- spec/java/lang/Integer.main.lsl | 29 ++++++++++++----- spec/java/lang/SecurityManager.lsl | 2 ++ spec/java/lang/SecurityManager.main.lsl | 3 +- spec/java/lang/System.StdOut.lsl | 13 ++++---- spec/java/lang/System.main.lsl | 41 +++++++++++++++---------- 12 files changed, 99 insertions(+), 58 deletions(-) diff --git a/spec/java/lang/Character.lsl b/spec/java/lang/Character.lsl index 4e764532..64249f78 100644 --- a/spec/java/lang/Character.lsl +++ b/spec/java/lang/Character.lsl @@ -18,8 +18,10 @@ import java/lang/Comparable; @FunctionalInterface("charValue") @final type Character is java.lang.Character - for Comparable, Serializable, char + for Comparable, Serializable { + // WARNING: use 'charValue' to get primitive value + fun *.charValue(): char; @static fun *.offsetByCodePoints(seq: CharSequence, index: int, codePointOffset: int): int; diff --git a/spec/java/lang/ClassLoader.lsl b/spec/java/lang/ClassLoader.lsl index 01d9c75b..5cbe3d09 100644 --- a/spec/java/lang/ClassLoader.lsl +++ b/spec/java/lang/ClassLoader.lsl @@ -8,16 +8,14 @@ library std // imports -import java/io/Serializable; -import java/lang/String; +import java/lang/Object; // primary semantic types @final type ClassLoader is java.lang.ClassLoader - // #problem: no reflection support - for Serializable //, GenericDeclaration, Type, AnnotatedElement + for Object { } diff --git a/spec/java/lang/Double.lsl b/spec/java/lang/Double.lsl index 9c314d43..fc6ff7e3 100644 --- a/spec/java/lang/Double.lsl +++ b/spec/java/lang/Double.lsl @@ -33,9 +33,8 @@ import java/lang/Number; // global aliases and type overrides -// note: this is a partial implementation, no need for additional constraints (abstract class) and synthetic methods (Comparable) -// @extends("java.lang.Number") -// @implements("java.lang.Comparable") +@extends("java.lang.Number") +@implements("java.lang.Comparable") @final type LSLDouble is java.lang.Double for Double diff --git a/spec/java/lang/Double.main.lsl b/spec/java/lang/Double.main.lsl index a8aed3c4..dc16b1b1 100644 --- a/spec/java/lang/Double.main.lsl +++ b/spec/java/lang/Double.main.lsl @@ -166,8 +166,11 @@ automaton DoubleAutomaton @static fun *.isFinite (d: double): boolean { - result = (d != POSITIVE_INFINITY) && - (d != NEGATIVE_INFINITY); + // behaving similarly to Math.abs + if (d <= 0.0) + d = 0.0 - d; + + result = d <= MAX_VALUE; } @@ -216,7 +219,11 @@ automaton DoubleAutomaton @static fun *.max (a: double, b: double): double { - if (a > b) + if (a != a) // catching NaN's + result = a; + else if (a == 0.0 && b == 0.0 && 1.0 / a == NEGATIVE_INFINITY) // catching '-0.0' + result = b; + else if (a >= b) result = a; else result = b; @@ -225,7 +232,11 @@ automaton DoubleAutomaton @static fun *.min (a: double, b: double): double { - if (a < b) + if (a != a) // catching NaN's + result = a; + else if (a == 0.0 && b == 0.0 && 1.0 / b == NEGATIVE_INFINITY) // catching '-0.0' + result = b; + else if (a <= b) result = a; else result = b; @@ -299,7 +310,7 @@ automaton DoubleAutomaton } - fun *.compareTo (@target self: LSLDouble, anotherDouble: Double): int + fun *.compareTo (@target self: LSLDouble, anotherDouble: LSLDouble): int { val a: double = this.value; val b: double = DoubleAutomaton(anotherDouble).value; diff --git a/spec/java/lang/Float.lsl b/spec/java/lang/Float.lsl index 0eef245f..fff96c1e 100644 --- a/spec/java/lang/Float.lsl +++ b/spec/java/lang/Float.lsl @@ -33,9 +33,8 @@ import java/lang/Number; // global aliases and type overrides -// note: this is a partial implementation, no need for additional constraints (abstract class) and synthetic methods (Comparable) -// @extends("java.lang.Number") -// @implements("java.lang.Comparable") +@extends("java.lang.Number") +@implements("java.lang.Comparable") @final type LSLFloat is java.lang.Float for Float diff --git a/spec/java/lang/Float.main.lsl b/spec/java/lang/Float.main.lsl index 751751ef..487baff5 100644 --- a/spec/java/lang/Float.main.lsl +++ b/spec/java/lang/Float.main.lsl @@ -203,8 +203,11 @@ automaton FloatAutomaton @static fun *.isFinite (f: float): boolean { - result = (f != POSITIVE_INFINITY) && - (f != NEGATIVE_INFINITY); + // behaving similarly to Math.abs + if (f <= 0.0f) + f = 0.0f - f; + + result = f <= MAX_VALUE; } @@ -223,7 +226,11 @@ automaton FloatAutomaton @static fun *.max (a: float, b: float): float { - if (a > b) + if (a != a) // catching NaN's + result = a; + else if (a == 0.0f && b == 0.0f && 1.0f / a == NEGATIVE_INFINITY) // catching '-0.0' + result = b; + else if (a >= b) result = a; else result = b; @@ -232,7 +239,11 @@ automaton FloatAutomaton @static fun *.min (a: float, b: float): float { - if (a < b) + if (a != a) // catching NaN's + result = a; + else if (a == 0.0f && b == 0.0f && 1.0f / b == NEGATIVE_INFINITY) // catching '-0.0' + result = b; + else if (a <= b) result = a; else result = b; @@ -306,10 +317,10 @@ automaton FloatAutomaton } - fun *.compareTo (@target self: LSLFloat, anotherFloat: Float): int + fun *.compareTo (@target self: LSLFloat, anotherFloat: LSLFloat): int { val a: float = this.value; - val b: float = action CALL_METHOD(anotherFloat, "floatValue", []); + val b: float = FloatAutomaton(anotherFloat).value; // #problem: does not catch (-0.0, 0.0) if (a == b || a != a || b != b) // include NaN's diff --git a/spec/java/lang/Integer.lsl b/spec/java/lang/Integer.lsl index eae93433..b2ddbfc3 100644 --- a/spec/java/lang/Integer.lsl +++ b/spec/java/lang/Integer.lsl @@ -28,9 +28,8 @@ import java/lang/Number; // global aliases and type overrides -// note: this is a partial implementation, no need for additional constraints (abstract class) and synthetic methods (Comparable) -// @extends("java.lang.Number") -// @implements("java.lang.Comparable") +@extends("java.lang.Number") +@implements("java.lang.Comparable") @final type LSLInteger is java.lang.Integer for Integer diff --git a/spec/java/lang/Integer.main.lsl b/spec/java/lang/Integer.main.lsl index 8569ac49..4c302ae8 100644 --- a/spec/java/lang/Integer.main.lsl +++ b/spec/java/lang/Integer.main.lsl @@ -272,14 +272,14 @@ automaton IntegerAutomaton { // direct adaptation from the JDK var y: int = 0; - var n: int = 31; + result = 31; - y = i << 16; if (y != 0) { n -= 16; i = y; } - y = i << 8; if (y != 0) { n -= 8; i = y; } - y = i << 4; if (y != 0) { n -= 4; i = y; } - y = i << 2; if (y != 0) { n -= 2; i = y; } + y = i << 16; if (y != 0) { result -= 16; i = y; } + y = i << 8; if (y != 0) { result -= 8; i = y; } + y = i << 4; if (y != 0) { result -= 4; i = y; } + y = i << 2; if (y != 0) { result -= 2; i = y; } - result = n - ((i << 1) >>> 31); + result -= ((i << 1) >>> 31); } } @@ -463,9 +463,22 @@ automaton IntegerAutomaton } - @Phantom fun *.compareTo (@target self: LSLInteger, anotherInteger: Integer): int + fun *.compareTo (@target self: LSLInteger, anotherInteger: LSLInteger): int { - // NOTE: using the original method + val x: int = this.value; + val y: int = IntegerAutomaton(anotherInteger).value; + + if (x == y) + { + result = 0; + } + else + { + if (x < y) + result = -1; + else + result = +1; + } } diff --git a/spec/java/lang/SecurityManager.lsl b/spec/java/lang/SecurityManager.lsl index 794c8f81..dfd7bbd3 100644 --- a/spec/java/lang/SecurityManager.lsl +++ b/spec/java/lang/SecurityManager.lsl @@ -9,6 +9,7 @@ library std // imports import java/lang/Object; +import java/security/Permission; // primary semantic types @@ -17,6 +18,7 @@ import java/lang/Object; is java.lang.SecurityManager for Object { + fun *.checkPermission(perm: Permission): void; } diff --git a/spec/java/lang/SecurityManager.main.lsl b/spec/java/lang/SecurityManager.main.lsl index 21a3d70c..d9b85e16 100644 --- a/spec/java/lang/SecurityManager.main.lsl +++ b/spec/java/lang/SecurityManager.main.lsl @@ -98,9 +98,8 @@ automaton SecurityManagerAutomaton constructor *.LSLSecurityManager (@target self: LSLSecurityManager) { - val actionName: String = "createSecurityManager"; _do_checkPermission( - action DEBUG_DO("new RuntimePermission(actionName)") + action DEBUG_DO("new RuntimePermission(\"createSecurityManager\")") ); } diff --git a/spec/java/lang/System.StdOut.lsl b/spec/java/lang/System.StdOut.lsl index 32a0501b..5cf6e771 100644 --- a/spec/java/lang/System.StdOut.lsl +++ b/spec/java/lang/System.StdOut.lsl @@ -92,9 +92,6 @@ automaton System_PrintStreamAutomaton fun *.append (@target self: System_PrintStream, csq: CharSequence): PrintStream { - if (csq == null) - _throwNPE(); - _checkOpen(); result = self as Object as PrintStream; @@ -104,11 +101,11 @@ automaton System_PrintStreamAutomaton fun *.append (@target self: System_PrintStream, csq: CharSequence, start: int, end: int): PrintStream { if (csq == null) - _throwNPE(); + csq = "null"; val size: int = action CALL_METHOD(csq, "length", []); if (start < 0 || end >= size) - action THROW_NEW("java.lang.IndexOutOfBoundsException", []); + action THROW_NEW("java.lang.StringIndexOutOfBoundsException", []); _checkOpen(); @@ -132,19 +129,21 @@ automaton System_PrintStreamAutomaton fun *.close (@target self: System_PrintStream): void { + // #todo: add synchronization for parallel executions this.closed = true; } fun *.flush (@target self: System_PrintStream): void { + // #todo: add synchronization for parallel executions _checkOpen(); } @varargs fun *.format (@target self: System_PrintStream, l: Locale, format: String, args: array): PrintStream { - if (l == null || format == null || args == null) + if (format == null) _throwNPE(); _checkOpen(); @@ -155,7 +154,7 @@ automaton System_PrintStreamAutomaton @varargs fun *.format (@target self: System_PrintStream, format: String, args: array): PrintStream { - if (format == null || args == null) + if (format == null) _throwNPE(); _checkOpen(); diff --git a/spec/java/lang/System.main.lsl b/spec/java/lang/System.main.lsl index ad0f70f1..d88ba0dc 100644 --- a/spec/java/lang/System.main.lsl +++ b/spec/java/lang/System.main.lsl @@ -207,6 +207,16 @@ automaton SystemAutomaton } + @AutoInline @Phantom proc _checkIO (): void + { + val sm: SecurityManager = security; + if (sm != null) + action CALL_METHOD(sm, "checkPermission", [ + action DEBUG_DO("new RuntimePermission(\"setIO\")") + ]); + } + + // constructors @private constructor *.LSLSystem (@target self: LSLSystem) @@ -309,9 +319,9 @@ automaton SystemAutomaton } - @Phantom @static fun *.getSecurityManager (): SecurityManager + @static fun *.getSecurityManager (): SecurityManager { - // NOTE: using the original method + result = security; } @@ -426,30 +436,21 @@ automaton SystemAutomaton @static fun *.setErr (stream: PrintStream): void { - if (stream == null) - _throwNPE(); - - // #todo: add checks and exceptions + _checkIO(); err = stream; } @static fun *.setIn (stream: InputStream): void { - if (stream == null) - _throwNPE(); - - // #todo: add checks and exceptions + _checkIO(); in = stream; } @static fun *.setOut (stream: PrintStream): void { - if (stream == null) - _throwNPE(); - - // #todo: add checks and exceptions + _checkIO(); out = stream; } @@ -476,9 +477,17 @@ automaton SystemAutomaton } - @Phantom @static fun *.setSecurityManager (s: SecurityManager): void + @static fun *.setSecurityManager (s: SecurityManager): void { - // NOTE: using the original method + val sm: SecurityManager = security; + if (sm != null) + action CALL_METHOD(sm, "checkPermission", [ + action DEBUG_DO("new RuntimePermission(\"setSecurityManager\")") + ]); + + // #problem: no protection domain checks here + + security = s; } From 5992719251017d8fece965c6acb1ac5cdd3436d7 Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Sat, 25 Nov 2023 16:16:40 +0300 Subject: [PATCH 57/78] Micro-optimization for `java.lang.System`: reduced access to static variable `propsMap` --- spec/java/lang/System.main.lsl | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/spec/java/lang/System.main.lsl b/spec/java/lang/System.main.lsl index d88ba0dc..2d98cf1c 100644 --- a/spec/java/lang/System.main.lsl +++ b/spec/java/lang/System.main.lsl @@ -239,13 +239,14 @@ automaton SystemAutomaton // #todo: check permission - if (action MAP_HAS_KEY(propsMap, key)) + val pm: map = propsMap; + if (action MAP_HAS_KEY(pm, key)) { - result = action MAP_GET(propsMap, key); + result = action MAP_GET(pm, key); // #todo: remove key from 'props' - action MAP_REMOVE(propsMap, key); + action MAP_REMOVE(pm, key); } } @@ -300,8 +301,10 @@ automaton SystemAutomaton _checkKey(key); // #todo: throw SecurityException - if (action MAP_HAS_KEY(propsMap, key)) - result = action MAP_GET(propsMap, key); + + val pm: map = propsMap; + if (action MAP_HAS_KEY(pm, key)) + result = action MAP_GET(pm, key); else result = null; } @@ -312,8 +315,10 @@ automaton SystemAutomaton _checkKey(key); // #todo: throw SecurityException - if (action MAP_HAS_KEY(propsMap, key)) - result = action MAP_GET(propsMap, key); + + val pm: map = propsMap; + if (action MAP_HAS_KEY(pm, key)) + result = action MAP_GET(pm, key); else result = def; } @@ -468,12 +473,13 @@ automaton SystemAutomaton // #todo: update 'props' - if (action MAP_HAS_KEY(propsMap, key)) - result = action MAP_GET(propsMap, key); + val pm: map = propsMap; + if (action MAP_HAS_KEY(pm, key)) + result = action MAP_GET(pm, key); else result = null; - action MAP_SET(propsMap, key, value); + action MAP_SET(pm, key, value); } From 3285a0c78e7d9ee07d69fdb9b6c6f7a0853b61e0 Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Mon, 27 Nov 2023 11:54:00 +0300 Subject: [PATCH 58/78] Added alternative initialization for `java.lang.System` + Minor improvements --- spec/java/lang/SecurityManager.lsl | 5 ++ spec/java/lang/System.main.lsl | 89 ++++++++++++++++++++++++++---- spec/sun/misc/VM.lsl | 25 +++++++++ spec/sun/misc/Version.lsl | 25 +++++++++ 4 files changed, 134 insertions(+), 10 deletions(-) create mode 100644 spec/sun/misc/VM.lsl create mode 100644 spec/sun/misc/Version.lsl diff --git a/spec/java/lang/SecurityManager.lsl b/spec/java/lang/SecurityManager.lsl index dfd7bbd3..afd38168 100644 --- a/spec/java/lang/SecurityManager.lsl +++ b/spec/java/lang/SecurityManager.lsl @@ -9,6 +9,7 @@ library std // imports import java/lang/Object; +import java/lang/String; import java/security/Permission; @@ -19,6 +20,10 @@ import java/security/Permission; for Object { fun *.checkPermission(perm: Permission): void; + + fun *.checkPropertiesAccess(): void; + + fun *.checkPropertyAccess(key: String): void; } diff --git a/spec/java/lang/System.main.lsl b/spec/java/lang/System.main.lsl index 2d98cf1c..b97aa57c 100644 --- a/spec/java/lang/System.main.lsl +++ b/spec/java/lang/System.main.lsl @@ -17,7 +17,10 @@ import java/nio/channels/Channel; import java/util/Map; import java/util/Properties; import java/util/ResourceBundle; -import jdk/internal/misc/VM; + +import jdk/internal/misc/VM; // #problem: does not exist in Java-8 +import sun/misc/Version; +import sun/misc/VM; // #problem: does not exist in Java-11 import java/lang/System; @@ -237,7 +240,11 @@ automaton SystemAutomaton { _checkKey(key); - // #todo: check permission + val sm: SecurityManager = security; + if (sm != null) + action CALL_METHOD(sm, "checkPermission", [ + action DEBUG_DO("new java.util.PropertyPermission(key, \"write\")") + ]); val pm: map = propsMap; if (action MAP_HAS_KEY(pm, key)) @@ -291,7 +298,10 @@ automaton SystemAutomaton @static fun *.getProperties (): Properties { - // #todo: throw SecurityException + val sm: SecurityManager = security; + if (sm != null) + action CALL_METHOD(sm, "checkPropertiesAccess", []); + result = props; } @@ -300,7 +310,9 @@ automaton SystemAutomaton { _checkKey(key); - // #todo: throw SecurityException + val sm: SecurityManager = security; + if (sm != null) + action CALL_METHOD(sm, "checkPropertyAccess", [key]); val pm: map = propsMap; if (action MAP_HAS_KEY(pm, key)) @@ -314,7 +326,9 @@ automaton SystemAutomaton { _checkKey(key); - // #todo: throw SecurityException + val sm: SecurityManager = security; + if (sm != null) + action CALL_METHOD(sm, "checkPropertyAccess", [key]); val pm: map = propsMap; if (action MAP_HAS_KEY(pm, key)) @@ -334,12 +348,24 @@ automaton SystemAutomaton { // NOTE: using the original method + val sm: SecurityManager = security; + if (sm != null) + action CALL_METHOD(sm, "checkPermission", [ + action DEBUG_DO("new RuntimePermission(\"getenv.*\")") + ]); + // #todo: provide an actual map with symbolic values } @static fun *.getenv (name: String): String { + val sm: SecurityManager = security; + if (sm != null) + action CALL_METHOD(sm, "checkPermission", [ + action DEBUG_DO("new RuntimePermission(\"getenv.\".concat(name))") + ]); + result = action SYMBOLIC("java.lang.String"); action ASSUME(result != null); @@ -462,6 +488,10 @@ automaton SystemAutomaton @static fun *.setProperties (p: Properties): void { + val sm: SecurityManager = security; + if (sm != null) + action CALL_METHOD(sm, "checkPropertiesAccess", []); + // #todo: improve after there will be some implementation for Properties props = p; } @@ -471,6 +501,12 @@ automaton SystemAutomaton { _checkKey(key); + val sm: SecurityManager = security; + if (sm != null) + action CALL_METHOD(sm, "checkPermission", [ + action DEBUG_DO("new java.util.PropertyPermission(key, \"write\")") + ]); + // #todo: update 'props' val pm: map = propsMap; @@ -501,7 +537,7 @@ automaton SystemAutomaton // special: internal class initialization by the JRE - @private @static proc initPhase1 (): void // WARNING: do not rename! + @private @static proc initPhase1 (): void // WARNING: do not change signature! { _initProperties(); @@ -531,8 +567,7 @@ automaton SystemAutomaton //val threadGroup: ThreadGroup = action CALL_METHOD(current, "getThreadGroup", []); //action CALL_METHOD(threadGroup, "add", [current]); - // #todo - //setJavaLangAccess(); + // #problem: unable to call or model 'java.lang.System#setJavaLangAccess' // #problem: too complex, package-private //action CALL_METHOD(null as ClassLoader, "initLibraryPaths", []); @@ -542,7 +577,7 @@ automaton SystemAutomaton } - @private @static proc initPhase2 (): int // WARNING: do not change! + @private @static proc initPhase2 (): int // WARNING: do not change signature! { // #problem: java.lang.System#bootLayer initialization @@ -554,7 +589,7 @@ automaton SystemAutomaton } - @private @static proc initPhase3 (): void // WARNING: do not rename! + @private @static proc initPhase3 (): void // WARNING: do not change signature! { // #problem: reflective access during security manager initialization // #todo: check property 'java.security.manager' @@ -570,13 +605,47 @@ automaton SystemAutomaton } + // NOTE: not using this + @Phantom @private @static proc init_as_java8 (): void + { + // #todo: use dedicated Properties automaton + props = action DEBUG_DO("new Properties()"); + + _initProperties(); + + action CALL_METHOD(null as SUN_Version, "init", []); + + // configure the standard streams + val newInput: InputStream = new SymbolicInputStreamAutomaton(state = Initialized, + maxSize = 1000, + supportMarks = false, + ); + // #todo: unsafe operations in BufferedInputStream + in = newInput;//action DEBUG_DO("new java.io.BufferedInputStream(newInput)"); + out = new System_PrintStreamAutomaton(state = Initialized); + err = new System_PrintStreamAutomaton(state = Initialized); + + // #problem: thread group initialization + + // #problem: unable to call or model 'java.lang.System#setJavaLangAccess' + + action CALL_METHOD(null as SUN_VM, "booted", []); + } + + // special: static initialization @Phantom @static fun *.__clinit__ (): void { + // #problem: version-specific initialization + initPhase1(); initPhase2(); initPhase3(); + + /* + init_as_java8(); + */ } } diff --git a/spec/sun/misc/VM.lsl b/spec/sun/misc/VM.lsl new file mode 100644 index 00000000..1dc96ad8 --- /dev/null +++ b/spec/sun/misc/VM.lsl @@ -0,0 +1,25 @@ +//#! pragma: non-synthesizable +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "https://github.com/openjdk/jdk8/blob/master/jdk/src/share/classes/sun/misc/VM.java"; + +// imports + +import java/lang/Object; + + +// primary semantic types + +@interface type SUN_VM + is sun.misc.VM + for Object +{ + @static fun *.booted(): void; +} + + +// global aliases and type overrides + diff --git a/spec/sun/misc/Version.lsl b/spec/sun/misc/Version.lsl new file mode 100644 index 00000000..11ccf5bd --- /dev/null +++ b/spec/sun/misc/Version.lsl @@ -0,0 +1,25 @@ +//#! pragma: non-synthesizable +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "https://github.com/openjdk/jdk8/blob/master/jdk/src/share/classes/sun/misc/Version.java.template"; + +// imports + +import java/lang/Object; + + +// primary semantic types + +@interface type SUN_Version + is sun.misc.Version + for Object +{ + @static fun *.init(): void; +} + + +// global aliases and type overrides + From 55f4ce377a9e6aec5106a8ab9b7d52f72b431814 Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Tue, 28 Nov 2023 15:17:30 +0300 Subject: [PATCH 59/78] Removed `length` automaton variable for `java.util.ArrayList` --- spec/java/util/ArrayList.ListIterator.lsl | 20 +-- spec/java/util/ArrayList.Spliterator.lsl | 6 +- .../util/ArrayList.SubList.ListIterator.lsl | 15 +-- spec/java/util/ArrayList.SubList.lsl | 9 +- spec/java/util/ArrayList.main.lsl | 127 +++++++----------- spec/java/util/List.main.lsl | 13 -- 6 files changed, 66 insertions(+), 124 deletions(-) diff --git a/spec/java/util/ArrayList.ListIterator.lsl b/spec/java/util/ArrayList.ListIterator.lsl index 7210f1fb..b17199c7 100644 --- a/spec/java/util/ArrayList.ListIterator.lsl +++ b/spec/java/util/ArrayList.ListIterator.lsl @@ -84,7 +84,7 @@ automaton ArrayList_ListIteratorAutomaton // relax state/error discovery process action ASSUME(this.parent != null); - result = this.cursor != ArrayListAutomaton(this.parent).length; + result = this.cursor != action LIST_SIZE(ArrayListAutomaton(this.parent).storage); } @@ -98,12 +98,8 @@ automaton ArrayList_ListIteratorAutomaton val parentStorage: list = ArrayListAutomaton(this.parent).storage; val i: int = this.cursor; - if (i >= ArrayListAutomaton(this.parent).length) - action THROW_NEW("java.util.NoSuchElementException", []); - - // iterrator validity check if (i >= action LIST_SIZE(parentStorage)) - _throwCME(); + action THROW_NEW("java.util.NoSuchElementException", []); this.cursor = i + 1; this.lastRet = i; @@ -156,8 +152,6 @@ automaton ArrayList_ListIteratorAutomaton ArrayListAutomaton(this.parent).modCount += 1; action LIST_REMOVE(pStorage, this.lastRet); - - ArrayListAutomaton(this.parent).length -= 1; } this.cursor = this.lastRet; @@ -203,8 +197,6 @@ automaton ArrayList_ListIteratorAutomaton ArrayListAutomaton(this.parent).modCount += 1; action LIST_INSERT_AT(pStorage, i, e); - - ArrayListAutomaton(this.parent).length += 1; } this.cursor = i + 1; @@ -222,15 +214,11 @@ automaton ArrayList_ListIteratorAutomaton action THROW_NEW("java.lang.NullPointerException", []); var i: int = this.cursor; - val size: int = ArrayListAutomaton(this.parent).length; + val es: list = ArrayListAutomaton(this.parent).storage; + val size: int = action LIST_SIZE(es); if (i < size) { - val es: list = ArrayListAutomaton(this.parent).storage; - - if (i >= action LIST_SIZE(es)) - _throwCME(); - // using this exact loop form here due to coplex termination expression action LOOP_WHILE( i < size && ArrayListAutomaton(this.parent).modCount == this.expectedModCount, diff --git a/spec/java/util/ArrayList.Spliterator.lsl b/spec/java/util/ArrayList.Spliterator.lsl index 101905ee..046876e0 100644 --- a/spec/java/util/ArrayList.Spliterator.lsl +++ b/spec/java/util/ArrayList.Spliterator.lsl @@ -68,7 +68,7 @@ automaton ArrayList_SpliteratorAutomaton { action ASSUME(this.parent != null); this.expectedModCount = ArrayListAutomaton(this.parent).modCount; - this.fence = ArrayListAutomaton(this.parent).length; + this.fence = action LIST_SIZE(ArrayListAutomaton(this.parent).storage); } result = this.fence; @@ -117,13 +117,13 @@ automaton ArrayList_SpliteratorAutomaton var mc: int = this.expectedModCount; if (hi == -1) { - hi = ArrayListAutomaton(this.parent).length; + hi = action LIST_SIZE(a); mc = ArrayListAutomaton(this.parent).modCount; } var i: int = this.index; this.index = hi; - if (i < 0 || hi > ArrayListAutomaton(this.parent).length) + if (i < 0 || hi > action LIST_SIZE(a)) _throwCME(); action LOOP_FOR( diff --git a/spec/java/util/ArrayList.SubList.ListIterator.lsl b/spec/java/util/ArrayList.SubList.ListIterator.lsl index 03797543..6dc5c6a2 100644 --- a/spec/java/util/ArrayList.SubList.ListIterator.lsl +++ b/spec/java/util/ArrayList.SubList.ListIterator.lsl @@ -95,14 +95,11 @@ automaton ArrayList_SubList_ListIteratorAutomaton _checkForComodification(); + val rootStorage: list = ArrayListAutomaton(this.root).storage; val i: int = this.offset + this.cursor; - if (i >= ArrayListAutomaton(this.root).length) - action THROW_NEW("java.util.NoSuchElementException", []); - // iterrator validity check - val rootStorage: list = ArrayListAutomaton(this.root).storage; if (i >= action LIST_SIZE(rootStorage)) - _throwCME(); + action THROW_NEW("java.util.NoSuchElementException", []); this.lastRet = this.cursor; this.cursor += 1; @@ -172,11 +169,13 @@ automaton ArrayList_SubList_ListIteratorAutomaton _checkForComodification(); + val rootStorage: list = ArrayListAutomaton(this.root).storage; + val index: int = this.offset + this.lastRet; - if (index >= ArrayListAutomaton(this.root).length) + if (index >= action LIST_SIZE(rootStorage)) _throwCME(); else - action LIST_SET(ArrayListAutomaton(this.root).storage, index, e); + action LIST_SET(rootStorage, index, e); } @@ -189,7 +188,7 @@ automaton ArrayList_SubList_ListIteratorAutomaton val i: int = this.offset + this.cursor; - if (this.offset + this.lastRet > ArrayListAutomaton(this.root).length) + if (this.offset + this.lastRet > action LIST_SIZE(ArrayListAutomaton(this.root).storage)) { _throwCME(); } diff --git a/spec/java/util/ArrayList.SubList.lsl b/spec/java/util/ArrayList.SubList.lsl index db3bc538..d257c494 100644 --- a/spec/java/util/ArrayList.SubList.lsl +++ b/spec/java/util/ArrayList.SubList.lsl @@ -166,12 +166,12 @@ automaton ArrayList_SubListAutomaton if (this.length != 0) { - val oldRootLength: int = ArrayListAutomaton(this.root).length; + val oldRootLength: int = action LIST_SIZE(ArrayListAutomaton(this.root).storage); result = ArrayListAutomaton(this.root)._batchRemove(c, complement, this.offset, this.offset + this.length); if (result) { - val newRootLength: int = ArrayListAutomaton(this.root).length; + val newRootLength: int = action LIST_SIZE(ArrayListAutomaton(this.root).storage); _updateSizeAndModCount(newRootLength - oldRootLength); } } @@ -262,7 +262,6 @@ automaton ArrayList_SubListAutomaton clear_loop(i, rootStorage) ); - ArrayListAutomaton(this.root).length -= size; ArrayListAutomaton(this.root).modCount += 1; _updateSizeAndModCount(-size); @@ -580,12 +579,12 @@ automaton ArrayList_SubListAutomaton val size: int = this.length; if (size != 0) { - val oldRootLength: int = ArrayListAutomaton(this.root).length; + val oldRootLength: int = action LIST_SIZE(ArrayListAutomaton(this.root).storage); result = ArrayListAutomaton(this.root)._removeIf(filter, this.offset, this.offset + this.length); if (result) { - val newRootLength: int = ArrayListAutomaton(this.root).length; + val newRootLength: int = action LIST_SIZE(ArrayListAutomaton(this.root).storage); _updateSizeAndModCount(newRootLength - oldRootLength); } } diff --git a/spec/java/util/ArrayList.main.lsl b/spec/java/util/ArrayList.main.lsl index 5f773904..4b5e4570 100644 --- a/spec/java/util/ArrayList.main.lsl +++ b/spec/java/util/ArrayList.main.lsl @@ -14,8 +14,7 @@ import java/util/ArrayList; automaton ArrayListAutomaton ( - var storage: list, - @transient var length: int + var storage: list ) : ArrayList { @@ -86,7 +85,7 @@ automaton ArrayListAutomaton if (index < 0 || length <= index) { //val idx: String = action OBJECT_TO_STRING(index); - //val len: String = action OBJECT_TO_STRING(this.length); + //val len: String = action OBJECT_TO_STRING(action LIST_SIZE(this.storage)); //val message: String = "Index "+ idx + " out of bounds for length "+ len; action THROW_NEW("java.lang.IndexOutOfBoundsException", []); } @@ -95,10 +94,10 @@ automaton ArrayListAutomaton @KeepVisible proc _rangeCheckForAdd (index: int): void { - if (index > this.length || index < 0) + if (index > action LIST_SIZE(this.storage) || index < 0) { //val idx: String = action OBJECT_TO_STRING(index); - //val len: String = action OBJECT_TO_STRING(this.length); + //val len: String = action OBJECT_TO_STRING(action LIST_SIZE(this.storage)); //val message: String = "Index: " + idx + ", Size: " + len; action THROW_NEW("java.lang.IndexOutOfBoundsException", []); } @@ -107,12 +106,12 @@ automaton ArrayListAutomaton @KeepVisible proc _addAllElements (index: int, c: Collection): boolean { - val oldLength: int = this.length; + val oldLength: int = action LIST_SIZE(this.storage); if (c has ArrayListAutomaton) { val otherStorage: list = ArrayListAutomaton(c).storage; - val otherLength: int = ArrayListAutomaton(c).length; + val otherLength: int = action LIST_SIZE(otherStorage); action ASSUME(otherStorage != null); action ASSUME(otherLength >= 0); @@ -132,7 +131,7 @@ automaton ArrayListAutomaton ); } - result = oldLength != this.length; + result = oldLength != action LIST_SIZE(this.storage); if (result) this.modCount += 1; } @@ -143,7 +142,6 @@ automaton ArrayListAutomaton action LIST_INSERT_AT(this.storage, index, item); index += 1; - this.length += 1; } @Phantom proc _addAllElements_loop_regular (iter: Iterator, index: int): void @@ -152,7 +150,6 @@ automaton ArrayListAutomaton action LIST_INSERT_AT(this.storage, index, item); index += 1; - this.length += 1; } @@ -190,12 +187,11 @@ automaton ArrayListAutomaton @KeepVisible proc _deleteElement (index: int): Object { - _checkValidIndex(index, this.length); + _checkValidIndex(index, action LIST_SIZE(this.storage)); result = action LIST_GET(this.storage, index); action LIST_REMOVE(this.storage, index); - this.length -= 1; this.modCount += 1; } @@ -206,14 +202,13 @@ automaton ArrayListAutomaton action LIST_INSERT_AT(this.storage, index, element); - this.length += 1; this.modCount += 1; } proc _setElement (index: int, element: Object): Object { - _checkValidIndex(index, this.length); + _checkValidIndex(index, action LIST_SIZE(this.storage)); result = action LIST_GET(this.storage, index); action LIST_SET(this.storage, index, element); @@ -253,7 +248,7 @@ automaton ArrayListAutomaton if (filter == null) _throwNPE(); - val oldLength: int = this.length; + val oldLength: int = action LIST_SIZE(this.storage); val expectedModCount: int = this.modCount; // remove elements from the back first @@ -266,17 +261,14 @@ automaton ArrayListAutomaton _checkForComodification(expectedModCount); - result = oldLength != this.length; + result = oldLength != action LIST_SIZE(this.storage); } @Phantom proc _removeIf_loop (i: int, filter: Predicate): void { val item: Object = action LIST_GET(this.storage, i); if (action CALL(filter, [item])) - { action LIST_REMOVE(this.storage, i); - this.length -= 1; - } } @@ -285,47 +277,32 @@ automaton ArrayListAutomaton result = true; var i: int = from; - var otherLength: int = 0; var otherStorage: list = null; if (other has ArrayListAutomaton) { - otherLength = ArrayListAutomaton(other).length; - action ASSUME(otherLength >= 0); + otherStorage = ArrayListAutomaton(other).storage; // assumptions: no multithreading, from == 0 - result = to == otherLength; + result = to == action LIST_SIZE(otherStorage); if (result) - { - otherStorage = ArrayListAutomaton(other).storage; - action ASSUME(otherStorage != null); - action LOOP_WHILE( result && i < to, _equalsRange_loop_optimized(i, otherStorage, result) ); - } } else if (other has ArrayList_SubListAutomaton) { - otherLength = ArrayList_SubListAutomaton(other).length; - action ASSUME(otherLength >= 0); + val otherRoot: ArrayList = ArrayList_SubListAutomaton(other).root; + otherStorage = ArrayListAutomaton(otherRoot).storage; // assumptions: no multithreading, from >= 0 - result = to == otherLength; + result = to == ArrayList_SubListAutomaton(other).length; if (result) - { - val otherRoot: ArrayList = ArrayList_SubListAutomaton(other).root; - action ASSUME(otherRoot != null); - - otherStorage = ArrayListAutomaton(otherRoot).storage; - action ASSUME(otherStorage != null); - action LOOP_WHILE( result && i < to, _equalsRange_loop_optimized(i, otherStorage, result) ); - } } else { @@ -371,7 +348,7 @@ automaton ArrayListAutomaton @KeepVisible proc _batchRemove (c: Collection, complement: boolean, start: int, end: int): boolean { - val oldLength: int = this.length; + val oldLength: int = action LIST_SIZE(this.storage); if (oldLength == 0 || start >= end) { result = false; @@ -409,7 +386,7 @@ automaton ArrayListAutomaton ); } - result = oldLength != this.length; + result = oldLength != action LIST_SIZE(this.storage); } } } @@ -417,7 +394,7 @@ automaton ArrayListAutomaton @Phantom proc _batchRemove_loop_optimized (i: int, otherStorage: list, complement: boolean): void { val item: Object = action LIST_GET(this.storage, i); - if ((action LIST_FIND(otherStorage, item, 0, this.length) == -1) == complement) + if ((action LIST_FIND(otherStorage, item, 0, action LIST_SIZE(this.storage)) == -1) == complement) _deleteElement(i); } @@ -526,7 +503,6 @@ automaton ArrayListAutomaton constructor *.ArrayList (@target self: ArrayList) { this.storage = action LIST_NEW(); - this.length = 0; } @@ -536,7 +512,6 @@ automaton ArrayListAutomaton _throwNPE(); this.storage = action LIST_NEW(); - this.length = 0; _addAllElements(0, c); } @@ -550,7 +525,6 @@ automaton ArrayListAutomaton action THROW_NEW("java.lang.IllegalArgumentException", []); } this.storage = action LIST_NEW(); - this.length = 0; } @@ -558,9 +532,8 @@ automaton ArrayListAutomaton fun *.add (@target self: ArrayList, e: Object): boolean { - action LIST_INSERT_AT(this.storage, this.length, e); + action LIST_INSERT_AT(this.storage, action LIST_SIZE(this.storage), e); - this.length += 1; this.modCount += 1; result = true; @@ -575,7 +548,7 @@ automaton ArrayListAutomaton fun *.addAll (@target self: ArrayList, c: Collection): boolean { - result = _addAllElements(this.length, c); + result = _addAllElements(action LIST_SIZE(this.storage), c); } @@ -589,7 +562,6 @@ automaton ArrayListAutomaton fun *.clear (@target self: ArrayList): void { this.storage = action LIST_NEW(); - this.length = 0; this.modCount += 1; } @@ -597,18 +569,17 @@ automaton ArrayListAutomaton fun *.clone (@target self: ArrayList): Object { val storageCopy: list = action LIST_NEW(); - action LIST_COPY(this.storage, storageCopy, 0, 0, this.length); + action LIST_COPY(this.storage, storageCopy, 0, 0, action LIST_SIZE(this.storage)); result = new ArrayListAutomaton(state = Initialized, storage = storageCopy, - length = this.length ); } fun *.contains (@target self: ArrayList, o: Object): boolean { - result = action LIST_FIND(this.storage, o, 0, this.length) != -1; + result = action LIST_FIND(this.storage, o, 0, action LIST_SIZE(this.storage)) != -1; } @@ -620,9 +591,9 @@ automaton ArrayListAutomaton if (c has ArrayListAutomaton) { val otherStorage: list = ArrayListAutomaton(c).storage; - val otherLength: int = ArrayListAutomaton(c).length; - action ASSUME(otherStorage != null); + + val otherLength: int = action LIST_SIZE(otherStorage); action ASSUME(otherLength >= 0); var i: int = 0; @@ -644,7 +615,7 @@ automaton ArrayListAutomaton @Phantom proc containsAll_loop_optimized (otherStorage: list, i: int, result: boolean): void { val item: Object = action LIST_GET(otherStorage, i); - result = action LIST_FIND(this.storage, item, 0, this.length) != -1; + result = action LIST_FIND(this.storage, item, 0, action LIST_SIZE(this.storage)) != -1; i += 1; } @@ -652,7 +623,7 @@ automaton ArrayListAutomaton @Phantom proc containsAll_loop_regular (iter: Iterator, result: boolean): void { val item: Object = action CALL_METHOD(iter, "next", []); - result = action LIST_FIND(this.storage, item, 0, this.length) != -1; + result = action LIST_FIND(this.storage, item, 0, action LIST_SIZE(this.storage)) != -1; } @@ -675,11 +646,9 @@ automaton ArrayListAutomaton { val expectedModCount: int = this.modCount; val otherExpectedModCount: int = ArrayListAutomaton(other).modCount; - val otherStorage: list = ArrayListAutomaton(other).storage; - val otherLength: int = ArrayListAutomaton(other).length; - if (this.length == otherLength) + if (action LIST_SIZE(this.storage) == action LIST_SIZE(otherStorage)) result = action OBJECT_EQUALS(this.storage, otherStorage); else result = false; @@ -704,7 +673,7 @@ automaton ArrayListAutomaton var i: int = 0; action LOOP_WHILE( - this.modCount == expectedModCount && i < this.length, + this.modCount == expectedModCount && i < action LIST_SIZE(this.storage), forEach_loop(i, _action) ); @@ -722,7 +691,7 @@ automaton ArrayListAutomaton fun *.get (@target self: ArrayList, index: int): Object { - _checkValidIndex(index, this.length); + _checkValidIndex(index, action LIST_SIZE(this.storage)); result = action LIST_GET(this.storage, index); } @@ -736,13 +705,13 @@ automaton ArrayListAutomaton fun *.indexOf (@target self: ArrayList, o: Object): int { - result = action LIST_FIND(this.storage, o, 0, this.length); + result = action LIST_FIND(this.storage, o, 0, action LIST_SIZE(this.storage)); } fun *.isEmpty (@target self: ArrayList): boolean { - result = this.length == 0; + result = action LIST_SIZE(this.storage) == 0; } @@ -758,22 +727,22 @@ automaton ArrayListAutomaton fun *.lastIndexOf (@target self: ArrayList, o: Object): int { - if (this.length == 0) + if (action LIST_SIZE(this.storage) == 0) { result = -1; } else { - action ASSUME(this.length > 0); + action ASSUME(action LIST_SIZE(this.storage) > 0); - result = action LIST_FIND(this.storage, o, 0, this.length); + result = action LIST_FIND(this.storage, o, 0, action LIST_SIZE(this.storage)); if (result != -1) { // there should be no elements to the right of the previously found position val nextIndex: int = result + 1; - if (nextIndex < this.length) + if (nextIndex < action LIST_SIZE(this.storage)) { - val rightIndex: int = action LIST_FIND(this.storage, o, nextIndex, this.length); + val rightIndex: int = action LIST_FIND(this.storage, o, nextIndex, action LIST_SIZE(this.storage)); action ASSUME(rightIndex == -1); } } @@ -812,7 +781,7 @@ automaton ArrayListAutomaton fun *.remove (@target self: ArrayList, o: Object): boolean { - val index: int = action LIST_FIND(this.storage, o, 0, this.length); + val index: int = action LIST_FIND(this.storage, o, 0, action LIST_SIZE(this.storage)); result = index != -1; if (result) _deleteElement(index); @@ -827,13 +796,13 @@ automaton ArrayListAutomaton fun *.removeAll (@target self: ArrayList, c: Collection): boolean { - result = _batchRemove(c, /* complement = */false, 0, this.length); + result = _batchRemove(c, /* complement = */false, 0, action LIST_SIZE(this.storage)); } fun *.removeIf (@target self: ArrayList, filter: Predicate): boolean { - result = _removeIf(filter, 0, this.length); + result = _removeIf(filter, 0, action LIST_SIZE(this.storage)); } @@ -842,14 +811,14 @@ automaton ArrayListAutomaton if (op == null) _throwNPE(); - _replaceAllRange(op, 0, this.length); + _replaceAllRange(op, 0, action LIST_SIZE(this.storage)); this.modCount += 1; } fun *.retainAll (@target self: ArrayList, c: Collection): boolean { - result = _batchRemove(c, /* complement = */true, 0, this.length); + result = _batchRemove(c, /* complement = */true, 0, action LIST_SIZE(this.storage)); } @@ -861,13 +830,13 @@ automaton ArrayListAutomaton fun *.size (@target self: ArrayList): int { - result = this.length; + result = action LIST_SIZE(this.storage); } fun *.sort (@target self: ArrayList, c: Comparator): void { - _do_sort(0, this.length, c); + _do_sort(0, action LIST_SIZE(this.storage), c); } @@ -888,7 +857,7 @@ automaton ArrayListAutomaton fun *.subList (@target self: ArrayList, fromIndex: int, toIndex: int): List { - _subListRangeCheck(fromIndex, toIndex, this.length); + _subListRangeCheck(fromIndex, toIndex, action LIST_SIZE(this.storage)); result = new ArrayList_SubListAutomaton(state = Initialized, root = self, @@ -902,7 +871,7 @@ automaton ArrayListAutomaton fun *.toArray (@target self: ArrayList): array { - val len: int = this.length; + val len: int = action LIST_SIZE(this.storage); result = action ARRAY_NEW("java.lang.Object", len); var i: int = 0; @@ -926,7 +895,7 @@ automaton ArrayListAutomaton val a: array = action CALL_METHOD(generator, "apply", [0]) as array; val aLen: int = action ARRAY_SIZE(a); - val len: int = this.length; + val len: int = action LIST_SIZE(this.storage); // #problem: a.getClass() should be called to construct a type-valid array (USVM issue) result = action ARRAY_NEW("java.lang.Object", len); @@ -941,7 +910,7 @@ automaton ArrayListAutomaton fun *.toArray (@target self: ArrayList, a: array): array { val aLen: int = action ARRAY_SIZE(a); - val len: int = this.length; + val len: int = action LIST_SIZE(this.storage); if (aLen < len) // #problem: a.getClass() should be called to construct a type-valid array (USVM issue) diff --git a/spec/java/util/List.main.lsl b/spec/java/util/List.main.lsl index 96944667..19f74a6d 100644 --- a/spec/java/util/List.main.lsl +++ b/spec/java/util/List.main.lsl @@ -71,7 +71,6 @@ automaton ListAutomaton result = new ArrayListAutomaton(state = Initialized, storage = data, - length = size, ); } @@ -87,7 +86,6 @@ automaton ListAutomaton { result = new ArrayListAutomaton(state = Initialized, storage = action LIST_NEW(), - length = 0, ); } @@ -100,7 +98,6 @@ automaton ListAutomaton result = new ArrayListAutomaton(state = Initialized, storage = data, - length = 1, ); } @@ -114,7 +111,6 @@ automaton ListAutomaton result = new ArrayListAutomaton(state = Initialized, storage = data, - length = 2, ); } @@ -129,7 +125,6 @@ automaton ListAutomaton result = new ArrayListAutomaton(state = Initialized, storage = data, - length = 3, ); } @@ -145,7 +140,6 @@ automaton ListAutomaton result = new ArrayListAutomaton(state = Initialized, storage = data, - length = 4, ); } @@ -162,7 +156,6 @@ automaton ListAutomaton result = new ArrayListAutomaton(state = Initialized, storage = data, - length = 5, ); } @@ -180,7 +173,6 @@ automaton ListAutomaton result = new ArrayListAutomaton(state = Initialized, storage = data, - length = 6, ); } @@ -199,7 +191,6 @@ automaton ListAutomaton result = new ArrayListAutomaton(state = Initialized, storage = data, - length = 7, ); } @@ -219,7 +210,6 @@ automaton ListAutomaton result = new ArrayListAutomaton(state = Initialized, storage = data, - length = 8, ); } @@ -240,7 +230,6 @@ automaton ListAutomaton result = new ArrayListAutomaton(state = Initialized, storage = data, - length = 9, ); } @@ -262,7 +251,6 @@ automaton ListAutomaton result = new ArrayListAutomaton(state = Initialized, storage = data, - length = 10, ); } @@ -284,7 +272,6 @@ automaton ListAutomaton result = new ArrayListAutomaton(state = Initialized, storage = data, - length = size, ); } From 793d55c17a13455faff3665849c19ab7d9a88eac Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Wed, 29 Nov 2023 08:48:41 +0300 Subject: [PATCH 60/78] Removed `length` automaton variable from `HashSetAutomaton` + Minor improvements --- spec/java/util/HashSet.KeyIterator.lsl | 14 ++-- spec/java/util/HashSet.Spliterator.lsl | 14 ++-- spec/java/util/HashSet.main.lsl | 91 +++++++++----------------- 3 files changed, 47 insertions(+), 72 deletions(-) diff --git a/spec/java/util/HashSet.KeyIterator.lsl b/spec/java/util/HashSet.KeyIterator.lsl index 6773f7b8..7a5e7669 100644 --- a/spec/java/util/HashSet.KeyIterator.lsl +++ b/spec/java/util/HashSet.KeyIterator.lsl @@ -74,7 +74,9 @@ automaton HashSet_KeyIteratorAutomaton fun *.hasNext (@target self: HashSet_KeyIterator): boolean { action ASSUME(this.parent != null); - val length: int = HashSetAutomaton(this.parent).length; + + val parentStorage: map = HashSetAutomaton(this.parent).storage; + val length: int = action MAP_SIZE(parentStorage); result = this.index < length; } @@ -84,7 +86,8 @@ automaton HashSet_KeyIteratorAutomaton action ASSUME(this.parent != null); _checkForComodification(); - val length: int = HashSetAutomaton(this.parent).length; + val parentStorage: map = HashSetAutomaton(this.parent).storage; + val length: int = action MAP_SIZE(parentStorage); val atValidPosition: boolean = this.index < length; if (!atValidPosition) action THROW_NEW("java.util.NoSuchElementException", []); @@ -105,7 +108,8 @@ automaton HashSet_KeyIteratorAutomaton { action ASSUME(this.parent != null); - val length: int = HashSetAutomaton(this.parent).length; + val parentStorage: map = HashSetAutomaton(this.parent).storage; + val length: int = action MAP_SIZE(parentStorage); val atValidPosition: boolean = this.index < length; if (!atValidPosition || !this.nextWasCalled) action THROW_NEW("java.lang.IllegalStateException", []); @@ -114,7 +118,6 @@ automaton HashSet_KeyIteratorAutomaton _checkForComodification(); - val parentStorage: map = HashSetAutomaton(this.parent).storage; action MAP_REMOVE(parentStorage, this.currentKey); this.expectedModCount = HashSetAutomaton(this.parent).modCount; @@ -128,7 +131,8 @@ automaton HashSet_KeyIteratorAutomaton if (userAction == null) action THROW_NEW("java.lang.NullPointerException", []); - val length: int = HashSetAutomaton(this.parent).length; + val parentStorage: map = HashSetAutomaton(this.parent).storage; + val length: int = action MAP_SIZE(parentStorage); var i: int = this.index; action LOOP_WHILE( diff --git a/spec/java/util/HashSet.Spliterator.lsl b/spec/java/util/HashSet.Spliterator.lsl index 597191d1..3cee357b 100644 --- a/spec/java/util/HashSet.Spliterator.lsl +++ b/spec/java/util/HashSet.Spliterator.lsl @@ -59,7 +59,7 @@ automaton HashSet_KeySpliteratorAutomaton if (hi < 0) { val parentStorage: map = HashSetAutomaton(this.parent).storage; - this.est = HashSetAutomaton(this.parent).length; + this.est = action MAP_SIZE(parentStorage); this.expectedModCount = HashSetAutomaton(this.parent).modCount; this.fence = this.est; // That's right ? @@ -108,12 +108,13 @@ automaton HashSet_KeySpliteratorAutomaton { action ASSUME(this.parent != null); - var mask: int = 0; - val length: int = HashSetAutomaton(this.parent).length; + result = 0; + val parentStorage: map = HashSetAutomaton(this.parent).storage; + val length: int = action MAP_SIZE(parentStorage); if (this.fence < 0 || this.est == length) - mask = SPLITERATOR_SIZED; + result = SPLITERATOR_SIZED; - result = mask | SPLITERATOR_DISTINCT; + result |= SPLITERATOR_DISTINCT; } @@ -127,7 +128,8 @@ automaton HashSet_KeySpliteratorAutomaton var hi: int = this.fence; var mc: int = this.expectedModCount; var i: int = this.index; - val length: int = HashSetAutomaton(this.parent).length; + val parentStorage: map = HashSetAutomaton(this.parent).storage; + val length: int = action MAP_SIZE(parentStorage); if(hi < 0) { diff --git a/spec/java/util/HashSet.main.lsl b/spec/java/util/HashSet.main.lsl index 09912dc4..c6307775 100644 --- a/spec/java/util/HashSet.main.lsl +++ b/spec/java/util/HashSet.main.lsl @@ -22,8 +22,7 @@ import java/util/Spliterator; automaton HashSetAutomaton ( - var storage: map = null, - @transient var length: int = 0 + var storage: map ) : HashSet { @@ -87,7 +86,7 @@ automaton HashSetAutomaton proc _addAllElements (c: Collection): boolean { - val lengthBeforeAdd: int = this.length; + val lengthBeforeAdd: int = action MAP_SIZE(this.storage); val iter: Iterator = action CALL_METHOD(c, "iterator", []); action LOOP_WHILE( @@ -95,7 +94,7 @@ automaton HashSetAutomaton _addAllElements_loop(iter) ); - if (lengthBeforeAdd != this.length) + if (lengthBeforeAdd != action MAP_SIZE(this.storage)) { this.modCount += 1; result = true; @@ -110,13 +109,9 @@ automaton HashSetAutomaton @Phantom proc _addAllElements_loop(iter: Iterator): void { val key: Object = action CALL_METHOD(iter, "next", []); - val hasKey: boolean = action MAP_HAS_KEY(this.storage, key); - if (!hasKey) - { + if (action MAP_HAS_KEY(this.storage, key) == false) action MAP_SET(this.storage, key, SOMETHING); - this.length += 1; - } } @@ -189,10 +184,7 @@ automaton HashSetAutomaton } else { - this.length += 1; - action MAP_SET(this.storage, obj, SOMETHING); - result = true; } @@ -202,9 +194,7 @@ automaton HashSetAutomaton fun *.clear (@target self: HashSet): void { - this.length = 0; this.storage = action MAP_NEW(); - this.modCount += 1; } @@ -215,14 +205,13 @@ automaton HashSetAutomaton result = new HashSetAutomaton(state = Initialized, storage = storageCopy, - length = this.length ); } fun *.contains (@target self: HashSet, obj: Object): boolean { - if (this.length == 0) + if (action MAP_SIZE(this.storage) == 0) result = false; else result = action MAP_HAS_KEY(this.storage, obj); @@ -231,7 +220,7 @@ automaton HashSetAutomaton fun *.isEmpty (@target self: HashSet): boolean { - result = this.length == 0; + result = action MAP_SIZE(this.storage) == 0; } @@ -248,11 +237,9 @@ automaton HashSetAutomaton fun *.remove (@target self: HashSet, obj: Object): boolean { - val hasKey: boolean = action MAP_HAS_KEY(this.storage, obj); - if (hasKey) + if (action MAP_HAS_KEY(this.storage, obj)) { action MAP_REMOVE(this.storage, obj); - this.length -= 1; this.modCount += 1; result = true; } @@ -265,18 +252,18 @@ automaton HashSetAutomaton fun *.size (@target self: HashSet): int { - result = this.length; + result = action MAP_SIZE(this.storage); } fun *.spliterator (@target self: HashSet): Spliterator { - val keysStorageArray: array = action ARRAY_NEW("java.lang.Object", this.length); + val keysStorageArray: array = action ARRAY_NEW("java.lang.Object", action MAP_SIZE(this.storage)); val unseenKeys: map = action MAP_CLONE(this.storage); var i: int = 0; action LOOP_FOR( - i, 0, this.length, +1, + i, 0, action MAP_SIZE(this.storage), +1, fromMapToArray_loop(i, keysStorageArray, unseenKeys) ); @@ -316,9 +303,8 @@ automaton HashSetAutomaton val otherExpectedModCount: int = HashSetAutomaton(other).modCount; val otherStorage: map = HashSetAutomaton(other).storage; - val otherLength: int = HashSetAutomaton(other).length; - if (this.length == otherLength) + if (action MAP_SIZE(this.storage) == action MAP_SIZE(otherStorage)) result = action OBJECT_EQUALS(this.storage, otherStorage); else result = false; @@ -348,10 +334,10 @@ automaton HashSetAutomaton val expectedModCount: int = this.modCount; val otherSize: int = action CALL_METHOD(c, "size", []); val iter: Iterator = action CALL_METHOD(c, "iterator", []); - val lengthBeforeRemoving: int = this.length; + val lengthBeforeRemoving: int = action MAP_SIZE(this.storage); var i: int = 0; - if (this.length > otherSize) + if (action MAP_SIZE(this.storage) > otherSize) { action LOOP_WHILE( action CALL_METHOD(iter, "hasNext", []), @@ -363,7 +349,7 @@ automaton HashSetAutomaton val unseenKeys: map = action MAP_CLONE(this.storage); action LOOP_WHILE( - i < this.length, + i < action MAP_SIZE(this.storage), _removeAllElements_loop_indirect(i, c, unseenKeys) ); } @@ -371,20 +357,16 @@ automaton HashSetAutomaton _checkForComodification(expectedModCount); this.modCount += 1; // If length changed, it means that at least one element was deleted - result = lengthBeforeRemoving != this.length; + result = lengthBeforeRemoving != action MAP_SIZE(this.storage); } @Phantom proc removeAllElements_loop_direct (iter: Iterator): void { val key: Object = action CALL_METHOD(iter, "next", []); - val isKeyExist: boolean = action MAP_HAS_KEY(this.storage, key); - if (isKeyExist) - { + if (action MAP_HAS_KEY(this.storage, key)) action MAP_REMOVE(this.storage, key); - this.length -= 1; - } } @@ -393,13 +375,8 @@ automaton HashSetAutomaton val key: Object = action MAP_GET_ANY_KEY(unseenKeys); action MAP_REMOVE(unseenKeys, key); - val isCollectionContainsKey: boolean = action CALL_METHOD(c, "contains", [key]); - - if (isCollectionContainsKey) - { + if (action CALL_METHOD(c, "contains", [key])) action MAP_REMOVE(this.storage, key); - this.length -= 1; - } i += 1; } @@ -407,7 +384,7 @@ automaton HashSetAutomaton fun *.toArray (@target self: HashSet): array { - val len: int = this.length; + val len: int = action MAP_SIZE(this.storage); result = action ARRAY_NEW("java.lang.Object", len); val expectedModCount: int = this.modCount; val unseenKeys: map = action MAP_CLONE(this.storage); @@ -435,7 +412,7 @@ automaton HashSetAutomaton { val expectedModCount: int = this.modCount; val aLen: int = action ARRAY_SIZE(a); - val len: int = this.length; + val len: int = action MAP_SIZE(this.storage); val unseenKeys: map = action MAP_CLONE(this.storage); var i: int = 0; @@ -449,8 +426,8 @@ automaton HashSetAutomaton toArray_loop(i, unseenKeys, result) ); - if (aLen > this.length) - result[this.length] = null; + if (aLen > len) + result[len] = null; _checkForComodification(expectedModCount); } @@ -461,7 +438,7 @@ automaton HashSetAutomaton if (generator == null) _throwNPE(); - val len: int = this.length; + val len: int = action MAP_SIZE(this.storage); result = action CALL(generator, [0]) as array; val expectedModCount: int = this.modCount; val unseenKeys: map = action MAP_CLONE(this.storage); @@ -515,7 +492,7 @@ automaton HashSetAutomaton if (c == null) _throwNPE(); - val lengthBeforeAdd: int = this.length; + val lengthBeforeAdd: int = action MAP_SIZE(this.storage); val iter: Iterator = action CALL_METHOD(c, "iterator", []); action LOOP_WHILE( @@ -523,7 +500,7 @@ automaton HashSetAutomaton _retainAllElements_loop(iter) ); - if (lengthBeforeAdd != this.length) + if (lengthBeforeAdd != action MAP_SIZE(this.storage)) { this.modCount += 1; result = true; @@ -538,13 +515,9 @@ automaton HashSetAutomaton @Phantom proc _retainAllElements_loop(iter: Iterator): void { val key: Object = action CALL_METHOD(iter, "next", []); - val hasKey: boolean = action MAP_HAS_KEY(this.storage, key); - if (!hasKey) - { + if (action MAP_HAS_KEY(this.storage, key) == false) action MAP_REMOVE(this.storage, key); - this.length -= 1; - } } @@ -553,7 +526,7 @@ automaton HashSetAutomaton if (filter == null) _throwNPE(); - val lengthBeforeAdd: int = this.length; + val lengthBeforeAdd: int = action MAP_SIZE(this.storage); val expectedModCount: int = this.modCount; var i: int = 0; val unseenKeys: map = action MAP_CLONE(this.storage); @@ -564,7 +537,7 @@ automaton HashSetAutomaton ); _checkForComodification(expectedModCount); - if (lengthBeforeAdd != this.length) + if (lengthBeforeAdd != action MAP_SIZE(this.storage)) { this.modCount += 1; result = true; @@ -581,13 +554,8 @@ automaton HashSetAutomaton val key: Object = action MAP_GET_ANY_KEY(unseenKeys); action MAP_REMOVE(unseenKeys, key); - var isDelete: boolean = action CALL(filter, [key]); - - if(isDelete) - { + if(action CALL(filter, [key])) action MAP_REMOVE(this.storage, key); - this.length -= 1; - } i += 1; } @@ -599,11 +567,12 @@ automaton HashSetAutomaton _throwNPE(); var i: int = 0; + val count: int = action MAP_SIZE(this.storage); val expectedModCount: int = this.modCount; val unseenKeys: map = action MAP_CLONE(this.storage); action LOOP_WHILE( - i < this.length, + i < count, forEach_loop(i, unseenKeys, userAction) ); From da47634c92f6f4d80f5fd147e23334495af59100 Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Wed, 29 Nov 2023 10:24:09 +0300 Subject: [PATCH 61/78] Removed `length` variable from `LinkedHashSetAutomaton` + Minor improvements --- spec/java/util/HashSet.main.lsl | 7 +- spec/java/util/LinkedHashSet.KeyIterator.lsl | 20 ++-- spec/java/util/LinkedHashSet.Spliterator.lsl | 17 ++-- spec/java/util/LinkedHashSet.main.lsl | 97 +++++++------------- 4 files changed, 55 insertions(+), 86 deletions(-) diff --git a/spec/java/util/HashSet.main.lsl b/spec/java/util/HashSet.main.lsl index c6307775..5982b48a 100644 --- a/spec/java/util/HashSet.main.lsl +++ b/spec/java/util/HashSet.main.lsl @@ -201,10 +201,8 @@ automaton HashSetAutomaton fun *.clone (@target self: HashSet): Object { - val storageCopy: map = action MAP_CLONE(this.storage); - result = new HashSetAutomaton(state = Initialized, - storage = storageCopy, + storage = action MAP_CLONE(this.storage) ); } @@ -296,8 +294,7 @@ automaton HashSetAutomaton } else { - val isSameType: boolean = action OBJECT_SAME_TYPE(self, other); - if (isSameType) + if (other has HashSetAutomaton) { val expectedModCount: int = this.modCount; val otherExpectedModCount: int = HashSetAutomaton(other).modCount; diff --git a/spec/java/util/LinkedHashSet.KeyIterator.lsl b/spec/java/util/LinkedHashSet.KeyIterator.lsl index 9c440f39..e1ce96d0 100644 --- a/spec/java/util/LinkedHashSet.KeyIterator.lsl +++ b/spec/java/util/LinkedHashSet.KeyIterator.lsl @@ -73,8 +73,10 @@ automaton LinkedHashSet_KeyIteratorAutomaton fun *.hasNext (@target self: LinkedHashSet_KeyIterator): boolean { action ASSUME(this.parent != null); - val length: int = LinkedHashSetAutomaton(this.parent).length; - result = this.index < length; + + val parentStorage: map = LinkedHashSetAutomaton(this.parent).storage; + + result = this.index < action MAP_SIZE(parentStorage); } @@ -83,8 +85,9 @@ automaton LinkedHashSet_KeyIteratorAutomaton action ASSUME(this.parent != null); _checkForComodification(); - val length: int = LinkedHashSetAutomaton(this.parent).length; - val atValidPosition: boolean = this.index < length; + val parentStorage: map = LinkedHashSetAutomaton(this.parent).storage; + + val atValidPosition: boolean = this.index < action MAP_SIZE(parentStorage); if (!atValidPosition) action THROW_NEW("java.util.NoSuchElementException", []); @@ -104,8 +107,9 @@ automaton LinkedHashSet_KeyIteratorAutomaton { action ASSUME(this.parent != null); - val length: int = LinkedHashSetAutomaton(this.parent).length; - val atValidPosition: boolean = this.index < length; + val parentStorage: map = LinkedHashSetAutomaton(this.parent).storage; + + val atValidPosition: boolean = this.index < action MAP_SIZE(parentStorage); if (!atValidPosition || !this.nextWasCalled) action THROW_NEW("java.lang.IllegalStateException", []); @@ -113,7 +117,6 @@ automaton LinkedHashSet_KeyIteratorAutomaton _checkForComodification(); - val parentStorage: map = LinkedHashSetAutomaton(this.parent).storage; action MAP_REMOVE(parentStorage, this.currentKey); this.expectedModCount = LinkedHashSetAutomaton(this.parent).modCount; @@ -127,7 +130,8 @@ automaton LinkedHashSet_KeyIteratorAutomaton if (userAction == null) action THROW_NEW("java.lang.NullPointerException", []); - val length: int = LinkedHashSetAutomaton(this.parent).length; + val parentStorage: map = LinkedHashSetAutomaton(this.parent).storage; + val length: int = action MAP_SIZE(parentStorage); var i: int = this.index; action LOOP_WHILE( diff --git a/spec/java/util/LinkedHashSet.Spliterator.lsl b/spec/java/util/LinkedHashSet.Spliterator.lsl index f356fbc5..86a161d5 100644 --- a/spec/java/util/LinkedHashSet.Spliterator.lsl +++ b/spec/java/util/LinkedHashSet.Spliterator.lsl @@ -59,7 +59,7 @@ automaton LinkedHashSet_KeySpliteratorAutomaton if (hi < 0) { val parentStorage: map = LinkedHashSetAutomaton(this.parent).storage; - this.est = LinkedHashSetAutomaton(this.parent).length; + this.est = action MAP_SIZE(parentStorage); this.expectedModCount = LinkedHashSetAutomaton(this.parent).modCount; this.fence = this.est; // That's right ? @@ -108,12 +108,13 @@ automaton LinkedHashSet_KeySpliteratorAutomaton { action ASSUME(this.parent != null); - var mask: int = 0; - val length: int = LinkedHashSetAutomaton(this.parent).length; - if (this.fence < 0 || this.est == length) - mask = SPLITERATOR_SIZED; + val parentStorage: map = LinkedHashSetAutomaton(this.parent).storage; - result = mask | SPLITERATOR_DISTINCT; + result = 0; + if (this.fence < 0 || this.est == action MAP_SIZE(parentStorage)) + result = SPLITERATOR_SIZED; + + result |= SPLITERATOR_DISTINCT; } @@ -127,7 +128,9 @@ automaton LinkedHashSet_KeySpliteratorAutomaton var hi: int = this.fence; var mc: int = this.expectedModCount; var i: int = this.index; - val length: int = LinkedHashSetAutomaton(this.parent).length; + + val parentStorage: map = LinkedHashSetAutomaton(this.parent).storage; + val length: int = action MAP_SIZE(parentStorage); if(hi < 0) { diff --git a/spec/java/util/LinkedHashSet.main.lsl b/spec/java/util/LinkedHashSet.main.lsl index 47a619df..f8a589be 100644 --- a/spec/java/util/LinkedHashSet.main.lsl +++ b/spec/java/util/LinkedHashSet.main.lsl @@ -20,8 +20,7 @@ import java/util/Spliterator; automaton LinkedHashSetAutomaton ( - var storage: map = null, - @transient var length: int = 0 + var storage: map ) : LinkedHashSet { @@ -84,7 +83,7 @@ automaton LinkedHashSetAutomaton proc _addAllElements (c: Collection): boolean { - val lengthBeforeAdd: int = this.length; + val lengthBeforeAdd: int = action MAP_SIZE(this.storage); val iter: Iterator = action CALL_METHOD(c, "iterator", []); action LOOP_WHILE( @@ -92,7 +91,7 @@ automaton LinkedHashSetAutomaton _addAllElements_loop(iter) ); - if (lengthBeforeAdd != this.length) + if (lengthBeforeAdd != action MAP_SIZE(this.storage)) { this.modCount += 1; result = true; @@ -107,13 +106,9 @@ automaton LinkedHashSetAutomaton @Phantom proc _addAllElements_loop(iter: Iterator): void { val key: Object = action CALL_METHOD(iter, "next", []); - val hasKey: boolean = action MAP_HAS_KEY(this.storage, key); - if (!hasKey) - { + if (action MAP_HAS_KEY(this.storage, key) == false) action MAP_SET(this.storage, key, SOMETHING); - this.length += 1; - } } @@ -180,10 +175,7 @@ automaton LinkedHashSetAutomaton } else { - this.length += 1; - action MAP_SET(this.storage, obj, SOMETHING); - result = true; } @@ -193,27 +185,22 @@ automaton LinkedHashSetAutomaton fun *.clear (@target self: LinkedHashSet): void { - this.length = 0; this.storage = action MAP_NEW(); - this.modCount +=1; } fun *.clone (@target self: LinkedHashSet): Object { - val storageCopy: map = action MAP_CLONE(this.storage); - result = new LinkedHashSetAutomaton(state = Initialized, - storage = storageCopy, - length = this.length + storage = action MAP_CLONE(this.storage) ); } fun *.contains (@target self: LinkedHashSet, obj: Object): boolean { - if (this.length == 0) + if (action MAP_SIZE(this.storage) == 0) result = false; else result = action MAP_HAS_KEY(this.storage, obj); @@ -222,7 +209,7 @@ automaton LinkedHashSetAutomaton fun *.isEmpty (@target self: LinkedHashSet): boolean { - result = this.length == 0; + result = action MAP_SIZE(this.storage) == 0; } @@ -239,11 +226,9 @@ automaton LinkedHashSetAutomaton fun *.remove (@target self: LinkedHashSet, obj: Object): boolean { - val hasKey: boolean = action MAP_HAS_KEY(this.storage, obj); - if (hasKey) + if (action MAP_HAS_KEY(this.storage, obj)) { action MAP_REMOVE(this.storage, obj); - this.length -= 1; this.modCount += 1; result = true; } @@ -256,18 +241,18 @@ automaton LinkedHashSetAutomaton fun *.size (@target self: LinkedHashSet): int { - result = this.length; + result = action MAP_SIZE(this.storage); } fun *.spliterator (@target self: LinkedHashSet): Spliterator { - val keysStorageArray: array = action ARRAY_NEW("java.lang.Object", this.length); + val keysStorageArray: array = action ARRAY_NEW("java.lang.Object", action MAP_SIZE(this.storage)); val unseenKeys: map = action MAP_CLONE(this.storage); var i: int = 0; action LOOP_FOR( - i, 0, this.length, +1, + i, 0, action MAP_SIZE(this.storage), +1, fromMapToArray_loop(i, keysStorageArray, unseenKeys) ); @@ -299,16 +284,14 @@ automaton LinkedHashSetAutomaton } else { - val isSameType: boolean = action OBJECT_SAME_TYPE(self, other); - if (isSameType) + if (other has LinkedHashSetAutomaton) { val expectedModCount: int = this.modCount; val otherExpectedModCount: int = LinkedHashSetAutomaton(other).modCount; val otherStorage: map = LinkedHashSetAutomaton(other).storage; - val otherLength: int = LinkedHashSetAutomaton(other).length; - if (this.length == otherLength) + if (action MAP_SIZE(this.storage) == action MAP_SIZE(otherStorage)) result = action OBJECT_EQUALS(this.storage, otherStorage); else result = false; @@ -338,10 +321,10 @@ automaton LinkedHashSetAutomaton val expectedModCount: int = this.modCount; val otherSize: int = action CALL_METHOD(c, "size", []); val iter: Iterator = action CALL_METHOD(c, "iterator", []); - val lengthBeforeRemoving: int = this.length; + val lengthBeforeRemoving: int = action MAP_SIZE(this.storage); var i: int = 0; - if (this.length > otherSize) + if (action MAP_SIZE(this.storage) > otherSize) { action LOOP_WHILE( action CALL_METHOD(iter, "hasNext", []), @@ -352,7 +335,7 @@ automaton LinkedHashSetAutomaton { val unseenKeys: map = action MAP_CLONE(this.storage); action LOOP_WHILE( - i < this.length, + i < action MAP_SIZE(this.storage), _removeAllElements_loop_indirect(i, c, unseenKeys) ); } @@ -360,20 +343,16 @@ automaton LinkedHashSetAutomaton _checkForComodification(expectedModCount); this.modCount += 1; // If length changed, it means that at least one element was deleted - result = lengthBeforeRemoving != this.length; + result = lengthBeforeRemoving != action MAP_SIZE(this.storage); } @Phantom proc removeAllElements_loop_direct (iter: Iterator): void { val key: Object = action CALL_METHOD(iter, "next", []); - val isKeyExist: boolean = action MAP_HAS_KEY(this.storage, key); - if (isKeyExist) - { + if (action MAP_HAS_KEY(this.storage, key)) action MAP_REMOVE(this.storage, key); - this.length -= 1; - } } @@ -382,13 +361,8 @@ automaton LinkedHashSetAutomaton val key: Object = action MAP_GET_ANY_KEY(unseenKeys); action MAP_REMOVE(unseenKeys, key); - val isCollectionContainsKey: boolean = action CALL_METHOD(c, "contains", [key]); - - if (isCollectionContainsKey) - { + if (action CALL_METHOD(c, "contains", [key])) action MAP_REMOVE(this.storage, key); - this.length -= 1; - } i += 1; } @@ -396,7 +370,7 @@ automaton LinkedHashSetAutomaton fun *.toArray (@target self: LinkedHashSet): array { - val len: int = this.length; + val len: int = action MAP_SIZE(this.storage); result = action ARRAY_NEW("java.lang.Object", len); val expectedModCount: int = this.modCount; val unseenKeys: map = action MAP_CLONE(this.storage); @@ -424,7 +398,7 @@ automaton LinkedHashSetAutomaton { val expectedModCount: int = this.modCount; val aLen: int = action ARRAY_SIZE(a); - val len: int = this.length; + val len: int = action MAP_SIZE(this.storage); val unseenKeys: map = action MAP_CLONE(this.storage); var i: int = 0; @@ -438,8 +412,8 @@ automaton LinkedHashSetAutomaton toArray_loop(i, unseenKeys, result) ); - if (aLen > this.length) - result[this.length] = null; + if (aLen > len) + result[len] = null; _checkForComodification(expectedModCount); } @@ -450,7 +424,7 @@ automaton LinkedHashSetAutomaton if (generator == null) _throwNPE(); - val len: int = this.length; + val len: int = action MAP_SIZE(this.storage); result = action CALL(generator, [0]) as array; val expectedModCount: int = this.modCount; val unseenKeys: map = action MAP_CLONE(this.storage); @@ -504,7 +478,7 @@ automaton LinkedHashSetAutomaton if (c == null) _throwNPE(); - val lengthBeforeAdd: int = this.length; + val lengthBeforeAdd: int = action MAP_SIZE(this.storage); val iter: Iterator = action CALL_METHOD(c, "iterator", []); action LOOP_WHILE( @@ -512,7 +486,7 @@ automaton LinkedHashSetAutomaton _retainAllElements_loop(iter) ); - if (lengthBeforeAdd != this.length) + if (lengthBeforeAdd != action MAP_SIZE(this.storage)) { this.modCount += 1; result = true; @@ -527,13 +501,9 @@ automaton LinkedHashSetAutomaton @Phantom proc _retainAllElements_loop(iter: Iterator): void { val key: Object = action CALL_METHOD(iter, "next", []); - val hasKey: boolean = action MAP_HAS_KEY(this.storage, key); - if (!hasKey) - { + if (action MAP_HAS_KEY(this.storage, key) == false) action MAP_REMOVE(this.storage, key); - this.length -= 1; - } } @@ -542,7 +512,7 @@ automaton LinkedHashSetAutomaton if (filter == null) _throwNPE(); - val lengthBeforeAdd: int = this.length; + val lengthBeforeAdd: int = action MAP_SIZE(this.storage); val expectedModCount: int = this.modCount; var i: int = 0; val unseenKeys: map = action MAP_CLONE(this.storage); @@ -553,7 +523,7 @@ automaton LinkedHashSetAutomaton ); _checkForComodification(expectedModCount); - if (lengthBeforeAdd != this.length) + if (lengthBeforeAdd != action MAP_SIZE(this.storage)) { this.modCount += 1; result = true; @@ -570,13 +540,8 @@ automaton LinkedHashSetAutomaton val key: Object = action MAP_GET_ANY_KEY(unseenKeys); action MAP_REMOVE(unseenKeys, key); - var isDelete: boolean = action CALL(filter, [key]); - - if(isDelete) - { + if(action CALL(filter, [key])) action MAP_REMOVE(this.storage, key); - this.length -= 1; - } i += 1; } @@ -592,7 +557,7 @@ automaton LinkedHashSetAutomaton val unseenKeys: map = action MAP_CLONE(this.storage); action LOOP_WHILE( - i < this.length, + i < action MAP_SIZE(this.storage), forEach_loop(i, unseenKeys, userAction) ); From d6589deeb80caf48da3b2497c37fbbc254e970a2 Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Wed, 29 Nov 2023 10:28:58 +0300 Subject: [PATCH 62/78] Spec file rename --- spec/java/util/{LinkedList.automata.lsl => LinkedList.main.lsl} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename spec/java/util/{LinkedList.automata.lsl => LinkedList.main.lsl} (100%) diff --git a/spec/java/util/LinkedList.automata.lsl b/spec/java/util/LinkedList.main.lsl similarity index 100% rename from spec/java/util/LinkedList.automata.lsl rename to spec/java/util/LinkedList.main.lsl From 60093302ef6b86ed0fc5256cb4071906b7fad2bf Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Wed, 29 Nov 2023 10:36:29 +0300 Subject: [PATCH 63/78] Removed `size` variable from `LinkedListAutomaton` + Minor improvements --- spec/java/util/LinkedList.main.lsl | 139 ++++++++++++----------------- 1 file changed, 59 insertions(+), 80 deletions(-) diff --git a/spec/java/util/LinkedList.main.lsl b/spec/java/util/LinkedList.main.lsl index 9c1d4eb8..8da38ef0 100644 --- a/spec/java/util/LinkedList.main.lsl +++ b/spec/java/util/LinkedList.main.lsl @@ -14,8 +14,7 @@ import java/util/LinkedList; automaton LinkedListAutomaton ( - var storage: list, - @transient var size: int + var storage: list ) : LinkedList { @@ -115,8 +114,6 @@ automaton LinkedListAutomaton { result = action LIST_GET(this.storage, index); action LIST_REMOVE(this.storage, index); - - this.size -= 1; this.modCount += 1; } @@ -124,8 +121,6 @@ automaton LinkedListAutomaton proc _linkAny (index: int, e: Object): void { action LIST_INSERT_AT(this.storage, index, e); - - this.size += 1; this.modCount += 1; } @@ -136,7 +131,7 @@ automaton LinkedListAutomaton { //val message: String = // "Index: " + action OBJECT_TO_STRING(index) + - // ", Size: " + action OBJECT_TO_STRING(this.size); + // ", Size: " + action OBJECT_TO_STRING(action LIST_SIZE(this.storage)); action THROW_NEW("java.lang.IndexOutOfBoundsException", []); } } @@ -144,13 +139,13 @@ automaton LinkedListAutomaton proc _isValidIndex (index: int): boolean { - result = 0 <= index && index < this.size; + result = 0 <= index && index < action LIST_SIZE(this.storage); } proc _isPositionIndex (index: int): boolean { - result = 0 <= index && index <= this.size; + result = 0 <= index && index <= action LIST_SIZE(this.storage); } @@ -160,7 +155,7 @@ automaton LinkedListAutomaton { //val message: String = // "Index: " + action OBJECT_TO_STRING(index) + - // ", Size: " + action OBJECT_TO_STRING(this.size); + // ", Size: " + action OBJECT_TO_STRING(action LIST_SIZE(this.storage)); action THROW_NEW("java.lang.IndexOutOfBoundsException", []); } } @@ -168,7 +163,7 @@ automaton LinkedListAutomaton proc _unlinkFirst (): Object { - if (this.size == 0) + if (action LIST_SIZE(this.storage) == 0) action THROW_NEW("java.util.NoSuchElementException", []); result = _unlinkAny(0); @@ -177,13 +172,11 @@ automaton LinkedListAutomaton proc _unlinkByFirstEqualsObject (o: Object): boolean { - val index: int = action LIST_FIND(this.storage, o, 0, this.size); + val index: int = action LIST_FIND(this.storage, o, 0, action LIST_SIZE(this.storage)); result = index != -1; if (result) { action LIST_REMOVE(this.storage, index); - - this.size -= 1; this.modCount += 1; } } @@ -210,13 +203,12 @@ automaton LinkedListAutomaton action LIST_INSERT_AT(this.storage, index, item); index += 1; - this.size += 1; } proc _getFirstElement (): Object { - if (this.size == 0) + if (action LIST_SIZE(this.storage) == 0) action THROW_NEW("java.util.NoSuchElementException", []); result = action LIST_GET(this.storage, 0); @@ -250,7 +242,7 @@ automaton LinkedListAutomaton if (filter == null) _throwNPE(); - val oldSize: int = this.size; + val oldSize: int = action LIST_SIZE(this.storage); val expectedModCount: int = this.modCount; // remove elements from the back first @@ -263,17 +255,15 @@ automaton LinkedListAutomaton _checkForComodification(expectedModCount); - result = oldSize != this.size; + result = oldSize != action LIST_SIZE(this.storage); } @Phantom proc _removeIf_loop (i: int, filter: Predicate): void { val item: Object = action LIST_GET(this.storage, i); + if (action CALL(filter, [item])) - { action LIST_REMOVE(this.storage, i); - this.size -= 1; - } } @@ -287,21 +277,16 @@ automaton LinkedListAutomaton if (other has LinkedListAutomaton) { - otherLength = LinkedListAutomaton(other).size; - action ASSUME(otherLength >= 0); + otherStorage = LinkedListAutomaton(other).storage; + otherLength = action LIST_SIZE(otherStorage); // assumptions: no multithreading, from == 0 result = to == otherLength; if (result) - { - otherStorage = LinkedListAutomaton(other).storage; - action ASSUME(otherStorage != null); - action LOOP_WHILE( result && i < to, _equalsRange_loop_optimized(i, otherStorage, result) ); - } } /*else if (other has LinkedList_SubListAutomaton) { @@ -368,7 +353,7 @@ automaton LinkedListAutomaton @KeepVisible proc _batchRemove (c: Collection, complement: boolean, start: int, end: int): boolean { - val oldSize: int = this.size; + val oldSize: int = action LIST_SIZE(this.storage); if (oldSize == 0 || start >= end) { result = false; @@ -406,7 +391,7 @@ automaton LinkedListAutomaton ); } - result = oldSize != this.size; + result = oldSize != action LIST_SIZE(this.storage); } } } @@ -414,7 +399,7 @@ automaton LinkedListAutomaton @Phantom proc _batchRemove_loop_optimized (i: int, otherStorage: list, complement: boolean): void { val item: Object = action LIST_GET(this.storage, i); - if ((action LIST_FIND(otherStorage, item, 0, this.size) == -1) == complement) + if ((action LIST_FIND(otherStorage, item, 0, action LIST_SIZE(this.storage)) == -1) == complement) _unlinkAny(i); } @@ -522,7 +507,6 @@ automaton LinkedListAutomaton constructor *.LinkedList (@target self: LinkedList) { this.storage = action LIST_NEW(); - this.size = 0; } @@ -532,9 +516,8 @@ automaton LinkedListAutomaton _throwNPE(); this.storage = action LIST_NEW(); - this.size = 0; - _addAllElements(this.size, c); + _addAllElements(action LIST_SIZE(this.storage), c); } @@ -542,7 +525,7 @@ automaton LinkedListAutomaton fun *.add (@target self: LinkedList, e: Object): boolean { - _linkAny(this.size, e); + _linkAny(action LIST_SIZE(this.storage), e); result = true; } @@ -556,7 +539,7 @@ automaton LinkedListAutomaton fun *.addAll (@target self: LinkedList, c: Collection): boolean { - result = _addAllElements(this.size, c); + result = _addAllElements(action LIST_SIZE(this.storage), c); } @@ -574,14 +557,13 @@ automaton LinkedListAutomaton fun *.addLast (@target self: LinkedList, e: Object): void { - _linkAny(this.size, e); + _linkAny(action LIST_SIZE(this.storage), e); } fun *.clear (@target self: LinkedList): void { this.storage = action LIST_NEW(); - this.size = 0; this.modCount += 1; } @@ -589,18 +571,17 @@ automaton LinkedListAutomaton fun *.clone (@target self: LinkedList): Object { val storageCopy: list = action LIST_NEW(); - action LIST_COPY(this.storage, storageCopy, 0, 0, this.size); + action LIST_COPY(this.storage, storageCopy, 0, 0, action LIST_SIZE(this.storage)); result = new LinkedListAutomaton(state = Initialized, - storage = storageCopy, - size = this.size + storage = storageCopy ); } fun *.contains (@target self: LinkedList, o: Object): boolean { - result = action LIST_FIND(this.storage, o, 0, this.size) != -1; + result = action LIST_FIND(this.storage, o, 0, action LIST_SIZE(this.storage)) != -1; } @@ -612,7 +593,7 @@ automaton LinkedListAutomaton if (c has LinkedListAutomaton) { val otherStorage: list = LinkedListAutomaton(c).storage; - val otherSize: int = LinkedListAutomaton(c).size; + val otherSize: int = action LIST_SIZE(otherStorage); action ASSUME(otherStorage != null); action ASSUME(otherSize >= 0); @@ -636,7 +617,7 @@ automaton LinkedListAutomaton @Phantom proc containsAll_loop_optimized (otherStorage: list, i: int, result: boolean): void { val item: Object = action LIST_GET(otherStorage, i); - result = action LIST_FIND(this.storage, item, 0, this.size) != -1; + result = action LIST_FIND(this.storage, item, 0, action LIST_SIZE(this.storage)) != -1; i += 1; } @@ -644,7 +625,7 @@ automaton LinkedListAutomaton @Phantom proc containsAll_loop_regular (iter: Iterator, result: boolean): void { val item: Object = action CALL_METHOD(iter, "next", []); - result = action LIST_FIND(this.storage, item, 0, this.size) != -1; + result = action LIST_FIND(this.storage, item, 0, action LIST_SIZE(this.storage)) != -1; } @@ -680,9 +661,8 @@ automaton LinkedListAutomaton val otherExpectedModCount: int = LinkedListAutomaton(o).modCount; val otherStorage: list = LinkedListAutomaton(o).storage; - val otherSize: int = LinkedListAutomaton(o).size; - if (this.size == otherSize) + if (action LIST_SIZE(this.storage) == action LIST_SIZE(otherStorage)) { result = action OBJECT_EQUALS(this.storage, otherStorage); } @@ -712,7 +692,7 @@ automaton LinkedListAutomaton var i: int = 0; action LOOP_WHILE( - this.modCount == expectedModCount && i < this.size, + this.modCount == expectedModCount && i < action LIST_SIZE(this.storage), forEach_loop(i, _action) ); @@ -743,10 +723,10 @@ automaton LinkedListAutomaton fun *.getLast (@target self: LinkedList): Object { - if (this.size == 0) + if (action LIST_SIZE(this.storage) == 0) action THROW_NEW("java.util.NoSuchElementException", []); - result = action LIST_GET(this.storage, this.size - 1); + result = action LIST_GET(this.storage, action LIST_SIZE(this.storage) - 1); } @@ -759,14 +739,14 @@ automaton LinkedListAutomaton fun *.indexOf (@target self: LinkedList, o: Object): int { - result = action LIST_FIND(this.storage, o, 0, this.size); + result = action LIST_FIND(this.storage, o, 0, action LIST_SIZE(this.storage)); } // within java.util.AbstractCollection fun *.isEmpty (@target self: LinkedList): boolean { - result = this.size == 0; + result = action LIST_SIZE(this.storage) == 0; } @@ -786,14 +766,14 @@ automaton LinkedListAutomaton fun *.lastIndexOf (@target self: LinkedList, o: Object): int { - result = action LIST_FIND(this.storage, o, 0, this.size); + result = action LIST_FIND(this.storage, o, 0, action LIST_SIZE(this.storage)); if (result != -1) { // there should be no elements to the right of the previously found position val nextIndex: int = result + 1; - if (nextIndex < this.size) + if (nextIndex < action LIST_SIZE(this.storage)) { - val rightIndex: int = action LIST_FIND(this.storage, o, nextIndex, this.size); + val rightIndex: int = action LIST_FIND(this.storage, o, nextIndex, action LIST_SIZE(this.storage)); action ASSUME(rightIndex == -1); } } @@ -831,7 +811,7 @@ automaton LinkedListAutomaton fun *.offer (@target self: LinkedList, e: Object): boolean { - _linkAny(this.size, e); + _linkAny(action LIST_SIZE(this.storage), e); result = true; } @@ -845,7 +825,7 @@ automaton LinkedListAutomaton fun *.offerLast (@target self: LinkedList, e: Object): boolean { - _linkAny(this.size, e); + _linkAny(action LIST_SIZE(this.storage), e); result = true; } @@ -859,7 +839,7 @@ automaton LinkedListAutomaton fun *.peek (@target self: LinkedList): Object { - if (this.size == 0) + if (action LIST_SIZE(this.storage) == 0) result = null; else result = action LIST_GET(this.storage, 0); @@ -868,7 +848,7 @@ automaton LinkedListAutomaton fun *.peekFirst (@target self: LinkedList): Object { - if (this.size == 0) + if (action LIST_SIZE(this.storage) == 0) result = null; else result = action LIST_GET(this.storage, 0); @@ -877,16 +857,16 @@ automaton LinkedListAutomaton fun *.peekLast (@target self: LinkedList): Object { - if (this.size == 0) + if (action LIST_SIZE(this.storage) == 0) result = null; else - result = action LIST_GET(this.storage, this.size - 1); + result = action LIST_GET(this.storage, action LIST_SIZE(this.storage) - 1); } fun *.poll (@target self: LinkedList): Object { - if (this.size == 0) + if (action LIST_SIZE(this.storage) == 0) result = null; else result = _unlinkAny(0); @@ -895,7 +875,7 @@ automaton LinkedListAutomaton fun *.pollFirst (@target self: LinkedList): Object { - if (this.size == 0) + if (action LIST_SIZE(this.storage) == 0) result = null; else result = _unlinkAny(0); @@ -904,10 +884,10 @@ automaton LinkedListAutomaton fun *.pollLast (@target self: LinkedList): Object { - if (this.size == 0) + if (action LIST_SIZE(this.storage) == 0) result = null; else - result = _unlinkAny(this.size - 1); + result = _unlinkAny(action LIST_SIZE(this.storage) - 1); } @@ -945,7 +925,7 @@ automaton LinkedListAutomaton // within java.util.AbstractCollection fun *.removeAll (@target self: LinkedList, c: Collection): boolean { - result = _batchRemove(c, /* complement = */false, 0, this.size); + result = _batchRemove(c, /* complement = */false, 0, action LIST_SIZE(this.storage)); } @@ -964,22 +944,22 @@ automaton LinkedListAutomaton // within java.util.Collection fun *.removeIf (@target self: LinkedList, filter: Predicate): boolean { - result = _removeIf(filter, 0, this.size); + result = _removeIf(filter, 0, action LIST_SIZE(this.storage)); } fun *.removeLast (@target self: LinkedList): Object { - if (this.size == 0) + if (action LIST_SIZE(this.storage) == 0) action THROW_NEW("java.util.NoSuchElementException", []); - result = _unlinkAny(this.size - 1); + result = _unlinkAny(action LIST_SIZE(this.storage) - 1); } fun *.removeLastOccurrence (@target self: LinkedList, o: Object): boolean { - val index: int = action LIST_FIND(this.storage, o, 0, this.size); + val index: int = action LIST_FIND(this.storage, o, 0, action LIST_SIZE(this.storage)); if (index == -1) { result = false; @@ -990,15 +970,14 @@ automaton LinkedListAutomaton // there should be no elements to the right of the previously found position val nextIndex: int = index + 1; - if (nextIndex < this.size) + if (nextIndex < action LIST_SIZE(this.storage)) { - val rightIndex: int = action LIST_FIND(this.storage, o, nextIndex, this.size); + val rightIndex: int = action LIST_FIND(this.storage, o, nextIndex, action LIST_SIZE(this.storage)); action ASSUME(rightIndex == -1); } // actual removal and associated modifications action LIST_REMOVE(this.storage, index); - this.size -= 1; this.modCount += 1; } } @@ -1010,7 +989,7 @@ automaton LinkedListAutomaton if (op == null) _throwNPE(); - _replaceAllRange(op, 0, this.size); + _replaceAllRange(op, 0, action LIST_SIZE(this.storage)); this.modCount += 1; } @@ -1018,7 +997,7 @@ automaton LinkedListAutomaton // within java.util.AbstractCollection fun *.retainAll (@target self: LinkedList, c: Collection): boolean { - result = _batchRemove(c, /* complement = */true, 0, this.size); + result = _batchRemove(c, /* complement = */true, 0, action LIST_SIZE(this.storage)); } @@ -1032,14 +1011,14 @@ automaton LinkedListAutomaton fun *.size (@target self: LinkedList): int { - result = this.size; + result = action LIST_SIZE(this.storage); } // within java.util.List fun *.sort (@target self: LinkedList, c: Comparator): void { - _do_sort(0, this.size, c); + _do_sort(0, action LIST_SIZE(this.storage), c); } @@ -1074,7 +1053,7 @@ automaton LinkedListAutomaton fun *.toArray (@target self: LinkedList): array { - val len: int = this.size; + val len: int = action LIST_SIZE(this.storage); result = action ARRAY_NEW("java.lang.Object", len); var i: int = 0; @@ -1098,7 +1077,7 @@ automaton LinkedListAutomaton val a: array = action CALL_METHOD(generator, "apply", [0]) as array; val aLen: int = action ARRAY_SIZE(a); - val len: int = this.size; + val len: int = action LIST_SIZE(this.storage); // #problem: a.getClass() should be called to construct a type-valid array (USVM issue) result = action ARRAY_NEW("java.lang.Object", len); @@ -1113,7 +1092,7 @@ automaton LinkedListAutomaton fun *.toArray (@target self: LinkedList, a: array): array { val aLen: int = action ARRAY_SIZE(a); - val len: int = this.size; + val len: int = action LIST_SIZE(this.storage); var i: int = 0; if (aLen < len) From 183b7056c90131b2d2bdd3b16f186546e2e76170 Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Wed, 29 Nov 2023 11:58:27 +0300 Subject: [PATCH 64/78] Activated custom stream implementations for some collections --- spec/java/util/ArrayList.main.lsl | 28 +++++++++++++--- spec/java/util/HashSet.main.lsl | 44 +++++++++++++++++++++---- spec/java/util/LinkedHashSet.main.lsl | 46 +++++++++++++++++++++++---- spec/java/util/LinkedList.main.lsl | 28 +++++++++++++--- 4 files changed, 124 insertions(+), 22 deletions(-) diff --git a/spec/java/util/ArrayList.main.lsl b/spec/java/util/ArrayList.main.lsl index 4b5e4570..a775e8f9 100644 --- a/spec/java/util/ArrayList.main.lsl +++ b/spec/java/util/ArrayList.main.lsl @@ -7,6 +7,8 @@ library std // imports +import java/util/stream/Stream; + import java/util/ArrayList; @@ -339,10 +341,28 @@ automaton ArrayListAutomaton proc _makeStream (parallel: boolean): Stream { - // #todo: use custom stream implementation - result = action SYMBOLIC("java.util.stream.Stream"); - action ASSUME(result != null); - action ASSUME(action CALL_METHOD(result, "isParallel", []) == parallel); + val count: int = action LIST_SIZE(this.storage); + val items: array = action ARRAY_NEW("java.lang.Object", count); + + var i: int = 0; + action LOOP_FOR( + i, 0, count, +1, + _makeStream_loop(i, items) + ); + + // #problem: unable to catch concurrent modifications during stream processing + + result = new StreamAutomaton(state = Initialized, + storage = items, + length = count, + closeHandlers = action LIST_NEW(), + isParallel = parallel, + ); + } + + @Phantom proc _makeStream_loop (i: int, items: array): void + { + items[i] = action LIST_GET(this.storage, i); } diff --git a/spec/java/util/HashSet.main.lsl b/spec/java/util/HashSet.main.lsl index 5982b48a..44e73380 100644 --- a/spec/java/util/HashSet.main.lsl +++ b/spec/java/util/HashSet.main.lsl @@ -9,13 +9,15 @@ library std // imports import java/lang/Object; -import java/util/HashSet; import java/util/function/IntFunction; import java/util/function/Consumer; import java/util/function/Predicate; import java/util/Collection; import java/util/Iterator; import java/util/Spliterator; +import java/util/stream/Stream; + +import java/util/HashSet; // automata @@ -121,6 +123,38 @@ automaton HashSetAutomaton } + proc _makeStream (parallel: boolean): Stream + { + val unseen: map = action MAP_CLONE(this.storage); + + val count: int = action MAP_SIZE(unseen); + val items: array = action ARRAY_NEW("java.lang.Object", count); + + var i: int = 0; + action LOOP_FOR( + i, 0, count, +1, + _makeStream_loop(i, items, unseen) + ); + + // #problem: unable to catch concurrent modifications during stream processing + + result = new StreamAutomaton(state = Initialized, + storage = items, + length = count, + closeHandlers = action LIST_NEW(), + isParallel = parallel, + ); + } + + @Phantom proc _makeStream_loop (i: int, items: array, unseen: map): void + { + val key: Object = action MAP_GET_ANY_KEY(unseen); + action MAP_REMOVE(unseen, key); + + items[i] = key; + } + + // constructors constructor *.HashSet (@target self: HashSet) @@ -591,18 +625,14 @@ automaton HashSetAutomaton // within java.util.Collection fun *.stream (@target self: HashSet): Stream { - // #todo: use custom stream implementation - result = action SYMBOLIC("java.util.stream.Stream"); - action ASSUME(result != null); + result = _makeStream(/* parallel = */ false); } // within java.util.Collection fun *.parallelStream (@target self: HashSet): Stream { - // #todo: use custom stream implementation - result = action SYMBOLIC("java.util.stream.Stream"); - action ASSUME(result != null); + result = _makeStream(/* parallel = */ true); } diff --git a/spec/java/util/LinkedHashSet.main.lsl b/spec/java/util/LinkedHashSet.main.lsl index f8a589be..1e908c8d 100644 --- a/spec/java/util/LinkedHashSet.main.lsl +++ b/spec/java/util/LinkedHashSet.main.lsl @@ -8,13 +8,16 @@ library std // imports import java/lang/Object; -import java/util/LinkedHashSet; import java/util/function/IntFunction; import java/util/function/Consumer; import java/util/function/Predicate; import java/util/Collection; import java/util/Iterator; import java/util/Spliterator; +import java/util/stream/Stream; + +import java/util/LinkedHashSet; + // automata @@ -72,6 +75,7 @@ automaton LinkedHashSetAutomaton @transient var modCount: int = 0; + // utilities @KeepVisible proc _checkForComodification (expectedModCount: int): void @@ -118,6 +122,38 @@ automaton LinkedHashSetAutomaton } + proc _makeStream (parallel: boolean): Stream + { + val unseen: map = action MAP_CLONE(this.storage); + + val count: int = action MAP_SIZE(unseen); + val items: array = action ARRAY_NEW("java.lang.Object", count); + + var i: int = 0; + action LOOP_FOR( + i, 0, count, +1, + _makeStream_loop(i, items, unseen) + ); + + // #problem: unable to catch concurrent modifications during stream processing + + result = new StreamAutomaton(state = Initialized, + storage = items, + length = count, + closeHandlers = action LIST_NEW(), + isParallel = parallel, + ); + } + + @Phantom proc _makeStream_loop (i: int, items: array, unseen: map): void + { + val key: Object = action MAP_GET_ANY_KEY(unseen); + action MAP_REMOVE(unseen, key); + + items[i] = key; + } + + // constructors constructor *.LinkedHashSet (@target self: LinkedHashSet) @@ -579,18 +615,14 @@ automaton LinkedHashSetAutomaton // within java.util.Collection fun *.stream (@target self: LinkedHashSet): Stream { - // #todo: use custom stream implementation - result = action SYMBOLIC("java.util.stream.Stream"); - action ASSUME(result != null); + result = _makeStream(/* parallel = */ false); } // within java.util.Collection fun *.parallelStream (@target self: LinkedHashSet): Stream { - // #todo: use custom stream implementation - result = action SYMBOLIC("java.util.stream.Stream"); - action ASSUME(result != null); + result = _makeStream(/* parallel = */ true); } diff --git a/spec/java/util/LinkedList.main.lsl b/spec/java/util/LinkedList.main.lsl index 8da38ef0..9570f924 100644 --- a/spec/java/util/LinkedList.main.lsl +++ b/spec/java/util/LinkedList.main.lsl @@ -7,6 +7,8 @@ library std // imports +import java/util/stream/Stream; + import java/util/LinkedList; @@ -344,10 +346,28 @@ automaton LinkedListAutomaton proc _makeStream (parallel: boolean): Stream { - // #todo: use custom stream implementation - result = action SYMBOLIC("java.util.stream.Stream"); - action ASSUME(result != null); - action ASSUME(action CALL_METHOD(result, "isParallel", []) == parallel); + val count: int = action LIST_SIZE(this.storage); + val items: array = action ARRAY_NEW("java.lang.Object", count); + + var i: int = 0; + action LOOP_FOR( + i, 0, count, +1, + _makeStream_loop(i, items) + ); + + // #problem: unable to catch concurrent modifications during stream processing + + result = new StreamAutomaton(state = Initialized, + storage = items, + length = count, + closeHandlers = action LIST_NEW(), + isParallel = parallel, + ); + } + + @Phantom proc _makeStream_loop (i: int, items: array): void + { + items[i] = action LIST_GET(this.storage, i); } From 6b347fd4c5f339641d844612f8472ea93b2cd029 Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Wed, 29 Nov 2023 16:31:36 +0300 Subject: [PATCH 65/78] Package name change for utility automata and types --- spec/java/lang/Object.main.lsl | 2 +- spec/java/lang/System.StdOut.lsl | 2 +- spec/java/lang/System.main.lsl | 2 +- spec/{runtime => libsl}/utils/SymbolicInputStream.lsl | 3 ++- spec/{runtime => libsl}/utils/SymbolicInputStream.main.lsl | 2 +- spec/{runtime => libsl}/utils/VoidInputStream.lsl | 2 +- spec/{runtime => libsl}/utils/VoidInputStream.main.lsl | 2 +- spec/{runtime => libsl}/utils/VoidOutputStream.lsl | 2 +- spec/{runtime => libsl}/utils/VoidOutputStream.main.lsl | 2 +- 9 files changed, 10 insertions(+), 9 deletions(-) rename spec/{runtime => libsl}/utils/SymbolicInputStream.lsl (78%) rename spec/{runtime => libsl}/utils/SymbolicInputStream.main.lsl (99%) rename spec/{runtime => libsl}/utils/VoidInputStream.lsl (91%) rename spec/{runtime => libsl}/utils/VoidInputStream.main.lsl (99%) rename spec/{runtime => libsl}/utils/VoidOutputStream.lsl (91%) rename spec/{runtime => libsl}/utils/VoidOutputStream.main.lsl (98%) diff --git a/spec/java/lang/Object.main.lsl b/spec/java/lang/Object.main.lsl index 97f4f10a..0748c4ce 100644 --- a/spec/java/lang/Object.main.lsl +++ b/spec/java/lang/Object.main.lsl @@ -48,7 +48,7 @@ automaton ObjectAutomaton @Phantom constructor *.LSLObject (@target self: LSLObject) { - // NOTE: using the original method + // WARNING: Using the original method here. Do not change! (infinite recursion otherwise) } diff --git a/spec/java/lang/System.StdOut.lsl b/spec/java/lang/System.StdOut.lsl index 5cf6e771..e4fbd14f 100644 --- a/spec/java/lang/System.StdOut.lsl +++ b/spec/java/lang/System.StdOut.lsl @@ -13,7 +13,7 @@ import java/lang/String; import java/util/Locale; import java/lang/System; -import runtime/utils/VoidOutputStream; +import libsl/utils/VoidOutputStream; // automata diff --git a/spec/java/lang/System.main.lsl b/spec/java/lang/System.main.lsl index b97aa57c..77a0e54f 100644 --- a/spec/java/lang/System.main.lsl +++ b/spec/java/lang/System.main.lsl @@ -24,7 +24,7 @@ import sun/misc/VM; // #problem: does not exist in Java-11 import java/lang/System; -import runtime/utils/SymbolicInputStream; +import libsl/utils/SymbolicInputStream; // automata diff --git a/spec/runtime/utils/SymbolicInputStream.lsl b/spec/libsl/utils/SymbolicInputStream.lsl similarity index 78% rename from spec/runtime/utils/SymbolicInputStream.lsl rename to spec/libsl/utils/SymbolicInputStream.lsl index 0cea4c2e..2ca192d2 100644 --- a/spec/runtime/utils/SymbolicInputStream.lsl +++ b/spec/libsl/utils/SymbolicInputStream.lsl @@ -1,3 +1,4 @@ +//#! pragma: non-synthesizable libsl "1.1.0"; library std @@ -15,7 +16,7 @@ import java/io/InputStream; @GenerateMe @extends("java.io.InputStream") @public @final type SymbolicInputStream - is runtime.utils.SymbolicInputStream + is `libsl.utils.SymbolicInputStream` for InputStream { } diff --git a/spec/runtime/utils/SymbolicInputStream.main.lsl b/spec/libsl/utils/SymbolicInputStream.main.lsl similarity index 99% rename from spec/runtime/utils/SymbolicInputStream.main.lsl rename to spec/libsl/utils/SymbolicInputStream.main.lsl index 646912a0..1a341d73 100644 --- a/spec/runtime/utils/SymbolicInputStream.main.lsl +++ b/spec/libsl/utils/SymbolicInputStream.main.lsl @@ -7,7 +7,7 @@ library std // imports -import runtime/utils/SymbolicInputStream; +import libsl/utils/SymbolicInputStream; // automata diff --git a/spec/runtime/utils/VoidInputStream.lsl b/spec/libsl/utils/VoidInputStream.lsl similarity index 91% rename from spec/runtime/utils/VoidInputStream.lsl rename to spec/libsl/utils/VoidInputStream.lsl index fa46ae6a..5ab46a8e 100644 --- a/spec/runtime/utils/VoidInputStream.lsl +++ b/spec/libsl/utils/VoidInputStream.lsl @@ -16,7 +16,7 @@ import java/io/InputStream; @GenerateMe @extends("java.io.InputStream") @public @final type VoidInputStream - is java.io.InputStream$Void + is `libsl.utils.VoldInputStream` for InputStream { } diff --git a/spec/runtime/utils/VoidInputStream.main.lsl b/spec/libsl/utils/VoidInputStream.main.lsl similarity index 99% rename from spec/runtime/utils/VoidInputStream.main.lsl rename to spec/libsl/utils/VoidInputStream.main.lsl index 0e7d2a42..1ac24f28 100644 --- a/spec/runtime/utils/VoidInputStream.main.lsl +++ b/spec/libsl/utils/VoidInputStream.main.lsl @@ -7,7 +7,7 @@ library std // imports -import runtime/utils/VoidInputStream; +import libsl/utils/VoidInputStream; // automata diff --git a/spec/runtime/utils/VoidOutputStream.lsl b/spec/libsl/utils/VoidOutputStream.lsl similarity index 91% rename from spec/runtime/utils/VoidOutputStream.lsl rename to spec/libsl/utils/VoidOutputStream.lsl index dd52e7b6..093f1115 100644 --- a/spec/runtime/utils/VoidOutputStream.lsl +++ b/spec/libsl/utils/VoidOutputStream.lsl @@ -16,7 +16,7 @@ import java/io/OutputStream; @GenerateMe @extends("java.io.OutputStream") @public @final type VoidOutputStream - is java.io.OutputStream$Void + is `libsl.utils.VoidOutputStream` for OutputStream { } diff --git a/spec/runtime/utils/VoidOutputStream.main.lsl b/spec/libsl/utils/VoidOutputStream.main.lsl similarity index 98% rename from spec/runtime/utils/VoidOutputStream.main.lsl rename to spec/libsl/utils/VoidOutputStream.main.lsl index aeb2c3fd..2104bf4e 100644 --- a/spec/runtime/utils/VoidOutputStream.main.lsl +++ b/spec/libsl/utils/VoidOutputStream.main.lsl @@ -7,7 +7,7 @@ library std // imports -import runtime/utils/VoidOutputStream; +import libsl/utils/VoidOutputStream; // automata From 658b7d52924200a841b65d54024f8e8f64275a47 Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Thu, 30 Nov 2023 12:23:41 +0300 Subject: [PATCH 66/78] MInor improvements to `java.lang.StringBuffer/StringBuilder` and `java.util.ArrayList/LinkedList` --- spec/java/lang/StringBuffer.main.lsl | 36 +++++++++++-------------- spec/java/lang/StringBuilder.main.lsl | 26 +++++++++--------- spec/java/util/ArrayList.main.lsl | 38 ++++++++++++++++----------- spec/java/util/LinkedList.main.lsl | 33 ++++++++++++++++------- 4 files changed, 74 insertions(+), 59 deletions(-) diff --git a/spec/java/lang/StringBuffer.main.lsl b/spec/java/lang/StringBuffer.main.lsl index 0d7f8050..941fb923 100644 --- a/spec/java/lang/StringBuffer.main.lsl +++ b/spec/java/lang/StringBuffer.main.lsl @@ -342,7 +342,7 @@ automaton StringBufferAutomaton @synchronized fun *.append (@target self: StringBuffer, s: CharSequence, start: int, end: int): StringBuffer { var seqLength: int = 4; - var seq: String = "null"; + var seq: CharSequence = "null"; if (s != null) { seq = s; @@ -543,8 +543,8 @@ automaton StringBufferAutomaton // within java.lang.AbstractStringBuilder fun *.chars (@target self: StringBuffer): IntStream { - var intStorage: array = action ARRAY_NEW("int", this.length); - var storageChars: array = action CALL_METHOD(this.storage, "toCharArray", []); + val intStorage: array = action ARRAY_NEW("int", this.length); + val storageChars: array = action CALL_METHOD(this.storage, "toCharArray", []); var i: int = 0; action LOOP_FOR( @@ -552,12 +552,11 @@ automaton StringBufferAutomaton _toIntArray_loop(i, intStorage, storageChars) ); - val handlers: list = action LIST_NEW(); result = new IntStreamAutomaton(state = Initialized, - storage = intStorage, - length = this.length, - closeHandlers = handlers - ); + storage = intStorage, + length = this.length, + closeHandlers = action LIST_NEW() + ); } @@ -596,8 +595,8 @@ automaton StringBufferAutomaton // within java.lang.AbstractStringBuilder fun *.codePoints (@target self: StringBuffer): IntStream { - var intStorage: array = action ARRAY_NEW("int", this.length); - var storageChars: array = action CALL_METHOD(this.storage, "toCharArray", []); + val intStorage: array = action ARRAY_NEW("int", this.length); + val storageChars: array = action CALL_METHOD(this.storage, "toCharArray", []); var i: int = 0; action LOOP_FOR( @@ -605,12 +604,11 @@ automaton StringBufferAutomaton _toIntArray_loop(i, intStorage, storageChars) ); - val handlers: list = action LIST_NEW(); result = new IntStreamAutomaton(state = Initialized, - storage = intStorage, - length = this.length, - closeHandlers = handlers - ); + storage = intStorage, + length = this.length, + closeHandlers = action LIST_NEW() + ); } @@ -698,7 +696,7 @@ automaton StringBufferAutomaton { _checkOffset(dstOffset); var len: int = 4; - var new_s: String = "null"; + var new_s: CharSequence = "null"; if (s != null) { len = action CALL_METHOD(s, "length", []); @@ -714,7 +712,7 @@ automaton StringBufferAutomaton { _checkOffset(dstOffset); var len: int = 4; - var new_s: String = "null"; + var new_s: CharSequence = "null"; if (s != null) { len = action CALL_METHOD(s, "length", []); @@ -901,9 +899,7 @@ automaton StringBufferAutomaton { _checkIndex(index); - // result = action DEBUG_DO("Character.offsetByCodePoints(this.storage, index, codePointOffset)"); //current - - result = action CALL_METHOD(null as Character, "offsetByCodePoints", [this.storage, index, codePointOffset]) //need + result = action CALL_METHOD(null as Character, "offsetByCodePoints", [this.storage, index, codePointOffset]); } diff --git a/spec/java/lang/StringBuilder.main.lsl b/spec/java/lang/StringBuilder.main.lsl index 19ecf383..d2c9acce 100644 --- a/spec/java/lang/StringBuilder.main.lsl +++ b/spec/java/lang/StringBuilder.main.lsl @@ -1047,8 +1047,8 @@ automaton StringBuilderAutomaton // within java.lang.AbstractStringBuilder fun *.codePoints (@target self: StringBuilder): IntStream { - var intStorage: array = action ARRAY_NEW("int", this.length); - var storageChars: array = action CALL_METHOD(this.storage, "toCharArray", []); + val intStorage: array = action ARRAY_NEW("int", this.length); + val storageChars: array = action CALL_METHOD(this.storage, "toCharArray", []); var i: int = 0; action LOOP_FOR( @@ -1056,20 +1056,19 @@ automaton StringBuilderAutomaton _toIntArray_loop(i, intStorage, storageChars) ); - val handlers: list = action LIST_NEW(); result = new IntStreamAutomaton(state = Initialized, - storage = intStorage, - length = this.length, - closeHandlers = handlers - ); + storage = intStorage, + length = this.length, + closeHandlers = action LIST_NEW() + ); } // within java.lang.AbstractStringBuilder fun *.chars (@target self: StringBuilder): IntStream { - var intStorage: array = action ARRAY_NEW("int", this.length); - var storageChars: array = action CALL_METHOD(this.storage, "toCharArray", []); + val intStorage: array = action ARRAY_NEW("int", this.length); + val storageChars: array = action CALL_METHOD(this.storage, "toCharArray", []); var i: int = 0; action LOOP_FOR( @@ -1077,12 +1076,11 @@ automaton StringBuilderAutomaton _toIntArray_loop(i, intStorage, storageChars) ); - val handlers: list = action LIST_NEW(); result = new IntStreamAutomaton(state = Initialized, - storage = intStorage, - length = this.length, - closeHandlers = handlers - ); + storage = intStorage, + length = this.length, + closeHandlers = action LIST_NEW() + ); } diff --git a/spec/java/util/ArrayList.main.lsl b/spec/java/util/ArrayList.main.lsl index a775e8f9..86b8a067 100644 --- a/spec/java/util/ArrayList.main.lsl +++ b/spec/java/util/ArrayList.main.lsl @@ -747,25 +747,31 @@ automaton ArrayListAutomaton fun *.lastIndexOf (@target self: ArrayList, o: Object): int { - if (action LIST_SIZE(this.storage) == 0) + result = -1; + + val size: int = action LIST_SIZE(this.storage); + if (size != 0) { - result = -1; + action ASSUME(size > 0); + + val items: list = this.storage; + + var i: int = 0; + action LOOP_FOR( + i, size - 1, -1, -1, + lastIndexOf_loop(i, items, o, result) + ); } - else - { - action ASSUME(action LIST_SIZE(this.storage) > 0); + } - result = action LIST_FIND(this.storage, o, 0, action LIST_SIZE(this.storage)); - if (result != -1) - { - // there should be no elements to the right of the previously found position - val nextIndex: int = result + 1; - if (nextIndex < action LIST_SIZE(this.storage)) - { - val rightIndex: int = action LIST_FIND(this.storage, o, nextIndex, action LIST_SIZE(this.storage)); - action ASSUME(rightIndex == -1); - } - } + @Phantom proc lastIndexOf_loop (i: int, items: list, o: Object, result: int): void + { + val e: Object = action LIST_GET(items, i); + + if (action OBJECT_EQUALS(o, e)) + { + result = i; + action LOOP_BREAK(); } } diff --git a/spec/java/util/LinkedList.main.lsl b/spec/java/util/LinkedList.main.lsl index 9570f924..4b772db3 100644 --- a/spec/java/util/LinkedList.main.lsl +++ b/spec/java/util/LinkedList.main.lsl @@ -786,16 +786,31 @@ automaton LinkedListAutomaton fun *.lastIndexOf (@target self: LinkedList, o: Object): int { - result = action LIST_FIND(this.storage, o, 0, action LIST_SIZE(this.storage)); - if (result != -1) + result = -1; + + val size: int = action LIST_SIZE(this.storage); + if (size != 0) { - // there should be no elements to the right of the previously found position - val nextIndex: int = result + 1; - if (nextIndex < action LIST_SIZE(this.storage)) - { - val rightIndex: int = action LIST_FIND(this.storage, o, nextIndex, action LIST_SIZE(this.storage)); - action ASSUME(rightIndex == -1); - } + action ASSUME(size > 0); + + val items: list = this.storage; + + var i: int = 0; + action LOOP_FOR( + i, size - 1, -1, -1, + lastIndexOf_loop(i, items, o, result) + ); + } + } + + @Phantom proc lastIndexOf_loop (i: int, items: list, o: Object, result: int): void + { + val e: Object = action LIST_GET(items, i); + + if (action OBJECT_EQUALS(o, e)) + { + result = i; + action LOOP_BREAK(); } } From dc43f12119ec8b764e2bbfb591c9b4d052be46af Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Thu, 30 Nov 2023 16:18:57 +0300 Subject: [PATCH 67/78] Added missing `ArrayList`-based implementations for `java.util.LinkedList` companion objects --- spec/java/util/LinkedList.ListIterator.lsl | 243 ++++++ spec/java/util/LinkedList.Spliterator.lsl | 216 +++++ .../util/LinkedList.SubList.ListIterator.lsl | 246 ++++++ .../util/LinkedList.SubList.Spliterator.lsl | 204 +++++ spec/java/util/LinkedList.SubList.lsl | 785 ++++++++++++++++++ spec/java/util/LinkedList.lsl | 51 +- spec/java/util/LinkedList.main.lsl | 100 ++- 7 files changed, 1803 insertions(+), 42 deletions(-) create mode 100644 spec/java/util/LinkedList.ListIterator.lsl create mode 100644 spec/java/util/LinkedList.Spliterator.lsl create mode 100644 spec/java/util/LinkedList.SubList.ListIterator.lsl create mode 100644 spec/java/util/LinkedList.SubList.Spliterator.lsl create mode 100644 spec/java/util/LinkedList.SubList.lsl diff --git a/spec/java/util/LinkedList.ListIterator.lsl b/spec/java/util/LinkedList.ListIterator.lsl new file mode 100644 index 00000000..eb83e030 --- /dev/null +++ b/spec/java/util/LinkedList.ListIterator.lsl @@ -0,0 +1,243 @@ +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/util/LinkedList.java"; + +// imports + +import java/util/LinkedList; + + +// automata + +automaton LinkedList_ListIteratorAutomaton +( + var parent: LinkedList, + var cursor: int, + var expectedModCount: int +) +: LinkedList_ListIterator +{ + // states and shifts + + initstate Initialized; + + shift Initialized -> self by [ + add, + forEachRemaining, + hasNext, + hasPrevious, + next, + nextIndex, + previous, + previousIndex, + remove, + set, + ]; + + + // local variables + + var lastRet: int = -1; + + + // utilities + + @AutoInline @Phantom proc _throwCME (): void + { + action THROW_NEW("java.util.ConcurrentModificationException", []); + } + + + proc _checkForComodification (): void + { + val modCount: int = LinkedListAutomaton(this.parent).modCount; + if (modCount != this.expectedModCount) + _throwCME(); + } + + + // methods + + fun *.hasPrevious (@target self: LinkedList_ListIterator): boolean + { + result = this.cursor != 0; + } + + + fun *.nextIndex (@target self: LinkedList_ListIterator): int + { + result = this.cursor; + } + + + fun *.previousIndex (@target self: LinkedList_ListIterator): int + { + result = this.cursor - 1; + } + + + fun *.hasNext (@target self: LinkedList_ListIterator): boolean + { + // relax state/error discovery process + action ASSUME(this.parent != null); + + result = this.cursor != action LIST_SIZE(LinkedListAutomaton(this.parent).storage); + } + + + fun *.next (@target self: LinkedList_ListIterator): Object + { + // relax state/error discovery process + action ASSUME(this.parent != null); + + _checkForComodification(); + + val parentStorage: list = LinkedListAutomaton(this.parent).storage; + + val i: int = this.cursor; + if (i >= action LIST_SIZE(parentStorage)) + action THROW_NEW("java.util.NoSuchElementException", []); + + this.cursor = i + 1; + this.lastRet = i; + + result = action LIST_GET(parentStorage, i); + } + + + fun *.previous (@target self: LinkedList_ListIterator): Object + { + // relax state/error discovery process + action ASSUME(this.parent != null); + + _checkForComodification(); + + val parentStorage: list = LinkedListAutomaton(this.parent).storage; + + val i: int = this.cursor - 1; + if (i < 0) + action THROW_NEW("java.util.NoSuchElementException", []); + + // iterrator validity check + if (i >= action LIST_SIZE(parentStorage)) + _throwCME(); + + this.cursor = i; + this.lastRet = i; + + result = action LIST_GET(parentStorage, i); + } + + + fun *.remove (@target self: LinkedList_ListIterator): void + { + // relax state/error discovery process + action ASSUME(this.parent != null); + + if (this.lastRet < 0) + action THROW_NEW("java.lang.IllegalStateException", []); + + _checkForComodification(); + + val pStorage: list = LinkedListAutomaton(this.parent).storage; + if (this.lastRet >= action LIST_SIZE(pStorage)) + { + _throwCME(); + } + else + { + LinkedListAutomaton(this.parent).modCount += 1; + + action LIST_REMOVE(pStorage, this.lastRet); + } + + this.cursor = this.lastRet; + this.lastRet = -1; + this.expectedModCount = LinkedListAutomaton(this.parent).modCount; + } + + + fun *.set (@target self: LinkedList_ListIterator, e: Object): void + { + // relax state/error discovery process + action ASSUME(this.parent != null); + + if (this.lastRet < 0) + action THROW_NEW("java.lang.IllegalStateException", []); + + _checkForComodification(); + + val pStorage: list = LinkedListAutomaton(this.parent).storage; + if (this.lastRet >= action LIST_SIZE(pStorage)) + _throwCME(); + else + action LIST_SET(pStorage, this.lastRet, e); + } + + + fun *.add (@target self: LinkedList_ListIterator, e: Object): void + { + // relax state/error discovery process + action ASSUME(this.parent != null); + + _checkForComodification(); + + val i: int = this.cursor; + + val pStorage: list = LinkedListAutomaton(this.parent).storage; + if (this.lastRet > action LIST_SIZE(pStorage)) + { + _throwCME(); + } + else + { + LinkedListAutomaton(this.parent).modCount += 1; + + action LIST_INSERT_AT(pStorage, i, e); + } + + this.cursor = i + 1; + this.lastRet = -1; + this.expectedModCount = LinkedListAutomaton(this.parent).modCount; + } + + + fun *.forEachRemaining (@target self: LinkedList_ListIterator, userAction: Consumer): void + { + // relax state/error discovery process + action ASSUME(this.parent != null); + + if (userAction == null) + action THROW_NEW("java.lang.NullPointerException", []); + + var i: int = this.cursor; + val es: list = LinkedListAutomaton(this.parent).storage; + val size: int = action LIST_SIZE(es); + + if (i < size) + { + // using this exact loop form here due to coplex termination expression + action LOOP_WHILE( + i < size && LinkedListAutomaton(this.parent).modCount == this.expectedModCount, + forEachRemaining_loop(userAction, es, i) + ); + + // JDK NOTE: "update once at end to reduce heap write traffic" + this.cursor = i; + this.lastRet = i - 1; + _checkForComodification(); + } + } + + @Phantom proc forEachRemaining_loop (userAction: Consumer, es: list, i: int): void + { + val item: Object = action LIST_GET(es, i); + action CALL(userAction, [item]); + + i += 1; + } + +} diff --git a/spec/java/util/LinkedList.Spliterator.lsl b/spec/java/util/LinkedList.Spliterator.lsl new file mode 100644 index 00000000..3a82fe85 --- /dev/null +++ b/spec/java/util/LinkedList.Spliterator.lsl @@ -0,0 +1,216 @@ +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/util/LinkedList.java"; + +// imports + +import java/util/LinkedList; + + +// automata + +automaton LinkedList_SpliteratorAutomaton +( + var parent: LinkedList +) +: LinkedList_Spliterator +{ + // states and shifts + + initstate Allocated; + state Initialized; + + shift Allocated -> Initialized by [ + // constructors + LinkedList_Spliterator, + ]; + + shift Initialized -> self by [ + // instance methods + characteristics, + estimateSize, + forEachRemaining, + getComparator, + getExactSizeIfKnown, + hasCharacteristics, + tryAdvance, + trySplit, + ]; + + // internal variables + + var index: int = 0; + var fence: int = -1; + var expectedModCount: int = 0; + + + // utilities + + @AutoInline @Phantom proc _throwNPE (): void + { + action THROW_NEW("java.lang.NullPointerException", []); + } + + + @AutoInline @Phantom proc _throwCME (): void + { + action THROW_NEW("java.util.ConcurrentModificationException", []); + } + + + proc _getFence (): int + { + // JDK comment: initialize fence to size on first use + if (this.fence == -1) + { + action ASSUME(this.parent != null); + this.expectedModCount = LinkedListAutomaton(this.parent).modCount; + this.fence = action LIST_SIZE(LinkedListAutomaton(this.parent).storage); + } + + result = this.fence; + } + + + // constructors + + @private constructor *.LinkedList_Spliterator ( + @target self: LinkedList_Spliterator, + _this: LinkedList, + origin: int, fence: int, expectedModCount: int) + { + // #problem: translator cannot generate and refer to private and/or inner classes, so this is effectively useless + action NOT_IMPLEMENTED("inaccessible constructor"); + } + + + // static methods + + // methods + + fun *.characteristics (@target self: LinkedList_Spliterator): int + { + result = SPLITERATOR_ORDERED | SPLITERATOR_SIZED | SPLITERATOR_SUBSIZED; + } + + + fun *.estimateSize (@target self: LinkedList_Spliterator): long + { + result = _getFence() - this.index; + } + + + fun *.forEachRemaining (@target self: LinkedList_Spliterator, _action: Consumer): void + { + if (_action == null) + _throwNPE(); + + action ASSUME(this.parent != null); + val a: list = LinkedListAutomaton(this.parent).storage; + if (a == null) + _throwCME(); + + var hi: int = this.fence; + var mc: int = this.expectedModCount; + if (hi == -1) + { + hi = action LIST_SIZE(a); + mc = LinkedListAutomaton(this.parent).modCount; + } + + var i: int = this.index; + this.index = hi; + if (i < 0 || hi > action LIST_SIZE(a)) + _throwCME(); + + action LOOP_FOR( + i, i, hi, +1, + forEachRemaining_loop(i, a, _action) + ); + + if (mc != LinkedListAutomaton(this.parent).modCount) + _throwCME(); + } + + @Phantom proc forEachRemaining_loop (i: int, a: list, _action: Consumer): void + { + val item: Object = action LIST_GET(a, i); + action CALL(_action, [item]); + } + + + // within java.util.Spliterator + @Phantom fun *.getComparator (@target self: LinkedList_Spliterator): Comparator + { + // NOTE: using the original method + } + + + // within java.util.Spliterator + fun *.getExactSizeIfKnown (@target self: LinkedList_Spliterator): long + { + result = _getFence() - this.index; + } + + + // within java.util.Spliterator + @Phantom fun *.hasCharacteristics (@target self: LinkedList_Spliterator, characteristics: int): boolean + { + // NOTE: using the original method + } + + + fun *.tryAdvance (@target self: LinkedList_Spliterator, _action: Consumer): boolean + { + if (_action == null) + _throwNPE(); + + val hi: int = _getFence(); + val i: int = this.index; + + if (i < hi) + { + action ASSUME(this.parent != null); + + this.index = i + 1; + + val parentStorage: list = LinkedListAutomaton(this.parent).storage; + val item: Object = action LIST_GET(parentStorage, i); + action CALL(_action, [item]); + + if (LinkedListAutomaton(this.parent).modCount != this.expectedModCount) + _throwCME(); + + result = true; + } + else + { + result = false; + } + } + + + fun *.trySplit (@target self: LinkedList_Spliterator): Spliterator + { + val hi: int = _getFence(); + val lo: int = this.index; + val mid: int = (lo + hi) >>> 1; + + // JDK comment: divide range in half unless too small + if (lo >= mid) + result = null; + else + result = new LinkedList_SpliteratorAutomaton(state = Initialized, + parent = this.parent, + index = lo, + fence = mid, + expectedModCount = this.expectedModCount, + ); + + this.index = mid; + } + +} diff --git a/spec/java/util/LinkedList.SubList.ListIterator.lsl b/spec/java/util/LinkedList.SubList.ListIterator.lsl new file mode 100644 index 00000000..3a70d9d0 --- /dev/null +++ b/spec/java/util/LinkedList.SubList.ListIterator.lsl @@ -0,0 +1,246 @@ +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/util/LinkedList.java"; + +// imports + +import java/util/LinkedList; + + +// automata + +automaton LinkedList_SubList_ListIteratorAutomaton +( + var root: LinkedList, + var sublist: LinkedList_SubList, + var cursor: int, + var expectedModCount: int, + var offset: int, + var size: int, +) +: LinkedList_SubList_ListIterator +{ + // states and shifts + + initstate Initialized; + + shift Initialized -> self by [ + add, + forEachRemaining, + hasNext, + hasPrevious, + next, + nextIndex, + previous, + previousIndex, + remove, + set, + ]; + + + // local variables + + var lastRet: int = -1; + + + // utilities + + @AutoInline @Phantom proc _throwCME (): void + { + action THROW_NEW("java.util.ConcurrentModificationException", []); + } + + + proc _checkForComodification (): void + { + val modCount: int = LinkedListAutomaton(this.root).modCount; + if (modCount != this.expectedModCount) + _throwCME(); + } + + + // methods + + fun *.hasPrevious (@target self: LinkedList_SubList_ListIterator): boolean + { + result = this.cursor != 0; + } + + + fun *.nextIndex (@target self: LinkedList_SubList_ListIterator): int + { + result = this.cursor; + } + + + fun *.previousIndex (@target self: LinkedList_SubList_ListIterator): int + { + result = this.cursor - 1; + } + + + fun *.hasNext (@target self: LinkedList_SubList_ListIterator): boolean + { + result = this.cursor != this.size; + } + + + fun *.next (@target self: LinkedList_SubList_ListIterator): Object + { + // relax state/error discovery process + action ASSUME(this.root != null); + + _checkForComodification(); + + val rootStorage: list = LinkedListAutomaton(this.root).storage; + val i: int = this.offset + this.cursor; + // iterrator validity check + if (i >= action LIST_SIZE(rootStorage)) + action THROW_NEW("java.util.NoSuchElementException", []); + + this.lastRet = this.cursor; + this.cursor += 1; + + result = action LIST_GET(rootStorage, i); + } + + + fun *.previous (@target self: LinkedList_SubList_ListIterator): Object + { + // relax state/error discovery process + action ASSUME(this.root != null); + + _checkForComodification(); + + val i: int = this.offset + this.cursor - 1; + if (i < this.offset) + action THROW_NEW("java.util.NoSuchElementException", []); + + // iterrator validity check + val rootStorage: list = LinkedListAutomaton(this.root).storage; + if (i >= action LIST_SIZE(rootStorage)) + _throwCME(); + + this.cursor -= 1; + this.lastRet = this.cursor; + + result = action LIST_GET(rootStorage, i); + } + + + fun *.remove (@target self: LinkedList_SubList_ListIterator): void + { + // relax state/error discovery process + action ASSUME(this.root != null); + + if (this.lastRet < 0) + action THROW_NEW("java.lang.IllegalStateException", []); + + _checkForComodification(); + + if (this.lastRet >= this.size) + { + _throwCME(); + } + else + { + LinkedListAutomaton(this.root)._unlinkAny(this.offset + this.lastRet); + + LinkedList_SubListAutomaton(this.sublist)._updateSizeAndModCount(-1); + this.expectedModCount = LinkedListAutomaton(this.root).modCount; + this.size -= 1; + } + + this.cursor = this.lastRet; + this.lastRet = -1; + } + + + fun *.set (@target self: LinkedList_SubList_ListIterator, e: Object): void + { + // relax state/error discovery process + action ASSUME(this.root != null); + + if (this.lastRet < 0) + action THROW_NEW("java.lang.IllegalStateException", []); + + _checkForComodification(); + + val rootStorage: list = LinkedListAutomaton(this.root).storage; + + val index: int = this.offset + this.lastRet; + if (index >= action LIST_SIZE(rootStorage)) + _throwCME(); + else + action LIST_SET(rootStorage, index, e); + } + + + fun *.add (@target self: LinkedList_SubList_ListIterator, e: Object): void + { + // relax state/error discovery process + action ASSUME(this.root != null); + + _checkForComodification(); + + val i: int = this.offset + this.cursor; + + if (this.offset + this.lastRet > action LIST_SIZE(LinkedListAutomaton(this.root).storage)) + { + _throwCME(); + } + else + { + LinkedListAutomaton(this.root)._linkAny(i, e); + + LinkedList_SubListAutomaton(this.sublist)._updateSizeAndModCount(+1); + this.expectedModCount = LinkedListAutomaton(this.root).modCount; + this.size += 1; + } + + this.cursor += 1; + this.lastRet = -1; + } + + + fun *.forEachRemaining (@target self: LinkedList_SubList_ListIterator, userAction: Consumer): void + { + // relax state/error discovery process + action ASSUME(this.root != null); + + if (userAction == null) + action THROW_NEW("java.lang.NullPointerException", []); + + var i: int = this.cursor; + if (i < this.size) + { + i += this.offset; + val es: list = LinkedListAutomaton(this.root).storage; + + if (i >= action LIST_SIZE(es)) + _throwCME(); + + val end: int = this.offset + this.size; + + action LOOP_FOR( + i, i, end, +1, + forEachRemaining_loop(userAction, es, i) + ); + + // JDK NOTE: "update once at end to reduce heap write traffic" + this.cursor = i - this.offset; + this.lastRet = this.cursor - 1; + _checkForComodification(); + } + } + + @Phantom proc forEachRemaining_loop (userAction: Consumer, es: list, i: int): void + { + val item: Object = action LIST_GET(es, i); + action CALL(userAction, [item]); + } + +} diff --git a/spec/java/util/LinkedList.SubList.Spliterator.lsl b/spec/java/util/LinkedList.SubList.Spliterator.lsl new file mode 100644 index 00000000..1065da67 --- /dev/null +++ b/spec/java/util/LinkedList.SubList.Spliterator.lsl @@ -0,0 +1,204 @@ +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/util/LinkedList.java"; + +// imports + +import java/util/LinkedList; + + +// automata + +automaton LinkedList_SubList_SpliteratorAutomaton +( + var root: LinkedList, + var parent: LinkedList_SubList, +) +: LinkedList_SubList_Spliterator +{ + // states and shifts + + initstate Initialized; + + shift Initialized -> self by [ + // instance methods + characteristics, + estimateSize, + forEachRemaining, + getComparator, + getExactSizeIfKnown, + hasCharacteristics, + tryAdvance, + trySplit, + ]; + + // internal variables + + var index: int = 0; + var fence: int = -1; + var expectedModCount: int = 0; + + + // utilities + + @AutoInline @Phantom proc _throwNPE (): void + { + action THROW_NEW("java.lang.NullPointerException", []); + } + + + @AutoInline @Phantom proc _throwCME (): void + { + action THROW_NEW("java.util.ConcurrentModificationException", []); + } + + + proc _getFence (): int + { + // JDK comment: initialize fence to size on first use + if (this.fence == -1) + { + action ASSUME(this.parent != null); + this.expectedModCount = LinkedList_SubListAutomaton(this.parent).modCount; + this.fence = LinkedList_SubListAutomaton(this.parent).length; + } + + result = this.fence; + } + + + // constructors + + // static methods + + // methods + + fun *.characteristics (@target self: LinkedList_SubList_Spliterator): int + { + result = SPLITERATOR_ORDERED | SPLITERATOR_SIZED | SPLITERATOR_SUBSIZED; + } + + + fun *.estimateSize (@target self: LinkedList_SubList_Spliterator): long + { + result = _getFence() - this.index; + } + + + fun *.forEachRemaining (@target self: LinkedList_SubList_Spliterator, _action: Consumer): void + { + if (_action == null) + _throwNPE(); + + action ASSUME(this.root != null); + action ASSUME(this.parent != null); + + val a: list = LinkedListAutomaton(this.root).storage; + if (a == null) + _throwCME(); + + var hi: int = this.fence; + var mc: int = this.expectedModCount; + if (hi == -1) + { + hi = LinkedList_SubListAutomaton(this.parent).length; + mc = LinkedList_SubListAutomaton(this.parent).modCount; + } + + var i: int = this.index; + this.index = hi; + if (i < 0 || hi > LinkedList_SubListAutomaton(this.parent).length) + _throwCME(); + + action LOOP_FOR( + i, i, hi, +1, + forEachRemaining_loop(i, a, _action) + ); + + if (mc != LinkedList_SubListAutomaton(this.parent).modCount) + _throwCME(); + } + + @Phantom proc forEachRemaining_loop (i: int, a: list, _action: Consumer): void + { + val item: Object = action LIST_GET(a, i); + action CALL(_action, [item]); + } + + + // within java.util.Spliterator + @Phantom fun *.getComparator (@target self: LinkedList_SubList_Spliterator): Comparator + { + // NOTE: using the original method + } + + + // within java.util.Spliterator + fun *.getExactSizeIfKnown (@target self: LinkedList_SubList_Spliterator): long + { + result = _getFence() - this.index; + } + + + // within java.util.Spliterator + @Phantom fun *.hasCharacteristics (@target self: LinkedList_SubList_Spliterator, characteristics: int): boolean + { + // NOTE: using the original method + } + + + fun *.tryAdvance (@target self: LinkedList_SubList_Spliterator, _action: Consumer): boolean + { + if (_action == null) + _throwNPE(); + + val hi: int = _getFence(); + val i: int = this.index; + + if (i < hi) + { + action ASSUME(this.root != null); + + this.index = i + 1; + + val rootStorage: list = LinkedListAutomaton(this.root).storage; + val item: Object = action LIST_GET(rootStorage, i); + action CALL(_action, [item]); + + if (LinkedListAutomaton(this.root).modCount != this.expectedModCount) + _throwCME(); + + result = true; + } + else + { + result = false; + } + } + + + fun *.trySplit (@target self: LinkedList_SubList_Spliterator): Spliterator + { + val hi: int = _getFence(); + val lo: int = this.index; + val mid: int = (lo + hi) >>> 1; + + // JDK comment: divide range in half unless too small + if (lo >= mid) + result = null; + else + result = new LinkedList_SubList_SpliteratorAutomaton(state = Initialized, + root = this.root, + parent = this.parent, + index = lo, + fence = mid, + expectedModCount = this.expectedModCount, + ); + + this.index = mid; + } + +} diff --git a/spec/java/util/LinkedList.SubList.lsl b/spec/java/util/LinkedList.SubList.lsl new file mode 100644 index 00000000..b68f881c --- /dev/null +++ b/spec/java/util/LinkedList.SubList.lsl @@ -0,0 +1,785 @@ +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/util/LinkedList.java"; + +// imports + +import java/util/LinkedList; + + +// automata + +automaton LinkedList_SubListAutomaton +( + var root: LinkedList, + var parentList: LinkedList_SubList, + var offset: int, + var length: int, + var modCount: int, +) +: LinkedList_SubList +{ + // states and shifts + + initstate Allocated; + state Initialized; + + shift Allocated -> Initialized by [ + // constructors + SubList (LinkedList_SubList, LinkedList, int, int), + SubList (LinkedList_SubList, LinkedList_SubList, int, int), + ]; + + shift Initialized -> self by [ + // instance methods + add (LinkedList_SubList, Object), + add (LinkedList_SubList, int, Object), + addAll (LinkedList_SubList, Collection), + addAll (LinkedList_SubList, int, Collection), + clear, + contains, + containsAll, + equals, + forEach, + get, + hashCode, + indexOf, + isEmpty, + iterator, + lastIndexOf, + listIterator (LinkedList_SubList), + listIterator (LinkedList_SubList, int), + parallelStream, + remove (LinkedList_SubList, Object), + remove (LinkedList_SubList, int), + removeAll, + removeIf, + replaceAll, + retainAll, + set, + size, + sort, + spliterator, + stream, + subList, + toArray (LinkedList_SubList), + toArray (LinkedList_SubList, IntFunction), + toArray (LinkedList_SubList, array), + toString, + ]; + + // internal variables + + // utilities + + @AutoInline @Phantom proc _throwNPE (): void + { + action THROW_NEW("java.lang.NullPointerException", []); + } + + + @AutoInline @Phantom proc _checkForComodification(): void + { + LinkedListAutomaton(this.root)._checkForComodification(this.modCount); + } + + + proc _addAllElements (index: int, c: Collection): boolean + { + action ASSUME(this.root != null); + + val effectiveIndex: int = this.offset + index; + LinkedListAutomaton(this.root)._checkPositionIndex(effectiveIndex); + + val collectionSize: int = action CALL_METHOD(c, "size", []); + if (collectionSize == 0) + { + result = false; + } + else + { + result = true; + + _checkForComodification(); + LinkedListAutomaton(this.root)._addAllElements(effectiveIndex, c); + _updateSizeAndModCount(collectionSize); + } + } + + + @KeepVisible proc _updateSizeAndModCount (sizeChange: int): void + { + action ASSUME(this.root != null); + + // update self first + this.length += sizeChange; + this.modCount = LinkedListAutomaton(this.root).modCount; + + // then propagate changes up the chain + var aList: LinkedList_SubList = this.parentList; + action LOOP_WHILE( + aList != null, + _updateSizeAndModCount_loop(aList, sizeChange) + ); + } + + @Phantom proc _updateSizeAndModCount_loop (aList: LinkedList_SubList, sizeChange: int): void + { + LinkedList_SubListAutomaton(aList).length += sizeChange; + LinkedList_SubListAutomaton(aList).modCount = this.modCount; + + aList = LinkedList_SubListAutomaton(aList).parentList; + } + + + proc _indexOfElement (o: Object): int + { + action ASSUME(this.root != null); + + _checkForComodification(); + val parentStorage: list = LinkedListAutomaton(this.root).storage; + + val index: int = action LIST_FIND(parentStorage, o, this.offset, this.offset + this.length); + if (index != -1) + result = index - this.offset; + else + result = -1; + } + + + proc _makeStream (parallel: boolean): Stream + { + // #todo: use custom stream implementation + result = action SYMBOLIC("java.util.stream.Stream"); + action ASSUME(result != null); + action ASSUME(action CALL_METHOD(result, "isParallel", []) == parallel); + } + + + proc _batchRemove (c: Collection, complement: boolean): boolean + { + action ASSUME(this.root != null); + _checkForComodification(); + + if (this.length != 0) + { + val oldRootLength: int = action LIST_SIZE(LinkedListAutomaton(this.root).storage); + + result = LinkedListAutomaton(this.root)._batchRemove(c, complement, this.offset, this.offset + this.length); + if (result) + { + val newRootLength: int = action LIST_SIZE(LinkedListAutomaton(this.root).storage); + _updateSizeAndModCount(newRootLength - oldRootLength); + } + } + else + { + result = false; + } + } + + + // constructors + + constructor *.SubList (@target self: LinkedList_SubList, root: LinkedList, fromIndex: int, toIndex: int) + { + // #problem: this constructor is useless + action NOT_IMPLEMENTED("inaccessible constructor"); + } + + + @private constructor *.SubList (@target self: LinkedList_SubList, parent: LinkedList_SubList, fromIndex: int, toIndex: int) + { + // #problem: this constructor is useless + action NOT_IMPLEMENTED("inaccessible constructor"); + } + + + // static methods + + // methods + + // within java.util.AbstractList + fun *.add (@target self: LinkedList_SubList, e: Object): boolean + { + action ASSUME(this.root != null); + + _checkForComodification(); + + val effectiveIndex: int = this.offset + this.length; + LinkedListAutomaton(this.root)._linkAny(effectiveIndex, e); + + _updateSizeAndModCount(+1); + } + + + fun *.add (@target self: LinkedList_SubList, index: int, element: Object): void + { + action ASSUME(this.root != null); + + _checkForComodification(); + + val effectiveIndex: int = this.offset + index; + LinkedListAutomaton(this.root)._linkAny(effectiveIndex, element); + + _updateSizeAndModCount(+1); + } + + + fun *.addAll (@target self: LinkedList_SubList, c: Collection): boolean + { + _addAllElements(this.length, c); + } + + + fun *.addAll (@target self: LinkedList_SubList, index: int, c: Collection): boolean + { + _addAllElements(index, c); + } + + + // within java.util.AbstractList + fun *.clear (@target self: LinkedList_SubList): void + { + action ASSUME(this.root != null); + _checkForComodification(); + + val size: int = this.length; + if (size != 0) + { + action ASSUME(size > 0); + val end: int = this.offset - 1; + val start: int = end + size; + + val rootStorage: list = LinkedListAutomaton(this.root).storage; + + var i: int = 0; + action LOOP_FOR( + i, start, end, -1, + clear_loop(i, rootStorage) + ); + + LinkedListAutomaton(this.root).modCount += 1; + + _updateSizeAndModCount(-size); + } + } + + @Phantom proc clear_loop (i: int, rootStorage: list): void + { + action LIST_REMOVE(rootStorage, i); + } + + + fun *.contains (@target self: LinkedList_SubList, o: Object): boolean + { + result = _indexOfElement(o) != -1; + } + + + // within java.util.AbstractCollection + fun *.containsAll (@target self: LinkedList_SubList, c: Collection): boolean + { + result = true; + + if (!action CALL_METHOD(c, "isEmpty", [])) + { + action ASSUME(this.root != null); + + val rootStorage: list = LinkedListAutomaton(this.root).storage; + val end: int = this.offset + this.length; + + if (c has LinkedList_SubListAutomaton) + { + val otherRoot: LinkedList = LinkedList_SubListAutomaton(c).root; + action ASSUME(otherRoot != null); + + val otherStorage: list = LinkedListAutomaton(otherRoot).storage; + val otherOffset: int = LinkedList_SubListAutomaton(c).offset; + val otherEnd: int = otherOffset + LinkedList_SubListAutomaton(c).length; + + action ASSUME(otherStorage != null); + action ASSUME(otherOffset >= 0); + action ASSUME(otherEnd >= 0); + + var i: int = otherOffset; + action LOOP_WHILE( + result && i < otherEnd, + containsAll_loop_optimized(rootStorage, end, otherStorage, i, result) + ); + } + else + { + val iter: Iterator = action CALL_METHOD(c, "iterator", []); + action LOOP_WHILE( + result && action CALL_METHOD(iter, "hasNext", []), + containsAll_loop_regular(rootStorage, end, iter, result) + ); + } + } + } + + @Phantom proc containsAll_loop_optimized (rootStorage: list, end: int, otherStorage: list, i: int, result: boolean): void + { + val item: Object = action LIST_GET(otherStorage, i); + result = action LIST_FIND(rootStorage, item, this.offset, end) != -1; + + i += 1; + } + + @Phantom proc containsAll_loop_regular (rootStorage: list, end: int, iter: Iterator, result: boolean): void + { + val item: Object = action CALL_METHOD(iter, "next", []); + result = action LIST_FIND(rootStorage, item, this.offset, end) != -1; + } + + + fun *.equals (@target self: LinkedList_SubList, o: Object): boolean + { + if (o == self) + { + result = true; + } + else + { + result = o has LinkedList_SubListAutomaton; + if (result) + { + action ASSUME(this.root != null); + + val otherLength: int = LinkedList_SubListAutomaton(o).length; + action ASSUME(otherLength >= 0); + + result = this.length == otherLength; + if (result) + { + result = LinkedListAutomaton(this.root)._equalsRange(o as List, this.offset, this.offset + this.length); + _checkForComodification(); + } + } + } + } + + + // within java.lang.Iterable + fun *.forEach (@target self: LinkedList_SubList, _action: Consumer): void + { + if (this.length != 0) + { + action ASSUME(this.length > 0); + action ASSUME(this.root != null); + + val rootStorage: list = LinkedListAutomaton(this.root).storage; + val expectedModCount: int = LinkedListAutomaton(this.root).modCount; + + this.modCount = expectedModCount; + + var i: int = this.offset; + val end: int = this.offset + this.length; + action LOOP_WHILE( + i < end && LinkedListAutomaton(this.root).modCount == expectedModCount, + forEach_loop(i, rootStorage, _action) + ); + + LinkedListAutomaton(this.root)._checkForComodification(expectedModCount); + } + } + + @Phantom proc forEach_loop (i: int, rootStorage: list, _action: Consumer): void + { + val item: Object = action LIST_GET(rootStorage, i); + action CALL(_action, [item]); + + i += 1; + } + + + fun *.get (@target self: LinkedList_SubList, index: int): Object + { + action ASSUME(this.root != null); + + LinkedListAutomaton(this.root)._checkElementIndex(index, this.length); + _checkForComodification(); + + val effectiveIndex: int = this.offset + index; + result = action LIST_GET(LinkedListAutomaton(this.root).storage, effectiveIndex); + } + + + fun *.hashCode (@target self: LinkedList_SubList): int + { + result = 1; + + if (this.length != 0) + { + action ASSUME(this.length > 0); + action ASSUME(this.root != null); + val rootStorage: list = LinkedListAutomaton(this.root).storage; + + var i: int = this.offset; + val end: int = this.offset + this.length; + action LOOP_FOR( + i, i, end, +1, + hashCode_loop(i, rootStorage, result) + ); + + _checkForComodification(); + } + } + + @Phantom proc hashCode_loop (i: int, rootStorage: list, result: int): void + { + val item: Object = action LIST_GET(rootStorage, i); + result = 31 * result + action OBJECT_HASH_CODE(item); + } + + + fun *.indexOf (@target self: LinkedList_SubList, o: Object): int + { + result = _indexOfElement(o); + } + + + // within java.util.AbstractCollection + fun *.isEmpty (@target self: LinkedList_SubList): boolean + { + result = this.length == 0; + } + + + fun *.iterator (@target self: LinkedList_SubList): Iterator + { + result = new LinkedList_SubList_ListIteratorAutomaton(state = Initialized, + root = this.root, + sublist = self, + cursor = 0, + expectedModCount = this.modCount, + offset = this.offset, + size = this.length, + ); + } + + + fun *.lastIndexOf (@target self: LinkedList_SubList, o: Object): int + { + action ASSUME(this.root != null); + _checkForComodification(); + + if (this.length == 0) + { + result = -1; + } + else + { + action ASSUME(this.length > 0); + + val end: int = this.offset + this.length; + val rootStorage: list = LinkedListAutomaton(this.root).storage; + + result = action LIST_FIND(rootStorage, o, this.offset, end); + if (result != -1) + { + // there should be no elements to the right of the previously found position + val nextIndex: int = result + 1; + if (nextIndex < end) + { + val rightIndex: int = action LIST_FIND(rootStorage, o, nextIndex, end); + action ASSUME(rightIndex == -1); + } + + result -= this.offset; + } + } + } + + + // within java.util.AbstractList + fun *.listIterator (@target self: LinkedList_SubList): ListIterator + { + result = new LinkedList_SubList_ListIteratorAutomaton(state = Initialized, + root = this.root, + sublist = self, + cursor = 0, + expectedModCount = this.modCount, + offset = this.offset, + size = this.length, + ); + } + + + fun *.listIterator (@target self: LinkedList_SubList, index: int): ListIterator + { + result = new LinkedList_SubList_ListIteratorAutomaton(state = Initialized, + root = this.root, + sublist = self, + cursor = index, + expectedModCount = this.modCount, + offset = this.offset, + size = this.length, + ); + } + + + // within java.util.Collection + fun *.parallelStream (@target self: LinkedList_SubList): Stream + { + result = _makeStream(/* parallel = */true); + } + + + // within java.util.AbstractCollection + fun *.remove (@target self: LinkedList_SubList, o: Object): boolean + { + action ASSUME(this.root != null); + + val end: int = this.offset + this.length; + val rootStorage: list = LinkedListAutomaton(this.root).storage; + + val index: int = action LIST_FIND(rootStorage, o, this.offset, end); + result = index != -1; + + if (result) + { + _checkForComodification(); + LinkedListAutomaton(this.root)._unlinkAny(index); + + _updateSizeAndModCount(-1); + } + } + + + fun *.remove (@target self: LinkedList_SubList, index: int): Object + { + action ASSUME(this.root != null); + + LinkedListAutomaton(this.root)._checkElementIndex(index, this.length); + _checkForComodification(); + + val effectiveIndex: int = this.offset + index; + result = LinkedListAutomaton(this.root)._unlinkAny(effectiveIndex); + + _updateSizeAndModCount(-1); + } + + + fun *.removeAll (@target self: LinkedList_SubList, c: Collection): boolean + { + _batchRemove(c, false); + } + + + fun *.removeIf (@target self: LinkedList_SubList, filter: Predicate): boolean + { + action ASSUME(this.root != null); + _checkForComodification(); + + val size: int = this.length; + if (size != 0) + { + val oldRootLength: int = action LIST_SIZE(LinkedListAutomaton(this.root).storage); + + result = LinkedListAutomaton(this.root)._removeIf(filter, this.offset, this.offset + this.length); + if (result) + { + val newRootLength: int = action LIST_SIZE(LinkedListAutomaton(this.root).storage); + _updateSizeAndModCount(newRootLength - oldRootLength); + } + } + else + { + result = false; + } + } + + + fun *.replaceAll (@target self: LinkedList_SubList, operator: UnaryOperator): void + { + action ASSUME(this.root != null); + LinkedListAutomaton(this.root)._replaceAllRange(operator, this.offset, this.offset + this.length); + } + + + fun *.retainAll (@target self: LinkedList_SubList, c: Collection): boolean + { + _batchRemove(c, true); + } + + + fun *.set (@target self: LinkedList_SubList, index: int, element: Object): Object + { + action ASSUME(this.root != null); + + LinkedListAutomaton(this.root)._checkElementIndex(index, this.length); + _checkForComodification(); + + val parentStorage: list = LinkedListAutomaton(this.root).storage; + val effectiveIndex: int = this.offset + index; + result = action LIST_GET(parentStorage, effectiveIndex); + action LIST_SET(parentStorage, effectiveIndex, element); + } + + + fun *.size (@target self: LinkedList_SubList): int + { + action ASSUME(this.root != null); + + _checkForComodification(); + result = this.length; + } + + + // within java.util.List + fun *.sort (@target self: LinkedList_SubList, c: Comparator): void + { + action ASSUME(this.root != null); + LinkedListAutomaton(this.root)._do_sort(this.offset, this.offset + this.length, c); + this.modCount = LinkedListAutomaton(this.root).modCount; + } + + + fun *.spliterator (@target self: LinkedList_SubList): Spliterator + { + result = new LinkedList_SubList_SpliteratorAutomaton(state = Initialized, + root = this.root, + parent = self, + ); + } + + + // within java.util.Collection + fun *.stream (@target self: LinkedList_SubList): Stream + { + result = _makeStream(/* parallel = */false); + } + + + fun *.subList (@target self: LinkedList_SubList, fromIndex: int, toIndex: int): List + { + action ASSUME(this.root != null); + + LinkedListAutomaton(this.root)._subListRangeCheck(fromIndex, toIndex, this.length); + + result = new LinkedList_SubListAutomaton(state = Initialized, + root = this.root, + parentList = self, + offset = this.offset + fromIndex, + length = toIndex - fromIndex, + modCount = this.modCount, + ); + } + + + fun *.toArray (@target self: LinkedList_SubList): array + { + action ASSUME(this.root != null); + _checkForComodification(); + + result = action ARRAY_NEW("java.lang.Object", this.length); + + val rootStorage: list = LinkedListAutomaton(this.root).storage; + val end: int = this.offset + this.length; + var i: int = 0; + var j: int = 0; + action LOOP_FOR( + i, this.offset, end, +1, + toArray_loop(i, j, result, rootStorage) + ); + } + + @Phantom proc toArray_loop (i: int, j: int, result: array, rootStorage: list): void + { + result[j] = action LIST_GET(rootStorage, i); + j += 1; + } + + + // within java.util.Collection + fun *.toArray (@target self: LinkedList_SubList, generator: IntFunction): array + { + // acting just like JDK + val a: array = action CALL(generator, [0]) as array; + val aSize: int = action ARRAY_SIZE(a); + + action ASSUME(this.root != null); + _checkForComodification(); + + result = action ARRAY_NEW("java.lang.Object", this.length); + + val rootStorage: list = LinkedListAutomaton(this.root).storage; + val end: int = this.offset + this.length; + var i: int = 0; + var j: int = 0; + action LOOP_FOR( + i, this.offset, end, +1, + toArray_loop(i, j, result, rootStorage) + ); + } + + + fun *.toArray (@target self: LinkedList_SubList, a: array): array + { + action ASSUME(this.root != null); + _checkForComodification(); + + val aSize: int = action ARRAY_SIZE(a); + if (aSize < this.length) + // #problem: a.getClass() should be called to construct a type-valid array (USVM issue) + a = action ARRAY_NEW("java.lang.Object", this.length); + + result = a; + + val rootStorage: list = LinkedListAutomaton(this.root).storage; + val end: int = this.offset + this.length; + var i: int = 0; + var j: int = 0; + action LOOP_FOR( + i, this.offset, end, +1, + toArray_loop(i, j, result, rootStorage) + ); + + if (aSize > this.length) + result[aSize] = null; + } + + + // within java.util.AbstractCollection + fun *.toString (@target self: LinkedList_SubList): String + { + if (this.length == 0) + { + result = "[]"; + } + else + { + result = "["; + + action ASSUME(this.root != null); + + val rootStorage: list = LinkedListAutomaton(this.root).storage; + + var i: int = this.offset; + val end: int = this.offset + this.length; + var counter: int = this.length; + action LOOP_FOR( + i, i, end, +1, + toString_loop(i, rootStorage, result, counter) + ); + + result += "]"; + } + } + + @Phantom proc toString_loop (i: int, rootStorage: list, result: String, counter: int): void + { + val item: Object = action LIST_GET(rootStorage, i); + result += action OBJECT_TO_STRING(item); + + counter -= 1; + if (counter != 0) + result += ", "; + } + +} diff --git a/spec/java/util/LinkedList.lsl b/spec/java/util/LinkedList.lsl index 0e981a07..a8392315 100644 --- a/spec/java/util/LinkedList.lsl +++ b/spec/java/util/LinkedList.lsl @@ -15,7 +15,7 @@ import java/util/Deque; import java/util/List; -// local semantic types +// primary types @extends("java.util.AbstractSequentialList") @implements("java.util.List") @@ -29,3 +29,52 @@ import java/util/List; @private @static val serialVersionUID: long = 876323262645176354L; } + +// new/introduced types + +@GenerateMe +@implements("java.util.ListIterator") +@public @final type LinkedList_ListIterator + is java.util.LinkedList_ListItr // NOTE: do not use inner classes + for ListIterator +{ +} + + +@GenerateMe +@implements("java.util.Spliterator") +@public @final type LinkedList_Spliterator + is java.util.LinkedList_Spliterator // NOTE: do not use inner classes + for Spliterator +{ +} + + +@GenerateMe +@extends("java.util.AbstractList") +@implements("java.util.List") +@implements("java.util.RandomAccess") +@public @final type LinkedList_SubList + is java.util.LinkedList_SubList // NOTE: do not use inner classes + for List +{ +} + + +@GenerateMe +@implements("java.util.Spliterator") +@public @final type LinkedList_SubList_Spliterator + // NOTE: using a '$' sign here to hint on a potential solution to inability to overwrite private constructors + is java.util.LinkedList_SubList$Spliterator + for Spliterator +{ +} + + +@GenerateMe +@implements("java.util.ListIterator") +@public @final type LinkedList_SubList_ListIterator + is java.util.LinkedList_SubList$ListIterator // NOTE: do not use inner classes + for ListIterator +{ +} diff --git a/spec/java/util/LinkedList.main.lsl b/spec/java/util/LinkedList.main.lsl index 4b772db3..84fb833f 100644 --- a/spec/java/util/LinkedList.main.lsl +++ b/spec/java/util/LinkedList.main.lsl @@ -112,7 +112,32 @@ automaton LinkedListAutomaton } - proc _unlinkAny (index: int): Object + // checks range [from, to) against [0, size) + @KeepVisible proc _subListRangeCheck (fromIndex: int, toIndex: int, size: int): void + { + if (fromIndex < 0) + { + //val message1: String = "fromIndex = " + action OBJECT_TO_STRING(fromIndex); + action THROW_NEW("java.lang.IndexOutOfBoundsException", []); + } + + if (toIndex > size) + { + //val message2: String = "toIndex = " + action OBJECT_TO_STRING(toIndex); + action THROW_NEW("java.lang.IndexOutOfBoundsException", []); + } + + if (fromIndex > toIndex) + { + //val from: String = action OBJECT_TO_STRING(fromIndex); + //val to: String = action OBJECT_TO_STRING(toIndex); + //val message3: String = "fromIndex(" + from + ") > toIndex(" + to + ")"; + action THROW_NEW("java.lang.IllegalArgumentException", []); + } + } + + + @KeepVisible proc _unlinkAny (index: int): Object { result = action LIST_GET(this.storage, index); action LIST_REMOVE(this.storage, index); @@ -120,26 +145,26 @@ automaton LinkedListAutomaton } - proc _linkAny (index: int, e: Object): void + @KeepVisible proc _linkAny (index: int, e: Object): void { action LIST_INSERT_AT(this.storage, index, e); this.modCount += 1; } - proc _checkElementIndex (index: int): void + @KeepVisible proc _checkElementIndex (index: int, size: int): void { - if (!_isValidIndex(index)) + if (!_isValidIndex(index, size)) { //val message: String = // "Index: " + action OBJECT_TO_STRING(index) + - // ", Size: " + action OBJECT_TO_STRING(action LIST_SIZE(this.storage)); + // ", Size: " + action OBJECT_TO_STRING(size); action THROW_NEW("java.lang.IndexOutOfBoundsException", []); } } - proc _isValidIndex (index: int): boolean + proc _isValidIndex (index: int, size: int): boolean { result = 0 <= index && index < action LIST_SIZE(this.storage); } @@ -151,7 +176,7 @@ automaton LinkedListAutomaton } - proc _checkPositionIndex (index: int): void + @KeepVisible proc _checkPositionIndex (index: int): void { if (!_isPositionIndex(index)) { @@ -184,8 +209,9 @@ automaton LinkedListAutomaton } - proc _addAllElements (index: int, @Parameterized(["E"]) c: Collection): boolean + @KeepVisible proc _addAllElements (index: int, @Parameterized(["E"]) c: Collection): boolean { + _checkPositionIndex(index); // #todo: add optimized version when 'C' is this automaton (HAS operator is required) val iter: Iterator = action CALL_METHOD(c, "iterator", []); @@ -730,7 +756,7 @@ automaton LinkedListAutomaton fun *.get (@target self: LinkedList, index: int): Object { - _checkElementIndex(index); + _checkElementIndex(index, action LIST_SIZE(this.storage)); result = action LIST_GET(this.storage, index); } @@ -773,14 +799,11 @@ automaton LinkedListAutomaton // within java.util.AbstractSequentialList fun *.iterator (@target self: LinkedList): Iterator { - // #problem: not implemented - /* - result = new ListItr(state = Created, - expectedModCount = this.modCounter + result = new LinkedList_ListIteratorAutomaton(state = Initialized, + parent = self, + cursor = 0, + expectedModCount = this.modCount ); - */ - result = action SYMBOLIC("java.util.Iterator"); - action ASSUME(result != null); } @@ -818,14 +841,11 @@ automaton LinkedListAutomaton // within java.util.AbstractList fun *.listIterator (@target self: LinkedList): ListIterator { - // #problem: not implemented - /* - result = new ListItr(state = Created, - expectedModCount = this.modCounter + result = new LinkedList_ListIteratorAutomaton(state = Initialized, + parent = self, + cursor = 0, + expectedModCount = this.modCount ); - */ - result = action SYMBOLIC("java.util.ListIterator"); - action ASSUME(result != null); } @@ -833,14 +853,11 @@ automaton LinkedListAutomaton { _checkPositionIndex(index); - // #problem: not implemented - /* - result = new ListItr(state = Created, - expectedModCount = this.modCounter + result = new LinkedList_ListIteratorAutomaton(state = Initialized, + parent = self, + cursor = index, + expectedModCount = this.modCount ); - */ - result = action SYMBOLIC("java.util.ListIterator"); - action ASSUME(result != null); } @@ -952,7 +969,7 @@ automaton LinkedListAutomaton fun *.remove (@target self: LinkedList, index: int): Object { - _checkElementIndex(index); + _checkElementIndex(index, action LIST_SIZE(this.storage)); result = _unlinkAny(index); } @@ -1038,7 +1055,7 @@ automaton LinkedListAutomaton fun *.set (@target self: LinkedList, index: int, element: Object): Object { - _checkElementIndex(index); + _checkElementIndex(index, action LIST_SIZE(this.storage)); result = action LIST_GET(this.storage, index); action LIST_SET(this.storage, index, element); } @@ -1059,16 +1076,9 @@ automaton LinkedListAutomaton fun *.spliterator (@target self: LinkedList): Spliterator { - // #problem: not implemented - /* - result = new LLSpliterator(state=Initialized, + result = new LinkedList_SpliteratorAutomaton(state = Initialized, parent = self, - est = -1, - expectedModCount = 0 ); - */ - result = action SYMBOLIC("java.util.Spliterator"); - action ASSUME(result != null); } @@ -1082,7 +1092,15 @@ automaton LinkedListAutomaton // within java.util.AbstractList fun *.subList (@target self: LinkedList, fromIndex: int, toIndex: int): List { - action TODO(); + _subListRangeCheck(fromIndex, toIndex, action LIST_SIZE(this.storage)); + + result = new LinkedList_SubListAutomaton(state = Initialized, + root = self, + parentList = null, + offset = fromIndex, + length = toIndex - fromIndex, + modCount = this.modCount, + ); } From ca777fb795401fa293cdf2d62b240fb50da320a1 Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Thu, 30 Nov 2023 16:27:00 +0300 Subject: [PATCH 68/78] Fixed subroutine parameter not being used --- spec/java/util/LinkedList.main.lsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/java/util/LinkedList.main.lsl b/spec/java/util/LinkedList.main.lsl index 84fb833f..4829dcd7 100644 --- a/spec/java/util/LinkedList.main.lsl +++ b/spec/java/util/LinkedList.main.lsl @@ -166,7 +166,7 @@ automaton LinkedListAutomaton proc _isValidIndex (index: int, size: int): boolean { - result = 0 <= index && index < action LIST_SIZE(this.storage); + result = 0 <= index && index < size; } From 33481b62fb6004ac9ae92c425d10810fdaf4fc5b Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Thu, 30 Nov 2023 18:24:30 +0300 Subject: [PATCH 69/78] Fixed `toString` method for `java.util.HashSet/LinkedHashSet` + Made result of `java.lang.Object#toString` constant and non-symbolic --- spec/java/lang/Object.main.lsl | 4 ++-- spec/java/util/HashSet.main.lsl | 34 ++++++++++++++++++++++++++- spec/java/util/LinkedHashSet.main.lsl | 34 ++++++++++++++++++++++++++- 3 files changed, 68 insertions(+), 4 deletions(-) diff --git a/spec/java/lang/Object.main.lsl b/spec/java/lang/Object.main.lsl index 0748c4ce..35331f46 100644 --- a/spec/java/lang/Object.main.lsl +++ b/spec/java/lang/Object.main.lsl @@ -94,8 +94,8 @@ automaton ObjectAutomaton fun *.toString (@target self: LSLObject): String { - result = action SYMBOLIC("java.lang.String"); - action ASSUME(result != null); + // #todo: use class name and a random hex string + result = "java.lang.Object@735b5592"; } diff --git a/spec/java/util/HashSet.main.lsl b/spec/java/util/HashSet.main.lsl index 44e73380..baed508d 100644 --- a/spec/java/util/HashSet.main.lsl +++ b/spec/java/util/HashSet.main.lsl @@ -655,6 +655,38 @@ automaton HashSetAutomaton // within java.util.AbstractCollection fun *.toString (@target self: HashSet): String { - result = action OBJECT_TO_STRING(this.storage); + val items: map = this.storage; + var count: int = action MAP_SIZE(items); + + if (count == 0) + { + result = "[]"; + } + else + { + action ASSUME(count > 0); + + result = "["; + + val unseen: map = action MAP_CLONE(items); + action LOOP_WHILE( + count != 0, + toString_loop(unseen, count, result) + ); + + result += "]"; + } + } + + @Phantom proc toString_loop (unseen: map, count: int, result: String): void + { + val key: Object = action MAP_GET_ANY_KEY(unseen); + action MAP_REMOVE(unseen, key); + + result += action OBJECT_TO_STRING(key); + + if (count > 1) + result += ", "; + count -= 1; } } \ No newline at end of file diff --git a/spec/java/util/LinkedHashSet.main.lsl b/spec/java/util/LinkedHashSet.main.lsl index 1e908c8d..4857d3bb 100644 --- a/spec/java/util/LinkedHashSet.main.lsl +++ b/spec/java/util/LinkedHashSet.main.lsl @@ -645,6 +645,38 @@ automaton LinkedHashSetAutomaton // within java.util.AbstractCollection fun *.toString (@target self: LinkedHashSet): String { - result = action OBJECT_TO_STRING(this.storage); + val items: map = this.storage; + var count: int = action MAP_SIZE(items); + + if (count == 0) + { + result = "[]"; + } + else + { + action ASSUME(count > 0); + + result = "["; + + val unseen: map = action MAP_CLONE(items); + action LOOP_WHILE( + count != 0, + toString_loop(unseen, count, result) + ); + + result += "]"; + } + } + + @Phantom proc toString_loop (unseen: map, count: int, result: String): void + { + val key: Object = action MAP_GET_ANY_KEY(unseen); + action MAP_REMOVE(unseen, key); + + result += action OBJECT_TO_STRING(key); + + if (count > 1) + result += ", "; + count -= 1; } } \ No newline at end of file From cef04119a874ea184bb74af16b050ce3241e61eb Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Wed, 6 Dec 2023 13:37:32 +0300 Subject: [PATCH 70/78] Failed attempts to improve `java.security.SecureRandom` --- spec/java/security/SecureRandom.main.lsl | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/spec/java/security/SecureRandom.main.lsl b/spec/java/security/SecureRandom.main.lsl index 03e7961f..2c7d5aa2 100644 --- a/spec/java/security/SecureRandom.main.lsl +++ b/spec/java/security/SecureRandom.main.lsl @@ -95,7 +95,7 @@ automaton SecureRandomAutomaton @AutoInline @Phantom proc _throwIE (): void { - action THROW_NEW("java.lang.InternalError", []); + action ERROR("java.lang.InternalError"); // action THROW_NEW("java.lang.InternalError", []); } @@ -113,13 +113,17 @@ automaton SecureRandomAutomaton proc _getDefaultPRNG (): void { + /* this.provider = action SYMBOLIC("java.security.Provider"); - this.algorithm = action SYMBOLIC("java.lang.String"); + this.algorithm = action SYMBOLIC("java.lang.String"); action ASSUME(action CALL_METHOD(this.algorithm, "length", []) > 0); if (this.provider == null || this.algorithm == null) _throwIE(); + */ + this.provider = null; // #problem: approximate the provider (symbolic is too dificult for the USVM) + this.algorithm = "SHA1PRNG"; // #todo: get from the provider this.defaultProvider = _isDefaultProvider(this.provider); } @@ -127,8 +131,15 @@ automaton SecureRandomAutomaton @static proc _isDefaultProvider (curProvider: Provider): boolean { - val providerName: String = action CALL_METHOD(curProvider, "getName", []); - result = action MAP_HAS_KEY(this.defaultProvidersMap, providerName); + if (curProvider == null) + { + result = false; // no visible effect on anything + } + else + { + val providerName: String = action CALL_METHOD(curProvider, "getName", []); + result = action MAP_HAS_KEY(this.defaultProvidersMap, providerName); + } } @@ -177,7 +188,7 @@ automaton SecureRandomAutomaton proc _generateRandomDoubleArrayWithBounds (size: int, randomNumberOrigin: double, randomNumberBound: double): array { - result = action SYMBOLIC_ARRAY("double", size); + result = action ARRAY_NEW("double", size); var i: int = 0; action LOOP_FOR( i, 0, size, +1, @@ -188,10 +199,11 @@ automaton SecureRandomAutomaton @Phantom proc checkDoubleBounds_loop (i: int, result: array, randomNumberOrigin: double, randomNumberBound: double): void { - val item: double = result[i]; + val item: double = action SYMBOLIC("double"); action ASSUME(item == item); action ASSUME(item >= randomNumberOrigin); action ASSUME(item < randomNumberBound); + result[i] = item; } From ebfd88bfefffe81277e30807e1f3c4d6d571cce7 Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Fri, 8 Dec 2023 15:50:18 +0300 Subject: [PATCH 71/78] Moved array-based spliterators into `java.util.*` package + Added type description for `java.util.Spliterators` + Minor comment fix for `java.lang.SecurityManager` --- spec/java/lang/SecurityManager.main.lsl | 3 +- .../Spliterators.DoubleArraySpliterator.lsl | 246 ++++++++++++++++++ .../util/Spliterators.IntArraySpliterator.lsl | 246 ++++++++++++++++++ .../Spliterators.LongArraySpliterator.lsl | 246 ++++++++++++++++++ spec/java/util/Spliterators.lsl | 87 +++++++ .../util/stream/DoubleStream.Spliterator.lsl | 237 ----------------- spec/java/util/stream/DoubleStream.lsl | 9 - spec/java/util/stream/DoubleStream.main.lsl | 11 +- .../util/stream/IntStream.Spliterator.lsl | 237 ----------------- spec/java/util/stream/IntStream.lsl | 9 - spec/java/util/stream/IntStream.main.lsl | 7 +- .../util/stream/LongStream.Spliterator.lsl | 237 ----------------- spec/java/util/stream/LongStream.lsl | 9 - spec/java/util/stream/LongStream.main.lsl | 7 +- 14 files changed, 839 insertions(+), 752 deletions(-) create mode 100644 spec/java/util/Spliterators.DoubleArraySpliterator.lsl create mode 100644 spec/java/util/Spliterators.IntArraySpliterator.lsl create mode 100644 spec/java/util/Spliterators.LongArraySpliterator.lsl create mode 100644 spec/java/util/Spliterators.lsl delete mode 100644 spec/java/util/stream/DoubleStream.Spliterator.lsl delete mode 100644 spec/java/util/stream/IntStream.Spliterator.lsl delete mode 100644 spec/java/util/stream/LongStream.Spliterator.lsl diff --git a/spec/java/lang/SecurityManager.main.lsl b/spec/java/lang/SecurityManager.main.lsl index d9b85e16..38323d1a 100644 --- a/spec/java/lang/SecurityManager.main.lsl +++ b/spec/java/lang/SecurityManager.main.lsl @@ -404,7 +404,8 @@ automaton SecurityManagerAutomaton @Phantom fun *.getThreadGroup (@target self: LSLSecurityManager): ThreadGroup { - // NOTE: using the original method + // NOTE: using the original method - Thread modelling is a separate task on its own + // #todo: return valid thread group object } } diff --git a/spec/java/util/Spliterators.DoubleArraySpliterator.lsl b/spec/java/util/Spliterators.DoubleArraySpliterator.lsl new file mode 100644 index 00000000..763a9624 --- /dev/null +++ b/spec/java/util/Spliterators.DoubleArraySpliterator.lsl @@ -0,0 +1,246 @@ +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/util/Spliterators.java"; + +// imports + +import java/util/Comparator; +import java/util/Spliterator; +import java/util/function/Consumer; +import java/util/function/DoubleConsumer; + +import java/util/Spliterators; + + +// automata + +automaton Spliterators_DoubleArraySpliteratorAutomaton +( + var array: array, + var index: int = 0, + var fence: int = -1, + var characteristics: int = 0, +) +: Spliterators_DoubleArraySpliterator +{ + // states and shifts + + initstate Allocated; + state Initialized; + + shift Allocated -> Initialized by [ + // constructors + init (Spliterators_DoubleArraySpliterator, array, int), + init (Spliterators_DoubleArraySpliterator, array, int, int, int), + ]; + + shift Initialized -> self by [ + // instance methods + characteristics, + estimateSize, + forEachRemaining (Spliterators_DoubleArraySpliterator, Consumer), + forEachRemaining (Spliterators_DoubleArraySpliterator, DoubleConsumer), + forEachRemaining (Spliterators_DoubleArraySpliterator, Object), + getComparator, + getExactSizeIfKnown, + hasCharacteristics, + tryAdvance (Spliterators_DoubleArraySpliterator, Consumer), + tryAdvance (Spliterators_DoubleArraySpliterator, DoubleConsumer), + tryAdvance (Spliterators_DoubleArraySpliterator, Object), + trySplit, + ]; + + // internal variables + + // utilities + + @AutoInline @Phantom proc _throwNPE (): void + { + action THROW_NEW("java.lang.NullPointerException", []); + } + + + @AutoInline @Phantom proc _throwISE (): void + { + action THROW_NEW("java.lang.IllegalStateException", []); + } + + + proc _hasCharacteristics (_characteristics: int): boolean + { + result = (this.characteristics & _characteristics) == _characteristics; + } + + + // constructors + + constructor *.init (@target self: Spliterators_DoubleArraySpliterator, + arr: array, additionalCharacteristics: int) + { + this.array = arr; + this.index = 0; + this.fence = action ARRAY_SIZE(arr); + this.characteristics = additionalCharacteristics | SPLITERATOR_SIZED | SPLITERATOR_SUBSIZED; + } + + + constructor *.init (@target self: Spliterators_DoubleArraySpliterator, + arr: array, origin: int, pFence: int, additionalCharacteristics: int) + { + this.array = arr; + this.index = origin; + this.fence = pFence; + this.characteristics = additionalCharacteristics | SPLITERATOR_SIZED | SPLITERATOR_SUBSIZED; + } + + + // static methods + + // methods + + fun *.characteristics (@target self: Spliterators_DoubleArraySpliterator): int + { + result = this.characteristics; + } + + + fun *.estimateSize (@target self: Spliterators_DoubleArraySpliterator): long + { + result = (this.fence - this.index) as long; + } + + + @AutoInline @Phantom proc _forEachRemaining (_action: Consumer): void + { + if (_action == null) + _throwNPE(); + + val a: array = this.array; + + var hi: int = this.fence; + var i: int = this.index; + this.index = hi; + + action LOOP_FOR( + i, i, hi, +1, + _forEachRemaining_loop(i, a, _action) + ); + } + + @Phantom proc _forEachRemaining_loop (i: int, a: array, _action: Consumer): void + { + val item: double = a[i]; + action CALL(_action, [item]); + } + + + fun *.forEachRemaining (@target self: Spliterators_DoubleArraySpliterator, _action: DoubleConsumer): void + { + _forEachRemaining(_action); // WARNING: inlined call! + } + + + fun *.forEachRemaining (@target self: Spliterators_DoubleArraySpliterator, _action: Consumer): void + { + _forEachRemaining(_action); // WARNING: inlined call! + } + + + @Phantom fun *.forEachRemaining (@target self: Spliterators_DoubleArraySpliterator, userAction: Object): void + { + // NOTE: using the original method due to Java Compiler error "name clash" + + val _action: DoubleConsumer = userAction as DoubleConsumer; + _forEachRemaining(_action); // WARNING: inlined call! + } + + + fun *.getComparator (@target self: Spliterators_DoubleArraySpliterator): Comparator + { + if (_hasCharacteristics(SPLITERATOR_SORTED)) + result = null; + else + _throwISE(); + } + + + fun *.getExactSizeIfKnown (@target self: Spliterators_DoubleArraySpliterator): long + { + result = (this.fence - this.index) as long; + } + + + fun *.hasCharacteristics (@target self: Spliterators_DoubleArraySpliterator, _characteristics: int): boolean + { + result = _hasCharacteristics(_characteristics); + } + + + @AutoInline @Phantom proc _tryAdvance (_action: Consumer): boolean + { + if (_action == null) + _throwNPE(); + + val hi: int = this.fence; + val i: int = this.index; + + if (i < hi) + { + this.index = i + 1; + + val item: double = this.array[i]; + action CALL(_action, [item]); + + result = true; + } + else + { + result = false; + } + } + + + fun *.tryAdvance (@target self: Spliterators_DoubleArraySpliterator, _action: DoubleConsumer): boolean + { + _tryAdvance(_action); // WARNING: inlined call! + } + + + fun *.tryAdvance (@target self: Spliterators_DoubleArraySpliterator, _action: Consumer): boolean + { + _tryAdvance(_action); // WARNING: inlined call! + } + + + @Phantom fun *.tryAdvance (@target self: Spliterators_DoubleArraySpliterator, userAction: Object): boolean + { + // NOTE: using the original method due to Java Compiler error "name clash" + + val _action: DoubleConsumer = userAction as DoubleConsumer; + _tryAdvance(_action); // WARNING: inlined call! + } + + + fun *.trySplit (@target self: Spliterators_DoubleArraySpliterator): Spliterator_OfDouble + { + val hi: int = this.fence; + val lo: int = this.index; + val mid: int = (lo + hi) >>> 1; + + if (lo >= mid) + result = null; + else + result = new Spliterators_DoubleArraySpliteratorAutomaton(state = Initialized, + array = this.array, + index = lo, + fence = mid, + characteristics = this.characteristics, + ); + + this.index = mid; + } + +} diff --git a/spec/java/util/Spliterators.IntArraySpliterator.lsl b/spec/java/util/Spliterators.IntArraySpliterator.lsl new file mode 100644 index 00000000..59c4868c --- /dev/null +++ b/spec/java/util/Spliterators.IntArraySpliterator.lsl @@ -0,0 +1,246 @@ +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/util/Spliterators.java"; + +// imports + +import java/util/Comparator; +import java/util/Spliterator; +import java/util/function/Consumer; +import java/util/function/IntConsumer; + +import java/util/Spliterators; + + +// automata + +automaton Spliterators_IntArraySpliteratorAutomaton +( + var array: array, + var index: int = 0, + var fence: int = -1, + var characteristics: int = 0, +) +: Spliterators_IntArraySpliterator +{ + // states and shifts + + initstate Allocated; + state Initialized; + + shift Allocated -> Initialized by [ + // constructors + init (Spliterators_IntArraySpliterator, array, int), + init (Spliterators_IntArraySpliterator, array, int, int, int), + ]; + + shift Initialized -> self by [ + // instance methods + characteristics, + estimateSize, + forEachRemaining (Spliterators_IntArraySpliterator, Consumer), + forEachRemaining (Spliterators_IntArraySpliterator, IntConsumer), + forEachRemaining (Spliterators_IntArraySpliterator, Object), + getComparator, + getExactSizeIfKnown, + hasCharacteristics, + tryAdvance (Spliterators_IntArraySpliterator, Consumer), + tryAdvance (Spliterators_IntArraySpliterator, IntConsumer), + tryAdvance (Spliterators_IntArraySpliterator, Object), + trySplit, + ]; + + // internal variables + + // utilities + + @AutoInline @Phantom proc _throwNPE (): void + { + action THROW_NEW("java.lang.NullPointerException", []); + } + + + @AutoInline @Phantom proc _throwISE (): void + { + action THROW_NEW("java.lang.IllegalStateException", []); + } + + + proc _hasCharacteristics (_characteristics: int): boolean + { + result = (this.characteristics & _characteristics) == _characteristics; + } + + + // constructors + + constructor *.init (@target self: Spliterators_IntArraySpliterator, + arr: array, additionalCharacteristics: int) + { + this.array = arr; + this.index = 0; + this.fence = action ARRAY_SIZE(arr); + this.characteristics = additionalCharacteristics | SPLITERATOR_SIZED | SPLITERATOR_SUBSIZED; + } + + + constructor *.init (@target self: Spliterators_IntArraySpliterator, + arr: array, origin: int, pFence: int, additionalCharacteristics: int) + { + this.array = arr; + this.index = origin; + this.fence = pFence; + this.characteristics = additionalCharacteristics | SPLITERATOR_SIZED | SPLITERATOR_SUBSIZED; + } + + + // static methods + + // methods + + fun *.characteristics (@target self: Spliterators_IntArraySpliterator): int + { + result = this.characteristics; + } + + + fun *.estimateSize (@target self: Spliterators_IntArraySpliterator): long + { + result = (this.fence - this.index) as long; + } + + + @AutoInline @Phantom proc _forEachRemaining (_action: Consumer): void + { + if (_action == null) + _throwNPE(); + + val a: array = this.array; + + var hi: int = this.fence; + var i: int = this.index; + this.index = hi; + + action LOOP_FOR( + i, i, hi, +1, + _forEachRemaining_loop(i, a, _action) + ); + } + + @Phantom proc _forEachRemaining_loop (i: int, a: array, _action: Consumer): void + { + val item: int = a[i]; + action CALL(_action, [item]); + } + + + fun *.forEachRemaining (@target self: Spliterators_IntArraySpliterator, _action: Consumer): void + { + _forEachRemaining(_action); // WARNING: inlined call! + } + + + fun *.forEachRemaining (@target self: Spliterators_IntArraySpliterator, _action: IntConsumer): void + { + _forEachRemaining(_action); // WARNING: inlined call! + } + + + @Phantom fun *.forEachRemaining (@target self: Spliterators_IntArraySpliterator, userAction: Object): void + { + // NOTE: using the original method due to Java Compiler error "name clash" + + val _action: IntConsumer = userAction as IntConsumer; + _forEachRemaining(_action); // WARNING: inlined call! + } + + + fun *.getComparator (@target self: Spliterators_IntArraySpliterator): Comparator + { + if (_hasCharacteristics(SPLITERATOR_SORTED)) + result = null; + else + _throwISE(); + } + + + fun *.getExactSizeIfKnown (@target self: Spliterators_IntArraySpliterator): long + { + result = (this.fence - this.index) as long; + } + + + fun *.hasCharacteristics (@target self: Spliterators_IntArraySpliterator, _characteristics: int): boolean + { + result = _hasCharacteristics(_characteristics); + } + + + @AutoInline @Phantom proc _tryAdvance (_action: Consumer): boolean + { + if (_action == null) + _throwNPE(); + + val hi: int = this.fence; + val i: int = this.index; + + if (i < hi) + { + this.index = i + 1; + + val item: int = this.array[i]; + action CALL(_action, [item]); + + result = true; + } + else + { + result = false; + } + } + + + fun *.tryAdvance (@target self: Spliterators_IntArraySpliterator, _action: IntConsumer): boolean + { + _tryAdvance(_action); // WARNING: inlined call! + } + + + fun *.tryAdvance (@target self: Spliterators_IntArraySpliterator, _action: Consumer): boolean + { + _tryAdvance(_action); // WARNING: inlined call! + } + + + @Phantom fun *.tryAdvance (@target self: Spliterators_IntArraySpliterator, userAction: Object): boolean + { + // NOTE: using the original method due to Java Compiler error "name clash" + + val _action: IntConsumer = userAction as IntConsumer; + _tryAdvance(_action); // WARNING: inlined call! + } + + + fun *.trySplit (@target self: Spliterators_IntArraySpliterator): Spliterator_OfInt + { + val hi: int = this.fence; + val lo: int = this.index; + val mid: int = (lo + hi) >>> 1; + + if (lo >= mid) + result = null; + else + result = new Spliterators_IntArraySpliteratorAutomaton(state = Initialized, + array = this.array, + index = lo, + fence = mid, + characteristics = this.characteristics, + ); + + this.index = mid; + } + +} diff --git a/spec/java/util/Spliterators.LongArraySpliterator.lsl b/spec/java/util/Spliterators.LongArraySpliterator.lsl new file mode 100644 index 00000000..34a7f08b --- /dev/null +++ b/spec/java/util/Spliterators.LongArraySpliterator.lsl @@ -0,0 +1,246 @@ +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/util/Spliterators.java"; + +// imports + +import java/util/Comparator; +import java/util/Spliterator; +import java/util/function/Consumer; +import java/util/function/LongConsumer; + +import java/util/Spliterators; + + +// automata + +automaton Spliterators_LongArraySpliteratorAutomaton +( + var array: array, + var index: int = 0, + var fence: int = -1, + var characteristics: int = 0, +) +: Spliterators_LongArraySpliterator +{ + // states and shifts + + initstate Allocated; + state Initialized; + + shift Allocated -> Initialized by [ + // constructors + init (Spliterators_LongArraySpliterator, array, int), + init (Spliterators_LongArraySpliterator, array, int, int, int), + ]; + + shift Initialized -> self by [ + // instance methods + characteristics, + estimateSize, + forEachRemaining (Spliterators_LongArraySpliterator, Consumer), + forEachRemaining (Spliterators_LongArraySpliterator, LongConsumer), + forEachRemaining (Spliterators_LongArraySpliterator, Object), + getComparator, + getExactSizeIfKnown, + hasCharacteristics, + tryAdvance (Spliterators_LongArraySpliterator, Consumer), + tryAdvance (Spliterators_LongArraySpliterator, LongConsumer), + tryAdvance (Spliterators_LongArraySpliterator, Object), + trySplit, + ]; + + // internal variables + + // utilities + + @AutoInline @Phantom proc _throwNPE (): void + { + action THROW_NEW("java.lang.NullPointerException", []); + } + + + @AutoInline @Phantom proc _throwISE (): void + { + action THROW_NEW("java.lang.IllegalStateException", []); + } + + + proc _hasCharacteristics (_characteristics: int): boolean + { + result = (this.characteristics & _characteristics) == _characteristics; + } + + + // constructors + + constructor *.init (@target self: Spliterators_LongArraySpliterator, + arr: array, additionalCharacteristics: int) + { + this.array = arr; + this.index = 0; + this.fence = action ARRAY_SIZE(arr); + this.characteristics = additionalCharacteristics | SPLITERATOR_SIZED | SPLITERATOR_SUBSIZED; + } + + + constructor *.init (@target self: Spliterators_LongArraySpliterator, + arr: array, origin: int, pFence: int, additionalCharacteristics: int) + { + this.array = arr; + this.index = origin; + this.fence = pFence; + this.characteristics = additionalCharacteristics | SPLITERATOR_SIZED | SPLITERATOR_SUBSIZED; + } + + + // static methods + + // methods + + fun *.characteristics (@target self: Spliterators_LongArraySpliterator): int + { + result = this.characteristics; + } + + + fun *.estimateSize (@target self: Spliterators_LongArraySpliterator): long + { + result = (this.fence - this.index) as long; + } + + + @AutoInline @Phantom proc _forEachRemaining (_action: Consumer): void + { + if (_action == null) + _throwNPE(); + + val a: array = this.array; + + var hi: int = this.fence; + var i: int = this.index; + this.index = hi; + + action LOOP_FOR( + i, i, hi, +1, + _forEachRemaining_loop(i, a, _action) + ); + } + + @Phantom proc _forEachRemaining_loop (i: int, a: array, _action: Consumer): void + { + val item: long = a[i]; + action CALL(_action, [item]); + } + + + fun *.forEachRemaining (@target self: Spliterators_LongArraySpliterator, _action: Consumer): void + { + _forEachRemaining(_action); // WARNING: inlined call! + } + + + fun *.forEachRemaining (@target self: Spliterators_LongArraySpliterator, _action: LongConsumer): void + { + _forEachRemaining(_action); // WARNING: inlined call! + } + + + @Phantom fun *.forEachRemaining (@target self: Spliterators_LongArraySpliterator, userAction: Object): void + { + // NOTE: using the original method due to Java Compiler error "name clash" + + val _action: LongConsumer = userAction as LongConsumer; + _forEachRemaining(_action); // WARNING: inlined call! + } + + + fun *.getComparator (@target self: Spliterators_LongArraySpliterator): Comparator + { + if (_hasCharacteristics(SPLITERATOR_SORTED)) + result = null; + else + _throwISE(); + } + + + fun *.getExactSizeIfKnown (@target self: Spliterators_LongArraySpliterator): long + { + result = (this.fence - this.index) as long; + } + + + fun *.hasCharacteristics (@target self: Spliterators_LongArraySpliterator, _characteristics: int): boolean + { + result = _hasCharacteristics(_characteristics); + } + + + @AutoInline @Phantom proc _tryAdvance (_action: Consumer): boolean + { + if (_action == null) + _throwNPE(); + + val hi: int = this.fence; + val i: int = this.index; + + if (i < hi) + { + this.index = i + 1; + + val item: long = this.array[i]; + action CALL(_action, [item]); + + result = true; + } + else + { + result = false; + } + } + + + fun *.tryAdvance (@target self: Spliterators_LongArraySpliterator, _action: LongConsumer): boolean + { + _tryAdvance(_action); // WARNING: inlined call! + } + + + fun *.tryAdvance (@target self: Spliterators_LongArraySpliterator, _action: Consumer): boolean + { + _tryAdvance(_action); // WARNING: inlined call! + } + + + @Phantom fun *.tryAdvance (@target self: Spliterators_LongArraySpliterator, userAction: Object): boolean + { + // NOTE: using the original method due to Java Compiler error "name clash" + + val _action: LongConsumer = userAction as LongConsumer; + _tryAdvance(_action); // WARNING: inlined call! + } + + + fun *.trySplit (@target self: Spliterators_LongArraySpliterator): Spliterator_OfLong + { + val hi: int = this.fence; + val lo: int = this.index; + val mid: int = (lo + hi) >>> 1; + + if (lo >= mid) + result = null; + else + result = new Spliterators_LongArraySpliteratorAutomaton(state = Initialized, + array = this.array, + index = lo, + fence = mid, + characteristics = this.characteristics, + ); + + this.index = mid; + } + +} diff --git a/spec/java/util/Spliterators.lsl b/spec/java/util/Spliterators.lsl new file mode 100644 index 00000000..d94a83ba --- /dev/null +++ b/spec/java/util/Spliterators.lsl @@ -0,0 +1,87 @@ +//#! pragma: non-synthesizable +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/util/Spliterators.java"; + +// imports + +import java/lang/Object; +import java/util/Iterator; +import java/util/PrimitiveIterator; +import java/util/Spliterator; + + +// primary semantic types + +@final type Spliterators + is java.util.Spliterators + for Object +{ + @static fun *.emptySpliterator(): Spliterator; + + @static fun *.emptyDoubleSpliterator(): Spliterator_OfDouble; + + @static fun *.emptyIntSpliterator(): Spliterator_OfInt; + + @static fun *.emptyLongSpliterator(): Spliterator_OfLong; + + @static fun *.iterator(spliterator: Spliterator): Iterator; + + @static fun *.iterator(spliterator: Spliterator_OfDouble): PrimitiveIterator_OfDouble; + + @static fun *.iterator(spliterator: Spliterator_OfInt): PrimitiveIterator_OfInt; + + @static fun *.iterator(spliterator: Spliterator_OfLong): PrimitiveIterator_OfLong; + + // #todo: add automata implementations + + @static fun *.spliterator(arr: array, fromIndex: int, toIndex: int, additionalCharacteristics: int): Spliterator; + + @static fun *.spliterator(arr: array, fromIndex: int, toIndex: int, additionalCharacteristics: int): Spliterator_OfDouble; + + @static fun *.spliterator(arr: array, fromIndex: int, toIndex: int, additionalCharacteristics: int): Spliterator_OfInt; + + @static fun *.spliterator(arr: array, fromIndex: int, toIndex: int, additionalCharacteristics: int): Spliterator_OfLong; +} + + +// global aliases and type overrides + +//@GenerateMe +@implements("java.util.Spliterator") +@final type Spliterators_ArraySpliterator + is java.util.Spliterators_ArraySpliterator // #problem: private class + for Spliterator +{ +} + + +@GenerateMe +@implements("java.util.Spliterator.OfDouble") +@final type Spliterators_DoubleArraySpliterator + is java.util.Spliterators_DoubleArraySpliterator // #problem: private class + for Spliterator_OfDouble +{ +} + + +@GenerateMe +@implements("java.util.Spliterator.OfInt") +@final type Spliterators_IntArraySpliterator + is java.util.Spliterators_IntArraySpliterator // #problem: private class + for Spliterator_OfInt +{ +} + + +@GenerateMe +@implements("java.util.Spliterator.OfLong") +@final type Spliterators_LongArraySpliterator + is java.util.Spliterators_LongArraySpliterator // #problem: private class + for Spliterator_OfLong +{ +} + diff --git a/spec/java/util/stream/DoubleStream.Spliterator.lsl b/spec/java/util/stream/DoubleStream.Spliterator.lsl deleted file mode 100644 index 9753b9dc..00000000 --- a/spec/java/util/stream/DoubleStream.Spliterator.lsl +++ /dev/null @@ -1,237 +0,0 @@ -libsl "1.1.0"; - -library std - version "11" - language "Java" - url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/util/Spliterators.java"; - -// imports - -import java/util/stream/Stream; -import java/util/function/Consumer; -import java/util/Spliterator; -import java/util/Comparator; -import java/util/function/DoubleConsumer; - - -// automata - -automaton DoubleStreamSpliteratorAutomaton -( - var parent: DoubleStreamLSL, - var characteristics: int = 0, - var fence: int = -1, - var index: int = 0 -) -: DoubleStreamLSLSpliterator -{ - // states and shifts - - initstate Initialized; - - shift Initialized -> self by [ - characteristics, - trySplit, - forEachRemaining (DoubleStreamLSLSpliterator, DoubleConsumer), - forEachRemaining (DoubleStreamLSLSpliterator, Consumer), - tryAdvance (DoubleStreamLSLSpliterator, DoubleConsumer), - tryAdvance (DoubleStreamLSLSpliterator, Consumer), - estimateSize, - getComparator, - getExactSizeIfKnown, - hasCharacteristics, - ]; - - - // utilities - - @AutoInline @Phantom proc _throwNPE (): void - { - action THROW_NEW("java.lang.NullPointerException", []); - } - - - @AutoInline @Phantom proc _throwISE (): void - { - action THROW_NEW("java.lang.IllegalStateException", []); - } - - - proc _getFence (): int - { - // JDK comment: initialize fence to size on first use - if (this.fence < 0) - { - action ASSUME(this.parent != null); - this.fence = DoubleStreamAutomaton(this.parent).length; - } - result = this.fence; - } - - - proc _hasCharacteristics (_characteristics: int): boolean - { - result = (this.characteristics & _characteristics) == _characteristics; - } - - - // methods - - fun *.characteristics (@target self: DoubleStreamLSLSpliterator): int - { - result = this.characteristics; - } - - - fun *.trySplit (@target self: DoubleStreamLSLSpliterator): Spliterator_OfDouble - { - val hi: int = _getFence(); - val lo: int = this.index; - val mid: int = (lo + hi) >>> 1; - - if (lo >= mid) - result = null; - else - result = new DoubleStreamSpliteratorAutomaton(state = Initialized, - parent = this.parent, - index = lo, - fence = mid, - characteristics = this.characteristics, - ); - - this.index = mid; - } - - - fun *.forEachRemaining (@target self: DoubleStreamLSLSpliterator, _action: DoubleConsumer): void - { - if (_action == null) - _throwNPE(); - - action ASSUME(this.parent != null); - val a: array = DoubleStreamAutomaton(this.parent).storage; - - var hi: int = this.fence; - var i: int = this.index; - this.index = hi; - - action LOOP_FOR( - i, i, hi, +1, - forEachRemaining_DoubleConsumer_loop(i, a, _action) - ); - } - - - @Phantom proc forEachRemaining_DoubleConsumer_loop (i: int, a: array, _action: DoubleConsumer): void - { - val item: double = a[i]; - action CALL(_action, [item]); - } - - - fun *.forEachRemaining (@target self: DoubleStreamLSLSpliterator, _action: Consumer): void - { - if (_action == null) - _throwNPE(); - - action ASSUME(this.parent != null); - val a: array = DoubleStreamAutomaton(this.parent).storage; - - var hi: int = this.fence; - var i: int = this.index; - this.index = hi; - - action LOOP_FOR( - i, i, hi, +1, - forEachRemaining_Consumer_loop(i, a, _action) - ); - } - - - @Phantom proc forEachRemaining_Consumer_loop (i: int, a: array, _action: Consumer): void - { - val item: double = a[i]; - action CALL(_action, [item]); - } - - - fun *.tryAdvance (@target self: DoubleStreamLSLSpliterator, _action: DoubleConsumer): boolean - { - if (_action == null) - _throwNPE(); - - val hi: int = _getFence(); - val i: int = this.index; - - if (i < hi) - { - action ASSUME(this.parent != null); - - this.index = i + 1; - - val parentStorage: array = DoubleStreamAutomaton(this.parent).storage; - val item: double = parentStorage[i]; - action CALL(_action, [item]); - - result = true; - } - else - { - result = false; - } - } - - - fun *.tryAdvance (@target self: DoubleStreamLSLSpliterator, _action: Consumer): boolean - { - if (_action == null) - _throwNPE(); - - val hi: int = _getFence(); - val i: int = this.index; - - if (i < hi) - { - action ASSUME(this.parent != null); - - this.index = i + 1; - - val parentStorage: array = DoubleStreamAutomaton(this.parent).storage; - val item: double = parentStorage[i]; - action CALL(_action, [item]); - - result = true; - } - else - { - result = false; - } - } - - - fun *.estimateSize (@target self: DoubleStreamLSLSpliterator): long - { - result = _getFence() - this.index; - } - - - fun *.getComparator (@target self: DoubleStreamLSLSpliterator): Comparator - { - if (_hasCharacteristics(SPLITERATOR_SORTED)) - result = null; - else - _throwISE(); - } - - - fun *.getExactSizeIfKnown (@target self: DoubleStreamLSLSpliterator): long - { - result = _getFence() - this.index; - } - - - fun *.hasCharacteristics (@target self: DoubleStreamLSLSpliterator, _characteristics: int): boolean - { - result = _hasCharacteristics(_characteristics); - } -} \ No newline at end of file diff --git a/spec/java/util/stream/DoubleStream.lsl b/spec/java/util/stream/DoubleStream.lsl index b44384b9..979875c2 100644 --- a/spec/java/util/stream/DoubleStream.lsl +++ b/spec/java/util/stream/DoubleStream.lsl @@ -44,12 +44,3 @@ import java/util/Spliterator; for PrimitiveIterator_OfDouble { } - - -@GenerateMe -@implements("java.util.Spliterator.OfDouble") -@public type DoubleStreamLSLSpliterator - is java.util.stream.DoubleStreamLSLSpliterator - for Spliterator_OfDouble -{ -} \ No newline at end of file diff --git a/spec/java/util/stream/DoubleStream.main.lsl b/spec/java/util/stream/DoubleStream.main.lsl index 80fef2a7..28b65a64 100644 --- a/spec/java/util/stream/DoubleStream.main.lsl +++ b/spec/java/util/stream/DoubleStream.main.lsl @@ -7,7 +7,6 @@ library std // imports -import java/util/stream/DoubleStream; import java/lang/Double; import java/util/function/DoubleFunction; import java/util/function/DoublePredicate; @@ -20,6 +19,9 @@ import java/util/DoubleSummaryStatistics; import java/util/PrimitiveIterator; import java/util/OptionalDouble; +import java/util/stream/DoubleStream; +import java/util/Spliterators; + // automata @@ -930,12 +932,11 @@ automaton DoubleStreamAutomaton { _checkConsumed(); - val default_characteristics: int = SPLITERATOR_ORDERED | SPLITERATOR_IMMUTABLE | SPLITERATOR_SIZED | SPLITERATOR_SUBSIZED; - result = new DoubleStreamSpliteratorAutomaton(state = Initialized, - parent = self, + result = new Spliterators_DoubleArraySpliteratorAutomaton(state = Initialized, + array = this.storage, index = 0, fence = this.length, - characteristics = default_characteristics, + characteristics = SPLITERATOR_ORDERED | SPLITERATOR_IMMUTABLE | SPLITERATOR_SIZED | SPLITERATOR_SUBSIZED, ); _consume(); diff --git a/spec/java/util/stream/IntStream.Spliterator.lsl b/spec/java/util/stream/IntStream.Spliterator.lsl deleted file mode 100644 index 900dc87f..00000000 --- a/spec/java/util/stream/IntStream.Spliterator.lsl +++ /dev/null @@ -1,237 +0,0 @@ -libsl "1.1.0"; - -library std - version "11" - language "Java" - url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/util/Spliterators.java"; - -// imports - -import java/util/stream/Stream; -import java/util/function/Consumer; -import java/util/Spliterator; -import java/util/Comparator; -import java/util/function/IntConsumer; - - -// automata - -automaton IntStreamSpliteratorAutomaton -( - var parent: IntStreamLSL, - var characteristics: int = 0, - var fence: int = -1, - var index: int = 0 -) -: IntStreamLSLSpliterator -{ - // states and shifts - - initstate Initialized; - - shift Initialized -> self by [ - characteristics, - trySplit, - forEachRemaining (IntStreamLSLSpliterator, IntConsumer), - forEachRemaining (IntStreamLSLSpliterator, Consumer), - tryAdvance (IntStreamLSLSpliterator, IntConsumer), - tryAdvance (IntStreamLSLSpliterator, Consumer), - estimateSize, - getComparator, - getExactSizeIfKnown, - hasCharacteristics, - ]; - - - // utilities - - @AutoInline @Phantom proc _throwNPE (): void - { - action THROW_NEW("java.lang.NullPointerException", []); - } - - - @AutoInline @Phantom proc _throwISE (): void - { - action THROW_NEW("java.lang.IllegalStateException", []); - } - - - proc _getFence (): int - { - // JDK comment: initialize fence to size on first use - if (this.fence < 0) - { - action ASSUME(this.parent != null); - this.fence = IntStreamAutomaton(this.parent).length; - } - result = this.fence; - } - - - proc _hasCharacteristics (_characteristics: int): boolean - { - result = (this.characteristics & _characteristics) == _characteristics; - } - - - // methods - - fun *.characteristics (@target self: IntStreamLSLSpliterator): int - { - result = this.characteristics; - } - - - fun *.trySplit (@target self: IntStreamLSLSpliterator): Spliterator_OfInt - { - val hi: int = _getFence(); - val lo: int = this.index; - val mid: int = (lo + hi) >>> 1; - - if (lo >= mid) - result = null; - else - result = new IntStreamSpliteratorAutomaton(state = Initialized, - parent = this.parent, - index = lo, - fence = mid, - characteristics = this.characteristics, - ); - - this.index = mid; - } - - - fun *.forEachRemaining (@target self: IntStreamLSLSpliterator, _action: IntConsumer): void - { - if (_action == null) - _throwNPE(); - - action ASSUME(this.parent != null); - val a: array = IntStreamAutomaton(this.parent).storage; - - var hi: int = this.fence; - var i: int = this.index; - this.index = hi; - - action LOOP_FOR( - i, i, hi, +1, - forEachRemaining_IntConsumer_loop(i, a, _action) - ); - } - - - @Phantom proc forEachRemaining_IntConsumer_loop (i: int, a: array, _action: IntConsumer): void - { - val item: int = a[i]; - action CALL(_action, [item]); - } - - - fun *.forEachRemaining (@target self: IntStreamLSLSpliterator, _action: Consumer): void - { - if (_action == null) - _throwNPE(); - - action ASSUME(this.parent != null); - val a: array = IntStreamAutomaton(this.parent).storage; - - var hi: int = this.fence; - var i: int = this.index; - this.index = hi; - - action LOOP_FOR( - i, i, hi, +1, - forEachRemaining_Consumer_loop(i, a, _action) - ); - } - - - @Phantom proc forEachRemaining_Consumer_loop (i: int, a: array, _action: Consumer): void - { - val item: int = a[i]; - action CALL(_action, [item]); - } - - - fun *.tryAdvance (@target self: IntStreamLSLSpliterator, _action: IntConsumer): boolean - { - if (_action == null) - _throwNPE(); - - val hi: int = _getFence(); - val i: int = this.index; - - if (i < hi) - { - action ASSUME(this.parent != null); - - this.index = i + 1; - - val parentStorage: array = IntStreamAutomaton(this.parent).storage; - val item: int = parentStorage[i]; - action CALL(_action, [item]); - - result = true; - } - else - { - result = false; - } - } - - - fun *.tryAdvance (@target self: IntStreamLSLSpliterator, _action: Consumer): boolean - { - if (_action == null) - _throwNPE(); - - val hi: int = _getFence(); - val i: int = this.index; - - if (i < hi) - { - action ASSUME(this.parent != null); - - this.index = i + 1; - - val parentStorage: array = IntStreamAutomaton(this.parent).storage; - val item: int = parentStorage[i]; - action CALL(_action, [item]); - - result = true; - } - else - { - result = false; - } - } - - - fun *.estimateSize (@target self: IntStreamLSLSpliterator): long - { - result = _getFence() - this.index; - } - - - fun *.getComparator (@target self: IntStreamLSLSpliterator): Comparator - { - if (_hasCharacteristics(SPLITERATOR_SORTED)) - result = null; - else - _throwISE(); - } - - - fun *.getExactSizeIfKnown (@target self: IntStreamLSLSpliterator): long - { - result = _getFence() - this.index; - } - - - fun *.hasCharacteristics (@target self: IntStreamLSLSpliterator, _characteristics: int): boolean - { - result = _hasCharacteristics(_characteristics); - } -} \ No newline at end of file diff --git a/spec/java/util/stream/IntStream.lsl b/spec/java/util/stream/IntStream.lsl index 4aaf4677..f771040d 100644 --- a/spec/java/util/stream/IntStream.lsl +++ b/spec/java/util/stream/IntStream.lsl @@ -40,12 +40,3 @@ import java/util/Spliterator; for PrimitiveIterator_OfInt { } - - -@GenerateMe -@implements("java.util.Spliterator.OfInt") -@public type IntStreamLSLSpliterator - is java.util.stream.IntStreamLSLSpliterator - for Spliterator_OfInt -{ -} \ No newline at end of file diff --git a/spec/java/util/stream/IntStream.main.lsl b/spec/java/util/stream/IntStream.main.lsl index 0dee2557..9c243068 100644 --- a/spec/java/util/stream/IntStream.main.lsl +++ b/spec/java/util/stream/IntStream.main.lsl @@ -906,12 +906,11 @@ automaton IntStreamAutomaton { _checkConsumed(); - val default_characteristics: int = SPLITERATOR_ORDERED | SPLITERATOR_IMMUTABLE | SPLITERATOR_SIZED | SPLITERATOR_SUBSIZED; - result = new IntStreamSpliteratorAutomaton(state = Initialized, - parent = self, + result = new Spliterators_IntArraySpliteratorAutomaton(state = Initialized, + array = this.storage, index = 0, fence = this.length, - characteristics = default_characteristics, + characteristics = SPLITERATOR_ORDERED | SPLITERATOR_IMMUTABLE | SPLITERATOR_SIZED | SPLITERATOR_SUBSIZED, ); _consume(); diff --git a/spec/java/util/stream/LongStream.Spliterator.lsl b/spec/java/util/stream/LongStream.Spliterator.lsl deleted file mode 100644 index d8d581f1..00000000 --- a/spec/java/util/stream/LongStream.Spliterator.lsl +++ /dev/null @@ -1,237 +0,0 @@ -libsl "1.1.0"; - -library std - version "11" - language "Java" - url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/util/Spliterators.java"; - -// imports - -import java/util/stream/Stream; -import java/util/function/Consumer; -import java/util/Spliterator; -import java/util/Comparator; -import java/util/function/LongConsumer; - - -// automata - -automaton LongStreamSpliteratorAutomaton -( - var parent: LongStreamLSL, - var characteristics: int = 0, - var fence: int = -1, - var index: int = 0 -) -: LongStreamLSLSpliterator -{ - // states and shifts - - initstate Initialized; - - shift Initialized -> self by [ - characteristics, - trySplit, - forEachRemaining (LongStreamLSLSpliterator, LongConsumer), - forEachRemaining (LongStreamLSLSpliterator, Consumer), - tryAdvance (LongStreamLSLSpliterator, LongConsumer), - tryAdvance (LongStreamLSLSpliterator, Consumer), - estimateSize, - getComparator, - getExactSizeIfKnown, - hasCharacteristics, - ]; - - - // utilities - - @AutoInline @Phantom proc _throwNPE (): void - { - action THROW_NEW("java.lang.NullPointerException", []); - } - - - @AutoInline @Phantom proc _throwISE (): void - { - action THROW_NEW("java.lang.IllegalStateException", []); - } - - - proc _getFence (): int - { - // JDK comment: initialize fence to size on first use - if (this.fence < 0) - { - action ASSUME(this.parent != null); - this.fence = LongStreamAutomaton(this.parent).length; - } - result = this.fence; - } - - - proc _hasCharacteristics (_characteristics: int): boolean - { - result = (this.characteristics & _characteristics) == _characteristics; - } - - - // methods - - fun *.characteristics (@target self: LongStreamLSLSpliterator): int - { - result = this.characteristics; - } - - - fun *.trySplit (@target self: LongStreamLSLSpliterator): Spliterator_OfLong - { - val hi: int = _getFence(); - val lo: int = this.index; - val mid: int = (lo + hi) >>> 1; - - if (lo >= mid) - result = null; - else - result = new LongStreamSpliteratorAutomaton(state = Initialized, - parent = this.parent, - index = lo, - fence = mid, - characteristics = this.characteristics, - ); - - this.index = mid; - } - - - fun *.forEachRemaining (@target self: LongStreamLSLSpliterator, _action: LongConsumer): void - { - if (_action == null) - _throwNPE(); - - action ASSUME(this.parent != null); - val a: array = LongStreamAutomaton(this.parent).storage; - - var hi: int = this.fence; - var i: int = this.index; - this.index = hi; - - action LOOP_FOR( - i, i, hi, +1, - forEachRemaining_LongConsumer_loop(i, a, _action) - ); - } - - - @Phantom proc forEachRemaining_LongConsumer_loop (i: int, a: array, _action: LongConsumer): void - { - val item: long = a[i]; - action CALL(_action, [item]); - } - - - fun *.forEachRemaining (@target self: LongStreamLSLSpliterator, _action: Consumer): void - { - if (_action == null) - _throwNPE(); - - action ASSUME(this.parent != null); - val a: array = LongStreamAutomaton(this.parent).storage; - - var hi: int = this.fence; - var i: int = this.index; - this.index = hi; - - action LOOP_FOR( - i, i, hi, +1, - forEachRemaining_Consumer_loop(i, a, _action) - ); - } - - - @Phantom proc forEachRemaining_Consumer_loop (i: int, a: array, _action: Consumer): void - { - val item: long = a[i]; - action CALL(_action, [item]); - } - - - fun *.tryAdvance (@target self: LongStreamLSLSpliterator, _action: LongConsumer): boolean - { - if (_action == null) - _throwNPE(); - - val hi: int = _getFence(); - val i: int = this.index; - - if (i < hi) - { - action ASSUME(this.parent != null); - - this.index = i + 1; - - val parentStorage: array = LongStreamAutomaton(this.parent).storage; - val item: long = parentStorage[i]; - action CALL(_action, [item]); - - result = true; - } - else - { - result = false; - } - } - - - fun *.tryAdvance (@target self: LongStreamLSLSpliterator, _action: Consumer): boolean - { - if (_action == null) - _throwNPE(); - - val hi: int = _getFence(); - val i: int = this.index; - - if (i < hi) - { - action ASSUME(this.parent != null); - - this.index = i + 1; - - val parentStorage: array = LongStreamAutomaton(this.parent).storage; - val item: long = parentStorage[i]; - action CALL(_action, [item]); - - result = true; - } - else - { - result = false; - } - } - - - fun *.estimateSize (@target self: LongStreamLSLSpliterator): long - { - result = _getFence() - this.index; - } - - - fun *.getComparator (@target self: LongStreamLSLSpliterator): Comparator - { - if (_hasCharacteristics(SPLITERATOR_SORTED)) - result = null; - else - _throwISE(); - } - - - fun *.getExactSizeIfKnown (@target self: LongStreamLSLSpliterator): long - { - result = _getFence() - this.index; - } - - - fun *.hasCharacteristics (@target self: LongStreamLSLSpliterator, _characteristics: int): boolean - { - result = _hasCharacteristics(_characteristics); - } -} \ No newline at end of file diff --git a/spec/java/util/stream/LongStream.lsl b/spec/java/util/stream/LongStream.lsl index 9dd84e8b..e4b3aeb0 100644 --- a/spec/java/util/stream/LongStream.lsl +++ b/spec/java/util/stream/LongStream.lsl @@ -40,12 +40,3 @@ import java/util/Spliterator; for PrimitiveIterator_OfLong { } - - -@GenerateMe -@implements("java.util.Spliterator.OfLong") -@public type LongStreamLSLSpliterator - is java.util.stream.LongStreamLSLSpliterator - for Spliterator_OfLong -{ -} \ No newline at end of file diff --git a/spec/java/util/stream/LongStream.main.lsl b/spec/java/util/stream/LongStream.main.lsl index a8aba97d..d077a2b4 100644 --- a/spec/java/util/stream/LongStream.main.lsl +++ b/spec/java/util/stream/LongStream.main.lsl @@ -907,12 +907,11 @@ automaton LongStreamAutomaton { _checkConsumed(); - val default_characteristics: int = SPLITERATOR_ORDERED | SPLITERATOR_IMMUTABLE | SPLITERATOR_SIZED | SPLITERATOR_SUBSIZED; - result = new LongStreamSpliteratorAutomaton(state = Initialized, - parent = self, + result = new Spliterators_LongArraySpliteratorAutomaton(state = Initialized, + array = this.storage, index = 0, fence = this.length, - characteristics = default_characteristics, + characteristics = SPLITERATOR_ORDERED | SPLITERATOR_IMMUTABLE | SPLITERATOR_SIZED | SPLITERATOR_SUBSIZED, ); _consume(); From 75c9b65205db4d9e1abd11af025c535349ab7575 Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Sat, 9 Dec 2023 15:18:06 +0300 Subject: [PATCH 72/78] Added partial implementation for `java.util.Spliterators` + Added implementation for "array of `Object`s"-focused spliterator automaton --- .../util/Spliterators.ArraySpliterator.lsl | 236 +++++++++++++++ .../Spliterators.DoubleArraySpliterator.lsl | 4 + .../util/Spliterators.IntArraySpliterator.lsl | 4 + .../Spliterators.LongArraySpliterator.lsl | 4 + spec/java/util/Spliterators.lsl | 14 +- spec/java/util/Spliterators.main.lsl | 284 ++++++++++++++++++ 6 files changed, 535 insertions(+), 11 deletions(-) create mode 100644 spec/java/util/Spliterators.ArraySpliterator.lsl create mode 100644 spec/java/util/Spliterators.main.lsl diff --git a/spec/java/util/Spliterators.ArraySpliterator.lsl b/spec/java/util/Spliterators.ArraySpliterator.lsl new file mode 100644 index 00000000..749bdbec --- /dev/null +++ b/spec/java/util/Spliterators.ArraySpliterator.lsl @@ -0,0 +1,236 @@ +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/util/Spliterators.java"; + +// imports + +import java/lang/Object; +import java/util/Comparator; +import java/util/Spliterator; +import java/util/function/Consumer; + +import java/util/Spliterators; + + +// automata + +automaton Spliterators_ArraySpliteratorAutomaton +( + var array: array, + var index: int = 0, + var fence: int = -1, + var characteristics: int = 0, +) +: Spliterators_ArraySpliterator +{ + // states and shifts + + initstate Allocated; + state Initialized; + + shift Allocated -> Initialized by [ + // constructors + init (Spliterators_ArraySpliterator, array, int), + init (Spliterators_ArraySpliterator, array, int, int, int), + ]; + + shift Initialized -> self by [ + // instance methods + characteristics, + estimateSize, + forEachRemaining (Spliterators_ArraySpliterator, Consumer), + forEachRemaining (Spliterators_ArraySpliterator, Object), + getComparator, + getExactSizeIfKnown, + hasCharacteristics, + tryAdvance (Spliterators_ArraySpliterator, Consumer), + tryAdvance (Spliterators_ArraySpliterator, Object), + trySplit, + ]; + + // internal variables + + // utilities + + @AutoInline @Phantom proc _throwNPE (): void + { + action THROW_NEW("java.lang.NullPointerException", []); + } + + + @AutoInline @Phantom proc _throwISE (): void + { + action THROW_NEW("java.lang.IllegalStateException", []); + } + + + proc _hasCharacteristics (_characteristics: int): boolean + { + result = (this.characteristics & _characteristics) == _characteristics; + } + + + // constructors + + constructor *.init (@target self: Spliterators_ArraySpliterator, + arr: array, additionalCharacteristics: int) + { + // WARNING: unused + + this.array = arr; + this.index = 0; + this.fence = action ARRAY_SIZE(arr); + this.characteristics = additionalCharacteristics | SPLITERATOR_SIZED | SPLITERATOR_SUBSIZED; + } + + + constructor *.init (@target self: Spliterators_ArraySpliterator, + arr: array, origin: int, pFence: int, additionalCharacteristics: int) + { + // WARNING: unused + + this.array = arr; + this.index = origin; + this.fence = pFence; + this.characteristics = additionalCharacteristics | SPLITERATOR_SIZED | SPLITERATOR_SUBSIZED; + } + + + // static methods + + // methods + + fun *.characteristics (@target self: Spliterators_ArraySpliterator): int + { + result = this.characteristics; + } + + + fun *.estimateSize (@target self: Spliterators_ArraySpliterator): long + { + result = (this.fence - this.index) as long; + } + + + @AutoInline @Phantom proc _forEachRemaining (_action: Consumer): void + { + if (_action == null) + _throwNPE(); + + val a: array = this.array; + + var hi: int = this.fence; + var i: int = this.index; + this.index = hi; + + action LOOP_FOR( + i, i, hi, +1, + _forEachRemaining_loop(i, a, _action) + ); + } + + @Phantom proc _forEachRemaining_loop (i: int, a: array, _action: Consumer): void + { + val item: Object = a[i]; + action CALL(_action, [item]); + } + + + fun *.forEachRemaining (@target self: Spliterators_ArraySpliterator, _action: Consumer): void + { + _forEachRemaining(_action); // WARNING: inlined call! + } + + + @Phantom fun *.forEachRemaining (@target self: Spliterators_ArraySpliterator, userAction: Object): void + { + // NOTE: using the original method due to Java Compiler error "name clash" + + val _action: Consumer = userAction as Consumer; + _forEachRemaining(_action); // WARNING: inlined call! + } + + + fun *.getComparator (@target self: Spliterators_ArraySpliterator): Comparator + { + if (_hasCharacteristics(SPLITERATOR_SORTED)) + result = null; + else + _throwISE(); + } + + + fun *.getExactSizeIfKnown (@target self: Spliterators_ArraySpliterator): long + { + result = (this.fence - this.index) as long; + } + + + fun *.hasCharacteristics (@target self: Spliterators_ArraySpliterator, _characteristics: int): boolean + { + result = _hasCharacteristics(_characteristics); + } + + + @AutoInline @Phantom proc _tryAdvance (_action: Consumer): boolean + { + if (_action == null) + _throwNPE(); + + val hi: int = this.fence; + val i: int = this.index; + + if (i < hi) + { + this.index = i + 1; + + val item: Object = this.array[i]; + action CALL(_action, [item]); + + result = true; + } + else + { + result = false; + } + } + + + fun *.tryAdvance (@target self: Spliterators_ArraySpliterator, _action: Consumer): boolean + { + _tryAdvance(_action); // WARNING: inlined call! + } + + + @Phantom fun *.tryAdvance (@target self: Spliterators_ArraySpliterator, userAction: Object): boolean + { + // NOTE: using the original method due to Java Compiler error "name clash" + + val _action: Consumer = userAction as Consumer; + _tryAdvance(_action); // WARNING: inlined call! + } + + + fun *.trySplit (@target self: Spliterators_ArraySpliterator): Spliterator + { + val hi: int = this.fence; + val lo: int = this.index; + val mid: int = (lo + hi) >>> 1; + + if (lo >= mid) + result = null; + else + result = new Spliterators_ArraySpliteratorAutomaton(state = Initialized, + array = this.array, + index = lo, + fence = mid, + characteristics = this.characteristics, + ); + + this.index = mid; + } + +} diff --git a/spec/java/util/Spliterators.DoubleArraySpliterator.lsl b/spec/java/util/Spliterators.DoubleArraySpliterator.lsl index 763a9624..826aa634 100644 --- a/spec/java/util/Spliterators.DoubleArraySpliterator.lsl +++ b/spec/java/util/Spliterators.DoubleArraySpliterator.lsl @@ -80,6 +80,8 @@ automaton Spliterators_DoubleArraySpliteratorAutomaton constructor *.init (@target self: Spliterators_DoubleArraySpliterator, arr: array, additionalCharacteristics: int) { + // WARNING: unused + this.array = arr; this.index = 0; this.fence = action ARRAY_SIZE(arr); @@ -90,6 +92,8 @@ automaton Spliterators_DoubleArraySpliteratorAutomaton constructor *.init (@target self: Spliterators_DoubleArraySpliterator, arr: array, origin: int, pFence: int, additionalCharacteristics: int) { + // WARNING: unused + this.array = arr; this.index = origin; this.fence = pFence; diff --git a/spec/java/util/Spliterators.IntArraySpliterator.lsl b/spec/java/util/Spliterators.IntArraySpliterator.lsl index 59c4868c..d9932e7c 100644 --- a/spec/java/util/Spliterators.IntArraySpliterator.lsl +++ b/spec/java/util/Spliterators.IntArraySpliterator.lsl @@ -80,6 +80,8 @@ automaton Spliterators_IntArraySpliteratorAutomaton constructor *.init (@target self: Spliterators_IntArraySpliterator, arr: array, additionalCharacteristics: int) { + // WARNING: unused + this.array = arr; this.index = 0; this.fence = action ARRAY_SIZE(arr); @@ -90,6 +92,8 @@ automaton Spliterators_IntArraySpliteratorAutomaton constructor *.init (@target self: Spliterators_IntArraySpliterator, arr: array, origin: int, pFence: int, additionalCharacteristics: int) { + // WARNING: unused + this.array = arr; this.index = origin; this.fence = pFence; diff --git a/spec/java/util/Spliterators.LongArraySpliterator.lsl b/spec/java/util/Spliterators.LongArraySpliterator.lsl index 34a7f08b..c5b0575c 100644 --- a/spec/java/util/Spliterators.LongArraySpliterator.lsl +++ b/spec/java/util/Spliterators.LongArraySpliterator.lsl @@ -80,6 +80,8 @@ automaton Spliterators_LongArraySpliteratorAutomaton constructor *.init (@target self: Spliterators_LongArraySpliterator, arr: array, additionalCharacteristics: int) { + // WARNING: unused + this.array = arr; this.index = 0; this.fence = action ARRAY_SIZE(arr); @@ -90,6 +92,8 @@ automaton Spliterators_LongArraySpliteratorAutomaton constructor *.init (@target self: Spliterators_LongArraySpliterator, arr: array, origin: int, pFence: int, additionalCharacteristics: int) { + // WARNING: unused + this.array = arr; this.index = origin; this.fence = pFence; diff --git a/spec/java/util/Spliterators.lsl b/spec/java/util/Spliterators.lsl index d94a83ba..4fdbcab7 100644 --- a/spec/java/util/Spliterators.lsl +++ b/spec/java/util/Spliterators.lsl @@ -20,6 +20,8 @@ import java/util/Spliterator; is java.util.Spliterators for Object { + // #todo: add automata implementations + @static fun *.emptySpliterator(): Spliterator; @static fun *.emptyDoubleSpliterator(): Spliterator_OfDouble; @@ -35,22 +37,12 @@ import java/util/Spliterator; @static fun *.iterator(spliterator: Spliterator_OfInt): PrimitiveIterator_OfInt; @static fun *.iterator(spliterator: Spliterator_OfLong): PrimitiveIterator_OfLong; - - // #todo: add automata implementations - - @static fun *.spliterator(arr: array, fromIndex: int, toIndex: int, additionalCharacteristics: int): Spliterator; - - @static fun *.spliterator(arr: array, fromIndex: int, toIndex: int, additionalCharacteristics: int): Spliterator_OfDouble; - - @static fun *.spliterator(arr: array, fromIndex: int, toIndex: int, additionalCharacteristics: int): Spliterator_OfInt; - - @static fun *.spliterator(arr: array, fromIndex: int, toIndex: int, additionalCharacteristics: int): Spliterator_OfLong; } // global aliases and type overrides -//@GenerateMe +@GenerateMe @implements("java.util.Spliterator") @final type Spliterators_ArraySpliterator is java.util.Spliterators_ArraySpliterator // #problem: private class diff --git a/spec/java/util/Spliterators.main.lsl b/spec/java/util/Spliterators.main.lsl new file mode 100644 index 00000000..47bf2733 --- /dev/null +++ b/spec/java/util/Spliterators.main.lsl @@ -0,0 +1,284 @@ +libsl "1.1.0"; + +library std + version "11" + language "Java" + url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/util/Spliterators.java"; + +// imports + +import java/lang/Object; +import java/util/Collection; +import java/util/Iterator; +import java/util/PrimitiveIterator; +import java/util/Spliterator; + +import java/util/Spliterators; + + +// automata + +automaton SpliteratorsAutomaton +( +) +: Spliterators +{ + // states and shifts + + initstate Allocated; + + shift Allocated -> self by [ + // constructors + init, + + // static operations + emptyDoubleSpliterator, + emptyIntSpliterator, + emptyLongSpliterator, + emptySpliterator, + iterator (Spliterator_OfDouble), + iterator (Spliterator_OfInt), + iterator (Spliterator_OfLong), + iterator (Spliterator), + spliterator (Collection, int), + spliterator (Iterator, long, int), + spliterator (array, int), + spliterator (array, int, int, int), + spliterator (PrimitiveIterator_OfDouble, long, int), + spliterator (PrimitiveIterator_OfInt, long, int), + spliterator (PrimitiveIterator_OfLong, long, int), + spliterator (array, int), + spliterator (array, int, int, int), + spliterator (array, int), + spliterator (array, int, int, int), + spliterator (array, int), + spliterator (array, int, int, int), + spliteratorUnknownSize (Iterator, int), + spliteratorUnknownSize (PrimitiveIterator_OfDouble, int), + spliteratorUnknownSize (PrimitiveIterator_OfInt, int), + spliteratorUnknownSize (PrimitiveIterator_OfLong, int), + ]; + + // internal variables + + // utilities + + // constructors + + @private constructor *.init (@target self: Spliterators) + { + // nothing - this is a utility class + } + + + // static methods + + @Phantom @static fun *.emptyDoubleSpliterator (): Spliterator_OfDouble + { + // #todo: using the original method for now + action TODO(); + } + + + @Phantom @static fun *.emptyIntSpliterator (): Spliterator_OfInt + { + // #todo: using the original method for now + action TODO(); + } + + + @Phantom @static fun *.emptyLongSpliterator (): Spliterator_OfLong + { + // #todo: using the original method for now + action TODO(); + } + + + @Phantom @static fun *.emptySpliterator (): Spliterator + { + // #todo: using the original method for now + action TODO(); + } + + + @Phantom @static fun *.iterator (spliterator: Spliterator_OfDouble): PrimitiveIterator_OfDouble + { + // #todo: using the original method for now + action TODO(); + } + + + @Phantom @static fun *.iterator (spliterator: Spliterator_OfInt): PrimitiveIterator_OfInt + { + // #todo: using the original method for now + action TODO(); + } + + + @Phantom @static fun *.iterator (spliterator: Spliterator_OfLong): PrimitiveIterator_OfLong + { + // #todo: using the original method for now + action TODO(); + } + + + @Phantom @static fun *.iterator (spliterator: Spliterator): Iterator + { + // #todo: using the original method for now + action TODO(); + } + + + @Phantom @static fun *.spliterator (c: Collection, characteristics: int): Spliterator + { + // #todo: using the original method for now + action TODO(); + } + + + @Phantom @static fun *.spliterator (iterator: Iterator, size: long, characteristics: int): Spliterator + { + // #todo: using the original method for now + action TODO(); + } + + + @static fun *.spliterator (arr: array, additionalCharacteristics: int): Spliterator + { + result = new Spliterators_ArraySpliteratorAutomaton(state = Initialized, + array = arr, + index = 0, + fence = action ARRAY_SIZE(arr), + characteristics = additionalCharacteristics | SPLITERATOR_SIZED | SPLITERATOR_SUBSIZED, + ); + } + + + @static fun *.spliterator (arr: array, fromIndex: int, toIndex: int, additionalCharacteristics: int): Spliterator + { + result = new Spliterators_ArraySpliteratorAutomaton(state = Initialized, + array = arr, + index = fromIndex, + fence = toIndex, + characteristics = additionalCharacteristics | SPLITERATOR_SIZED | SPLITERATOR_SUBSIZED, + ); + } + + + @Phantom @static fun *.spliterator (iterator: PrimitiveIterator_OfDouble, size: long, characteristics: int): Spliterator_OfDouble + { + // #todo: using the original method for now + action TODO(); + } + + + @Phantom @static fun *.spliterator (iterator: PrimitiveIterator_OfInt, size: long, characteristics: int): Spliterator_OfInt + { + // #todo: using the original method for now + action TODO(); + } + + + @Phantom @static fun *.spliterator (iterator: PrimitiveIterator_OfLong, size: long, characteristics: int): Spliterator_OfLong + { + // #todo: using the original method for now + action TODO(); + } + + + @static fun *.spliterator (arr: array, additionalCharacteristics: int): Spliterator_OfDouble + { + result = new Spliterators_DoubleArraySpliteratorAutomaton(state = Initialized, + array = arr, + index = 0, + fence = action ARRAY_SIZE(arr), + characteristics = additionalCharacteristics | SPLITERATOR_SIZED | SPLITERATOR_SUBSIZED, + ); + } + + + @static fun *.spliterator (arr: array, fromIndex: int, toIndex: int, additionalCharacteristics: int): Spliterator_OfDouble + { + result = new Spliterators_DoubleArraySpliteratorAutomaton(state = Initialized, + array = arr, + index = fromIndex, + fence = toIndex, + characteristics = additionalCharacteristics | SPLITERATOR_SIZED | SPLITERATOR_SUBSIZED, + ); + } + + + @static fun *.spliterator (arr: array, additionalCharacteristics: int): Spliterator_OfInt + { + result = new Spliterators_IntArraySpliteratorAutomaton(state = Initialized, + array = arr, + index = 0, + fence = action ARRAY_SIZE(arr), + characteristics = additionalCharacteristics | SPLITERATOR_SIZED | SPLITERATOR_SUBSIZED, + ); + } + + + @static fun *.spliterator (arr: array, fromIndex: int, toIndex: int, additionalCharacteristics: int): Spliterator_OfInt + { + result = new Spliterators_IntArraySpliteratorAutomaton(state = Initialized, + array = arr, + index = fromIndex, + fence = toIndex, + characteristics = additionalCharacteristics | SPLITERATOR_SIZED | SPLITERATOR_SUBSIZED, + ); + } + + + @static fun *.spliterator (arr: array, additionalCharacteristics: int): Spliterator_OfLong + { + result = new Spliterators_LongArraySpliteratorAutomaton(state = Initialized, + array = arr, + index = 0, + fence = action ARRAY_SIZE(arr), + characteristics = additionalCharacteristics | SPLITERATOR_SIZED | SPLITERATOR_SUBSIZED, + ); + } + + + @static fun *.spliterator (arr: array, fromIndex: int, toIndex: int, additionalCharacteristics: int): Spliterator_OfLong + { + result = new Spliterators_LongArraySpliteratorAutomaton(state = Initialized, + array = arr, + index = fromIndex, + fence = toIndex, + characteristics = additionalCharacteristics | SPLITERATOR_SIZED | SPLITERATOR_SUBSIZED, + ); + } + + + @Phantom @static fun *.spliteratorUnknownSize (iterator: Iterator, characteristics: int): Spliterator + { + // #todo: using the original method for now + action TODO(); + } + + + @Phantom @static fun *.spliteratorUnknownSize (iterator: PrimitiveIterator_OfDouble, characteristics: int): Spliterator_OfDouble + { + // #todo: using the original method for now + action TODO(); + } + + + @Phantom @static fun *.spliteratorUnknownSize (iterator: PrimitiveIterator_OfInt, characteristics: int): Spliterator_OfInt + { + // #todo: using the original method for now + action TODO(); + } + + + @Phantom @static fun *.spliteratorUnknownSize (iterator: PrimitiveIterator_OfLong, characteristics: int): Spliterator_OfLong + { + // #todo: using the original method for now + action TODO(); + } + + + // methods +} From 98fac71b5f76ea6005e59911b1fb8bd908a0d10e Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Sun, 10 Dec 2023 04:39:05 +0300 Subject: [PATCH 73/78] Switched `java.util.stream.Stream` implementation from custom spliterator to use one from `java.util.Spliterators` --- spec/java/util/stream/Stream.Spliterator.lsl | 182 ------------------- spec/java/util/stream/Stream.lsl | 9 - spec/java/util/stream/Stream.main.lsl | 10 +- 3 files changed, 6 insertions(+), 195 deletions(-) delete mode 100644 spec/java/util/stream/Stream.Spliterator.lsl diff --git a/spec/java/util/stream/Stream.Spliterator.lsl b/spec/java/util/stream/Stream.Spliterator.lsl deleted file mode 100644 index 762bf116..00000000 --- a/spec/java/util/stream/Stream.Spliterator.lsl +++ /dev/null @@ -1,182 +0,0 @@ -libsl "1.1.0"; - -library std - version "11" - language "Java" - url "https://github.com/openjdk/jdk11/blob/master/src/java.base/share/classes/java/util/Spliterators.java"; - -// imports - -import java/util/stream/Stream; -import java/util/function/Consumer; -import java/util/Spliterator; -import java/util/Comparator; - - -// #note - base class of this specification was: "java.util.Spliterators$ArraySpliterator"; -// automata - -automaton StreamSpliteratorAutomaton -( - var parent: StreamLSL, - var characteristics: int = 0, - var fence: int = -1, - var index: int = 0 -) -: StreamLSLSpliterator -{ - // states and shifts - - initstate Initialized; - - shift Initialized -> self by [ - characteristics, - trySplit, - forEachRemaining, - tryAdvance, - estimateSize, - getComparator, - getExactSizeIfKnown, - hasCharacteristics, - ]; - - - // utilities - - @AutoInline @Phantom proc _throwNPE (): void - { - action THROW_NEW("java.lang.NullPointerException", []); - } - - - @AutoInline @Phantom proc _throwISE (): void - { - action THROW_NEW("java.lang.IllegalStateException", []); - } - - - proc _getFence (): int - { - // JDK comment: initialize fence to size on first use - if (this.fence < 0) - { - action ASSUME(this.parent != null); - this.fence = StreamAutomaton(this.parent).length; - } - result = this.fence; - } - - - proc _hasCharacteristics (_characteristics: int): boolean - { - result = (this.characteristics & _characteristics) == _characteristics; - } - - - // methods - - fun *.characteristics (@target self: StreamLSLSpliterator): int - { - result = this.characteristics; - } - - - fun *.trySplit (@target self: StreamLSLSpliterator): Spliterator - { - val hi: int = _getFence(); - val lo: int = this.index; - val mid: int = (lo + hi) >>> 1; - - if (lo >= mid) - result = null; - else - result = new StreamSpliteratorAutomaton(state = Initialized, - parent = this.parent, - index = lo, - fence = mid, - characteristics = this.characteristics, - ); - - this.index = mid; - } - - - fun *.forEachRemaining (@target self: StreamLSLSpliterator, _action: Consumer): void - { - if (_action == null) - _throwNPE(); - - action ASSUME(this.parent != null); - val a: array = StreamAutomaton(this.parent).storage; - - var hi: int = this.fence; - var i: int = this.index; - this.index = hi; - - action LOOP_FOR( - i, i, hi, +1, - forEachRemaining_loop(i, a, _action) - ); - } - - - @Phantom proc forEachRemaining_loop (i: int, a: array, _action: Consumer): void - { - val item: Object = a[i]; - action CALL(_action, [item]); - } - - - fun *.tryAdvance (@target self: StreamLSLSpliterator, _action: Consumer): boolean - { - if (_action == null) - _throwNPE(); - - val hi: int = _getFence(); - val i: int = this.index; - - if (i < hi) - { - action ASSUME(this.parent != null); - - this.index = i + 1; - - val parentStorage: array = StreamAutomaton(this.parent).storage; - val item: Object = parentStorage[i]; - action CALL(_action, [item]); - - result = true; - } - else - { - result = false; - } - } - - - fun *.estimateSize (@target self: StreamLSLSpliterator): long - { - result = _getFence() - this.index; - } - - - fun *.getComparator (@target self: StreamLSLSpliterator): Comparator - { - if (_hasCharacteristics(SPLITERATOR_SORTED)) - result = null; - else - _throwISE(); - } - - - fun *.getExactSizeIfKnown (@target self: StreamLSLSpliterator): long - { - result = _getFence() - this.index; - } - - - fun *.hasCharacteristics (@target self: StreamLSLSpliterator, _characteristics: int): boolean - { - result = _hasCharacteristics(_characteristics); - } -} \ No newline at end of file diff --git a/spec/java/util/stream/Stream.lsl b/spec/java/util/stream/Stream.lsl index e6f35384..92bc9e25 100644 --- a/spec/java/util/stream/Stream.lsl +++ b/spec/java/util/stream/Stream.lsl @@ -48,12 +48,3 @@ import java/util/Spliterator; for Iterator { } - - -@GenerateMe -@implements("java.util.Spliterator") -@public type StreamLSLSpliterator - is java.util.stream.StreamLSLSpliterator - for Spliterator -{ -} \ No newline at end of file diff --git a/spec/java/util/stream/Stream.main.lsl b/spec/java/util/stream/Stream.main.lsl index 5dd4c08d..b4907c4d 100644 --- a/spec/java/util/stream/Stream.main.lsl +++ b/spec/java/util/stream/Stream.main.lsl @@ -29,7 +29,9 @@ import java/util/stream/Collector; import java/util/stream/DoubleStream; import java/util/stream/IntStream; import java/util/stream/LongStream; + import java/util/stream/Stream; +import java/util/Spliterators; // automata @@ -1095,13 +1097,13 @@ automaton StreamAutomaton { _checkConsumed(); - val default_characteristics: int = SPLITERATOR_ORDERED | SPLITERATOR_SIZED | SPLITERATOR_SUBSIZED; - result = new StreamSpliteratorAutomaton(state = Initialized, - parent = self, + result = new Spliterators_ArraySpliteratorAutomaton(state = Initialized, + array = this.storage, index = 0, fence = this.length, - characteristics = default_characteristics, + characteristics = SPLITERATOR_ORDERED | SPLITERATOR_SIZED | SPLITERATOR_SUBSIZED, ); + _consume(); } From 0246b2d18cebe2d063e82fc44e064fec301c6305 Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Sun, 10 Dec 2023 13:21:49 +0300 Subject: [PATCH 74/78] Minor improvements to `java.security.SecureRandom` --- spec/java/security/SecureRandom.main.lsl | 90 ++++++++++++++---------- 1 file changed, 51 insertions(+), 39 deletions(-) diff --git a/spec/java/security/SecureRandom.main.lsl b/spec/java/security/SecureRandom.main.lsl index 2c7d5aa2..89e3b9a0 100644 --- a/spec/java/security/SecureRandom.main.lsl +++ b/spec/java/security/SecureRandom.main.lsl @@ -143,21 +143,18 @@ automaton SecureRandomAutomaton } - @static proc _nextBytes (result: array, numBytes: int): void - { - val symbolicArray: array = action SYMBOLIC_ARRAY("byte", numBytes); - action ARRAY_COPY(symbolicArray, 0, result, 0, numBytes); - } - - proc _generateRandomIntegerArrayWithBounds (size: int, randomNumberOrigin: int, randomNumberBound: int): array { result = action SYMBOLIC_ARRAY("int", size); + + // #problem: too complex for symbolic execution + /* var i: int = 0; action LOOP_FOR( i, 0, size, +1, checkIntBounds_loop(i, result, randomNumberOrigin, randomNumberBound) ); + */ } @@ -171,11 +168,15 @@ automaton SecureRandomAutomaton proc _generateRandomLongArrayWithBounds (size: int, randomNumberOrigin: long, randomNumberBound: long): array { result = action SYMBOLIC_ARRAY("long", size); + + // #problem: too complex for symbolic execution + /* var i: int = 0; action LOOP_FOR( i, 0, size, +1, checkLongBounds_loop(i, result, randomNumberOrigin, randomNumberBound) ); + */ } @@ -188,18 +189,22 @@ automaton SecureRandomAutomaton proc _generateRandomDoubleArrayWithBounds (size: int, randomNumberOrigin: double, randomNumberBound: double): array { - result = action ARRAY_NEW("double", size); + result = action SYMBOLIC_ARRAY("double", size); + + // #problem: too complex for symbolic execution + /* var i: int = 0; action LOOP_FOR( i, 0, size, +1, checkDoubleBounds_loop(i, result, randomNumberOrigin, randomNumberBound) ); + */ } @Phantom proc checkDoubleBounds_loop (i: int, result: array, randomNumberOrigin: double, randomNumberBound: double): void { - val item: double = action SYMBOLIC("double"); + val item: double = result[i]; action ASSUME(item == item); action ASSUME(item >= randomNumberOrigin); action ASSUME(item < randomNumberBound); @@ -312,9 +317,7 @@ automaton SecureRandomAutomaton // #note this property can be disabled with SecurityManager. We assume that this situation is impossible, // because we can't check enable/disable property status. And we can't invoke "AccessController.doPrivileged" method like in source code; - val propertyName: String = "securerandom.strongAlgorithms"; - val property: String = action CALL_METHOD(null as Security, "getProperty", [propertyName]); - + val property: String = action CALL_METHOD(null as Security, "getProperty", ["securerandom.strongAlgorithms"]); if (property == null) _throwNSAE(); @@ -340,8 +343,8 @@ automaton SecureRandomAutomaton { if (numBytes < 0) _throwIAE(); - result = action ARRAY_NEW("byte", numBytes); - _nextBytes(result, numBytes); + + result = action SYMBOLIC_ARRAY("byte", numBytes); } @@ -363,7 +366,9 @@ automaton SecureRandomAutomaton { if (randomNumberOrigin >= randomNumberBound) _throwIAE(); + result = new DoubleStreamAutomaton(state = Initialized, + // #problem: too complex for symbolic execution storage = _generateRandomDoubleArrayWithBounds(MAX_RANDOM_STREAM_SIZE, randomNumberOrigin, randomNumberBound), length = MAX_RANDOM_STREAM_SIZE, closeHandlers = action LIST_NEW(), @@ -377,6 +382,7 @@ automaton SecureRandomAutomaton var size: int = streamSize as int; if (size < 0) _throwIAE(); + // WARNING: this is our special constraint; We must constraint infinite stream for USVM. if (size > MAX_RANDOM_STREAM_SIZE) size = MAX_RANDOM_STREAM_SIZE; @@ -397,6 +403,7 @@ automaton SecureRandomAutomaton _throwIAE(); if (randomNumberOrigin >= randomNumberBound) _throwIAE(); + // WARNING: this is our special constraint; We must constraint infinite stream for USVM. if (size > MAX_RANDOM_STREAM_SIZE) size = MAX_RANDOM_STREAM_SIZE; @@ -414,8 +421,7 @@ automaton SecureRandomAutomaton if (numBytes < 0) _throwIAE(); - result = action ARRAY_NEW("byte", numBytes); - _nextBytes(result, numBytes); + result = action SYMBOLIC_ARRAY("byte", numBytes); } @@ -447,6 +453,7 @@ automaton SecureRandomAutomaton { if (randomNumberOrigin >= randomNumberBound) _throwIAE(); + result = new IntStreamAutomaton(state = Initialized, storage = _generateRandomIntegerArrayWithBounds(MAX_RANDOM_STREAM_SIZE, randomNumberOrigin, randomNumberBound), length = MAX_RANDOM_STREAM_SIZE, @@ -461,6 +468,7 @@ automaton SecureRandomAutomaton var size: int = streamSize as int; if (size < 0) _throwIAE(); + // WARNING: this is our special constraint; We must constraint infinite stream for USVM. if (size > MAX_RANDOM_STREAM_SIZE) size = MAX_RANDOM_STREAM_SIZE; @@ -481,6 +489,7 @@ automaton SecureRandomAutomaton _throwIAE(); if (randomNumberOrigin >= randomNumberBound) _throwIAE(); + // WARNING: this is our special constraint; We must constraint infinite stream for USVM. if (size > MAX_RANDOM_STREAM_SIZE) size = MAX_RANDOM_STREAM_SIZE; @@ -510,6 +519,7 @@ automaton SecureRandomAutomaton var size: int = streamSize as int; if (size < 0) _throwIAE(); + // WARNING: this is our special constraint; We must constraint infinite stream for USVM. if (size > MAX_RANDOM_STREAM_SIZE) size = MAX_RANDOM_STREAM_SIZE; @@ -527,6 +537,7 @@ automaton SecureRandomAutomaton { if (randomNumberOrigin >= randomNumberBound) _throwIAE(); + result = new LongStreamAutomaton(state = Initialized, storage = _generateRandomLongArrayWithBounds(MAX_RANDOM_STREAM_SIZE, randomNumberOrigin, randomNumberBound), length = MAX_RANDOM_STREAM_SIZE, @@ -543,6 +554,7 @@ automaton SecureRandomAutomaton _throwIAE(); if (randomNumberOrigin >= randomNumberBound) _throwIAE(); + // WARNING: this is our special constraint; We must constraint infinite stream for USVM. if (size > MAX_RANDOM_STREAM_SIZE) size = MAX_RANDOM_STREAM_SIZE; @@ -564,13 +576,9 @@ automaton SecureRandomAutomaton fun *.nextBytes (@target self: SecureRandom, bytes: array): void { - _nextBytes(bytes, action ARRAY_SIZE(bytes)); - } - - - @Phantom proc nextBytes_loop (i: int, bytes: array): void - { - bytes[i] = action SYMBOLIC("byte"); + val len: int = action ARRAY_SIZE(bytes); + val src: array = action SYMBOLIC_ARRAY("byte", len); + action ARRAY_COPY(src, 0, bytes, 0, len); } @@ -653,22 +661,26 @@ automaton SecureRandomAutomaton { // #note: list of default providers https://docs.oracle.com/javase/9/security/oracleproviders.htm#JSSEC-GUID-F41EE1C9-DD6A-4BAB-8979-EB7654094029 - action MAP_SET(defaultProvidersMap, "SUN", SOMETHING); - action MAP_SET(defaultProvidersMap, "SunRsaSign", SOMETHING); - action MAP_SET(defaultProvidersMap, "SunJSSE", SOMETHING); - action MAP_SET(defaultProvidersMap, "SunJCE", SOMETHING); - action MAP_SET(defaultProvidersMap, "Apple", SOMETHING); - - action MAP_SET(defaultProvidersMap, "JdkLDAP", SOMETHING); - action MAP_SET(defaultProvidersMap, "SunJGSS", SOMETHING); - action MAP_SET(defaultProvidersMap, "SunSASL", SOMETHING); - action MAP_SET(defaultProvidersMap, "SunPCSC", SOMETHING); - action MAP_SET(defaultProvidersMap, "XMLDSig", SOMETHING); - action MAP_SET(defaultProvidersMap, "SunPKCS11", SOMETHING); - action MAP_SET(defaultProvidersMap, "SunEC", SOMETHING); - action MAP_SET(defaultProvidersMap, "SunMSCAPI", SOMETHING); - action MAP_SET(defaultProvidersMap, "OracleUcrypto", SOMETHING); - action MAP_SET(defaultProvidersMap, "JdkSASL", SOMETHING); + // limiting static field access + val dpMap: map = defaultProvidersMap; + val o: Object = SOMETHING; + + action MAP_SET(dpMap, "SUN", o); + action MAP_SET(dpMap, "SunRsaSign", o); + action MAP_SET(dpMap, "SunJSSE", o); + action MAP_SET(dpMap, "SunJCE", o); + action MAP_SET(dpMap, "Apple", o); + + action MAP_SET(dpMap, "JdkLDAP", o); + action MAP_SET(dpMap, "SunJGSS", o); + action MAP_SET(dpMap, "SunSASL", o); + action MAP_SET(dpMap, "SunPCSC", o); + action MAP_SET(dpMap, "XMLDSig", o); + action MAP_SET(dpMap, "SunPKCS11", o); + action MAP_SET(dpMap, "SunEC", o); + action MAP_SET(dpMap, "SunMSCAPI", o); + action MAP_SET(dpMap, "OracleUcrypto", o); + action MAP_SET(dpMap, "JdkSASL", o); } } \ No newline at end of file From 73d8326fe3235bc6fdd61428e9bad8b12cc98213 Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Mon, 11 Dec 2023 04:48:53 +0300 Subject: [PATCH 75/78] Corrections to function names --- spec/java/lang/Double.main.lsl | 8 +- spec/java/lang/Float.main.lsl | 12 +- spec/java/lang/Integer.main.lsl | 8 +- spec/java/lang/Object.main.lsl | 6 +- spec/java/lang/SecurityManager.main.lsl | 4 +- spec/java/lang/StringBuffer.main.lsl | 16 +- spec/java/lang/StringBuilder.main.lsl | 16 +- spec/java/lang/System.StdOut.lsl | 2 +- spec/java/lang/System.main.lsl | 6 +- spec/java/lang/Throwable.main.lsl | 22 +- spec/java/nio/charset/Charset.main.lsl | 4 +- spec/java/security/SecureRandom.main.lsl | 20 +- spec/java/util/ArrayList.Spliterator.lsl | 4 +- spec/java/util/ArrayList.SubList.lsl | 8 +- spec/java/util/ArrayList.main.lsl | 12 +- spec/java/util/HashSet.KeyIterator.lsl | 4 +- spec/java/util/HashSet.Spliterator.lsl | 5 +- spec/java/util/HashSet.main.lsl | 24 +- spec/java/util/LinkedHashSet.KeyIterator.lsl | 4 +- spec/java/util/LinkedHashSet.Spliterator.lsl | 4 +- spec/java/util/LinkedHashSet.main.lsl | 16 +- spec/java/util/LinkedList.Spliterator.lsl | 9 +- spec/java/util/LinkedList.SubList.lsl | 8 +- spec/java/util/LinkedList.main.lsl | 354 +----------------- spec/java/util/Optional.automata.lsl | 8 +- spec/java/util/OptionalDouble.automata.lsl | 8 +- spec/java/util/OptionalInt.automata.lsl | 8 +- spec/java/util/OptionalLong.automata.lsl | 8 +- spec/java/util/Random.main.lsl | 8 +- .../util/Spliterators.ArraySpliterator.lsl | 12 +- .../Spliterators.DoubleArraySpliterator.lsl | 12 +- .../util/Spliterators.IntArraySpliterator.lsl | 12 +- .../Spliterators.LongArraySpliterator.lsl | 12 +- spec/java/util/Spliterators.main.lsl | 4 +- .../concurrent/atomic/AtomicBoolean.main.lsl | 8 +- .../concurrent/atomic/AtomicInteger.main.lsl | 8 +- .../concurrent/atomic/AtomicLong.main.lsl | 8 +- .../atomic/AtomicReference.main.lsl | 8 +- spec/java/util/zip/CRC32.automaton.lsl | 4 +- 39 files changed, 178 insertions(+), 526 deletions(-) diff --git a/spec/java/lang/Double.main.lsl b/spec/java/lang/Double.main.lsl index dc16b1b1..273e4447 100644 --- a/spec/java/lang/Double.main.lsl +++ b/spec/java/lang/Double.main.lsl @@ -28,8 +28,8 @@ automaton DoubleAutomaton shift Allocated -> Initialized by [ // constructors - Double (LSLDouble, String), - Double (LSLDouble, double), + `` (LSLDouble, String), + `` (LSLDouble, double), // static operations compare, @@ -115,13 +115,13 @@ automaton DoubleAutomaton // constructors @throws(["java.lang.NumberFormatException"]) - @Phantom constructor *.Double (@target self: LSLDouble, s: String) + @Phantom constructor *.`` (@target self: LSLDouble, s: String) { // NOTE: using original method } - constructor *.Double (@target self: LSLDouble, v: double) + constructor *.`` (@target self: LSLDouble, v: double) { this.value = v; } diff --git a/spec/java/lang/Float.main.lsl b/spec/java/lang/Float.main.lsl index 487baff5..4ecc52a9 100644 --- a/spec/java/lang/Float.main.lsl +++ b/spec/java/lang/Float.main.lsl @@ -27,9 +27,9 @@ automaton FloatAutomaton shift Allocated -> Initialized by [ // constructors - LSLFloat (LSLFloat, String), - LSLFloat (LSLFloat, double), - LSLFloat (LSLFloat, float), + `` (LSLFloat, String), + `` (LSLFloat, double), + `` (LSLFloat, float), // static operations compare, @@ -115,20 +115,20 @@ automaton FloatAutomaton // constructors @throws(["java.lang.NumberFormatException"]) - @Phantom constructor *.LSLFloat (@target self: LSLFloat, s: String) + @Phantom constructor *.`` (@target self: LSLFloat, s: String) { // NOTE: using the original method this.value = _parse(s); } - constructor *.LSLFloat (@target self: LSLFloat, v: double) + constructor *.`` (@target self: LSLFloat, v: double) { this.value = v as float; } - constructor *.LSLFloat (@target self: LSLFloat, v: float) + constructor *.`` (@target self: LSLFloat, v: float) { this.value = v; } diff --git a/spec/java/lang/Integer.main.lsl b/spec/java/lang/Integer.main.lsl index 4c302ae8..e3622ccd 100644 --- a/spec/java/lang/Integer.main.lsl +++ b/spec/java/lang/Integer.main.lsl @@ -28,8 +28,8 @@ automaton IntegerAutomaton shift Initialized -> self by [ // constructors - Integer (LSLInteger, String), - Integer (LSLInteger, int), + `` (LSLInteger, String), + `` (LSLInteger, int), // static operations bitCount, @@ -103,14 +103,14 @@ automaton IntegerAutomaton // constructors @throws(["java.lang.NumberFormatException"]) - @Phantom constructor *.Integer (@target self: LSLInteger, s: String) + @Phantom constructor *.`` (@target self: LSLInteger, s: String) { // NOTE: using the original method this.value = _parse(s); } - constructor *.Integer (@target self: LSLInteger, v: int) + constructor *.`` (@target self: LSLInteger, v: int) { this.value = v; } diff --git a/spec/java/lang/Object.main.lsl b/spec/java/lang/Object.main.lsl index 35331f46..52bdaef7 100644 --- a/spec/java/lang/Object.main.lsl +++ b/spec/java/lang/Object.main.lsl @@ -25,7 +25,7 @@ automaton ObjectAutomaton shift Initialized -> self by [ // constructors - LSLObject, + ``, // instance methods equals, @@ -46,7 +46,7 @@ automaton ObjectAutomaton // constructors - @Phantom constructor *.LSLObject (@target self: LSLObject) + @Phantom constructor *.`` (@target self: LSLObject) { // WARNING: Using the original method here. Do not change! (infinite recursion otherwise) } @@ -122,7 +122,7 @@ automaton ObjectAutomaton // special: static initialization - @Phantom @static fun *.__clinit__ (): void + @Phantom @static fun *.`` (): void { action DO_NOTHING(); } diff --git a/spec/java/lang/SecurityManager.main.lsl b/spec/java/lang/SecurityManager.main.lsl index 38323d1a..3fb0143a 100644 --- a/spec/java/lang/SecurityManager.main.lsl +++ b/spec/java/lang/SecurityManager.main.lsl @@ -32,7 +32,7 @@ automaton SecurityManagerAutomaton shift Allocated -> Initialized by [ // constructors - LSLSecurityManager, + ``, ]; shift Initialized -> self by [ @@ -96,7 +96,7 @@ automaton SecurityManagerAutomaton // constructors - constructor *.LSLSecurityManager (@target self: LSLSecurityManager) + constructor *.`` (@target self: LSLSecurityManager) { _do_checkPermission( action DEBUG_DO("new RuntimePermission(\"createSecurityManager\")") diff --git a/spec/java/lang/StringBuffer.main.lsl b/spec/java/lang/StringBuffer.main.lsl index 941fb923..aaac6c51 100644 --- a/spec/java/lang/StringBuffer.main.lsl +++ b/spec/java/lang/StringBuffer.main.lsl @@ -26,10 +26,10 @@ automaton StringBufferAutomaton shift Allocated -> Initialized by [ // constructors - StringBuffer (StringBuffer), - StringBuffer (StringBuffer, CharSequence), - StringBuffer (StringBuffer, String), - StringBuffer (StringBuffer, int), + `` (StringBuffer), + `` (StringBuffer, CharSequence), + `` (StringBuffer, String), + `` (StringBuffer, int), ]; shift Initialized -> self by [ @@ -297,14 +297,14 @@ automaton StringBufferAutomaton // constructors - constructor *.StringBuffer (@target self: StringBuffer) + constructor *.`` (@target self: StringBuffer) { // This constructor's body is empty, because in original class is used byte array and this initializes 16 size; // In this realization is used "String" instead of to array; And this string initializes in "internal variables"; } - constructor *.StringBuffer (@target self: StringBuffer, seq: CharSequence) + constructor *.`` (@target self: StringBuffer, seq: CharSequence) { if (seq == null) _throwNPE(); @@ -313,7 +313,7 @@ automaton StringBufferAutomaton } - constructor *.StringBuffer (@target self: StringBuffer, str: String) + constructor *.`` (@target self: StringBuffer, str: String) { if (str == null) _throwNPE(); @@ -322,7 +322,7 @@ automaton StringBufferAutomaton } - constructor *.StringBuffer (@target self: StringBuffer, capacity: int) + constructor *.`` (@target self: StringBuffer, capacity: int) { // This constructor's body is empty, because in original class is used byte array and this initializes 16 + capacity size; // In this realization is used "String" instead of to array; And this string initializes in "internal variables"; diff --git a/spec/java/lang/StringBuilder.main.lsl b/spec/java/lang/StringBuilder.main.lsl index d2c9acce..ab8ab54b 100644 --- a/spec/java/lang/StringBuilder.main.lsl +++ b/spec/java/lang/StringBuilder.main.lsl @@ -28,10 +28,10 @@ automaton StringBuilderAutomaton shift Allocated -> Initialized by [ // constructors - StringBuilder (StringBuilder), - StringBuilder (StringBuilder, CharSequence), - StringBuilder (StringBuilder, String), - StringBuilder (StringBuilder, int), + `` (StringBuilder), + `` (StringBuilder, CharSequence), + `` (StringBuilder, String), + `` (StringBuilder, int), ]; shift Initialized -> self by [ @@ -299,14 +299,14 @@ automaton StringBuilderAutomaton // constructors - constructor *.StringBuilder (@target self: StringBuilder) + constructor *.`` (@target self: StringBuilder) { // This constructor's body is empty, because in original class is used byte array and this initializes 16 size; // In this realization is used "String" instead of to array; And this string initializes in "internal variables"; } - constructor *.StringBuilder (@target self: StringBuilder, seq: CharSequence) + constructor *.`` (@target self: StringBuilder, seq: CharSequence) { if (seq == null) _throwNPE(); @@ -315,7 +315,7 @@ automaton StringBuilderAutomaton } - constructor *.StringBuilder (@target self: StringBuilder, str: String) + constructor *.`` (@target self: StringBuilder, str: String) { if (str == null) _throwNPE(); @@ -324,7 +324,7 @@ automaton StringBuilderAutomaton } - constructor *.StringBuilder (@target self: StringBuilder, capacity: int) + constructor *.`` (@target self: StringBuilder, capacity: int) { // This constructor's body is empty, because in original class is used byte array and this initializes 16 + capacity size; // In this realization is used "String" instead of to array; And this string initializes in "internal variables"; diff --git a/spec/java/lang/System.StdOut.lsl b/spec/java/lang/System.StdOut.lsl index e4fbd14f..b717cfc7 100644 --- a/spec/java/lang/System.StdOut.lsl +++ b/spec/java/lang/System.StdOut.lsl @@ -337,7 +337,7 @@ automaton System_PrintStreamAutomaton // special methods - @Phantom @static fun *.__super__ (): array + @Phantom @static fun *.`` (): array { result = [ null as OutputStream, diff --git a/spec/java/lang/System.main.lsl b/spec/java/lang/System.main.lsl index 77a0e54f..92eb39e4 100644 --- a/spec/java/lang/System.main.lsl +++ b/spec/java/lang/System.main.lsl @@ -40,7 +40,7 @@ automaton SystemAutomaton shift Initialized -> self by [ // constructors - LSLSystem, + ``, // static operations arraycopy, @@ -222,7 +222,7 @@ automaton SystemAutomaton // constructors - @private constructor *.LSLSystem (@target self: LSLSystem) + @private constructor *.`` (@target self: LSLSystem) { // doing nothing - this is a (singleton) utility class } @@ -635,7 +635,7 @@ automaton SystemAutomaton // special: static initialization - @Phantom @static fun *.__clinit__ (): void + @Phantom @static fun *.`` (): void { // #problem: version-specific initialization diff --git a/spec/java/lang/Throwable.main.lsl b/spec/java/lang/Throwable.main.lsl index 47bfff96..8e7e58bd 100644 --- a/spec/java/lang/Throwable.main.lsl +++ b/spec/java/lang/Throwable.main.lsl @@ -29,11 +29,11 @@ automaton ThrowableAutomaton shift Initialized -> self by [ // constructors - Throwable (LSLThrowable), - Throwable (LSLThrowable, String), - Throwable (LSLThrowable, String, Throwable), - Throwable (LSLThrowable, String, Throwable, boolean, boolean), - Throwable (LSLThrowable, Throwable), + `` (LSLThrowable), + `` (LSLThrowable, String), + `` (LSLThrowable, String, Throwable), + `` (LSLThrowable, String, Throwable, boolean, boolean), + `` (LSLThrowable, Throwable), // instance methods addSuppressed, @@ -57,36 +57,36 @@ automaton ThrowableAutomaton // constructors - @Phantom constructor *.Throwable (@target self: LSLThrowable) + @Phantom constructor *.`` (@target self: LSLThrowable) { // Note: using the original method action TODO(); } - @Phantom constructor *.Throwable (@target self: LSLThrowable, message: String) + @Phantom constructor *.`` (@target self: LSLThrowable, message: String) { // Note: using the original method action TODO(); } - @Phantom constructor *.Throwable (@target self: LSLThrowable, message: String, cause: Throwable) + @Phantom constructor *.`` (@target self: LSLThrowable, message: String, cause: Throwable) { // Note: using the original method action TODO(); } - @Phantom @protected constructor *.Throwable (@target self: LSLThrowable, - message: String, cause: Throwable, enableSuppression: boolean, writableStackTrace: boolean) + @Phantom @protected constructor *.`` (@target self: LSLThrowable, + message: String, cause: Throwable, enableSuppression: boolean, writableStackTrace: boolean) { // Note: using the original method action TODO(); } - @Phantom constructor *.Throwable (@target self: LSLThrowable, cause: Throwable) + @Phantom constructor *.`` (@target self: LSLThrowable, cause: Throwable) { // Note: using the original method action TODO(); diff --git a/spec/java/nio/charset/Charset.main.lsl b/spec/java/nio/charset/Charset.main.lsl index 47d9a0f7..edb006f2 100644 --- a/spec/java/nio/charset/Charset.main.lsl +++ b/spec/java/nio/charset/Charset.main.lsl @@ -33,7 +33,7 @@ automaton CharsetAutomaton shift Allocated -> Initialized by [ // constructors - LSLCharset, + ``, // static operations availableCharsets, @@ -65,7 +65,7 @@ automaton CharsetAutomaton // constructors - @protected constructor *.LSLCharset (@target self: LSLCharset, canonicalName: String, aliases: array) + @protected constructor *.`` (@target self: LSLCharset, canonicalName: String, aliases: array) { action TODO(); } diff --git a/spec/java/security/SecureRandom.main.lsl b/spec/java/security/SecureRandom.main.lsl index 89e3b9a0..c7fe8802 100644 --- a/spec/java/security/SecureRandom.main.lsl +++ b/spec/java/security/SecureRandom.main.lsl @@ -36,10 +36,10 @@ automaton SecureRandomAutomaton shift Allocated -> Initialized by [ // constructors - SecureRandom (SecureRandom), - SecureRandom (SecureRandom, SecureRandomSpi, Provider), - SecureRandom (SecureRandom, SecureRandomSpi, Provider, String), - SecureRandom (SecureRandom, array), + `` (SecureRandom), + `` (SecureRandom, SecureRandomSpi, Provider), + `` (SecureRandom, SecureRandomSpi, Provider, String), + `` (SecureRandom, array), // static operations getInstance (String), @@ -214,27 +214,25 @@ automaton SecureRandomAutomaton // constructors - constructor *.SecureRandom (@target self: SecureRandom) + constructor *.`` (@target self: SecureRandom) { _getDefaultPRNG(); } - // #question: do we need such realization of constructor ? Or it must be empty because this is "protected" ? - @protected constructor *.SecureRandom (@target self: SecureRandom, secureRandomSpi: SecureRandomSpi, provider: Provider) + @protected constructor *.`` (@target self: SecureRandom, secureRandomSpi: SecureRandomSpi, provider: Provider) { action ERROR("Protected constructor call"); } - // #question: do we need such realization of constructor ? Or it must be empty because this is "private" ? - @private constructor *.SecureRandom (@target self: SecureRandom, secureRandomSpi: SecureRandomSpi, provider: Provider, algorithm: String) + @private constructor *.`` (@target self: SecureRandom, secureRandomSpi: SecureRandomSpi, provider: Provider, algorithm: String) { action ERROR("Private constructor call"); } - constructor *.SecureRandom (@target self: SecureRandom, seed: array) + constructor *.`` (@target self: SecureRandom, seed: array) { _getDefaultPRNG(); } @@ -657,7 +655,7 @@ automaton SecureRandomAutomaton // special: static initialization - @Phantom @static fun *.__clinit__ (): void + @Phantom @static fun *.`` (): void { // #note: list of default providers https://docs.oracle.com/javase/9/security/oracleproviders.htm#JSSEC-GUID-F41EE1C9-DD6A-4BAB-8979-EB7654094029 diff --git a/spec/java/util/ArrayList.Spliterator.lsl b/spec/java/util/ArrayList.Spliterator.lsl index 046876e0..111856de 100644 --- a/spec/java/util/ArrayList.Spliterator.lsl +++ b/spec/java/util/ArrayList.Spliterator.lsl @@ -25,7 +25,7 @@ automaton ArrayList_SpliteratorAutomaton shift Allocated -> Initialized by [ // constructors - ArrayList_Spliterator, + ``, ]; shift Initialized -> self by [ @@ -77,7 +77,7 @@ automaton ArrayList_SpliteratorAutomaton // constructors - @private constructor *.ArrayList_Spliterator ( + @private constructor *.`` ( @target self: ArrayList_Spliterator, _this: ArrayList, origin: int, fence: int, expectedModCount: int) diff --git a/spec/java/util/ArrayList.SubList.lsl b/spec/java/util/ArrayList.SubList.lsl index d257c494..e8600f37 100644 --- a/spec/java/util/ArrayList.SubList.lsl +++ b/spec/java/util/ArrayList.SubList.lsl @@ -29,8 +29,8 @@ automaton ArrayList_SubListAutomaton shift Allocated -> Initialized by [ // constructors - SubList (ArrayList_SubList, ArrayList, int, int), - SubList (ArrayList_SubList, ArrayList_SubList, int, int), + `` (ArrayList_SubList, ArrayList, int, int), + `` (ArrayList_SubList, ArrayList_SubList, int, int), ]; shift Initialized -> self by [ @@ -184,14 +184,14 @@ automaton ArrayList_SubListAutomaton // constructors - constructor *.SubList (@target self: ArrayList_SubList, root: ArrayList, fromIndex: int, toIndex: int) + constructor *.`` (@target self: ArrayList_SubList, root: ArrayList, fromIndex: int, toIndex: int) { // #problem: this constructor is useless action NOT_IMPLEMENTED("inaccessible constructor"); } - @private constructor *.SubList (@target self: ArrayList_SubList, parent: ArrayList_SubList, fromIndex: int, toIndex: int) + @private constructor *.`` (@target self: ArrayList_SubList, parent: ArrayList_SubList, fromIndex: int, toIndex: int) { // #problem: this constructor is useless action NOT_IMPLEMENTED("inaccessible constructor"); diff --git a/spec/java/util/ArrayList.main.lsl b/spec/java/util/ArrayList.main.lsl index 86b8a067..d850fb89 100644 --- a/spec/java/util/ArrayList.main.lsl +++ b/spec/java/util/ArrayList.main.lsl @@ -27,9 +27,9 @@ automaton ArrayListAutomaton shift Allocated -> Initialized by [ // constructors - ArrayList (ArrayList), - ArrayList (ArrayList, Collection), - ArrayList (ArrayList, int), + `` (ArrayList), + `` (ArrayList, Collection), + `` (ArrayList, int), ]; shift Initialized -> self by [ @@ -520,13 +520,13 @@ automaton ArrayListAutomaton // constructors - constructor *.ArrayList (@target self: ArrayList) + constructor *.`` (@target self: ArrayList) { this.storage = action LIST_NEW(); } - constructor *.ArrayList (@target self: ArrayList, c: Collection) + constructor *.`` (@target self: ArrayList, c: Collection) { if (c == null) _throwNPE(); @@ -537,7 +537,7 @@ automaton ArrayListAutomaton } - constructor *.ArrayList (@target self: ArrayList, initialCapacity: int) + constructor *.`` (@target self: ArrayList, initialCapacity: int) { if (initialCapacity < 0) { diff --git a/spec/java/util/HashSet.KeyIterator.lsl b/spec/java/util/HashSet.KeyIterator.lsl index 7a5e7669..c857d705 100644 --- a/spec/java/util/HashSet.KeyIterator.lsl +++ b/spec/java/util/HashSet.KeyIterator.lsl @@ -37,7 +37,7 @@ automaton HashSet_KeyIteratorAutomaton shift Allocated -> Initialized by [ // constructors // Problem: here mustn't be "HashMap"; What must be here ? What we must to do with constructor ? - HashSet_KeyIterator, + ``, ]; shift Initialized -> self by [ @@ -63,7 +63,7 @@ automaton HashSet_KeyIteratorAutomaton // constructors - @private constructor *.HashSet_KeyIterator (@target self: HashSet_KeyIterator, source: HashMap) + @private constructor *.`` (@target self: HashSet_KeyIterator, source: HashMap) { action ERROR("Private constructor call"); } diff --git a/spec/java/util/HashSet.Spliterator.lsl b/spec/java/util/HashSet.Spliterator.lsl index 3cee357b..4b859140 100644 --- a/spec/java/util/HashSet.Spliterator.lsl +++ b/spec/java/util/HashSet.Spliterator.lsl @@ -34,7 +34,7 @@ automaton HashSet_KeySpliteratorAutomaton shift Allocated -> Initialized by [ // constructors - HashSet_KeySpliterator + `` ]; shift Initialized -> self by [ @@ -86,7 +86,8 @@ automaton HashSet_KeySpliteratorAutomaton // constructors - @private constructor *.HashSet_KeySpliterator (@target self: HashSet_KeySpliterator, source: HashMap, origin: int, fence: int, est: int, expectedModCount: int) + @private constructor *.`` (@target self: HashSet_KeySpliterator, + source: HashMap, origin: int, fence: int, est: int, expectedModCount: int) { this.index = origin; this.fence = fence; diff --git a/spec/java/util/HashSet.main.lsl b/spec/java/util/HashSet.main.lsl index baed508d..2bcdc1a5 100644 --- a/spec/java/util/HashSet.main.lsl +++ b/spec/java/util/HashSet.main.lsl @@ -35,10 +35,10 @@ automaton HashSetAutomaton shift Allocated -> Initialized by [ // constructors - HashSet(HashSet), - HashSet(HashSet, Collection), - HashSet(HashSet, int, float), - HashSet(HashSet, int, float, boolean) + `` (HashSet), + `` (HashSet, Collection), + `` (HashSet, int, float), + `` (HashSet, int, float, boolean) ]; shift Initialized -> self by [ @@ -56,9 +56,9 @@ automaton HashSetAutomaton spliterator, stream, parallelStream, - toArray(HashSet), - toArray(HashSet, array), - toArray(HashSet, IntFunction), + toArray (HashSet), + toArray (HashSet, array), + toArray (HashSet, IntFunction), toString, // write operations @@ -157,20 +157,20 @@ automaton HashSetAutomaton // constructors - constructor *.HashSet (@target self: HashSet) + constructor *.`` (@target self: HashSet) { this.storage = action MAP_NEW(); } - constructor *.HashSet (@target self: HashSet, c: Collection) + constructor *.`` (@target self: HashSet, c: Collection) { this.storage = action MAP_NEW(); _addAllElements(c); } - constructor *.HashSet (@target self: HashSet, initialCapacity: int) + constructor *.`` (@target self: HashSet, initialCapacity: int) { if (initialCapacity < 0) { @@ -182,7 +182,7 @@ automaton HashSetAutomaton } - constructor *.HashSet (@target self: HashSet, initialCapacity: int, loadFactor: float) + constructor *.`` (@target self: HashSet, initialCapacity: int, loadFactor: float) { if (initialCapacity < 0) { @@ -200,7 +200,7 @@ automaton HashSetAutomaton } - @private constructor *.HashSet (@target self: HashSet, initialCapacity: int, loadFactor: float, dummy: boolean) + @private constructor *.`` (@target self: HashSet, initialCapacity: int, loadFactor: float, dummy: boolean) { action ERROR("Private constructor call"); } diff --git a/spec/java/util/LinkedHashSet.KeyIterator.lsl b/spec/java/util/LinkedHashSet.KeyIterator.lsl index e1ce96d0..03a43232 100644 --- a/spec/java/util/LinkedHashSet.KeyIterator.lsl +++ b/spec/java/util/LinkedHashSet.KeyIterator.lsl @@ -36,7 +36,7 @@ automaton LinkedHashSet_KeyIteratorAutomaton shift Allocated -> Initialized by [ // constructors - LinkedHashSet_KeyIterator, + ``, ]; shift Initialized -> self by [ @@ -62,7 +62,7 @@ automaton LinkedHashSet_KeyIteratorAutomaton // constructors - @private constructor *.LinkedHashSet_KeyIterator (@target self: LinkedHashSet_KeyIterator, source: HashMap) + @private constructor *.`` (@target self: LinkedHashSet_KeyIterator, source: HashMap) { action ERROR("Private constructor call"); } diff --git a/spec/java/util/LinkedHashSet.Spliterator.lsl b/spec/java/util/LinkedHashSet.Spliterator.lsl index 86a161d5..0254aba7 100644 --- a/spec/java/util/LinkedHashSet.Spliterator.lsl +++ b/spec/java/util/LinkedHashSet.Spliterator.lsl @@ -34,7 +34,7 @@ automaton LinkedHashSet_KeySpliteratorAutomaton shift Allocated -> Initialized by [ // constructors - LinkedHashSet_KeySpliterator + `` ]; shift Initialized -> self by [ @@ -86,7 +86,7 @@ automaton LinkedHashSet_KeySpliteratorAutomaton // constructors - @private constructor *.LinkedHashSet_KeySpliterator (@target self: LinkedHashSet_KeySpliterator, source: HashMap, origin: int, fence: int, est: int, expectedModCount: int) + @private constructor *.`` (@target self: LinkedHashSet_KeySpliterator, source: HashMap, origin: int, fence: int, est: int, expectedModCount: int) { this.index = origin; this.fence = fence; diff --git a/spec/java/util/LinkedHashSet.main.lsl b/spec/java/util/LinkedHashSet.main.lsl index 4857d3bb..1c6c2fd9 100644 --- a/spec/java/util/LinkedHashSet.main.lsl +++ b/spec/java/util/LinkedHashSet.main.lsl @@ -34,10 +34,10 @@ automaton LinkedHashSetAutomaton shift Allocated -> Initialized by [ // constructors - LinkedHashSet (LinkedHashSet), - LinkedHashSet (LinkedHashSet, Collection), - LinkedHashSet (LinkedHashSet, int), - LinkedHashSet (LinkedHashSet, int, float), + `` (LinkedHashSet), + `` (LinkedHashSet, Collection), + `` (LinkedHashSet, int), + `` (LinkedHashSet, int, float), ]; shift Initialized -> self by [ @@ -156,20 +156,20 @@ automaton LinkedHashSetAutomaton // constructors - constructor *.LinkedHashSet (@target self: LinkedHashSet) + constructor *.`` (@target self: LinkedHashSet) { this.storage = action MAP_NEW(); } - constructor *.LinkedHashSet (@target self: LinkedHashSet, c: Collection) + constructor *.`` (@target self: LinkedHashSet, c: Collection) { this.storage = action MAP_NEW(); _addAllElements(c); } - constructor *.LinkedHashSet (@target self: LinkedHashSet, initialCapacity: int) + constructor *.`` (@target self: LinkedHashSet, initialCapacity: int) { if (initialCapacity < 0) { @@ -181,7 +181,7 @@ automaton LinkedHashSetAutomaton } - constructor *.LinkedHashSet (@target self: LinkedHashSet, initialCapacity: int, loadFactor: float) + constructor *.`` (@target self: LinkedHashSet, initialCapacity: int, loadFactor: float) { if (initialCapacity < 0) { diff --git a/spec/java/util/LinkedList.Spliterator.lsl b/spec/java/util/LinkedList.Spliterator.lsl index 3a82fe85..5f102715 100644 --- a/spec/java/util/LinkedList.Spliterator.lsl +++ b/spec/java/util/LinkedList.Spliterator.lsl @@ -25,7 +25,7 @@ automaton LinkedList_SpliteratorAutomaton shift Allocated -> Initialized by [ // constructors - LinkedList_Spliterator, + ``, ]; shift Initialized -> self by [ @@ -77,10 +77,9 @@ automaton LinkedList_SpliteratorAutomaton // constructors - @private constructor *.LinkedList_Spliterator ( - @target self: LinkedList_Spliterator, - _this: LinkedList, - origin: int, fence: int, expectedModCount: int) + @private constructor *.`` (@target self: LinkedList_Spliterator, + _this: LinkedList, + origin: int, fence: int, expectedModCount: int) { // #problem: translator cannot generate and refer to private and/or inner classes, so this is effectively useless action NOT_IMPLEMENTED("inaccessible constructor"); diff --git a/spec/java/util/LinkedList.SubList.lsl b/spec/java/util/LinkedList.SubList.lsl index b68f881c..4ba9feb1 100644 --- a/spec/java/util/LinkedList.SubList.lsl +++ b/spec/java/util/LinkedList.SubList.lsl @@ -29,8 +29,8 @@ automaton LinkedList_SubListAutomaton shift Allocated -> Initialized by [ // constructors - SubList (LinkedList_SubList, LinkedList, int, int), - SubList (LinkedList_SubList, LinkedList_SubList, int, int), + `` (LinkedList_SubList, LinkedList, int, int), + `` (LinkedList_SubList, LinkedList_SubList, int, int), ]; shift Initialized -> self by [ @@ -184,14 +184,14 @@ automaton LinkedList_SubListAutomaton // constructors - constructor *.SubList (@target self: LinkedList_SubList, root: LinkedList, fromIndex: int, toIndex: int) + constructor *.`` (@target self: LinkedList_SubList, root: LinkedList, fromIndex: int, toIndex: int) { // #problem: this constructor is useless action NOT_IMPLEMENTED("inaccessible constructor"); } - @private constructor *.SubList (@target self: LinkedList_SubList, parent: LinkedList_SubList, fromIndex: int, toIndex: int) + @private constructor *.`` (@target self: LinkedList_SubList, parent: LinkedList_SubList, fromIndex: int, toIndex: int) { // #problem: this constructor is useless action NOT_IMPLEMENTED("inaccessible constructor"); diff --git a/spec/java/util/LinkedList.main.lsl b/spec/java/util/LinkedList.main.lsl index 4829dcd7..79fbf280 100644 --- a/spec/java/util/LinkedList.main.lsl +++ b/spec/java/util/LinkedList.main.lsl @@ -27,8 +27,8 @@ automaton LinkedListAutomaton shift Allocated -> Initialized by [ // constructors - LinkedList (LinkedList), - LinkedList (LinkedList, Collection), + `` (LinkedList), + `` (LinkedList, Collection), ]; shift Initialized -> self by [ @@ -550,13 +550,13 @@ automaton LinkedListAutomaton // constructors - constructor *.LinkedList (@target self: LinkedList) + constructor *.`` (@target self: LinkedList) { this.storage = action LIST_NEW(); } - constructor *.LinkedList (@target self: LinkedList, c: Collection) + constructor *.`` (@target self: LinkedList, c: Collection) { if (c == null) _throwNPE(); @@ -1180,349 +1180,3 @@ automaton LinkedListAutomaton } } - - - - - -/* -@Private -@Implements("java.util.ListIterator") -@WrapperMeta( - src="java.util.ListItr", - dst="org.utbot.engine.overrides.collections.UtListItr", - matchInterfaces=true, -) -automaton ListItr: int( - var index: int = 0, - var expectedModCount: int, - var nextWasCalled: boolean = false, - var prevWasCalled: boolean = false -) -{ - initstate Initialized; - - // constructors - shift Allocated -> Initialized by [ - ListItr(int) - ]; - - shift Initialized -> self by [ - // read operations - hasNext, - hasPrevious, - nextIndex, - previousIndex, - - // write operations - next, - remove, - previous, - set, - add, - forEachRemaining - ]; - - //constructors - - constructor ListItr (startIndex: int) - { - index = startIndex; - } - - - //methods - - fun *.hasNext (): boolean - { - result = index < self.parent.size; - } - - - fun *.next (): Object - { - checkForComodification(); - val atValidPosition = index < self.parent.length; - - if (!atValidPosition) - { - action THROW_NEW("java.util.NoSuchElementException", []); - } - - result = action LIST_GET(self.parent.storage, index); - index = index + 1; - nextWasCalled = true; - prevWasCalled = false; - } - - - fun *.hasPrevious (): boolean - { - result = index > 0; - } - - - fun *.previous (): Object - { - checkForComodification(); - val atValidPosition = index > 0; - - if (!atValidPosition) - { - action THROW_NEW("java.util.NoSuchElementException", []); - } - - index = index - 1; - result = action LIST_GET(self.parent.storage, index); - prevWasCalled = true; - nextWasCalled = false; - } - - - fun *.nextIndex (): int - { - result = index; - } - - - fun *.previousIndex (): int - { - result = index - 1; - } - - - fun *.remove (): void - { - checkForComodification(); - - if (!nextWasCalled && !prevWasCalled) - { - action THROW_NEW("java.lang.IllegalStateException", []); - } - - if (nextWasCalled) - { - self.parent._unlinkAny(index - 1); - nextWasCalled = false; - } - else - { - self.parent._unlinkAny(index); - index = index - 1; - prevWasCalled = false; - } - - expectedModCount = expectedModCount + 1; - } - - - fun *.set (e: Object): void - { - if (!nextWasCalled && !prevWasCalled) - { - action THROW_NEW("java.lang.IllegalStateException", []); - } - - checkForComodification(); - - if (nextWasCalled) - { - action LIST_SET(storage, index - 1, e); - } - else - { - action LIST_SET(storage, index, e); - } - } - - - fun *.add (e: Object): void - { - checkForComodification(); - val hasNextPosition = index < self.parent.length; - - - if (!hasNextPosition) - { - self.parent.linkAny(self.parent.size, e); - } - else - { - self.parent.linkAny(index, e); - } - - nextWasCalled = false; - prevWasCalled = false; - - index = index + 1; - expectedModCount = expectedModCount + 1; - } - - - fun *.forEachRemaining (action: Consumer): void - { - // #problem - action NOT_IMPLEMENTED(); - } - - - - proc checkForComodification (): void - { - if (self.parent.modCount != expectedModCount) - { - action THROW_NEW("java.util.ConcurrentModificationException", []); - } - } - -} -*/ - - -/* -@Private -@Implements("java.util.Iterator") -@WrapperMeta( - src="java.util.ListItr", - dst="org.utbot.engine.overrides.collections.UtDescendingIterator", - matchInterfaces=true, -) -automaton DescendingIterator: int( - var index: int = 0, - var expectedModCount: int, - var nextWasCalled: boolean = false) -{ - - initstate Initialized; - - shift Initialized -> self by [ - // read operations - hasNext, - - // write operations - next, - remove, - forEachRemaining - ]; - - - fun *.next (): Object - { - checkForComodification(); - val atValidPosition = index > 0; - - if (!atValidPosition) - { - action THROW_NEW("java.util.NoSuchElementException", []); - } - - index = index - 1; - result = action LIST_GET(self.parent.storage, index); - nextWasCalled = true; - } - - - fun *.hasNext (): boolean - { - result = index > 0; - } - - - fun *.remove (): void - { - checkForComodification(); - - if (!nextWasCalled) - { - action THROW_NEW("java.lang.IllegalStateException", []); - } - - self.parent._unlinkAny(index); - index = index - 1; - nextWasCalled = false; - - expectedModCount = expectedModCount + 1; - } - - - fun *.forEachRemaining (action: Consumer): void - { - // #problem - action NOT_IMPLEMENTED(); - } - - - proc checkForComodification (): void - { - if (self.parent.modCount != expectedModCount) - { - action THROW_NEW("java.util.ConcurrentModificationException", []); - } - } - -} -*/ - - - -/* -@Private -@Implements("java.util.Spliterator") -@WrapperMeta( - src="java.util.ListItr", - dst="org.utbot.engine.overrides.collections.UtLLSpliterator", - matchInterfaces=true, -) -automaton LLSpliterator: int( - @Final var BATCH_UNIT: int = 1 << 10, - @Final var MAX_BATCH: int = 1 << 25, - @Final var list: LinkedList, - est: int, - expectedModCount: int, - batch: int -) -{ - - //constructors - - constructor LLSpliterator (list: LinkedList, est: int, expectedModCount: int) - { - action NOT_IMPLEMENTED(); - } - - //sub's - - proc getEst (): int - { - action NOT_IMPLEMENTED(); - } - - //methods - - fun *.estimateSize (): long - { - action NOT_IMPLEMENTED(); - } - - fun *.trySplit (): Spliterator - { - action NOT_IMPLEMENTED(); - } - - fun *.forEachRemaining (action: Consumer): void - { - action NOT_IMPLEMENTED(); - } - - fun *.tryAdvance (action: Consumer): boolean - { - action NOT_IMPLEMENTED(); - } - - fun *.characteristics (): int - { - action NOT_IMPLEMENTED(); - } - -} -*/ diff --git a/spec/java/util/Optional.automata.lsl b/spec/java/util/Optional.automata.lsl index 0ece893e..5436e337 100644 --- a/spec/java/util/Optional.automata.lsl +++ b/spec/java/util/Optional.automata.lsl @@ -40,8 +40,8 @@ automaton OptionalAutomaton shift Allocated -> Initialized by [ // constructors - LSLOptional (LSLOptional), - LSLOptional (LSLOptional, Object), + `` (LSLOptional), + `` (LSLOptional, Object), // static methods empty, @@ -81,7 +81,7 @@ automaton OptionalAutomaton // constructors - @private constructor *.LSLOptional (@target @Parameterized(["T"]) self: LSLOptional) + @private constructor *.`` (@target @Parameterized(["T"]) self: LSLOptional) { action ERROR("Private constructor call"); /*assigns this.value; @@ -91,7 +91,7 @@ automaton OptionalAutomaton } - @private constructor *.LSLOptional (@target @Parameterized(["T"]) self: LSLOptional, obj: Object) + @private constructor *.`` (@target @Parameterized(["T"]) self: LSLOptional, obj: Object) { action ERROR("Private constructor call"); /*requires obj != null; diff --git a/spec/java/util/OptionalDouble.automata.lsl b/spec/java/util/OptionalDouble.automata.lsl index 3112617b..590642e3 100644 --- a/spec/java/util/OptionalDouble.automata.lsl +++ b/spec/java/util/OptionalDouble.automata.lsl @@ -40,8 +40,8 @@ automaton OptionalDoubleAutomaton shift Allocated -> Initialized by [ // constructors - LSLOptionalDouble (LSLOptionalDouble), - LSLOptionalDouble (LSLOptionalDouble, double), + `` (LSLOptionalDouble), + `` (LSLOptionalDouble, double), // static methods empty, @@ -76,13 +76,13 @@ automaton OptionalDoubleAutomaton // constructors - @private constructor *.LSLOptionalDouble (@target self: LSLOptionalDouble) + @private constructor *.`` (@target self: LSLOptionalDouble) { action NOT_IMPLEMENTED("this method can be called using reflection only"); } - @private constructor *.LSLOptionalDouble (@target self: LSLOptionalDouble, x: double) + @private constructor *.`` (@target self: LSLOptionalDouble, x: double) { action NOT_IMPLEMENTED("this method can be called using reflection only"); } diff --git a/spec/java/util/OptionalInt.automata.lsl b/spec/java/util/OptionalInt.automata.lsl index a5a92523..5ccccc15 100644 --- a/spec/java/util/OptionalInt.automata.lsl +++ b/spec/java/util/OptionalInt.automata.lsl @@ -40,8 +40,8 @@ automaton OptionalIntAutomaton shift Allocated -> Initialized by [ // constructors - LSLOptionalInt (LSLOptionalInt), - LSLOptionalInt (LSLOptionalInt, int), + `` (LSLOptionalInt), + `` (LSLOptionalInt, int), // static methods empty, @@ -76,13 +76,13 @@ automaton OptionalIntAutomaton // constructors - @private constructor *.LSLOptionalInt (@target self: LSLOptionalInt) + @private constructor *.`` (@target self: LSLOptionalInt) { action NOT_IMPLEMENTED("this method can be called using reflection only"); } - @private constructor *.LSLOptionalInt (@target self: LSLOptionalInt, x: int) + @private constructor *.`` (@target self: LSLOptionalInt, x: int) { action NOT_IMPLEMENTED("this method can be called using reflection only"); } diff --git a/spec/java/util/OptionalLong.automata.lsl b/spec/java/util/OptionalLong.automata.lsl index 353a33ed..39113ec8 100644 --- a/spec/java/util/OptionalLong.automata.lsl +++ b/spec/java/util/OptionalLong.automata.lsl @@ -40,8 +40,8 @@ automaton OptionalLongAutomaton shift Allocated -> Initialized by [ // constructors - LSLOptionalLong (LSLOptionalLong), - LSLOptionalLong (LSLOptionalLong, long), + `` (LSLOptionalLong), + `` (LSLOptionalLong, long), // static methods empty, @@ -76,13 +76,13 @@ automaton OptionalLongAutomaton // constructors - @private constructor *.LSLOptionalLong (@target self: LSLOptionalLong) + @private constructor *.`` (@target self: LSLOptionalLong) { action NOT_IMPLEMENTED("this method can be called using reflection only"); } - @private constructor *.LSLOptionalLong (@target self: LSLOptionalLong, x: long) + @private constructor *.`` (@target self: LSLOptionalLong, x: long) { action NOT_IMPLEMENTED("this method can be called using reflection only"); } diff --git a/spec/java/util/Random.main.lsl b/spec/java/util/Random.main.lsl index 559be3d6..88cf8b6a 100644 --- a/spec/java/util/Random.main.lsl +++ b/spec/java/util/Random.main.lsl @@ -30,8 +30,8 @@ automaton RandomAutomaton shift Allocated -> Initialized by [ // constructors - Random (Random), - Random (Random, long), + `` (Random), + `` (Random, long), ]; shift Initialized -> self by [ @@ -134,13 +134,13 @@ automaton RandomAutomaton // constructors - constructor *.Random (@target self: Random) + constructor *.`` (@target self: Random) { action DO_NOTHING(); } - constructor *.Random (@target self: Random, seed: long) + constructor *.`` (@target self: Random, seed: long) { action DO_NOTHING(); } diff --git a/spec/java/util/Spliterators.ArraySpliterator.lsl b/spec/java/util/Spliterators.ArraySpliterator.lsl index 749bdbec..f322bf9e 100644 --- a/spec/java/util/Spliterators.ArraySpliterator.lsl +++ b/spec/java/util/Spliterators.ArraySpliterator.lsl @@ -33,8 +33,8 @@ automaton Spliterators_ArraySpliteratorAutomaton shift Allocated -> Initialized by [ // constructors - init (Spliterators_ArraySpliterator, array, int), - init (Spliterators_ArraySpliterator, array, int, int, int), + `` (Spliterators_ArraySpliterator, array, int), + `` (Spliterators_ArraySpliterator, array, int, int, int), ]; shift Initialized -> self by [ @@ -75,8 +75,8 @@ automaton Spliterators_ArraySpliteratorAutomaton // constructors - constructor *.init (@target self: Spliterators_ArraySpliterator, - arr: array, additionalCharacteristics: int) + constructor *.`` (@target self: Spliterators_ArraySpliterator, + arr: array, additionalCharacteristics: int) { // WARNING: unused @@ -87,8 +87,8 @@ automaton Spliterators_ArraySpliteratorAutomaton } - constructor *.init (@target self: Spliterators_ArraySpliterator, - arr: array, origin: int, pFence: int, additionalCharacteristics: int) + constructor *.`` (@target self: Spliterators_ArraySpliterator, + arr: array, origin: int, pFence: int, additionalCharacteristics: int) { // WARNING: unused diff --git a/spec/java/util/Spliterators.DoubleArraySpliterator.lsl b/spec/java/util/Spliterators.DoubleArraySpliterator.lsl index 826aa634..62e491be 100644 --- a/spec/java/util/Spliterators.DoubleArraySpliterator.lsl +++ b/spec/java/util/Spliterators.DoubleArraySpliterator.lsl @@ -33,8 +33,8 @@ automaton Spliterators_DoubleArraySpliteratorAutomaton shift Allocated -> Initialized by [ // constructors - init (Spliterators_DoubleArraySpliterator, array, int), - init (Spliterators_DoubleArraySpliterator, array, int, int, int), + `` (Spliterators_DoubleArraySpliterator, array, int), + `` (Spliterators_DoubleArraySpliterator, array, int, int, int), ]; shift Initialized -> self by [ @@ -77,8 +77,8 @@ automaton Spliterators_DoubleArraySpliteratorAutomaton // constructors - constructor *.init (@target self: Spliterators_DoubleArraySpliterator, - arr: array, additionalCharacteristics: int) + constructor *.`` (@target self: Spliterators_DoubleArraySpliterator, + arr: array, additionalCharacteristics: int) { // WARNING: unused @@ -89,8 +89,8 @@ automaton Spliterators_DoubleArraySpliteratorAutomaton } - constructor *.init (@target self: Spliterators_DoubleArraySpliterator, - arr: array, origin: int, pFence: int, additionalCharacteristics: int) + constructor *.`` (@target self: Spliterators_DoubleArraySpliterator, + arr: array, origin: int, pFence: int, additionalCharacteristics: int) { // WARNING: unused diff --git a/spec/java/util/Spliterators.IntArraySpliterator.lsl b/spec/java/util/Spliterators.IntArraySpliterator.lsl index d9932e7c..b127a888 100644 --- a/spec/java/util/Spliterators.IntArraySpliterator.lsl +++ b/spec/java/util/Spliterators.IntArraySpliterator.lsl @@ -33,8 +33,8 @@ automaton Spliterators_IntArraySpliteratorAutomaton shift Allocated -> Initialized by [ // constructors - init (Spliterators_IntArraySpliterator, array, int), - init (Spliterators_IntArraySpliterator, array, int, int, int), + `` (Spliterators_IntArraySpliterator, array, int), + `` (Spliterators_IntArraySpliterator, array, int, int, int), ]; shift Initialized -> self by [ @@ -77,8 +77,8 @@ automaton Spliterators_IntArraySpliteratorAutomaton // constructors - constructor *.init (@target self: Spliterators_IntArraySpliterator, - arr: array, additionalCharacteristics: int) + constructor *.`` (@target self: Spliterators_IntArraySpliterator, + arr: array, additionalCharacteristics: int) { // WARNING: unused @@ -89,8 +89,8 @@ automaton Spliterators_IntArraySpliteratorAutomaton } - constructor *.init (@target self: Spliterators_IntArraySpliterator, - arr: array, origin: int, pFence: int, additionalCharacteristics: int) + constructor *.`` (@target self: Spliterators_IntArraySpliterator, + arr: array, origin: int, pFence: int, additionalCharacteristics: int) { // WARNING: unused diff --git a/spec/java/util/Spliterators.LongArraySpliterator.lsl b/spec/java/util/Spliterators.LongArraySpliterator.lsl index c5b0575c..69dd8267 100644 --- a/spec/java/util/Spliterators.LongArraySpliterator.lsl +++ b/spec/java/util/Spliterators.LongArraySpliterator.lsl @@ -33,8 +33,8 @@ automaton Spliterators_LongArraySpliteratorAutomaton shift Allocated -> Initialized by [ // constructors - init (Spliterators_LongArraySpliterator, array, int), - init (Spliterators_LongArraySpliterator, array, int, int, int), + `` (Spliterators_LongArraySpliterator, array, int), + `` (Spliterators_LongArraySpliterator, array, int, int, int), ]; shift Initialized -> self by [ @@ -77,8 +77,8 @@ automaton Spliterators_LongArraySpliteratorAutomaton // constructors - constructor *.init (@target self: Spliterators_LongArraySpliterator, - arr: array, additionalCharacteristics: int) + constructor *.`` (@target self: Spliterators_LongArraySpliterator, + arr: array, additionalCharacteristics: int) { // WARNING: unused @@ -89,8 +89,8 @@ automaton Spliterators_LongArraySpliteratorAutomaton } - constructor *.init (@target self: Spliterators_LongArraySpliterator, - arr: array, origin: int, pFence: int, additionalCharacteristics: int) + constructor *.`` (@target self: Spliterators_LongArraySpliterator, + arr: array, origin: int, pFence: int, additionalCharacteristics: int) { // WARNING: unused diff --git a/spec/java/util/Spliterators.main.lsl b/spec/java/util/Spliterators.main.lsl index 47bf2733..5cc8b7d1 100644 --- a/spec/java/util/Spliterators.main.lsl +++ b/spec/java/util/Spliterators.main.lsl @@ -29,7 +29,7 @@ automaton SpliteratorsAutomaton shift Allocated -> self by [ // constructors - init, + ``, // static operations emptyDoubleSpliterator, @@ -65,7 +65,7 @@ automaton SpliteratorsAutomaton // constructors - @private constructor *.init (@target self: Spliterators) + @private constructor *.`` (@target self: Spliterators) { // nothing - this is a utility class } diff --git a/spec/java/util/concurrent/atomic/AtomicBoolean.main.lsl b/spec/java/util/concurrent/atomic/AtomicBoolean.main.lsl index ce088ef3..53bf6dbe 100644 --- a/spec/java/util/concurrent/atomic/AtomicBoolean.main.lsl +++ b/spec/java/util/concurrent/atomic/AtomicBoolean.main.lsl @@ -26,8 +26,8 @@ automaton AtomicBooleanAutomaton shift Allocated -> Initialized by [ // constructors - LSLAtomicBoolean (LSLAtomicBoolean), - LSLAtomicBoolean (LSLAtomicBoolean, boolean), + `` (LSLAtomicBoolean), + `` (LSLAtomicBoolean, boolean), ]; shift Initialized -> self by [ @@ -60,13 +60,13 @@ automaton AtomicBooleanAutomaton // constructors - constructor *.LSLAtomicBoolean (@target self: LSLAtomicBoolean) + constructor *.`` (@target self: LSLAtomicBoolean) { this.value = FALSE; } - constructor *.LSLAtomicBoolean (@target self: LSLAtomicBoolean, initialValue: boolean) + constructor *.`` (@target self: LSLAtomicBoolean, initialValue: boolean) { if (initialValue) this.value = TRUE; diff --git a/spec/java/util/concurrent/atomic/AtomicInteger.main.lsl b/spec/java/util/concurrent/atomic/AtomicInteger.main.lsl index 6c67a3b9..fe261391 100644 --- a/spec/java/util/concurrent/atomic/AtomicInteger.main.lsl +++ b/spec/java/util/concurrent/atomic/AtomicInteger.main.lsl @@ -29,8 +29,8 @@ automaton AtomicIntegerAutomaton shift Allocated -> Initialized by [ // constructors - LSLAtomicInteger (LSLAtomicInteger), - LSLAtomicInteger (LSLAtomicInteger, int), + `` (LSLAtomicInteger), + `` (LSLAtomicInteger, int), ]; shift Initialized -> self by [ @@ -79,13 +79,13 @@ automaton AtomicIntegerAutomaton // constructors - constructor *.LSLAtomicInteger (@target self: LSLAtomicInteger) + constructor *.`` (@target self: LSLAtomicInteger) { this.value = 0; } - constructor *.LSLAtomicInteger (@target self: LSLAtomicInteger, initialValue: int) + constructor *.`` (@target self: LSLAtomicInteger, initialValue: int) { this.value = initialValue; } diff --git a/spec/java/util/concurrent/atomic/AtomicLong.main.lsl b/spec/java/util/concurrent/atomic/AtomicLong.main.lsl index 3a33ecae..bb808ddc 100644 --- a/spec/java/util/concurrent/atomic/AtomicLong.main.lsl +++ b/spec/java/util/concurrent/atomic/AtomicLong.main.lsl @@ -29,8 +29,8 @@ automaton AtomicLongAutomaton shift Allocated -> Initialized by [ // constructors - LSLAtomicLong (LSLAtomicLong), - LSLAtomicLong (LSLAtomicLong, long), + `` (LSLAtomicLong), + `` (LSLAtomicLong, long), ]; shift Initialized -> self by [ @@ -79,13 +79,13 @@ automaton AtomicLongAutomaton // constructors - constructor *.LSLAtomicLong (@target self: LSLAtomicLong) + constructor *.`` (@target self: LSLAtomicLong) { this.value = 0L; } - constructor *.LSLAtomicLong (@target self: LSLAtomicLong, initialValue: long) + constructor *.`` (@target self: LSLAtomicLong, initialValue: long) { this.value = initialValue; } diff --git a/spec/java/util/concurrent/atomic/AtomicReference.main.lsl b/spec/java/util/concurrent/atomic/AtomicReference.main.lsl index 290639f4..92dfdfaa 100644 --- a/spec/java/util/concurrent/atomic/AtomicReference.main.lsl +++ b/spec/java/util/concurrent/atomic/AtomicReference.main.lsl @@ -30,8 +30,8 @@ automaton AtomicReferenceAutomaton shift Allocated -> Initialized by [ // constructors - LSLAtomicReference (LSLAtomicReference), - LSLAtomicReference (LSLAtomicReference, Object), + `` (LSLAtomicReference), + `` (LSLAtomicReference, Object), ]; shift Initialized -> self by [ @@ -68,13 +68,13 @@ automaton AtomicReferenceAutomaton // constructors - constructor *.LSLAtomicReference (@target self: LSLAtomicReference) + constructor *.`` (@target self: LSLAtomicReference) { this.value = null; } - constructor *.LSLAtomicReference (@target self: LSLAtomicReference, initialValue: Object) + constructor *.`` (@target self: LSLAtomicReference, initialValue: Object) { this.value = initialValue; } diff --git a/spec/java/util/zip/CRC32.automaton.lsl b/spec/java/util/zip/CRC32.automaton.lsl index 3d59559c..127e1d52 100644 --- a/spec/java/util/zip/CRC32.automaton.lsl +++ b/spec/java/util/zip/CRC32.automaton.lsl @@ -26,7 +26,7 @@ automaton CRC32Automaton shift Allocated -> Initialized by [ // constructors - CRC32, + ``, ]; shift Initialized -> self by [ @@ -95,7 +95,7 @@ automaton CRC32Automaton // constructors - constructor *.CRC32 (@target self: CRC32) + constructor *.`` (@target self: CRC32) { // original constructor is empty } From b9463ee6200b630e4f4bda307436a2e5b1c154e6 Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Mon, 11 Dec 2023 08:46:48 +0300 Subject: [PATCH 76/78] Added implementation to `java.lang.Object#clone` method --- spec/java/lang/Object.main.lsl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/spec/java/lang/Object.main.lsl b/spec/java/lang/Object.main.lsl index 52bdaef7..62f356fb 100644 --- a/spec/java/lang/Object.main.lsl +++ b/spec/java/lang/Object.main.lsl @@ -62,9 +62,11 @@ automaton ObjectAutomaton } - @Phantom @protected fun *.clone (@target self: LSLObject): Object + @throws(["java.lang.CloneNotSupportedException"]) + @protected fun *.clone (@target self: LSLObject): Object { - // NOTE: using the original method + if (true) // <- fooling Java compiler to not give "unreachable statement" error + action THROW_NEW("java.lang.CloneNotSupportedException", []); } From 6c787b0e07fbdefdd15db12bd68dff03772c4c2b Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Tue, 12 Dec 2023 04:01:18 +0300 Subject: [PATCH 77/78] Fixed a typo in class name --- spec/libsl/utils/VoidInputStream.lsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/libsl/utils/VoidInputStream.lsl b/spec/libsl/utils/VoidInputStream.lsl index 5ab46a8e..c38a9d1b 100644 --- a/spec/libsl/utils/VoidInputStream.lsl +++ b/spec/libsl/utils/VoidInputStream.lsl @@ -16,7 +16,7 @@ import java/io/InputStream; @GenerateMe @extends("java.io.InputStream") @public @final type VoidInputStream - is `libsl.utils.VoldInputStream` + is `libsl.utils.VoidInputStream` for InputStream { } From db77c7d85178e24793c6b9c6841315e4c2959dba Mon Sep 17 00:00:00 2001 From: Mikhail Onischuck <43421682+dog-m@users.noreply.github.com> Date: Tue, 12 Dec 2023 09:12:53 +0300 Subject: [PATCH 78/78] Improved `java.lang.Object#clone` method --- spec/java/lang/Object.main.lsl | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/spec/java/lang/Object.main.lsl b/spec/java/lang/Object.main.lsl index 62f356fb..1729e014 100644 --- a/spec/java/lang/Object.main.lsl +++ b/spec/java/lang/Object.main.lsl @@ -8,6 +8,7 @@ library std // imports import java/lang/Class; +import java/lang/Cloneable; import java/lang/Object; import java/lang/String; @@ -65,8 +66,15 @@ automaton ObjectAutomaton @throws(["java.lang.CloneNotSupportedException"]) @protected fun *.clone (@target self: LSLObject): Object { - if (true) // <- fooling Java compiler to not give "unreachable statement" error + if (self is Cloneable == false) action THROW_NEW("java.lang.CloneNotSupportedException", []); + + result = action SYMBOLIC("java.lang.Object"); + action ASSUME(result != null); + + val thisType: Class = action TYPE_OF(self); + val cloneType: Class = action TYPE_OF(result); + action ASSUME(thisType == cloneType); }