Implement registering JIT unwind information on Windows.

This commit implements registering unwind information for JIT functions on
Windows so that the operating system can both walk and unwind stacks containing
JIT frames.

Currently this only works with Cranelift as lightbeam does not emit unwind
information yet.

This commit also resets the stack guard page on Windows for stack overflow
exceptions, allowing reliable stack overflow traps.

With these changes, all previously disabled test suite tests (not including
the multi-value tests) on Windows are now passing.

Fixes #291.
This commit is contained in:
Peter Huene
2019-10-19 13:12:04 -07:00
parent ab80785c05
commit 920728d14d
16 changed files with 382 additions and 131 deletions

View File

@@ -12,17 +12,20 @@ use serde::{Deserialize, Serialize};
use std::ops::Range;
use thiserror::Error;
/// Compiled machine code: body and jump table offsets.
/// Compiled function: machine code body, jump table offsets, and unwind information.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
pub struct CodeAndJTOffsets {
pub struct CompiledFunction {
/// The function body.
pub body: Vec<u8>,
/// The jump tables offsets (in the body).
pub jt_offsets: ir::JumpTableOffsets,
/// The unwind information.
pub unwind_info: Vec<u8>,
}
type Functions = PrimaryMap<DefinedFuncIndex, CodeAndJTOffsets>;
type Functions = PrimaryMap<DefinedFuncIndex, CompiledFunction>;
/// The result of compiling a WebAssembly module's functions.
#[derive(Deserialize, Serialize, Debug, PartialEq, Eq)]
@@ -40,21 +43,22 @@ impl Compilation {
/// Allocates the compilation result with the given function bodies.
pub fn from_buffer(
buffer: Vec<u8>,
functions: impl IntoIterator<Item = (Range<usize>, ir::JumpTableOffsets)>,
functions: impl IntoIterator<Item = (Range<usize>, ir::JumpTableOffsets, Range<usize>)>,
) -> Self {
Self::new(
functions
.into_iter()
.map(|(range, jt_offsets)| CodeAndJTOffsets {
body: buffer[range].to_vec(),
.map(|(body_range, jt_offsets, unwind_range)| CompiledFunction {
body: buffer[body_range].to_vec(),
jt_offsets,
unwind_info: buffer[unwind_range].to_vec(),
})
.collect(),
)
}
/// Gets the bytes of a single function
pub fn get(&self, func: DefinedFuncIndex) -> &CodeAndJTOffsets {
pub fn get(&self, func: DefinedFuncIndex) -> &CompiledFunction {
&self.functions[func]
}
@@ -67,7 +71,7 @@ impl Compilation {
pub fn get_jt_offsets(&self) -> PrimaryMap<DefinedFuncIndex, ir::JumpTableOffsets> {
self.functions
.iter()
.map(|(_, code_and_jt)| code_and_jt.jt_offsets.clone())
.map(|(_, func)| func.jt_offsets.clone())
.collect::<PrimaryMap<DefinedFuncIndex, _>>()
}
}
@@ -88,7 +92,7 @@ pub struct Iter<'a> {
}
impl<'a> Iterator for Iter<'a> {
type Item = &'a CodeAndJTOffsets;
type Item = &'a CompiledFunction;
fn next(&mut self) -> Option<Self::Item> {
self.iterator.next().map(|(_, b)| b)