Stack Walking subsystem

Introduction

The interface for stack walking is given in stack_walker.h. Various types of the frames are discussed in Native Frames

Rationale

Usage scenarios.

  1. update_code_addresses_for_thread. (on-stack replacement?)

    In case a code block was moved, iterate over the thread stack frames and change the ip in each stack frame.

        StackIterator* iterator = si_create();
        while (!si_over(iterator)) {
            NativeCodePtr old_ip = si_get_ip(iterator);
            NativeCodePtr new_ip = update_address(old_ip);
            si_set_ip(iterator,new_ip);
            si_next(iterator);
        }
        si_free(iterator);
    

  2. compile_rewrite_dcl{1,2} rewrite direct call

        StackIterator* si = si_create();
        si_next(si);
        assert(!si_over(si));
        Execution_Engine_Handle jit = si_get_owner(si);
        Method_Handle method = si_get_method(si);
        NativeCodePtr ret_ip = si_get_ip(si);
        si_free(si);
    
        jit->rewrite_direct_call(REWRITE_PATCH_CALLER, (Method_Handle)method, ret_ip, method->get_code_addr());
    

  3. throw exception

        StackIterator* frame = si_create();
        while (!si_over(frame) && si_is_unwindable(frame)) {
            Execution_Engine_Handle ee = si_get_owner(frame);
            Pointer ip = si_get_ip(frame);
            for (handlers in ee_get_handlers(ee,frame)) { // XXX
                if (hanlder catches exception at ip) {
                    Execution_Context* context = si_get_context(frame);
                    ee_fix_context(ee,context,handler);
                    si_free(frame);
                    vm_transfer_control(context);
                }
            }
            si_unwind(frame);
        }
    
        if (si_over(frame)) {
            // uncaught exception
        } else if (!si_is_unwindable(frame)) {
            set_current_thread_exception(exception);
        }
        si_free(frame);
    

  4. Stack trace construction (security or printStackTrace())

        StackIterator* frame = si_create();
        while (!si_over(frame)) {
            Method_Handle method = si_get_trace_method(frame);
            char filename[256];
            si_get_trace_file(frame,filename,sizeof(filename));
            int linenumber = si_get_trace_line(frame);
    
            // fill in some other structure
            si_next_trace(frame);
        }
        si_free(frame);
    

  5. Root set enumeration

        StackIterator *frame = si_create();
        while (!si_over(frame)) {
            Execution_Engine_Handle ee = si_get_owner(frame);
            ee_enumerate(ee,frame);
            si_next(frame);
        }
        si_free(frame);
    

External requirements

Only very rough list of required from EE functionality, needs thorough work.

GC needs to

Security manager nees to Stack trace constructor needs to Unwinding needs to The rough list of methods required from external components to accomplish stack walking tasks follows.

Method_Handle ee_get_method(Execution_Engine_Handle ee, NativeCodePtr ip);
Execution_Engine_Handle vm_get_owner(NativeCodePtr ip);
void ee_get_line_info(Execution_Engine_Handle ee, Method_Handle method, int *pline, char **pfile);
?? ee_get_arg_description(Execution_Engine_Handle ee, Method_Handle method, ??);
void ee_enumerate(Execution_Engine_Handle ee, Method_Handle method, void* info);
void ee_unwind(Execution_Engine_Handle ee, Method_Handle method, Execution_Context* context, void* info); //??
void ee_fix_context(Execution_Engine_Handle ee, Method_Handle method, Execution_Context* context, Exception e); //??

Issues

Existing interfaces

struct StackIterator {
    CodeChunkInfo*    cci;
    JitFrameContext   c;
    M2nFrame*         m2nfl;
    uint32            ip;
};

StackIterator* si_create_from_native();
StackIterator* si_create_from_native(VM_thread* thread);
StackIterator* si_create_from_registers(Registers* regs, bool is_ip_past, M2nFrame* lm2nf);
void si_transfer_all_preserved_registers(StackIterator*);
bool si_is_past_end(StackIterator* si);
void si_goto_previous(StackIterator* si);
StackIterator* si_dup(StackIterator* si);
void si_free(StackIterator* si);
NativeCodePtr si_get_ip(StackIterator* si);
void si_set_ip(StackIterator* si, NativeCodePtr ip, bool also_update_stack_itself);
void si_set_code_chunk_info(StackIterator* si, CodeChunkInfo* cci);
CodeChunkInfo* si_get_code_chunk_info(StackIterator* si);
JitFrameContext* si_get_jit_context(StackIterator* si);
bool si_is_native(StackIterator* si);
M2nFrame* si_get_m2n(StackIterator* si);
void si_set_return_pointer(StackIterator* si, void** return_value);
void si_transfer_control(StackIterator* si);
void si_copy_to_registers(StackIterator* si, Registers* regs);
void si_reload_registers();
static void si_unwind_from_m2n(StackIterator* si);

// Stack trace

unsigned st_get_depth()
bool st_get_frame(unsigned target_depth, StackTraceFrame* stf)
void st_get_trace(unsigned* res_depth, StackTraceFrame** stfs)
void st_print_frame(ExpandableMemBlock* buf, StackTraceFrame* stf)
void st_print(FILE* f)

struct StackTraceFrame {
    Method_Handle method;
    NativeCodePtr ip;
    const char* file;
    int line;  // -2 for native methods, -1 for unknown line number
};

Genereated on Tue Mar 11 19:25:58 2008 by Doxygen.

(c) Copyright 2005, 2008 The Apache Software Foundation or its licensors, as applicable.