Refactor scope pooling logic for robustness and efficiency, optimize argument assignment, and enhance benchmarks with pool-specific scenarios.
This commit is contained in:
1 parent
6b957ae6a3
commit
8f04b25fcb
5 files changed
+133
-53
No files matched your search
@@ -51,6 +51,32 @@ data class ArgsDeclaration(val params: List<Item>, val endTokenType: Token.Type)
|
||||
defaultVisibility: Visibility = Visibility.Public,
|
||||
declaringClass: net.sergeych.lyng.obj.ObjClass? = scope.currentClassCtx
|
||||
) {
|
||||
// Fast path for simple positional-only calls with no ellipsis and no defaults
|
||||
if (arguments.named.isEmpty() && !arguments.tailBlockMode) {
|
||||
var hasComplex = false
|
||||
for (p in params) {
|
||||
if (p.isEllipsis || p.defaultValue != null) {
|
||||
hasComplex = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if (!hasComplex) {
|
||||
if (arguments.list.size != params.size)
|
||||
scope.raiseIllegalArgument("expected ${params.size} arguments, got ${arguments.list.size}")
|
||||
|
||||
for (i in params.indices) {
|
||||
val a = params[i]
|
||||
val value = arguments.list[i]
|
||||
scope.addItem(a.name, (a.accessType ?: defaultAccessType).isMutable,
|
||||
value.byValueCopy(),
|
||||
a.visibility ?: defaultVisibility,
|
||||
recordType = ObjRecord.Type.Argument,
|
||||
declaringClass = declaringClass)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
fun assign(a: Item, value: Obj) {
|
||||
scope.addItem(a.name, (a.accessType ?: defaultAccessType).isMutable,
|
||||
value.byValueCopy(),
|
||||
|
||||
@@ -70,9 +70,8 @@ open class Scope(
|
||||
|
||||
internal fun findExtension(receiverClass: ObjClass, name: String): ObjRecord? {
|
||||
var s: Scope? = this
|
||||
val visited = HashSet<Long>(4)
|
||||
while (s != null) {
|
||||
if (!visited.add(s.frameId)) break
|
||||
var hops = 0
|
||||
while (s != null && hops++ < 1024) {
|
||||
// Proximity rule: check all extensions in the current scope before going to parent.
|
||||
// Priority within scope: more specific class in MRO wins.
|
||||
for (cls in receiverClass.mro) {
|
||||
@@ -108,7 +107,7 @@ open class Scope(
|
||||
*/
|
||||
internal fun tryGetLocalRecord(s: Scope, name: String, caller: net.sergeych.lyng.obj.ObjClass?): ObjRecord? {
|
||||
caller?.let { ctx ->
|
||||
s.objects["${ctx.className}::$name"]?.let { rec ->
|
||||
s.objects[ctx.mangledName(name)]?.let { rec ->
|
||||
if (rec.visibility == Visibility.Private) return rec
|
||||
}
|
||||
}
|
||||
@@ -116,7 +115,7 @@ open class Scope(
|
||||
if (rec.declaringClass == null || canAccessMember(rec.visibility, rec.declaringClass, caller)) return rec
|
||||
}
|
||||
caller?.let { ctx ->
|
||||
s.localBindings["${ctx.className}::$name"]?.let { rec ->
|
||||
s.localBindings[ctx.mangledName(name)]?.let { rec ->
|
||||
if (rec.visibility == Visibility.Private) return rec
|
||||
}
|
||||
}
|
||||
@@ -132,11 +131,10 @@ open class Scope(
|
||||
|
||||
internal fun chainLookupIgnoreClosure(name: String, followClosure: Boolean = false, caller: net.sergeych.lyng.obj.ObjClass? = null): ObjRecord? {
|
||||
var s: Scope? = this
|
||||
// use frameId to detect unexpected structural cycles in the parent chain
|
||||
val visited = HashSet<Long>(4)
|
||||
// use hop counter to detect unexpected structural cycles in the parent chain
|
||||
var hops = 0
|
||||
val effectiveCaller = caller ?: currentClassCtx
|
||||
while (s != null) {
|
||||
if (!visited.add(s.frameId)) return null
|
||||
while (s != null && hops++ < 1024) {
|
||||
tryGetLocalRecord(s, name, effectiveCaller)?.let { return it }
|
||||
s = if (followClosure && s is ClosureScope) s.closureScope else s.parent
|
||||
}
|
||||
@@ -155,9 +153,8 @@ open class Scope(
|
||||
tryGetLocalRecord(this, name, currentClassCtx)?.let { return it }
|
||||
// 2) walk parents for plain locals/bindings only
|
||||
var s = parent
|
||||
val visited = HashSet<Long>(4)
|
||||
while (s != null) {
|
||||
if (!visited.add(s.frameId)) return null
|
||||
var hops = 0
|
||||
while (s != null && hops++ < 1024) {
|
||||
tryGetLocalRecord(s, name, currentClassCtx)?.let { return it }
|
||||
s = s.parent
|
||||
}
|
||||
@@ -182,9 +179,8 @@ open class Scope(
|
||||
*/
|
||||
internal fun chainLookupWithMembers(name: String, caller: net.sergeych.lyng.obj.ObjClass? = currentClassCtx, followClosure: Boolean = false): ObjRecord? {
|
||||
var s: Scope? = this
|
||||
val visited = HashSet<Long>(4)
|
||||
while (s != null) {
|
||||
if (!visited.add(s.frameId)) return null
|
||||
var hops = 0
|
||||
while (s != null && hops++ < 1024) {
|
||||
tryGetLocalRecord(s, name, caller)?.let { return it }
|
||||
for (cls in s.thisObj.objClass.mro) {
|
||||
s.extensions[cls]?.get(name)?.let { return it }
|
||||
@@ -396,6 +392,20 @@ open class Scope(
|
||||
nameToSlot[name]?.let { slots[it] = record }
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all references and maps to prevent memory leaks when pooled.
|
||||
*/
|
||||
fun scrub() {
|
||||
this.parent = null
|
||||
this.skipScopeCreation = false
|
||||
this.currentClassCtx = null
|
||||
objects.clear()
|
||||
slots.clear()
|
||||
nameToSlot.clear()
|
||||
localBindings.clear()
|
||||
extensions.clear()
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset this scope instance so it can be safely reused as a fresh child frame.
|
||||
* Clears locals and slots, assigns new frameId, and sets parent/args/pos/thisObj.
|
||||
@@ -414,7 +424,6 @@ open class Scope(
|
||||
nameToSlot.clear()
|
||||
localBindings.clear()
|
||||
extensions.clear()
|
||||
this.currentClassCtx = parent?.currentClassCtx
|
||||
// Now safe to validate and re-parent
|
||||
ensureNoCycle(parent)
|
||||
this.parent = parent
|
||||
@@ -534,11 +543,15 @@ open class Scope(
|
||||
}
|
||||
}
|
||||
// Map to a slot for fast local access (ensure consistency)
|
||||
val idx = getSlotIndexOf(name)
|
||||
if (idx == null) {
|
||||
if (nameToSlot.isEmpty()) {
|
||||
allocateSlotFor(name, rec)
|
||||
} else {
|
||||
slots[idx] = rec
|
||||
val idx = nameToSlot[name]
|
||||
if (idx == null) {
|
||||
allocateSlotFor(name, rec)
|
||||
} else {
|
||||
slots[idx] = rec
|
||||
}
|
||||
}
|
||||
return rec
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user