diff options
| author | Steve Block <steveblock@google.com> | 2009-10-30 11:49:00 +0000 |
|---|---|---|
| committer | Steve Block <steveblock@google.com> | 2009-11-03 17:23:38 +0000 |
| commit | a7e24c173cf37484693b9abb38e494fa7bd7baeb (patch) | |
| tree | 4aeefe31292fbed0d94f1b93fe86c51849b001c2 /src/frames.cc | |
| parent | af654c46444383e0baed1cb27a4c1d1bdcac8dd9 (diff) | |
| download | android_external_v8-a7e24c173cf37484693b9abb38e494fa7bd7baeb.tar.gz android_external_v8-a7e24c173cf37484693b9abb38e494fa7bd7baeb.tar.bz2 android_external_v8-a7e24c173cf37484693b9abb38e494fa7bd7baeb.zip | |
Move V8 to external/v8
Change-Id: If68025d67453785a651c5dfb34fad298c16676a4
Diffstat (limited to 'src/frames.cc')
| -rw-r--r-- | src/frames.cc | 743 |
1 files changed, 743 insertions, 0 deletions
diff --git a/src/frames.cc b/src/frames.cc new file mode 100644 index 00000000..5cd83324 --- /dev/null +++ b/src/frames.cc @@ -0,0 +1,743 @@ +// Copyright 2006-2008 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "v8.h" + +#include "frames-inl.h" +#include "mark-compact.h" +#include "scopeinfo.h" +#include "string-stream.h" +#include "top.h" +#include "zone-inl.h" + +namespace v8 { +namespace internal { + +// Iterator that supports traversing the stack handlers of a +// particular frame. Needs to know the top of the handler chain. +class StackHandlerIterator BASE_EMBEDDED { + public: + StackHandlerIterator(const StackFrame* frame, StackHandler* handler) + : limit_(frame->fp()), handler_(handler) { + // Make sure the handler has already been unwound to this frame. + ASSERT(frame->sp() <= handler->address()); + } + + StackHandler* handler() const { return handler_; } + + bool done() { + return handler_ == NULL || handler_->address() > limit_; + } + void Advance() { + ASSERT(!done()); + handler_ = handler_->next(); + } + + private: + const Address limit_; + StackHandler* handler_; +}; + + +// ------------------------------------------------------------------------- + + +#define INITIALIZE_SINGLETON(type, field) field##_(this), +StackFrameIterator::StackFrameIterator() + : STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON) + frame_(NULL), handler_(NULL), thread_(Top::GetCurrentThread()), + fp_(NULL), sp_(NULL), advance_(&StackFrameIterator::AdvanceWithHandler) { + Reset(); +} +StackFrameIterator::StackFrameIterator(ThreadLocalTop* t) + : STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON) + frame_(NULL), handler_(NULL), thread_(t), + fp_(NULL), sp_(NULL), advance_(&StackFrameIterator::AdvanceWithHandler) { + Reset(); +} +StackFrameIterator::StackFrameIterator(bool use_top, Address fp, Address sp) + : STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON) + frame_(NULL), handler_(NULL), + thread_(use_top ? Top::GetCurrentThread() : NULL), + fp_(use_top ? NULL : fp), sp_(sp), + advance_(use_top ? &StackFrameIterator::AdvanceWithHandler : + &StackFrameIterator::AdvanceWithoutHandler) { + if (use_top || fp != NULL) { + Reset(); + } + JavaScriptFrame_.DisableHeapAccess(); +} + +#undef INITIALIZE_SINGLETON + + +void StackFrameIterator::AdvanceWithHandler() { + ASSERT(!done()); + // Compute the state of the calling frame before restoring + // callee-saved registers and unwinding handlers. This allows the + // frame code that computes the caller state to access the top + // handler and the value of any callee-saved register if needed. + StackFrame::State state; + StackFrame::Type type = frame_->GetCallerState(&state); + + // Unwind handlers corresponding to the current frame. + StackHandlerIterator it(frame_, handler_); + while (!it.done()) it.Advance(); + handler_ = it.handler(); + + // Advance to the calling frame. + frame_ = SingletonFor(type, &state); + + // When we're done iterating over the stack frames, the handler + // chain must have been completely unwound. + ASSERT(!done() || handler_ == NULL); +} + + +void StackFrameIterator::AdvanceWithoutHandler() { + // A simpler version of Advance which doesn't care about handler. + ASSERT(!done()); + StackFrame::State state; + StackFrame::Type type = frame_->GetCallerState(&state); + frame_ = SingletonFor(type, &state); +} + + +void StackFrameIterator::Reset() { + StackFrame::State state; + StackFrame::Type type; + if (thread_ != NULL) { + type = ExitFrame::GetStateForFramePointer(Top::c_entry_fp(thread_), &state); + handler_ = StackHandler::FromAddress(Top::handler(thread_)); + } else { + ASSERT(fp_ != NULL); + state.fp = fp_; + state.sp = sp_; + state.pc_address = + reinterpret_cast<Address*>(StandardFrame::ComputePCAddress(fp_)); + type = StackFrame::ComputeType(&state); + if (SingletonFor(type) == NULL) return; + } + frame_ = SingletonFor(type, &state); +} + + +StackFrame* StackFrameIterator::SingletonFor(StackFrame::Type type, + StackFrame::State* state) { + if (type == StackFrame::NONE) return NULL; + StackFrame* result = SingletonFor(type); + ASSERT(result != NULL); + result->state_ = *state; + return result; +} + + +StackFrame* StackFrameIterator::SingletonFor(StackFrame::Type type) { +#define FRAME_TYPE_CASE(type, field) \ + case StackFrame::type: result = &field##_; break; + + StackFrame* result = NULL; + switch (type) { + case StackFrame::NONE: return NULL; + STACK_FRAME_TYPE_LIST(FRAME_TYPE_CASE) + default: break; + } + return result; + +#undef FRAME_TYPE_CASE +} + + +// ------------------------------------------------------------------------- + + +StackTraceFrameIterator::StackTraceFrameIterator() { + if (!done() && !frame()->function()->IsJSFunction()) Advance(); +} + + +void StackTraceFrameIterator::Advance() { + while (true) { + JavaScriptFrameIterator::Advance(); + if (done()) return; + if (frame()->function()->IsJSFunction()) return; + } +} + + +// ------------------------------------------------------------------------- + + +SafeStackFrameIterator::SafeStackFrameIterator( + Address fp, Address sp, Address low_bound, Address high_bound) : + low_bound_(low_bound), high_bound_(high_bound), + is_valid_top_( + IsWithinBounds(low_bound, high_bound, + Top::c_entry_fp(Top::GetCurrentThread())) && + Top::handler(Top::GetCurrentThread()) != NULL), + is_valid_fp_(IsWithinBounds(low_bound, high_bound, fp)), + is_working_iterator_(is_valid_top_ || is_valid_fp_), + iteration_done_(!is_working_iterator_), + iterator_(is_valid_top_, is_valid_fp_ ? fp : NULL, sp) { +} + + +void SafeStackFrameIterator::Advance() { + ASSERT(is_working_iterator_); + ASSERT(!done()); + StackFrame* last_frame = iterator_.frame(); + Address last_sp = last_frame->sp(), last_fp = last_frame->fp(); + // Before advancing to the next stack frame, perform pointer validity tests + iteration_done_ = !IsValidFrame(last_frame) || + !CanIterateHandles(last_frame, iterator_.handler()) || + !IsValidCaller(last_frame); + if (iteration_done_) return; + + iterator_.Advance(); + if (iterator_.done()) return; + // Check that we have actually moved to the previous frame in the stack + StackFrame* prev_frame = iterator_.frame(); + iteration_done_ = prev_frame->sp() < last_sp || prev_frame->fp() < last_fp; +} + + +bool SafeStackFrameIterator::CanIterateHandles(StackFrame* frame, + StackHandler* handler) { + // If StackIterator iterates over StackHandles, verify that + // StackHandlerIterator can be instantiated (see StackHandlerIterator + // constructor.) + return !is_valid_top_ || (frame->sp() <= handler->address()); +} + + +bool SafeStackFrameIterator::IsValidFrame(StackFrame* frame) const { + return IsValidStackAddress(frame->sp()) && IsValidStackAddress(frame->fp()); +} + + +bool SafeStackFrameIterator::IsValidCaller(StackFrame* frame) { + StackFrame::State state; + if (frame->is_entry() || frame->is_entry_construct()) { + // See EntryFrame::GetCallerState. It computes the caller FP address + // and calls ExitFrame::GetStateForFramePointer on it. We need to be + // sure that caller FP address is valid. + Address caller_fp = Memory::Address_at( + frame->fp() + EntryFrameConstants::kCallerFPOffset); + if (!IsValidStackAddress(caller_fp)) { + return false; + } + } else if (frame->is_arguments_adaptor()) { + // See ArgumentsAdaptorFrame::GetCallerStackPointer. It assumes that + // the number of arguments is stored on stack as Smi. We need to check + // that it really an Smi. + Object* number_of_args = reinterpret_cast<ArgumentsAdaptorFrame*>(frame)-> + GetExpression(0); + if (!number_of_args->IsSmi()) { + return false; + } + } + frame->ComputeCallerState(&state); + return IsValidStackAddress(state.sp) && IsValidStackAddress(state.fp) && + iterator_.SingletonFor(frame->GetCallerState(&state)) != NULL; +} + + +void SafeStackFrameIterator::Reset() { + if (is_working_iterator_) { + iterator_.Reset(); + iteration_done_ = false; + } +} + + +// ------------------------------------------------------------------------- + + +#ifdef ENABLE_LOGGING_AND_PROFILING +SafeStackTraceFrameIterator::SafeStackTraceFrameIterator( + Address fp, Address sp, Address low_bound, Address high_bound) : + SafeJavaScriptFrameIterator(fp, sp, low_bound, high_bound) { + if (!done() && !frame()->is_java_script()) Advance(); +} + + +void SafeStackTraceFrameIterator::Advance() { + while (true) { + SafeJavaScriptFrameIterator::Advance(); + if (done()) return; + if (frame()->is_java_script()) return; + } +} +#endif + + +// ------------------------------------------------------------------------- + + +void StackHandler::Cook(Code* code) { + ASSERT(MarkCompactCollector::IsCompacting()); + ASSERT(code->contains(pc())); + set_pc(AddressFrom<Address>(pc() - code->instruction_start())); +} + + +void StackHandler::Uncook(Code* code) { + ASSERT(MarkCompactCollector::IsCompacting()); + set_pc(code->instruction_start() + OffsetFrom(pc())); + ASSERT(code->contains(pc())); +} + + +// ------------------------------------------------------------------------- + + +bool StackFrame::HasHandler() const { + StackHandlerIterator it(this, top_handler()); + return !it.done(); +} + + +void StackFrame::CookFramesForThread(ThreadLocalTop* thread) { + // Only cooking frames when the collector is compacting and thus moving code + // around. + ASSERT(MarkCompactCollector::IsCompacting()); + ASSERT(!thread->stack_is_cooked()); + for (StackFrameIterator it(thread); !it.done(); it.Advance()) { + it.frame()->Cook(); + } + thread->set_stack_is_cooked(true); +} + + +void StackFrame::UncookFramesForThread(ThreadLocalTop* thread) { + // Only uncooking frames when the collector is compacting and thus moving code + // around. + ASSERT(MarkCompactCollector::IsCompacting()); + ASSERT(thread->stack_is_cooked()); + for (StackFrameIterator it(thread); !it.done(); it.Advance()) { + it.frame()->Uncook(); + } + thread->set_stack_is_cooked(false); +} + + +void StackFrame::Cook() { + Code* code = this->code(); + for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) { + it.handler()->Cook(code); + } + ASSERT(code->contains(pc())); + set_pc(AddressFrom<Address>(pc() - code->instruction_start())); +} + + +void StackFrame::Uncook() { + Code* code = this->code(); + for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) { + it.handler()->Uncook(code); + } + set_pc(code->instruction_start() + OffsetFrom(pc())); + ASSERT(code->contains(pc())); +} + + +StackFrame::Type StackFrame::GetCallerState(State* state) const { + ComputeCallerState(state); + return ComputeType(state); +} + + +Code* EntryFrame::code() const { + return Heap::js_entry_code(); +} + + +void EntryFrame::ComputeCallerState(State* state) const { + GetCallerState(state); +} + + +StackFrame::Type EntryFrame::GetCallerState(State* state) const { + const int offset = EntryFrameConstants::kCallerFPOffset; + Address fp = Memory::Address_at(this->fp() + offset); + return ExitFrame::GetStateForFramePointer(fp, state); +} + + +Code* EntryConstructFrame::code() const { + return Heap::js_construct_entry_code(); +} + + +Code* ExitFrame::code() const { + return Heap::c_entry_code(); +} + + +void ExitFrame::ComputeCallerState(State* state) const { + // Setup the caller state. + state->sp = caller_sp(); + state->fp = Memory::Address_at(fp() + ExitFrameConstants::kCallerFPOffset); + state->pc_address + = reinterpret_cast<Address*>(fp() + ExitFrameConstants::kCallerPCOffset); +} + + +Address ExitFrame::GetCallerStackPointer() const { + return fp() + ExitFrameConstants::kCallerSPDisplacement; +} + + +Code* ExitDebugFrame::code() const { + return Heap::c_entry_debug_break_code(); +} + + +Address StandardFrame::GetExpressionAddress(int n) const { + const int offset = StandardFrameConstants::kExpressionsOffset; + return fp() + offset - n * kPointerSize; +} + + +int StandardFrame::ComputeExpressionsCount() const { + const int offset = + StandardFrameConstants::kExpressionsOffset + kPointerSize; + Address base = fp() + offset; + Address limit = sp(); + ASSERT(base >= limit); // stack grows downwards + // Include register-allocated locals in number of expressions. + return (base - limit) / kPointerSize; +} + + +void StandardFrame::ComputeCallerState(State* state) const { + state->sp = caller_sp(); + state->fp = caller_fp(); + state->pc_address = reinterpret_cast<Address*>(ComputePCAddress(fp())); +} + + +bool StandardFrame::IsExpressionInsideHandler(int n) const { + Address address = GetExpressionAddress(n); + for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) { + if (it.handler()->includes(address)) return true; + } + return false; +} + + +Object* JavaScriptFrame::GetParameter(int index) const { + ASSERT(index >= 0 && index < ComputeParametersCount()); + const int offset = JavaScriptFrameConstants::kParam0Offset; + return Memory::Object_at(caller_sp() + offset - (index * kPointerSize)); +} + + +int JavaScriptFrame::ComputeParametersCount() const { + Address base = caller_sp() + JavaScriptFrameConstants::kReceiverOffset; + Address limit = fp() + JavaScriptFrameConstants::kSavedRegistersOffset; + return (base - limit) / kPointerSize; +} + + +bool JavaScriptFrame::IsConstructor() const { + Address fp = caller_fp(); + if (has_adapted_arguments()) { + // Skip the arguments adaptor frame and look at the real caller. + fp = Memory::Address_at(fp + StandardFrameConstants::kCallerFPOffset); + } + return IsConstructFrame(fp); +} + + +Code* JavaScriptFrame::code() const { + JSFunction* function = JSFunction::cast(this->function()); + return function->shared()->code(); +} + + +Code* ArgumentsAdaptorFrame::code() const { + return Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline); +} + + +Code* InternalFrame::code() const { + const int offset = InternalFrameConstants::kCodeOffset; + Object* code = Memory::Object_at(fp() + offset); + ASSERT(code != NULL); + return Code::cast(code); +} + + +void StackFrame::PrintIndex(StringStream* accumulator, + PrintMode mode, + int index) { + accumulator->Add((mode == OVERVIEW) ? "%5d: " : "[%d]: ", index); +} + + +void JavaScriptFrame::Print(StringStream* accumulator, + PrintMode mode, + int index) const { + HandleScope scope; + Object* receiver = this->receiver(); + Object* function = this->function(); + + accumulator->PrintSecurityTokenIfChanged(function); + PrintIndex(accumulator, mode, index); + Code* code = NULL; + if (IsConstructor()) accumulator->Add("new "); + accumulator->PrintFunction(function, receiver, &code); + accumulator->Add("(this=%o", receiver); + + // Get scope information for nicer output, if possible. If code is + // NULL, or doesn't contain scope info, info will return 0 for the + // number of parameters, stack slots, or context slots. + ScopeInfo<PreallocatedStorage> info(code); + + // Print the parameters. + int parameters_count = ComputeParametersCount(); + for (int i = 0; i < parameters_count; i++) { + accumulator->Add(","); + // If we have a name for the parameter we print it. Nameless + // parameters are either because we have more actual parameters + // than formal parameters or because we have no scope information. + if (i < info.number_of_parameters()) { + accumulator->PrintName(*info.parameter_name(i)); + accumulator->Add("="); + } + accumulator->Add("%o", GetParameter(i)); + } + + accumulator->Add(")"); + if (mode == OVERVIEW) { + accumulator->Add("\n"); + return; + } + accumulator->Add(" {\n"); + + // Compute the number of locals and expression stack elements. + int stack_locals_count = info.number_of_stack_slots(); + int heap_locals_count = info.number_of_context_slots(); + int expressions_count = ComputeExpressionsCount(); + + // Print stack-allocated local variables. + if (stack_locals_count > 0) { + accumulator->Add(" // stack-allocated locals\n"); + } + for (int i = 0; i < stack_locals_count; i++) { + accumulator->Add(" var "); + accumulator->PrintName(*info.stack_slot_name(i)); + accumulator->Add(" = "); + if (i < expressions_count) { + accumulator->Add("%o", GetExpression(i)); + } else { + accumulator->Add("// no expression found - inconsistent frame?"); + } + accumulator->Add("\n"); + } + + // Try to get hold of the context of this frame. + Context* context = NULL; + if (this->context() != NULL && this->context()->IsContext()) { + context = Context::cast(this->context()); + } + + // Print heap-allocated local variables. + if (heap_locals_count > Context::MIN_CONTEXT_SLOTS) { + accumulator->Add(" // heap-allocated locals\n"); + } + for (int i = Context::MIN_CONTEXT_SLOTS; i < heap_locals_count; i++) { + accumulator->Add(" var "); + accumulator->PrintName(*info.context_slot_name(i)); + accumulator->Add(" = "); + if (context != NULL) { + if (i < context->length()) { + accumulator->Add("%o", context->get(i)); + } else { + accumulator->Add( + "// warning: missing context slot - inconsistent frame?"); + } + } else { + accumulator->Add("// warning: no context found - inconsistent frame?"); + } + accumulator->Add("\n"); + } + + // Print the expression stack. + int expressions_start = stack_locals_count; + if (expressions_start < expressions_count) { + accumulator->Add(" // expression stack (top to bottom)\n"); + } + for (int i = expressions_count - 1; i >= expressions_start; i--) { + if (IsExpressionInsideHandler(i)) continue; + accumulator->Add(" [%02d] : %o\n", i, GetExpression(i)); + } + + // Print details about the function. + if (FLAG_max_stack_trace_source_length != 0 && code != NULL) { + SharedFunctionInfo* shared = JSFunction::cast(function)->shared(); + accumulator->Add("--------- s o u r c e c o d e ---------\n"); + shared->SourceCodePrint(accumulator, FLAG_max_stack_trace_source_length); + accumulator->Add("\n-----------------------------------------\n"); + } + + accumulator->Add("}\n\n"); +} + + +void ArgumentsAdaptorFrame::Print(StringStream* accumulator, + PrintMode mode, + int index) const { + int actual = ComputeParametersCount(); + int expected = -1; + Object* function = this->function(); + if (function->IsJSFunction()) { + expected = JSFunction::cast(function)->shared()->formal_parameter_count(); + } + + PrintIndex(accumulator, mode, index); + accumulator->Add("arguments adaptor frame: %d->%d", actual, expected); + if (mode == OVERVIEW) { + accumulator->Add("\n"); + return; + } + accumulator->Add(" {\n"); + + // Print actual arguments. + if (actual > 0) accumulator->Add(" // actual arguments\n"); + for (int i = 0; i < actual; i++) { + accumulator->Add(" [%02d] : %o", i, GetParameter(i)); + if (expected != -1 && i >= expected) { + accumulator->Add(" // not passed to callee"); + } + accumulator->Add("\n"); + } + + accumulator->Add("}\n\n"); +} + + +void EntryFrame::Iterate(ObjectVisitor* v) const { + StackHandlerIterator it(this, top_handler()); + ASSERT(!it.done()); + StackHandler* handler = it.handler(); + ASSERT(handler->is_entry()); + handler->Iterate(v); + // Make sure that there's the entry frame does not contain more than + // one stack handler. +#ifdef DEBUG + it.Advance(); + ASSERT(it.done()); +#endif +} + + +void StandardFrame::IterateExpressions(ObjectVisitor* v) const { + const int offset = StandardFrameConstants::kContextOffset; + Object** base = &Memory::Object_at(sp()); + Object** limit = &Memory::Object_at(fp() + offset) + 1; + for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) { + StackHandler* handler = it.handler(); + // Traverse pointers down to - but not including - the next + // handler in the handler chain. Update the base to skip the + // handler and allow the handler to traverse its own pointers. + const Address address = handler->address(); + v->VisitPointers(base, reinterpret_cast<Object**>(address)); + base = reinterpret_cast<Object**>(address + StackHandlerConstants::kSize); + // Traverse the pointers in the handler itself. + handler->Iterate(v); + } + v->VisitPointers(base, limit); +} + + +void JavaScriptFrame::Iterate(ObjectVisitor* v) const { + IterateExpressions(v); + + // Traverse callee-saved registers, receiver, and parameters. + const int kBaseOffset = JavaScriptFrameConstants::kSavedRegistersOffset; + const int kLimitOffset = JavaScriptFrameConstants::kReceiverOffset; + Object** base = &Memory::Object_at(fp() + kBaseOffset); + Object** limit = &Memory::Object_at(caller_sp() + kLimitOffset) + 1; + v->VisitPointers(base, limit); +} + + +void InternalFrame::Iterate(ObjectVisitor* v) const { + // Internal frames only have object pointers on the expression stack + // as they never have any arguments. + IterateExpressions(v); +} + + +// ------------------------------------------------------------------------- + + +JavaScriptFrame* StackFrameLocator::FindJavaScriptFrame(int n) { + ASSERT(n >= 0); + for (int i = 0; i <= n; i++) { + while (!iterator_.frame()->is_java_script()) iterator_.Advance(); + if (i == n) return JavaScriptFrame::cast(iterator_.frame()); + iterator_.Advance(); + } + UNREACHABLE(); + return NULL; +} + + +// ------------------------------------------------------------------------- + + +int NumRegs(RegList reglist) { + int n = 0; + while (reglist != 0) { + n++; + reglist &= reglist - 1; // clear one bit + } + return n; +} + + +int JSCallerSavedCode(int n) { + static int reg_code[kNumJSCallerSaved]; + static bool initialized = false; + if (!initialized) { + initialized = true; + int i = 0; + for (int r = 0; r < kNumRegs; r++) + if ((kJSCallerSaved & (1 << r)) != 0) + reg_code[i++] = r; + + ASSERT(i == kNumJSCallerSaved); + } + ASSERT(0 <= n && n < kNumJSCallerSaved); + return reg_code[n]; +} + + +} } // namespace v8::internal |
