Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import org.usvm.ts.pbt.backend.PropertyRunConfiguration
import org.usvm.ts.pbt.backend.PropertyRunStatus
import org.usvm.ts.pbt.fastcheck.FastCheckBackend
import org.usvm.ts.pbt.fastcheck.FastCheckRuntime
import org.usvm.ts.pbt.fastcheck.TypeScriptLocalSourceClosure
import org.usvm.ts.pbt.model.ArrayDomain
import org.usvm.ts.pbt.model.BooleanDomain
import org.usvm.ts.pbt.model.ConstantDomain
Expand Down Expand Up @@ -269,6 +270,9 @@ internal class OriginalTypeScriptClassReplayer(
sourceOverride: String? = null,
overrideSourceFile: String? = null,
private val counterGlobalName: String? = null,
// Saved environments may replay naturally evaluated initializers outside the lifecycle oracle's checked subset.
// The supplied graph still passes the normal copy/hash checks and cannot contain unresolved module boundaries.
sourceClosure: TypeScriptLocalSourceClosure? = null,
) : AutoCloseable {
private val root = sourceRoot.toRealPath()
private val workspace = Files.createTempDirectory("usvm-calls-class-replay-")
Expand All @@ -282,7 +286,15 @@ internal class OriginalTypeScriptClassReplayer(
require(
(sourceOverride == null) == (overrideSourceFile == null)
) { "Source override needs a relative target file" }
val closure = checkedCallsSourceClosure(root = root, entry = root.resolve(function.sourceFile))
val closure = sourceClosure ?: checkedCallsSourceClosure(
root = root,
entry = root.resolve(function.sourceFile),
)
val closureResolved = closure.reasonCode == null && function.sourceFile in closure.files &&
closure.resolution?.runtimeBoundaries.orEmpty().isEmpty()
require(closureResolved) {
"Native replay requires a resolved closure containing its harness"
}
copyCallsSourceClosure(root = root, destination = overlay, closure = closure)
if (overrideSourceFile != null) {
require(overrideSourceFile in closure.files) { "Replay override is outside the frozen runtime closure" }
Expand Down Expand Up @@ -452,7 +464,7 @@ ${classReplayThrownValueDiagnosticSource().prependIndent(indent = " ")}
""".trimIndent() + "\n"
}

private fun classReplayValueEncoderSource(): String = """
internal fun classReplayValueEncoderSource(): String = """
function encode(value: unknown, seen = new Set<object>()): unknown {
if (value === undefined) return { kind: 'undefined' };
if (value === null) return { kind: 'null' };
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,28 @@
package org.usvm.ts.calls

/** Input slots have already passed the Kotlin primitive-only journal schema. */
internal fun callsConcretePrimitiveDecoderSource(): String = """
function decodeCallsConcretePrimitive(value: any): any {
switch (value.kind) {
case 'undefined': return undefined;
case 'null': return null;
case 'boolean': case 'string': return value.value;
case 'number':
switch (value.value) {
case 'nan': return NaN;
case 'positive-infinity': return Infinity;
case 'negative-infinity': return -Infinity;
case 'finite': {
const view = new DataView(new ArrayBuffer(8));
view.setBigUint64(0, BigInt('0x' + value.bits), false);
return view.getFloat64(0, false);
}
}
}
throw Error('Invalid saved input primitive');
}
""".trimIndent()

/** Used inside the existing native replay wrapper with its lossless primitive decoder and exact prototype registry. */
internal fun callsConcreteHeapRestoreSource(): String = """
function restoreCallsConcreteHeap(graph: any, prototypes: Map<string, object>, decodePrimitive: (x: any) => any,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ fun main(args: Array<String>) {
"class-catalog" -> runClassCatalog(args.drop(1))
"class-start-smoke" -> runClassStartSmoke(args.drop(1))
"class-symbolic-probe" -> runClassSymbolicProbe(args.drop(1))
"class-replay-input" -> runSavedInputReplay(args.drop(1))
"class-prepare" -> runClassPrepare(args.drop(1))
"class-preflight" -> runClassPreflight(args.drop(1))
"class-cell" -> runClassCell(args.drop(1))
Expand Down Expand Up @@ -108,6 +109,7 @@ private fun usage(): String = """
calls class-catalog
calls class-start-smoke <startup-manifest.json> <class-id> <output-directory>
calls class-symbolic-probe <startup-manifest.json> <class-id> <output-directory>
calls class-replay-input <startup-manifest.json> <class-id> <probe-directory> <state-id> <timeout-ms> <output.json>
calls class-prepare <class-manifest.json> <prepared-directory>
calls class-preflight <prepared-directory> <class-id> <preflight-ms>
calls class-cell <prepared-directory> <class-id> <profile> <seed> <budget-ms> <output-directory>
Expand Down
Loading
Loading