[modular_aot] Closures, part 2
Issue: https://github.com/dart-lang/sdk/issues/61635 Change-Id: Id8029dddd75b5f771ddf8197190d18aea9efd192 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/503080 Commit-Queue: Alexander Markov <alexmarkov@google.com> Reviewed-by: Slava Egorov <vegorov@google.com>
This commit is contained in:
committed by
dart-scoped@luci-project-accounts.iam.gserviceaccount.com
parent
433ee9bb92
commit
e09282c8f2
@@ -56,6 +56,7 @@ class AstToIr extends ast.RecursiveVisitor {
|
||||
function.member,
|
||||
GlobalContext.instance.typeEnvironment,
|
||||
);
|
||||
late final ClosureLayout _currentClosureLayout;
|
||||
|
||||
Map<ast.LabeledStatement, JoinBlock>? labeledStatements;
|
||||
Map<ast.SwitchCase, JoinBlock>? switchCases;
|
||||
@@ -85,6 +86,10 @@ class AstToIr extends ast.RecursiveVisitor {
|
||||
scopes,
|
||||
function,
|
||||
);
|
||||
final f = function;
|
||||
if (f is ClosureFunction) {
|
||||
_currentClosureLayout = _computeClosureLayout(f);
|
||||
}
|
||||
}
|
||||
|
||||
/// Create [FlowGraph] for the body of the [function].
|
||||
@@ -151,13 +156,34 @@ class AstToIr extends ast.RecursiveVisitor {
|
||||
if (function.hasClassTypeParameters) {
|
||||
if (function.hasReceiverParameter) {
|
||||
builder.addLoadLocal(localVarIndexer.receiver);
|
||||
} else {
|
||||
assert(_isCaptured(localVarIndexer.receiverDeclaration!));
|
||||
throw 'Unimplemented _buildPrologue for class type parameters with captured receiver';
|
||||
classTypeParameters = builder.addTypeParameters(
|
||||
.classTypeParameters,
|
||||
);
|
||||
} else if (_isCaptured(localVarIndexer.receiverDeclaration!)) {
|
||||
// Read captured receiver. Load context from closure
|
||||
// as contexts are not defined yet.
|
||||
final variable = localVarIndexer.receiverDeclaration!;
|
||||
builder.addLoadLocal(localVarIndexer.closure);
|
||||
builder.addLoadInstanceField(
|
||||
CField(
|
||||
ClosureField(
|
||||
_currentClosureLayout.firstContextIndex +
|
||||
scopes
|
||||
.getCapturedContexts(
|
||||
function.functionNode!,
|
||||
enableAsserts: enableAsserts,
|
||||
)
|
||||
.indexOf(scopes.getVariableContext(variable)),
|
||||
),
|
||||
),
|
||||
);
|
||||
builder.addLoadInstanceField(
|
||||
localVarIndexer.contextField(variable),
|
||||
);
|
||||
classTypeParameters = builder.addTypeParameters(
|
||||
.classTypeParameters,
|
||||
);
|
||||
}
|
||||
classTypeParameters = builder.addTypeParameters(
|
||||
.classTypeParameters,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -819,16 +845,26 @@ class AstToIr extends ast.RecursiveVisitor {
|
||||
return;
|
||||
}
|
||||
if (node is ast.FunctionNode) {
|
||||
var index = 0;
|
||||
for (final context in scopes.getCapturedContexts(
|
||||
node,
|
||||
enableAsserts: enableAsserts,
|
||||
)) {
|
||||
assert(_isCapturedContext(context));
|
||||
builder.addLoadLocal(localVarIndexer.closure);
|
||||
builder.addLoadInstanceField(CField(ClosureField(index)));
|
||||
localVarIndexer.defineContext(context, builder.pop());
|
||||
++index;
|
||||
assert(function.functionNode == node);
|
||||
if (function is ClosureFunction) {
|
||||
var index = _currentClosureLayout.firstContextIndex;
|
||||
for (final context in scopes.getCapturedContexts(
|
||||
node,
|
||||
enableAsserts: enableAsserts,
|
||||
)) {
|
||||
assert(_isCapturedContext(context));
|
||||
assert(index < _currentClosureLayout.length);
|
||||
builder.addLoadLocal(localVarIndexer.closure);
|
||||
builder.addLoadInstanceField(CField(ClosureField(index)));
|
||||
localVarIndexer.defineContext(context, builder.pop());
|
||||
++index;
|
||||
}
|
||||
} else {
|
||||
assert(
|
||||
scopes
|
||||
.getCapturedContexts(node, enableAsserts: enableAsserts)
|
||||
.isEmpty,
|
||||
);
|
||||
}
|
||||
}
|
||||
final scope = scopes.getScope(node);
|
||||
@@ -1763,18 +1799,82 @@ class AstToIr extends ast.RecursiveVisitor {
|
||||
as ClosureFunction;
|
||||
onLocalFunction(closureFunction);
|
||||
|
||||
// TODO: capture (parent) function type arguments and instantiator
|
||||
// type arguments if needed.
|
||||
final closureLayout = _computeClosureLayout(closureFunction);
|
||||
final closure = builder.addAllocateClosure(
|
||||
closureFunction,
|
||||
closureLayout,
|
||||
type,
|
||||
);
|
||||
|
||||
if (closureLayout.hasClassTypeArgs) {
|
||||
assert(typeParametersStyle == .separateFunctionAndClassTypeParameters);
|
||||
builder.push(closure);
|
||||
builder.push(classTypeParameters!);
|
||||
builder.addStoreInstanceField(
|
||||
CField(ClosureField(closureLayout.classTypeArgsIndex)),
|
||||
);
|
||||
}
|
||||
|
||||
if (closureLayout.hasFunctionTypeArgs) {
|
||||
assert(typeParametersStyle == .separateFunctionAndClassTypeParameters);
|
||||
builder.push(closure);
|
||||
builder.push(functionTypeParameters!);
|
||||
builder.addStoreInstanceField(
|
||||
CField(ClosureField(closureLayout.functionTypeArgsIndex)),
|
||||
);
|
||||
}
|
||||
|
||||
final contexts = scopes.getCapturedContexts(
|
||||
node.function,
|
||||
enableAsserts: enableAsserts,
|
||||
);
|
||||
var index = closureLayout.firstContextIndex;
|
||||
for (final context in contexts) {
|
||||
assert(_isCapturedContext(context));
|
||||
assert(index < closureLayout.length);
|
||||
builder.push(closure);
|
||||
builder.push(localVarIndexer.contextDef(context));
|
||||
// TODO: cache and reuse ClosureField objects.
|
||||
builder.addStoreInstanceField(CField(ClosureField(index++)));
|
||||
}
|
||||
builder.addAllocateClosure(closureFunction, type, contexts.length);
|
||||
}
|
||||
|
||||
ClosureLayout _computeClosureLayout(ClosureFunction closureFunction) {
|
||||
var hasDelayedTypeArgs = false;
|
||||
var hasClassTypeArgs = false;
|
||||
var hasFunctionTypeArgs = false;
|
||||
switch (typeParametersStyle) {
|
||||
case .separateFunctionAndClassTypeParameters:
|
||||
hasDelayedTypeArgs = closureFunction.hasFunctionTypeParameters;
|
||||
|
||||
final visitor = _FindTypeParameters();
|
||||
closureFunction.functionNode!
|
||||
.computeFunctionType(ast.Nullability.nonNullable)
|
||||
.accept(visitor);
|
||||
hasClassTypeArgs = visitor.containsClassTypeParams;
|
||||
|
||||
hasFunctionTypeArgs = switch (closureFunction) {
|
||||
LocalFunction() => closureFunction.hasGenericEnclosingFunction(),
|
||||
TearOffFunction() => false,
|
||||
};
|
||||
}
|
||||
final numContexts = switch (closureFunction) {
|
||||
LocalFunction() =>
|
||||
scopes
|
||||
.getCapturedContexts(
|
||||
closureFunction.functionNode!,
|
||||
enableAsserts: enableAsserts,
|
||||
)
|
||||
.length,
|
||||
TearOffFunction() =>
|
||||
closureFunction.member.isInstanceMember ? /* receiver */ 1 : 0,
|
||||
};
|
||||
return ClosureLayout(
|
||||
numContexts,
|
||||
hasDelayedTypeArgs: hasDelayedTypeArgs,
|
||||
hasClassTypeArgs: hasClassTypeArgs,
|
||||
hasFunctionTypeArgs: hasFunctionTypeArgs,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'package:cfg/front_end/scopes.dart';
|
||||
import 'package:cfg/ir/global_context.dart';
|
||||
import 'package:kernel/ast.dart' as ast;
|
||||
|
||||
/// Implementation of [Scopes] by computing scopes and contexts.
|
||||
@@ -16,8 +17,13 @@ final class ComputedScopes implements Scopes {
|
||||
|
||||
ComputedScopes(this.member, {required this.enableAsserts}) {
|
||||
if (member.isInstanceMember || member is ast.Constructor) {
|
||||
final type = member.enclosingClass!.getThisType(
|
||||
GlobalContext.instance.coreTypes,
|
||||
.nonNullable,
|
||||
);
|
||||
thisVariable =
|
||||
member.function?.thisVariable ?? ast.VariableDeclaration('this');
|
||||
member.function?.thisVariable ??
|
||||
ast.VariableDeclaration('this', type: type);
|
||||
}
|
||||
final builder = _ScopeBuilder(this);
|
||||
member.accept(builder);
|
||||
|
||||
@@ -56,3 +56,65 @@ final class ClosureField extends SyntheticField {
|
||||
isFinal: true,
|
||||
);
|
||||
}
|
||||
|
||||
/// Defines assignment of the closure elements.
|
||||
class ClosureLayout {
|
||||
static const int hasDelayedTypeArgsFlag = 1 << 0;
|
||||
static const int hasClassTypeArgsFlag = 1 << 1;
|
||||
static const int hasFunctionTypeArgsFlag = 1 << 2;
|
||||
|
||||
final int _flags;
|
||||
|
||||
/// Total number of closure elements.
|
||||
final int length;
|
||||
|
||||
ClosureLayout(
|
||||
int numContexts, {
|
||||
required bool hasDelayedTypeArgs,
|
||||
required bool hasClassTypeArgs,
|
||||
required bool hasFunctionTypeArgs,
|
||||
}) : _flags =
|
||||
(hasDelayedTypeArgs ? hasDelayedTypeArgsFlag : 0) |
|
||||
(hasClassTypeArgs ? hasClassTypeArgsFlag : 0) |
|
||||
(hasFunctionTypeArgs ? hasFunctionTypeArgsFlag : 0),
|
||||
length =
|
||||
(hasDelayedTypeArgs ? 1 : 0) +
|
||||
(hasClassTypeArgs ? 1 : 0) +
|
||||
(hasFunctionTypeArgs ? 1 : 0) +
|
||||
numContexts {
|
||||
assert(length == firstContextIndex + numContexts);
|
||||
}
|
||||
|
||||
/// Whether closure has an element for delayed type arguments.
|
||||
bool get hasDelayedTypeArgs => (_flags & hasDelayedTypeArgsFlag) != 0;
|
||||
|
||||
/// Whether closure has an element for enclosing class type arguments.
|
||||
bool get hasClassTypeArgs => (_flags & hasClassTypeArgsFlag) != 0;
|
||||
|
||||
/// Whether closure has an element for enclosing function type arguments.
|
||||
bool get hasFunctionTypeArgs => (_flags & hasFunctionTypeArgsFlag) != 0;
|
||||
|
||||
/// Index of the delayed type arguments element.
|
||||
int get delayedTypeArgsIndex {
|
||||
assert(hasDelayedTypeArgs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// Index of the enclosing class type arguments element.
|
||||
int get classTypeArgsIndex {
|
||||
assert(hasClassTypeArgs);
|
||||
return hasDelayedTypeArgs ? 1 : 0;
|
||||
}
|
||||
|
||||
/// Index of the enclosing function type arguments element.
|
||||
int get functionTypeArgsIndex {
|
||||
assert(hasFunctionTypeArgs);
|
||||
return (hasDelayedTypeArgs ? 1 : 0) + (hasClassTypeArgs ? 1 : 0);
|
||||
}
|
||||
|
||||
int get firstContextIndex {
|
||||
return (hasDelayedTypeArgs ? 1 : 0) +
|
||||
(hasClassTypeArgs ? 1 : 0) +
|
||||
(hasFunctionTypeArgs ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -546,17 +546,16 @@ class FlowGraphBuilder {
|
||||
/// Append [AllocateClosure] to the graph.
|
||||
AllocateClosure addAllocateClosure(
|
||||
ClosureFunction function,
|
||||
ClosureLayout closureLayout,
|
||||
CType type,
|
||||
int inputCount,
|
||||
) {
|
||||
final instr = AllocateClosure(
|
||||
graph,
|
||||
currentSourcePosition,
|
||||
function,
|
||||
closureLayout,
|
||||
type,
|
||||
inputCount: inputCount,
|
||||
);
|
||||
popInputs(instr, 0, inputCount);
|
||||
push(instr);
|
||||
appendInstruction(instr);
|
||||
return instr;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'package:cfg/ir/constant_value.dart';
|
||||
import 'package:cfg/ir/field.dart';
|
||||
import 'package:cfg/ir/instructions.dart';
|
||||
import 'package:cfg/ir/ir_to_text.dart';
|
||||
import 'package:cfg/ir/types.dart';
|
||||
@@ -352,11 +353,15 @@ final class FlowGraphChecker extends Pass implements InstructionVisitor<void> {
|
||||
void visitTypeParameters(TypeParameters instr) {
|
||||
assert(instr.block is EntryBlock);
|
||||
// TypeParameters can only be used in TypeCast, TypeTest,
|
||||
// TypeArguments and TypeLiteral.
|
||||
// TypeArguments, TypeLiteral and StoreInstanceField for capturing.
|
||||
for (final use in instr.inputUses) {
|
||||
final user = use.getInstruction(graph);
|
||||
switch (user) {
|
||||
case TypeCast() || TypeTest() || TypeArguments() || TypeLiteral():
|
||||
case StoreInstanceField(:var field)
|
||||
when field.isSynthetic &&
|
||||
(field.asSynthetic is ClosureField ||
|
||||
field.asSynthetic is ContextField):
|
||||
break;
|
||||
default:
|
||||
throw 'Unexpected user ${IrToText.instruction(user)} of TypeParameters';
|
||||
|
||||
@@ -232,6 +232,19 @@ final class LocalFunction extends ClosureFunction {
|
||||
|
||||
@override
|
||||
SourcePosition get sourcePosition => SourcePosition(localFunction.fileOffset);
|
||||
|
||||
bool hasGenericEnclosingFunction() {
|
||||
ast.TreeNode node = localFunction;
|
||||
for (;;) {
|
||||
node = node.parent!;
|
||||
if (node is ast.Member) {
|
||||
return false;
|
||||
}
|
||||
if (node is ast.FunctionNode && node.typeParameters.isNotEmpty) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Tear-off (result of function closurization).
|
||||
|
||||
@@ -1319,10 +1319,9 @@ final class AllocateObject extends Definition with CanThrow, Pure {
|
||||
}
|
||||
|
||||
/// Allocate a closure instance.
|
||||
///
|
||||
/// Takes captured values as inputs.
|
||||
final class AllocateClosure extends Definition with CanThrow, Pure {
|
||||
final ClosureFunction function;
|
||||
final ClosureLayout closureLayout;
|
||||
|
||||
@override
|
||||
final CType type;
|
||||
@@ -1331,9 +1330,9 @@ final class AllocateClosure extends Definition with CanThrow, Pure {
|
||||
super.graph,
|
||||
super.sourcePosition,
|
||||
this.function,
|
||||
this.type, {
|
||||
required super.inputCount,
|
||||
});
|
||||
this.closureLayout,
|
||||
this.type,
|
||||
) : super(inputCount: 0);
|
||||
|
||||
@override
|
||||
R accept<R>(InstructionVisitor<R> v) => v.visitAllocateClosure(this);
|
||||
|
||||
@@ -156,12 +156,11 @@ void foo46() {
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: support class type parameters via captured receiver
|
||||
class A /*<T>*/ {
|
||||
class A<T> {
|
||||
List<int> aField = [
|
||||
for (int i = 0; i < 10; ++i)
|
||||
() {
|
||||
// print(T);
|
||||
print(T);
|
||||
print(i);
|
||||
i += 2;
|
||||
return i;
|
||||
|
||||
@@ -1,66 +1,83 @@
|
||||
--- A.foo47
|
||||
B0 = EntryBlock() dominates:(B9)
|
||||
v3 = Constant(<int>)
|
||||
v4 = Constant(0)
|
||||
v12 = Constant(10)
|
||||
v22 = Constant(1)
|
||||
v30 = Constant(null)
|
||||
B0 = EntryBlock() dominates:(B14)
|
||||
v8 = Constant(<int>)
|
||||
v9 = Constant(0)
|
||||
v17 = Constant(10)
|
||||
v29 = Constant(1)
|
||||
v37 = Constant(null)
|
||||
v1 = Parameter(this)
|
||||
v5 = DirectCall _GrowableList.(v3, v4)
|
||||
v7 = AllocateContext()
|
||||
StoreInstanceField(#context-field:i, v7, v4)
|
||||
Goto(B9)
|
||||
B9 = JoinBlock(B0, B14) idom:B0 dominates:(B15, B14) loop-header (depth:1 body:(B9, B14) back-edges:(B14))
|
||||
v11 = LoadInstanceField(#context-field:i, v7)
|
||||
v13 = Comparison int <(v11, v12)
|
||||
Branch(v13, true: B14, false: B15)
|
||||
B14 = TargetBlock() idom:B9 in-loop:B9
|
||||
v18 = AllocateClosure(v7)
|
||||
v32 = DirectCall closure FunctionExpression(int () {
|
||||
TypeParameters(v1)
|
||||
v4 = AllocateContext()
|
||||
StoreInstanceField(#context-field:this, v4, v1)
|
||||
v10 = DirectCall _GrowableList.(v8, v9)
|
||||
v12 = AllocateContext()
|
||||
StoreInstanceField(#context-field:i, v12, v9)
|
||||
Goto(B14)
|
||||
B14 = JoinBlock(B0, B19) idom:B0 dominates:(B20, B19) loop-header (depth:1 body:(B14, B19) back-edges:(B19))
|
||||
v16 = LoadInstanceField(#context-field:i, v12)
|
||||
v18 = Comparison int <(v16, v17)
|
||||
Branch(v18, true: B19, false: B20)
|
||||
B19 = TargetBlock() idom:B14 in-loop:B14
|
||||
v23 = AllocateClosure()
|
||||
StoreInstanceField(#closure-field[0], v23, v4)
|
||||
StoreInstanceField(#closure-field[1], v23, v12)
|
||||
v39 = DirectCall closure FunctionExpression(int () {
|
||||
print(A.T%);
|
||||
print(i);
|
||||
i = i.{num.+}(2);
|
||||
return i;
|
||||
}) at A.foo47(v18)
|
||||
InterfaceCall List.add(v5, v32)
|
||||
v21 = LoadInstanceField(#context-field:i, v7)
|
||||
v23 = BinaryIntOp +(v21, v22)
|
||||
StoreInstanceField(#context-field:i, v7, v23)
|
||||
Goto(B9)
|
||||
B15 = TargetBlock() idom:B9
|
||||
StoreInstanceField(A.aField, v1, v5)
|
||||
DirectCall Object.(v1)
|
||||
Return(v30)
|
||||
}) at A.foo47(v23)
|
||||
InterfaceCall List.add(v10, v39)
|
||||
v28 = LoadInstanceField(#context-field:i, v12)
|
||||
v30 = BinaryIntOp +(v28, v29)
|
||||
StoreInstanceField(#context-field:i, v12, v30)
|
||||
Goto(B14)
|
||||
B20 = TargetBlock() idom:B14
|
||||
StoreInstanceField(A.aField, v1, v10)
|
||||
v35 = LoadInstanceField(#context-field:this, v4)
|
||||
DirectCall Object.(v35)
|
||||
Return(v37)
|
||||
|
||||
--- closure FunctionExpression(int () {
|
||||
print(A.T%);
|
||||
print(i);
|
||||
i = i.{num.+}(2);
|
||||
return i;
|
||||
}) at A.foo47
|
||||
B0 = EntryBlock()
|
||||
v7 = Constant(2)
|
||||
v10 = Constant(null)
|
||||
v16 = Constant(2)
|
||||
v1 = Parameter(#closure)
|
||||
v3 = LoadInstanceField(#closure-field[0], v1)
|
||||
v4 = LoadInstanceField(#context-field:i, v3)
|
||||
DirectCall print(v4)
|
||||
v6 = LoadInstanceField(#context-field:i, v3)
|
||||
v8 = BinaryIntOp +(v6, v7)
|
||||
StoreInstanceField(#context-field:i, v3, v8)
|
||||
v10 = LoadInstanceField(#context-field:i, v3)
|
||||
Return(v10)
|
||||
v4 = LoadInstanceField(#context-field:this, v3)
|
||||
v5 = TypeParameters(v4)
|
||||
LoadInstanceField(#closure-field[0], v1)
|
||||
v9 = LoadInstanceField(#closure-field[1], v1)
|
||||
v11 = TypeLiteral(A.T%, v5, v10)
|
||||
DirectCall print(v11)
|
||||
v13 = LoadInstanceField(#context-field:i, v9)
|
||||
DirectCall print(v13)
|
||||
v15 = LoadInstanceField(#context-field:i, v9)
|
||||
v17 = BinaryIntOp +(v15, v16)
|
||||
StoreInstanceField(#context-field:i, v9, v17)
|
||||
v19 = LoadInstanceField(#context-field:i, v9)
|
||||
Return(v19)
|
||||
|
||||
--- getter A.aField
|
||||
B0 = EntryBlock()
|
||||
v1 = Parameter(this)
|
||||
v3 = LoadInstanceField(A.aField, v1)
|
||||
Return(v3)
|
||||
TypeParameters(v1)
|
||||
v5 = LoadInstanceField(A.aField, v1)
|
||||
Return(v5)
|
||||
|
||||
--- setter A.aField
|
||||
B0 = EntryBlock()
|
||||
v6 = Constant(null)
|
||||
v8 = Constant(null)
|
||||
v1 = Parameter(this)
|
||||
v2 = Parameter(#value)
|
||||
TypeParameters(v1)
|
||||
StoreInstanceField(A.aField, v1, v2)
|
||||
Return(v6)
|
||||
Return(v8)
|
||||
|
||||
--- opaqueVal
|
||||
B0 = EntryBlock()
|
||||
@@ -85,16 +102,16 @@ B8 = JoinBlock(B6, B5) idom:B0
|
||||
Return(v13)
|
||||
|
||||
--- foo42
|
||||
B0 = EntryBlock() dominates:(B14)
|
||||
B0 = EntryBlock() dominates:(B16)
|
||||
Constant(true)
|
||||
v21 = Constant(50)
|
||||
v23 = Constant(60)
|
||||
v25 = Constant(70)
|
||||
v42 = Constant(1)
|
||||
v54 = Constant(0)
|
||||
v59 = Constant(10)
|
||||
v77 = Constant(90)
|
||||
v91 = Constant(null)
|
||||
v23 = Constant(50)
|
||||
v25 = Constant(60)
|
||||
v27 = Constant(70)
|
||||
v47 = Constant(1)
|
||||
v59 = Constant(0)
|
||||
v64 = Constant(10)
|
||||
v83 = Constant(90)
|
||||
v98 = Constant(null)
|
||||
v1 = AllocateContext()
|
||||
v2 = DirectCall opaqueVal()
|
||||
StoreInstanceField(#context-field:a, v1, v2)
|
||||
@@ -104,72 +121,79 @@ B0 = EntryBlock() dominates:(B14)
|
||||
StoreInstanceField(#context-field:c, v1, v6)
|
||||
v8 = DirectCall opaqueVal()
|
||||
StoreInstanceField(#context-field:d, v1, v8)
|
||||
v10 = AllocateClosure(v1)
|
||||
v10 = AllocateClosure()
|
||||
StoreInstanceField(#closure-field[0], v10, v1)
|
||||
DirectCall callClosure(v10)
|
||||
v12 = AllocateClosure(v1)
|
||||
DirectCall callClosure(v12)
|
||||
Goto(B14)
|
||||
B14 = JoinBlock(B0, B45) idom:B0 dominates:(B45, B44) loop-header (depth:1 body:(B14, B45) back-edges:(B45))
|
||||
v20 = AllocateContext()
|
||||
StoreInstanceField(#context-field:e, v20, v21)
|
||||
StoreInstanceField(#context-field:f, v20, v23)
|
||||
StoreInstanceField(#context-field:g, v20, v25)
|
||||
v27 = AllocateClosure(v1)
|
||||
DirectCall callClosure(v27)
|
||||
v29 = AllocateClosure(v20)
|
||||
v13 = AllocateClosure()
|
||||
StoreInstanceField(#closure-field[0], v13, v1)
|
||||
DirectCall callClosure(v13)
|
||||
Goto(B16)
|
||||
B16 = JoinBlock(B0, B50) idom:B0 dominates:(B50, B49) loop-header (depth:1 body:(B16, B50) back-edges:(B50))
|
||||
v22 = AllocateContext()
|
||||
StoreInstanceField(#context-field:e, v22, v23)
|
||||
StoreInstanceField(#context-field:f, v22, v25)
|
||||
StoreInstanceField(#context-field:g, v22, v27)
|
||||
v29 = AllocateClosure()
|
||||
StoreInstanceField(#closure-field[0], v29, v1)
|
||||
DirectCall callClosure(v29)
|
||||
v31 = AllocateClosure(v20)
|
||||
DirectCall callClosure(v31)
|
||||
v33 = LoadInstanceField(#context-field:d, v1)
|
||||
DirectCall print(v33)
|
||||
v35 = LoadInstanceField(#context-field:e, v20)
|
||||
DirectCall print(v35)
|
||||
v37 = LoadInstanceField(#context-field:f, v20)
|
||||
DirectCall print(v37)
|
||||
v39 = LoadInstanceField(#context-field:g, v20)
|
||||
DirectCall print(v39)
|
||||
v41 = DirectCall opaqueVal()
|
||||
v43 = Comparison int ==(v41, v42)
|
||||
Branch(v43, true: B44, false: B45)
|
||||
B44 = TargetBlock() idom:B14 dominates:(B56)
|
||||
v53 = AllocateContext()
|
||||
StoreInstanceField(#context-field:i, v53, v54)
|
||||
Goto(B56)
|
||||
B56 = JoinBlock(B44, B75) idom:B44 dominates:(B62, B61) loop-header (depth:1 body:(B56, B61, B70, B75, B74) back-edges:(B75))
|
||||
v58 = LoadInstanceField(#context-field:i, v53)
|
||||
v60 = Comparison int <(v58, v59)
|
||||
Branch(v60, true: B61, false: B62)
|
||||
B61 = TargetBlock() idom:B56 dominates:(B70) in-loop:B56
|
||||
v64 = DirectCall opaqueVal()
|
||||
StoreInstanceField(#context-field:h, v53, v64)
|
||||
v66 = AllocateClosure(v53)
|
||||
DirectCall callClosure(v66)
|
||||
v68 = AllocateContext()
|
||||
StoreInstanceField(#context-field:j, v68, v54)
|
||||
Goto(B70)
|
||||
B70 = JoinBlock(B61, B74) idom:B61 dominates:(B75, B74) loop-header (depth:2 body:(B70, B74) back-edges:(B74))
|
||||
v72 = LoadInstanceField(#context-field:j, v68)
|
||||
v73 = Comparison int <(v72, v59)
|
||||
Branch(v73, true: B74, false: B75)
|
||||
B74 = TargetBlock() idom:B70 in-loop:B70
|
||||
StoreInstanceField(#context-field:k, v68, v77)
|
||||
v79 = AllocateClosure(v68)
|
||||
DirectCall callClosure(v79)
|
||||
v81 = LoadInstanceField(#context-field:k, v68)
|
||||
DirectCall print(v81)
|
||||
v83 = LoadInstanceField(#context-field:j, v68)
|
||||
v84 = BinaryIntOp +(v83, v42)
|
||||
StoreInstanceField(#context-field:j, v68, v84)
|
||||
Goto(B70)
|
||||
B75 = TargetBlock() idom:B70 in-loop:B56
|
||||
v87 = LoadInstanceField(#context-field:i, v53)
|
||||
v88 = BinaryIntOp +(v87, v42)
|
||||
StoreInstanceField(#context-field:i, v53, v88)
|
||||
Goto(B56)
|
||||
B62 = TargetBlock() idom:B56
|
||||
Return(v91)
|
||||
B45 = TargetBlock() idom:B14 in-loop:B14
|
||||
Goto(B14)
|
||||
v32 = AllocateClosure()
|
||||
StoreInstanceField(#closure-field[0], v32, v22)
|
||||
DirectCall callClosure(v32)
|
||||
v35 = AllocateClosure()
|
||||
StoreInstanceField(#closure-field[0], v35, v22)
|
||||
DirectCall callClosure(v35)
|
||||
v38 = LoadInstanceField(#context-field:d, v1)
|
||||
DirectCall print(v38)
|
||||
v40 = LoadInstanceField(#context-field:e, v22)
|
||||
DirectCall print(v40)
|
||||
v42 = LoadInstanceField(#context-field:f, v22)
|
||||
DirectCall print(v42)
|
||||
v44 = LoadInstanceField(#context-field:g, v22)
|
||||
DirectCall print(v44)
|
||||
v46 = DirectCall opaqueVal()
|
||||
v48 = Comparison int ==(v46, v47)
|
||||
Branch(v48, true: B49, false: B50)
|
||||
B49 = TargetBlock() idom:B16 dominates:(B61)
|
||||
v58 = AllocateContext()
|
||||
StoreInstanceField(#context-field:i, v58, v59)
|
||||
Goto(B61)
|
||||
B61 = JoinBlock(B49, B81) idom:B49 dominates:(B67, B66) loop-header (depth:1 body:(B61, B66, B76, B81, B80) back-edges:(B81))
|
||||
v63 = LoadInstanceField(#context-field:i, v58)
|
||||
v65 = Comparison int <(v63, v64)
|
||||
Branch(v65, true: B66, false: B67)
|
||||
B66 = TargetBlock() idom:B61 dominates:(B76) in-loop:B61
|
||||
v69 = DirectCall opaqueVal()
|
||||
StoreInstanceField(#context-field:h, v58, v69)
|
||||
v71 = AllocateClosure()
|
||||
StoreInstanceField(#closure-field[0], v71, v58)
|
||||
DirectCall callClosure(v71)
|
||||
v74 = AllocateContext()
|
||||
StoreInstanceField(#context-field:j, v74, v59)
|
||||
Goto(B76)
|
||||
B76 = JoinBlock(B66, B80) idom:B66 dominates:(B81, B80) loop-header (depth:2 body:(B76, B80) back-edges:(B80))
|
||||
v78 = LoadInstanceField(#context-field:j, v74)
|
||||
v79 = Comparison int <(v78, v64)
|
||||
Branch(v79, true: B80, false: B81)
|
||||
B80 = TargetBlock() idom:B76 in-loop:B76
|
||||
StoreInstanceField(#context-field:k, v74, v83)
|
||||
v85 = AllocateClosure()
|
||||
StoreInstanceField(#closure-field[0], v85, v74)
|
||||
DirectCall callClosure(v85)
|
||||
v88 = LoadInstanceField(#context-field:k, v74)
|
||||
DirectCall print(v88)
|
||||
v90 = LoadInstanceField(#context-field:j, v74)
|
||||
v91 = BinaryIntOp +(v90, v47)
|
||||
StoreInstanceField(#context-field:j, v74, v91)
|
||||
Goto(B76)
|
||||
B81 = TargetBlock() idom:B76 in-loop:B61
|
||||
v94 = LoadInstanceField(#context-field:i, v58)
|
||||
v95 = BinaryIntOp +(v94, v47)
|
||||
StoreInstanceField(#context-field:i, v58, v95)
|
||||
Goto(B61)
|
||||
B67 = TargetBlock() idom:B61
|
||||
Return(v98)
|
||||
B50 = TargetBlock() idom:B16 in-loop:B16
|
||||
Goto(B16)
|
||||
|
||||
--- closure FunctionExpression(void () {
|
||||
print(a);
|
||||
@@ -289,21 +313,25 @@ B0 = EntryBlock()
|
||||
v4 = Constant(20)
|
||||
v6 = Constant(30)
|
||||
v8 = Constant(40)
|
||||
v18 = Constant(null)
|
||||
v22 = Constant(null)
|
||||
v1 = AllocateContext()
|
||||
StoreInstanceField(#context-field:a, v1, v2)
|
||||
StoreInstanceField(#context-field:b, v1, v4)
|
||||
StoreInstanceField(#context-field:c, v1, v6)
|
||||
StoreInstanceField(#context-field:d, v1, v8)
|
||||
v10 = AllocateClosure(v1)
|
||||
v10 = AllocateClosure()
|
||||
StoreInstanceField(#closure-field[0], v10, v1)
|
||||
DirectCall callClosure(v10)
|
||||
v12 = AllocateClosure(v1)
|
||||
DirectCall callClosure(v12)
|
||||
v14 = AllocateClosure(v1)
|
||||
DirectCall callClosure(v14)
|
||||
v16 = AllocateClosure(v1)
|
||||
v13 = AllocateClosure()
|
||||
StoreInstanceField(#closure-field[0], v13, v1)
|
||||
DirectCall callClosure(v13)
|
||||
v16 = AllocateClosure()
|
||||
StoreInstanceField(#closure-field[0], v16, v1)
|
||||
DirectCall callClosure(v16)
|
||||
Return(v18)
|
||||
v19 = AllocateClosure()
|
||||
StoreInstanceField(#closure-field[0], v19, v1)
|
||||
DirectCall callClosure(v19)
|
||||
Return(v22)
|
||||
|
||||
--- closure FunctionExpression(void () {
|
||||
a = a.{num.+}(11);
|
||||
@@ -373,39 +401,42 @@ B0 = EntryBlock()
|
||||
Return(v8)
|
||||
|
||||
--- foo45
|
||||
B0 = EntryBlock() dominates:(B10, B12, B9)
|
||||
B0 = EntryBlock() dominates:(B11, B13, B10)
|
||||
v2 = Constant(10)
|
||||
v7 = Constant(1)
|
||||
v14 = Constant(20)
|
||||
v26 = Constant(30)
|
||||
v31 = Constant(null)
|
||||
v8 = Constant(1)
|
||||
v15 = Constant(20)
|
||||
v28 = Constant(30)
|
||||
v34 = Constant(null)
|
||||
v1 = AllocateContext()
|
||||
StoreInstanceField(#context-field:a, v1, v2)
|
||||
v4 = AllocateClosure(v1)
|
||||
v4 = AllocateClosure()
|
||||
StoreInstanceField(#closure-field[0], v4, v1)
|
||||
DirectCall callClosure(v4)
|
||||
v6 = DirectCall opaqueVal()
|
||||
v8 = Comparison int ==(v6, v7)
|
||||
Branch(v8, true: B9, false: B10)
|
||||
B9 = TargetBlock() idom:B0
|
||||
StoreInstanceField(#context-field:b, v1, v14)
|
||||
v16 = AllocateClosure(v1)
|
||||
DirectCall callClosure(v16)
|
||||
Goto(B12)
|
||||
v7 = DirectCall opaqueVal()
|
||||
v9 = Comparison int ==(v7, v8)
|
||||
Branch(v9, true: B10, false: B11)
|
||||
B10 = TargetBlock() idom:B0
|
||||
Goto(B12)
|
||||
B12 = JoinBlock(B10, B9) idom:B0 dominates:(B22, B24, B21)
|
||||
v19 = DirectCall opaqueVal()
|
||||
v20 = Comparison int ==(v19, v7)
|
||||
Branch(v20, true: B21, false: B22)
|
||||
B21 = TargetBlock() idom:B12
|
||||
StoreInstanceField(#context-field:c, v1, v26)
|
||||
v28 = AllocateClosure(v1)
|
||||
DirectCall callClosure(v28)
|
||||
Goto(B24)
|
||||
B22 = TargetBlock() idom:B12
|
||||
Goto(B24)
|
||||
B24 = JoinBlock(B22, B21) idom:B12
|
||||
Return(v31)
|
||||
StoreInstanceField(#context-field:b, v1, v15)
|
||||
v17 = AllocateClosure()
|
||||
StoreInstanceField(#closure-field[0], v17, v1)
|
||||
DirectCall callClosure(v17)
|
||||
Goto(B13)
|
||||
B11 = TargetBlock() idom:B0
|
||||
Goto(B13)
|
||||
B13 = JoinBlock(B11, B10) idom:B0 dominates:(B24, B26, B23)
|
||||
v21 = DirectCall opaqueVal()
|
||||
v22 = Comparison int ==(v21, v8)
|
||||
Branch(v22, true: B23, false: B24)
|
||||
B23 = TargetBlock() idom:B13
|
||||
StoreInstanceField(#context-field:c, v1, v28)
|
||||
v30 = AllocateClosure()
|
||||
StoreInstanceField(#closure-field[0], v30, v1)
|
||||
DirectCall callClosure(v30)
|
||||
Goto(B26)
|
||||
B24 = TargetBlock() idom:B13
|
||||
Goto(B26)
|
||||
B26 = JoinBlock(B24, B23) idom:B13
|
||||
Return(v34)
|
||||
|
||||
--- closure FunctionExpression(void () {
|
||||
a = a.{num.+}(11);
|
||||
@@ -458,17 +489,19 @@ B0 = EntryBlock()
|
||||
|
||||
--- foo46
|
||||
B0 = EntryBlock()
|
||||
v10 = Constant(null)
|
||||
v12 = Constant(null)
|
||||
v1 = AllocateContext()
|
||||
v2 = DirectCall opaqueVal()
|
||||
StoreInstanceField(#context-field:a, v1, v2)
|
||||
v4 = DirectCall opaqueVal()
|
||||
StoreInstanceField(#context-field:b, v1, v4)
|
||||
v6 = AllocateClosure(v1)
|
||||
v6 = AllocateClosure()
|
||||
StoreInstanceField(#closure-field[0], v6, v1)
|
||||
DirectCall callClosure(v6)
|
||||
v8 = AllocateClosure(v1)
|
||||
DirectCall callClosure(v8)
|
||||
Return(v10)
|
||||
v9 = AllocateClosure()
|
||||
StoreInstanceField(#closure-field[0], v9, v1)
|
||||
DirectCall callClosure(v9)
|
||||
Return(v12)
|
||||
|
||||
--- closure FunctionExpression(void () {
|
||||
callClosure(void () {
|
||||
@@ -476,12 +509,13 @@ B0 = EntryBlock()
|
||||
});
|
||||
}) at foo46
|
||||
B0 = EntryBlock()
|
||||
v6 = Constant(null)
|
||||
v7 = Constant(null)
|
||||
v1 = Parameter(#closure)
|
||||
v3 = LoadInstanceField(#closure-field[0], v1)
|
||||
v4 = AllocateClosure(v3)
|
||||
v4 = AllocateClosure()
|
||||
StoreInstanceField(#closure-field[0], v4, v3)
|
||||
DirectCall callClosure(v4)
|
||||
Return(v6)
|
||||
Return(v7)
|
||||
|
||||
--- closure FunctionExpression(void () {
|
||||
print(a);
|
||||
@@ -500,12 +534,13 @@ B0 = EntryBlock()
|
||||
});
|
||||
}) at foo46
|
||||
B0 = EntryBlock()
|
||||
v6 = Constant(null)
|
||||
v7 = Constant(null)
|
||||
v1 = Parameter(#closure)
|
||||
v3 = LoadInstanceField(#closure-field[0], v1)
|
||||
v4 = AllocateClosure(v3)
|
||||
v4 = AllocateClosure()
|
||||
StoreInstanceField(#closure-field[0], v4, v3)
|
||||
DirectCall callClosure(v4)
|
||||
Return(v6)
|
||||
Return(v7)
|
||||
|
||||
--- closure FunctionExpression(void () {
|
||||
b = b.{num.+}(11);
|
||||
@@ -524,33 +559,35 @@ B0 = EntryBlock()
|
||||
B0 = EntryBlock() dominates:(B5, B7, B4)
|
||||
v2 = Constant(1)
|
||||
v10 = Constant(10)
|
||||
v23 = Constant(20)
|
||||
v28 = Constant(null)
|
||||
v24 = Constant(20)
|
||||
v30 = Constant(null)
|
||||
v1 = DirectCall opaqueVal()
|
||||
v3 = Comparison int ==(v1, v2)
|
||||
Branch(v3, true: B4, false: B5)
|
||||
B4 = TargetBlock() idom:B0
|
||||
v9 = AllocateContext()
|
||||
StoreInstanceField(#context-field:a, v9, v10)
|
||||
v12 = AllocateClosure(v9)
|
||||
v12 = AllocateClosure()
|
||||
StoreInstanceField(#closure-field[0], v12, v9)
|
||||
DirectCall callClosure(v12)
|
||||
Goto(B7)
|
||||
B5 = TargetBlock() idom:B0
|
||||
Goto(B7)
|
||||
B7 = JoinBlock(B5, B4) idom:B0 dominates:(B18, B20, B17)
|
||||
v15 = DirectCall opaqueVal()
|
||||
v16 = Comparison int ==(v15, v2)
|
||||
Branch(v16, true: B17, false: B18)
|
||||
B17 = TargetBlock() idom:B7
|
||||
v22 = AllocateContext()
|
||||
StoreInstanceField(#context-field:b, v22, v23)
|
||||
v25 = AllocateClosure(v22)
|
||||
DirectCall callClosure(v25)
|
||||
Goto(B20)
|
||||
B7 = JoinBlock(B5, B4) idom:B0 dominates:(B19, B21, B18)
|
||||
v16 = DirectCall opaqueVal()
|
||||
v17 = Comparison int ==(v16, v2)
|
||||
Branch(v17, true: B18, false: B19)
|
||||
B18 = TargetBlock() idom:B7
|
||||
Goto(B20)
|
||||
B20 = JoinBlock(B18, B17) idom:B7
|
||||
Return(v28)
|
||||
v23 = AllocateContext()
|
||||
StoreInstanceField(#context-field:b, v23, v24)
|
||||
v26 = AllocateClosure()
|
||||
StoreInstanceField(#closure-field[0], v26, v23)
|
||||
DirectCall callClosure(v26)
|
||||
Goto(B21)
|
||||
B19 = TargetBlock() idom:B7
|
||||
Goto(B21)
|
||||
B21 = JoinBlock(B19, B18) idom:B7
|
||||
Return(v30)
|
||||
|
||||
--- closure FunctionExpression(void () {
|
||||
a = a.{num.+}(11);
|
||||
@@ -579,28 +616,30 @@ B0 = EntryBlock()
|
||||
Return(v8)
|
||||
|
||||
--- foo49
|
||||
B0 = EntryBlock() dominates:(B8)
|
||||
v6 = Constant(0)
|
||||
v11 = Constant(4)
|
||||
v19 = Constant(1)
|
||||
v23 = Constant(null)
|
||||
B0 = EntryBlock() dominates:(B9)
|
||||
v7 = Constant(0)
|
||||
v12 = Constant(4)
|
||||
v21 = Constant(1)
|
||||
v25 = Constant(null)
|
||||
v1 = AllocateContext()
|
||||
v2 = DirectCall opaqueVal()
|
||||
StoreInstanceField(#context-field:a, v1, v2)
|
||||
v4 = AllocateClosure(v1)
|
||||
v4 = AllocateClosure()
|
||||
StoreInstanceField(#closure-field[0], v4, v1)
|
||||
DirectCall callClosure(v4)
|
||||
Goto(B8)
|
||||
B8 = JoinBlock(B0, B13) idom:B0 dominates:(B14, B13) loop-header (depth:1 body:(B8, B13) back-edges:(B13))
|
||||
v25 = Phi(v6, v20)
|
||||
v12 = Comparison int <(v25, v11)
|
||||
Branch(v12, true: B13, false: B14)
|
||||
B13 = TargetBlock() idom:B8 in-loop:B8
|
||||
v16 = AllocateClosure(v1)
|
||||
DirectCall callClosure(v16)
|
||||
v20 = BinaryIntOp +(v25, v19)
|
||||
Goto(B8)
|
||||
B14 = TargetBlock() idom:B8
|
||||
Return(v23)
|
||||
Goto(B9)
|
||||
B9 = JoinBlock(B0, B14) idom:B0 dominates:(B15, B14) loop-header (depth:1 body:(B9, B14) back-edges:(B14))
|
||||
v27 = Phi(v7, v22)
|
||||
v13 = Comparison int <(v27, v12)
|
||||
Branch(v13, true: B14, false: B15)
|
||||
B14 = TargetBlock() idom:B9 in-loop:B9
|
||||
v17 = AllocateClosure()
|
||||
StoreInstanceField(#closure-field[0], v17, v1)
|
||||
DirectCall callClosure(v17)
|
||||
v22 = BinaryIntOp +(v27, v21)
|
||||
Goto(B9)
|
||||
B15 = TargetBlock() idom:B9
|
||||
Return(v25)
|
||||
|
||||
--- closure FunctionExpression(void () {
|
||||
a = a.{num.+}(10);
|
||||
@@ -623,15 +662,16 @@ B0 = EntryBlock()
|
||||
}) at foo49
|
||||
B0 = EntryBlock()
|
||||
v5 = Constant(20)
|
||||
v10 = Constant(null)
|
||||
v11 = Constant(null)
|
||||
v1 = Parameter(#closure)
|
||||
v3 = LoadInstanceField(#closure-field[0], v1)
|
||||
v4 = LoadInstanceField(#context-field:a, v3)
|
||||
v6 = BinaryIntOp +(v4, v5)
|
||||
StoreInstanceField(#context-field:a, v3, v6)
|
||||
v8 = AllocateClosure(v3)
|
||||
v8 = AllocateClosure()
|
||||
StoreInstanceField(#closure-field[0], v8, v3)
|
||||
DirectCall callClosure(v8)
|
||||
Return(v10)
|
||||
Return(v11)
|
||||
|
||||
--- closure FunctionExpression(void () {
|
||||
a = a.{num.+}(30);
|
||||
|
||||
@@ -719,7 +719,9 @@ final class Arm64CodeGenerator extends CodeGenerator {
|
||||
|
||||
bool _canBeSmi(Definition def) => switch (def) {
|
||||
Constant(:var value) => value.isInt && objectLayout.isSmi(value.intValue),
|
||||
_ => def.type is IntType || const IntType().isSubtypeOf(def.type),
|
||||
Definition(type: IntType()) => true,
|
||||
Definition(type: ExtendedType()) => false,
|
||||
Definition(:var type) => const IntType().isSubtypeOf(type),
|
||||
};
|
||||
|
||||
void _writeBarrier(
|
||||
@@ -1283,37 +1285,16 @@ final class Arm64CodeGenerator extends CodeGenerator {
|
||||
@override
|
||||
void visitAllocateClosure(AllocateClosure instr) {
|
||||
final function = instr.function;
|
||||
final hasDelayedTypeArgs = function.hasFunctionTypeParameters;
|
||||
final hasInstantiatorTypeArgs = switch (function) {
|
||||
LocalFunction() => containsClassTypeParameters(
|
||||
function.functionNode!.computeFunctionType(ast.Nullability.nonNullable),
|
||||
),
|
||||
TearOffFunction() =>
|
||||
function.member.isInstanceMember &&
|
||||
containsClassTypeParameters(
|
||||
function.member.function!.computeFunctionType(
|
||||
ast.Nullability.nonNullable,
|
||||
),
|
||||
),
|
||||
};
|
||||
final hasFunctionTypeArgs = switch (function) {
|
||||
LocalFunction() => hasGenericEnclosingFunction(function.localFunction),
|
||||
TearOffFunction() => false,
|
||||
};
|
||||
final numElements =
|
||||
(hasDelayedTypeArgs ? 1 : 0) +
|
||||
(hasInstantiatorTypeArgs ? 1 : 0) +
|
||||
(hasFunctionTypeArgs ? 1 : 0) +
|
||||
1 /* context */;
|
||||
final closureLayout = instr.closureLayout;
|
||||
final lengthAndFlags = vmOffsets.encodeClosureLengthAndFlags(
|
||||
numElements,
|
||||
hasDelayedTypeArgs: hasDelayedTypeArgs,
|
||||
hasInstantiatorTypeArgs: hasInstantiatorTypeArgs,
|
||||
hasFunctionTypeArgs: hasFunctionTypeArgs,
|
||||
closureLayout.length,
|
||||
hasDelayedTypeArgs: closureLayout.hasDelayedTypeArgs,
|
||||
hasInstantiatorTypeArgs: closureLayout.hasClassTypeArgs,
|
||||
hasFunctionTypeArgs: closureLayout.hasFunctionTypeArgs,
|
||||
);
|
||||
final instanceSize = roundUp(
|
||||
vmOffsets.Closure_elementsStartOffset +
|
||||
numElements * objectLayout.compressedWordSize,
|
||||
closureLayout.length * objectLayout.compressedWordSize,
|
||||
objectAlignment(wordSize),
|
||||
);
|
||||
|
||||
@@ -1357,8 +1338,7 @@ final class Arm64CodeGenerator extends CodeGenerator {
|
||||
_asm.fieldAddress(resultReg, vmOffsets.Closure_length_and_flags_offset),
|
||||
);
|
||||
_asm.str(ZR, _asm.fieldAddress(resultReg, vmOffsets.Closure_hash_offset));
|
||||
// TODO: initialize the rest of the fields.
|
||||
assert(instr.inputCount == 0);
|
||||
// TODO: initialize delayed type arguments.
|
||||
_asm.bind(done);
|
||||
}
|
||||
|
||||
|
||||
@@ -330,18 +330,11 @@ final class Arm64Constraints extends Constraints {
|
||||
|
||||
@override
|
||||
InstructionConstraints? visitAllocateClosure(AllocateClosure instr) =>
|
||||
InstructionConstraints(
|
||||
AllocationStub.resultReg,
|
||||
List<Constraint?>.generate(
|
||||
instr.inputCount,
|
||||
(int i) => anyLocationOrImmediate(instr.inputDefAt(i)),
|
||||
),
|
||||
const [
|
||||
AllocationStub.tagsReg,
|
||||
AllocationStub.scratch1Reg,
|
||||
AllocationStub.scratch2Reg,
|
||||
],
|
||||
);
|
||||
const InstructionConstraints(AllocationStub.resultReg, [], [
|
||||
AllocationStub.tagsReg,
|
||||
AllocationStub.scratch1Reg,
|
||||
AllocationStub.scratch2Reg,
|
||||
]);
|
||||
|
||||
@override
|
||||
InstructionConstraints? visitAllocateContext(AllocateContext instr) =>
|
||||
|
||||
@@ -150,35 +150,3 @@ bool hasNonTrivialInitializer(ast.Field field) {
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if [type] references class type parameters.
|
||||
bool containsClassTypeParameters(ast.DartType type) {
|
||||
final visitor = _FindClassTypeParameters();
|
||||
type.accept(visitor);
|
||||
return visitor.containsClassTypeParams;
|
||||
}
|
||||
|
||||
class _FindClassTypeParameters extends ast.RecursiveVisitor {
|
||||
bool containsClassTypeParams = false;
|
||||
|
||||
_FindClassTypeParameters();
|
||||
|
||||
@override
|
||||
void visitTypeParameterType(ast.TypeParameterType node) {
|
||||
if (node.parameter.declaration is ast.Class) {
|
||||
containsClassTypeParams = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool hasGenericEnclosingFunction(ast.TreeNode node) {
|
||||
for (;;) {
|
||||
node = node.parent!;
|
||||
if (node is ast.Member) {
|
||||
return false;
|
||||
}
|
||||
if (node is ast.FunctionNode && node.typeParameters.isNotEmpty) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -506,7 +506,7 @@ B0 = EntryBlock() dominates:(B11, B10)
|
||||
v3 = Parameter(compare) # RA: R2 <- ()
|
||||
v4 = Parameter(isValidKey) # RA: R3 <- ()
|
||||
ParallelMove output(R3 -> vloc:R10, R2 -> vloc:R9, R1 -> vloc:R6, R0 -> vloc:R5)
|
||||
ParallelMove spill(R6 -> stack[0])
|
||||
ParallelMove spill(R5 -> stack[0], R6 -> stack[1])
|
||||
ParallelMove input(vloc:R6 -> R0, NullConstant(null) -> R2, vloc:R5 -> R1)
|
||||
v9 = TypeTest(v2, v8, v1, Map<SplayTreeMap.from.K%, SplayTreeMap.from.V%>) # RA: R7 <- (R0, R2, R1) temps: [R8, R3, R4]
|
||||
ParallelMove output(R7 -> vloc:R7)
|
||||
@@ -527,12 +527,14 @@ B11 = TargetBlock() idom:B0
|
||||
ParallelMove input(vloc:R1 -> R1)
|
||||
v23 = AllocateObject SplayTreeMap<SplayTreeMap.from.K%, SplayTreeMap.from.V%>(v22) # RA: R0 <- (R1) temps: [R2, R3, R4]
|
||||
ParallelMove output(R0 -> vloc:R0)
|
||||
ParallelMove spill(R0 -> stack[1])
|
||||
ParallelMove spill(R0 -> stack[2])
|
||||
DirectCall SplayTreeMap.(v23, v3, v4) # RA: R0 <- (R0, R9, R10) temps: [R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, R19, R20, R23, R25, V0, V1, V2, V3, V4, V5, V6, V7, V8, V9, V10, V11, V12, V13, V14, V15, V16, V17, V18, V19, V20, V21, V22, V23, V24, V25, V26, V27, V28, V29, V30]
|
||||
v29 = AllocateClosure() # RA: R0 <- () temps: [R2, R3, R4]
|
||||
ParallelMove output(R0 -> vloc:R0, stack[0] -> R1)
|
||||
InterfaceCall Map.forEach(v2, v29) # RA: R0 <- (R1, R0) temps: [R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, R19, R20, R23, R25, V0, V1, V2, V3, V4, V5, V6, V7, V8, V9, V10, V11, V12, V13, V14, V15, V16, V17, V18, V19, V20, V21, V22, V23, V24, V25, V26, V27, V28, V29, V30]
|
||||
ParallelMove output(R0 -> vloc:R0, stack[0] -> R3)
|
||||
StoreInstanceField(#closure-field[0], v29, v1) # RA: (R0, R3) temps: [R1, R2]
|
||||
ParallelMove output(stack[1] -> R1)
|
||||
InterfaceCall Map.forEach(v2, v29) # RA: R0 <- (R1, R0) temps: [R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, R19, R20, R23, R25, V0, V1, V2, V3, V4, V5, V6, V7, V8, V9, V10, V11, V12, V13, V14, V15, V16, V17, V18, V19, V20, V21, V22, V23, V24, V25, V26, V27, V28, V29, V30]
|
||||
ParallelMove output(stack[2] -> R1)
|
||||
ParallelMove input(vloc:R1 -> R0)
|
||||
Return(v23) # RA: (R0)
|
||||
|
||||
@@ -1784,7 +1786,7 @@ B0 = EntryBlock()
|
||||
|
||||
--- closures
|
||||
B0 = EntryBlock()
|
||||
v9 = Constant(null)
|
||||
v11 = Constant(null)
|
||||
Parameter(a1) # RA: R0 <- ()
|
||||
v2 = Parameter(a2) # RA: R1 <- ()
|
||||
ParallelMove output(R1 -> vloc:R1)
|
||||
@@ -1792,13 +1794,16 @@ B0 = EntryBlock()
|
||||
ParallelMove output(R0 -> vloc:R0)
|
||||
StoreInstanceField(#context-field:a2, v3, v2) # RA: (R0, R1) temps: [R2, R3]
|
||||
ParallelMove output(R0 -> R1)
|
||||
v6 = AllocateClosure(v3) # RA: R0 <- (R1) temps: [R2, R3, R4]
|
||||
ParallelMove output(R0 -> vloc:R5)
|
||||
v7 = AllocateClosure(v3) # RA: R0 <- (R1) temps: [R2, R3, R4]
|
||||
v6 = AllocateClosure() # RA: R0 <- () temps: [R2, R3, R4]
|
||||
ParallelMove output(R0 -> vloc:R0)
|
||||
DirectCall foo2(v6, v7) # RA: R0 <- (R5, R0) temps: [R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, R19, R20, R23, R25, V0, V1, V2, V3, V4, V5, V6, V7, V8, V9, V10, V11, V12, V13, V14, V15, V16, V17, V18, V19, V20, V21, V22, V23, V24, V25, V26, V27, V28, V29, V30]
|
||||
StoreInstanceField(#closure-field[0], v6, v3) # RA: (R0, R1) temps: [R2, R3]
|
||||
ParallelMove output(R0 -> R5)
|
||||
v8 = AllocateClosure() # RA: R0 <- () temps: [R2, R3, R4]
|
||||
ParallelMove output(R0 -> vloc:R0)
|
||||
StoreInstanceField(#closure-field[0], v8, v3) # RA: (R0, R1) temps: [R2, R3]
|
||||
DirectCall foo2(v6, v8) # RA: R0 <- (R5, R0) temps: [R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, R19, R20, R23, R25, V0, V1, V2, V3, V4, V5, V6, V7, V8, V9, V10, V11, V12, V13, V14, V15, V16, V17, V18, V19, V20, V21, V22, V23, V24, V25, V26, V27, V28, V29, V30]
|
||||
ParallelMove input(NullConstant(null) -> R0)
|
||||
Return(v9) # RA: (R0)
|
||||
Return(v11) # RA: (R0)
|
||||
|
||||
--- closure FunctionExpression(Null (dynamic _#wc0#formal) {
|
||||
print(a2);
|
||||
|
||||
Reference in New Issue
Block a user