mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-04-25 15:12:12 +00:00
Always compile globals because initializers might have side effects
This commit is contained in:
parent
50dea3b1df
commit
7e9b58428b
@ -151,10 +151,9 @@ export function initialize(program: Program): void {
|
||||
|
||||
/** Adds a built-in constant to the specified program. */
|
||||
function addConstant(program: Program, name: string, type: Type): Global {
|
||||
var global = new Global(program, name, name, null);
|
||||
var global = new Global(program, name, name, null, type);
|
||||
global.isBuiltIn = true;
|
||||
global.isConstant = true;
|
||||
global.type = type;
|
||||
program.elements.set(name, global);
|
||||
return global;
|
||||
}
|
||||
|
@ -21,7 +21,8 @@ import {
|
||||
NativeType,
|
||||
FunctionTypeRef,
|
||||
FunctionRef,
|
||||
ExpressionId
|
||||
ExpressionId,
|
||||
readString
|
||||
} from "./module";
|
||||
|
||||
import {
|
||||
@ -295,9 +296,8 @@ export class Compiler extends DiagnosticEmitter {
|
||||
this.compileNamespaceDeclaration(<NamespaceDeclaration>statement);
|
||||
break;
|
||||
|
||||
case NodeKind.VARIABLE:
|
||||
if (noTreeShaking || source.isEntry && hasModifier(ModifierKind.EXPORT, (<VariableStatement>statement).modifiers))
|
||||
this.compileVariableStatement(<VariableStatement>statement);
|
||||
case NodeKind.VARIABLE: // global
|
||||
this.compileVariableStatement(<VariableStatement>statement); // always because initializers might have side effects
|
||||
break;
|
||||
|
||||
case NodeKind.EXPORT:
|
||||
@ -344,12 +344,17 @@ export class Compiler extends DiagnosticEmitter {
|
||||
var declaration = global.declaration;
|
||||
var initExpr: ExpressionRef = 0;
|
||||
|
||||
if (!global.type) { // infer type
|
||||
if (global.type == Type.void) { // infer type
|
||||
if (declaration) {
|
||||
if (declaration.type) {
|
||||
global.type = this.program.resolveType(declaration.type); // reports
|
||||
if (!global.type)
|
||||
var resolvedType = this.program.resolveType(declaration.type); // reports
|
||||
if (!resolvedType)
|
||||
return false;
|
||||
if (resolvedType == Type.void) {
|
||||
this.error(DiagnosticCode.Type_0_is_not_assignable_to_type_1, declaration.range, "*", resolvedType.toString());
|
||||
return false;
|
||||
}
|
||||
global.type = resolvedType;
|
||||
} else if (declaration.initializer) {
|
||||
initExpr = this.compileExpression(declaration.initializer, Type.void, ConversionKind.NONE); // reports and returns unreachable
|
||||
if (this.currentType == Type.void) {
|
||||
@ -2119,18 +2124,9 @@ export class Compiler extends DiagnosticEmitter {
|
||||
switch (element.kind) {
|
||||
|
||||
case ElementKind.LOCAL:
|
||||
elementType = (<Local>element).type;
|
||||
break;
|
||||
|
||||
case ElementKind.GLOBAL:
|
||||
if (!this.compileGlobal(<Global>element)) // reports
|
||||
return this.module.createUnreachable();
|
||||
assert((<Global>element).type != null);
|
||||
elementType = <Type>(<Global>element).type;
|
||||
break;
|
||||
|
||||
case ElementKind.FIELD:
|
||||
elementType = (<Field>element).type;
|
||||
elementType = (<VariableLikeElement>element).type;
|
||||
break;
|
||||
|
||||
case ElementKind.PROPERTY:
|
||||
@ -2174,17 +2170,17 @@ export class Compiler extends DiagnosticEmitter {
|
||||
: this.module.createSetLocal((<Local>element).index, valueWithCorrectType);
|
||||
|
||||
case ElementKind.GLOBAL:
|
||||
if (!this.compileGlobal(<Global>element))
|
||||
if (!this.compileGlobal(<Global>element)) // reports; not yet compiled if a static field compiled as a global
|
||||
return this.module.createUnreachable();
|
||||
assert((<Global>element).type != null);
|
||||
this.currentType = select<Type>(<Type>(<Global>element).type, Type.void, tee);
|
||||
assert((<Global>element).type != Type.void);
|
||||
this.currentType = select<Type>((<Global>element).type, Type.void, tee);
|
||||
if ((<Local>element).isConstant) {
|
||||
this.error(DiagnosticCode.Cannot_assign_to_0_because_it_is_a_constant_or_a_read_only_property, expression.range, (<Local>element).internalName);
|
||||
return this.module.createUnreachable();
|
||||
}
|
||||
if (!tee)
|
||||
return this.module.createSetGlobal((<Global>element).internalName, valueWithCorrectType);
|
||||
var globalNativeType = (<Type>(<Global>element).type).toNativeType();
|
||||
var globalNativeType = (<Global>element).type.toNativeType();
|
||||
return this.module.createBlock(null, [ // emulated teeGlobal
|
||||
this.module.createSetGlobal((<Global>element).internalName, valueWithCorrectType),
|
||||
this.module.createGetGlobal((<Global>element).internalName, globalNativeType)
|
||||
@ -2431,10 +2427,10 @@ export class Compiler extends DiagnosticEmitter {
|
||||
case ElementKind.GLOBAL:
|
||||
if (element.isBuiltIn)
|
||||
return compileBuiltinGetConstant(this, <Global>element);
|
||||
if (!this.compileGlobal(<Global>element)) // reports
|
||||
if (!this.compileGlobal(<Global>element)) // reports; not yet compiled if a static field compiled as a global
|
||||
return this.module.createUnreachable();
|
||||
assert((<Global>element).type != null);
|
||||
this.currentType = <Type>(<Global>element).type;
|
||||
assert((<Global>element).type != Type.void);
|
||||
this.currentType = (<Global>element).type;
|
||||
if ((<Global>element).hasConstantValue)
|
||||
return makeInlineConstant(<Global>element, this.module);
|
||||
return this.module.createGetGlobal((<Global>element).internalName, this.currentType.toNativeType());
|
||||
@ -2504,10 +2500,10 @@ export class Compiler extends DiagnosticEmitter {
|
||||
switch (element.kind) {
|
||||
|
||||
case ElementKind.GLOBAL: // static property
|
||||
if (!this.compileGlobal(<Global>element))
|
||||
if (!this.compileGlobal(<Global>element)) // reports; not yet compiled if a static field compiled as a global
|
||||
return this.module.createUnreachable();
|
||||
assert((<Global>element).type != null);
|
||||
this.currentType = <Type>(<Global>element).type;
|
||||
assert((<Global>element).type != Type.void);
|
||||
this.currentType = (<Global>element).type;
|
||||
if ((<Global>element).hasConstantValue)
|
||||
return makeInlineConstant(<Global>element, this.module);
|
||||
return this.module.createGetGlobal((<Global>element).internalName, this.currentType.toNativeType());
|
||||
|
@ -333,7 +333,7 @@ export class Program extends DiagnosticEmitter {
|
||||
}
|
||||
} else
|
||||
classPrototype.members = new Map();
|
||||
var staticField = new Global(this, name, internalName, declaration, null);
|
||||
var staticField = new Global(this, name, internalName, declaration, Type.void);
|
||||
classPrototype.members.set(name, staticField);
|
||||
this.elements.set(internalName, staticField);
|
||||
|
||||
@ -801,7 +801,7 @@ export class Program extends DiagnosticEmitter {
|
||||
continue;
|
||||
}
|
||||
|
||||
var global = new Global(this, declaration.name.name, internalName, declaration, null);
|
||||
var global = new Global(this, declaration.name.name, internalName, declaration, /* resolved later */ Type.void);
|
||||
global.namespace = namespace;
|
||||
this.elements.set(internalName, global);
|
||||
|
||||
@ -949,19 +949,16 @@ export class Program extends DiagnosticEmitter {
|
||||
|
||||
// at this point we know exactly what the target is, so look up the element within
|
||||
var propertyName = propertyAccess.property.name;
|
||||
var targetType: Type | null;
|
||||
var targetType: Type;
|
||||
switch (target.kind) {
|
||||
|
||||
case ElementKind.GLOBAL:
|
||||
case ElementKind.LOCAL:
|
||||
targetType = (<VariableLikeElement>target).type;
|
||||
assert(targetType != null); // FIXME: this is a problem because auto-globals might not be
|
||||
// resolved (and should not be attempted to be resolved) here
|
||||
if ((<Type>targetType).classType)
|
||||
target = <Class>(<Type>targetType).classType;
|
||||
// fall-through
|
||||
else
|
||||
case ElementKind.FIELD:
|
||||
if (!(targetType = (<VariableLikeElement>target).type).classType)
|
||||
break;
|
||||
target = <Class>targetType.classType;
|
||||
// fall-through
|
||||
|
||||
default:
|
||||
if (target.members) {
|
||||
@ -1265,8 +1262,8 @@ export class VariableLikeElement extends Element {
|
||||
|
||||
/** Declaration reference. */
|
||||
declaration: VariableLikeDeclarationStatement | null;
|
||||
/** Resolved type, if resolved. */
|
||||
type: Type | null;
|
||||
/** Variable type. Is {@link Type.void} for type-inferred {@link Global}s before compilation. */
|
||||
type: Type;
|
||||
/** Constant integer value, if applicable. */
|
||||
constantIntegerValue: I64 | null = null;
|
||||
/** Constant float value, if applicable. */
|
||||
@ -1292,7 +1289,7 @@ export class Global extends VariableLikeElement {
|
||||
|
||||
kind = ElementKind.GLOBAL;
|
||||
|
||||
constructor(program: Program, simpleName: string, internalName: string, declaration: VariableLikeDeclarationStatement | null = null, type: Type | null = null) {
|
||||
constructor(program: Program, simpleName: string, internalName: string, declaration: VariableLikeDeclarationStatement | null = null, type: Type) {
|
||||
super(program, simpleName, internalName);
|
||||
if (this.declaration = declaration) {
|
||||
if (this.declaration.modifiers) {
|
||||
@ -1310,7 +1307,7 @@ export class Global extends VariableLikeElement {
|
||||
} else {
|
||||
this.hasConstantValue = true; // built-ins have constant values
|
||||
}
|
||||
this.type = type; // resolved later if `null`
|
||||
this.type = type; // resolved later if `void`
|
||||
}
|
||||
}
|
||||
|
||||
@ -1339,7 +1336,6 @@ export class Local extends VariableLikeElement {
|
||||
|
||||
kind = ElementKind.LOCAL;
|
||||
|
||||
type: Type; // more specific
|
||||
/** Local index. */
|
||||
index: i32;
|
||||
|
||||
@ -1679,12 +1675,10 @@ export class Function extends Element {
|
||||
}
|
||||
|
||||
/** A yet unresolved instance field prototype. */
|
||||
export class FieldPrototype extends Element {
|
||||
export class FieldPrototype extends VariableLikeElement {
|
||||
|
||||
kind = ElementKind.FIELD_PROTOTYPE;
|
||||
|
||||
/** Declaration reference. */
|
||||
declaration: FieldDeclaration | null;
|
||||
/** Parent class prototype. */
|
||||
classPrototype: ClassPrototype;
|
||||
|
||||
@ -1710,12 +1704,6 @@ export class FieldPrototype extends Element {
|
||||
/** Whether the field is read-only or not. */
|
||||
get isReadonly(): bool { return (this.flags & ElementFlags.READONLY) != 0; }
|
||||
set isReadonly(is: bool) { if (is) this.flags |= ElementFlags.READONLY; else this.flags &= ~ElementFlags.READONLY; }
|
||||
|
||||
// resolve(contextualTypeArguments: Map<string,Type> | null = null): Field {
|
||||
// if (!this.declaration)
|
||||
// throw new Error("declaration expected");
|
||||
// this.declaration.type
|
||||
// }
|
||||
}
|
||||
|
||||
/** A resolved instance field. */
|
||||
@ -1871,7 +1859,7 @@ export class ClassPrototype extends Element {
|
||||
var fieldType = this.program.resolveType(fieldDeclaration.type, instance.contextualTypeArguments); // reports
|
||||
if (fieldType) {
|
||||
var fieldInstance = new Field(<FieldPrototype>member, (<FieldPrototype>member).internalName, fieldType);
|
||||
switch (fieldType.byteSize) { // align
|
||||
switch (fieldType.size >> 3) { // align (byteSize might vary if a class type)
|
||||
case 1: break;
|
||||
case 2: if (memoryOffset & 1) ++memoryOffset; break;
|
||||
case 4: if (memoryOffset & 3) memoryOffset = (memoryOffset | 3) + 1; break;
|
||||
|
@ -1,7 +1,7 @@
|
||||
(module
|
||||
(type $v (func))
|
||||
(global $binary/i (mut i32) (i32.const 0))
|
||||
(global $binary/b (mut i32) (i32.const 0))
|
||||
(global $binary/i (mut i32) (i32.const 0))
|
||||
(global $binary/I (mut i64) (i64.const 0))
|
||||
(global $binary/f (mut f32) (f32.const 0))
|
||||
(global $binary/F (mut f64) (f64.const 0))
|
||||
|
@ -1,7 +1,7 @@
|
||||
(module
|
||||
(type $v (func))
|
||||
(global $binary/i (mut i32) (i32.const 0))
|
||||
(global $binary/b (mut i32) (i32.const 0))
|
||||
(global $binary/i (mut i32) (i32.const 0))
|
||||
(global $binary/I (mut i64) (i64.const 0))
|
||||
(global $binary/f (mut f32) (f32.const 0))
|
||||
(global $binary/F (mut f64) (f64.const 0))
|
||||
|
@ -1,9 +1,9 @@
|
||||
(module
|
||||
(type $v (func))
|
||||
(global $builtins/b (mut i32) (i32.const 0))
|
||||
(global $builtins/i (mut i32) (i32.const 0))
|
||||
(global $builtins/I (mut i64) (i64.const 0))
|
||||
(global $builtins/f (mut f32) (f32.const 0))
|
||||
(global $builtins/b (mut i32) (i32.const 0))
|
||||
(global $builtins/F (mut f64) (f64.const 0))
|
||||
(global $builtins/s (mut i32) (i32.const 0))
|
||||
(memory $0 1)
|
||||
|
@ -1,9 +1,9 @@
|
||||
(module
|
||||
(type $v (func))
|
||||
(global $builtins/b (mut i32) (i32.const 0))
|
||||
(global $builtins/i (mut i32) (i32.const 0))
|
||||
(global $builtins/I (mut i64) (i64.const 0))
|
||||
(global $builtins/f (mut f32) (f32.const 0))
|
||||
(global $builtins/b (mut i32) (i32.const 0))
|
||||
(global $builtins/F (mut f64) (f64.const 0))
|
||||
(global $builtins/s (mut i32) (i32.const 0))
|
||||
(global $i8.MIN_VALUE i32 (i32.const -128))
|
||||
|
@ -1,7 +1,7 @@
|
||||
(module
|
||||
(type $v (func))
|
||||
(import "env" "externalFunc" (func $declare/externalFunc))
|
||||
(import "env" "externalConst" (global $declare/externalConst i32))
|
||||
(import "env" "externalFunc" (func $declare/externalFunc))
|
||||
(import "external" "externalFunc" (func $declare/external.externalFunc))
|
||||
(import "external" "externalConst" (global $declare/external.externalConst i32))
|
||||
(global $HEAP_BASE i32 (i32.const 4))
|
||||
|
@ -2,8 +2,8 @@
|
||||
(type $i (func (result i32)))
|
||||
(type $iiv (func (param i32 i32)))
|
||||
(type $iiiiv (func (param i32 i32 i32 i32)))
|
||||
(global $../../examples/i64-polyfill/assembly/i64/hi (mut i32) (i32.const 0))
|
||||
(global $../../examples/i64-polyfill/assembly/i64/lo (mut i32) (i32.const 0))
|
||||
(global $../../examples/i64-polyfill/assembly/i64/hi (mut i32) (i32.const 0))
|
||||
(memory $0 1)
|
||||
(export "getHi" (func $../../examples/i64-polyfill/assembly/i64/getHi))
|
||||
(export "getLo" (func $../../examples/i64-polyfill/assembly/i64/getLo))
|
||||
|
@ -2,8 +2,8 @@
|
||||
(type $i (func (result i32)))
|
||||
(type $iiv (func (param i32 i32)))
|
||||
(type $iiiiv (func (param i32 i32 i32 i32)))
|
||||
(global $../../examples/i64-polyfill/assembly/i64/hi (mut i32) (i32.const 0))
|
||||
(global $../../examples/i64-polyfill/assembly/i64/lo (mut i32) (i32.const 0))
|
||||
(global $../../examples/i64-polyfill/assembly/i64/hi (mut i32) (i32.const 0))
|
||||
(global $HEAP_BASE i32 (i32.const 4))
|
||||
(memory $0 1)
|
||||
(export "getHi" (func $../../examples/i64-polyfill/assembly/i64/getHi))
|
||||
|
@ -1,8 +1,8 @@
|
||||
(module
|
||||
(type $iii (func (param i32 i32) (result i32)))
|
||||
(type $v (func))
|
||||
(global $export/b i32 (i32.const 2))
|
||||
(global $export/a i32 (i32.const 1))
|
||||
(global $export/b i32 (i32.const 2))
|
||||
(global $HEAP_BASE i32 (i32.const 4))
|
||||
(memory $0 1)
|
||||
(export "memory" (memory $0))
|
||||
|
@ -1,8 +1,8 @@
|
||||
(module
|
||||
(type $iii (func (param i32 i32) (result i32)))
|
||||
(type $v (func))
|
||||
(global $export/b i32 (i32.const 2))
|
||||
(global $export/a i32 (i32.const 1))
|
||||
(global $export/b i32 (i32.const 2))
|
||||
(memory $0 1)
|
||||
(export "add" (func $export/add))
|
||||
(export "renamed_sub" (func $export/sub))
|
||||
|
@ -1,8 +1,8 @@
|
||||
(module
|
||||
(type $iii (func (param i32 i32) (result i32)))
|
||||
(type $v (func))
|
||||
(global $export/b i32 (i32.const 2))
|
||||
(global $export/a i32 (i32.const 1))
|
||||
(global $export/b i32 (i32.const 2))
|
||||
(global $HEAP_BASE i32 (i32.const 4))
|
||||
(memory $0 1)
|
||||
(export "add" (func $export/add))
|
||||
|
@ -8,19 +8,27 @@
|
||||
(type $v (func))
|
||||
(global $tlsf/ALIGN_SIZE_LOG2 i32 (i32.const 3))
|
||||
(global $tlsf/ALIGN_SIZE i32 (i32.const 8))
|
||||
(global $tlsf/SL_INDEX_COUNT_LOG2 i32 (i32.const 5))
|
||||
(global $tlsf/FL_INDEX_MAX i32 (i32.const 30))
|
||||
(global $tlsf/SL_INDEX_COUNT i32 (i32.const 32))
|
||||
(global $tlsf/FL_INDEX_SHIFT i32 (i32.const 8))
|
||||
(global $tlsf/FL_INDEX_COUNT i32 (i32.const 23))
|
||||
(global $tlsf/SMALL_BLOCK_SIZE i32 (i32.const 256))
|
||||
(global $tlsf/BLOCK$PREV_PHYS_BLOCK_OFFSET i32 (i32.const 0))
|
||||
(global $tlsf/BLOCK$TAGGED_SIZE_OFFSET i32 (i32.const 4))
|
||||
(global $tlsf/BLOCK$NEXT_FREE_OFFSET i32 (i32.const 8))
|
||||
(global $tlsf/BLOCK$PREV_FREE_OFFSET i32 (i32.const 12))
|
||||
(global $tlsf/BLOCK$SIZE i32 (i32.const 16))
|
||||
(global $tlsf/BLOCK_HEADER_FREE_BIT i32 (i32.const 1))
|
||||
(global $tlsf/BLOCK_HEADER_PREV_FREE_BIT i32 (i32.const 2))
|
||||
(global $tlsf/BLOCK_OVERHEAD i32 (i32.const 4))
|
||||
(global $tlsf/BLOCK_START_OFFSET i32 (i32.const 8))
|
||||
(global $tlsf/BLOCK_SIZE_MIN i32 (i32.const 12))
|
||||
(global $tlsf/BLOCK_SIZE_MAX i32 (i32.const 1073741824))
|
||||
(global $tlsf/CONTROL$FL_BITMAP_OFFSET i32 (i32.const 16))
|
||||
(global $tlsf/FL_INDEX_MAX i32 (i32.const 30))
|
||||
(global $tlsf/SL_INDEX_COUNT_LOG2 i32 (i32.const 5))
|
||||
(global $tlsf/FL_INDEX_SHIFT i32 (i32.const 8))
|
||||
(global $tlsf/FL_INDEX_COUNT i32 (i32.const 23))
|
||||
(global $tlsf/CONTROL$SL_BITMAP_OFFSET i32 (i32.const 20))
|
||||
(global $tlsf/SL_INDEX_COUNT i32 (i32.const 32))
|
||||
(global $tlsf/CONTROL$BLOCKS_OFFSET i32 (i32.const 112))
|
||||
(global $tlsf/CONTROL$SIZE i32 (i32.const 3056))
|
||||
(global $HEAP_BASE i32 (i32.const 4))
|
||||
(memory $0 1)
|
||||
(export "control$construct" (func $tlsf/control$construct))
|
||||
|
Loading…
x
Reference in New Issue
Block a user