small optimizations
This commit is contained in:
parent
2d721101dd
commit
813ebebddd
@ -55,9 +55,10 @@ Special syntax allows to insert key-value pair from the variable which name shou
|
|||||||
```
|
```
|
||||||
val foo = "bar"
|
val foo = "bar"
|
||||||
val bar = "buzz"
|
val bar = "buzz"
|
||||||
assertEquals( {foo: "bar", bar: "buzz"}, { foo, bar } )
|
assertEquals( {foo: "bar", bar: "buzz"}, { *foo, *bar } )
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Question to the AI: maybe better syntax than asterisk for that case?
|
||||||
|
|
||||||
So, summarizing, overwriting/duplication rules are:
|
So, summarizing, overwriting/duplication rules are:
|
||||||
|
|
||||||
@ -74,7 +75,8 @@ This approach resolves the ambiguity from lambda syntax, as
|
|||||||
map_literal start = "{", ws, (s1 | s2 | s3)
|
map_literal start = "{", ws, (s1 | s2 | s3)
|
||||||
s1 = string_literal, ws, ":", ws, expression
|
s1 = string_literal, ws, ":", ws, expression
|
||||||
s2 = "...", string_literal
|
s2 = "...", string_literal
|
||||||
s3 = string_literal, ("," | "}")
|
s3 = "*", string_literal
|
||||||
```
|
```
|
||||||
is not a valid lambda beginning.
|
|
||||||
|
as we can see, `map_literal_start` is not a valid lambda beginning so it is not create ambiguity.
|
||||||
|
|
||||||
|
|||||||
@ -165,9 +165,9 @@ data class ParsedArgument(
|
|||||||
if (x.name != null) {
|
if (x.name != null) {
|
||||||
// Named argument
|
// Named argument
|
||||||
if (named == null) named = linkedMapOf()
|
if (named == null) named = linkedMapOf()
|
||||||
if (named!!.containsKey(x.name)) scope.raiseIllegalArgument("argument '${x.name}' is already set")
|
if (named.containsKey(x.name)) scope.raiseIllegalArgument("argument '${x.name}' is already set")
|
||||||
val v = x.value.execute(scope)
|
val v = x.value.execute(scope)
|
||||||
named!![x.name] = v
|
named[x.name] = v
|
||||||
namedSeen = true
|
namedSeen = true
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -181,8 +181,8 @@ data class ParsedArgument(
|
|||||||
for ((k, v) in value.map) {
|
for ((k, v) in value.map) {
|
||||||
if (k !is ObjString) scope.raiseIllegalArgument("named splat expects a Map with string keys")
|
if (k !is ObjString) scope.raiseIllegalArgument("named splat expects a Map with string keys")
|
||||||
val key = k.value
|
val key = k.value
|
||||||
if (named!!.containsKey(key)) scope.raiseIllegalArgument("argument '$key' is already set")
|
if (named.containsKey(key)) scope.raiseIllegalArgument("argument '$key' is already set")
|
||||||
named!![key] = v
|
named[key] = v
|
||||||
}
|
}
|
||||||
namedSeen = true
|
namedSeen = true
|
||||||
}
|
}
|
||||||
@ -226,17 +226,16 @@ data class ParsedArgument(
|
|||||||
|
|
||||||
fun firstAndOnly(pos: Pos = Pos.UNKNOWN): Obj {
|
fun firstAndOnly(pos: Pos = Pos.UNKNOWN): Obj {
|
||||||
if (list.size != 1) throw ScriptError(pos, "expected one argument, got ${list.size}")
|
if (list.size != 1) throw ScriptError(pos, "expected one argument, got ${list.size}")
|
||||||
val v = list.first()
|
|
||||||
// Tiny micro-alloc win: avoid byValueCopy for immutable singletons
|
// Tiny micro-alloc win: avoid byValueCopy for immutable singletons
|
||||||
return when (v) {
|
return when (val v = list.first()) {
|
||||||
net.sergeych.lyng.obj.ObjNull,
|
ObjNull,
|
||||||
net.sergeych.lyng.obj.ObjTrue,
|
ObjTrue,
|
||||||
net.sergeych.lyng.obj.ObjFalse,
|
ObjFalse,
|
||||||
// Immutable scalars: safe to return directly
|
// Immutable scalars: safe to return directly
|
||||||
is net.sergeych.lyng.obj.ObjInt,
|
is ObjInt,
|
||||||
is net.sergeych.lyng.obj.ObjReal,
|
is ObjReal,
|
||||||
is net.sergeych.lyng.obj.ObjChar,
|
is ObjChar,
|
||||||
is net.sergeych.lyng.obj.ObjString -> v
|
is ObjString -> v
|
||||||
else -> v.byValueCopy()
|
else -> v.byValueCopy()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,6 +15,8 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("INLINE_NOT_NEEDED", "REDUNDANT_INLINE")
|
||||||
|
|
||||||
package net.sergeych.lyng.obj
|
package net.sergeych.lyng.obj
|
||||||
|
|
||||||
import net.sergeych.lyng.*
|
import net.sergeych.lyng.*
|
||||||
@ -62,9 +64,9 @@ enum class BinOp {
|
|||||||
/** R-value reference for unary operations. */
|
/** R-value reference for unary operations. */
|
||||||
class UnaryOpRef(private val op: UnaryOp, private val a: ObjRef) : ObjRef {
|
class UnaryOpRef(private val op: UnaryOp, private val a: ObjRef) : ObjRef {
|
||||||
override suspend fun get(scope: Scope): ObjRecord {
|
override suspend fun get(scope: Scope): ObjRecord {
|
||||||
val fastRval = net.sergeych.lyng.PerfFlags.RVAL_FASTPATH
|
val fastRval = PerfFlags.RVAL_FASTPATH
|
||||||
val v = if (fastRval) a.evalValue(scope) else a.get(scope).value
|
val v = if (fastRval) a.evalValue(scope) else a.get(scope).value
|
||||||
if (net.sergeych.lyng.PerfFlags.PRIMITIVE_FASTOPS) {
|
if (PerfFlags.PRIMITIVE_FASTOPS) {
|
||||||
val rFast: Obj? = when (op) {
|
val rFast: Obj? = when (op) {
|
||||||
UnaryOp.NOT -> if (v is ObjBool) if (!v.value) ObjTrue else ObjFalse else null
|
UnaryOp.NOT -> if (v is ObjBool) if (!v.value) ObjTrue else ObjFalse else null
|
||||||
UnaryOp.NEGATE -> when (v) {
|
UnaryOp.NEGATE -> when (v) {
|
||||||
@ -75,7 +77,7 @@ class UnaryOpRef(private val op: UnaryOp, private val a: ObjRef) : ObjRef {
|
|||||||
UnaryOp.BITNOT -> if (v is ObjInt) ObjInt(v.value.inv()) else null
|
UnaryOp.BITNOT -> if (v is ObjInt) ObjInt(v.value.inv()) else null
|
||||||
}
|
}
|
||||||
if (rFast != null) {
|
if (rFast != null) {
|
||||||
if (net.sergeych.lyng.PerfFlags.PIC_DEBUG_COUNTERS) net.sergeych.lyng.PerfStats.primitiveFastOpsHit++
|
if (PerfFlags.PIC_DEBUG_COUNTERS) PerfStats.primitiveFastOpsHit++
|
||||||
return rFast.asReadonly
|
return rFast.asReadonly
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -91,11 +93,11 @@ class UnaryOpRef(private val op: UnaryOp, private val a: ObjRef) : ObjRef {
|
|||||||
/** R-value reference for binary operations. */
|
/** R-value reference for binary operations. */
|
||||||
class BinaryOpRef(private val op: BinOp, private val left: ObjRef, private val right: ObjRef) : ObjRef {
|
class BinaryOpRef(private val op: BinOp, private val left: ObjRef, private val right: ObjRef) : ObjRef {
|
||||||
override suspend fun get(scope: Scope): ObjRecord {
|
override suspend fun get(scope: Scope): ObjRecord {
|
||||||
val a = if (net.sergeych.lyng.PerfFlags.RVAL_FASTPATH) left.evalValue(scope) else left.get(scope).value
|
val a = if (PerfFlags.RVAL_FASTPATH) left.evalValue(scope) else left.get(scope).value
|
||||||
val b = if (net.sergeych.lyng.PerfFlags.RVAL_FASTPATH) right.evalValue(scope) else right.get(scope).value
|
val b = if (PerfFlags.RVAL_FASTPATH) right.evalValue(scope) else right.get(scope).value
|
||||||
|
|
||||||
// Primitive fast paths for common cases (guarded by PerfFlags.PRIMITIVE_FASTOPS)
|
// Primitive fast paths for common cases (guarded by PerfFlags.PRIMITIVE_FASTOPS)
|
||||||
if (net.sergeych.lyng.PerfFlags.PRIMITIVE_FASTOPS) {
|
if (PerfFlags.PRIMITIVE_FASTOPS) {
|
||||||
// Fast boolean ops when both operands are ObjBool
|
// Fast boolean ops when both operands are ObjBool
|
||||||
if (a is ObjBool && b is ObjBool) {
|
if (a is ObjBool && b is ObjBool) {
|
||||||
val r: Obj? = when (op) {
|
val r: Obj? = when (op) {
|
||||||
@ -106,7 +108,7 @@ class BinaryOpRef(private val op: BinOp, private val left: ObjRef, private val r
|
|||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
if (r != null) {
|
if (r != null) {
|
||||||
if (net.sergeych.lyng.PerfFlags.PIC_DEBUG_COUNTERS) net.sergeych.lyng.PerfStats.primitiveFastOpsHit++
|
if (PerfFlags.PIC_DEBUG_COUNTERS) PerfStats.primitiveFastOpsHit++
|
||||||
return r.asReadonly
|
return r.asReadonly
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -134,7 +136,7 @@ class BinaryOpRef(private val op: BinOp, private val left: ObjRef, private val r
|
|||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
if (r != null) {
|
if (r != null) {
|
||||||
if (net.sergeych.lyng.PerfFlags.PIC_DEBUG_COUNTERS) net.sergeych.lyng.PerfStats.primitiveFastOpsHit++
|
if (PerfFlags.PIC_DEBUG_COUNTERS) PerfStats.primitiveFastOpsHit++
|
||||||
return r.asReadonly
|
return r.asReadonly
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -151,7 +153,7 @@ class BinaryOpRef(private val op: BinOp, private val left: ObjRef, private val r
|
|||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
if (r != null) {
|
if (r != null) {
|
||||||
if (net.sergeych.lyng.PerfFlags.PIC_DEBUG_COUNTERS) net.sergeych.lyng.PerfStats.primitiveFastOpsHit++
|
if (PerfFlags.PIC_DEBUG_COUNTERS) PerfStats.primitiveFastOpsHit++
|
||||||
return r.asReadonly
|
return r.asReadonly
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -169,7 +171,7 @@ class BinaryOpRef(private val op: BinOp, private val left: ObjRef, private val r
|
|||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
if (r != null) {
|
if (r != null) {
|
||||||
if (net.sergeych.lyng.PerfFlags.PIC_DEBUG_COUNTERS) net.sergeych.lyng.PerfStats.primitiveFastOpsHit++
|
if (PerfFlags.PIC_DEBUG_COUNTERS) PerfStats.primitiveFastOpsHit++
|
||||||
return r.asReadonly
|
return r.asReadonly
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -177,19 +179,19 @@ class BinaryOpRef(private val op: BinOp, private val left: ObjRef, private val r
|
|||||||
if (op == BinOp.PLUS) {
|
if (op == BinOp.PLUS) {
|
||||||
when {
|
when {
|
||||||
a is ObjString && b is ObjInt -> {
|
a is ObjString && b is ObjInt -> {
|
||||||
if (net.sergeych.lyng.PerfFlags.PIC_DEBUG_COUNTERS) net.sergeych.lyng.PerfStats.primitiveFastOpsHit++
|
if (PerfFlags.PIC_DEBUG_COUNTERS) PerfStats.primitiveFastOpsHit++
|
||||||
return ObjString(a.value + b.value.toString()).asReadonly
|
return ObjString(a.value + b.value.toString()).asReadonly
|
||||||
}
|
}
|
||||||
a is ObjString && b is ObjChar -> {
|
a is ObjString && b is ObjChar -> {
|
||||||
if (net.sergeych.lyng.PerfFlags.PIC_DEBUG_COUNTERS) net.sergeych.lyng.PerfStats.primitiveFastOpsHit++
|
if (PerfFlags.PIC_DEBUG_COUNTERS) PerfStats.primitiveFastOpsHit++
|
||||||
return ObjString(a.value + b.value).asReadonly
|
return ObjString(a.value + b.value).asReadonly
|
||||||
}
|
}
|
||||||
b is ObjString && a is ObjInt -> {
|
b is ObjString && a is ObjInt -> {
|
||||||
if (net.sergeych.lyng.PerfFlags.PIC_DEBUG_COUNTERS) net.sergeych.lyng.PerfStats.primitiveFastOpsHit++
|
if (PerfFlags.PIC_DEBUG_COUNTERS) PerfStats.primitiveFastOpsHit++
|
||||||
return ObjString(a.value.toString() + b.value).asReadonly
|
return ObjString(a.value.toString() + b.value).asReadonly
|
||||||
}
|
}
|
||||||
b is ObjString && a is ObjChar -> {
|
b is ObjString && a is ObjChar -> {
|
||||||
if (net.sergeych.lyng.PerfFlags.PIC_DEBUG_COUNTERS) net.sergeych.lyng.PerfStats.primitiveFastOpsHit++
|
if (PerfFlags.PIC_DEBUG_COUNTERS) PerfStats.primitiveFastOpsHit++
|
||||||
return ObjString(a.value.toString() + b.value).asReadonly
|
return ObjString(a.value.toString() + b.value).asReadonly
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -213,7 +215,7 @@ class BinaryOpRef(private val op: BinOp, private val left: ObjRef, private val r
|
|||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
if (rNum != null) {
|
if (rNum != null) {
|
||||||
if (net.sergeych.lyng.PerfFlags.PIC_DEBUG_COUNTERS) net.sergeych.lyng.PerfStats.primitiveFastOpsHit++
|
if (PerfFlags.PIC_DEBUG_COUNTERS) PerfStats.primitiveFastOpsHit++
|
||||||
return rNum.asReadonly
|
return rNum.asReadonly
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -260,7 +262,7 @@ class ConditionalRef(
|
|||||||
private val ifFalse: ObjRef
|
private val ifFalse: ObjRef
|
||||||
) : ObjRef {
|
) : ObjRef {
|
||||||
override suspend fun get(scope: Scope): ObjRecord {
|
override suspend fun get(scope: Scope): ObjRecord {
|
||||||
val condVal = if (net.sergeych.lyng.PerfFlags.RVAL_FASTPATH) condition.evalValue(scope) else condition.get(scope).value
|
val condVal = if (PerfFlags.RVAL_FASTPATH) condition.evalValue(scope) else condition.get(scope).value
|
||||||
val condTrue = when (condVal) {
|
val condTrue = when (condVal) {
|
||||||
is ObjBool -> condVal.value
|
is ObjBool -> condVal.value
|
||||||
is ObjInt -> condVal.value != 0L
|
is ObjInt -> condVal.value != 0L
|
||||||
@ -279,8 +281,8 @@ class CastRef(
|
|||||||
private val atPos: Pos,
|
private val atPos: Pos,
|
||||||
) : ObjRef {
|
) : ObjRef {
|
||||||
override suspend fun get(scope: Scope): ObjRecord {
|
override suspend fun get(scope: Scope): ObjRecord {
|
||||||
val v0 = if (net.sergeych.lyng.PerfFlags.RVAL_FASTPATH) valueRef.evalValue(scope) else valueRef.get(scope).value
|
val v0 = if (PerfFlags.RVAL_FASTPATH) valueRef.evalValue(scope) else valueRef.get(scope).value
|
||||||
val t = if (net.sergeych.lyng.PerfFlags.RVAL_FASTPATH) typeRef.evalValue(scope) else typeRef.get(scope).value
|
val t = if (PerfFlags.RVAL_FASTPATH) typeRef.evalValue(scope) else typeRef.get(scope).value
|
||||||
val target = (t as? ObjClass) ?: scope.raiseClassCastError("${'$'}t is not the class instance")
|
val target = (t as? ObjClass) ?: scope.raiseClassCastError("${'$'}t is not the class instance")
|
||||||
// unwrap qualified views
|
// unwrap qualified views
|
||||||
val v = when (v0) {
|
val v = when (v0) {
|
||||||
@ -323,7 +325,7 @@ class AssignOpRef(
|
|||||||
) : ObjRef {
|
) : ObjRef {
|
||||||
override suspend fun get(scope: Scope): ObjRecord {
|
override suspend fun get(scope: Scope): ObjRecord {
|
||||||
val x = target.get(scope).value
|
val x = target.get(scope).value
|
||||||
val y = if (net.sergeych.lyng.PerfFlags.RVAL_FASTPATH) value.evalValue(scope) else value.get(scope).value
|
val y = if (PerfFlags.RVAL_FASTPATH) value.evalValue(scope) else value.get(scope).value
|
||||||
val inPlace: Obj? = when (op) {
|
val inPlace: Obj? = when (op) {
|
||||||
BinOp.PLUS -> x.plusAssign(scope, y)
|
BinOp.PLUS -> x.plusAssign(scope, y)
|
||||||
BinOp.MINUS -> x.minusAssign(scope, y)
|
BinOp.MINUS -> x.minusAssign(scope, y)
|
||||||
@ -380,7 +382,7 @@ class IncDecRef(
|
|||||||
/** Elvis operator reference: a ?: b */
|
/** Elvis operator reference: a ?: b */
|
||||||
class ElvisRef(private val left: ObjRef, private val right: ObjRef) : ObjRef {
|
class ElvisRef(private val left: ObjRef, private val right: ObjRef) : ObjRef {
|
||||||
override suspend fun get(scope: Scope): ObjRecord {
|
override suspend fun get(scope: Scope): ObjRecord {
|
||||||
val fastRval = net.sergeych.lyng.PerfFlags.RVAL_FASTPATH
|
val fastRval = PerfFlags.RVAL_FASTPATH
|
||||||
val a = if (fastRval) left.evalValue(scope) else left.get(scope).value
|
val a = if (fastRval) left.evalValue(scope) else left.get(scope).value
|
||||||
val r = if (a != ObjNull) a else if (fastRval) right.evalValue(scope) else right.get(scope).value
|
val r = if (a != ObjNull) a else if (fastRval) right.evalValue(scope) else right.get(scope).value
|
||||||
return r.asReadonly
|
return r.asReadonly
|
||||||
@ -390,8 +392,8 @@ class ElvisRef(private val left: ObjRef, private val right: ObjRef) : ObjRef {
|
|||||||
/** Logical OR with short-circuit: a || b */
|
/** Logical OR with short-circuit: a || b */
|
||||||
class LogicalOrRef(private val left: ObjRef, private val right: ObjRef) : ObjRef {
|
class LogicalOrRef(private val left: ObjRef, private val right: ObjRef) : ObjRef {
|
||||||
override suspend fun get(scope: Scope): ObjRecord {
|
override suspend fun get(scope: Scope): ObjRecord {
|
||||||
val fastRval = net.sergeych.lyng.PerfFlags.RVAL_FASTPATH
|
val fastRval = PerfFlags.RVAL_FASTPATH
|
||||||
val fastPrim = net.sergeych.lyng.PerfFlags.PRIMITIVE_FASTOPS
|
val fastPrim = PerfFlags.PRIMITIVE_FASTOPS
|
||||||
val a = if (fastRval) left.evalValue(scope) else left.get(scope).value
|
val a = if (fastRval) left.evalValue(scope) else left.get(scope).value
|
||||||
if ((a as? ObjBool)?.value == true) return ObjTrue.asReadonly
|
if ((a as? ObjBool)?.value == true) return ObjTrue.asReadonly
|
||||||
val b = if (fastRval) right.evalValue(scope) else right.get(scope).value
|
val b = if (fastRval) right.evalValue(scope) else right.get(scope).value
|
||||||
@ -408,8 +410,8 @@ class LogicalOrRef(private val left: ObjRef, private val right: ObjRef) : ObjRef
|
|||||||
class LogicalAndRef(private val left: ObjRef, private val right: ObjRef) : ObjRef {
|
class LogicalAndRef(private val left: ObjRef, private val right: ObjRef) : ObjRef {
|
||||||
override suspend fun get(scope: Scope): ObjRecord {
|
override suspend fun get(scope: Scope): ObjRecord {
|
||||||
// Hoist flags to locals for JIT friendliness
|
// Hoist flags to locals for JIT friendliness
|
||||||
val fastRval = net.sergeych.lyng.PerfFlags.RVAL_FASTPATH
|
val fastRval = PerfFlags.RVAL_FASTPATH
|
||||||
val fastPrim = net.sergeych.lyng.PerfFlags.PRIMITIVE_FASTOPS
|
val fastPrim = PerfFlags.PRIMITIVE_FASTOPS
|
||||||
val a = if (fastRval) left.evalValue(scope) else left.get(scope).value
|
val a = if (fastRval) left.evalValue(scope) else left.get(scope).value
|
||||||
if ((a as? ObjBool)?.value == false) return ObjFalse.asReadonly
|
if ((a as? ObjBool)?.value == false) return ObjFalse.asReadonly
|
||||||
val b = if (fastRval) right.evalValue(scope) else right.get(scope).value
|
val b = if (fastRval) right.evalValue(scope) else right.get(scope).value
|
||||||
@ -459,18 +461,18 @@ class FieldRef(
|
|||||||
private var rAccesses: Int = 0; private var rMisses: Int = 0; private var rPromotedTo4: Boolean = false
|
private var rAccesses: Int = 0; private var rMisses: Int = 0; private var rPromotedTo4: Boolean = false
|
||||||
private var wAccesses: Int = 0; private var wMisses: Int = 0; private var wPromotedTo4: Boolean = false
|
private var wAccesses: Int = 0; private var wMisses: Int = 0; private var wPromotedTo4: Boolean = false
|
||||||
private inline fun size4ReadsEnabled(): Boolean =
|
private inline fun size4ReadsEnabled(): Boolean =
|
||||||
net.sergeych.lyng.PerfFlags.FIELD_PIC_SIZE_4 ||
|
PerfFlags.FIELD_PIC_SIZE_4 ||
|
||||||
(net.sergeych.lyng.PerfFlags.PIC_ADAPTIVE_2_TO_4 && rPromotedTo4)
|
(PerfFlags.PIC_ADAPTIVE_2_TO_4 && rPromotedTo4)
|
||||||
private inline fun size4WritesEnabled(): Boolean =
|
private inline fun size4WritesEnabled(): Boolean =
|
||||||
net.sergeych.lyng.PerfFlags.FIELD_PIC_SIZE_4 ||
|
PerfFlags.FIELD_PIC_SIZE_4 ||
|
||||||
(net.sergeych.lyng.PerfFlags.PIC_ADAPTIVE_2_TO_4 && wPromotedTo4)
|
(PerfFlags.PIC_ADAPTIVE_2_TO_4 && wPromotedTo4)
|
||||||
private fun noteReadHit() {
|
private fun noteReadHit() {
|
||||||
if (!net.sergeych.lyng.PerfFlags.PIC_ADAPTIVE_2_TO_4) return
|
if (!PerfFlags.PIC_ADAPTIVE_2_TO_4) return
|
||||||
val a = (rAccesses + 1).coerceAtMost(1_000_000)
|
val a = (rAccesses + 1).coerceAtMost(1_000_000)
|
||||||
rAccesses = a
|
rAccesses = a
|
||||||
}
|
}
|
||||||
private fun noteReadMiss() {
|
private fun noteReadMiss() {
|
||||||
if (!net.sergeych.lyng.PerfFlags.PIC_ADAPTIVE_2_TO_4) return
|
if (!PerfFlags.PIC_ADAPTIVE_2_TO_4) return
|
||||||
val a = (rAccesses + 1).coerceAtMost(1_000_000)
|
val a = (rAccesses + 1).coerceAtMost(1_000_000)
|
||||||
rAccesses = a
|
rAccesses = a
|
||||||
rMisses = (rMisses + 1).coerceAtMost(1_000_000)
|
rMisses = (rMisses + 1).coerceAtMost(1_000_000)
|
||||||
@ -482,12 +484,12 @@ class FieldRef(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
private fun noteWriteHit() {
|
private fun noteWriteHit() {
|
||||||
if (!net.sergeych.lyng.PerfFlags.PIC_ADAPTIVE_2_TO_4) return
|
if (!PerfFlags.PIC_ADAPTIVE_2_TO_4) return
|
||||||
val a = (wAccesses + 1).coerceAtMost(1_000_000)
|
val a = (wAccesses + 1).coerceAtMost(1_000_000)
|
||||||
wAccesses = a
|
wAccesses = a
|
||||||
}
|
}
|
||||||
private fun noteWriteMiss() {
|
private fun noteWriteMiss() {
|
||||||
if (!net.sergeych.lyng.PerfFlags.PIC_ADAPTIVE_2_TO_4) return
|
if (!PerfFlags.PIC_ADAPTIVE_2_TO_4) return
|
||||||
val a = (wAccesses + 1).coerceAtMost(1_000_000)
|
val a = (wAccesses + 1).coerceAtMost(1_000_000)
|
||||||
wAccesses = a
|
wAccesses = a
|
||||||
wMisses = (wMisses + 1).coerceAtMost(1_000_000)
|
wMisses = (wMisses + 1).coerceAtMost(1_000_000)
|
||||||
@ -498,15 +500,15 @@ class FieldRef(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun get(scope: Scope): ObjRecord {
|
override suspend fun get(scope: Scope): ObjRecord {
|
||||||
val fastRval = net.sergeych.lyng.PerfFlags.RVAL_FASTPATH
|
val fastRval = PerfFlags.RVAL_FASTPATH
|
||||||
val fieldPic = net.sergeych.lyng.PerfFlags.FIELD_PIC
|
val fieldPic = PerfFlags.FIELD_PIC
|
||||||
val picCounters = net.sergeych.lyng.PerfFlags.PIC_DEBUG_COUNTERS
|
val picCounters = PerfFlags.PIC_DEBUG_COUNTERS
|
||||||
val base = if (fastRval) target.evalValue(scope) else target.get(scope).value
|
val base = if (fastRval) target.evalValue(scope) else target.get(scope).value
|
||||||
if (base == ObjNull && isOptional) return ObjNull.asMutable
|
if (base == ObjNull && isOptional) return ObjNull.asMutable
|
||||||
if (fieldPic) {
|
if (fieldPic) {
|
||||||
val (key, ver) = receiverKeyAndVersion(base)
|
val (key, ver) = receiverKeyAndVersion(base)
|
||||||
rGetter1?.let { g -> if (key == rKey1 && ver == rVer1) {
|
rGetter1?.let { g -> if (key == rKey1 && ver == rVer1) {
|
||||||
if (picCounters) net.sergeych.lyng.PerfStats.fieldPicHit++
|
if (picCounters) PerfStats.fieldPicHit++
|
||||||
noteReadHit()
|
noteReadHit()
|
||||||
val rec0 = g(base, scope)
|
val rec0 = g(base, scope)
|
||||||
if (base is ObjClass) {
|
if (base is ObjClass) {
|
||||||
@ -516,7 +518,7 @@ class FieldRef(
|
|||||||
return rec0
|
return rec0
|
||||||
} }
|
} }
|
||||||
rGetter2?.let { g -> if (key == rKey2 && ver == rVer2) {
|
rGetter2?.let { g -> if (key == rKey2 && ver == rVer2) {
|
||||||
if (picCounters) net.sergeych.lyng.PerfStats.fieldPicHit++
|
if (picCounters) PerfStats.fieldPicHit++
|
||||||
noteReadHit()
|
noteReadHit()
|
||||||
// move-to-front: promote 2→1
|
// move-to-front: promote 2→1
|
||||||
val tK = rKey2; val tV = rVer2; val tG = rGetter2
|
val tK = rKey2; val tV = rVer2; val tG = rGetter2
|
||||||
@ -530,7 +532,7 @@ class FieldRef(
|
|||||||
return rec0
|
return rec0
|
||||||
} }
|
} }
|
||||||
if (size4ReadsEnabled()) rGetter3?.let { g -> if (key == rKey3 && ver == rVer3) {
|
if (size4ReadsEnabled()) rGetter3?.let { g -> if (key == rKey3 && ver == rVer3) {
|
||||||
if (picCounters) net.sergeych.lyng.PerfStats.fieldPicHit++
|
if (picCounters) PerfStats.fieldPicHit++
|
||||||
noteReadHit()
|
noteReadHit()
|
||||||
// move-to-front: promote 3→1
|
// move-to-front: promote 3→1
|
||||||
val tK = rKey3; val tV = rVer3; val tG = rGetter3
|
val tK = rKey3; val tV = rVer3; val tG = rGetter3
|
||||||
@ -545,7 +547,7 @@ class FieldRef(
|
|||||||
return rec0
|
return rec0
|
||||||
} }
|
} }
|
||||||
if (size4ReadsEnabled()) rGetter4?.let { g -> if (key == rKey4 && ver == rVer4) {
|
if (size4ReadsEnabled()) rGetter4?.let { g -> if (key == rKey4 && ver == rVer4) {
|
||||||
if (picCounters) net.sergeych.lyng.PerfStats.fieldPicHit++
|
if (picCounters) PerfStats.fieldPicHit++
|
||||||
noteReadHit()
|
noteReadHit()
|
||||||
// move-to-front: promote 4→1
|
// move-to-front: promote 4→1
|
||||||
val tK = rKey4; val tV = rVer4; val tG = rGetter4
|
val tK = rKey4; val tV = rVer4; val tG = rGetter4
|
||||||
@ -561,7 +563,7 @@ class FieldRef(
|
|||||||
return rec0
|
return rec0
|
||||||
} }
|
} }
|
||||||
// Slow path
|
// Slow path
|
||||||
if (picCounters) net.sergeych.lyng.PerfStats.fieldPicMiss++
|
if (picCounters) PerfStats.fieldPicMiss++
|
||||||
noteReadMiss()
|
noteReadMiss()
|
||||||
val rec = try {
|
val rec = try {
|
||||||
base.readField(scope, name)
|
base.readField(scope, name)
|
||||||
@ -606,8 +608,8 @@ class FieldRef(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun setAt(pos: Pos, scope: Scope, newValue: Obj) {
|
override suspend fun setAt(pos: Pos, scope: Scope, newValue: Obj) {
|
||||||
val fieldPic = net.sergeych.lyng.PerfFlags.FIELD_PIC
|
val fieldPic = PerfFlags.FIELD_PIC
|
||||||
val picCounters = net.sergeych.lyng.PerfFlags.PIC_DEBUG_COUNTERS
|
val picCounters = PerfFlags.PIC_DEBUG_COUNTERS
|
||||||
val base = target.get(scope).value
|
val base = target.get(scope).value
|
||||||
if (base == ObjNull && isOptional) {
|
if (base == ObjNull && isOptional) {
|
||||||
// no-op on null receiver for optional chaining assignment
|
// no-op on null receiver for optional chaining assignment
|
||||||
@ -629,12 +631,12 @@ class FieldRef(
|
|||||||
if (fieldPic) {
|
if (fieldPic) {
|
||||||
val (key, ver) = receiverKeyAndVersion(base)
|
val (key, ver) = receiverKeyAndVersion(base)
|
||||||
wSetter1?.let { s -> if (key == wKey1 && ver == wVer1) {
|
wSetter1?.let { s -> if (key == wKey1 && ver == wVer1) {
|
||||||
if (picCounters) net.sergeych.lyng.PerfStats.fieldPicSetHit++
|
if (picCounters) PerfStats.fieldPicSetHit++
|
||||||
noteWriteHit()
|
noteWriteHit()
|
||||||
return s(base, scope, newValue)
|
return s(base, scope, newValue)
|
||||||
} }
|
} }
|
||||||
wSetter2?.let { s -> if (key == wKey2 && ver == wVer2) {
|
wSetter2?.let { s -> if (key == wKey2 && ver == wVer2) {
|
||||||
if (picCounters) net.sergeych.lyng.PerfStats.fieldPicSetHit++
|
if (picCounters) PerfStats.fieldPicSetHit++
|
||||||
noteWriteHit()
|
noteWriteHit()
|
||||||
// move-to-front: promote 2→1
|
// move-to-front: promote 2→1
|
||||||
val tK = wKey2; val tV = wVer2; val tS = wSetter2
|
val tK = wKey2; val tV = wVer2; val tS = wSetter2
|
||||||
@ -643,7 +645,7 @@ class FieldRef(
|
|||||||
return s(base, scope, newValue)
|
return s(base, scope, newValue)
|
||||||
} }
|
} }
|
||||||
if (size4WritesEnabled()) wSetter3?.let { s -> if (key == wKey3 && ver == wVer3) {
|
if (size4WritesEnabled()) wSetter3?.let { s -> if (key == wKey3 && ver == wVer3) {
|
||||||
if (picCounters) net.sergeych.lyng.PerfStats.fieldPicSetHit++
|
if (picCounters) PerfStats.fieldPicSetHit++
|
||||||
noteWriteHit()
|
noteWriteHit()
|
||||||
// move-to-front: promote 3→1
|
// move-to-front: promote 3→1
|
||||||
val tK = wKey3; val tV = wVer3; val tS = wSetter3
|
val tK = wKey3; val tV = wVer3; val tS = wSetter3
|
||||||
@ -653,7 +655,7 @@ class FieldRef(
|
|||||||
return s(base, scope, newValue)
|
return s(base, scope, newValue)
|
||||||
} }
|
} }
|
||||||
if (size4WritesEnabled()) wSetter4?.let { s -> if (key == wKey4 && ver == wVer4) {
|
if (size4WritesEnabled()) wSetter4?.let { s -> if (key == wKey4 && ver == wVer4) {
|
||||||
if (picCounters) net.sergeych.lyng.PerfStats.fieldPicSetHit++
|
if (picCounters) PerfStats.fieldPicSetHit++
|
||||||
noteWriteHit()
|
noteWriteHit()
|
||||||
// move-to-front: promote 4→1
|
// move-to-front: promote 4→1
|
||||||
val tK = wKey4; val tV = wVer4; val tS = wSetter4
|
val tK = wKey4; val tV = wVer4; val tS = wSetter4
|
||||||
@ -664,7 +666,7 @@ class FieldRef(
|
|||||||
return s(base, scope, newValue)
|
return s(base, scope, newValue)
|
||||||
} }
|
} }
|
||||||
// Slow path
|
// Slow path
|
||||||
if (picCounters) net.sergeych.lyng.PerfStats.fieldPicSetMiss++
|
if (picCounters) PerfStats.fieldPicSetMiss++
|
||||||
noteWriteMiss()
|
noteWriteMiss()
|
||||||
base.writeField(scope, name, newValue)
|
base.writeField(scope, name, newValue)
|
||||||
// Install move-to-front with a handle-aware setter; honor PIC size flag
|
// Install move-to-front with a handle-aware setter; honor PIC size flag
|
||||||
@ -707,26 +709,26 @@ class FieldRef(
|
|||||||
|
|
||||||
override suspend fun evalValue(scope: Scope): Obj {
|
override suspend fun evalValue(scope: Scope): Obj {
|
||||||
// Mirror get(), but return raw Obj to avoid transient ObjRecord on R-value paths
|
// Mirror get(), but return raw Obj to avoid transient ObjRecord on R-value paths
|
||||||
val fastRval = net.sergeych.lyng.PerfFlags.RVAL_FASTPATH
|
val fastRval = PerfFlags.RVAL_FASTPATH
|
||||||
val fieldPic = net.sergeych.lyng.PerfFlags.FIELD_PIC
|
val fieldPic = PerfFlags.FIELD_PIC
|
||||||
val picCounters = net.sergeych.lyng.PerfFlags.PIC_DEBUG_COUNTERS
|
val picCounters = PerfFlags.PIC_DEBUG_COUNTERS
|
||||||
val base = if (fastRval) target.evalValue(scope) else target.get(scope).value
|
val base = if (fastRval) target.evalValue(scope) else target.get(scope).value
|
||||||
if (base == ObjNull && isOptional) return ObjNull
|
if (base == ObjNull && isOptional) return ObjNull
|
||||||
if (fieldPic) {
|
if (fieldPic) {
|
||||||
val (key, ver) = receiverKeyAndVersion(base)
|
val (key, ver) = receiverKeyAndVersion(base)
|
||||||
rGetter1?.let { g -> if (key == rKey1 && ver == rVer1) {
|
rGetter1?.let { g -> if (key == rKey1 && ver == rVer1) {
|
||||||
if (picCounters) net.sergeych.lyng.PerfStats.fieldPicHit++
|
if (picCounters) PerfStats.fieldPicHit++
|
||||||
return g(base, scope).value
|
return g(base, scope).value
|
||||||
} }
|
} }
|
||||||
rGetter2?.let { g -> if (key == rKey2 && ver == rVer2) {
|
rGetter2?.let { g -> if (key == rKey2 && ver == rVer2) {
|
||||||
if (picCounters) net.sergeych.lyng.PerfStats.fieldPicHit++
|
if (picCounters) PerfStats.fieldPicHit++
|
||||||
val tK = rKey2; val tV = rVer2; val tG = rGetter2
|
val tK = rKey2; val tV = rVer2; val tG = rGetter2
|
||||||
rKey2 = rKey1; rVer2 = rVer1; rGetter2 = rGetter1
|
rKey2 = rKey1; rVer2 = rVer1; rGetter2 = rGetter1
|
||||||
rKey1 = tK; rVer1 = tV; rGetter1 = tG
|
rKey1 = tK; rVer1 = tV; rGetter1 = tG
|
||||||
return g(base, scope).value
|
return g(base, scope).value
|
||||||
} }
|
} }
|
||||||
if (size4ReadsEnabled()) rGetter3?.let { g -> if (key == rKey3 && ver == rVer3) {
|
if (size4ReadsEnabled()) rGetter3?.let { g -> if (key == rKey3 && ver == rVer3) {
|
||||||
if (picCounters) net.sergeych.lyng.PerfStats.fieldPicHit++
|
if (picCounters) PerfStats.fieldPicHit++
|
||||||
val tK = rKey3; val tV = rVer3; val tG = rGetter3
|
val tK = rKey3; val tV = rVer3; val tG = rGetter3
|
||||||
rKey3 = rKey2; rVer3 = rVer2; rGetter3 = rGetter2
|
rKey3 = rKey2; rVer3 = rVer2; rGetter3 = rGetter2
|
||||||
rKey2 = rKey1; rVer2 = rVer1; rGetter2 = rGetter1
|
rKey2 = rKey1; rVer2 = rVer1; rGetter2 = rGetter1
|
||||||
@ -734,7 +736,7 @@ class FieldRef(
|
|||||||
return g(base, scope).value
|
return g(base, scope).value
|
||||||
} }
|
} }
|
||||||
if (size4ReadsEnabled()) rGetter4?.let { g -> if (key == rKey4 && ver == rVer4) {
|
if (size4ReadsEnabled()) rGetter4?.let { g -> if (key == rKey4 && ver == rVer4) {
|
||||||
if (picCounters) net.sergeych.lyng.PerfStats.fieldPicHit++
|
if (picCounters) PerfStats.fieldPicHit++
|
||||||
val tK = rKey4; val tV = rVer4; val tG = rGetter4
|
val tK = rKey4; val tV = rVer4; val tG = rGetter4
|
||||||
rKey4 = rKey3; rVer4 = rVer3; rGetter4 = rGetter3
|
rKey4 = rKey3; rVer4 = rVer3; rGetter4 = rGetter3
|
||||||
rKey3 = rKey2; rVer3 = rVer2; rGetter3 = rGetter2
|
rKey3 = rKey2; rVer3 = rVer2; rGetter3 = rGetter2
|
||||||
@ -742,7 +744,7 @@ class FieldRef(
|
|||||||
rKey1 = tK; rVer1 = tV; rGetter1 = tG
|
rKey1 = tK; rVer1 = tV; rGetter1 = tG
|
||||||
return g(base, scope).value
|
return g(base, scope).value
|
||||||
} }
|
} }
|
||||||
if (picCounters) net.sergeych.lyng.PerfStats.fieldPicMiss++
|
if (picCounters) PerfStats.fieldPicMiss++
|
||||||
val rec = base.readField(scope, name)
|
val rec = base.readField(scope, name)
|
||||||
// install primary generic getter for this shape
|
// install primary generic getter for this shape
|
||||||
when (base) {
|
when (base) {
|
||||||
@ -789,7 +791,7 @@ class IndexRef(
|
|||||||
else -> 0L to -1
|
else -> 0L to -1
|
||||||
}
|
}
|
||||||
override suspend fun get(scope: Scope): ObjRecord {
|
override suspend fun get(scope: Scope): ObjRecord {
|
||||||
val fastRval = net.sergeych.lyng.PerfFlags.RVAL_FASTPATH
|
val fastRval = PerfFlags.RVAL_FASTPATH
|
||||||
val base = if (fastRval) target.evalValue(scope) else target.get(scope).value
|
val base = if (fastRval) target.evalValue(scope) else target.get(scope).value
|
||||||
if (base == ObjNull && isOptional) return ObjNull.asMutable
|
if (base == ObjNull && isOptional) return ObjNull.asMutable
|
||||||
val idx = if (fastRval) index.evalValue(scope) else index.get(scope).value
|
val idx = if (fastRval) index.evalValue(scope) else index.get(scope).value
|
||||||
@ -810,7 +812,7 @@ class IndexRef(
|
|||||||
val v = base.map[idx] ?: ObjNull
|
val v = base.map[idx] ?: ObjNull
|
||||||
return v.asMutable
|
return v.asMutable
|
||||||
}
|
}
|
||||||
if (net.sergeych.lyng.PerfFlags.INDEX_PIC) {
|
if (PerfFlags.INDEX_PIC) {
|
||||||
// Polymorphic inline cache for other common shapes
|
// Polymorphic inline cache for other common shapes
|
||||||
val (key, ver) = when (base) {
|
val (key, ver) = when (base) {
|
||||||
is ObjInstance -> base.objClass.classId to base.objClass.layoutVersion
|
is ObjInstance -> base.objClass.classId to base.objClass.layoutVersion
|
||||||
@ -819,26 +821,26 @@ class IndexRef(
|
|||||||
}
|
}
|
||||||
if (key != 0L) {
|
if (key != 0L) {
|
||||||
rGetter1?.let { g -> if (key == rKey1 && ver == rVer1) {
|
rGetter1?.let { g -> if (key == rKey1 && ver == rVer1) {
|
||||||
if (net.sergeych.lyng.PerfFlags.PIC_DEBUG_COUNTERS) net.sergeych.lyng.PerfStats.indexPicHit++
|
if (PerfFlags.PIC_DEBUG_COUNTERS) PerfStats.indexPicHit++
|
||||||
return g(base, scope, idx).asMutable
|
return g(base, scope, idx).asMutable
|
||||||
} }
|
} }
|
||||||
rGetter2?.let { g -> if (key == rKey2 && ver == rVer2) {
|
rGetter2?.let { g -> if (key == rKey2 && ver == rVer2) {
|
||||||
if (net.sergeych.lyng.PerfFlags.PIC_DEBUG_COUNTERS) net.sergeych.lyng.PerfStats.indexPicHit++
|
if (PerfFlags.PIC_DEBUG_COUNTERS) PerfStats.indexPicHit++
|
||||||
val tk = rKey2; val tv = rVer2; val tg = rGetter2
|
val tk = rKey2; val tv = rVer2; val tg = rGetter2
|
||||||
rKey2 = rKey1; rVer2 = rVer1; rGetter2 = rGetter1
|
rKey2 = rKey1; rVer2 = rVer1; rGetter2 = rGetter1
|
||||||
rKey1 = tk; rVer1 = tv; rGetter1 = tg
|
rKey1 = tk; rVer1 = tv; rGetter1 = tg
|
||||||
return g(base, scope, idx).asMutable
|
return g(base, scope, idx).asMutable
|
||||||
} }
|
} }
|
||||||
if (net.sergeych.lyng.PerfFlags.INDEX_PIC_SIZE_4) rGetter3?.let { g -> if (key == rKey3 && ver == rVer3) {
|
if (PerfFlags.INDEX_PIC_SIZE_4) rGetter3?.let { g -> if (key == rKey3 && ver == rVer3) {
|
||||||
if (net.sergeych.lyng.PerfFlags.PIC_DEBUG_COUNTERS) net.sergeych.lyng.PerfStats.indexPicHit++
|
if (PerfFlags.PIC_DEBUG_COUNTERS) PerfStats.indexPicHit++
|
||||||
val tk = rKey3; val tv = rVer3; val tg = rGetter3
|
val tk = rKey3; val tv = rVer3; val tg = rGetter3
|
||||||
rKey3 = rKey2; rVer3 = rVer2; rGetter3 = rGetter2
|
rKey3 = rKey2; rVer3 = rVer2; rGetter3 = rGetter2
|
||||||
rKey2 = rKey1; rVer2 = rVer1; rGetter2 = rGetter1
|
rKey2 = rKey1; rVer2 = rVer1; rGetter2 = rGetter1
|
||||||
rKey1 = tk; rVer1 = tv; rGetter1 = tg
|
rKey1 = tk; rVer1 = tv; rGetter1 = tg
|
||||||
return g(base, scope, idx).asMutable
|
return g(base, scope, idx).asMutable
|
||||||
} }
|
} }
|
||||||
if (net.sergeych.lyng.PerfFlags.INDEX_PIC_SIZE_4) rGetter4?.let { g -> if (key == rKey4 && ver == rVer4) {
|
if (PerfFlags.INDEX_PIC_SIZE_4) rGetter4?.let { g -> if (key == rKey4 && ver == rVer4) {
|
||||||
if (net.sergeych.lyng.PerfFlags.PIC_DEBUG_COUNTERS) net.sergeych.lyng.PerfStats.indexPicHit++
|
if (PerfFlags.PIC_DEBUG_COUNTERS) PerfStats.indexPicHit++
|
||||||
val tk = rKey4; val tv = rVer4; val tg = rGetter4
|
val tk = rKey4; val tv = rVer4; val tg = rGetter4
|
||||||
rKey4 = rKey3; rVer4 = rVer3; rGetter4 = rGetter3
|
rKey4 = rKey3; rVer4 = rVer3; rGetter4 = rGetter3
|
||||||
rKey3 = rKey2; rVer3 = rVer2; rGetter3 = rGetter2
|
rKey3 = rKey2; rVer3 = rVer2; rGetter3 = rGetter2
|
||||||
@ -847,9 +849,9 @@ class IndexRef(
|
|||||||
return g(base, scope, idx).asMutable
|
return g(base, scope, idx).asMutable
|
||||||
} }
|
} }
|
||||||
// Miss: resolve and install generic handler
|
// Miss: resolve and install generic handler
|
||||||
if (net.sergeych.lyng.PerfFlags.PIC_DEBUG_COUNTERS) net.sergeych.lyng.PerfStats.indexPicMiss++
|
if (PerfFlags.PIC_DEBUG_COUNTERS) PerfStats.indexPicMiss++
|
||||||
val v = base.getAt(scope, idx)
|
val v = base.getAt(scope, idx)
|
||||||
if (net.sergeych.lyng.PerfFlags.INDEX_PIC_SIZE_4) {
|
if (PerfFlags.INDEX_PIC_SIZE_4) {
|
||||||
rKey4 = rKey3; rVer4 = rVer3; rGetter4 = rGetter3
|
rKey4 = rKey3; rVer4 = rVer3; rGetter4 = rGetter3
|
||||||
rKey3 = rKey2; rVer3 = rVer2; rGetter3 = rGetter2
|
rKey3 = rKey2; rVer3 = rVer2; rGetter3 = rGetter2
|
||||||
}
|
}
|
||||||
@ -863,7 +865,7 @@ class IndexRef(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun evalValue(scope: Scope): Obj {
|
override suspend fun evalValue(scope: Scope): Obj {
|
||||||
val fastRval = net.sergeych.lyng.PerfFlags.RVAL_FASTPATH
|
val fastRval = PerfFlags.RVAL_FASTPATH
|
||||||
val base = if (fastRval) target.evalValue(scope) else target.get(scope).value
|
val base = if (fastRval) target.evalValue(scope) else target.get(scope).value
|
||||||
if (base == ObjNull && isOptional) return ObjNull
|
if (base == ObjNull && isOptional) return ObjNull
|
||||||
val idx = if (fastRval) index.evalValue(scope) else index.get(scope).value
|
val idx = if (fastRval) index.evalValue(scope) else index.get(scope).value
|
||||||
@ -882,7 +884,7 @@ class IndexRef(
|
|||||||
if (base is ObjMap && idx is ObjString) {
|
if (base is ObjMap && idx is ObjString) {
|
||||||
return base.map[idx] ?: ObjNull
|
return base.map[idx] ?: ObjNull
|
||||||
}
|
}
|
||||||
if (net.sergeych.lyng.PerfFlags.INDEX_PIC) {
|
if (PerfFlags.INDEX_PIC) {
|
||||||
// PIC path analogous to get(), but returning raw Obj
|
// PIC path analogous to get(), but returning raw Obj
|
||||||
val (key, ver) = when (base) {
|
val (key, ver) = when (base) {
|
||||||
is ObjInstance -> base.objClass.classId to base.objClass.layoutVersion
|
is ObjInstance -> base.objClass.classId to base.objClass.layoutVersion
|
||||||
@ -891,26 +893,26 @@ class IndexRef(
|
|||||||
}
|
}
|
||||||
if (key != 0L) {
|
if (key != 0L) {
|
||||||
rGetter1?.let { g -> if (key == rKey1 && ver == rVer1) {
|
rGetter1?.let { g -> if (key == rKey1 && ver == rVer1) {
|
||||||
if (net.sergeych.lyng.PerfFlags.PIC_DEBUG_COUNTERS) net.sergeych.lyng.PerfStats.indexPicHit++
|
if (PerfFlags.PIC_DEBUG_COUNTERS) PerfStats.indexPicHit++
|
||||||
return g(base, scope, idx)
|
return g(base, scope, idx)
|
||||||
} }
|
} }
|
||||||
rGetter2?.let { g -> if (key == rKey2 && ver == rVer2) {
|
rGetter2?.let { g -> if (key == rKey2 && ver == rVer2) {
|
||||||
if (net.sergeych.lyng.PerfFlags.PIC_DEBUG_COUNTERS) net.sergeych.lyng.PerfStats.indexPicHit++
|
if (PerfFlags.PIC_DEBUG_COUNTERS) PerfStats.indexPicHit++
|
||||||
val tk = rKey2; val tv = rVer2; val tg = rGetter2
|
val tk = rKey2; val tv = rVer2; val tg = rGetter2
|
||||||
rKey2 = rKey1; rVer2 = rVer1; rGetter2 = rGetter1
|
rKey2 = rKey1; rVer2 = rVer1; rGetter2 = rGetter1
|
||||||
rKey1 = tk; rVer1 = tv; rGetter1 = tg
|
rKey1 = tk; rVer1 = tv; rGetter1 = tg
|
||||||
return g(base, scope, idx)
|
return g(base, scope, idx)
|
||||||
} }
|
} }
|
||||||
if (net.sergeych.lyng.PerfFlags.INDEX_PIC_SIZE_4) rGetter3?.let { g -> if (key == rKey3 && ver == rVer3) {
|
if (PerfFlags.INDEX_PIC_SIZE_4) rGetter3?.let { g -> if (key == rKey3 && ver == rVer3) {
|
||||||
if (net.sergeych.lyng.PerfFlags.PIC_DEBUG_COUNTERS) net.sergeych.lyng.PerfStats.indexPicHit++
|
if (PerfFlags.PIC_DEBUG_COUNTERS) PerfStats.indexPicHit++
|
||||||
val tk = rKey3; val tv = rVer3; val tg = rGetter3
|
val tk = rKey3; val tv = rVer3; val tg = rGetter3
|
||||||
rKey3 = rKey2; rVer3 = rVer2; rGetter3 = rGetter2
|
rKey3 = rKey2; rVer3 = rVer2; rGetter3 = rGetter2
|
||||||
rKey2 = rKey1; rVer2 = rVer1; rGetter2 = rGetter1
|
rKey2 = rKey1; rVer2 = rVer1; rGetter2 = rGetter1
|
||||||
rKey1 = tk; rVer1 = tv; rGetter1 = tg
|
rKey1 = tk; rVer1 = tv; rGetter1 = tg
|
||||||
return g(base, scope, idx)
|
return g(base, scope, idx)
|
||||||
} }
|
} }
|
||||||
if (net.sergeych.lyng.PerfFlags.INDEX_PIC_SIZE_4) rGetter4?.let { g -> if (key == rKey4 && ver == rVer4) {
|
if (PerfFlags.INDEX_PIC_SIZE_4) rGetter4?.let { g -> if (key == rKey4 && ver == rVer4) {
|
||||||
if (net.sergeych.lyng.PerfFlags.PIC_DEBUG_COUNTERS) net.sergeych.lyng.PerfStats.indexPicHit++
|
if (PerfFlags.PIC_DEBUG_COUNTERS) PerfStats.indexPicHit++
|
||||||
val tk = rKey4; val tv = rVer4; val tg = rGetter4
|
val tk = rKey4; val tv = rVer4; val tg = rGetter4
|
||||||
rKey4 = rKey3; rVer4 = rVer3; rGetter4 = rGetter3
|
rKey4 = rKey3; rVer4 = rVer3; rGetter4 = rGetter3
|
||||||
rKey3 = rKey2; rVer3 = rVer2; rGetter3 = rGetter2
|
rKey3 = rKey2; rVer3 = rVer2; rGetter3 = rGetter2
|
||||||
@ -918,9 +920,9 @@ class IndexRef(
|
|||||||
rKey1 = tk; rVer1 = tv; rGetter1 = tg
|
rKey1 = tk; rVer1 = tv; rGetter1 = tg
|
||||||
return g(base, scope, idx)
|
return g(base, scope, idx)
|
||||||
} }
|
} }
|
||||||
if (net.sergeych.lyng.PerfFlags.PIC_DEBUG_COUNTERS) net.sergeych.lyng.PerfStats.indexPicMiss++
|
if (PerfFlags.PIC_DEBUG_COUNTERS) PerfStats.indexPicMiss++
|
||||||
val v = base.getAt(scope, idx)
|
val v = base.getAt(scope, idx)
|
||||||
if (net.sergeych.lyng.PerfFlags.INDEX_PIC_SIZE_4) {
|
if (PerfFlags.INDEX_PIC_SIZE_4) {
|
||||||
rKey4 = rKey3; rVer4 = rVer3; rGetter4 = rGetter3
|
rKey4 = rKey3; rVer4 = rVer3; rGetter4 = rGetter3
|
||||||
rKey3 = rKey2; rVer3 = rVer2; rGetter3 = rGetter2
|
rKey3 = rKey2; rVer3 = rVer2; rGetter3 = rGetter2
|
||||||
}
|
}
|
||||||
@ -934,7 +936,7 @@ class IndexRef(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun setAt(pos: Pos, scope: Scope, newValue: Obj) {
|
override suspend fun setAt(pos: Pos, scope: Scope, newValue: Obj) {
|
||||||
val fastRval = net.sergeych.lyng.PerfFlags.RVAL_FASTPATH
|
val fastRval = PerfFlags.RVAL_FASTPATH
|
||||||
val base = if (fastRval) target.evalValue(scope) else target.get(scope).value
|
val base = if (fastRval) target.evalValue(scope) else target.get(scope).value
|
||||||
if (base == ObjNull && isOptional) {
|
if (base == ObjNull && isOptional) {
|
||||||
// no-op on null receiver for optional chaining assignment
|
// no-op on null receiver for optional chaining assignment
|
||||||
@ -953,7 +955,7 @@ class IndexRef(
|
|||||||
base.map[idx] = newValue
|
base.map[idx] = newValue
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (net.sergeych.lyng.PerfFlags.INDEX_PIC) {
|
if (PerfFlags.INDEX_PIC) {
|
||||||
// Polymorphic inline cache for index write
|
// Polymorphic inline cache for index write
|
||||||
val (key, ver) = when (base) {
|
val (key, ver) = when (base) {
|
||||||
is ObjInstance -> base.objClass.classId to base.objClass.layoutVersion
|
is ObjInstance -> base.objClass.classId to base.objClass.layoutVersion
|
||||||
@ -968,14 +970,14 @@ class IndexRef(
|
|||||||
wKey1 = tk; wVer1 = tv; wSetter1 = ts
|
wKey1 = tk; wVer1 = tv; wSetter1 = ts
|
||||||
s(base, scope, idx, newValue); return
|
s(base, scope, idx, newValue); return
|
||||||
} }
|
} }
|
||||||
if (net.sergeych.lyng.PerfFlags.INDEX_PIC_SIZE_4) wSetter3?.let { s -> if (key == wKey3 && ver == wVer3) {
|
if (PerfFlags.INDEX_PIC_SIZE_4) wSetter3?.let { s -> if (key == wKey3 && ver == wVer3) {
|
||||||
val tk = wKey3; val tv = wVer3; val ts = wSetter3
|
val tk = wKey3; val tv = wVer3; val ts = wSetter3
|
||||||
wKey3 = wKey2; wVer3 = wVer2; wSetter3 = wSetter2
|
wKey3 = wKey2; wVer3 = wVer2; wSetter3 = wSetter2
|
||||||
wKey2 = wKey1; wVer2 = wVer1; wSetter2 = wSetter1
|
wKey2 = wKey1; wVer2 = wVer1; wSetter2 = wSetter1
|
||||||
wKey1 = tk; wVer1 = tv; wSetter1 = ts
|
wKey1 = tk; wVer1 = tv; wSetter1 = ts
|
||||||
s(base, scope, idx, newValue); return
|
s(base, scope, idx, newValue); return
|
||||||
} }
|
} }
|
||||||
if (net.sergeych.lyng.PerfFlags.INDEX_PIC_SIZE_4) wSetter4?.let { s -> if (key == wKey4 && ver == wVer4) {
|
if (PerfFlags.INDEX_PIC_SIZE_4) wSetter4?.let { s -> if (key == wKey4 && ver == wVer4) {
|
||||||
val tk = wKey4; val tv = wVer4; val ts = wSetter4
|
val tk = wKey4; val tv = wVer4; val ts = wSetter4
|
||||||
wKey4 = wKey3; wVer4 = wVer3; wSetter4 = wSetter3
|
wKey4 = wKey3; wVer4 = wVer3; wSetter4 = wSetter3
|
||||||
wKey3 = wKey2; wVer3 = wVer2; wSetter3 = wSetter2
|
wKey3 = wKey2; wVer3 = wVer2; wSetter3 = wSetter2
|
||||||
@ -985,7 +987,7 @@ class IndexRef(
|
|||||||
} }
|
} }
|
||||||
// Miss: perform write and install generic handler
|
// Miss: perform write and install generic handler
|
||||||
base.putAt(scope, idx, newValue)
|
base.putAt(scope, idx, newValue)
|
||||||
if (net.sergeych.lyng.PerfFlags.INDEX_PIC_SIZE_4) {
|
if (PerfFlags.INDEX_PIC_SIZE_4) {
|
||||||
wKey4 = wKey3; wVer4 = wVer3; wSetter4 = wSetter3
|
wKey4 = wKey3; wVer4 = wVer3; wSetter4 = wSetter3
|
||||||
wKey3 = wKey2; wVer3 = wVer2; wSetter3 = wSetter2
|
wKey3 = wKey2; wVer3 = wVer2; wSetter3 = wSetter2
|
||||||
}
|
}
|
||||||
@ -1016,8 +1018,8 @@ class CallRef(
|
|||||||
private val isOptionalInvoke: Boolean,
|
private val isOptionalInvoke: Boolean,
|
||||||
) : ObjRef {
|
) : ObjRef {
|
||||||
override suspend fun get(scope: Scope): ObjRecord {
|
override suspend fun get(scope: Scope): ObjRecord {
|
||||||
val fastRval = net.sergeych.lyng.PerfFlags.RVAL_FASTPATH
|
val fastRval = PerfFlags.RVAL_FASTPATH
|
||||||
val usePool = net.sergeych.lyng.PerfFlags.SCOPE_POOL
|
val usePool = PerfFlags.SCOPE_POOL
|
||||||
val callee = if (fastRval) target.evalValue(scope) else target.get(scope).value
|
val callee = if (fastRval) target.evalValue(scope) else target.get(scope).value
|
||||||
if (callee == ObjNull && isOptionalInvoke) return ObjNull.asReadonly
|
if (callee == ObjNull && isOptionalInvoke) return ObjNull.asReadonly
|
||||||
val callArgs = args.toArguments(scope, tailBlock)
|
val callArgs = args.toArguments(scope, tailBlock)
|
||||||
@ -1055,20 +1057,20 @@ class MethodCallRef(
|
|||||||
private var mWindowAccesses: Int = 0
|
private var mWindowAccesses: Int = 0
|
||||||
private var mWindowMisses: Int = 0
|
private var mWindowMisses: Int = 0
|
||||||
private inline fun size4MethodsEnabled(): Boolean =
|
private inline fun size4MethodsEnabled(): Boolean =
|
||||||
net.sergeych.lyng.PerfFlags.METHOD_PIC_SIZE_4 ||
|
PerfFlags.METHOD_PIC_SIZE_4 ||
|
||||||
((net.sergeych.lyng.PerfFlags.PIC_ADAPTIVE_2_TO_4 || net.sergeych.lyng.PerfFlags.PIC_ADAPTIVE_METHODS_ONLY) && mPromotedTo4 && mFreezeWindowsLeft == 0)
|
((PerfFlags.PIC_ADAPTIVE_2_TO_4 || PerfFlags.PIC_ADAPTIVE_METHODS_ONLY) && mPromotedTo4 && mFreezeWindowsLeft == 0)
|
||||||
private fun noteMethodHit() {
|
private fun noteMethodHit() {
|
||||||
if (!(net.sergeych.lyng.PerfFlags.PIC_ADAPTIVE_2_TO_4 || net.sergeych.lyng.PerfFlags.PIC_ADAPTIVE_METHODS_ONLY)) return
|
if (!(PerfFlags.PIC_ADAPTIVE_2_TO_4 || PerfFlags.PIC_ADAPTIVE_METHODS_ONLY)) return
|
||||||
val a = (mAccesses + 1).coerceAtMost(1_000_000)
|
val a = (mAccesses + 1).coerceAtMost(1_000_000)
|
||||||
mAccesses = a
|
mAccesses = a
|
||||||
if (net.sergeych.lyng.PerfFlags.PIC_ADAPTIVE_HEURISTIC) {
|
if (PerfFlags.PIC_ADAPTIVE_HEURISTIC) {
|
||||||
// Windowed tracking
|
// Windowed tracking
|
||||||
mWindowAccesses = (mWindowAccesses + 1).coerceAtMost(1_000_000)
|
mWindowAccesses = (mWindowAccesses + 1).coerceAtMost(1_000_000)
|
||||||
if (mWindowAccesses >= 256) endHeuristicWindow()
|
if (mWindowAccesses >= 256) endHeuristicWindow()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private fun noteMethodMiss() {
|
private fun noteMethodMiss() {
|
||||||
if (!(net.sergeych.lyng.PerfFlags.PIC_ADAPTIVE_2_TO_4 || net.sergeych.lyng.PerfFlags.PIC_ADAPTIVE_METHODS_ONLY)) return
|
if (!(PerfFlags.PIC_ADAPTIVE_2_TO_4 || PerfFlags.PIC_ADAPTIVE_METHODS_ONLY)) return
|
||||||
val a = (mAccesses + 1).coerceAtMost(1_000_000)
|
val a = (mAccesses + 1).coerceAtMost(1_000_000)
|
||||||
mAccesses = a
|
mAccesses = a
|
||||||
mMisses = (mMisses + 1).coerceAtMost(1_000_000)
|
mMisses = (mMisses + 1).coerceAtMost(1_000_000)
|
||||||
@ -1076,7 +1078,7 @@ class MethodCallRef(
|
|||||||
if (mMisses * 100 / a > 20) mPromotedTo4 = true
|
if (mMisses * 100 / a > 20) mPromotedTo4 = true
|
||||||
mAccesses = 0; mMisses = 0
|
mAccesses = 0; mMisses = 0
|
||||||
}
|
}
|
||||||
if (net.sergeych.lyng.PerfFlags.PIC_ADAPTIVE_HEURISTIC) {
|
if (PerfFlags.PIC_ADAPTIVE_HEURISTIC) {
|
||||||
mWindowAccesses = (mWindowAccesses + 1).coerceAtMost(1_000_000)
|
mWindowAccesses = (mWindowAccesses + 1).coerceAtMost(1_000_000)
|
||||||
mWindowMisses = (mWindowMisses + 1).coerceAtMost(1_000_000)
|
mWindowMisses = (mWindowMisses + 1).coerceAtMost(1_000_000)
|
||||||
if (mWindowAccesses >= 256) endHeuristicWindow()
|
if (mWindowAccesses >= 256) endHeuristicWindow()
|
||||||
@ -1106,26 +1108,26 @@ class MethodCallRef(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun get(scope: Scope): ObjRecord {
|
override suspend fun get(scope: Scope): ObjRecord {
|
||||||
val fastRval = net.sergeych.lyng.PerfFlags.RVAL_FASTPATH
|
val fastRval = PerfFlags.RVAL_FASTPATH
|
||||||
val methodPic = net.sergeych.lyng.PerfFlags.METHOD_PIC
|
val methodPic = PerfFlags.METHOD_PIC
|
||||||
val picCounters = net.sergeych.lyng.PerfFlags.PIC_DEBUG_COUNTERS
|
val picCounters = PerfFlags.PIC_DEBUG_COUNTERS
|
||||||
val base = if (fastRval) receiver.evalValue(scope) else receiver.get(scope).value
|
val base = if (fastRval) receiver.evalValue(scope) else receiver.get(scope).value
|
||||||
if (base == ObjNull && isOptional) return ObjNull.asReadonly
|
if (base == ObjNull && isOptional) return ObjNull.asReadonly
|
||||||
val callArgs = args.toArguments(scope, tailBlock)
|
val callArgs = args.toArguments(scope, tailBlock)
|
||||||
if (methodPic) {
|
if (methodPic) {
|
||||||
val (key, ver) = receiverKeyAndVersion(base)
|
val (key, ver) = receiverKeyAndVersion(base)
|
||||||
mInvoker1?.let { inv -> if (key == mKey1 && ver == mVer1) {
|
mInvoker1?.let { inv -> if (key == mKey1 && ver == mVer1) {
|
||||||
if (picCounters) net.sergeych.lyng.PerfStats.methodPicHit++
|
if (picCounters) PerfStats.methodPicHit++
|
||||||
noteMethodHit()
|
noteMethodHit()
|
||||||
return inv(base, scope, callArgs).asReadonly
|
return inv(base, scope, callArgs).asReadonly
|
||||||
} }
|
} }
|
||||||
mInvoker2?.let { inv -> if (key == mKey2 && ver == mVer2) {
|
mInvoker2?.let { inv -> if (key == mKey2 && ver == mVer2) {
|
||||||
if (picCounters) net.sergeych.lyng.PerfStats.methodPicHit++
|
if (picCounters) PerfStats.methodPicHit++
|
||||||
noteMethodHit()
|
noteMethodHit()
|
||||||
return inv(base, scope, callArgs).asReadonly
|
return inv(base, scope, callArgs).asReadonly
|
||||||
} }
|
} }
|
||||||
if (size4MethodsEnabled()) mInvoker3?.let { inv -> if (key == mKey3 && ver == mVer3) {
|
if (size4MethodsEnabled()) mInvoker3?.let { inv -> if (key == mKey3 && ver == mVer3) {
|
||||||
if (picCounters) net.sergeych.lyng.PerfStats.methodPicHit++
|
if (picCounters) PerfStats.methodPicHit++
|
||||||
noteMethodHit()
|
noteMethodHit()
|
||||||
// move-to-front: promote 3→1
|
// move-to-front: promote 3→1
|
||||||
val tK = mKey3; val tV = mVer3; val tI = mInvoker3
|
val tK = mKey3; val tV = mVer3; val tI = mInvoker3
|
||||||
@ -1135,7 +1137,7 @@ class MethodCallRef(
|
|||||||
return inv(base, scope, callArgs).asReadonly
|
return inv(base, scope, callArgs).asReadonly
|
||||||
} }
|
} }
|
||||||
if (size4MethodsEnabled()) mInvoker4?.let { inv -> if (key == mKey4 && ver == mVer4) {
|
if (size4MethodsEnabled()) mInvoker4?.let { inv -> if (key == mKey4 && ver == mVer4) {
|
||||||
if (picCounters) net.sergeych.lyng.PerfStats.methodPicHit++
|
if (picCounters) PerfStats.methodPicHit++
|
||||||
noteMethodHit()
|
noteMethodHit()
|
||||||
// move-to-front: promote 4→1
|
// move-to-front: promote 4→1
|
||||||
val tK = mKey4; val tV = mVer4; val tI = mInvoker4
|
val tK = mKey4; val tV = mVer4; val tI = mInvoker4
|
||||||
@ -1146,7 +1148,7 @@ class MethodCallRef(
|
|||||||
return inv(base, scope, callArgs).asReadonly
|
return inv(base, scope, callArgs).asReadonly
|
||||||
} }
|
} }
|
||||||
// Slow path
|
// Slow path
|
||||||
if (picCounters) net.sergeych.lyng.PerfStats.methodPicMiss++
|
if (picCounters) PerfStats.methodPicMiss++
|
||||||
noteMethodMiss()
|
noteMethodMiss()
|
||||||
val result = try {
|
val result = try {
|
||||||
base.invokeInstanceMethod(scope, name, callArgs)
|
base.invokeInstanceMethod(scope, name, callArgs)
|
||||||
@ -1232,34 +1234,26 @@ class LocalVarRef(private val name: String, private val atPos: Pos) : ObjRef {
|
|||||||
// 1) Try fast slot/local
|
// 1) Try fast slot/local
|
||||||
if (!PerfFlags.LOCAL_SLOT_PIC) {
|
if (!PerfFlags.LOCAL_SLOT_PIC) {
|
||||||
scope.getSlotIndexOf(name)?.let {
|
scope.getSlotIndexOf(name)?.let {
|
||||||
if (net.sergeych.lyng.PerfFlags.PIC_DEBUG_COUNTERS) net.sergeych.lyng.PerfStats.localVarPicHit++
|
if (PerfFlags.PIC_DEBUG_COUNTERS) PerfStats.localVarPicHit++
|
||||||
return scope.getSlotRecord(it)
|
return scope.getSlotRecord(it)
|
||||||
}
|
}
|
||||||
if (net.sergeych.lyng.PerfFlags.PIC_DEBUG_COUNTERS) net.sergeych.lyng.PerfStats.localVarPicMiss++
|
if (PerfFlags.PIC_DEBUG_COUNTERS) PerfStats.localVarPicMiss++
|
||||||
// 2) Fallback to current-scope object or field on `this`
|
// 2) Fallback to current-scope object or field on `this`
|
||||||
scope[name]?.let { return it }
|
scope[name]?.let { return it }
|
||||||
val th = scope.thisObj
|
return scope.thisObj.readField(scope, name)
|
||||||
return when (th) {
|
|
||||||
is Obj -> th.readField(scope, name)
|
|
||||||
else -> scope.raiseError("symbol not defined: '$name'")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
val hit = (cachedFrameId == scope.frameId && cachedSlot >= 0 && cachedSlot < scope.slotCount())
|
val hit = (cachedFrameId == scope.frameId && cachedSlot >= 0 && cachedSlot < scope.slotCount())
|
||||||
val slot = if (hit) cachedSlot else resolveSlot(scope)
|
val slot = if (hit) cachedSlot else resolveSlot(scope)
|
||||||
if (slot >= 0) {
|
if (slot >= 0) {
|
||||||
if (net.sergeych.lyng.PerfFlags.PIC_DEBUG_COUNTERS) {
|
if (PerfFlags.PIC_DEBUG_COUNTERS) {
|
||||||
if (hit) net.sergeych.lyng.PerfStats.localVarPicHit++ else net.sergeych.lyng.PerfStats.localVarPicMiss++
|
if (hit) PerfStats.localVarPicHit++ else PerfStats.localVarPicMiss++
|
||||||
}
|
}
|
||||||
return scope.getSlotRecord(slot)
|
return scope.getSlotRecord(slot)
|
||||||
}
|
}
|
||||||
if (net.sergeych.lyng.PerfFlags.PIC_DEBUG_COUNTERS) net.sergeych.lyng.PerfStats.localVarPicMiss++
|
if (PerfFlags.PIC_DEBUG_COUNTERS) PerfStats.localVarPicMiss++
|
||||||
// 2) Fallback name in scope or field on `this`
|
// 2) Fallback name in scope or field on `this`
|
||||||
scope[name]?.let { return it }
|
scope[name]?.let { return it }
|
||||||
val th = scope.thisObj
|
return scope.thisObj.readField(scope, name)
|
||||||
return when (th) {
|
|
||||||
is Obj -> th.readField(scope, name)
|
|
||||||
else -> scope.raiseError("symbol not defined: '$name'")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun evalValue(scope: Scope): Obj {
|
override suspend fun evalValue(scope: Scope): Obj {
|
||||||
@ -1268,22 +1262,14 @@ class LocalVarRef(private val name: String, private val atPos: Pos) : ObjRef {
|
|||||||
scope.getSlotIndexOf(name)?.let { return scope.getSlotRecord(it).value }
|
scope.getSlotIndexOf(name)?.let { return scope.getSlotRecord(it).value }
|
||||||
// fallback to current-scope object or field on `this`
|
// fallback to current-scope object or field on `this`
|
||||||
scope[name]?.let { return it.value }
|
scope[name]?.let { return it.value }
|
||||||
val th = scope.thisObj
|
return scope.thisObj.readField(scope, name).value
|
||||||
return when (th) {
|
|
||||||
is Obj -> th.readField(scope, name).value
|
|
||||||
else -> scope.raiseError("symbol not defined: '$name'")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
val hit = (cachedFrameId == scope.frameId && cachedSlot >= 0 && cachedSlot < scope.slotCount())
|
val hit = (cachedFrameId == scope.frameId && cachedSlot >= 0 && cachedSlot < scope.slotCount())
|
||||||
val slot = if (hit) cachedSlot else resolveSlot(scope)
|
val slot = if (hit) cachedSlot else resolveSlot(scope)
|
||||||
if (slot >= 0) return scope.getSlotRecord(slot).value
|
if (slot >= 0) return scope.getSlotRecord(slot).value
|
||||||
// Fallback name in scope or field on `this`
|
// Fallback name in scope or field on `this`
|
||||||
scope[name]?.let { return it.value }
|
scope[name]?.let { return it.value }
|
||||||
val th = scope.thisObj
|
return scope.thisObj.readField(scope, name).value
|
||||||
return when (th) {
|
|
||||||
is Obj -> th.readField(scope, name).value
|
|
||||||
else -> scope.raiseError("symbol not defined: '$name'")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun setAt(pos: Pos, scope: Scope, newValue: Obj) {
|
override suspend fun setAt(pos: Pos, scope: Scope, newValue: Obj) {
|
||||||
@ -1301,12 +1287,8 @@ class LocalVarRef(private val name: String, private val atPos: Pos) : ObjRef {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Fallback: write to field on `this`
|
// Fallback: write to field on `this`
|
||||||
val th = scope.thisObj
|
scope.thisObj.writeField(scope, name, newValue)
|
||||||
if (th is Obj) {
|
return
|
||||||
th.writeField(scope, name, newValue)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
scope.raiseError("symbol not defined: '$name'")
|
|
||||||
}
|
}
|
||||||
val slot = if (cachedFrameId == scope.frameId && cachedSlot >= 0 && cachedSlot < scope.slotCount()) cachedSlot else resolveSlot(scope)
|
val slot = if (cachedFrameId == scope.frameId && cachedSlot >= 0 && cachedSlot < scope.slotCount()) cachedSlot else resolveSlot(scope)
|
||||||
if (slot >= 0) {
|
if (slot >= 0) {
|
||||||
@ -1320,12 +1302,8 @@ class LocalVarRef(private val name: String, private val atPos: Pos) : ObjRef {
|
|||||||
else scope.raiseError("Cannot assign to immutable value")
|
else scope.raiseError("Cannot assign to immutable value")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val th = scope.thisObj
|
scope.thisObj.writeField(scope, name, newValue)
|
||||||
if (th is Obj) {
|
return
|
||||||
th.writeField(scope, name, newValue)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
scope.raiseError("symbol not defined: '$name'")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1401,8 +1379,8 @@ class FastLocalVarRef(
|
|||||||
val slot = if (ownerValid && cachedSlot >= 0) cachedSlot else resolveSlotInAncestry(scope)
|
val slot = if (ownerValid && cachedSlot >= 0) cachedSlot else resolveSlotInAncestry(scope)
|
||||||
val actualOwner = cachedOwnerScope
|
val actualOwner = cachedOwnerScope
|
||||||
if (slot >= 0 && actualOwner != null) {
|
if (slot >= 0 && actualOwner != null) {
|
||||||
if (net.sergeych.lyng.PerfFlags.PIC_DEBUG_COUNTERS) {
|
if (PerfFlags.PIC_DEBUG_COUNTERS) {
|
||||||
if (ownerValid) net.sergeych.lyng.PerfStats.fastLocalHit++ else net.sergeych.lyng.PerfStats.fastLocalMiss++
|
if (ownerValid) PerfStats.fastLocalHit++ else PerfStats.fastLocalMiss++
|
||||||
}
|
}
|
||||||
return actualOwner.getSlotRecord(slot)
|
return actualOwner.getSlotRecord(slot)
|
||||||
}
|
}
|
||||||
@ -1423,9 +1401,7 @@ class FastLocalVarRef(
|
|||||||
// Fallback to standard name lookup (locals or closure chain) if the slot owner changed across suspension
|
// Fallback to standard name lookup (locals or closure chain) if the slot owner changed across suspension
|
||||||
scope[name]?.let { return it }
|
scope[name]?.let { return it }
|
||||||
// As a last resort, treat as field on `this`
|
// As a last resort, treat as field on `this`
|
||||||
val th = scope.thisObj
|
return scope.thisObj.readField(scope, name)
|
||||||
if (th is Obj) return th.readField(scope, name)
|
|
||||||
scope.raiseError("local '$name' is not available in this scope")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun evalValue(scope: Scope): Obj {
|
override suspend fun evalValue(scope: Scope): Obj {
|
||||||
@ -1450,9 +1426,7 @@ class FastLocalVarRef(
|
|||||||
}
|
}
|
||||||
// Fallback to standard name lookup (locals or closure chain)
|
// Fallback to standard name lookup (locals or closure chain)
|
||||||
scope[name]?.let { return it.value }
|
scope[name]?.let { return it.value }
|
||||||
val th = scope.thisObj
|
return scope.thisObj.readField(scope, name).value
|
||||||
if (th is Obj) return th.readField(scope, name).value
|
|
||||||
scope.raiseError("local '$name' is not available in this scope")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun setAt(pos: Pos, scope: Scope, newValue: Obj) {
|
override suspend fun setAt(pos: Pos, scope: Scope, newValue: Obj) {
|
||||||
@ -1485,12 +1459,8 @@ class FastLocalVarRef(
|
|||||||
else scope.raiseError("Cannot assign to immutable value")
|
else scope.raiseError("Cannot assign to immutable value")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val th = scope.thisObj
|
scope.thisObj.writeField(scope, name, newValue)
|
||||||
if (th is Obj) {
|
return
|
||||||
th.writeField(scope, name, newValue)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
scope.raiseError("local '$name' is not available in this scope")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1502,11 +1472,11 @@ class ListLiteralRef(private val entries: List<ListEntry>) : ObjRef {
|
|||||||
for (e in entries) {
|
for (e in entries) {
|
||||||
when (e) {
|
when (e) {
|
||||||
is ListEntry.Element -> {
|
is ListEntry.Element -> {
|
||||||
val v = if (net.sergeych.lyng.PerfFlags.RVAL_FASTPATH) e.ref.evalValue(scope) else e.ref.get(scope).value
|
val v = if (PerfFlags.RVAL_FASTPATH) e.ref.evalValue(scope) else e.ref.get(scope).value
|
||||||
list += v
|
list += v
|
||||||
}
|
}
|
||||||
is ListEntry.Spread -> {
|
is ListEntry.Spread -> {
|
||||||
val elements = if (net.sergeych.lyng.PerfFlags.RVAL_FASTPATH) e.ref.evalValue(scope) else e.ref.get(scope).value
|
val elements = if (PerfFlags.RVAL_FASTPATH) e.ref.evalValue(scope) else e.ref.get(scope).value
|
||||||
when (elements) {
|
when (elements) {
|
||||||
is ObjList -> {
|
is ObjList -> {
|
||||||
// Grow underlying array once when possible
|
// Grow underlying array once when possible
|
||||||
@ -1531,8 +1501,8 @@ class RangeRef(
|
|||||||
private val isEndInclusive: Boolean
|
private val isEndInclusive: Boolean
|
||||||
) : ObjRef {
|
) : ObjRef {
|
||||||
override suspend fun get(scope: Scope): ObjRecord {
|
override suspend fun get(scope: Scope): ObjRecord {
|
||||||
val l = left?.let { if (net.sergeych.lyng.PerfFlags.RVAL_FASTPATH) it.evalValue(scope) else it.get(scope).value } ?: ObjNull
|
val l = left?.let { if (PerfFlags.RVAL_FASTPATH) it.evalValue(scope) else it.get(scope).value } ?: ObjNull
|
||||||
val r = right?.let { if (net.sergeych.lyng.PerfFlags.RVAL_FASTPATH) it.evalValue(scope) else it.get(scope).value } ?: ObjNull
|
val r = right?.let { if (PerfFlags.RVAL_FASTPATH) it.evalValue(scope) else it.get(scope).value } ?: ObjNull
|
||||||
return ObjRange(l, r, isEndInclusive = isEndInclusive).asReadonly
|
return ObjRange(l, r, isEndInclusive = isEndInclusive).asReadonly
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1544,7 +1514,7 @@ class AssignRef(
|
|||||||
private val atPos: Pos,
|
private val atPos: Pos,
|
||||||
) : ObjRef {
|
) : ObjRef {
|
||||||
override suspend fun get(scope: Scope): ObjRecord {
|
override suspend fun get(scope: Scope): ObjRecord {
|
||||||
val v = if (net.sergeych.lyng.PerfFlags.RVAL_FASTPATH) value.evalValue(scope) else value.get(scope).value
|
val v = if (PerfFlags.RVAL_FASTPATH) value.evalValue(scope) else value.get(scope).value
|
||||||
val rec = target.get(scope)
|
val rec = target.get(scope)
|
||||||
if (!rec.isMutable) throw ScriptError(atPos, "cannot assign to immutable variable")
|
if (!rec.isMutable) throw ScriptError(atPos, "cannot assign to immutable variable")
|
||||||
if (rec.value.assign(scope, v) == null) {
|
if (rec.value.assign(scope, v) == null) {
|
||||||
|
|||||||
@ -2569,7 +2569,6 @@ class ScriptTest {
|
|||||||
x += i
|
x += i
|
||||||
}
|
}
|
||||||
delay(100)
|
delay(100)
|
||||||
println("-> "+x)
|
|
||||||
assert(x == 5050)
|
assert(x == 5050)
|
||||||
}
|
}
|
||||||
""".trimIndent())
|
""".trimIndent())
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user