Files
sdk/runtime/vm/stack_frame.cc
T
asiva@google.com 09adb99a85 Add a stub_code_space in the heap alongside code_space so that stub code generation happens here and it is easy to determine if a PC is a stub code or not.
This gets rid of the temporary change made in code_generator.cc for fast access to the top dart frame. In addition it will not pollute the pc ==> code cache that I plan to add next as we don't have to store stub pcs in that table.
Review URL: https://chromiumcodereview.appspot.com//10223015

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@7033 260f80e4-7a28-3924-810f-c04153c831b5
2012-04-26 18:00:53 +00:00

255 lines
8.2 KiB
C++

// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "vm/stack_frame.h"
#include "vm/isolate.h"
#include "vm/object.h"
#include "vm/object_store.h"
#include "vm/os.h"
#include "vm/raw_object.h"
#include "vm/stub_code.h"
#include "vm/visitor.h"
namespace dart {
bool StackFrame::FindRawCodeVisitor::FindObject(RawObject* obj) {
return RawInstructions::ContainsPC(obj, pc_);
}
bool StackFrame::IsStubFrame() const {
if (Dart::vm_isolate()->heap()->StubCodeContains(pc())) {
return true; // Common stub code is generated in the VM heap.
}
if (Isolate::Current()->heap()->StubCodeContains(pc())) {
return true; // Common stub code is generated in the VM heap.
}
return false;
}
void StackFrame::Print() const {
OS::Print("[%-8s : sp(%p) ]\n", GetName(), sp());
}
RawCode* StackFrame::LookupCode(Isolate* isolate, uword pc) {
// TODO(asiva): Need to add a data structure for storing a (pc, code
// object) map in order to do a quick lookup and avoid having to
// traverse the code heap.
ASSERT(isolate != NULL);
// We add a no gc scope to ensure that the code below does not trigger
// a GC as we are handling raw object references here. It is possible
// that the code is called while a GC is in progress, that is ok.
NoGCScope no_gc;
FindRawCodeVisitor visitor(pc);
RawInstructions* instr = isolate->heap()->FindObjectInCodeSpace(&visitor);
if (instr != Instructions::null()) {
return instr->ptr()->code_;
}
return Code::null();
}
void ExitFrame::VisitObjectPointers(ObjectPointerVisitor* visitor) {
// There are no objects to visit in this frame.
}
void EntryFrame::VisitObjectPointers(ObjectPointerVisitor* visitor) {
// Visit objects between SP and (FP - callee_save_area).
ASSERT(visitor != NULL);
RawObject** start = reinterpret_cast<RawObject**>(sp());
RawObject** end = reinterpret_cast<RawObject**>(
fp() - kWordSize + ExitLinkOffset());
visitor->VisitPointers(start, end);
}
void StackFrame::VisitObjectPointers(ObjectPointerVisitor* visitor) {
// NOTE: This code runs while GC is in progress and runs within
// a NoHandleScope block. Hence it is not ok to use regular Zone or
// Scope handles. We use direct stack handles, the raw pointers in
// these handles are not traversed. The use of handles is mainly to
// be able to reuse the handle based code and avoid having to add
// helper functions to the raw object interface.
NoGCScope no_gc;
Code code;
code = LookupDartCode();
if (!code.IsNull()) {
Array maps;
maps = Array::null();
Stackmap map;
map = code.GetStackmap(pc(), &maps, &map);
if (!map.IsNull()) {
// A stack map is present in the code object, use the stack map to visit
// frame slots which are marked as having objects.
intptr_t bit_offset = map.MinimumBitOffset();
intptr_t end_bit_offset = map.MaximumBitOffset();
while (bit_offset <= end_bit_offset) {
uword addr = (fp() - ((bit_offset + 1) * kWordSize));
ASSERT(addr >= sp());
if (map.IsObject(bit_offset)) {
visitor->VisitPointer(reinterpret_cast<RawObject**>(addr));
}
bit_offset += 1;
}
return;
}
}
// No stack maps are present in the code object which means this
// frame relies on tagged pointers and hence we visit each entry
// on the frame between SP and FP.
ASSERT(visitor != NULL);
visitor->VisitPointers(reinterpret_cast<RawObject**>(sp()),
reinterpret_cast<RawObject**>(fp() - kWordSize));
}
RawFunction* StackFrame::LookupDartFunction() const {
const Code& code = Code::Handle(LookupDartCode());
if (!code.IsNull()) {
return code.function();
}
return Function::null();
}
RawCode* StackFrame::LookupDartCode() const {
// We add a no gc scope to ensure that the code below does not trigger
// a GC as we are handling raw object references here. It is possible
// that the code is called while a GC is in progress, that is ok.
NoGCScope no_gc;
Isolate* isolate = Isolate::Current();
RawCode* code = StackFrame::LookupCode(isolate, pc());
if ((code != Code::null()) && (code->ptr()->function_ != Function::null())) {
return code;
}
return Code::null();
}
bool StackFrame::FindExceptionHandler(uword* handler_pc) const {
const Code& code = Code::Handle(LookupDartCode());
if (code.IsNull()) {
return false; // Stub frames do not have exception handlers.
}
// First try to find pc descriptor for the current pc.
intptr_t try_index = -1;
const PcDescriptors& descriptors =
PcDescriptors::Handle(code.pc_descriptors());
for (intptr_t i = 0; i < descriptors.Length(); i++) {
if (static_cast<uword>(descriptors.PC(i)) == pc() &&
descriptors.TryIndex(i) != -1) {
try_index = descriptors.TryIndex(i);
break;
}
}
if (try_index != -1) {
// We found a pc descriptor, now try to see if we have an
// exception catch handler for this try index.
const ExceptionHandlers& handlers =
ExceptionHandlers::Handle(code.exception_handlers());
for (intptr_t j = 0; j < handlers.Length(); j++) {
if (handlers.TryIndex(j) == try_index) {
*handler_pc = handlers.HandlerPC(j);
return true;
}
}
}
return false;
}
bool StackFrame::IsValid() const {
if (IsEntryFrame() || IsExitFrame() || IsStubFrame()) {
return true;
}
return (StackFrame::LookupCode(Isolate::Current(), pc()) != Code::null());
}
StackFrameIterator::StackFrameIterator(bool validate)
: validate_(validate), entry_(), exit_(), current_frame_(NULL) {
SetupLastExitFrameData(); // Setup data for last exit frame.
}
StackFrame* StackFrameIterator::NextFrame() {
// When we are at the start of iteration after having created an
// iterator object current_frame_ will be NULL as we haven't seen
// any frames yet. At this point if NextFrame is called it tries
// to set up the next exit frame by reading the top_exit_frame_info
// from the isolate. If we do not have any dart invocations yet
// top_exit_frame_info will be 0 and so we would return NULL.
// current_frame_ will also be NULL, when we are at the end of having
// iterated through all the frames. if NextFrame is called at this
// point we will try and set up the next exit frame but since we are
// at the end of the iteration fp_ will be 0 and we would return NULL.
if (current_frame_ == NULL) {
if (!HasNextFrame()) {
return NULL;
}
current_frame_ = NextExitFrame();
return current_frame_;
}
ASSERT((validate_ == kDontValidateFrames) || current_frame_->IsValid());
if (current_frame_->IsEntryFrame()) {
if (HasNextFrame()) { // We have another chained block.
current_frame_ = NextExitFrame();
return current_frame_;
}
current_frame_ = NULL; // No more frames.
return current_frame_;
}
ASSERT(current_frame_->IsExitFrame() ||
current_frame_->IsDartFrame() ||
current_frame_->IsStubFrame());
// Consume dart/stub frames using StackFrameIterator::FrameSetIterator
// until we are out of dart/stub frames at which point we return the
// corresponding entry frame for that set of dart/stub frames.
current_frame_ =
(frames_.HasNext()) ? frames_.NextFrame(validate_) : NextEntryFrame();
return current_frame_;
}
StackFrame* StackFrameIterator::FrameSetIterator::NextFrame(bool validate) {
StackFrame* frame;
ASSERT(HasNext());
frame = &stack_frame_;
frame->sp_ = sp_;
frame->fp_ = fp_;
sp_ = frame->GetCallerSp();
fp_ = frame->GetCallerFp();
ASSERT((validate == kDontValidateFrames) || frame->IsValid());
return frame;
}
ExitFrame* StackFrameIterator::NextExitFrame() {
exit_.sp_ = frames_.sp_;
exit_.fp_ = frames_.fp_;
frames_.sp_ = exit_.GetCallerSp();
frames_.fp_ = exit_.GetCallerFp();
ASSERT(exit_.IsValid());
return &exit_;
}
EntryFrame* StackFrameIterator::NextEntryFrame() {
ASSERT(!frames_.HasNext());
entry_.sp_ = frames_.sp_;
entry_.fp_ = frames_.fp_;
SetupNextExitFrameData(); // Setup data for next exit frame in chain.
ASSERT(entry_.IsValid());
return &entry_;
}
} // namespace dart