From b65246896c79f081fdfb0935f79e6c953e1ec333 Mon Sep 17 00:00:00 2001 From: Yehuda Katz Date: Tue, 5 Nov 2024 16:26:26 -0800 Subject: [PATCH] Substantial clarity improvements Improvements to naming and documentation as well as significant consolidation of concepts that no longer need to be separated. The consolidation is largely driven by the removal of concepts that were originally introduced for the (long removed) AOT mode. --- .../lib/benchmark/create-registry.ts | 38 ++++--- .../lib/benchmark/render-benchmark.ts | 23 +--- .../lib/modes/jit/compilation-context.ts | 4 +- .../lib/modes/jit/delegate.ts | 39 +++---- .../integration-tests/lib/modes/jit/render.ts | 17 +-- .../lib/modes/jit/resolver.ts | 4 +- .../lib/modes/rehydration/delegate.ts | 18 ++-- .../partial-rehydration-delegate.ts | 18 ++-- .../test/debug-render-tree-test.ts | 8 +- .../@glimmer/debug-util/lib/platform-utils.ts | 2 +- packages/@glimmer/debug/lib/debug.ts | 26 ++--- packages/@glimmer/debug/lib/dism/opcode.ts | 8 +- packages/@glimmer/debug/lib/dism/operands.ts | 16 +-- .../lib/managers/internal/component.d.ts | 4 +- packages/@glimmer/interfaces/lib/program.d.ts | 71 +++++++------ packages/@glimmer/interfaces/lib/runtime.d.ts | 1 - .../interfaces/lib/runtime/environment.d.ts | 7 ++ .../@glimmer/interfaces/lib/runtime/jit.d.ts | 7 -- .../interfaces/lib/runtime/local-debug.d.ts | 6 +- .../interfaces/lib/runtime/runtime.d.ts | 27 ++--- .../@glimmer/interfaces/lib/serialize.d.ts | 17 ++- .../lib/compilable-template.ts | 9 +- .../@glimmer/opcode-compiler/lib/compiler.ts | 4 +- .../lib/opcode-builder/context.ts | 20 +--- .../lib/opcode-builder/encoder.ts | 19 ++-- .../lib/opcode-builder/helpers/resolution.ts | 40 +++---- .../lib/opcode-builder/helpers/stdlib.ts | 12 +-- .../opcode-compiler/lib/program-context.ts | 29 +++-- .../opcode-compiler/lib/wrapped-component.ts | 7 +- packages/@glimmer/program/lib/opcode.ts | 4 +- packages/@glimmer/program/lib/program.ts | 53 ++-------- .../runtime/lib/compiled/opcodes/component.ts | 10 +- .../lib/compiled/opcodes/expressions.ts | 2 +- .../@glimmer/runtime/lib/component/resolve.ts | 6 +- packages/@glimmer/runtime/lib/environment.ts | 14 +-- packages/@glimmer/runtime/lib/opcodes.ts | 15 +++ .../runtime/lib/references/curry-value.ts | 6 +- packages/@glimmer/runtime/lib/render.ts | 39 +++---- packages/@glimmer/runtime/lib/vm/append.ts | 100 ++++++------------ packages/@glimmer/runtime/lib/vm/low-level.ts | 23 ++-- packages/@glimmer/runtime/lib/vm/update.ts | 27 +++-- 41 files changed, 346 insertions(+), 454 deletions(-) delete mode 100644 packages/@glimmer/interfaces/lib/runtime/jit.d.ts diff --git a/packages/@glimmer-workspace/benchmark-env/lib/benchmark/create-registry.ts b/packages/@glimmer-workspace/benchmark-env/lib/benchmark/create-registry.ts index 0bb4a87e3..ce4577ce9 100644 --- a/packages/@glimmer-workspace/benchmark-env/lib/benchmark/create-registry.ts +++ b/packages/@glimmer-workspace/benchmark-env/lib/benchmark/create-registry.ts @@ -5,6 +5,7 @@ import type { InternalModifierManager, ModifierDefinitionState, ResolvedComponentDefinition, + SimpleDocument, SimpleElement, } from '@glimmer/interfaces'; import { @@ -13,11 +14,13 @@ import { setInternalHelperManager, setInternalModifierManager, } from '@glimmer/manager'; -import { programCompilationContext } from '@glimmer/opcode-compiler'; +import { ProgramContextImpl } from '@glimmer/opcode-compiler'; import { artifacts, RuntimeOpImpl } from '@glimmer/program'; +import { runtimeContext } from '@glimmer/runtime'; import type { UpdateBenchmark } from '../interfaces'; +import createEnvDelegate from './create-env-delegate'; import renderBenchmark from './render-benchmark'; export interface Registry { @@ -77,9 +80,23 @@ export default function createRegistry(): Registry { setInternalModifierManager(manager, modifier); modifiers.set(name, modifier); }, - render: (entry, args, element, isIteractive) => { + render: (entry, args, element, isInteractive) => { const sharedArtifacts = artifacts(); - const context = programCompilationContext( + + const document = element.ownerDocument as SimpleDocument; + const envDelegate = createEnvDelegate(isInteractive ?? true); + const runtime = runtimeContext( + { + document, + }, + envDelegate, + sharedArtifacts, + { + lookupComponent: () => null, + } + ); + + const context = new ProgramContextImpl( sharedArtifacts, { lookupHelper: (name) => helpers.get(name) ?? null, @@ -89,24 +106,15 @@ export default function createRegistry(): Registry { lookupBuiltInHelper: () => null, lookupBuiltInModifier: () => null, }, - (heap) => new RuntimeOpImpl(heap) + (heap) => new RuntimeOpImpl(heap), + runtime ); const component = components.get(entry); if (!component) { throw new Error(`missing ${entry} component`); } - return renderBenchmark( - sharedArtifacts, - context, - { - lookupComponent: () => null, - }, - component, - args, - element as SimpleElement, - isIteractive - ); + return renderBenchmark(sharedArtifacts, context, component, args, element as SimpleElement); }, }; } diff --git a/packages/@glimmer-workspace/benchmark-env/lib/benchmark/render-benchmark.ts b/packages/@glimmer-workspace/benchmark-env/lib/benchmark/render-benchmark.ts index c7db3edc0..8b5192074 100644 --- a/packages/@glimmer-workspace/benchmark-env/lib/benchmark/render-benchmark.ts +++ b/packages/@glimmer-workspace/benchmark-env/lib/benchmark/render-benchmark.ts @@ -3,45 +3,32 @@ import type { ProgramContext, ResolvedComponentDefinition, RuntimeArtifacts, - RuntimeResolver, SimpleElement, } from '@glimmer/interfaces'; -import { NewElementBuilder, renderComponent, renderSync, runtimeContext } from '@glimmer/runtime'; +import { NewElementBuilder, renderComponent, renderSync } from '@glimmer/runtime'; import type { UpdateBenchmark } from '../interfaces'; -import createEnvDelegate, { registerResult } from './create-env-delegate'; +import { registerResult } from './create-env-delegate'; import { measureRender } from './util'; export default async function renderBenchmark( artifacts: RuntimeArtifacts, context: ProgramContext, - runtimeResolver: RuntimeResolver, component: ResolvedComponentDefinition, args: Dict, - element: SimpleElement, - isInteractive = true + element: SimpleElement ): Promise { let resolveRender: (() => void) | undefined; await measureRender('render', 'renderStart', 'renderEnd', () => { - const document = element.ownerDocument; - const envDelegate = createEnvDelegate(isInteractive); - const runtime = runtimeContext( - { - document, - }, - envDelegate, - artifacts, - runtimeResolver - ); - const env = runtime.env; + const env = context.env; const cursor = { element, nextSibling: null }; const treeBuilder = NewElementBuilder.forInitialRender(env, cursor); const result = renderSync( env, - renderComponent(runtime, treeBuilder, context, {}, component.state, args) + renderComponent(context, treeBuilder, {}, component.state, args) ); registerResult(result, () => { diff --git a/packages/@glimmer-workspace/integration-tests/lib/modes/jit/compilation-context.ts b/packages/@glimmer-workspace/integration-tests/lib/modes/jit/compilation-context.ts index d9b405942..a4f8d235b 100644 --- a/packages/@glimmer-workspace/integration-tests/lib/modes/jit/compilation-context.ts +++ b/packages/@glimmer-workspace/integration-tests/lib/modes/jit/compilation-context.ts @@ -1,5 +1,5 @@ import type { - CompileTimeResolver, + ClassicResolver, HelperDefinitionState, ModifierDefinitionState, Nullable, @@ -8,7 +8,7 @@ import type { import type { TestJitRuntimeResolver } from './resolver'; -export default class JitCompileTimeLookup implements CompileTimeResolver { +export default class JitCompileTimeLookup implements ClassicResolver { constructor(private resolver: TestJitRuntimeResolver) {} lookupHelper(name: string): Nullable { diff --git a/packages/@glimmer-workspace/integration-tests/lib/modes/jit/delegate.ts b/packages/@glimmer-workspace/integration-tests/lib/modes/jit/delegate.ts index eed5c7d56..0e8499437 100644 --- a/packages/@glimmer-workspace/integration-tests/lib/modes/jit/delegate.ts +++ b/packages/@glimmer-workspace/integration-tests/lib/modes/jit/delegate.ts @@ -8,10 +8,9 @@ import type { Environment, HandleResult, Helper, - Nullable, ProgramContext, + Nullable, RenderResult, - RuntimeContext, SimpleDocument, SimpleDocumentFragment, SimpleElement, @@ -21,7 +20,7 @@ import type { Reference } from '@glimmer/reference'; import type { CurriedValue, EnvironmentDelegate } from '@glimmer/runtime'; import type { ASTPluginBuilder, PrecompileOptions } from '@glimmer/syntax'; import { castToBrowser, castToSimple, expect, unwrapTemplate } from '@glimmer/debug-util'; -import { programCompilationContext } from '@glimmer/opcode-compiler'; +import { ProgramContextImpl } from '@glimmer/opcode-compiler'; import { artifacts, RuntimeOpImpl } from '@glimmer/program'; import { createConstRef } from '@glimmer/reference'; import { @@ -58,24 +57,19 @@ import { TestJitRegistry } from './registry'; import { renderTemplate } from './render'; import { TestJitRuntimeResolver } from './resolver'; -export interface JitTestDelegateContext { - runtime: RuntimeContext; - program: ProgramContext; -} - export function JitDelegateContext( doc: SimpleDocument, resolver: TestJitRuntimeResolver, env: EnvironmentDelegate -): JitTestDelegateContext { +): ProgramContext { let sharedArtifacts = artifacts(); - let context = programCompilationContext( + let runtime = runtimeContext({ document: doc }, env, sharedArtifacts, resolver); + return new ProgramContextImpl( sharedArtifacts, new JitCompileTimeLookup(resolver), - (heap) => new RuntimeOpImpl(heap) + (heap) => new RuntimeOpImpl(heap), + runtime ); - let runtime = runtimeContext({ document: doc }, env, sharedArtifacts, resolver); - return { runtime, program: context }; } export class JitRenderDelegate implements RenderDelegate { @@ -86,7 +80,7 @@ export class JitRenderDelegate implements RenderDelegate { protected resolver: TestJitRuntimeResolver; private plugins: ASTPluginBuilder[] = []; - private _context: JitTestDelegateContext | null = null; + private _context: ProgramContext | null = null; private self: Nullable = null; private doc: SimpleDocument; private env: EnvironmentDelegate; @@ -108,7 +102,7 @@ export class JitRenderDelegate implements RenderDelegate { this.registry.register('helper', 'concat', concat); } - get context(): JitTestDelegateContext { + get context(): ProgramContext { if (this._context === null) { this._context = JitDelegateContext(this.doc, this.resolver, this.env); } @@ -118,7 +112,7 @@ export class JitRenderDelegate implements RenderDelegate { getCapturedRenderTree(): CapturedRenderNode[] { return expect( - this.context.runtime.env.debugRenderTree, + this.context.env.debugRenderTree, 'Attempted to capture the DebugRenderTree during tests, but it was not created. Did you enable it in the environment?' ).capture(); } @@ -206,13 +200,13 @@ export class JitRenderDelegate implements RenderDelegate { compileTemplate(template: string): HandleResult { let compiled = preprocess(template, this.precompileOptions); - return unwrapTemplate(compiled).asLayout().compile(this.context.program); + return unwrapTemplate(compiled).asLayout().compile(this.context); } renderTemplate(template: string, context: Dict, element: SimpleElement): RenderResult { let cursor = { element, nextSibling: null }; - let { env } = this.context.runtime; + let { env } = this.context; return renderTemplate( template, @@ -230,11 +224,12 @@ export class JitRenderDelegate implements RenderDelegate { dynamicScope?: DynamicScope ): RenderResult { let cursor = { element, nextSibling: null }; - let { program, runtime } = this.context; - let builder = this.getElementBuilder(runtime.env, cursor); - let iterator = renderComponent(runtime, builder, program, {}, component, args, dynamicScope); + let { context } = this; + + let builder = this.getElementBuilder(context.env, cursor); + let iterator = renderComponent(this.context, builder, {}, component, args, dynamicScope); - return renderSync(runtime.env, iterator); + return renderSync(context.env, iterator); } private get precompileOptions(): PrecompileOptions { diff --git a/packages/@glimmer-workspace/integration-tests/lib/modes/jit/render.ts b/packages/@glimmer-workspace/integration-tests/lib/modes/jit/render.ts index 2ac9c1c15..7e867e5fd 100644 --- a/packages/@glimmer-workspace/integration-tests/lib/modes/jit/render.ts +++ b/packages/@glimmer-workspace/integration-tests/lib/modes/jit/render.ts @@ -1,29 +1,20 @@ -import type { ElementBuilder, RenderResult } from '@glimmer/interfaces'; +import type { ElementBuilder, ProgramContext, RenderResult } from '@glimmer/interfaces'; import type { Reference } from '@glimmer/reference'; import type { PrecompileOptions } from '@glimmer/syntax'; import { unwrapTemplate } from '@glimmer/debug-util'; import { renderMain, renderSync } from '@glimmer/runtime'; -import type { JitTestDelegateContext } from './delegate'; - import { preprocess } from '../../compile'; export function renderTemplate( src: string, - { runtime, program }: JitTestDelegateContext, + context: ProgramContext, self: Reference, builder: ElementBuilder, options?: PrecompileOptions ): RenderResult { let template = preprocess(src, options); - let iterator = renderMain( - runtime, - program, - {}, - self, - builder, - unwrapTemplate(template).asLayout() - ); - return renderSync(runtime.env, iterator); + let iterator = renderMain(context, {}, self, builder, unwrapTemplate(template).asLayout()); + return renderSync(context.env, iterator); } diff --git a/packages/@glimmer-workspace/integration-tests/lib/modes/jit/resolver.ts b/packages/@glimmer-workspace/integration-tests/lib/modes/jit/resolver.ts index 6cf6b2613..fd1aa5da9 100644 --- a/packages/@glimmer-workspace/integration-tests/lib/modes/jit/resolver.ts +++ b/packages/@glimmer-workspace/integration-tests/lib/modes/jit/resolver.ts @@ -1,14 +1,14 @@ import type { HelperDefinitionState, + ClassicResolver, ModifierDefinitionState, Nullable, ResolvedComponentDefinition, - RuntimeResolver, } from '@glimmer/interfaces'; import type { TestJitRegistry } from './registry'; -export class TestJitRuntimeResolver implements RuntimeResolver { +export class TestJitRuntimeResolver implements ClassicResolver { constructor(private registry: TestJitRegistry) {} lookupHelper(name: string): Nullable { diff --git a/packages/@glimmer-workspace/integration-tests/lib/modes/rehydration/delegate.ts b/packages/@glimmer-workspace/integration-tests/lib/modes/rehydration/delegate.ts index 7f8e4e660..f1a7cb592 100644 --- a/packages/@glimmer-workspace/integration-tests/lib/modes/rehydration/delegate.ts +++ b/packages/@glimmer-workspace/integration-tests/lib/modes/rehydration/delegate.ts @@ -5,6 +5,7 @@ import type { ElementNamespace, Environment, Helper, + ProgramContext, Nullable, RenderResult, SimpleDocument, @@ -26,7 +27,6 @@ import type { UserHelper } from '../../helpers'; import type { TestModifierConstructor } from '../../modifiers'; import type RenderDelegate from '../../render-delegate'; import type { RenderDelegateOptions } from '../../render-delegate'; -import type { JitTestDelegateContext } from '../jit/delegate'; import type { DebugRehydrationBuilder } from './builder'; import { BaseEnv } from '../../base-env'; @@ -53,8 +53,8 @@ export class RehydrationDelegate implements RenderDelegate { private plugins: ASTPluginBuilder[] = []; - public clientEnv: JitTestDelegateContext; - public serverEnv: JitTestDelegateContext; + public clientContext: ProgramContext; + public serverContext: ProgramContext; private clientResolver: TestJitRuntimeResolver; private serverResolver: TestJitRuntimeResolver; @@ -75,12 +75,12 @@ export class RehydrationDelegate implements RenderDelegate { this.clientDoc = castToSimple(document); this.clientRegistry = new TestJitRegistry(); this.clientResolver = new TestJitRuntimeResolver(this.clientRegistry); - this.clientEnv = JitDelegateContext(this.clientDoc, this.clientResolver, delegate); + this.clientContext = JitDelegateContext(this.clientDoc, this.clientResolver, delegate); this.serverDoc = createHTMLDocument(); this.serverRegistry = new TestJitRegistry(); this.serverResolver = new TestJitRuntimeResolver(this.serverRegistry); - this.serverEnv = JitDelegateContext(this.serverDoc, this.serverResolver, delegate); + this.serverContext = JitDelegateContext(this.serverDoc, this.serverResolver, delegate); } getInitialElement(): SimpleElement { @@ -119,12 +119,12 @@ export class RehydrationDelegate implements RenderDelegate { ): string { element = element || this.serverDoc.createElement('div'); let cursor = { element, nextSibling: null }; - let { env } = this.serverEnv.runtime; + let { env } = this.serverContext; // Emulate server-side render renderTemplate( template, - this.serverEnv, + this.serverContext, this.getSelf(env, context), this.getElementBuilder(env, cursor), this.precompileOptions @@ -147,7 +147,7 @@ export class RehydrationDelegate implements RenderDelegate { } renderClientSide(template: string, context: Dict, element: SimpleElement): RenderResult { - let env = this.clientEnv.runtime.env; + let env = this.clientContext.env; this.self = null; // Client-side rehydration @@ -155,7 +155,7 @@ export class RehydrationDelegate implements RenderDelegate { let builder = this.getElementBuilder(env, cursor) as DebugRehydrationBuilder; let result = renderTemplate( template, - this.clientEnv, + this.clientContext, this.getSelf(env, context), builder, this.precompileOptions diff --git a/packages/@glimmer-workspace/integration-tests/lib/modes/rehydration/partial-rehydration-delegate.ts b/packages/@glimmer-workspace/integration-tests/lib/modes/rehydration/partial-rehydration-delegate.ts index ca3e2ab48..a210c646c 100644 --- a/packages/@glimmer-workspace/integration-tests/lib/modes/rehydration/partial-rehydration-delegate.ts +++ b/packages/@glimmer-workspace/integration-tests/lib/modes/rehydration/partial-rehydration-delegate.ts @@ -16,16 +16,16 @@ export class PartialRehydrationDelegate extends RehydrationDelegate { element: SimpleElement ): RenderResult { let cursor = { element, nextSibling: null }; - let { program, runtime } = this.clientEnv; - let builder = this.getElementBuilder(runtime.env, cursor) as DebugRehydrationBuilder; + let context = this.clientContext; + let tree = this.getElementBuilder(context.env, cursor) as DebugRehydrationBuilder; let component = this.clientRegistry.lookupComponent(name)!; - let iterator = renderComponent(runtime, builder, program, {}, component.state, args); + let iterator = renderComponent(context, tree, {}, component.state, args); - const result = renderSync(runtime.env, iterator); + const result = renderSync(context.env, iterator); this.rehydrationStats = { - clearedNodes: builder.clearedNodes, + clearedNodes: tree.clearedNodes, }; return result; @@ -34,14 +34,14 @@ export class PartialRehydrationDelegate extends RehydrationDelegate { renderComponentServerSide(name: string, args: Dict): string { const element = this.serverDoc.createElement('div'); let cursor = { element, nextSibling: null }; - let { program, runtime } = this.serverEnv; - let builder = this.getElementBuilder(runtime.env, cursor); + let context = this.serverContext; + let builder = this.getElementBuilder(context.env, cursor); let component = this.serverRegistry.lookupComponent(name)!; - let iterator = renderComponent(runtime, builder, program, {}, component.state, args); + let iterator = renderComponent(context, builder, {}, component.state, args); - renderSync(runtime.env, iterator); + renderSync(context.env, iterator); return this.serialize(element); } diff --git a/packages/@glimmer-workspace/integration-tests/test/debug-render-tree-test.ts b/packages/@glimmer-workspace/integration-tests/test/debug-render-tree-test.ts index 3ede754dd..90381e73a 100644 --- a/packages/@glimmer-workspace/integration-tests/test/debug-render-tree-test.ts +++ b/packages/@glimmer-workspace/integration-tests/test/debug-render-tree-test.ts @@ -254,12 +254,8 @@ class DebugRenderTreeTest extends RenderTest { args: (actual) => { const args = { positional: [], named: { arg: 'first', arg2: { error } } }; this.assert.deepEqual(actual, args); - this.assert.ok( - !this.delegate.context.runtime.env.isArgumentCaptureError!(actual.named['arg']) - ); - this.assert.ok( - this.delegate.context.runtime.env.isArgumentCaptureError!(actual.named['arg2']) - ); + this.assert.ok(!this.delegate.context.env.isArgumentCaptureError!(actual.named['arg'])); + this.assert.ok(this.delegate.context.env.isArgumentCaptureError!(actual.named['arg2'])); return true; }, instance: (instance: EmberishCurlyComponent) => (instance as any).arg === 'first', diff --git a/packages/@glimmer/debug-util/lib/platform-utils.ts b/packages/@glimmer/debug-util/lib/platform-utils.ts index 791a73189..72829a36a 100644 --- a/packages/@glimmer/debug-util/lib/platform-utils.ts +++ b/packages/@glimmer/debug-util/lib/platform-utils.ts @@ -17,7 +17,7 @@ export const expect = ( return val as Present; } : (value: T, _message: string) => value -) as (value: T, message: string) => NonNullable; +) as (value: T, message: string) => Present; export const unreachable = ( LOCAL_DEBUG diff --git a/packages/@glimmer/debug/lib/debug.ts b/packages/@glimmer/debug/lib/debug.ts index 5a3a64dd5..c6b976912 100644 --- a/packages/@glimmer/debug/lib/debug.ts +++ b/packages/@glimmer/debug/lib/debug.ts @@ -1,11 +1,11 @@ import type { BlockMetadata, + CompilationContext, Dict, - JitConstants, Nullable, - RuntimeHeap, + ProgramConstants, + ProgramHeap, RuntimeOp, - CompilationContext, } from '@glimmer/interfaces'; import { CURRIED_COMPONENT, @@ -33,15 +33,15 @@ export function logOpcodeSlice(context: CompilationContext, start: number, end: const logger = new DebugLogger(LOCAL_LOGGER, { showSubtle: !!LOCAL_SUBTLE_LOGGING }); LOCAL_LOGGER.group(`%c${start}:${end}`, 'color: #999'); - const constants = context.program.constants; + const constants = context.program.program.constants; - let heap = context.program.heap; + let heap = context.program.program.heap; let opcode = context.program.createOp(heap); let _size = 0; for (let i = start; i <= end; i = i + _size) { opcode.offset = i; - const op = describeOp(opcode, constants, context.program.heap, context.meta); + const op = describeOp(opcode, constants, heap, context.meta); logger.log(frag`${i}. ${op}`); @@ -316,16 +316,16 @@ class DebugOperandInfo { readonly #offset: number; readonly #operand: NormalizedOperand; readonly #value: number; - readonly #constants: JitConstants; - readonly #heap: RuntimeHeap; + readonly #constants: ProgramConstants; + readonly #heap: ProgramHeap; readonly #metadata: BlockMetadata | null; constructor( offset: number, operand: NormalizedOperand, value: number, - constants: JitConstants, - heap: RuntimeHeap, + constants: ProgramConstants, + heap: ProgramHeap, metadata: BlockMetadata | null ) { this.#offset = offset; @@ -354,8 +354,8 @@ class DebugOperandInfo { } export function debugOp( - heap: RuntimeHeap, - constants: JitConstants, + heap: ProgramHeap, + constants: ProgramConstants, op: OpSnapshot, meta: BlockMetadata | null ): DebugOp { @@ -449,7 +449,7 @@ export function decodeRegister(register: number): RegisterName { } } -export function decodePrimitive(primitive: number, constants: JitConstants): Primitive { +export function decodePrimitive(primitive: number, constants: ProgramConstants): Primitive { if (primitive >= 0) { return constants.getValue(decodeHandle(primitive)); } diff --git a/packages/@glimmer/debug/lib/dism/opcode.ts b/packages/@glimmer/debug/lib/dism/opcode.ts index 2d30ed9f6..3051976f8 100644 --- a/packages/@glimmer/debug/lib/dism/opcode.ts +++ b/packages/@glimmer/debug/lib/dism/opcode.ts @@ -1,8 +1,8 @@ import type { BlockMetadata, CompilableTemplate, - CompileTimeHeap, - JitConstants, + ProgramHeap, + ProgramConstants, Reference, RuntimeOp, } from '@glimmer/interfaces'; @@ -22,8 +22,8 @@ import { describeRef } from '../render/ref'; export function describeOp( op: RuntimeOp, - constants: JitConstants, - heap: CompileTimeHeap, + constants: ProgramConstants, + heap: ProgramHeap, meta: BlockMetadata ): Fragment { const { name, params } = debugOp(heap, constants, op, meta)!; diff --git a/packages/@glimmer/debug/lib/dism/operands.ts b/packages/@glimmer/debug/lib/dism/operands.ts index fe0c618cc..89a21c19e 100644 --- a/packages/@glimmer/debug/lib/dism/operands.ts +++ b/packages/@glimmer/debug/lib/dism/operands.ts @@ -1,23 +1,23 @@ -import type { BlockMetadata, JitConstants, RuntimeHeap } from '@glimmer/interfaces'; +import type { BlockMetadata, ProgramConstants, ProgramHeap } from '@glimmer/interfaces'; import { decodeHandle } from '@glimmer/constants'; import type { RawDisassembledOperand } from '../debug'; import type { NonNullableOperandType, - NullableOperandType, NormalizedOperand, + NullableOperandType, OperandType, } from './operand-types'; import { decodeCurry, decodePrimitive, decodeRegister } from '../debug'; interface DisassemblyState { - offset: number; - label: NormalizedOperand; - value: number; - constants: JitConstants; - heap: RuntimeHeap; - meta: BlockMetadata | null; + readonly offset: number; + readonly label: NormalizedOperand; + readonly value: number; + readonly constants: ProgramConstants; + readonly heap: ProgramHeap; + readonly meta: BlockMetadata | null; } export type OperandDisassembler = (options: DisassemblyState) => RawDisassembledOperand; diff --git a/packages/@glimmer/interfaces/lib/managers/internal/component.d.ts b/packages/@glimmer/interfaces/lib/managers/internal/component.d.ts index 3ac36eb4b..81aaef28b 100644 --- a/packages/@glimmer/interfaces/lib/managers/internal/component.d.ts +++ b/packages/@glimmer/interfaces/lib/managers/internal/component.d.ts @@ -9,7 +9,7 @@ import type { RenderNode } from '../../runtime/debug-render-tree.js'; import type { ElementOperations } from '../../runtime/element.js'; import type { Environment } from '../../runtime/environment.js'; import type { DynamicScope } from '../../runtime/scope.js'; -import type { RuntimeResolver } from '../../serialize.js'; +import type { ClassicResolver } from '../../serialize.js'; import type { CompilableProgram } from '../../template.js'; import type { ProgramSymbolTable } from '../../tier1/symbol-table.js'; @@ -237,7 +237,7 @@ export interface WithUpdateHook export interface WithDynamicLayout< I = ComponentInstanceState, - R extends RuntimeResolver = RuntimeResolver, + R extends ClassicResolver | null = ClassicResolver | null, > extends InternalComponentManager { // Return the compiled layout to use for this component. This is called // *after* the component instance has been created, because you might diff --git a/packages/@glimmer/interfaces/lib/program.d.ts b/packages/@glimmer/interfaces/lib/program.d.ts index 9743e0699..df49c1976 100644 --- a/packages/@glimmer/interfaces/lib/program.d.ts +++ b/packages/@glimmer/interfaces/lib/program.d.ts @@ -1,12 +1,12 @@ import type { Encoder } from './compile/index.js'; import type { ComponentDefinition, ComponentDefinitionState } from './components.js'; -import type { HelperDefinitionState } from './runtime.js'; +import type { Environment, HelperDefinitionState, Program } from './runtime.js'; import type { ModifierDefinitionState } from './runtime/modifier.js'; -import type { CompileTimeResolver, ResolvedComponentDefinition } from './serialize.js'; +import type { ClassicResolver, ResolvedComponentDefinition } from './serialize.js'; import type { BlockMetadata, STDLib, Template } from './template.js'; import type { SomeVmOp, VmMachineOp, VmOp } from './vm-opcodes.js'; -export type CreateRuntimeOp = (heap: CompileTimeHeap) => RuntimeOp; +export type CreateRuntimeOp = (heap: ProgramHeap) => RuntimeOp; export interface RuntimeOp { offset: number; @@ -24,18 +24,7 @@ export interface SerializedHeap { handle: number; } -export interface OpcodeHeap { - getbyaddr(address: number): number; - /** - * Return the number of entries in the table. A handle is legal if - * it is less than this number. - * - * @debugging - */ - entries(): number; -} - -export interface CompileTimeHeap extends OpcodeHeap { +export interface ProgramHeap { pushRaw(value: number): void; pushOp(name: VmOp, op1?: number, op2?: number, op3?: number): void; pushMachine(name: VmMachineOp, op1?: number, op2?: number, op3?: number): void; @@ -49,25 +38,47 @@ export interface CompileTimeHeap extends OpcodeHeap { sizeof(handle: number): number; getbyaddr(address: number): number; setbyaddr(address: number, value: number): void; -} -export interface RuntimeHeap extends OpcodeHeap { - getaddr(handle: number): number; - sizeof(handle: number): number; + /** + * Return the number of entries in the table. A handle is legal if + * it is less than this number. + * + * @debugging + */ + entries(): number; } +/** + * The `ProgramContext` is the context that remains the same across all of the templates and + * evaluations in a single program. + * + * Note that multiple programs can co-exist on the same page, sharing tracking logic (and the + * global tracking context) but having different *program* contexts. + */ export interface ProgramContext { - // The offsets to stdlib functions - readonly stdlib: STDLib; + /** + * The program's environment, which contains customized framework behavior. + */ + readonly env: Environment; - // Interned constants - readonly constants: JitConstants; + /** + * The compiled program itself: the constants and heap + */ + readonly program: Program; - // The mechanism of resolving names to values at compile-time - readonly resolver: CompileTimeResolver; + /** + * The offsets to stdlib functions + */ + readonly stdlib: STDLib; - // The heap that the program is serializing into - readonly heap: CompileTimeHeap; + /** + * A framework-specified resolver for resolving free variables in classic templates. + * + * A strict component can invoke a classic component and vice versa, but only classic components + * will use the resolver. If no resolver is available in the `ProgramContext`, only strict components + * will compile and run. + */ + readonly resolver: ClassicResolver | null; // Create a runtime op from the heap readonly createOp: CreateRuntimeOp; @@ -148,9 +159,9 @@ export interface RuntimeConstants { getArray(handle: number): T[]; } -export type JitConstants = CompileTimeConstants & ResolutionTimeConstants & RuntimeConstants; +export type ProgramConstants = CompileTimeConstants & ResolutionTimeConstants & RuntimeConstants; export interface CompileTimeArtifacts { - heap: CompileTimeHeap; - constants: JitConstants; + heap: ProgramHeap; + constants: ProgramConstants; } diff --git a/packages/@glimmer/interfaces/lib/runtime.d.ts b/packages/@glimmer/interfaces/lib/runtime.d.ts index c4da7d76a..eeb3cb769 100644 --- a/packages/@glimmer/interfaces/lib/runtime.d.ts +++ b/packages/@glimmer/interfaces/lib/runtime.d.ts @@ -3,7 +3,6 @@ export * from './runtime/debug-render-tree.js'; export * from './runtime/element.js'; export * from './runtime/environment.js'; export * from './runtime/helper.js'; -export * from './runtime/jit.js'; export * from './runtime/local-debug.js'; export * from './runtime/modifier.js'; export * from './runtime/owner.js'; diff --git a/packages/@glimmer/interfaces/lib/runtime/environment.d.ts b/packages/@glimmer/interfaces/lib/runtime/environment.d.ts index 25750fb5f..8d7d0c997 100644 --- a/packages/@glimmer/interfaces/lib/runtime/environment.d.ts +++ b/packages/@glimmer/interfaces/lib/runtime/environment.d.ts @@ -8,8 +8,10 @@ import type { import type { Nullable } from '../core.js'; import type { GlimmerTreeChanges, GlimmerTreeConstruction } from '../dom/changes.js'; import type { WithCreateInstance } from '../managers.js'; +import type { ClassicResolver } from '../serialize.js'; import type { DebugRenderTree } from './debug-render-tree.js'; import type { ModifierInstance } from './modifier.js'; +import type { Program } from './runtime.js'; export interface EnvironmentOptions { document?: SimpleDocument; @@ -48,3 +50,8 @@ export interface Environment { // eslint-disable-next-line @typescript-eslint/no-explicit-any isArgumentCaptureError?: ((error: any) => boolean) | undefined; } +export interface RuntimeOptions { + readonly env: Environment; + readonly program: Program; + readonly resolver: ClassicResolver | null; +} diff --git a/packages/@glimmer/interfaces/lib/runtime/jit.d.ts b/packages/@glimmer/interfaces/lib/runtime/jit.d.ts deleted file mode 100644 index 406f624e3..000000000 --- a/packages/@glimmer/interfaces/lib/runtime/jit.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { ProgramContext } from '../program.js'; -import type { RuntimeContext } from './runtime.js'; - -export interface JitContext { - runtime: RuntimeContext; - program: ProgramContext; -} diff --git a/packages/@glimmer/interfaces/lib/runtime/local-debug.d.ts b/packages/@glimmer/interfaces/lib/runtime/local-debug.d.ts index 432e2d57e..019e9a590 100644 --- a/packages/@glimmer/interfaces/lib/runtime/local-debug.d.ts +++ b/packages/@glimmer/interfaces/lib/runtime/local-debug.d.ts @@ -1,4 +1,4 @@ -import type { JitConstants, RuntimeHeap } from '../program.js'; +import type { ProgramConstants, ProgramHeap } from '../program.js'; import type { Stack } from '../stack.js'; import type { BlockMetadata } from '../template.js'; import type { DynamicScope, Scope } from './scope.js'; @@ -24,7 +24,7 @@ export interface DebugRegisters extends Array { export interface DebugVmState { readonly stacks: DebugStacks; readonly destroyableStack: object[]; - readonly constants: JitConstants; + readonly constants: ProgramConstants; /** * These values can change for each opcode @@ -38,7 +38,7 @@ export interface DebugVmState { * These values are the same for the entire program */ readonly program: { - readonly heap: RuntimeHeap; + readonly heap: ProgramHeap; }; /** diff --git a/packages/@glimmer/interfaces/lib/runtime/runtime.d.ts b/packages/@glimmer/interfaces/lib/runtime/runtime.d.ts index e1adcbb98..949a958e9 100644 --- a/packages/@glimmer/interfaces/lib/runtime/runtime.d.ts +++ b/packages/@glimmer/interfaces/lib/runtime/runtime.d.ts @@ -1,28 +1,13 @@ -import type { JitConstants, RuntimeHeap, RuntimeOp } from '../program.js'; -import type { RuntimeResolver } from '../serialize.js'; -import type { Environment } from './environment.js'; +import type { ProgramConstants, ProgramHeap, RuntimeOp } from '../program.js'; -/** - The Runtime is the set of static structures that contain the compiled - code and any host configuration. - - The contents of the Runtime do not change as the VM executes, unlike - the VM state. - */ -export interface RuntimeContext { - env: Environment; - program: RuntimeProgram; - resolver: RuntimeResolver; -} - -export interface RuntimeProgram { - readonly constants: JitConstants; - readonly heap: RuntimeHeap; +export interface Program { + readonly constants: ProgramConstants; + readonly heap: ProgramHeap; opcode(offset: number): RuntimeOp; } export interface RuntimeArtifacts { - readonly constants: JitConstants; - readonly heap: RuntimeHeap; + readonly constants: ProgramConstants; + readonly heap: ProgramHeap; } diff --git a/packages/@glimmer/interfaces/lib/serialize.d.ts b/packages/@glimmer/interfaces/lib/serialize.d.ts index ee6a89dd8..fb247115a 100644 --- a/packages/@glimmer/interfaces/lib/serialize.d.ts +++ b/packages/@glimmer/interfaces/lib/serialize.d.ts @@ -75,17 +75,14 @@ export interface ResolvedComponentDefinition< template: Template | null; } -export interface CompileTimeResolver { - lookupHelper(name: string, owner: O): Nullable; - lookupModifier(name: string, owner: O): Nullable; - lookupComponent(name: string, owner: O): Nullable; +export interface ClassicResolver { + lookupHelper?(name: string, owner: O): Nullable; + lookupModifier?(name: string, owner: O): Nullable; + lookupComponent?(name: string, owner: O): Nullable; // TODO: These are used to lookup keywords that are implemented as helpers/modifiers. // We should try to figure out a cleaner way to do this. - lookupBuiltInHelper(name: string): Nullable; - lookupBuiltInModifier(name: string): Nullable; -} - -export interface RuntimeResolver { - lookupComponent(name: string, owner: O): Nullable; + lookupBuiltInHelper?(name: string): Nullable; + lookupBuiltInModifier?(name: string): Nullable; + lookupComponent?(name: string, owner: O): Nullable; } diff --git a/packages/@glimmer/opcode-compiler/lib/compilable-template.ts b/packages/@glimmer/opcode-compiler/lib/compilable-template.ts index 17e4482a2..46fe663b1 100644 --- a/packages/@glimmer/opcode-compiler/lib/compilable-template.ts +++ b/packages/@glimmer/opcode-compiler/lib/compilable-template.ts @@ -5,11 +5,11 @@ import type { CompilableBlock, CompilableProgram, CompilableTemplate, - ProgramContext, HandleResult, HighLevelOp, LayoutWithContext, Nullable, + ProgramContext, SerializedBlock, SerializedInlineBlock, Statement, @@ -91,13 +91,10 @@ export function compileStatements( let sCompiler = STATEMENTS; let context = templateCompilationContext(syntaxContext, meta); - let { - encoder, - program: { constants, resolver }, - } = context; + let { encoder, program } = context; function pushOp(...op: BuilderOp | HighLevelOp | HighLevelStatementOp) { - encodeOp(encoder, constants, resolver, meta, op as BuilderOp | HighLevelOp); + encodeOp(encoder, program, meta, op as BuilderOp | HighLevelOp); } for (const statement of statements) { diff --git a/packages/@glimmer/opcode-compiler/lib/compiler.ts b/packages/@glimmer/opcode-compiler/lib/compiler.ts index 1c81dc317..2c085d926 100644 --- a/packages/@glimmer/opcode-compiler/lib/compiler.ts +++ b/packages/@glimmer/opcode-compiler/lib/compiler.ts @@ -1,4 +1,4 @@ -import type { HandleResult, CompilationContext } from '@glimmer/interfaces'; +import type { CompilationContext, HandleResult } from '@glimmer/interfaces'; import { logOpcodeSlice } from '@glimmer/debug'; import { extractHandle } from '@glimmer/debug-util'; import { LOCAL_TRACE_LOGGING } from '@glimmer/local-debug-flags'; @@ -8,7 +8,7 @@ export let debugCompiler: (context: CompilationContext, handle: HandleResult) => if (LOCAL_TRACE_LOGGING) { debugCompiler = (context: CompilationContext, result: HandleResult) => { let handle = extractHandle(result); - let { heap } = context.program; + let { heap } = context.program.program; let start = heap.getaddr(handle); let end = start + heap.sizeof(handle); diff --git a/packages/@glimmer/opcode-compiler/lib/opcode-builder/context.ts b/packages/@glimmer/opcode-compiler/lib/opcode-builder/context.ts index 811c5d746..f6548aab6 100644 --- a/packages/@glimmer/opcode-compiler/lib/opcode-builder/context.ts +++ b/packages/@glimmer/opcode-compiler/lib/opcode-builder/context.ts @@ -1,28 +1,12 @@ -import type { - BlockMetadata, - ProgramContext, - CompileTimeArtifacts, - CompileTimeResolver, - CreateRuntimeOp, - CompilationContext, -} from '@glimmer/interfaces'; +import type { BlockMetadata, CompilationContext, ProgramContext } from '@glimmer/interfaces'; -import { CompilationContextImpl } from '../program-context'; import { EncoderImpl } from './encoder'; -export function programCompilationContext( - artifacts: CompileTimeArtifacts, - resolver: CompileTimeResolver, - createOp: CreateRuntimeOp -): ProgramContext { - return new CompilationContextImpl(artifacts, resolver, createOp); -} - export function templateCompilationContext( program: ProgramContext, meta: BlockMetadata ): CompilationContext { - let encoder = new EncoderImpl(program.heap, meta, program.stdlib); + let encoder = new EncoderImpl(program.program.heap, meta, program.stdlib); return { program, diff --git a/packages/@glimmer/opcode-compiler/lib/opcode-builder/encoder.ts b/packages/@glimmer/opcode-compiler/lib/opcode-builder/encoder.ts index 692b0bc78..caf7f6f28 100644 --- a/packages/@glimmer/opcode-compiler/lib/opcode-builder/encoder.ts +++ b/packages/@glimmer/opcode-compiler/lib/opcode-builder/encoder.ts @@ -1,10 +1,8 @@ import type { + BlockMetadata, BuilderOp, BuilderOpcode, CompileTimeConstants, - CompileTimeHeap, - CompileTimeResolver, - BlockMetadata, Dict, Encoder, EncoderError, @@ -12,7 +10,8 @@ import type { HighLevelOp, InstructionEncoder, Operand, - ResolutionTimeConstants, + ProgramContext, + ProgramHeap, SingleBuilderOperand, STDLib, } from '@glimmer/interfaces'; @@ -45,7 +44,7 @@ export class Labels { this.targets.push({ at, target }); } - patch(heap: CompileTimeHeap): void { + patch(heap: ProgramHeap): void { let { targets, labels } = this; for (const { at, target } of targets) { @@ -60,11 +59,15 @@ export class Labels { export function encodeOp( encoder: Encoder, - constants: CompileTimeConstants & ResolutionTimeConstants, - resolver: CompileTimeResolver, + context: ProgramContext, meta: BlockMetadata, op: BuilderOp | HighLevelOp ): void { + let { + program: { constants }, + resolver, + } = context; + if (isBuilderOpcode(op[0])) { let [type, ...operands] = op; encoder.push(constants, type, ...(operands as SingleBuilderOperand[])); @@ -124,7 +127,7 @@ export class EncoderImpl implements Encoder { private handle: number; constructor( - private heap: CompileTimeHeap, + private heap: ProgramHeap, private meta: BlockMetadata, private stdlib?: STDLib ) { diff --git a/packages/@glimmer/opcode-compiler/lib/opcode-builder/helpers/resolution.ts b/packages/@glimmer/opcode-compiler/lib/opcode-builder/helpers/resolution.ts index c1c4a1f9a..e9f951a52 100644 --- a/packages/@glimmer/opcode-compiler/lib/opcode-builder/helpers/resolution.ts +++ b/packages/@glimmer/opcode-compiler/lib/opcode-builder/helpers/resolution.ts @@ -1,8 +1,8 @@ import type { - CompileTimeConstants, - CompileTimeResolver, BlockMetadata, + CompileTimeConstants, Expressions, + ClassicResolver, Owner, ResolutionTimeConstants, ResolveComponentOp, @@ -74,7 +74,7 @@ function assertResolverInvariants(meta: BlockMetadata): ResolvedContainingMetada * */ export function resolveComponent( - resolver: CompileTimeResolver, + resolver: ClassicResolver | null, constants: CompileTimeConstants & ResolutionTimeConstants, meta: BlockMetadata, [, expr, then]: ResolveComponentOp @@ -111,7 +111,7 @@ export function resolveComponent( let { upvars, owner } = assertResolverInvariants(meta); let name = unwrap(upvars[expr[1]]); - let definition = resolver.lookupComponent(name, owner)!; + let definition = resolver?.lookupComponent?.(name, owner) ?? null; if (import.meta.env.DEV && (typeof definition !== 'object' || definition === null)) { assert(!meta.isStrictMode, 'Strict mode errors should already be handled at compile time'); @@ -121,7 +121,7 @@ export function resolveComponent( ); } - then(constants.resolvedComponent(definition, name)); + then(constants.resolvedComponent(definition!, name)); } } @@ -130,7 +130,7 @@ export function resolveComponent( * (helper arg) */ export function resolveHelper( - resolver: CompileTimeResolver, + resolver: ClassicResolver | null, constants: CompileTimeConstants & ResolutionTimeConstants, meta: BlockMetadata, [, expr, then]: ResolveHelperOp @@ -154,7 +154,7 @@ export function resolveHelper( let { upvars, owner } = assertResolverInvariants(meta); let name = unwrap(upvars[expr[1]]); - let helper = resolver.lookupHelper(name, owner)!; + let helper = resolver?.lookupHelper?.(name, owner) ?? null; if (import.meta.env.DEV && helper === null) { assert(!meta.isStrictMode, 'Strict mode errors should already be handled at compile time'); @@ -164,7 +164,7 @@ export function resolveHelper( ); } - then(constants.helper(helper, name)); + then(constants.helper(helper!, name)); } } @@ -174,7 +174,7 @@ export function resolveHelper( * */ export function resolveModifier( - resolver: CompileTimeResolver, + resolver: ClassicResolver | null, constants: CompileTimeConstants & ResolutionTimeConstants, meta: BlockMetadata, [, expr, then]: ResolveModifierOp @@ -193,7 +193,7 @@ export function resolveModifier( } else if (type === SexpOpcodes.GetStrictKeyword) { let { upvars } = assertResolverInvariants(meta); let name = unwrap(upvars[expr[1]]); - let modifier = resolver.lookupBuiltInModifier(name); + let modifier = resolver?.lookupBuiltInModifier?.(name) ?? null; if (import.meta.env.DEV && modifier === null) { assert(!meta.isStrictMode, 'Strict mode errors should already be handled at compile time'); @@ -207,7 +207,7 @@ export function resolveModifier( } else { let { upvars, owner } = assertResolverInvariants(meta); let name = unwrap(upvars[expr[1]]); - let modifier = resolver.lookupModifier(name, owner)!; + let modifier = resolver?.lookupModifier?.(name, owner) ?? null; if (import.meta.env.DEV && modifier === null) { assert(!meta.isStrictMode, 'Strict mode errors should already be handled at compile time'); @@ -217,7 +217,7 @@ export function resolveModifier( ); } - then(constants.modifier(modifier)); + then(constants.modifier(modifier!)); } } @@ -225,7 +225,7 @@ export function resolveModifier( * {{component-or-helper arg}} */ export function resolveComponentOrHelper( - resolver: CompileTimeResolver, + resolver: ClassicResolver | null, constants: CompileTimeConstants & ResolutionTimeConstants, meta: BlockMetadata, [, expr, { ifComponent, ifHelper }]: ResolveComponentOrHelperOp @@ -282,12 +282,12 @@ export function resolveComponentOrHelper( let { upvars, owner } = assertResolverInvariants(meta); let name = unwrap(upvars[expr[1]]); - let definition = resolver.lookupComponent(name, owner); + let definition = resolver?.lookupComponent?.(name, owner) ?? null; if (definition !== null) { ifComponent(constants.resolvedComponent(definition, name)); } else { - let helper = resolver.lookupHelper(name, owner); + let helper = resolver?.lookupHelper?.(name, owner) ?? null; if (import.meta.env.DEV && helper === null) { assert(!meta.isStrictMode, 'Strict mode errors should already be handled at compile time'); @@ -306,7 +306,7 @@ export function resolveComponentOrHelper( * {{maybeHelperOrComponent}} */ export function resolveOptionalComponentOrHelper( - resolver: CompileTimeResolver, + resolver: ClassicResolver | null, constants: CompileTimeConstants & ResolutionTimeConstants, meta: BlockMetadata, [, expr, { ifComponent, ifHelper, ifValue }]: ResolveOptionalComponentOrHelperOp @@ -361,14 +361,14 @@ export function resolveOptionalComponentOrHelper( let { upvars, owner } = assertResolverInvariants(meta); let name = unwrap(upvars[expr[1]]); - let definition = resolver.lookupComponent(name, owner); + let definition = resolver?.lookupComponent?.(name, owner) ?? null; if (definition !== null) { ifComponent(constants.resolvedComponent(definition, name)); return; } - let helper = resolver.lookupHelper(name, owner); + let helper = resolver?.lookupHelper?.(name, owner) ?? null; if (helper !== null) { ifHelper(constants.helper(helper, name)); @@ -378,7 +378,7 @@ export function resolveOptionalComponentOrHelper( function lookupBuiltInHelper( expr: Expressions.GetStrictFree, - resolver: CompileTimeResolver, + resolver: ClassicResolver | null, meta: BlockMetadata, constants: ResolutionTimeConstants, type: string @@ -386,7 +386,7 @@ function lookupBuiltInHelper( let { upvars } = assertResolverInvariants(meta); let name = unwrap(upvars[expr[1]]); - let helper = resolver.lookupBuiltInHelper(name); + let helper = resolver?.lookupBuiltInHelper?.(name); if (import.meta.env.DEV && helper === null) { assert(!meta.isStrictMode, 'Strict mode errors should already be handled at compile time'); diff --git a/packages/@glimmer/opcode-compiler/lib/opcode-builder/helpers/stdlib.ts b/packages/@glimmer/opcode-compiler/lib/opcode-builder/helpers/stdlib.ts index e6c3445cd..91f16d088 100644 --- a/packages/@glimmer/opcode-compiler/lib/opcode-builder/helpers/stdlib.ts +++ b/packages/@glimmer/opcode-compiler/lib/opcode-builder/helpers/stdlib.ts @@ -1,9 +1,4 @@ -import type { - BlockMetadata, - BuilderOp, - ProgramContext, - HighLevelOp, -} from '@glimmer/interfaces'; +import type { BlockMetadata, BuilderOp, HighLevelOp, ProgramContext } from '@glimmer/interfaces'; import { VM_APPEND_DOCUMENT_FRAGMENT_OP, VM_APPEND_HTML_OP, @@ -134,11 +129,10 @@ export const STDLIB_META: BlockMetadata = { }; function build(program: ProgramContext, builder: (op: PushStatementOp) => void): number { - let { constants, heap, resolver } = program; - let encoder = new EncoderImpl(heap, STDLIB_META); + let encoder = new EncoderImpl(program.program.heap, STDLIB_META); function pushOp(...op: BuilderOp | HighLevelOp | HighLevelStatementOp) { - encodeOp(encoder, constants, resolver, STDLIB_META, op as BuilderOp | HighLevelOp); + encodeOp(encoder, program, STDLIB_META, op as BuilderOp | HighLevelOp); } builder(pushOp); diff --git a/packages/@glimmer/opcode-compiler/lib/program-context.ts b/packages/@glimmer/opcode-compiler/lib/program-context.ts index fce21ec87..78f6352e4 100644 --- a/packages/@glimmer/opcode-compiler/lib/program-context.ts +++ b/packages/@glimmer/opcode-compiler/lib/program-context.ts @@ -1,31 +1,40 @@ import type { - ProgramContext, + ClassicResolver, CompileTimeArtifacts, - CompileTimeHeap, - CompileTimeResolver, CreateRuntimeOp, - JitConstants, + Environment, + Program, + ProgramConstants, + ProgramContext, + ProgramHeap, + RuntimeOptions, STDLib, } from '@glimmer/interfaces'; import { compileStd } from './opcode-builder/helpers/stdlib'; -export class CompilationContextImpl implements ProgramContext { - readonly constants: JitConstants; - readonly heap: CompileTimeHeap; - readonly resolver: CompileTimeResolver; +export class ProgramContextImpl implements ProgramContext { + readonly constants: ProgramConstants; + readonly heap: ProgramHeap; + readonly resolver: ClassicResolver | null; readonly stdlib: STDLib; readonly createOp: CreateRuntimeOp; + readonly env: Environment; + readonly program: Program; constructor( { constants, heap }: CompileTimeArtifacts, - resolver: CompileTimeResolver, - createOp: CreateRuntimeOp + resolver: ClassicResolver | null, + createOp: CreateRuntimeOp, + runtime: RuntimeOptions ) { this.constants = constants; this.heap = heap; this.resolver = resolver; this.createOp = createOp; + this.env = runtime.env; + this.program = runtime.program; + this.stdlib = compileStd(this); } } diff --git a/packages/@glimmer/opcode-compiler/lib/wrapped-component.ts b/packages/@glimmer/opcode-compiler/lib/wrapped-component.ts index a51f92e7a..7c3530e7c 100644 --- a/packages/@glimmer/opcode-compiler/lib/wrapped-component.ts +++ b/packages/@glimmer/opcode-compiler/lib/wrapped-component.ts @@ -56,13 +56,10 @@ export class WrappedBuilder implements CompilableProgram { let m = meta(this.layout); let context = templateCompilationContext(syntax, m); - let { - encoder, - program: { constants, resolver }, - } = context; + let { encoder, program } = context; function pushOp(...op: BuilderOp | HighLevelOp | HighLevelStatementOp) { - encodeOp(encoder, constants, resolver, m, op as BuilderOp | HighLevelOp); + encodeOp(encoder, program, m, op as BuilderOp | HighLevelOp); } WrappedComponent(pushOp, this.layout, this.attrsBlockNumber); diff --git a/packages/@glimmer/program/lib/opcode.ts b/packages/@glimmer/program/lib/opcode.ts index 4e983728c..c7c9a4736 100644 --- a/packages/@glimmer/program/lib/opcode.ts +++ b/packages/@glimmer/program/lib/opcode.ts @@ -1,9 +1,9 @@ -import type { OpcodeHeap, RuntimeOp, SomeVmOp } from '@glimmer/interfaces'; +import type { ProgramHeap, RuntimeOp, SomeVmOp } from '@glimmer/interfaces'; import { ARG_SHIFT, MACHINE_MASK, OPERAND_LEN_MASK, TYPE_MASK } from '@glimmer/vm'; export class RuntimeOpImpl implements RuntimeOp { public offset = 0; - constructor(readonly heap: OpcodeHeap) {} + constructor(readonly heap: ProgramHeap) {} get size() { let rawType = this.heap.getbyaddr(this.offset); diff --git a/packages/@glimmer/program/lib/program.ts b/packages/@glimmer/program/lib/program.ts index 81ee9c2dd..4426cba2c 100644 --- a/packages/@glimmer/program/lib/program.ts +++ b/packages/@glimmer/program/lib/program.ts @@ -1,12 +1,11 @@ import type { - CompileTimeHeap, - JitConstants, - RuntimeHeap, - RuntimeProgram, + Program, + ProgramConstants, + ProgramHeap, SerializedHeap, StdLibOperand, } from '@glimmer/interfaces'; -import { expect, unwrap } from '@glimmer/debug-util'; +import { unwrap } from '@glimmer/debug-util'; import { LOCAL_DEBUG } from '@glimmer/local-debug-flags'; import { MACHINE_MASK } from '@glimmer/vm'; @@ -24,42 +23,8 @@ export type StdlibPlaceholder = [number, StdLibOperand]; const PAGE_SIZE = 0x100000; -export class RuntimeHeapImpl implements RuntimeHeap { - private heap: Int32Array; - private table: number[]; - - constructor(serializedHeap: SerializedHeap) { - let { buffer, table } = serializedHeap; - this.heap = new Int32Array(buffer); - this.table = table; - } - - entries(): number { - return this.table.length; - } - - // It is illegal to close over this address, as compaction - // may move it. However, it is legal to use this address - // multiple times between compactions. - getaddr(handle: number): number { - return unwrap(this.table[handle]); - } - - getbyaddr(address: number): number { - return expect(this.heap[address], 'Access memory out of bounds of the heap'); - } - - sizeof(handle: number): number { - return sizeof(this.table, handle); - } -} - -export function hydrateHeap(serializedHeap: SerializedHeap): RuntimeHeap { - return new RuntimeHeapImpl(serializedHeap); -} - /** - * The Heap is responsible for dynamically allocating + * The Program Heap is responsible for dynamically allocating * memory in which we read/write the VM's instructions * from/to. When we malloc we pass out a VMHandle, which * is used as an indirect way of accessing the memory during @@ -78,7 +43,7 @@ export function hydrateHeap(serializedHeap: SerializedHeap): RuntimeHeap { * valid during the execution. This means you cannot close * over them as you will have a bad memory access exception. */ -export class HeapImpl implements CompileTimeHeap, RuntimeHeap { +export class HeapImpl implements ProgramHeap { offset = 0; private heap: Int32Array; @@ -210,14 +175,14 @@ export class HeapImpl implements CompileTimeHeap, RuntimeHeap { } } -export class RuntimeProgramImpl implements RuntimeProgram { +export class ProgramImpl implements Program { [key: number]: never; private _opcode: RuntimeOpImpl; constructor( - public constants: JitConstants, - public heap: RuntimeHeap + public constants: ProgramConstants, + public heap: ProgramHeap ) { this._opcode = new RuntimeOpImpl(this.heap); } diff --git a/packages/@glimmer/runtime/lib/compiled/opcodes/component.ts b/packages/@glimmer/runtime/lib/compiled/opcodes/component.ts index 390ecf521..aec5cb819 100644 --- a/packages/@glimmer/runtime/lib/compiled/opcodes/component.ts +++ b/packages/@glimmer/runtime/lib/compiled/opcodes/component.ts @@ -172,7 +172,7 @@ APPEND_OPCODES.add(VM_RESOLVE_DYNAMIC_COMPONENT_OP, (vm, { op1: _isStrict }) => ); } - let resolvedDefinition = resolveComponent(vm.runtime.resolver, constants, component, owner); + let resolvedDefinition = resolveComponent(vm.context.resolver, constants, component, owner); definition = expect(resolvedDefinition, `Could not find a component named "${component}"`); } else if (isCurriedValue(component)) { @@ -290,7 +290,7 @@ APPEND_OPCODES.add(VM_PREPARE_ARGS_OP, (vm, { op1: register }) => { if (resolved === true) { definition = resolvedDefinition as ComponentDefinition; } else if (typeof resolvedDefinition === 'string') { - let resolvedValue = vm.runtime.resolver.lookupComponent(resolvedDefinition, owner); + let resolvedValue = vm.context.resolver?.lookupComponent?.(resolvedDefinition, owner); definition = constants.resolvedComponent( expect(resolvedValue, 'BUG: expected resolved component'), @@ -674,7 +674,7 @@ APPEND_OPCODES.add(VM_GET_COMPONENT_SELF_OP, (vm, { op1: register, op2: _names } 'BUG: No template was found for this component, and the component did not have the dynamic layout capability' ); - compilable = manager.getDynamicLayout(state, vm.runtime.resolver); + compilable = manager.getDynamicLayout(state, vm.context.resolver); if (compilable !== null) { moduleName = compilable.moduleName; @@ -760,7 +760,7 @@ APPEND_OPCODES.add(VM_GET_COMPONENT_LAYOUT_OP, (vm, { op1: register }) => { 'BUG: No template was found for this component, and the component did not have the dynamic layout capability' ); - compilable = manager.getDynamicLayout(instance.state, vm.runtime.resolver); + compilable = manager.getDynamicLayout(instance.state, vm.context.resolver); if (compilable === null) { if (managerHasCapability(manager, capabilities, InternalComponentCapabilities.wrapped)) { @@ -771,7 +771,7 @@ APPEND_OPCODES.add(VM_GET_COMPONENT_LAYOUT_OP, (vm, { op1: register }) => { } } - let handle = compilable.compile(vm.context.program); + let handle = compilable.compile(vm.context); stack.push(compilable.symbolTable); stack.push(handle); diff --git a/packages/@glimmer/runtime/lib/compiled/opcodes/expressions.ts b/packages/@glimmer/runtime/lib/compiled/opcodes/expressions.ts index 0c29d3843..e6e9b249c 100644 --- a/packages/@glimmer/runtime/lib/compiled/opcodes/expressions.ts +++ b/packages/@glimmer/runtime/lib/compiled/opcodes/expressions.ts @@ -73,7 +73,7 @@ APPEND_OPCODES.add(VM_CURRY_OP, (vm, { op1: type, op2: _isStrict }) => { let capturedArgs = check(stack.pop(), CheckCapturedArguments); let owner = vm.getOwner(); - let resolver = vm.runtime.resolver; + let resolver = vm.context.resolver; let isStrict = false; diff --git a/packages/@glimmer/runtime/lib/component/resolve.ts b/packages/@glimmer/runtime/lib/component/resolve.ts index 60fc60094..53f67e176 100644 --- a/packages/@glimmer/runtime/lib/component/resolve.ts +++ b/packages/@glimmer/runtime/lib/component/resolve.ts @@ -1,19 +1,19 @@ import type { ComponentDefinition, + ClassicResolver, Nullable, Owner, ResolutionTimeConstants, - RuntimeResolver, } from '@glimmer/interfaces'; import { expect } from '@glimmer/debug-util'; export function resolveComponent( - resolver: RuntimeResolver, + resolver: ClassicResolver | null, constants: ResolutionTimeConstants, name: string, owner: Owner | null ): Nullable { - let definition = resolver.lookupComponent( + let definition = resolver?.lookupComponent?.( name, expect(owner, 'BUG: expected owner when looking up component') ); diff --git a/packages/@glimmer/runtime/lib/environment.ts b/packages/@glimmer/runtime/lib/environment.ts index 93b030647..6f06535c6 100644 --- a/packages/@glimmer/runtime/lib/environment.ts +++ b/packages/@glimmer/runtime/lib/environment.ts @@ -4,16 +4,16 @@ import type { EnvironmentOptions, GlimmerTreeChanges, GlimmerTreeConstruction, + ClassicResolver, ModifierInstance, Nullable, RuntimeArtifacts, - RuntimeContext, - RuntimeResolver, + RuntimeOptions, Transaction, TransactionSymbol, } from '@glimmer/interfaces'; import { assert, expect } from '@glimmer/debug-util'; -import { RuntimeProgramImpl } from '@glimmer/program'; +import { ProgramImpl } from '@glimmer/program'; import { track, updateTag } from '@glimmer/validator'; import DebugRenderTree from './debug-render-tree'; @@ -203,12 +203,12 @@ export function runtimeContext( options: EnvironmentOptions, delegate: EnvironmentDelegate, artifacts: RuntimeArtifacts, - resolver: RuntimeResolver -): RuntimeContext { + resolver: ClassicResolver | null +): RuntimeOptions { return { env: new EnvironmentImpl(options, delegate), - program: new RuntimeProgramImpl(artifacts.constants, artifacts.heap), - resolver: resolver, + program: new ProgramImpl(artifacts.constants, artifacts.heap), + resolver, }; } diff --git a/packages/@glimmer/runtime/lib/opcodes.ts b/packages/@glimmer/runtime/lib/opcodes.ts index e38291768..30ba73f8c 100644 --- a/packages/@glimmer/runtime/lib/opcodes.ts +++ b/packages/@glimmer/runtime/lib/opcodes.ts @@ -17,6 +17,7 @@ import { LOCAL_LOGGER } from '@glimmer/util'; import { $fp, $pc, $ra, $s0, $s1, $sp, $t0, $t1, $v0 } from '@glimmer/vm'; import type { LowLevelVM, VM } from './vm'; +import type { Externs } from './vm/low-level'; import { isScopeReference } from './scope'; import { CURSOR_STACK } from './vm/element-builder'; @@ -90,6 +91,20 @@ export class AppendOpcodes { } } +export function externs(vm: VM): Externs | undefined { + return LOCAL_DEBUG + ? { + debugBefore: (opcode: RuntimeOp): DebugState => { + return APPEND_OPCODES.debugBefore!(vm, opcode); + }, + + debugAfter: (state: DebugState): void => { + APPEND_OPCODES.debugAfter!(vm, state); + }, + } + : undefined; +} + if (import.meta.env.VM_LOCAL_DEV) { Object.assign(AppendOpcodes.prototype, { debugBefore(vm: VM, opcode: RuntimeOp): DebugState { diff --git a/packages/@glimmer/runtime/lib/references/curry-value.ts b/packages/@glimmer/runtime/lib/references/curry-value.ts index 98497dba0..a41a2cd85 100644 --- a/packages/@glimmer/runtime/lib/references/curry-value.ts +++ b/packages/@glimmer/runtime/lib/references/curry-value.ts @@ -2,10 +2,10 @@ import type { CapturedArguments, CurriedType, Dict, + ClassicResolver, Maybe, Nullable, Owner, - RuntimeResolver, } from '@glimmer/interfaces'; import type { Reference } from '@glimmer/reference'; import { CURRIED_COMPONENT } from '@glimmer/constants'; @@ -20,7 +20,7 @@ export default function createCurryRef( inner: Reference, owner: Owner, args: Nullable, - resolver: RuntimeResolver, + resolver: ClassicResolver | null, isStrict: boolean ) { let lastValue: Maybe | string, curriedDefinition: object | string | null; @@ -48,7 +48,7 @@ export default function createCurryRef( let resolvedDefinition = expect( resolver, 'BUG: expected resolver for curried component definitions' - ).lookupComponent(value, owner); + ).lookupComponent?.(value, owner); if (!resolvedDefinition) { throw new Error( diff --git a/packages/@glimmer/runtime/lib/render.ts b/packages/@glimmer/runtime/lib/render.ts index 5b1cf199a..7bc5787b7 100644 --- a/packages/@glimmer/runtime/lib/render.ts +++ b/packages/@glimmer/runtime/lib/render.ts @@ -4,11 +4,10 @@ import type { DynamicScope, ElementBuilder, Environment, - Owner, ProgramContext, + Owner, RenderResult, RichIteratorResult, - RuntimeContext, TemplateIterator, } from '@glimmer/interfaces'; import type { Reference } from '@glimmer/reference'; @@ -45,29 +44,25 @@ export function renderSync(env: Environment, iterator: TemplateIterator): Render } export function renderMain( - runtime: RuntimeContext, - program: ProgramContext, + context: ProgramContext, owner: Owner, self: Reference, tree: ElementBuilder, layout: CompilableProgram, dynamicScope: DynamicScope = new DynamicScopeImpl() ): TemplateIterator { - let handle = unwrapHandle(layout.compile(program)); + let handle = unwrapHandle(layout.compile(context)); let numSymbols = layout.symbolTable.symbols.length; - let vm = VM.initial( - { runtime, program: program }, - { - scope: { - self, - size: numSymbols, - }, - dynamicScope, - tree, - handle, - owner, - } - ); + let vm = VM.initial(context, { + scope: { + self, + size: numSymbols, + }, + dynamicScope, + tree, + handle, + owner, + }); return new TemplateIteratorImpl(vm); } @@ -126,18 +121,14 @@ function renderInvocation( } export function renderComponent( - runtime: RuntimeContext, - tree: ElementBuilder, context: ProgramContext, + tree: ElementBuilder, owner: Owner, definition: ComponentDefinitionState, args: Record = {}, dynamicScope: DynamicScope = new DynamicScopeImpl() ): TemplateIterator { - let vm = VM.empty( - { runtime, program: context }, - { tree, handle: context.stdlib.main, dynamicScope, owner } - ); + let vm = VM.initial(context, { tree, handle: context.stdlib.main, dynamicScope, owner }); return renderInvocation(vm, context, owner, definition, recordToReference(args)); } diff --git a/packages/@glimmer/runtime/lib/vm/append.ts b/packages/@glimmer/runtime/lib/vm/append.ts index a4f88f967..a99f5f54d 100644 --- a/packages/@glimmer/runtime/lib/vm/append.ts +++ b/packages/@glimmer/runtime/lib/vm/append.ts @@ -8,19 +8,17 @@ import type { DynamicScope, ElementBuilder, Environment, - JitConstants, - JitContext, Owner, + Program, + ProgramConstants, + ProgramContext, + ProgramHeap, RenderResult, RichIteratorResult, - RuntimeContext, - RuntimeHeap, - RuntimeProgram, Scope, SyscallRegisters, UpdatingOpcode, } from '@glimmer/interfaces'; -import type { RuntimeOpImpl } from '@glimmer/program'; import type { OpaqueIterationItem, OpaqueIterator, Reference } from '@glimmer/reference'; import type { MachineRegister, Register, SyscallRegister } from '@glimmer/vm'; import { expect, unwrapHandle } from '@glimmer/debug-util'; @@ -32,7 +30,6 @@ import { LOCAL_LOGGER, reverse, Stack } from '@glimmer/util'; import { beginTrackFrame, endTrackFrame, resetTracking } from '@glimmer/validator'; import { $pc, isLowLevelRegister } from '@glimmer/vm'; -import type { DebugState } from '../opcodes'; import type { ScopeOptions } from '../scope'; import type { LiveBlockList } from './element-builder'; import type { EvaluationStack } from './stack'; @@ -43,7 +40,7 @@ import { EndTrackFrameOpcode, JumpIfNotModifiedOpcode, } from '../compiled/opcodes/vm'; -import { APPEND_OPCODES } from '../opcodes'; +import { externs } from '../opcodes'; import { ScopeImpl } from '../scope'; import { VMArgumentsImpl } from './arguments'; import { LowLevelVM } from './low-level'; @@ -57,6 +54,7 @@ class Stacks implements DebugStacks { readonly updating = new Stack(); readonly cache = new Stack(); readonly list = new Stack(); + readonly destroyable = new Stack(); } type Handle = number; @@ -107,11 +105,10 @@ export class VM { declare debugDidReturn?: (this: VM) => void; readonly #stacks = new Stacks(); - readonly #heap: RuntimeHeap; + readonly #heap: ProgramHeap; readonly #destructor: object; readonly #templates?: TemplateDebug; - readonly #destroyableStack = new Stack(); - readonly constants: JitConstants; + readonly constants: ProgramConstants; readonly args: VMArgumentsImpl; readonly lowlevel: LowLevelVM; readonly debug?: () => DebugVmState; @@ -215,7 +212,7 @@ export class VM { constructor( { pc, scope, dynamicScope, stack }: ClosureState, private readonly tree: ElementBuilder, - readonly context: JitContext + readonly context: ProgramContext ) { if (import.meta.env.DEV) { assertGlobalContextWasSet!(); @@ -223,39 +220,24 @@ export class VM { let evalStack = EvaluationStackImpl.restore(stack, pc); - this.#heap = this.program.heap; this.constants = this.program.constants; this.tree = tree; + + this.#heap = this.program.heap; this.#stacks.scope.push(scope); this.#stacks.dynamicScope.push(dynamicScope); - this.args = new VMArgumentsImpl(); - this.lowlevel = new LowLevelVM( - evalStack, - this.#heap, - context.runtime.program, - import.meta.env.VM_LOCAL_DEV - ? { - debugBefore: (opcode: RuntimeOpImpl): DebugState => { - return APPEND_OPCODES.debugBefore!(this, opcode); - }, - - debugAfter: (state: DebugState): void => { - APPEND_OPCODES.debugAfter!(this, state); - }, - } - : undefined, - evalStack.registers - ); - this.#destructor = {}; - this.#destroyableStack.push(this.#destructor); + this.#stacks.destroyable.push(this.#destructor); + + this.args = new VMArgumentsImpl(); + this.lowlevel = new LowLevelVM(evalStack, context, externs(this)); if (LOCAL_DEBUG) { const templates = (this.#templates = new TemplateDebug()); this.debug = () => ({ stacks: this.#stacks, - destroyableStack: this.#destroyableStack.snapshot(), + destroyableStack: this.#stacks.destroyable.snapshot(), constants: this.constants, lowlevel: this.lowlevel, @@ -273,26 +255,15 @@ export class VM { }, }); } - } - static initial(context: JitContext, options: InitialVmState) { - let scope = ScopeImpl.root( - options.owner, - options.scope ?? { self: UNDEFINED_REFERENCE, size: 0 } - ); - return VM.create({ - ...options, - scope, - context, - }); + this.pushUpdating(); } - static empty(context: JitContext, options: InitialVmState) { + static initial(context: ProgramContext, options: InitialVmState) { let scope = ScopeImpl.root( options.owner, options.scope ?? { self: UNDEFINED_REFERENCE, size: 0 } ); - return VM.create({ ...options, scope, @@ -311,16 +282,15 @@ export class VM { dynamicScope: DynamicScope; handle: number; tree: ElementBuilder; - context: JitContext; + context: ProgramContext; }) { - let state = closureState(context.runtime.program.heap.getaddr(handle), scope, dynamicScope); + let state = closureState(context.program.heap.getaddr(handle), scope, dynamicScope); let vm = new VM(state, tree, context); - vm.pushUpdating(); return vm; } compile(block: CompilableTemplate): number { - let handle = unwrapHandle(block.compile(this.context.program)); + let handle = unwrapHandle(block.compile(this.context)); if (LOCAL_DEBUG) { this.#templates?.register(handle, block.meta); @@ -329,16 +299,12 @@ export class VM { return handle; } - get runtime(): RuntimeContext { - return this.context.runtime; - } - - get program(): RuntimeProgram { - return this.context.runtime.program; + get program(): Program { + return this.context.program; } get env(): Environment { - return this.context.runtime.env; + return this.context.env; } private captureClosure(args: number, pc = this.lowlevel.fetchRegister($pc)): ClosureState { @@ -425,7 +391,7 @@ export class VM { let state = this.capture(args); let block = this.elements().pushUpdatableBlock(); - let tryOpcode = new TryOpcode(state, this.runtime, block, updating); + let tryOpcode = new TryOpcode(state, this.context, block, updating); this.didEnter(tryOpcode); } @@ -467,7 +433,7 @@ export class VM { let state = this.capture(2); let block = this.elements().pushUpdatableBlock(); - let opcode = new ListItemOpcode(state, this.runtime, block, key, memoRef, valueRef); + let opcode = new ListItemOpcode(state, this.context, block, key, memoRef, valueRef); this.didEnter(opcode); return opcode; @@ -503,7 +469,7 @@ export class VM { let state = this.capture(0, addr); let list = this.elements().pushBlockList(updating) as LiveBlockList; - let opcode = new ListBlockOpcode(state, this.runtime, list, updating, iterableRef); + let opcode = new ListBlockOpcode(state, this.context, list, updating, iterableRef); this.#stacks.list.push(opcode); @@ -528,7 +494,7 @@ export class VM { */ private didEnter(opcode: BlockOpcode) { this.associateDestroyable(opcode); - this.#destroyableStack.push(opcode); + this.#stacks.destroyable.push(opcode); this.updateWith(opcode); this.pushUpdating(opcode.children); } @@ -546,7 +512,7 @@ export class VM { * [!] pop Updating Stack */ exit() { - this.#destroyableStack.pop(); + this.#stacks.destroyable.pop(); this.elements().popBlock(); this.popUpdating(); } @@ -702,7 +668,7 @@ export class VM { * @utility */ associateDestroyable(child: Destroyable): void { - let parent = expect(this.#destroyableStack.current, 'Expected destructor parent'); + let parent = expect(this.#stacks.destroyable.current, 'Expected destructor parent'); associateDestroyableChild(parent, child); } @@ -873,14 +839,14 @@ export interface ClosureState { */ export class Closure { private state: ClosureState; - private context: JitContext; + private context: ProgramContext; - constructor(state: ClosureState, context: JitContext) { + constructor(state: ClosureState, context: ProgramContext) { this.state = state; this.context = context; } - evaluate(runtime: RuntimeContext, tree: ElementBuilder): VM { + evaluate(runtime: ProgramContext, tree: ElementBuilder): VM { return new VM(this.state, tree, this.context); } } diff --git a/packages/@glimmer/runtime/lib/vm/low-level.ts b/packages/@glimmer/runtime/lib/vm/low-level.ts index 7507ec1fe..f834d2462 100644 --- a/packages/@glimmer/runtime/lib/vm/low-level.ts +++ b/packages/@glimmer/runtime/lib/vm/low-level.ts @@ -1,4 +1,4 @@ -import type { Nullable, RuntimeHeap, RuntimeOp, RuntimeProgram } from '@glimmer/interfaces'; +import type { Nullable, ProgramContext, RuntimeOp } from '@glimmer/interfaces'; import type { MachineRegister } from '@glimmer/vm'; import { VM_INVOKE_STATIC_OP, @@ -41,6 +41,8 @@ export function initializeRegistersWithPC(pc: number): LowLevelRegisters { } export interface VmStack { + readonly registers: LowLevelRegisters; + push(value: unknown): void; get(position: number): number; pop(): T; @@ -55,14 +57,17 @@ export interface Externs { export class LowLevelVM { public currentOpSize = 0; + readonly registers: LowLevelRegisters; + readonly context: ProgramContext; constructor( public stack: VmStack, - public heap: RuntimeHeap, - public program: RuntimeProgram, - public externs: Externs | undefined, - readonly registers: LowLevelRegisters - ) {} + context: ProgramContext, + public externs: Externs | undefined + ) { + this.context = context; + this.registers = stack.registers; + } fetchRegister(register: MachineRegister): number { return this.registers[register]; @@ -113,7 +118,7 @@ export class LowLevelVM { assert(handle < 0xffffffff, `Jumping to placeholder address`); this.registers[$ra] = this.registers[$pc]; - this.setPc(this.heap.getaddr(handle)); + this.setPc(this.context.program.heap.getaddr(handle)); } // Put a specific `program` address in $ra @@ -127,7 +132,7 @@ export class LowLevelVM { } nextStatement(): Nullable { - let { registers, program } = this; + let { registers, context } = this; let pc = registers[$pc]; @@ -142,7 +147,7 @@ export class LowLevelVM { // to where we are going. We can't simply ask for the size // in a jump because we have have already incremented the // program counter to the next instruction prior to executing. - let opcode = program.opcode(pc); + let opcode = context.program.opcode(pc); let operationSize = (this.currentOpSize = opcode.size); this.registers[$pc] += operationSize; diff --git a/packages/@glimmer/runtime/lib/vm/update.ts b/packages/@glimmer/runtime/lib/vm/update.ts index 38546ae40..091cda20e 100644 --- a/packages/@glimmer/runtime/lib/vm/update.ts +++ b/packages/@glimmer/runtime/lib/vm/update.ts @@ -4,9 +4,9 @@ import type { Environment, ExceptionHandler, GlimmerTreeChanges, + ProgramContext, Nullable, ResettableBlock, - RuntimeContext, SimpleComment, UpdatingOpcode, UpdatingVM as IUpdatingVM, @@ -103,7 +103,7 @@ export abstract class BlockOpcode implements UpdatingOpcode, Bounds { constructor( protected state: Closure, - protected runtime: RuntimeContext, + protected context: ProgramContext, bounds: AppendingBlock, children: UpdatingOpcode[] ) { @@ -138,18 +138,16 @@ export class TryOpcode extends BlockOpcode implements ExceptionHandler { } handleException() { - let { state, bounds, runtime } = this; + let { state, bounds, context } = this; destroyChildren(this); - let elementStack = NewElementBuilder.resume(runtime.env, bounds); - let vm = state.evaluate(runtime, elementStack); + let elementStack = NewElementBuilder.resume(context.env, bounds); + let vm = state.evaluate(context, elementStack); - let updating: UpdatingOpcode[] = []; let children = (this.children = []); let result = vm.execute((vm) => { - vm.pushUpdating(updating); vm.updateWith(this); vm.pushUpdating(children); }); @@ -164,13 +162,13 @@ export class ListItemOpcode extends TryOpcode { constructor( state: Closure, - runtime: RuntimeContext, + context: ProgramContext, bounds: ResettableBlock, public key: unknown, public memo: Reference, public value: Reference ) { - super(state, runtime, bounds, []); + super(state, context, bounds, []); } shouldRemove(): boolean { @@ -194,12 +192,12 @@ export class ListBlockOpcode extends BlockOpcode { constructor( state: Closure, - runtime: RuntimeContext, + context: ProgramContext, bounds: LiveBlockList, children: ListItemOpcode[], private iterableRef: Reference ) { - super(state, runtime, bounds, children); + super(state, context, bounds, children); this.lastIterator = valueForRef(iterableRef); } @@ -328,19 +326,18 @@ export class ListBlockOpcode extends BlockOpcode { logStep!('list-updates', ['insert', item.key]); } - let { opcodeMap, bounds, state, runtime, children } = this; + let { opcodeMap, bounds, state, context, children } = this; let { key } = item; let nextSibling = before === undefined ? this.marker : before.firstNode(); - let elementStack = NewElementBuilder.forInitialRender(runtime.env, { + let elementStack = NewElementBuilder.forInitialRender(context.env, { element: bounds.parentElement(), nextSibling, }); - let vm = state.evaluate(runtime, elementStack); + let vm = state.evaluate(context, elementStack); vm.execute((vm) => { - vm.pushUpdating(); let opcode = vm.enterItem(item); opcode.index = children.length;