- Notifications
You must be signed in to change notification settings - Fork396
Description
Currently, all class fields are mutable at the Wasm level: thegenFunctionID.newDefault
function creates a class instance with fields initialized to their zero values, and then the constructor initializes them (byAssign
at the IR level).
scala-js/linker/shared/src/main/scala/org/scalajs/linker/backend/wasmemitter/ClassEmitter.scala
Lines 351 to 358 in4c9494e
valfields= classInfo.allFieldDefs.map { field=> | |
watpe.StructField( | |
genFieldID.forClassInstanceField(field.name.name), | |
makeDebugName(ns.InstanceField, field.name.name), | |
transformFieldType(field.ftpe), | |
isMutable=true// initialized by the constructors, so always mutable at the Wasm level | |
) | |
} |
Fields being mutable means that accessing a field is an impure operation at the Wasm level, causing us to miss some optimization opportunities.
In fact, making itables immutable has improved performance in some benchmarks, as seen in#5038.
We may want to "merge" thegenFunctionID.newDefault
function with the constructor: The fused constructor would:
- Set up the vtable (virtual method table) and itable (interface table)
- Initialize the fields
- Instead of filling fields with zero values, the
wasmemitter
would transform the RHS of fieldAssign
nodes to become the initial values of the fields.
- Instead of filling fields with zero values, the
- Execute
struct.new
for instantiation (asnewDefault
currently does)
Alternatively, should we modify the IR structure somehow? It appears that theseAssign
operations in the constructor originate from Scala compiler, not fromGenJSCode
🤷. In this case, making changes at the IR level seems introduce more complications than it solves.