Implement calls to 'super()' (#445)

This commit is contained in:
Daniel Wirtz 2019-01-31 10:35:49 +01:00 committed by GitHub
parent 65c4acd2d4
commit 75328f3feb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 832 additions and 14 deletions

View File

@ -120,7 +120,8 @@ export function nodeIsCallable(kind: NodeKind): bool {
case NodeKind.CALL:
case NodeKind.ELEMENTACCESS:
case NodeKind.PARENTHESIZED:
case NodeKind.PROPERTYACCESS: return true;
case NodeKind.PROPERTYACCESS:
case NodeKind.SUPER: return true;
}
return false;
}

View File

@ -1095,6 +1095,8 @@ export class Compiler extends DiagnosticEmitter {
if (isConstructor) {
let nativeSizeType = this.options.nativeSizeType;
assert(instance.is(CommonFlags.INSTANCE));
let parent = assert(instance.parent);
assert(parent.kind == ElementKind.CLASS);
// implicitly return `this` if the constructor doesn't always return on its own
if (!flow.is(FlowFlags.RETURNS)) {
@ -1105,14 +1107,20 @@ export class Compiler extends DiagnosticEmitter {
// if not all branches are guaranteed to allocate, also append a conditional allocation
} else {
let parent = assert(instance.parent);
assert(parent.kind == ElementKind.CLASS);
stmts.push(module.createTeeLocal(0,
this.makeConditionalAllocate(<Class>parent, declaration.name)
));
}
}
// check that super has been called if this is a derived class
if ((<Class>parent).base && !flow.is(FlowFlags.CALLS_SUPER)) {
this.error(
DiagnosticCode.Constructors_for_derived_classes_must_contain_a_super_call,
instance.prototype.declaration.range
);
}
// make sure all branches return
} else if (returnType != Type.void && !flow.is(FlowFlags.RETURNS)) {
this.error(
@ -5230,6 +5238,43 @@ export class Compiler extends DiagnosticEmitter {
break;
}
case ElementKind.CLASS: {
// call to `super()`
if (expression.expression.kind == NodeKind.SUPER) {
if (!currentFunction.is(CommonFlags.CONSTRUCTOR)) {
this.error(
DiagnosticCode.Super_calls_are_not_permitted_outside_constructors_or_in_nested_functions_inside_constructors,
expression.range
);
return module.createUnreachable();
}
let classInstance = assert(currentFunction.parent);
assert(classInstance.kind == ElementKind.CLASS);
let expr = this.compileSuperInstantiate(<Class>classInstance, expression.arguments, expression);
this.currentType = Type.void;
// check that super() is called before allocation is performed (incl. in super arguments)
let flow = currentFunction.flow;
if (flow.isAny(
FlowFlags.ALLOCATES |
FlowFlags.CONDITIONALLY_ALLOCATES
)) {
this.error(
DiagnosticCode._super_must_be_called_before_accessing_this_in_the_constructor_of_a_derived_class,
expression.range
);
return module.createUnreachable();
}
flow.set(FlowFlags.ALLOCATES | FlowFlags.CALLS_SUPER);
let thisLocal = assert(this.currentFunction.flow.getScopedLocal("this"));
return module.createSetLocal(thisLocal.index, expr);
}
// otherwise fall-through
}
// not supported
default: {
this.error(
@ -6027,6 +6072,15 @@ export class Compiler extends DiagnosticEmitter {
return module.createUnreachable();
}
case NodeKind.SUPER: {
if (currentFunction.is(CommonFlags.CONSTRUCTOR)) {
if (!currentFunction.flow.is(FlowFlags.CALLS_SUPER)) {
// TS1034 in the parser effectively limits this to property accesses
this.error(
DiagnosticCode._super_must_be_called_before_accessing_a_property_of_super_in_the_constructor_of_a_derived_class,
expression.range
);
}
}
let flow = currentFunction.flow;
if (flow.is(FlowFlags.INLINE_CONTEXT)) {
let scopedThis = flow.getScopedLocal("this");
@ -6658,6 +6712,37 @@ export class Compiler extends DiagnosticEmitter {
return expr;
}
compileSuperInstantiate(classInstance: Class, argumentExpressions: Expression[], reportNode: Node): ExpressionRef {
// traverse to the top-most visible constructor (except the current one)
var currentClassInstance: Class | null = classInstance.base;
var constructorInstance: Function | null = null;
while (currentClassInstance) {
constructorInstance = currentClassInstance.constructorInstance;
if (constructorInstance) break; // TODO: check visibility
currentClassInstance = currentClassInstance.base;
}
// if a constructor is present, allocate the necessary memory for `this` and call it
var expr: ExpressionRef;
if (constructorInstance) {
expr = this.compileCallDirect(constructorInstance, argumentExpressions, reportNode,
this.makeAllocate(classInstance, reportNode)
);
// otherwise simply allocate a new instance and initialize its fields
} else {
if (argumentExpressions.length) {
this.error(
DiagnosticCode.Expected_0_arguments_but_got_1,
reportNode.range, "0", argumentExpressions.length.toString(10)
);
}
expr = this.makeAllocate(classInstance, reportNode);
}
this.currentType = classInstance.type;
return expr;
}
compileParenthesizedExpression(
expression: ParenthesizedExpression,
contextualType: Type

View File

@ -66,6 +66,7 @@ export enum DiagnosticCode {
Unexpected_end_of_text = 1126,
Invalid_character = 1127,
_case_or_default_expected = 1130,
_super_must_be_followed_by_an_argument_list_or_member_access = 1034,
A_declare_modifier_cannot_be_used_in_an_already_ambient_context = 1038,
Type_argument_expected = 1140,
String_literal_expected = 1141,
@ -94,6 +95,7 @@ export enum DiagnosticCode {
Index_signature_is_missing_in_type_0 = 2329,
_this_cannot_be_referenced_in_current_location = 2332,
_super_can_only_be_referenced_in_a_derived_class = 2335,
Super_calls_are_not_permitted_outside_constructors_or_in_nested_functions_inside_constructors = 2337,
Property_0_does_not_exist_on_type_1 = 2339,
Cannot_invoke_an_expression_whose_type_lacks_a_call_signature_Type_0_has_no_compatible_call_signatures = 2349,
Cannot_use_new_with_an_expression_whose_type_lacks_a_construct_signature = 2351,
@ -101,6 +103,8 @@ export enum DiagnosticCode {
The_operand_of_an_increment_or_decrement_operator_must_be_a_variable_or_a_property_access = 2357,
The_left_hand_side_of_an_assignment_expression_must_be_a_variable_or_a_property_access = 2364,
Operator_0_cannot_be_applied_to_types_1_and_2 = 2365,
A_super_call_must_be_the_first_statement_in_the_constructor = 2376,
Constructors_for_derived_classes_must_contain_a_super_call = 2377,
_get_and_set_accessor_must_have_the_same_type = 2380,
Constructor_implementation_is_missing = 2390,
Function_implementation_is_missing_or_not_immediately_following_the_declaration = 2391,
@ -124,7 +128,9 @@ export enum DiagnosticCode {
Required_type_parameters_may_not_follow_optional_type_parameters = 2706,
File_0_not_found = 6054,
Numeric_separators_are_not_allowed_here = 6188,
Multiple_consecutive_numeric_separators_are_not_permitted = 6189
Multiple_consecutive_numeric_separators_are_not_permitted = 6189,
_super_must_be_called_before_accessing_this_in_the_constructor_of_a_derived_class = 17009,
_super_must_be_called_before_accessing_a_property_of_super_in_the_constructor_of_a_derived_class = 17011
}
/** Translates a diagnostic code to its respective string. */
@ -189,6 +195,7 @@ export function diagnosticCodeToString(code: DiagnosticCode): string {
case 1126: return "Unexpected end of text.";
case 1127: return "Invalid character.";
case 1130: return "'case' or 'default' expected.";
case 1034: return "'super' must be followed by an argument list or member access.";
case 1038: return "A 'declare' modifier cannot be used in an already ambient context.";
case 1140: return "Type argument expected.";
case 1141: return "String literal expected.";
@ -217,6 +224,7 @@ export function diagnosticCodeToString(code: DiagnosticCode): string {
case 2329: return "Index signature is missing in type '{0}'.";
case 2332: return "'this' cannot be referenced in current location.";
case 2335: return "'super' can only be referenced in a derived class.";
case 2337: return "Super calls are not permitted outside constructors or in nested functions inside constructors.";
case 2339: return "Property '{0}' does not exist on type '{1}'.";
case 2349: return "Cannot invoke an expression whose type lacks a call signature. Type '{0}' has no compatible call signatures.";
case 2351: return "Cannot use 'new' with an expression whose type lacks a construct signature.";
@ -224,6 +232,8 @@ export function diagnosticCodeToString(code: DiagnosticCode): string {
case 2357: return "The operand of an increment or decrement operator must be a variable or a property access.";
case 2364: return "The left-hand side of an assignment expression must be a variable or a property access.";
case 2365: return "Operator '{0}' cannot be applied to types '{1}' and '{2}'.";
case 2376: return "A 'super' call must be the first statement in the constructor.";
case 2377: return "Constructors for derived classes must contain a 'super' call.";
case 2380: return "'get' and 'set' accessor must have the same type.";
case 2390: return "Constructor implementation is missing.";
case 2391: return "Function implementation is missing or not immediately following the declaration.";
@ -248,6 +258,8 @@ export function diagnosticCodeToString(code: DiagnosticCode): string {
case 6054: return "File '{0}' not found.";
case 6188: return "Numeric separators are not allowed here.";
case 6189: return "Multiple consecutive numeric separators are not permitted.";
case 17009: return "'super' must be called before accessing 'this' in the constructor of a derived class.";
case 17011: return "'super' must be called before accessing a property of 'super' in the constructor of a derived class.";
default: return "";
}
}

View File

@ -59,6 +59,7 @@
"Unexpected end of text.": 1126,
"Invalid character.": 1127,
"'case' or 'default' expected.": 1130,
"'super' must be followed by an argument list or member access.": 1034,
"A 'declare' modifier cannot be used in an already ambient context.": 1038,
"Type argument expected.": 1140,
"String literal expected.": 1141,
@ -88,6 +89,7 @@
"Index signature is missing in type '{0}'.": 2329,
"'this' cannot be referenced in current location.": 2332,
"'super' can only be referenced in a derived class.": 2335,
"Super calls are not permitted outside constructors or in nested functions inside constructors.": 2337,
"Property '{0}' does not exist on type '{1}'.": 2339,
"Cannot invoke an expression whose type lacks a call signature. Type '{0}' has no compatible call signatures.": 2349,
"Cannot use 'new' with an expression whose type lacks a construct signature.": 2351,
@ -95,6 +97,8 @@
"The operand of an increment or decrement operator must be a variable or a property access.": 2357,
"The left-hand side of an assignment expression must be a variable or a property access.": 2364,
"Operator '{0}' cannot be applied to types '{1}' and '{2}'.": 2365,
"A 'super' call must be the first statement in the constructor.": 2376,
"Constructors for derived classes must contain a 'super' call.": 2377,
"'get' and 'set' accessor must have the same type.": 2380,
"Constructor implementation is missing.": 2390,
"Function implementation is missing or not immediately following the declaration.": 2391,
@ -119,5 +123,7 @@
"File '{0}' not found.": 6054,
"Numeric separators are not allowed here.": 6188,
"Multiple consecutive numeric separators are not permitted.": 6189
"Multiple consecutive numeric separators are not permitted.": 6189,
"'super' must be called before accessing 'this' in the constructor of a derived class.": 17009,
"'super' must be called before accessing a property of 'super' in the constructor of a derived class.": 17011
}

View File

@ -3337,6 +3337,12 @@ export class Parser extends DiagnosticEmitter {
return Node.createConstructorExpression(tn.range(startPos, tn.pos));
}
case Token.SUPER: {
if (tn.peek() != Token.DOT && tn.nextToken != Token.OPENPAREN) {
this.error(
DiagnosticCode._super_must_be_followed_by_an_argument_list_or_member_access,
tn.range()
);
}
return Node.createSuperExpression(tn.range(startPos, tn.pos));
}
case Token.STRINGLITERAL: {

View File

@ -3041,26 +3041,28 @@ export const enum FlowFlags {
CONTINUES = 1 << 4,
/** This branch always allocates. Constructors only. */
ALLOCATES = 1 << 5,
/** This branch always calls super. Constructors only. */
CALLS_SUPER = 1 << 6,
// conditional
/** This branch conditionally returns in a child branch. */
CONDITIONALLY_RETURNS = 1 << 6,
CONDITIONALLY_RETURNS = 1 << 7,
/** This branch conditionally throws in a child branch. */
CONDITIONALLY_THROWS = 1 << 7,
CONDITIONALLY_THROWS = 1 << 8,
/** This branch conditionally breaks in a child branch. */
CONDITIONALLY_BREAKS = 1 << 8,
CONDITIONALLY_BREAKS = 1 << 9,
/** This branch conditionally continues in a child branch. */
CONDITIONALLY_CONTINUES = 1 << 9,
CONDITIONALLY_CONTINUES = 1 << 10,
/** This branch conditionally allocates in a child branch. Constructors only. */
CONDITIONALLY_ALLOCATES = 1 << 10,
CONDITIONALLY_ALLOCATES = 1 << 11,
// special
/** This branch is part of inlining a function. */
INLINE_CONTEXT = 1 << 11,
INLINE_CONTEXT = 1 << 12,
/** This branch explicitly requests no bounds checking. */
UNCHECKED_CONTEXT = 1 << 12,
UNCHECKED_CONTEXT = 1 << 13,
// masks
@ -3076,7 +3078,8 @@ export const enum FlowFlags {
| FlowFlags.THROWS
| FlowFlags.BREAKS
| FlowFlags.CONTINUES
| FlowFlags.ALLOCATES,
| FlowFlags.ALLOCATES
| FlowFlags.CALLS_SUPER,
/** Any conditional flag. */
ANY_CONDITIONAL = FlowFlags.CONDITIONALLY_RETURNS

View File

@ -1242,8 +1242,16 @@ export class Resolver extends DiagnosticEmitter {
// Lay out fields in advance
case ElementKind.FIELD_PROTOTYPE: {
if (!instance.members) instance.members = new Map();
let fieldDeclaration = (<FieldPrototype>member).declaration;
if (!instance.members) instance.members = new Map();
else if (instance.members.has(member.simpleName)) {
this.error(
DiagnosticCode.Duplicate_identifier_0,
fieldDeclaration.name.range,
member.simpleName
);
break;
}
let fieldType: Type | null = null;
// TODO: handle duplicate non-private fields
if (!fieldDeclaration.type) {

View File

@ -0,0 +1,276 @@
(module
(type $v (func))
(type $ii (func (param i32) (result i32)))
(type $iiiiv (func (param i32 i32 i32 i32)))
(type $FUNCSIG$i (func (result i32)))
(import "env" "abort" (func $~lib/env/abort (param i32 i32 i32 i32)))
(memory $0 1)
(data (i32.const 8) "\0d\00\00\00c\00a\00l\00l\00-\00s\00u\00p\00e\00r\00.\00t\00s")
(table $0 1 anyfunc)
(elem (i32.const 0) $null)
(global $~lib/allocator/arena/startOffset (mut i32) (i32.const 0))
(global $~lib/allocator/arena/offset (mut i32) (i32.const 0))
(export "memory" (memory $0))
(export "table" (table $0))
(start $start)
(func $~lib/allocator/arena/__memory_allocate (; 1 ;) (type $ii) (param $0 i32) (result i32)
(local $1 i32)
(local $2 i32)
(local $3 i32)
get_local $0
i32.const 1073741824
i32.gt_u
if
unreachable
end
get_global $~lib/allocator/arena/offset
tee_local $1
get_local $0
i32.const 1
get_local $0
i32.const 1
i32.gt_u
select
i32.add
i32.const 7
i32.add
i32.const -8
i32.and
tee_local $2
current_memory
tee_local $3
i32.const 16
i32.shl
i32.gt_u
if
get_local $3
get_local $2
get_local $1
i32.sub
i32.const 65535
i32.add
i32.const -65536
i32.and
i32.const 16
i32.shr_u
tee_local $0
get_local $3
get_local $0
i32.gt_s
select
grow_memory
i32.const 0
i32.lt_s
if
get_local $0
grow_memory
i32.const 0
i32.lt_s
if
unreachable
end
end
end
get_local $2
set_global $~lib/allocator/arena/offset
get_local $1
)
(func $call-super/A#constructor (; 2 ;) (type $ii) (param $0 i32) (result i32)
get_local $0
i32.eqz
if
i32.const 4
call $~lib/allocator/arena/__memory_allocate
tee_local $0
i32.const 1
i32.store
end
get_local $0
i32.load
i32.const 1
i32.ne
if
i32.const 0
i32.const 8
i32.const 6
i32.const 4
call $~lib/env/abort
unreachable
end
get_local $0
)
(func $call-super/B#constructor (; 3 ;) (type $FUNCSIG$i) (result i32)
(local $0 i32)
i32.const 8
call $~lib/allocator/arena/__memory_allocate
tee_local $0
i32.const 1
i32.store
get_local $0
i32.const 2
i32.store offset=4
get_local $0
call $call-super/A#constructor
tee_local $0
i32.load
i32.const 1
i32.ne
if
i32.const 0
i32.const 8
i32.const 15
i32.const 4
call $~lib/env/abort
unreachable
end
get_local $0
i32.load offset=4
i32.const 2
i32.ne
if
i32.const 0
i32.const 8
i32.const 16
i32.const 4
call $~lib/env/abort
unreachable
end
get_local $0
)
(func $call-super/test1 (; 4 ;) (type $v)
(local $0 i32)
call $call-super/B#constructor
tee_local $0
i32.load
i32.const 1
i32.ne
if
i32.const 0
i32.const 8
i32.const 22
i32.const 2
call $~lib/env/abort
unreachable
end
get_local $0
i32.load offset=4
i32.const 2
i32.ne
if
i32.const 0
i32.const 8
i32.const 23
i32.const 2
call $~lib/env/abort
unreachable
end
)
(func $call-super/D#constructor (; 5 ;) (type $FUNCSIG$i) (result i32)
(local $0 i32)
i32.const 8
call $~lib/allocator/arena/__memory_allocate
tee_local $0
i32.const 1
i32.store
get_local $0
i32.const 2
i32.store offset=4
get_local $0
i32.load
i32.const 1
i32.ne
if
i32.const 0
i32.const 8
i32.const 36
i32.const 4
call $~lib/env/abort
unreachable
end
get_local $0
i32.load offset=4
i32.const 2
i32.ne
if
i32.const 0
i32.const 8
i32.const 37
i32.const 4
call $~lib/env/abort
unreachable
end
get_local $0
)
(func $call-super/test2 (; 6 ;) (type $v)
(local $0 i32)
call $call-super/D#constructor
tee_local $0
i32.load
i32.const 1
i32.ne
if
i32.const 0
i32.const 8
i32.const 43
i32.const 2
call $~lib/env/abort
unreachable
end
get_local $0
i32.load offset=4
i32.const 2
i32.ne
if
i32.const 0
i32.const 8
i32.const 44
i32.const 2
call $~lib/env/abort
unreachable
end
)
(func $call-super/E#constructor (; 7 ;) (type $FUNCSIG$i) (result i32)
(local $0 i32)
i32.const 4
call $~lib/allocator/arena/__memory_allocate
tee_local $0
i32.const 1
i32.store
get_local $0
i32.load
i32.const 1
i32.ne
if
i32.const 0
i32.const 8
i32.const 52
i32.const 4
call $~lib/env/abort
unreachable
end
get_local $0
)
(func $start (; 8 ;) (type $v)
i32.const 40
set_global $~lib/allocator/arena/startOffset
get_global $~lib/allocator/arena/startOffset
set_global $~lib/allocator/arena/offset
call $call-super/test1
call $call-super/test2
call $call-super/E#constructor
i32.load
i32.const 1
i32.ne
if
i32.const 0
i32.const 8
i32.const 62
i32.const 2
call $~lib/env/abort
unreachable
end
)
(func $null (; 9 ;) (type $v)
nop
)
)

View File

@ -0,0 +1,66 @@
import "allocator/arena";
class A {
a: i32 = 1;
constructor() {
assert(this.a == 1);
}
}
class B extends A {
// a: i32 = 3; // FIXME: currently duplicate identifier
b: i32 = 2;
constructor() {
super();
assert(this.a == 1);
assert(this.b == 2);
}
}
function test1(): void {
var b = new B();
assert(b.a == 1);
assert(b.b == 2);
}
test1();
class C {
a: i32 = 1;
}
class D extends C {
b: i32 = 2;
constructor() {
super();
assert(this.a == 1);
assert(this.b == 2);
}
}
function test2(): void {
var d = new D();
assert(d.a == 1);
assert(d.b == 2);
}
test2();
class E {
a: i32 = 1;
constructor() {
assert(this.a == 1);
}
}
class F extends E {
b: i32 = 2;
}
function test3(): void {
var f = new F();
assert(f.a == 1);
// assert(f.b == 2); // FIXME: uses E#constructor, not initializing fields
}
test3();

View File

@ -0,0 +1,355 @@
(module
(type $v (func))
(type $ii (func (param i32) (result i32)))
(type $iiiiv (func (param i32 i32 i32 i32)))
(import "env" "abort" (func $~lib/env/abort (param i32 i32 i32 i32)))
(memory $0 1)
(data (i32.const 8) "\0d\00\00\00c\00a\00l\00l\00-\00s\00u\00p\00e\00r\00.\00t\00s\00")
(table $0 1 anyfunc)
(elem (i32.const 0) $null)
(global $~lib/internal/allocator/AL_BITS i32 (i32.const 3))
(global $~lib/internal/allocator/AL_SIZE i32 (i32.const 8))
(global $~lib/internal/allocator/AL_MASK i32 (i32.const 7))
(global $~lib/internal/allocator/MAX_SIZE_32 i32 (i32.const 1073741824))
(global $~lib/allocator/arena/startOffset (mut i32) (i32.const 0))
(global $~lib/allocator/arena/offset (mut i32) (i32.const 0))
(global $HEAP_BASE i32 (i32.const 40))
(export "memory" (memory $0))
(export "table" (table $0))
(start $start)
(func $~lib/allocator/arena/__memory_allocate (; 1 ;) (type $ii) (param $0 i32) (result i32)
(local $1 i32)
(local $2 i32)
(local $3 i32)
(local $4 i32)
(local $5 i32)
(local $6 i32)
get_local $0
get_global $~lib/internal/allocator/MAX_SIZE_32
i32.gt_u
if
unreachable
end
get_global $~lib/allocator/arena/offset
set_local $1
get_local $1
get_local $0
tee_local $2
i32.const 1
tee_local $3
get_local $2
get_local $3
i32.gt_u
select
i32.add
get_global $~lib/internal/allocator/AL_MASK
i32.add
get_global $~lib/internal/allocator/AL_MASK
i32.const -1
i32.xor
i32.and
set_local $4
current_memory
set_local $5
get_local $4
get_local $5
i32.const 16
i32.shl
i32.gt_u
if
get_local $4
get_local $1
i32.sub
i32.const 65535
i32.add
i32.const 65535
i32.const -1
i32.xor
i32.and
i32.const 16
i32.shr_u
set_local $2
get_local $5
tee_local $3
get_local $2
tee_local $6
get_local $3
get_local $6
i32.gt_s
select
set_local $3
get_local $3
grow_memory
i32.const 0
i32.lt_s
if
get_local $2
grow_memory
i32.const 0
i32.lt_s
if
unreachable
end
end
end
get_local $4
set_global $~lib/allocator/arena/offset
get_local $1
)
(func $~lib/memory/memory.allocate (; 2 ;) (type $ii) (param $0 i32) (result i32)
get_local $0
call $~lib/allocator/arena/__memory_allocate
return
)
(func $call-super/A#constructor (; 3 ;) (type $ii) (param $0 i32) (result i32)
(local $1 i32)
get_local $0
if (result i32)
get_local $0
else
block (result i32)
i32.const 4
call $~lib/memory/memory.allocate
set_local $1
get_local $1
i32.const 1
i32.store
get_local $1
end
tee_local $0
end
tee_local $0
i32.load
i32.const 1
i32.eq
i32.eqz
if
i32.const 0
i32.const 8
i32.const 6
i32.const 4
call $~lib/env/abort
unreachable
end
get_local $0
)
(func $call-super/B#constructor (; 4 ;) (type $ii) (param $0 i32) (result i32)
(local $1 i32)
block (result i32)
i32.const 8
call $~lib/memory/memory.allocate
set_local $1
get_local $1
i32.const 1
i32.store
get_local $1
i32.const 2
i32.store offset=4
get_local $1
end
call $call-super/A#constructor
set_local $0
get_local $0
i32.load
i32.const 1
i32.eq
i32.eqz
if
i32.const 0
i32.const 8
i32.const 15
i32.const 4
call $~lib/env/abort
unreachable
end
get_local $0
i32.load offset=4
i32.const 2
i32.eq
i32.eqz
if
i32.const 0
i32.const 8
i32.const 16
i32.const 4
call $~lib/env/abort
unreachable
end
get_local $0
)
(func $call-super/test1 (; 5 ;) (type $v)
(local $0 i32)
i32.const 0
call $call-super/B#constructor
set_local $0
get_local $0
i32.load
i32.const 1
i32.eq
i32.eqz
if
i32.const 0
i32.const 8
i32.const 22
i32.const 2
call $~lib/env/abort
unreachable
end
get_local $0
i32.load offset=4
i32.const 2
i32.eq
i32.eqz
if
i32.const 0
i32.const 8
i32.const 23
i32.const 2
call $~lib/env/abort
unreachable
end
)
(func $call-super/D#constructor (; 6 ;) (type $ii) (param $0 i32) (result i32)
(local $1 i32)
block (result i32)
i32.const 8
call $~lib/memory/memory.allocate
set_local $1
get_local $1
i32.const 1
i32.store
get_local $1
i32.const 2
i32.store offset=4
get_local $1
end
set_local $0
get_local $0
i32.load
i32.const 1
i32.eq
i32.eqz
if
i32.const 0
i32.const 8
i32.const 36
i32.const 4
call $~lib/env/abort
unreachable
end
get_local $0
i32.load offset=4
i32.const 2
i32.eq
i32.eqz
if
i32.const 0
i32.const 8
i32.const 37
i32.const 4
call $~lib/env/abort
unreachable
end
get_local $0
)
(func $call-super/test2 (; 7 ;) (type $v)
(local $0 i32)
i32.const 0
call $call-super/D#constructor
set_local $0
get_local $0
i32.load
i32.const 1
i32.eq
i32.eqz
if
i32.const 0
i32.const 8
i32.const 43
i32.const 2
call $~lib/env/abort
unreachable
end
get_local $0
i32.load offset=4
i32.const 2
i32.eq
i32.eqz
if
i32.const 0
i32.const 8
i32.const 44
i32.const 2
call $~lib/env/abort
unreachable
end
)
(func $call-super/E#constructor (; 8 ;) (type $ii) (param $0 i32) (result i32)
(local $1 i32)
get_local $0
if (result i32)
get_local $0
else
block (result i32)
i32.const 4
call $~lib/memory/memory.allocate
set_local $1
get_local $1
i32.const 1
i32.store
get_local $1
end
tee_local $0
end
tee_local $0
i32.load
i32.const 1
i32.eq
i32.eqz
if
i32.const 0
i32.const 8
i32.const 52
i32.const 4
call $~lib/env/abort
unreachable
end
get_local $0
)
(func $call-super/test3 (; 9 ;) (type $v)
(local $0 i32)
i32.const 0
call $call-super/E#constructor
set_local $0
get_local $0
i32.load
i32.const 1
i32.eq
i32.eqz
if
i32.const 0
i32.const 8
i32.const 62
i32.const 2
call $~lib/env/abort
unreachable
end
)
(func $start (; 10 ;) (type $v)
get_global $HEAP_BASE
get_global $~lib/internal/allocator/AL_MASK
i32.add
get_global $~lib/internal/allocator/AL_MASK
i32.const -1
i32.xor
i32.and
set_global $~lib/allocator/arena/startOffset
get_global $~lib/allocator/arena/startOffset
set_global $~lib/allocator/arena/offset
call $call-super/test1
call $call-super/test2
call $call-super/test3
)
(func $null (; 11 ;) (type $v)
)
)