[x64] Fix up unwind info for emitted functions.
- [x64] Track size of code within emitted functions (prolog, body, epilog). - [x64] Don't use hardcoded prolog size in generated unwind info. - [x64] Update URLs to MSDN documentation on UNWIND_INFO/UNWIND_CODE.
This commit is contained in:
@@ -102,14 +102,14 @@ bool X64Emitter::Emit(GuestFunction* function, HIRBuilder* builder,
|
||||
source_map_arena_.Reset();
|
||||
|
||||
// Fill the generator with code.
|
||||
size_t stack_size = 0;
|
||||
if (!Emit(builder, &stack_size)) {
|
||||
EmitFunctionInfo func_info = {};
|
||||
if (!Emit(builder, func_info)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Copy the final code to the cache and relocate it.
|
||||
*out_code_size = getSize();
|
||||
*out_code_address = Emplace(stack_size, function);
|
||||
*out_code_address = Emplace(func_info, function);
|
||||
|
||||
// Stash source map.
|
||||
source_map_arena_.CloneContents(out_source_map);
|
||||
@@ -117,18 +117,20 @@ bool X64Emitter::Emit(GuestFunction* function, HIRBuilder* builder,
|
||||
return true;
|
||||
}
|
||||
|
||||
void* X64Emitter::Emplace(size_t stack_size, GuestFunction* function) {
|
||||
void* X64Emitter::Emplace(const EmitFunctionInfo& func_info,
|
||||
GuestFunction* function) {
|
||||
// To avoid changing xbyak, we do a switcharoo here.
|
||||
// top_ points to the Xbyak buffer, and since we are in AutoGrow mode
|
||||
// it has pending relocations. We copy the top_ to our buffer, swap the
|
||||
// pointer, relocate, then return the original scratch pointer for use.
|
||||
uint8_t* old_address = top_;
|
||||
void* new_address;
|
||||
assert_true(func_info.code_size.total == size_);
|
||||
if (function) {
|
||||
new_address = code_cache_->PlaceGuestCode(function->address(), top_, size_,
|
||||
stack_size, function);
|
||||
new_address = code_cache_->PlaceGuestCode(function->address(), top_,
|
||||
func_info, function);
|
||||
} else {
|
||||
new_address = code_cache_->PlaceHostCode(0, top_, size_, stack_size);
|
||||
new_address = code_cache_->PlaceHostCode(0, top_, func_info);
|
||||
}
|
||||
top_ = reinterpret_cast<uint8_t*>(new_address);
|
||||
ready();
|
||||
@@ -137,7 +139,7 @@ void* X64Emitter::Emplace(size_t stack_size, GuestFunction* function) {
|
||||
return new_address;
|
||||
}
|
||||
|
||||
bool X64Emitter::Emit(HIRBuilder* builder, size_t* out_stack_size) {
|
||||
bool X64Emitter::Emit(HIRBuilder* builder, EmitFunctionInfo& func_info) {
|
||||
Xbyak::Label epilog_label;
|
||||
epilog_label_ = &epilog_label;
|
||||
|
||||
@@ -159,6 +161,15 @@ bool X64Emitter::Emit(HIRBuilder* builder, size_t* out_stack_size) {
|
||||
stack_offset -= StackLayout::GUEST_STACK_SIZE;
|
||||
stack_offset = xe::align(stack_offset, static_cast<size_t>(16));
|
||||
|
||||
struct _code_offsets {
|
||||
size_t prolog;
|
||||
size_t body;
|
||||
size_t epilog;
|
||||
size_t tail;
|
||||
} code_offsets = {};
|
||||
|
||||
code_offsets.prolog = getSize();
|
||||
|
||||
// Function prolog.
|
||||
// Must be 16b aligned.
|
||||
// Windows is very strict about the form of this and the epilog:
|
||||
@@ -168,7 +179,7 @@ bool X64Emitter::Emit(HIRBuilder* builder, size_t* out_stack_size) {
|
||||
// Adding or changing anything here must be matched!
|
||||
const size_t stack_size = StackLayout::GUEST_STACK_SIZE + stack_offset;
|
||||
assert_true((stack_size + 8) % 16 == 0);
|
||||
*out_stack_size = stack_size;
|
||||
func_info.stack_size = stack_size;
|
||||
stack_size_ = stack_size;
|
||||
|
||||
sub(rsp, (uint32_t)stack_size);
|
||||
@@ -208,6 +219,8 @@ bool X64Emitter::Emit(HIRBuilder* builder, size_t* out_stack_size) {
|
||||
mov(GetMembaseReg(),
|
||||
qword[GetContextReg() + offsetof(ppc::PPCContext, virtual_membase)]);
|
||||
|
||||
code_offsets.body = getSize();
|
||||
|
||||
// Body.
|
||||
auto block = builder->first_block();
|
||||
while (block) {
|
||||
@@ -236,6 +249,8 @@ bool X64Emitter::Emit(HIRBuilder* builder, size_t* out_stack_size) {
|
||||
block = block->next;
|
||||
}
|
||||
|
||||
code_offsets.epilog = getSize();
|
||||
|
||||
// Function epilog.
|
||||
L(epilog_label);
|
||||
epilog_label_ = nullptr;
|
||||
@@ -244,6 +259,8 @@ bool X64Emitter::Emit(HIRBuilder* builder, size_t* out_stack_size) {
|
||||
add(rsp, (uint32_t)stack_size);
|
||||
ret();
|
||||
|
||||
code_offsets.tail = getSize();
|
||||
|
||||
if (cvars::emit_source_annotations) {
|
||||
nop();
|
||||
nop();
|
||||
@@ -252,6 +269,13 @@ bool X64Emitter::Emit(HIRBuilder* builder, size_t* out_stack_size) {
|
||||
nop();
|
||||
}
|
||||
|
||||
assert_zero(code_offsets.prolog);
|
||||
func_info.code_size.total = getSize();
|
||||
func_info.code_size.prolog = code_offsets.body - code_offsets.prolog;
|
||||
func_info.code_size.body = code_offsets.epilog - code_offsets.body;
|
||||
func_info.code_size.epilog = code_offsets.tail - code_offsets.epilog;
|
||||
func_info.code_size.tail = getSize() - code_offsets.tail;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user