MIRROR: javascript for ๐Ÿœ's, a tiny runtime with big ambitions
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

clean up destructuring iterator helpers to avoid VM stack relocation

+68 -63
+21 -63
src/silver/glue.c
··· 23 23 return used > js->cstk.limit; 24 24 } 25 25 26 - static bool jit_vm_ensure_stack(sv_vm_t *vm, int need) { 27 - while (vm->sp + need > vm->stack_size) { 28 - int new_size = vm->stack_size * 2; 29 - if (new_size > SV_STACK_HARD_MAX) new_size = SV_STACK_HARD_MAX; 30 - if (new_size <= vm->stack_size) return false; 31 - 32 - ant_value_t *old = vm->stack; 33 - int old_size = vm->stack_size; 34 - 35 - ant_value_t *ns = realloc(vm->stack, (size_t)new_size * sizeof(ant_value_t)); 36 - if (!ns) return false; 37 - 38 - ptrdiff_t delta = ns - old; 39 - vm->stack = ns; 40 - vm->stack_size = new_size; 41 - 42 - if (delta != 0) { 43 - for (int i = 0; i <= vm->fp; i++) { 44 - if (vm->frames[i].bp) vm->frames[i].bp += delta; 45 - if (vm->frames[i].lp) vm->frames[i].lp += delta; 46 - } 47 - for (sv_upvalue_t *uv = vm->open_upvalues; uv; uv = uv->next) if ( 48 - uv->location != &uv->closed && 49 - sv_slot_in_range(old, (size_t)old_size, uv->location) 50 - ) uv->location += delta; 51 - } 52 - } 53 - 54 - return true; 55 - } 56 - 57 26 ant_value_t jit_helper_stack_overflow_error(sv_vm_t *vm, ant_t *js) { 58 27 return js_mkerr_typed(js, JS_ERR_RANGE | JS_ERR_NO_STACK, "Maximum JIT call stack size exceeded"); 59 28 } ··· 377 346 }} 378 347 } 379 348 349 + void jit_helper_destructure_close( 350 + sv_vm_t *vm, ant_t *js, ant_value_t *iter_buf 351 + ) { 352 + GC_ROOT_SAVE(root_mark, js); 353 + 354 + int tag = (int)js_getnum(iter_buf[2]); 355 + if (tag == SV_ITER_GENERIC) { 356 + ant_value_t iterator = iter_buf[0]; 357 + GC_ROOT_PIN(js, iterator); 358 + ant_value_t return_fn = js_getprop_fallback(js, iterator, "return"); 359 + GC_ROOT_PIN(js, return_fn); 360 + uint8_t ft = vtype(return_fn); 361 + if (ft == T_FUNC || ft == T_CFUNC) 362 + sv_vm_call(vm, js, return_fn, iterator, NULL, 0, NULL, false); 363 + } 364 + 365 + GC_ROOT_RESTORE(js, root_mark); 366 + } 367 + 380 368 ant_value_t jit_helper_for_of( 381 369 sv_vm_t *vm, ant_t *js, 382 370 ant_value_t iterable, ant_value_t *iter_buf ··· 451 439 return tov(0); 452 440 } 453 441 454 - void jit_helper_destructure_close( 455 - sv_vm_t *vm, ant_t *js, 456 - ant_value_t *iter_buf 457 - ) { 458 - int old_sp = vm->sp; 459 - if (!jit_vm_ensure_stack(vm, 3)) 460 - return; 461 - 462 - vm->stack[vm->sp++] = iter_buf[0]; 463 - vm->stack[vm->sp++] = iter_buf[1]; 464 - vm->stack[vm->sp++] = iter_buf[2]; 465 - sv_op_iter_close(vm, js); 466 - vm->sp = old_sp; 467 - } 468 - 469 442 ant_value_t jit_helper_destructure_next( 470 443 sv_vm_t *vm, ant_t *js, 471 444 ant_value_t *iter_buf 472 445 ) { 473 - int old_sp = vm->sp; 474 - if (!jit_vm_ensure_stack(vm, 4)) 475 - return js_mkerr(js, "stack overflow"); 476 - 477 - vm->stack[vm->sp++] = iter_buf[0]; 478 - vm->stack[vm->sp++] = iter_buf[1]; 479 - vm->stack[vm->sp++] = iter_buf[2]; 480 - 481 446 ant_value_t value = js_mkundef(); 482 447 bool done = false; 483 - ant_value_t status = sv_iter_advance(vm, js, 0, &value, &done); 484 - if (is_err(status)) { 485 - vm->sp = old_sp; 486 - return status; 487 - } 448 + ant_value_t status = jit_iter_advance_from_buf(vm, js, iter_buf, 0, &value, &done); 449 + if (is_err(status)) return status; 488 450 489 - iter_buf[0] = vm->stack[old_sp + 0]; 490 - iter_buf[1] = vm->stack[old_sp + 1]; 491 - iter_buf[2] = vm->stack[old_sp + 2]; 492 451 iter_buf[3] = done ? js_mkundef() : value; 493 - vm->sp = old_sp; 494 452 return status; 495 453 } 496 454
+47
tests/test_jit_destructure_arg_resume.cjs
··· 1 + function assertEq(actual, expected, msg) { 2 + if (actual !== expected) { 3 + throw new Error(msg + " (expected " + expected + ", got " + actual + ")"); 4 + } 5 + } 6 + 7 + function makeValues(count, first) { 8 + const values = new Array(count); 9 + for (let i = 0; i < count; i++) values[i] = i; 10 + values[0] = first; 11 + return values; 12 + } 13 + 14 + function makeTarget(paramCount) { 15 + const params = []; 16 + let source = ""; 17 + 18 + for (let i = 0; i < paramCount; i++) { 19 + params.push("a" + i); 20 + } 21 + 22 + source += "function target(" + params.join(",") + ") {"; 23 + source += " let [x] = [1, 2];"; 24 + source += " return a0;"; 25 + source += "}"; 26 + source += "return target;"; 27 + return Function(source)(); 28 + } 29 + 30 + function runCase(label, paramCount) { 31 + const target = makeTarget(paramCount); 32 + const warm = makeValues(paramCount, "warm"); 33 + 34 + for (let i = 0; i < 200; i++) { 35 + const got = target.apply(undefined, warm); 36 + assertEq(got, "warm", label + " should preserve arg reads during warmup"); 37 + } 38 + 39 + const magic = makeValues(paramCount, "MAGIC"); 40 + const got = target.apply(undefined, magic); 41 + assertEq(got, "MAGIC", label + " should preserve arg reads after destructuring"); 42 + } 43 + 44 + runCase("high-arity apply call", 242); 45 + runCase("slightly-lower-arity apply call", 241); 46 + 47 + console.log("OK: test_jit_destructure_arg_resume");