Skip to content

Commit d66cf50

Browse files
Implement return_call execution
1 parent b32dbca commit d66cf50

File tree

10 files changed

+1030
-774
lines changed

10 files changed

+1030
-774
lines changed

Sources/WasmKit/Execution/DispatchInstruction.swift

Lines changed: 206 additions & 189 deletions
Large diffs are not rendered by default.

Sources/WasmKit/Execution/Execution.swift

Lines changed: 65 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,20 @@ struct Execution {
7878
return Backtrace(symbols: symbols)
7979
}
8080

81+
private func initializeConstSlots(
82+
sp: Sp, iseq: InstructionSequence,
83+
numberOfNonParameterLocals: Int
84+
) {
85+
// Initialize the locals with zeros (all types of value have the same representation)
86+
sp.initialize(repeating: UntypedValue.default.storage, count: numberOfNonParameterLocals)
87+
if let constants = iseq.constants.baseAddress {
88+
let count = iseq.constants.count
89+
sp.advanced(by: numberOfNonParameterLocals).withMemoryRebound(to: UntypedValue.self, capacity: count) {
90+
$0.initialize(from: constants, count: count)
91+
}
92+
}
93+
}
94+
8195
/// Pushes a new call frame to the VM stack.
8296
@inline(__always)
8397
func pushFrame(
@@ -88,17 +102,8 @@ struct Execution {
88102
spAddend: VReg
89103
) throws -> Sp {
90104
let newSp = sp.advanced(by: Int(spAddend))
91-
guard newSp.advanced(by: iseq.maxStackHeight) < stackEnd else {
92-
throw Trap(.callStackExhausted)
93-
}
94-
// Initialize the locals with zeros (all types of value have the same representation)
95-
newSp.initialize(repeating: UntypedValue.default.storage, count: numberOfNonParameterLocals)
96-
if let constants = iseq.constants.baseAddress {
97-
let count = iseq.constants.count
98-
newSp.advanced(by: numberOfNonParameterLocals).withMemoryRebound(to: UntypedValue.self, capacity: count) {
99-
$0.initialize(from: constants, count: count)
100-
}
101-
}
105+
try checkStackBoundary(newSp.advanced(by: iseq.maxStackHeight))
106+
initializeConstSlots(sp: newSp, iseq: iseq, numberOfNonParameterLocals: numberOfNonParameterLocals)
102107
newSp.previousSP = sp
103108
newSp.returnPC = returnPC
104109
newSp.currentFunction = function
@@ -505,6 +510,11 @@ extension Execution {
505510
self.trap = (rawError, sp)
506511
}
507512

513+
@inline(__always)
514+
func checkStackBoundary(_ sp: Sp) throws {
515+
guard sp < stackEnd else { throw Trap(.callStackExhausted) }
516+
}
517+
508518
/// Returns the new program counter and stack pointer.
509519
@inline(never)
510520
func invoke(
@@ -524,6 +534,50 @@ extension Execution {
524534
}
525535
}
526536

537+
@inline(never)
538+
func tailInvoke(
539+
function: InternalFunction,
540+
callerInstance: InternalInstance?,
541+
spAddend: VReg,
542+
sp: Sp, pc: Pc, md: inout Md, ms: inout Ms
543+
) throws -> (Pc, Sp) {
544+
if function.isWasm {
545+
return try tailInvokeWasmFunction(
546+
function: function.wasm, callerInstance: callerInstance,
547+
spAddend: spAddend,
548+
sp: sp, md: &md, ms: &ms
549+
)
550+
} else {
551+
try invokeHostFunction(function: function.host, sp: sp, spAddend: spAddend)
552+
return (pc, sp)
553+
}
554+
}
555+
556+
/// Executes the given wasm function while overwriting the current frame.
557+
///
558+
/// Precondition: The frame header must be already resized to be compatible
559+
/// with the callee's frame header layout.
560+
@inline(__always)
561+
private func tailInvokeWasmFunction(
562+
function: EntityHandle<WasmFunctionEntity>,
563+
callerInstance: InternalInstance?,
564+
spAddend: VReg,
565+
sp: Sp, md: inout Md, ms: inout Ms
566+
) throws -> (Pc, Sp) {
567+
let iseq = try function.ensureCompiled(store: store)
568+
let newSp = sp.advanced(by: Int(spAddend))
569+
try checkStackBoundary(newSp.advanced(by: iseq.maxStackHeight))
570+
newSp.currentFunction = function
571+
572+
initializeConstSlots(sp: newSp, iseq: iseq, numberOfNonParameterLocals: function.numberOfNonParameterLocals)
573+
574+
Execution.CurrentMemory.mayUpdateCurrentInstance(
575+
instance: function.instance,
576+
from: callerInstance, md: &md, ms: &ms
577+
)
578+
return (iseq.baseAddress, newSp)
579+
}
580+
527581
/// Executes the given WebAssembly function.
528582
@inline(__always)
529583
private func invokeWasmFunction(

Sources/WasmKit/Execution/Instructions/Control.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,26 @@ extension Execution {
151151
)
152152
return pc.next()
153153
}
154+
155+
mutating func returnCall(sp: inout Sp, pc: Pc, md: inout Md, ms: inout Ms, immediate: Instruction.ReturnCallOperand) throws -> (Pc, CodeSlot) {
156+
var pc = pc
157+
(pc, sp) = try tailInvoke(
158+
function: immediate.callee,
159+
callerInstance: currentInstance(sp: sp),
160+
spAddend: 0,
161+
sp: sp, pc: pc, md: &md, ms: &ms
162+
)
163+
return pc.next()
164+
}
165+
166+
mutating func resizeFrameHeader(sp: inout Sp, immediate: Instruction.ResizeFrameHeaderOperand) throws {
167+
let newSp = sp.advanced(by: Int(immediate.delta))
168+
try checkStackBoundary(newSp)
169+
let oldFrameHeader = sp.advanced(by: -FrameHeaderLayout.numberOfSavingSlots)
170+
let newFrameHeader = newSp.advanced(by: -FrameHeaderLayout.numberOfSavingSlots)
171+
newFrameHeader.update(from: oldFrameHeader, count: Int(immediate.sizeToCopy))
172+
sp = newSp
173+
}
154174

155175
mutating func onEnter(sp: Sp, immediate: Instruction.OnEnterOperand) {
156176
let function = currentInstance(sp: sp).functions[Int(immediate)]

0 commit comments

Comments
 (0)