Skip to content

Commit

Permalink
[BREAKING] All internals now support serialization
Browse files Browse the repository at this point in the history
This is the initial pass of making the program serializable. In general,
previous work has made the program itself serializable, because the
program itself is an array of opcodes, and an opcode is an array of
numbers (128 bits).

However, the program often has references into the constant pool. Some
of the constant pool is already serializable (for example, strings).
However, before this series of commits, the constant pool also contained
a number of direct references to live objects that could not be
trivially serialized.

The purpose of these commits is to make all constants serializable.

To make more objects supplied by the user serializable, we introduced a
Resolver (similar but not identical to the interface in @glimmer/di)
to indirect any lookup of user objects. The lookup specifier is required
to be serializable.

As part of this work, we added a few new features, because certain
important functionality was previously implemented in userland, and the
API for implementing them was excessively dynamic.

- Implemented `{{component}}` and `(component)` (from Glimmer.js and
  Ember) natively in glimmer-vm.
- Support for first-class argument currying in `(component)`.

---

Previously, blocks were always compiled "in-place", taking advantage of
the fact that nested blocks were never compiled during the compilation
of their parent.

Now, eager compilation requires us to compile nested blocks ahead of
time, so the naive strategy of compiling into the "current" position
doesn't work anymore. Instead, we compile into a temporary buffer, and
commit into the main program once a particular block is finished. In
practice, this means that nested blocks always appear *before* their
parent in the program.

Also added initial support for a component capability mask, which
allowed us to build static component invocation. The most important
consequence is that the system is no longer architected around the quirk
of Ember's late-bound layouts. If a component definition is able to
specify its layout ahead of time, we can generate a specialized
invocation for the component we're invoking, rather than a bunch of
dynamic checks that require us to keep static information around at
runtime.

Similarly, instead of modelling dynamic blocks as a special kind of
runtime object, we now push the symbol table and Handle onto the stack.
Because the symbol table is serializable (and Handle is an integer),
this means that the constants used by dynamic invocation are always,
themselves, serializable.

[BREAKING]

Remove all of the cases where Glimmer was sticking functions in the
constant pool (which aren't serializable).

The breaking change is that dynamic attributes should be installed by
the didCreateElement manager hook (note: this is *not* the place where
user code is invoked) rather than using the wrapping DSL. Similarly,
dynamic tag name is now modelled by using a getTagName hook on the
component manager.

These hooks should be run in SSR mode.
  • Loading branch information
chancancode committed Jul 25, 2017
1 parent 0730db8 commit 79f2b45
Show file tree
Hide file tree
Showing 61 changed files with 3,041 additions and 2,543 deletions.
12 changes: 3 additions & 9 deletions packages/@glimmer/compiler/test/compile-options-test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { TemplateMeta } from '@glimmer/wire-format';
import { TestEnvironment, compile } from "@glimmer/test-helpers";
import { TestEnvironment } from "@glimmer/test-helpers";
import { precompile } from "@glimmer/compiler";

let env: TestEnvironment;
Expand All @@ -14,12 +13,7 @@ QUnit.module('Compile options', {

QUnit.test('moduleName option is passed into meta', assert => {
let moduleName = 'It ain\'t hard to tell';
let template = compile('Hi, {{name}}!', {
env,
meta: {
moduleName
}
});
let template = env.compile('Hi, {{name}}!', { moduleName });
assert.equal(template.meta.moduleName, moduleName, 'Template has the moduleName');
});

Expand All @@ -34,7 +28,7 @@ QUnit.test('returned meta is correct', assert => {
meta: {
moduleName: 'my/module-name',
metaIsOpaque: 'yes'
} as any as TemplateMeta
}
}));

assert.equal(wire.meta.moduleName, 'my/module-name', 'Template has correct meta');
Expand Down
1 change: 1 addition & 0 deletions packages/@glimmer/interfaces/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from './lib/tier1/symbol-table';
export * from './lib/di';
export * from './lib/core';

import * as Simple from './lib/dom/simple';
Expand Down
6 changes: 6 additions & 0 deletions packages/@glimmer/interfaces/lib/core.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,9 @@ export type unsafe = any;
export interface Dict<T> {
[key: string]: T;
}

export interface Unique<T> {
"Unique [id=ada0f31f-27f7-4ab0-bc03-0005387c9d5f]": T;
}

export type Recast<T, U> = (T & U) | U;
11 changes: 11 additions & 0 deletions packages/@glimmer/interfaces/lib/di.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { TemplateMeta } from '@glimmer/wire-format';
import { Opaque, Option, Unique } from './core';

export interface Resolver<Specifier, T extends TemplateMeta = TemplateMeta> {
lookupHelper(name: string, meta: T): Option<Specifier>;
lookupModifier(name: string, meta: T): Option<Specifier>;
lookupComponent(name: string, meta: T): Option<Specifier>;
lookupPartial(name: string, meta: T): Option<Specifier>;

resolve<U>(specifier: Specifier): U;
}
4 changes: 2 additions & 2 deletions packages/@glimmer/node/test/node-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,10 @@ function commonSetup() {
root = rootElement();
}

function render<T>(template: Template<T>, self: any) {
function render(template: Template, self: any) {
let result;
env.begin();
let templateIterator = template.render({ self: new UpdatableReference(self), parentNode: root, dynamicScope: new TestDynamicScope() });
let templateIterator = template.render({ env, self: new UpdatableReference(self), parentNode: root, dynamicScope: new TestDynamicScope() });

do {
result = templateIterator.next();
Expand Down
4 changes: 2 additions & 2 deletions packages/@glimmer/reference/lib/validators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -278,9 +278,9 @@ register(UpdatableTag);

//////////

export interface VersionedReference<T> extends Reference<T>, Tagged {}
export interface VersionedReference<T = Opaque> extends Reference<T>, Tagged {}

export interface VersionedPathReference<T> extends PathReference<T>, Tagged {
export interface VersionedPathReference<T = Opaque> extends PathReference<T>, Tagged {
get(property: string): VersionedPathReference<Opaque>;
}

Expand Down
31 changes: 15 additions & 16 deletions packages/@glimmer/runtime/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ export {

export {
CompilableLayout,
compileLayout
ComponentLayoutBuilder,
scanLayout
} from './lib/compiler';

export {
Expand All @@ -19,14 +20,6 @@ export {
} from './lib/opcode-builder';

export {
CompiledStaticTemplate,
CompiledDynamicTemplate,
CompiledDynamicBlock,
CompiledDynamicProgram
} from './lib/compiled/blocks';

export {
Register,
debugSlice
} from './lib/opcodes';

Expand All @@ -45,16 +38,19 @@ export {
Inlines as InlineMacros,
BlockMacro,
MissingBlockMacro,
compileList,
expr as compileExpression
} from './lib/syntax/functions';

export {
CompilableTemplate,
Block,
Program
BlockSyntax,
TopLevelSyntax
} from './lib/syntax/interfaces';

export {
Macros
} from './lib/syntax/macros';

export { PublicVM as VM, UpdatingVM, RenderResult, IteratorResult } from './lib/vm';

export {
Expand All @@ -76,23 +72,26 @@ export { SafeString } from './lib/upsert';

export {
Scope,
Handle,
default as Environment,
Helper,
DynamicScope,
Program,
CompilationOptions
} from './lib/environment';

export {
PartialDefinition
} from './lib/partial';

export {
Component,
ComponentClass,
ComponentCapabilities,
ComponentManager,
ComponentDefinition,
ComponentLayoutBuilder,
ComponentAttrsBuilder,
WithDynamicTagName,
PreparedArguments,
WithDynamicLayout,
WithStaticLayout,
isComponentDefinition
} from './lib/component/interfaces';

Expand Down
53 changes: 0 additions & 53 deletions packages/@glimmer/runtime/lib/compiled/blocks.ts

This file was deleted.

Loading

0 comments on commit 79f2b45

Please sign in to comment.