[dart2wasm] Generate local names in the names section
Local names for function value parameters and for "precise this", return values are generated, state indices in `async` and `sync*` functions are generated. We can generate names for more locals as needed. Change-Id: Ie919f030f0bfae8adbca90408509dd04a7414278 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/419200 Commit-Queue: Ömer Ağacan <omersa@google.com> Reviewed-by: Martin Kustermann <kustermann@google.com>
This commit is contained in:
committed by
Commit Queue
parent
52da6a0037
commit
82282b6287
@@ -26,8 +26,9 @@ mixin AsyncCodeGeneratorMixin on StateMachineEntryAstCodeGenerator {
|
||||
|
||||
// (1) Create async state.
|
||||
|
||||
final asyncStateLocal =
|
||||
b.addLocal(w.RefType(asyncSuspendStateInfo.struct, nullable: false));
|
||||
final asyncStateLocal = b.addLocal(
|
||||
w.RefType(asyncSuspendStateInfo.struct, nullable: false),
|
||||
name: "asyncState");
|
||||
|
||||
// AsyncResumeFun _resume
|
||||
translator.globals.readGlobal(b, translator.makeFunctionRef(resumeFun));
|
||||
@@ -195,13 +196,16 @@ class AsyncStateMachineCodeGenerator extends StateMachineCodeGenerator {
|
||||
Context? localContext = context;
|
||||
while (localContext != null) {
|
||||
if (!localContext.isEmpty) {
|
||||
localContext.currentLocal =
|
||||
b.addLocal(w.RefType.def(localContext.struct, nullable: true));
|
||||
localContext.currentLocal = b.addLocal(
|
||||
w.RefType.def(localContext.struct, nullable: true),
|
||||
name: "context");
|
||||
if (localContext.containsThis) {
|
||||
assert(thisLocal == null);
|
||||
thisLocal = b.addLocal(localContext
|
||||
.struct.fields[localContext.thisFieldIndex].type.unpacked
|
||||
.withNullability(false));
|
||||
thisLocal = b.addLocal(
|
||||
localContext
|
||||
.struct.fields[localContext.thisFieldIndex].type.unpacked
|
||||
.withNullability(false),
|
||||
name: "this");
|
||||
translator
|
||||
.getDummyValuesCollectorForModule(b.module)
|
||||
.instantiateDummyValue(b, thisLocal!.type);
|
||||
@@ -214,7 +218,7 @@ class AsyncStateMachineCodeGenerator extends StateMachineCodeGenerator {
|
||||
}
|
||||
|
||||
// Read target index from the suspend state.
|
||||
targetIndexLocal = addLocal(w.NumType.i32);
|
||||
targetIndexLocal = addLocal(w.NumType.i32, name: "targetIndex");
|
||||
b.local_get(_suspendStateLocal);
|
||||
b.struct_get(
|
||||
asyncSuspendStateInfo.struct, FieldIndex.asyncSuspendStateTargetIndex);
|
||||
|
||||
@@ -115,9 +115,8 @@ abstract class AstCodeGenerator
|
||||
|
||||
w.ValueType translateType(DartType type) => translator.translateType(type);
|
||||
|
||||
w.Local addLocal(w.ValueType type) {
|
||||
return b.addLocal(type);
|
||||
}
|
||||
w.Local addLocal(w.ValueType type, {String? name}) =>
|
||||
b.addLocal(type, name: name);
|
||||
|
||||
DartType dartTypeOf(Expression exp) {
|
||||
if (exp is ConstantExpression) {
|
||||
@@ -257,7 +256,12 @@ abstract class AstCodeGenerator
|
||||
int index,
|
||||
Constant? defaultValue,
|
||||
bool isRequired) {
|
||||
w.Local local = paramLocals[implicitParams + index];
|
||||
final localIndex = implicitParams + index;
|
||||
w.Local local = paramLocals[localIndex];
|
||||
final variableName = variable.name;
|
||||
if (variableName != null) {
|
||||
b.localNames[local.index] = variableName;
|
||||
}
|
||||
if (defaultValue == ParameterInfo.defaultValueSentinel) {
|
||||
// The default value for this parameter differs between implementations
|
||||
// within the same selector. This means that callers will pass the
|
||||
@@ -357,7 +361,8 @@ abstract class AstCodeGenerator
|
||||
if (local.type == w.RefType.extern(nullable: true) &&
|
||||
!(parameterType is InterfaceType &&
|
||||
parameterType.classNode == translator.wasmExternRefClass)) {
|
||||
w.Local newLocal = addLocal(translateType(parameterType));
|
||||
w.Local newLocal =
|
||||
addLocal(translateType(parameterType), name: parameter.name);
|
||||
b.local_get(local);
|
||||
translator.convertType(b, local.type, newLocal.type);
|
||||
b.local_set(newLocal);
|
||||
@@ -490,9 +495,10 @@ abstract class AstCodeGenerator
|
||||
member.isInstanceMember || reference.isConstructorBodyReference;
|
||||
if (hasThis) {
|
||||
thisLocal = paramLocals[0];
|
||||
b.localNames[thisLocal!.index] = "this";
|
||||
final preciseThisType = translator.preciseThisFor(member);
|
||||
if (translator.needsConversion(thisLocal!.type, preciseThisType)) {
|
||||
preciseThisLocal = addLocal(preciseThisType);
|
||||
preciseThisLocal = addLocal(preciseThisType, name: "preciseThis");
|
||||
b.local_get(thisLocal!);
|
||||
translator.convertType(b, thisLocal!.type, preciseThisType);
|
||||
b.local_set(preciseThisLocal!);
|
||||
@@ -537,9 +543,10 @@ abstract class AstCodeGenerator
|
||||
}
|
||||
|
||||
if (context.containsThis) {
|
||||
thisLocal = addLocal(context
|
||||
.struct.fields[context.thisFieldIndex].type.unpacked
|
||||
.withNullability(false));
|
||||
thisLocal = addLocal(
|
||||
context.struct.fields[context.thisFieldIndex].type.unpacked
|
||||
.withNullability(false),
|
||||
name: "this");
|
||||
preciseThisLocal = thisLocal;
|
||||
|
||||
b.struct_get(context.struct, context.thisFieldIndex);
|
||||
@@ -794,7 +801,7 @@ abstract class AstCodeGenerator
|
||||
w.Local? local;
|
||||
Capture? capture = closures.captures[node];
|
||||
if (capture == null || !capture.written) {
|
||||
local = addLocal(type);
|
||||
local = addLocal(type, name: node.name);
|
||||
locals[node] = local;
|
||||
}
|
||||
|
||||
@@ -836,7 +843,7 @@ abstract class AstCodeGenerator
|
||||
w.Local? local;
|
||||
final Capture? capture = closures.captures[node];
|
||||
if (capture == null || !capture.written) {
|
||||
local = addLocal(type);
|
||||
local = addLocal(type, name: node.name);
|
||||
locals[node] = local;
|
||||
}
|
||||
|
||||
@@ -1352,7 +1359,8 @@ abstract class AstCodeGenerator
|
||||
// Since the flow of the return value through the returnValueLocal
|
||||
// crosses control-flow constructs, the local needs to always have a
|
||||
// defaultable type in order for the Wasm code to validate.
|
||||
returnValueLocal ??= addLocal(returnType.withNullability(true));
|
||||
returnValueLocal ??=
|
||||
addLocal(returnType.withNullability(true), name: "returnValue");
|
||||
b.local_set(returnValueLocal!);
|
||||
}
|
||||
b.br(returnFinalizers.last.label);
|
||||
|
||||
@@ -1761,7 +1761,8 @@ class Intrinsifier {
|
||||
w.ArrayType arrayType =
|
||||
(functionType.outputs.single as w.RefType).heapType as w.ArrayType;
|
||||
w.Local object = paramLocals[0];
|
||||
w.Local preciseObject = codeGen.addLocal(classInfo.nonNullableType);
|
||||
w.Local preciseObject =
|
||||
codeGen.addLocal(classInfo.nonNullableType, name: "this");
|
||||
b.local_get(object);
|
||||
b.ref_cast(classInfo.nonNullableType);
|
||||
b.local_set(preciseObject);
|
||||
|
||||
@@ -168,13 +168,16 @@ class SyncStarStateMachineCodeGenerator extends StateMachineCodeGenerator {
|
||||
Context? localContext = context;
|
||||
while (localContext != null) {
|
||||
if (!localContext.isEmpty) {
|
||||
localContext.currentLocal =
|
||||
b.addLocal(w.RefType.def(localContext.struct, nullable: true));
|
||||
localContext.currentLocal = b.addLocal(
|
||||
w.RefType.def(localContext.struct, nullable: true),
|
||||
name: "context");
|
||||
if (localContext.containsThis) {
|
||||
assert(thisLocal == null);
|
||||
thisLocal = b.addLocal(localContext
|
||||
.struct.fields[localContext.thisFieldIndex].type.unpacked
|
||||
.withNullability(false));
|
||||
thisLocal = b.addLocal(
|
||||
localContext
|
||||
.struct.fields[localContext.thisFieldIndex].type.unpacked
|
||||
.withNullability(false),
|
||||
name: "this");
|
||||
translator
|
||||
.getDummyValuesCollectorForModule(b.module)
|
||||
.instantiateDummyValue(b, thisLocal!.type);
|
||||
@@ -187,7 +190,7 @@ class SyncStarStateMachineCodeGenerator extends StateMachineCodeGenerator {
|
||||
}
|
||||
|
||||
// Read target index from the suspend state.
|
||||
targetIndexLocal = addLocal(w.NumType.i32);
|
||||
targetIndexLocal = addLocal(w.NumType.i32, name: "targetIndex");
|
||||
b.local_get(_suspendStateLocal);
|
||||
b.struct_get(suspendStateInfo.struct, FieldIndex.suspendStateTargetIndex);
|
||||
b.local_set(targetIndexLocal);
|
||||
|
||||
@@ -171,6 +171,12 @@ class InstructionsBuilder with Builder<ir.Instructions> {
|
||||
/// Locals declared in this body, including parameters.
|
||||
final List<ir.Local> locals = [];
|
||||
|
||||
/// Names of the locals in `locals`.
|
||||
///
|
||||
/// Most of the locals won't have names, so this is a [Map] instead of [List]
|
||||
/// like [locals], with local indices as keys and names as values.
|
||||
final Map<int, String> localNames = {};
|
||||
|
||||
/// Whether a textual trace of the instruction stream should be recorded when
|
||||
/// emitting instructions (provided asserts are enabled).
|
||||
///
|
||||
@@ -251,8 +257,8 @@ class InstructionsBuilder with Builder<ir.Instructions> {
|
||||
}
|
||||
|
||||
@override
|
||||
ir.Instructions forceBuild() => ir.Instructions(
|
||||
locals, _instructions, _stackTraces, _traceLines, _sourceMappings);
|
||||
ir.Instructions forceBuild() => ir.Instructions(locals, localNames,
|
||||
_instructions, _stackTraces, _traceLines, _sourceMappings);
|
||||
|
||||
void _add(ir.Instruction i) {
|
||||
assert(!_constantExpression || i.isConstant,
|
||||
@@ -271,7 +277,11 @@ class InstructionsBuilder with Builder<ir.Instructions> {
|
||||
return local;
|
||||
}
|
||||
|
||||
ir.Local addLocal(ir.ValueType type) {
|
||||
ir.Local addLocal(ir.ValueType type, {String? name}) {
|
||||
if (name != null) {
|
||||
final index = locals.length;
|
||||
localNames[index] = name;
|
||||
}
|
||||
final local = ir.Local(locals.length, type);
|
||||
locals.add(local);
|
||||
_localInitialized.add(type.defaultable);
|
||||
|
||||
@@ -46,6 +46,8 @@ class DefinedFunction extends BaseFunction implements Serializable {
|
||||
/// All local variables defined in the function, including its inputs.
|
||||
List<Local> get locals => body.locals;
|
||||
|
||||
Map<int, String> get localNames => body.localNames;
|
||||
|
||||
DefinedFunction(
|
||||
super.enclosingModule, this.body, super.finalizableIndex, super.type,
|
||||
[super.functionName]);
|
||||
|
||||
@@ -10,6 +10,12 @@ class Instructions implements Serializable {
|
||||
/// The locals used by this group of instructions.
|
||||
final List<Local> locals;
|
||||
|
||||
/// Names of the locals in `locals`.
|
||||
///
|
||||
/// Most of the locals won't have names, so this is a [Map] instead of [List]
|
||||
/// like [locals], with local indices as keys and names as values.
|
||||
final Map<int, String> localNames;
|
||||
|
||||
/// A sequence of Wasm instructions.
|
||||
final List<Instruction> instructions;
|
||||
|
||||
@@ -27,8 +33,8 @@ class Instructions implements Serializable {
|
||||
final List<SourceMapping>? _sourceMappings;
|
||||
|
||||
/// Create a new instruction sequence.
|
||||
Instructions(this.locals, this.instructions, this._stackTraces,
|
||||
this._traceLines, this._sourceMappings);
|
||||
Instructions(this.locals, this.localNames, this.instructions,
|
||||
this._stackTraces, this._traceLines, this._sourceMappings);
|
||||
|
||||
@override
|
||||
void serialize(Serializer s) {
|
||||
|
||||
@@ -471,6 +471,28 @@ class NameSection extends CustomSection {
|
||||
}
|
||||
}
|
||||
|
||||
final localNameSubsection = Serializer();
|
||||
List<ir.DefinedFunction> functionsWithLocalNames = [];
|
||||
for (final function in functions) {
|
||||
if (function is ir.DefinedFunction) {
|
||||
if (function.localNames.isNotEmpty) {
|
||||
functionsWithLocalNames.add(function);
|
||||
}
|
||||
}
|
||||
}
|
||||
localNameSubsection.writeUnsigned(functionsWithLocalNames.length);
|
||||
|
||||
if (functionsWithLocalNames.isNotEmpty) {
|
||||
for (final function in functionsWithLocalNames) {
|
||||
localNameSubsection.writeUnsigned(function.finalizableIndex.value);
|
||||
localNameSubsection.writeUnsigned(function.localNames.length);
|
||||
for (final entry in function.localNames.entries) {
|
||||
localNameSubsection.writeUnsigned(entry.key);
|
||||
localNameSubsection.writeName(entry.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s.writeByte(0); // Module name subsection
|
||||
s.writeUnsigned(moduleNameSubsection.data.length);
|
||||
s.writeData(moduleNameSubsection);
|
||||
@@ -479,6 +501,10 @@ class NameSection extends CustomSection {
|
||||
s.writeUnsigned(functionNameSubsection.data.length);
|
||||
s.writeData(functionNameSubsection);
|
||||
|
||||
s.writeByte(2); // Local names substion
|
||||
s.writeUnsigned(localNameSubsection.data.length);
|
||||
s.writeData(localNameSubsection);
|
||||
|
||||
s.writeByte(4); // Type names subsection
|
||||
s.writeUnsigned(typeNameSubsection.data.length);
|
||||
s.writeData(typeNameSubsection);
|
||||
|
||||
Reference in New Issue
Block a user