str stone; concat

This commit is contained in:
2026-02-20 21:54:19 -06:00
parent a82c13170f
commit fca1041e52
9 changed files with 389 additions and 15 deletions

View File

@@ -212,6 +212,7 @@ typedef enum MachOpcode {
/* Text */
MACH_CONCAT, /* R(A) = R(B) ++ R(C) — string concatenation */
MACH_STONE_TEXT, /* stone(R(A)) — freeze mutable text before escape */
/* Typed integer comparisons (ABC) */
MACH_EQ_INT, /* R(A) = (R(B) == R(C)) — int */
@@ -372,6 +373,7 @@ static const char *mach_opcode_names[MACH_OP_COUNT] = {
[MACH_NOP] = "nop",
/* Mcode-derived */
[MACH_CONCAT] = "concat",
[MACH_STONE_TEXT] = "stone_text",
[MACH_EQ_INT] = "eq_int",
[MACH_NE_INT] = "ne_int",
[MACH_LT_INT] = "lt_int",
@@ -1392,7 +1394,7 @@ vm_dispatch:
DT(MACH_HASPROP), DT(MACH_REGEXP),
DT(MACH_EQ_TOL), DT(MACH_NEQ_TOL),
DT(MACH_NOP),
DT(MACH_CONCAT),
DT(MACH_CONCAT), DT(MACH_STONE_TEXT),
DT(MACH_EQ_INT), DT(MACH_NE_INT),
DT(MACH_LT_INT), DT(MACH_LE_INT),
DT(MACH_GT_INT), DT(MACH_GE_INT),
@@ -2026,6 +2028,7 @@ vm_dispatch:
}
target = next;
}
stone_mutable_text(target->slots[c]);
frame->slots[a] = target->slots[c];
VM_BREAK();
}
@@ -2123,6 +2126,7 @@ vm_dispatch:
}
VM_CASE(MACH_RETURN):
stone_mutable_text(frame->slots[a]);
result = frame->slots[a];
if (!JS_IsPtr(frame->caller)) goto done;
{
@@ -2285,15 +2289,48 @@ vm_dispatch:
/* === New mcode-derived opcodes === */
/* Text concatenation */
/* Text concatenation — with in-place append fast path for s = s + x */
VM_CASE(MACH_CONCAT): {
JSValue res = JS_ConcatString(ctx, frame->slots[b], frame->slots[c]);
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
if (JS_IsException(res)) goto disrupt;
frame->slots[a] = res;
if (a == b) {
/* Self-assign pattern: slot[a] = slot[a] + slot[c] */
JSValue left = frame->slots[a];
JSValue right = frame->slots[c];
/* Inline fast path: mutable heap text with enough capacity */
if (JS_IsPtr(left)) {
JSText *s = (JSText *)chase(left);
int slen = (int)s->length;
int rlen = js_string_value_len(right);
int cap = (int)objhdr_cap56(s->hdr);
if (objhdr_type(s->hdr) == OBJ_TEXT
&& !(s->hdr & OBJHDR_S_MASK)
&& slen + rlen <= cap) {
/* Append in-place — zero allocation, no GC possible */
for (int i = 0; i < rlen; i++)
string_put(s, slen + i, js_string_value_get(right, i));
s->length = slen + rlen;
VM_BREAK();
}
}
/* Slow path: allocate with growth factor, leave unstoned */
JSValue res = JS_ConcatStringGrow(ctx, frame->slots[b], frame->slots[c]);
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
if (JS_IsException(res)) goto disrupt;
frame->slots[a] = res;
} else {
/* Different target: use existing exact-fit stoned path */
JSValue res = JS_ConcatString(ctx, frame->slots[b], frame->slots[c]);
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
if (JS_IsException(res)) goto disrupt;
frame->slots[a] = res;
}
VM_BREAK();
}
/* Stone mutable text — compiler-emitted at escape points */
VM_CASE(MACH_STONE_TEXT):
stone_mutable_text(frame->slots[a]);
VM_BREAK();
/* Typed integer comparisons */
VM_CASE(MACH_EQ_INT):
frame->slots[a] = JS_NewBool(ctx, JS_VALUE_GET_INT(frame->slots[b]) == JS_VALUE_GET_INT(frame->slots[c]));
@@ -3026,6 +3063,7 @@ static MachCode *mcode_lower_func(cJSON *fobj, const char *filename) {
else if (strcmp(op, "move") == 0) { AB2(MACH_MOVE); }
/* Text */
else if (strcmp(op, "concat") == 0) { ABC3(MACH_CONCAT); }
else if (strcmp(op, "stone_text") == 0) { EM(MACH_ABC(MACH_STONE_TEXT, A1, 0, 0)); }
/* Generic arithmetic */
else if (strcmp(op, "add") == 0) { ABC3(MACH_ADD); }
else if (strcmp(op, "subtract") == 0) { ABC3(MACH_SUB); }