layout rtti with fixed ids for buffers and strings

This commit is contained in:
dcode
2019-05-22 00:14:44 +02:00
parent c92ca0d8cb
commit d94b4fca50
27 changed files with 7579 additions and 9975 deletions

View File

@ -6,7 +6,8 @@
import {
Compiler,
ContextualFlags,
RuntimeFeatures
RuntimeFeatures,
flatten
} from "./compiler";
import {
@ -73,7 +74,7 @@ import {
import {
CommonFlags,
Feature,
RTTIFlags
TypeinfoFlags
} from "./common";
import {
@ -4133,7 +4134,6 @@ export function compileVisitMembers(compiler: Compiler): void {
var managedClasses = program.managedClasses;
var visitInstance = assert(program.visitInstance);
var blocks = new Array<RelooperBlockRef>();
var lastId = 0;
var relooper = Relooper.create(module);
var outer = relooper.addBlockWithSwitch(
@ -4153,17 +4153,10 @@ export function compileVisitMembers(compiler: Compiler): void {
)
);
blocks.push(
relooper.addBlock(
module.createUnreachable()
)
);
relooper.addBranchForSwitch(outer, blocks[0], []);
var lastId = 0;
for (let [id, instance] of managedClasses) {
assert(instance.type.isManaged);
assert(id == ++lastId);
assert(id == lastId++);
let visitImpl: Element | null;
@ -4234,7 +4227,9 @@ export function compileVisitMembers(compiler: Compiler): void {
}
}
if (!instance.base) code.push(module.createReturn());
let block = relooper.addBlock(module.createBlock(null, code)); // TODO: flatten?
let block = relooper.addBlock(
flatten(module, code, NativeType.None)
);
relooper.addBranchForSwitch(outer, block, [ id ]);
blocks.push(block);
}
@ -4245,15 +4240,21 @@ export function compileVisitMembers(compiler: Compiler): void {
relooper.addBranch(blocks[id], blocks[base.id]);
}
}
blocks.push(
relooper.addBlock(
module.createUnreachable()
)
);
relooper.addBranchForSwitch(outer, blocks[blocks.length - 1], []); // default
compiler.compileFunction(visitInstance);
module.addFunction(BuiltinSymbols.visit_members, ftype, [ nativeSizeType ], relooper.renderAndDispose(outer, 2));
}
function typeToRuntimeFlags(type: Type): RTTIFlags {
var flags = RTTIFlags.VALUE_ALIGN_0 * (1 << type.alignLog2);
if (type.is(TypeFlags.NULLABLE)) flags |= RTTIFlags.VALUE_NULLABLE;
if (type.isManaged) flags |= RTTIFlags.VALUE_MANAGED;
return flags / RTTIFlags.VALUE_ALIGN_0;
function typeToRuntimeFlags(type: Type): TypeinfoFlags {
var flags = TypeinfoFlags.VALUE_ALIGN_0 * (1 << type.alignLog2);
if (type.is(TypeFlags.NULLABLE)) flags |= TypeinfoFlags.VALUE_NULLABLE;
if (type.isManaged) flags |= TypeinfoFlags.VALUE_MANAGED;
return flags / TypeinfoFlags.VALUE_ALIGN_0;
}
/** Compiles runtime type information for use by stdlib. */
@ -4262,34 +4263,34 @@ export function compileRTTI(compiler: Compiler): void {
var module = compiler.module;
var managedClasses = program.managedClasses;
var count = managedClasses.size;
var size = 8 + 8 * count;
var size = 4 + 8 * count;
var data = new Uint8Array(size);
writeI32(count, data, 0);
var off = 8;
var off = 4;
var arrayPrototype = program.arrayPrototype;
var setPrototype = program.setPrototype;
var mapPrototype = program.mapPrototype;
var lastId = 0;
for (let [id, instance] of managedClasses) {
assert(id == ++lastId);
let flags: RTTIFlags = 0;
if (instance.isAcyclic) flags |= RTTIFlags.ACYCLIC;
assert(id == lastId++);
let flags: TypeinfoFlags = 0;
if (instance.isAcyclic) flags |= TypeinfoFlags.ACYCLIC;
if (instance.prototype.extends(arrayPrototype)) {
let typeArguments = assert(instance.getTypeArgumentsTo(arrayPrototype));
assert(typeArguments.length == 1);
flags |= RTTIFlags.ARRAY;
flags |= RTTIFlags.VALUE_ALIGN_0 * typeToRuntimeFlags(typeArguments[0]);
flags |= TypeinfoFlags.ARRAY;
flags |= TypeinfoFlags.VALUE_ALIGN_0 * typeToRuntimeFlags(typeArguments[0]);
} else if (instance.prototype.extends(setPrototype)) {
let typeArguments = assert(instance.getTypeArgumentsTo(setPrototype));
assert(typeArguments.length == 1);
flags |= RTTIFlags.SET;
flags |= RTTIFlags.VALUE_ALIGN_0 * typeToRuntimeFlags(typeArguments[0]);
flags |= TypeinfoFlags.SET;
flags |= TypeinfoFlags.VALUE_ALIGN_0 * typeToRuntimeFlags(typeArguments[0]);
} else if (instance.prototype.extends(mapPrototype)) {
let typeArguments = assert(instance.getTypeArgumentsTo(mapPrototype));
assert(typeArguments.length == 2);
flags |= RTTIFlags.MAP;
flags |= RTTIFlags.KEY_ALIGN_0 * typeToRuntimeFlags(typeArguments[0]);
flags |= RTTIFlags.VALUE_ALIGN_0 * typeToRuntimeFlags(typeArguments[1]);
flags |= TypeinfoFlags.MAP;
flags |= TypeinfoFlags.KEY_ALIGN_0 * typeToRuntimeFlags(typeArguments[0]);
flags |= TypeinfoFlags.VALUE_ALIGN_0 * typeToRuntimeFlags(typeArguments[1]);
}
writeI32(flags, data, off); off += 4;
let base = instance.base;

View File

@ -196,7 +196,6 @@ export namespace CommonSymbols {
}
// shared
import { Feature } from "../std/assembly/common/feature";
import { RTTIData, RTTIFlags } from "../std/assembly/common/rtti";
import { Target } from "../std/assembly/common/target";
export { Feature, RTTIData, RTTIFlags, Target };
export { Feature } from "../std/assembly/shared/feature";
export { Target } from "../std/assembly/shared/target";
export { Typeinfo, TypeinfoFlags } from "../std/assembly/shared/typeinfo";

View File

@ -9033,7 +9033,7 @@ var mangleImportName_moduleName: string;
var mangleImportName_elementName: string;
/** Flattens a series of expressions to a nop, a single statement or a block depending on statement count. */
function flatten(module: Module, stmts: ExpressionRef[], type: NativeType): ExpressionRef {
export function flatten(module: Module, stmts: ExpressionRef[], type: NativeType): ExpressionRef {
var length = stmts.length;
if (length == 0) return module.createNop(); // usually filtered out again
if (length == 1) return stmts[0];

View File

@ -280,8 +280,8 @@ export abstract class DiagnosticEmitter {
var message = DiagnosticMessage.create(code, category, arg0, arg1, arg2).withRange(range);
if (relatedRange) message.relatedRange = relatedRange;
this.diagnostics.push(message);
console.log(formatDiagnosticMessage(message, true, true) + "\n"); // temporary
console.log(<string>new Error("stack").stack);
// console.log(formatDiagnosticMessage(message, true, true) + "\n"); // temporary
// console.log(<string>new Error("stack").stack);
}
/** Emits an informatory diagnostic message. */

View File

@ -387,7 +387,7 @@ export class Program extends DiagnosticEmitter {
allocArrayInstance: Function;
/** Next class id. */
nextClassId: u32 = 1;
nextClassId: u32 = 0;
/** Constructs a new program, optionally inheriting parser diagnostics. */
constructor(
@ -732,6 +732,13 @@ export class Program extends DiagnosticEmitter {
}
}
// register ArrayBuffer (id=0) and String (id=1)
assert(this.nextClassId == 0);
this.arrayBufferInstance = this.requireClass(CommonSymbols.ArrayBuffer);
assert(this.arrayBufferInstance.id == 0);
this.stringInstance = this.requireClass(CommonSymbols.String);
assert(this.stringInstance.id == 1);
// register classes backing basic types
this.registerNativeTypeClass(TypeKind.I8, CommonSymbols.I8);
this.registerNativeTypeClass(TypeKind.I16, CommonSymbols.I16);
@ -805,8 +812,6 @@ export class Program extends DiagnosticEmitter {
// register stdlib components
this.arrayBufferViewInstance = this.requireClass(CommonSymbols.ArrayBufferView);
this.arrayBufferInstance = this.requireClass(CommonSymbols.ArrayBuffer);
this.stringInstance = this.requireClass(CommonSymbols.String);
this.arrayPrototype = <ClassPrototype>this.require(CommonSymbols.Array, ElementKind.CLASS_PROTOTYPE);
this.fixedArrayPrototype = <ClassPrototype>this.require(CommonSymbols.FixedArray, ElementKind.CLASS_PROTOTYPE);
this.setPrototype = <ClassPrototype>this.require(CommonSymbols.Set, ElementKind.CLASS_PROTOTYPE);
@ -2997,11 +3002,9 @@ export class Class extends TypedElement {
/** Remembers acyclic state. */
private _acyclic: AcyclicState = AcyclicState.UNKNOWN;
/** Gets the unique runtime id of this class. Must be a managed class. */
/** Gets the unique runtime id of this class. */
get id(): u32 {
var id = this._id;
assert(id); // must be managed to have an id
return id;
return this._id; // unmanaged remains 0 (=ArrayBuffer)
}
/** Tests if this class is of a builtin array type (Array/TypedArray). */