Support dynamic import call phases#687
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (2)
📝 WalkthroughWalkthroughThis PR adds parser and runtime support for dynamic import option syntax and new import call phases. The changes introduce ChangesDynamic import options and import phases
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
Benchmark Results407 benchmarks Interpreted: 🟢 57 improved · 🔴 222 regressed · 128 unchanged · avg -2.4% arraybuffer.js — Interp: 🔴 9, 5 unch. · avg -6.3% · Bytecode: 🔴 12, 2 unch. · avg -7.5%
arrays.js — Interp: 🔴 16, 3 unch. · avg -5.4% · Bytecode: 🔴 17, 2 unch. · avg -8.3%
async-await.js — Interp: 🔴 6 · avg -6.7% · Bytecode: 🔴 5, 1 unch. · avg -7.3%
async-generators.js — Interp: 🔴 2 · avg -7.4% · Bytecode: 🔴 1, 1 unch. · avg -10.2%
base64.js — Interp: 🔴 4, 6 unch. · avg -3.2% · Bytecode: 🟢 7, 🔴 3 · avg +0.1%
classes.js — Interp: 🟢 1, 🔴 20, 10 unch. · avg -4.0% · Bytecode: 🔴 20, 11 unch. · avg -6.9%
closures.js — Interp: 🔴 10, 1 unch. · avg -5.6% · Bytecode: 🔴 11 · avg -10.1%
collections.js — Interp: 🔴 12 · avg -11.1% · Bytecode: 🔴 12 · avg -10.7%
csv.js — Interp: 🟢 2, 11 unch. · avg +0.8% · Bytecode: 🔴 13 · avg -12.0%
destructuring.js — Interp: 🔴 17, 5 unch. · avg -5.5% · Bytecode: 🔴 22 · avg -9.2%
fibonacci.js — Interp: 🔴 8 · avg -8.0% · Bytecode: 🔴 8 · avg -11.8%
float16array.js — Interp: 🟢 13, 🔴 8, 11 unch. · avg +4.0% · Bytecode: 🔴 27, 5 unch. · avg -7.6%
for-of.js — Interp: 🔴 5, 2 unch. · avg -2.4% · Bytecode: 🔴 7 · avg -11.1%
generators.js — Interp: 🔴 3, 1 unch. · avg -5.6% · Bytecode: 🔴 3, 1 unch. · avg -4.7%
iterators.js — Interp: 🔴 42 · avg -8.4% · Bytecode: 🔴 40, 2 unch. · avg -8.8%
json.js — Interp: 🔴 16, 4 unch. · avg -6.0% · Bytecode: 🔴 18, 2 unch. · avg -9.2%
jsx.jsx — Interp: 🟢 2, 🔴 5, 14 unch. · avg -1.2% · Bytecode: 🔴 21 · avg -8.9%
modules.js — Interp: 🔴 2, 7 unch. · avg -1.8% · Bytecode: 🔴 9 · avg -12.1%
numbers.js — Interp: 🟢 3, 🔴 3, 5 unch. · avg -0.2% · Bytecode: 🔴 11 · avg -10.3%
objects.js — Interp: 🟢 1, 🔴 1, 5 unch. · avg -0.1% · Bytecode: 🔴 7 · avg -8.7%
promises.js — Interp: 🔴 6, 6 unch. · avg -4.0% · Bytecode: 🔴 12 · avg -9.0%
regexp.js — Interp: 🟢 3, 🔴 1, 7 unch. · avg +1.6% · Bytecode: 🟢 7, 🔴 3, 1 unch. · avg +5.1%
strings.js — Interp: 🟢 3, 🔴 5, 11 unch. · avg -0.6% · Bytecode: 🔴 18, 1 unch. · avg -9.5%
tsv.js — Interp: 🟢 8, 🔴 1 · avg +5.5% · Bytecode: 🔴 9 · avg -10.5%
typed-arrays.js — Interp: 🟢 8, 🔴 6, 8 unch. · avg -0.5% · Bytecode: 🟢 5, 🔴 10, 7 unch. · avg +6.6%
uint8array-encoding.js — Interp: 🟢 1, 🔴 14, 3 unch. · avg -22.8% · Bytecode: 🟢 1, 🔴 17 · avg -32.0%
weak-collections.js — Interp: 🟢 12, 3 unch. · avg +43.8% · Bytecode: 🟢 3, 🔴 11, 1 unch. · avg -0.2%
Deterministic profile diffDeterministic profile diff: no significant changes. Measured on ubuntu-latest x64. Benchmark ranges compare cached main-branch min/max ops/sec with the PR run; overlapping ranges are treated as unchanged noise. Percentage deltas are secondary context. |
Suite TimingTest Runner (interpreted: 9,819 passed; bytecode: 9,819 passed)
MemoryGC rows aggregate the main thread plus all worker thread-local GCs. Test runner worker shutdown frees thread-local heaps in bulk; that shutdown reclamation is not counted as GC collections or collected objects.
Benchmarks (interpreted: 407; bytecode: 407)
MemoryGC rows aggregate the main thread plus all worker thread-local GCs. Benchmark runner performs explicit between-file collections, so collection and collected-object counts can be much higher than the test runner.
Measured on ubuntu-latest x64. |
0315eb2 to
9b07382
Compare
test262 Conformance
Areas closest to 100%
Per-test deltas (+164 / -0)Newly passing (164):
Steady-state failures are non-blocking; regressions vs the cached main baseline (lower total pass count, or any PASS → non-PASS transition) fail the conformance gate. Measured on ubuntu-latest x64, bytecode mode. Areas grouped by the first two test262 path components; minimum 25 attempted tests, areas already at 100% excluded. Δ vs main compares against the most recent cached |
Parse dynamic import trailing comma/options syntax and preserve import.source/import.defer phases in the AST and bytecode. Evaluate import options for side effects while leaving attribute semantics for later. Add source-phase module source values and deferred dynamic import namespace wrappers so import.source resolves without evaluating the target module and import.defer delays evaluation until namespace exports are observed. Wire both paths through interpreter and bytecode execution. Update dynamic import docs and regression coverage for source/defer behavior. Closes #646
9b07382 to
68d7579
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
source/units/Goccia.Interpreter.pas (1)
149-160:⚠️ Potential issue | 🟠 Major | ⚡ Quick winInitialize
DisposalTrackerinCreateEvaluationContext.Line 149 builds a stack record;
Result.DisposalTrackeris never assigned here, so it can remain undefined and trip downstreamAssigned(...)checks.🩹 Proposed fix
function TGocciaInterpreter.CreateEvaluationContext: TGocciaEvaluationContext; begin Result.Scope := FGlobalScope; Result.OnError := ThrowError; Result.LoadModule := LoadModule; Result.LoadModuleSource := LoadModuleSourceValue; Result.CurrentFilePath := FFileName; Result.CoverageEnabled := Assigned(TGocciaCoverageTracker.Instance) and TGocciaCoverageTracker.Instance.Enabled; Result.StrictTypes := FStrictTypesEnabled; Result.NonStrictMode := FNonStrictModeEnabled; + Result.DisposalTracker := nil; end;🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@source/units/Goccia.Interpreter.pas` around lines 149 - 160, The evaluation context built in TGocciaInterpreter.CreateEvaluationContext does not set Result.DisposalTracker, leaving it undefined; update CreateEvaluationContext to initialize DisposalTracker (e.g. assign a new TGocciaDisposalTracker instance to Result.DisposalTracker) so subsequent Assigned(...) checks are safe, and ensure the evaluation context's lifecycle code (where TGocciaEvaluationContext is freed) takes responsibility for freeing that DisposalTracker to avoid leaks.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@source/units/Goccia.Modules.pas`:
- Around line 163-164: Module returned from FLoadModule(FModulePath,
FImportingFilePath) may be nil but is dereferenced immediately via
Module.GetNamespaceObject; add a nil check after calling FLoadModule and handle
the nil case by raising a script error or returning early instead of proceeding.
Update the block that assigns Module and FNamespaceObject to first assign Module
:= FLoadModule(...), then if Module = nil then raise an appropriate exception or
set an error result (so callers receive a controlled script error), otherwise
call Module.GetNamespaceObject to assign FNamespaceObject; reference
FLoadModule, Module, FNamespaceObject, FModulePath and FImportingFilePath when
making the change.
In `@source/units/Goccia.VM.pas`:
- Around line 10170-10203: The dynamic-import handling currently treats any
unknown phase (variable C) as a normal import, which can silently execute
modules for malformed bytecode; update the cases in the blocks that call
DynImportPromise.Resolve (the branches using
VMRegisterToStringFast(FRegisters[B]).Value and Template.DebugInfo.SourceFile or
FCurrentModuleSourcePath) to explicitly handle only known icpSource and icpDefer
values and, for any other C value, fail closed by rejecting the DynImportPromise
(or raising a VM/Import error) with a clear message including the offending
phase and module name instead of calling ImportModuleValue; ensure both the
Template.DebugInfo branch and the FCurrentModuleSourcePath branch apply the same
reject/raise behavior and reference the same identifying symbols
(DynImportPromise.Resolve, ImportModuleSourceValue,
ImportDeferredModuleNamespaceValue, ImportModuleValue) when locating where to
change the logic.
---
Outside diff comments:
In `@source/units/Goccia.Interpreter.pas`:
- Around line 149-160: The evaluation context built in
TGocciaInterpreter.CreateEvaluationContext does not set Result.DisposalTracker,
leaving it undefined; update CreateEvaluationContext to initialize
DisposalTracker (e.g. assign a new TGocciaDisposalTracker instance to
Result.DisposalTracker) so subsequent Assigned(...) checks are safe, and ensure
the evaluation context's lifecycle code (where TGocciaEvaluationContext is
freed) takes responsibility for freeing that DisposalTracker to avoid leaks.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 9bedb3bf-9970-4200-bef2-fb81734a8dd3
📒 Files selected for processing (18)
docs/interpreter.mddocs/language.mdsource/units/Goccia.AST.Expressions.passource/units/Goccia.Compiler.Expressions.passource/units/Goccia.Evaluator.Context.passource/units/Goccia.Executor.Bytecode.passource/units/Goccia.Interpreter.passource/units/Goccia.Keywords.Contextual.passource/units/Goccia.Modules.Loader.passource/units/Goccia.Modules.passource/units/Goccia.Parser.passource/units/Goccia.Scope.passource/units/Goccia.VM.passource/units/Goccia.Values.FunctionValue.passource/units/Goccia.Values.GeneratorValue.pastests/language/modules/dynamic-import.jstests/language/modules/helpers/deferred-dynamic-import-side-effect.jstests/language/modules/helpers/source-dynamic-import-side-effect.js
Guard deferred namespace loader results before dereference. Reject unsupported bytecode dynamic import phases instead of falling back to ordinary import.
Summary
import(specifier, options), andimport.source(...)/import.defer(...)call spellings.import.source(...)as aModuleSourcevalue without target evaluation andimport.defer(...)as a deferred namespace wrapper that resolves the specifier before fulfillment and evaluates when exports are observed.Testing
./build.pas clean testrunner./build/GocciaTestRunner tests/language/modules/dynamic-import.js./build/GocciaTestRunner tests/language/modules/dynamic-import.js --mode=bytecode./build/GocciaTestRunner tests/language/functions/stack-depth-limit.js./build.pas loaderbarebun scripts/run_test262_suite.ts --suite-dir /tmp/goccia-test262-vXUU7U --filter 'language/expressions/dynamic-import/syntax/valid/nested-with-*' --categories language --mode interpreted --jobs 1 --timeout-ms 10000 --max-tests 0bun scripts/run_test262_suite.ts --suite-dir /tmp/goccia-test262-vXUU7U --filter 'language/expressions/dynamic-import/syntax/valid/nested-with-*' --categories language --mode bytecode --jobs 1 --timeout-ms 10000 --max-tests 0./fixtures/ffi/build.sh./build/GocciaTestRunner tests./format.pas --checkgit diff --check