Skip to content

jcmd java_stack

ceragon edited this page Jun 1, 2022 · 3 revisions

java 栈结构

最后一帧

javaVFrame* JavaThread::last_java_vframe(RegisterMap *reg_map) {
    // 栈顶
    frame f = last_frame();
    // 下面的作用是从栈顶开始,找到一个java的栈帧,并转换为 javaVFrame
    for (vframe* vf = vframe::new_vframe(&f, reg_map, this); vf; vf = vf->sender()) {
        if (vf->is_java_frame()) return javaVFrame::cast(vf);
    }
    return NULL;
}
class JavaThread: public Thread {
    JavaFrameAnchor _anchor;
    // 获取最后一帧
    frame last_frame() {
        _anchor.make_walkable(this);
        return pd_last_frame();
    }
};

make_walkable

void JavaFrameAnchor::make_walkable(JavaThread* thread) {
    if (walkable()) return;
    capture_last_Java_pc();
}

void JavaFrameAnchor::capture_last_Java_pc() {
    _last_Java_pc = (address)_last_Java_sp[-1];
}
class JavaFrameAnchor {
    intptr_t* volatile _last_Java_sp;
    volatile  address _last_Java_pc;
    // x86 架构相关 
    // FP value associated with _last_Java_sp:
    intptr_t* volatile        _last_Java_fp;
    bool walkable(void) {
        return _last_Java_sp != NULL && _last_Java_pc != NULL; 
    }
};

pd_last_frame

frame JavaThread::pd_last_frame() {
    return frame(_anchor.last_Java_sp(), _anchor.last_Java_fp(), _anchor.last_Java_pc());
}
class frame {
    intptr_t* _sp; // stack pointer (from Thread::last_Java_sp)
    address   _pc; // program counter (the next instruction after the call)
    CodeBlob* _cb; // CodeBlob that "owns" pc
    enum deopt_state {
        not_deoptimized,
        is_deoptimized,
        unknown
    };
    deopt_state _deopt_state;
};

inline frame::frame(intptr_t* sp, intptr_t* fp, address pc) {
    init(sp, fp, pc);
}

inline void frame::init(intptr_t* sp, intptr_t* fp, address pc) {
    _sp = sp;
    _unextended_sp = sp;
    _fp = fp;
    _pc = pc;
    _cb = CodeCache::find_blob(pc);
    address original_pc = CompiledMethod::get_deopt_original_pc(this);
    if (original_pc != NULL) {
        // 说明这一帧对应的方法已经被 jit 优化过了
        _pc = original_pc;
        _deopt_state = is_deoptimized;
    } else {
        // 还处于解释执行阶段
        _deopt_state = not_deoptimized;
    }
}

遍历上一帧

class vframe: public ResourceObj {
    frame        _fr;
};
vframe* vframe::sender() const {
    RegisterMap temp_map = *register_map();
    if (_fr.is_entry_frame() && _fr.is_first_frame()) return NULL;
    frame s = _fr.real_sender(&temp_map);
    if (s.is_first_frame()) return NULL;
    return vframe::new_vframe(&s, &temp_map, thread());
}
frame frame::real_sender(RegisterMap* map) const {
    frame result = sender(map);
    while (result.is_runtime_frame() || result.is_ignored_frame()) {
        result = result.sender(map);
    }
    return result;
}

frame frame::sender(RegisterMap* map) const {
    if (is_entry_frame())       return sender_for_entry_frame(map);
    if (is_interpreted_frame()) return sender_for_interpreter_frame(map);
    if (_cb != NULL) {
        return sender_for_compiled_frame(map);
    }
    return frame(sender_sp(), link(), sender_pc());
}

栈帧的分类

vframe* vframe::new_vframe(const frame* f, const RegisterMap* reg_map, JavaThread* thread) {
    if (f->is_interpreted_frame()) {
        // java 解释执行的栈帧
        return new interpretedVFrame(f, reg_map, thread);
    }
    CodeBlob* cb = f->cb();
    if (cb != NULL) {
        // 代码块不为空
        if (cb->is_compiled()) {
            // 只要是被编译后的方法,或者执行过 AOT 的方法,都被视为编译后的代码
            CompiledMethod* nm = (CompiledMethod*)cb;
            // java 编译后的栈帧
            return new compiledVFrame(f, reg_map, thread, nm);
        }
        if (f->is_runtime_frame()) {
            RegisterMap temp_map = *reg_map;
            frame s = f->sender(&temp_map);
            // 非java栈帧
            return new_vframe(&s, &temp_map, thread);
        }
    }
    // 非 java栈帧
    return new externalVFrame(f, reg_map, thread);
}

bool frame::is_interpreted_frame() const  {
    // 由于 pc 指向的是当前栈帧执行的下一条指令地址,
    // 只要指令的地址范围在解释器产生的代码范围内,就说明是解释执行产生的栈帧
    return Interpreter::contains(pc());
}

method

Method* interpretedVFrame::method() const {
    return fr().interpreter_frame_method();
}

Method* frame::interpreter_frame_method() const {
    Method* m = *interpreter_frame_method_addr();
    return m;
}

enum {
    pc_return_offset                                 =  0,
    interpreter_frame_sender_sp_offset               = -1,
    interpreter_frame_last_sp_offset                 = interpreter_frame_sender_sp_offset - 1,
    interpreter_frame_method_offset                  = interpreter_frame_last_sp_offset - 1,
};

inline Method** frame::interpreter_frame_method_addr() const {
    return (Method**)addr_at(interpreter_frame_method_offset);
}

class frame {
    intptr_t*   _fp; // frame pointer
    
    intptr_t* addr_at(int index) const             { return &fp()[index];    }
    intptr_t*   fp() const { return _fp; }
};

Clone this wiki locally