Skip to content

Commit

Permalink
[dart2wasm] Use a Wasm array directly in chunked JSON parser state stack
Browse files Browse the repository at this point in the history
Update `popWasmArray` desugaring to only clear the popped slot when the
element type is nullable.

Use `push/popWasmArray` in `_ChunkedJsonParserState.states` stack to
avoid indirection.

Change-Id: I641b4a78b85640b3676ef935bfd98b8cd5f7789d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/394483
Reviewed-by: Slava Egorov <[email protected]>
Commit-Queue: Ömer Ağacan <[email protected]>
  • Loading branch information
osa1 authored and Commit Queue committed Nov 13, 2024
1 parent fd35dc4 commit 34a6cbc
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 15 deletions.
26 changes: 16 additions & 10 deletions pkg/dart2wasm/lib/transformers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -962,8 +962,8 @@ class PushPopWasmArrayTransformer {

Expression _transformPopWasmArray(StaticInvocation invocation) {
final elementType = invocation.arguments.types[0] as InterfaceType;
final elementTypeNullable =
elementType.withDeclaredNullability(Nullability.nullable);
final elementIsNullable =
elementType.nullability != Nullability.nonNullable;

final positionalArguments = invocation.arguments.positional;
assert(positionalArguments.length == 2);
Expand Down Expand Up @@ -991,6 +991,8 @@ class PushPopWasmArrayTransformer {
return cloner.clone(node);
}

final List<Statement> blockStatements = [];

// length - 1
final intSubtractType = _intSubtract.computeSignatureOrFunctionType();
final lengthMinusOne = InstanceInvocation(InstanceAccessKind.Instance,
Expand All @@ -1008,24 +1010,28 @@ class PushPopWasmArrayTransformer {
arrayLengthUpdate = ExpressionStatement(
VariableSet(lengthVariableGet.variable, lengthMinusOne));
}
blockStatements.add(arrayLengthUpdate);

// array[length]
final arrayGet = StaticInvocation(_wasmArrayElementGet,
Arguments([clone(array), clone(length)], types: [elementTypeNullable]));
Arguments([clone(array), clone(length)], types: [elementType]));

// final temp = array[length]
final arrayGetVariable = VariableDeclaration.forValue(arrayGet,
isFinal: true, type: elementTypeNullable);
isFinal: true, type: elementType);
blockStatements.add(arrayGetVariable);

// array[length] = null
final arrayClearElement = ExpressionStatement(StaticInvocation(
_wasmArrayElementSet,
Arguments([clone(array), clone(length), NullLiteral()],
types: [elementTypeNullable])));
if (elementIsNullable) {
final arrayClearElement = ExpressionStatement(StaticInvocation(
_wasmArrayElementSet,
Arguments([clone(array), clone(length), NullLiteral()],
types: [elementType])));
blockStatements.add(arrayClearElement);
}

return BlockExpression(
Block([arrayLengthUpdate, arrayGetVariable, arrayClearElement]),
VariableGet(arrayGetVariable));
Block(blockStatements), VariableGet(arrayGetVariable));
}
}

Expand Down
19 changes: 15 additions & 4 deletions sdk/lib/_internal/wasm/lib/convert_patch.dart
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ class _JsonListener {

GrowableList<dynamic>? stackPop() {
assert(stackLength != 0);
return popWasmArray<GrowableList<dynamic>>(stack, stackLength);
return popWasmArray<GrowableList<dynamic>?>(stack, stackLength);
}

/** Contents of the current container being built, or null if not building a
Expand Down Expand Up @@ -328,7 +328,9 @@ abstract class _ChunkedJsonParserState {

// The current parsing state.
int state = _ChunkedJsonParser.STATE_INITIAL;
GrowableList<int> states = GrowableList<int>.empty();

WasmArray<WasmI64> states = WasmArray<WasmI64>(0);
int statesLength = 0;

/**
* Stores tokenizer state between chunks.
Expand Down Expand Up @@ -390,6 +392,7 @@ abstract class _ChunkedJsonParserState {
) {
state = chunkedParserState.state;
states = chunkedParserState.states;
statesLength = chunkedParserState.statesLength;
partialState = chunkedParserState.partialState;
_stringBuffer = chunkedParserState._stringBuffer;
_numberBuffer = chunkedParserState._numberBuffer;
Expand All @@ -402,13 +405,21 @@ abstract class _ChunkedJsonParserState {
* so the parser can go back to the correct value when the literal ends.
*/
void saveState(int state) {
states.add(state);
pushWasmArray<WasmI64>(
states,
statesLength,
state.toWasmI64(),
(statesLength * 2) | 3,
);
}

/**
* Restore a state pushed with [saveState].
*/
int restoreState() => states.removeLast(); // Throws if empty.
int restoreState() {
assert(statesLength > 0);
return popWasmArray<WasmI64>(states, statesLength).toInt();
}

/**
* Read out the result after successfully closing the parser.
Expand Down
6 changes: 5 additions & 1 deletion sdk/lib/_internal/wasm/lib/internal_patch.dart
Original file line number Diff line number Diff line change
Expand Up @@ -226,4 +226,8 @@ external void pushWasmArray<T>(
);

/// Similar to `pushWasmArray`, but for popping.
external T? popWasmArray<T>(WasmArray<T?> array, int length);
///
/// Note that when [T] is not nullable, this does not clear the popped element
/// slot in the array, which may cause memory leaks. Callers should manually
/// clear non-nullable reference element slots in the array when popping.
external T popWasmArray<T>(WasmArray<T> array, int length);

0 comments on commit 34a6cbc

Please sign in to comment.