blob: be537c96e92a8c3512135c38ea7f4f3dc71ef1c0 [file] [log] [blame]
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001// Copyright 2012 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
kasperl@chromium.orga5551262010-12-07 12:49:48 +000030#include "ast.h"
31#include "deoptimizer.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000032#include "frames-inl.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000033#include "full-codegen.h"
kasperl@chromium.org061ef742009-02-27 12:16:20 +000034#include "mark-compact.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000035#include "safepoint-table.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000036#include "scopeinfo.h"
37#include "string-stream.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000038
whesse@chromium.org030d38e2011-07-13 13:23:34 +000039#include "allocation-inl.h"
40
kasperl@chromium.org71affb52009-05-26 05:44:31 +000041namespace v8 {
42namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000043
ulan@chromium.org967e2702012-02-28 09:49:15 +000044
45static ReturnAddressLocationResolver return_address_location_resolver = NULL;
46
47
48// Resolves pc_address through the resolution address function if one is set.
49static inline Address* ResolveReturnAddressLocation(Address* pc_address) {
50 if (return_address_location_resolver == NULL) {
51 return pc_address;
52 } else {
53 return reinterpret_cast<Address*>(
54 return_address_location_resolver(
55 reinterpret_cast<uintptr_t>(pc_address)));
56 }
57}
58
59
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000060// Iterator that supports traversing the stack handlers of a
61// particular frame. Needs to know the top of the handler chain.
62class StackHandlerIterator BASE_EMBEDDED {
63 public:
64 StackHandlerIterator(const StackFrame* frame, StackHandler* handler)
65 : limit_(frame->fp()), handler_(handler) {
66 // Make sure the handler has already been unwound to this frame.
67 ASSERT(frame->sp() <= handler->address());
68 }
69
70 StackHandler* handler() const { return handler_; }
71
ager@chromium.orgeadaf222009-06-16 09:43:10 +000072 bool done() {
73 return handler_ == NULL || handler_->address() > limit_;
74 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000075 void Advance() {
76 ASSERT(!done());
77 handler_ = handler_->next();
78 }
79
80 private:
81 const Address limit_;
82 StackHandler* handler_;
83};
84
85
86// -------------------------------------------------------------------------
87
88
89#define INITIALIZE_SINGLETON(type, field) field##_(this),
90StackFrameIterator::StackFrameIterator()
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000091 : isolate_(Isolate::Current()),
92 STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000093 frame_(NULL), handler_(NULL),
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000094 thread_(isolate_->thread_local_top()),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000095 fp_(NULL), sp_(NULL), advance_(&StackFrameIterator::AdvanceWithHandler) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000096 Reset();
97}
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000098StackFrameIterator::StackFrameIterator(Isolate* isolate)
99 : isolate_(isolate),
100 STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON)
101 frame_(NULL), handler_(NULL),
102 thread_(isolate_->thread_local_top()),
103 fp_(NULL), sp_(NULL), advance_(&StackFrameIterator::AdvanceWithHandler) {
104 Reset();
105}
106StackFrameIterator::StackFrameIterator(Isolate* isolate, ThreadLocalTop* t)
107 : isolate_(isolate),
108 STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON)
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000109 frame_(NULL), handler_(NULL), thread_(t),
110 fp_(NULL), sp_(NULL), advance_(&StackFrameIterator::AdvanceWithHandler) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000111 Reset();
112}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000113StackFrameIterator::StackFrameIterator(Isolate* isolate,
114 bool use_top, Address fp, Address sp)
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000115 : isolate_(isolate),
116 STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON)
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000117 frame_(NULL), handler_(NULL),
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000118 thread_(use_top ? isolate_->thread_local_top() : NULL),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000119 fp_(use_top ? NULL : fp), sp_(sp),
120 advance_(use_top ? &StackFrameIterator::AdvanceWithHandler :
121 &StackFrameIterator::AdvanceWithoutHandler) {
122 if (use_top || fp != NULL) {
123 Reset();
124 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000125}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000126
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000127#undef INITIALIZE_SINGLETON
128
129
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000130void StackFrameIterator::AdvanceWithHandler() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000131 ASSERT(!done());
132 // Compute the state of the calling frame before restoring
133 // callee-saved registers and unwinding handlers. This allows the
134 // frame code that computes the caller state to access the top
135 // handler and the value of any callee-saved register if needed.
136 StackFrame::State state;
137 StackFrame::Type type = frame_->GetCallerState(&state);
138
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000139 // Unwind handlers corresponding to the current frame.
140 StackHandlerIterator it(frame_, handler_);
141 while (!it.done()) it.Advance();
142 handler_ = it.handler();
143
144 // Advance to the calling frame.
145 frame_ = SingletonFor(type, &state);
146
147 // When we're done iterating over the stack frames, the handler
148 // chain must have been completely unwound.
149 ASSERT(!done() || handler_ == NULL);
150}
151
152
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000153void StackFrameIterator::AdvanceWithoutHandler() {
154 // A simpler version of Advance which doesn't care about handler.
155 ASSERT(!done());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000156 StackFrame::State state;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000157 StackFrame::Type type = frame_->GetCallerState(&state);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000158 frame_ = SingletonFor(type, &state);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000159}
160
161
162void StackFrameIterator::Reset() {
163 StackFrame::State state;
164 StackFrame::Type type;
165 if (thread_ != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000166 type = ExitFrame::GetStateForFramePointer(
167 Isolate::c_entry_fp(thread_), &state);
168 handler_ = StackHandler::FromAddress(
169 Isolate::handler(thread_));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000170 } else {
171 ASSERT(fp_ != NULL);
172 state.fp = fp_;
173 state.sp = sp_;
ulan@chromium.org967e2702012-02-28 09:49:15 +0000174 state.pc_address = ResolveReturnAddressLocation(
175 reinterpret_cast<Address*>(StandardFrame::ComputePCAddress(fp_)));
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000176 type = StackFrame::ComputeType(isolate(), &state);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000177 }
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000178 if (SingletonFor(type) == NULL) return;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000179 frame_ = SingletonFor(type, &state);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000180}
181
182
183StackFrame* StackFrameIterator::SingletonFor(StackFrame::Type type,
184 StackFrame::State* state) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000185 if (type == StackFrame::NONE) return NULL;
186 StackFrame* result = SingletonFor(type);
187 ASSERT(result != NULL);
188 result->state_ = *state;
189 return result;
190}
191
192
193StackFrame* StackFrameIterator::SingletonFor(StackFrame::Type type) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000194#define FRAME_TYPE_CASE(type, field) \
195 case StackFrame::type: result = &field##_; break;
196
197 StackFrame* result = NULL;
198 switch (type) {
199 case StackFrame::NONE: return NULL;
200 STACK_FRAME_TYPE_LIST(FRAME_TYPE_CASE)
201 default: break;
202 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000203 return result;
204
205#undef FRAME_TYPE_CASE
206}
207
208
209// -------------------------------------------------------------------------
210
211
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000212StackTraceFrameIterator::StackTraceFrameIterator() {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000213 if (!done() && !IsValidFrame()) Advance();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000214}
215
216
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000217StackTraceFrameIterator::StackTraceFrameIterator(Isolate* isolate)
218 : JavaScriptFrameIterator(isolate) {
219 if (!done() && !IsValidFrame()) Advance();
220}
221
222
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000223void StackTraceFrameIterator::Advance() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000224 while (true) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000225 JavaScriptFrameIterator::Advance();
226 if (done()) return;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000227 if (IsValidFrame()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000228 }
229}
230
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000231bool StackTraceFrameIterator::IsValidFrame() {
232 if (!frame()->function()->IsJSFunction()) return false;
233 Object* script = JSFunction::cast(frame()->function())->shared()->script();
234 // Don't show functions from native scripts to user.
235 return (script->IsScript() &&
236 Script::TYPE_NATIVE != Script::cast(script)->type()->value());
237}
238
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000239
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000240// -------------------------------------------------------------------------
241
242
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000243bool SafeStackFrameIterator::ExitFrameValidator::IsValidFP(Address fp) {
244 if (!validator_.IsValid(fp)) return false;
245 Address sp = ExitFrame::ComputeStackPointer(fp);
246 if (!validator_.IsValid(sp)) return false;
247 StackFrame::State state;
248 ExitFrame::FillState(fp, sp, &state);
249 if (!validator_.IsValid(reinterpret_cast<Address>(state.pc_address))) {
250 return false;
251 }
252 return *state.pc_address != NULL;
253}
254
255
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000256SafeStackFrameIterator::ActiveCountMaintainer::ActiveCountMaintainer(
257 Isolate* isolate)
258 : isolate_(isolate) {
259 isolate_->set_safe_stack_iterator_counter(
260 isolate_->safe_stack_iterator_counter() + 1);
261}
262
263
264SafeStackFrameIterator::ActiveCountMaintainer::~ActiveCountMaintainer() {
265 isolate_->set_safe_stack_iterator_counter(
266 isolate_->safe_stack_iterator_counter() - 1);
267}
268
269
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000270SafeStackFrameIterator::SafeStackFrameIterator(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000271 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000272 Address fp, Address sp, Address low_bound, Address high_bound) :
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000273 maintainer_(isolate),
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000274 stack_validator_(low_bound, high_bound),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000275 is_valid_top_(IsValidTop(isolate, low_bound, high_bound)),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000276 is_valid_fp_(IsWithinBounds(low_bound, high_bound, fp)),
277 is_working_iterator_(is_valid_top_ || is_valid_fp_),
278 iteration_done_(!is_working_iterator_),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000279 iterator_(isolate, is_valid_top_, is_valid_fp_ ? fp : NULL, sp) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000280}
281
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000282bool SafeStackFrameIterator::is_active(Isolate* isolate) {
283 return isolate->safe_stack_iterator_counter() > 0;
284}
285
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000286
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000287bool SafeStackFrameIterator::IsValidTop(Isolate* isolate,
288 Address low_bound, Address high_bound) {
289 ThreadLocalTop* top = isolate->thread_local_top();
290 Address fp = Isolate::c_entry_fp(top);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000291 ExitFrameValidator validator(low_bound, high_bound);
292 if (!validator.IsValidFP(fp)) return false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000293 return Isolate::handler(top) != NULL;
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000294}
295
296
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000297void SafeStackFrameIterator::Advance() {
298 ASSERT(is_working_iterator_);
299 ASSERT(!done());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000300 StackFrame* last_frame = iterator_.frame();
301 Address last_sp = last_frame->sp(), last_fp = last_frame->fp();
302 // Before advancing to the next stack frame, perform pointer validity tests
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000303 iteration_done_ = !IsValidFrame(last_frame) ||
304 !CanIterateHandles(last_frame, iterator_.handler()) ||
305 !IsValidCaller(last_frame);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000306 if (iteration_done_) return;
307
308 iterator_.Advance();
309 if (iterator_.done()) return;
310 // Check that we have actually moved to the previous frame in the stack
311 StackFrame* prev_frame = iterator_.frame();
312 iteration_done_ = prev_frame->sp() < last_sp || prev_frame->fp() < last_fp;
313}
314
315
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000316bool SafeStackFrameIterator::CanIterateHandles(StackFrame* frame,
317 StackHandler* handler) {
318 // If StackIterator iterates over StackHandles, verify that
319 // StackHandlerIterator can be instantiated (see StackHandlerIterator
320 // constructor.)
321 return !is_valid_top_ || (frame->sp() <= handler->address());
322}
323
324
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000325bool SafeStackFrameIterator::IsValidFrame(StackFrame* frame) const {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000326 return IsValidStackAddress(frame->sp()) && IsValidStackAddress(frame->fp());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000327}
328
329
330bool SafeStackFrameIterator::IsValidCaller(StackFrame* frame) {
331 StackFrame::State state;
ager@chromium.org41826e72009-03-30 13:30:57 +0000332 if (frame->is_entry() || frame->is_entry_construct()) {
333 // See EntryFrame::GetCallerState. It computes the caller FP address
334 // and calls ExitFrame::GetStateForFramePointer on it. We need to be
335 // sure that caller FP address is valid.
336 Address caller_fp = Memory::Address_at(
337 frame->fp() + EntryFrameConstants::kCallerFPOffset);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000338 ExitFrameValidator validator(stack_validator_);
339 if (!validator.IsValidFP(caller_fp)) return false;
ager@chromium.org41826e72009-03-30 13:30:57 +0000340 } else if (frame->is_arguments_adaptor()) {
341 // See ArgumentsAdaptorFrame::GetCallerStackPointer. It assumes that
342 // the number of arguments is stored on stack as Smi. We need to check
343 // that it really an Smi.
344 Object* number_of_args = reinterpret_cast<ArgumentsAdaptorFrame*>(frame)->
345 GetExpression(0);
346 if (!number_of_args->IsSmi()) {
347 return false;
348 }
349 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000350 frame->ComputeCallerState(&state);
351 return IsValidStackAddress(state.sp) && IsValidStackAddress(state.fp) &&
352 iterator_.SingletonFor(frame->GetCallerState(&state)) != NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000353}
354
355
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000356void SafeStackFrameIterator::Reset() {
357 if (is_working_iterator_) {
358 iterator_.Reset();
359 iteration_done_ = false;
360 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000361}
362
363
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000364// -------------------------------------------------------------------------
365
366
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000367SafeStackTraceFrameIterator::SafeStackTraceFrameIterator(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000368 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000369 Address fp, Address sp, Address low_bound, Address high_bound) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000370 SafeJavaScriptFrameIterator(isolate, fp, sp, low_bound, high_bound) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000371 if (!done() && !frame()->is_java_script()) Advance();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000372}
373
374
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000375void SafeStackTraceFrameIterator::Advance() {
376 while (true) {
377 SafeJavaScriptFrameIterator::Advance();
378 if (done()) return;
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000379 if (frame()->is_java_script()) return;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000380 }
381}
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000382
383
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000384Code* StackFrame::GetSafepointData(Isolate* isolate,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000385 Address inner_pointer,
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000386 SafepointEntry* safepoint_entry,
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000387 unsigned* stack_slots) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000388 InnerPointerToCodeCache::InnerPointerToCodeCacheEntry* entry =
389 isolate->inner_pointer_to_code_cache()->GetCacheEntry(inner_pointer);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000390 if (!entry->safepoint_entry.is_valid()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000391 entry->safepoint_entry = entry->code->GetSafepointEntry(inner_pointer);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000392 ASSERT(entry->safepoint_entry.is_valid());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000393 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000394 ASSERT(entry->safepoint_entry.Equals(
395 entry->code->GetSafepointEntry(inner_pointer)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000396 }
397
398 // Fill in the results and return the code.
399 Code* code = entry->code;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000400 *safepoint_entry = entry->safepoint_entry;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000401 *stack_slots = code->stack_slots();
402 return code;
403}
404
405
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000406bool StackFrame::HasHandler() const {
407 StackHandlerIterator it(this, top_handler());
408 return !it.done();
409}
410
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000411
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000412#ifdef DEBUG
413static bool GcSafeCodeContains(HeapObject* object, Address addr);
414#endif
415
416
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000417void StackFrame::IteratePc(ObjectVisitor* v,
418 Address* pc_address,
419 Code* holder) {
420 Address pc = *pc_address;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000421 ASSERT(GcSafeCodeContains(holder, pc));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000422 unsigned pc_offset = static_cast<unsigned>(pc - holder->instruction_start());
423 Object* code = holder;
424 v->VisitPointer(&code);
425 if (code != holder) {
426 holder = reinterpret_cast<Code*>(code);
427 pc = holder->instruction_start() + pc_offset;
428 *pc_address = pc;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000429 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000430}
431
432
ulan@chromium.org967e2702012-02-28 09:49:15 +0000433void StackFrame::SetReturnAddressLocationResolver(
434 ReturnAddressLocationResolver resolver) {
435 ASSERT(return_address_location_resolver == NULL);
436 return_address_location_resolver = resolver;
437}
438
439
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000440StackFrame::Type StackFrame::ComputeType(Isolate* isolate, State* state) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000441 ASSERT(state->fp != NULL);
442 if (StandardFrame::IsArgumentsAdaptorFrame(state->fp)) {
443 return ARGUMENTS_ADAPTOR;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000444 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000445 // The marker and function offsets overlap. If the marker isn't a
446 // smi then the frame is a JavaScript frame -- and the marker is
447 // really the function.
448 const int offset = StandardFrameConstants::kMarkerOffset;
449 Object* marker = Memory::Object_at(state->fp + offset);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000450 if (!marker->IsSmi()) {
451 // If we're using a "safe" stack iterator, we treat optimized
452 // frames as normal JavaScript frames to avoid having to look
453 // into the heap to determine the state. This is safe as long
454 // as nobody tries to GC...
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000455 if (SafeStackFrameIterator::is_active(isolate)) return JAVA_SCRIPT;
456 Code::Kind kind = GetContainingCode(isolate, *(state->pc_address))->kind();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000457 ASSERT(kind == Code::FUNCTION || kind == Code::OPTIMIZED_FUNCTION);
458 return (kind == Code::OPTIMIZED_FUNCTION) ? OPTIMIZED : JAVA_SCRIPT;
459 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000460 return static_cast<StackFrame::Type>(Smi::cast(marker)->value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000461}
462
463
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000464
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000465StackFrame::Type StackFrame::GetCallerState(State* state) const {
466 ComputeCallerState(state);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000467 return ComputeType(isolate(), state);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000468}
469
470
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000471Code* EntryFrame::unchecked_code() const {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000472 return HEAP->raw_unchecked_js_entry_code();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000473}
474
475
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000476void EntryFrame::ComputeCallerState(State* state) const {
477 GetCallerState(state);
478}
479
480
ager@chromium.org357bf652010-04-12 11:30:10 +0000481void EntryFrame::SetCallerFp(Address caller_fp) {
482 const int offset = EntryFrameConstants::kCallerFPOffset;
483 Memory::Address_at(this->fp() + offset) = caller_fp;
484}
485
486
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000487StackFrame::Type EntryFrame::GetCallerState(State* state) const {
488 const int offset = EntryFrameConstants::kCallerFPOffset;
489 Address fp = Memory::Address_at(this->fp() + offset);
490 return ExitFrame::GetStateForFramePointer(fp, state);
491}
492
493
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000494Code* EntryConstructFrame::unchecked_code() const {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000495 return HEAP->raw_unchecked_js_construct_entry_code();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000496}
497
498
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000499Object*& ExitFrame::code_slot() const {
500 const int offset = ExitFrameConstants::kCodeOffset;
501 return Memory::Object_at(fp() + offset);
502}
503
504
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000505Code* ExitFrame::unchecked_code() const {
506 return reinterpret_cast<Code*>(code_slot());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000507}
508
509
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000510void ExitFrame::ComputeCallerState(State* state) const {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000511 // Set up the caller state.
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000512 state->sp = caller_sp();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000513 state->fp = Memory::Address_at(fp() + ExitFrameConstants::kCallerFPOffset);
ulan@chromium.org967e2702012-02-28 09:49:15 +0000514 state->pc_address = ResolveReturnAddressLocation(
515 reinterpret_cast<Address*>(fp() + ExitFrameConstants::kCallerPCOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000516}
517
518
ager@chromium.org357bf652010-04-12 11:30:10 +0000519void ExitFrame::SetCallerFp(Address caller_fp) {
520 Memory::Address_at(fp() + ExitFrameConstants::kCallerFPOffset) = caller_fp;
521}
522
523
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000524void ExitFrame::Iterate(ObjectVisitor* v) const {
525 // The arguments are traversed as part of the expression stack of
526 // the calling frame.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000527 IteratePc(v, pc_address(), LookupCode());
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000528 v->VisitPointer(&code_slot());
529}
530
531
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000532Address ExitFrame::GetCallerStackPointer() const {
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000533 return fp() + ExitFrameConstants::kCallerSPDisplacement;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000534}
535
536
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000537StackFrame::Type ExitFrame::GetStateForFramePointer(Address fp, State* state) {
538 if (fp == 0) return NONE;
539 Address sp = ComputeStackPointer(fp);
540 FillState(fp, sp, state);
541 ASSERT(*state->pc_address != NULL);
542 return EXIT;
543}
544
545
546void ExitFrame::FillState(Address fp, Address sp, State* state) {
547 state->sp = sp;
548 state->fp = fp;
ulan@chromium.org967e2702012-02-28 09:49:15 +0000549 state->pc_address = ResolveReturnAddressLocation(
550 reinterpret_cast<Address*>(sp - 1 * kPointerSize));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000551}
552
553
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000554Address StandardFrame::GetExpressionAddress(int n) const {
kasper.lund7276f142008-07-30 08:49:36 +0000555 const int offset = StandardFrameConstants::kExpressionsOffset;
556 return fp() + offset - n * kPointerSize;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000557}
558
559
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000560Object* StandardFrame::GetExpression(Address fp, int index) {
561 return Memory::Object_at(GetExpressionAddress(fp, index));
562}
563
564
565Address StandardFrame::GetExpressionAddress(Address fp, int n) {
566 const int offset = StandardFrameConstants::kExpressionsOffset;
567 return fp + offset - n * kPointerSize;
568}
569
570
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000571int StandardFrame::ComputeExpressionsCount() const {
572 const int offset =
573 StandardFrameConstants::kExpressionsOffset + kPointerSize;
574 Address base = fp() + offset;
575 Address limit = sp();
576 ASSERT(base >= limit); // stack grows downwards
577 // Include register-allocated locals in number of expressions.
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000578 return static_cast<int>((base - limit) / kPointerSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000579}
580
581
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000582void StandardFrame::ComputeCallerState(State* state) const {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000583 state->sp = caller_sp();
584 state->fp = caller_fp();
ulan@chromium.org967e2702012-02-28 09:49:15 +0000585 state->pc_address = ResolveReturnAddressLocation(
586 reinterpret_cast<Address*>(ComputePCAddress(fp())));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000587}
588
589
ager@chromium.org357bf652010-04-12 11:30:10 +0000590void StandardFrame::SetCallerFp(Address caller_fp) {
591 Memory::Address_at(fp() + StandardFrameConstants::kCallerFPOffset) =
592 caller_fp;
593}
594
595
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000596bool StandardFrame::IsExpressionInsideHandler(int n) const {
597 Address address = GetExpressionAddress(n);
598 for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) {
599 if (it.handler()->includes(address)) return true;
600 }
601 return false;
602}
603
604
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000605void OptimizedFrame::Iterate(ObjectVisitor* v) const {
606#ifdef DEBUG
607 // Make sure that optimized frames do not contain any stack handlers.
608 StackHandlerIterator it(this, top_handler());
609 ASSERT(it.done());
610#endif
611
612 // Make sure that we're not doing "safe" stack frame iteration. We cannot
613 // possibly find pointers in optimized frames in that state.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000614 ASSERT(!SafeStackFrameIterator::is_active(isolate()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000615
616 // Compute the safepoint information.
617 unsigned stack_slots = 0;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000618 SafepointEntry safepoint_entry;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000619 Code* code = StackFrame::GetSafepointData(
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000620 isolate(), pc(), &safepoint_entry, &stack_slots);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000621 unsigned slot_space = stack_slots * kPointerSize;
622
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000623 // Visit the outgoing parameters.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000624 Object** parameters_base = &Memory::Object_at(sp());
625 Object** parameters_limit = &Memory::Object_at(
626 fp() + JavaScriptFrameConstants::kFunctionOffset - slot_space);
627
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000628 // Visit the parameters that may be on top of the saved registers.
629 if (safepoint_entry.argument_count() > 0) {
630 v->VisitPointers(parameters_base,
631 parameters_base + safepoint_entry.argument_count());
632 parameters_base += safepoint_entry.argument_count();
633 }
634
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000635 // Skip saved double registers.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000636 if (safepoint_entry.has_doubles()) {
637 parameters_base += DoubleRegister::kNumAllocatableRegisters *
638 kDoubleSize / kPointerSize;
639 }
640
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000641 // Visit the registers that contain pointers if any.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000642 if (safepoint_entry.HasRegisters()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000643 for (int i = kNumSafepointRegisters - 1; i >=0; i--) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000644 if (safepoint_entry.HasRegisterAt(i)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000645 int reg_stack_index = MacroAssembler::SafepointRegisterStackIndex(i);
646 v->VisitPointer(parameters_base + reg_stack_index);
647 }
648 }
649 // Skip the words containing the register values.
650 parameters_base += kNumSafepointRegisters;
651 }
652
653 // We're done dealing with the register bits.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000654 uint8_t* safepoint_bits = safepoint_entry.bits();
655 safepoint_bits += kNumSafepointRegisters >> kBitsPerByteLog2;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000656
657 // Visit the rest of the parameters.
658 v->VisitPointers(parameters_base, parameters_limit);
659
660 // Visit pointer spill slots and locals.
661 for (unsigned index = 0; index < stack_slots; index++) {
662 int byte_index = index >> kBitsPerByteLog2;
663 int bit_index = index & (kBitsPerByte - 1);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000664 if ((safepoint_bits[byte_index] & (1U << bit_index)) != 0) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000665 v->VisitPointer(parameters_limit + index);
666 }
667 }
668
669 // Visit the context and the function.
670 Object** fixed_base = &Memory::Object_at(
671 fp() + JavaScriptFrameConstants::kFunctionOffset);
672 Object** fixed_limit = &Memory::Object_at(fp());
673 v->VisitPointers(fixed_base, fixed_limit);
674
675 // Visit the return address in the callee and incoming arguments.
676 IteratePc(v, pc_address(), code);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000677}
678
679
680bool JavaScriptFrame::IsConstructor() const {
ager@chromium.org7c537e22008-10-16 08:43:32 +0000681 Address fp = caller_fp();
682 if (has_adapted_arguments()) {
683 // Skip the arguments adaptor frame and look at the real caller.
684 fp = Memory::Address_at(fp + StandardFrameConstants::kCallerFPOffset);
685 }
686 return IsConstructFrame(fp);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000687}
688
689
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000690int JavaScriptFrame::GetArgumentsLength() const {
691 // If there is an arguments adaptor frame get the arguments length from it.
692 if (has_adapted_arguments()) {
693 return Smi::cast(GetExpression(caller_fp(), 0))->value();
694 } else {
695 return GetNumberOfIncomingArguments();
696 }
697}
698
699
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000700Code* JavaScriptFrame::unchecked_code() const {
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000701 JSFunction* function = JSFunction::cast(this->function());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000702 return function->unchecked_code();
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000703}
704
705
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000706int JavaScriptFrame::GetNumberOfIncomingArguments() const {
707 ASSERT(!SafeStackFrameIterator::is_active(isolate()) &&
708 isolate()->heap()->gc_state() == Heap::NOT_IN_GC);
709
710 JSFunction* function = JSFunction::cast(this->function());
711 return function->shared()->formal_parameter_count();
712}
713
714
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000715Address JavaScriptFrame::GetCallerStackPointer() const {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000716 return fp() + StandardFrameConstants::kCallerSPOffset;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000717}
718
719
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000720void JavaScriptFrame::GetFunctions(List<JSFunction*>* functions) {
721 ASSERT(functions->length() == 0);
722 functions->Add(JSFunction::cast(function()));
723}
724
725
726void JavaScriptFrame::Summarize(List<FrameSummary>* functions) {
727 ASSERT(functions->length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000728 Code* code_pointer = LookupCode();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000729 int offset = static_cast<int>(pc() - code_pointer->address());
730 FrameSummary summary(receiver(),
731 JSFunction::cast(function()),
732 code_pointer,
733 offset,
734 IsConstructor());
735 functions->Add(summary);
736}
737
738
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000739void JavaScriptFrame::PrintTop(FILE* file,
740 bool print_args,
741 bool print_line_number) {
742 // constructor calls
743 HandleScope scope;
744 AssertNoAllocation no_allocation;
745 JavaScriptFrameIterator it;
746 while (!it.done()) {
747 if (it.frame()->is_java_script()) {
748 JavaScriptFrame* frame = it.frame();
749 if (frame->IsConstructor()) PrintF(file, "new ");
750 // function name
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000751 Object* maybe_fun = frame->function();
752 if (maybe_fun->IsJSFunction()) {
753 JSFunction* fun = JSFunction::cast(maybe_fun);
754 fun->PrintName();
755 Code* js_code = frame->unchecked_code();
756 Address pc = frame->pc();
757 int code_offset =
758 static_cast<int>(pc - js_code->instruction_start());
759 PrintF("+%d", code_offset);
760 SharedFunctionInfo* shared = fun->shared();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000761 if (print_line_number) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000762 Code* code = Code::cast(
763 v8::internal::Isolate::Current()->heap()->FindCodeObject(pc));
764 int source_pos = code->SourcePosition(pc);
765 Object* maybe_script = shared->script();
766 if (maybe_script->IsScript()) {
767 Handle<Script> script(Script::cast(maybe_script));
768 int line = GetScriptLineNumberSafe(script, source_pos) + 1;
769 Object* script_name_raw = script->name();
770 if (script_name_raw->IsString()) {
771 String* script_name = String::cast(script->name());
772 SmartArrayPointer<char> c_script_name =
773 script_name->ToCString(DISALLOW_NULLS,
774 ROBUST_STRING_TRAVERSAL);
775 PrintF(file, " at %s:%d", *c_script_name, line);
776 } else {
777 PrintF(file, "at <unknown>:%d", line);
778 }
779 } else {
780 PrintF(file, " at <unknown>:<unknown>");
781 }
782 }
783 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000784 PrintF("<unknown>");
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000785 }
786
787 if (print_args) {
788 // function arguments
789 // (we are intentionally only printing the actually
790 // supplied parameters, not all parameters required)
791 PrintF(file, "(this=");
792 frame->receiver()->ShortPrint(file);
793 const int length = frame->ComputeParametersCount();
794 for (int i = 0; i < length; i++) {
795 PrintF(file, ", ");
796 frame->GetParameter(i)->ShortPrint(file);
797 }
798 PrintF(file, ")");
799 }
800 break;
801 }
802 it.Advance();
803 }
804}
805
806
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000807void FrameSummary::Print() {
808 PrintF("receiver: ");
809 receiver_->ShortPrint();
810 PrintF("\nfunction: ");
811 function_->shared()->DebugName()->ShortPrint();
812 PrintF("\ncode: ");
813 code_->ShortPrint();
814 if (code_->kind() == Code::FUNCTION) PrintF(" NON-OPT");
815 if (code_->kind() == Code::OPTIMIZED_FUNCTION) PrintF(" OPT");
816 PrintF("\npc: %d\n", offset_);
817}
818
819
820void OptimizedFrame::Summarize(List<FrameSummary>* frames) {
821 ASSERT(frames->length() == 0);
822 ASSERT(is_optimized());
823
ager@chromium.org378b34e2011-01-28 08:04:38 +0000824 int deopt_index = Safepoint::kNoDeoptimizationIndex;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000825 DeoptimizationInputData* data = GetDeoptimizationData(&deopt_index);
826
827 // BUG(3243555): Since we don't have a lazy-deopt registered at
828 // throw-statements, we can't use the translation at the call-site of
829 // throw. An entry with no deoptimization index indicates a call-site
830 // without a lazy-deopt. As a consequence we are not allowed to inline
831 // functions containing throw.
832 if (deopt_index == Safepoint::kNoDeoptimizationIndex) {
833 JavaScriptFrame::Summarize(frames);
834 return;
835 }
836
837 TranslationIterator it(data->TranslationByteArray(),
838 data->TranslationIndex(deopt_index)->value());
839 Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next());
840 ASSERT(opcode == Translation::BEGIN);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000841 it.Next(); // Drop frame count.
842 int jsframe_count = it.Next();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000843
844 // We create the summary in reverse order because the frames
845 // in the deoptimization translation are ordered bottom-to-top.
ulan@chromium.org967e2702012-02-28 09:49:15 +0000846 bool is_constructor = IsConstructor();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000847 int i = jsframe_count;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000848 while (i > 0) {
849 opcode = static_cast<Translation::Opcode>(it.Next());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000850 if (opcode == Translation::JS_FRAME) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000851 i--;
852 int ast_id = it.Next();
853 int function_id = it.Next();
854 it.Next(); // Skip height.
855 JSFunction* function =
856 JSFunction::cast(data->LiteralArray()->get(function_id));
857
858 // The translation commands are ordered and the receiver is always
859 // at the first position. Since we are always at a call when we need
860 // to construct a stack trace, the receiver is always in a stack slot.
861 opcode = static_cast<Translation::Opcode>(it.Next());
danno@chromium.org40cb8782011-05-25 07:58:50 +0000862 ASSERT(opcode == Translation::STACK_SLOT ||
863 opcode == Translation::LITERAL);
864 int index = it.Next();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000865
866 // Get the correct receiver in the optimized frame.
867 Object* receiver = NULL;
danno@chromium.org40cb8782011-05-25 07:58:50 +0000868 if (opcode == Translation::LITERAL) {
869 receiver = data->LiteralArray()->get(index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000870 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000871 // Positive index means the value is spilled to the locals
872 // area. Negative means it is stored in the incoming parameter
873 // area.
874 if (index >= 0) {
875 receiver = GetExpression(index);
876 } else {
877 // Index -1 overlaps with last parameter, -n with the first parameter,
878 // (-n - 1) with the receiver with n being the number of parameters
879 // of the outermost, optimized frame.
880 int parameter_count = ComputeParametersCount();
881 int parameter_index = index + parameter_count;
882 receiver = (parameter_index == -1)
883 ? this->receiver()
884 : this->GetParameter(parameter_index);
885 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000886 }
887
888 Code* code = function->shared()->code();
889 DeoptimizationOutputData* output_data =
890 DeoptimizationOutputData::cast(code->deoptimization_data());
891 unsigned entry = Deoptimizer::GetOutputInfo(output_data,
892 ast_id,
893 function->shared());
894 unsigned pc_offset =
895 FullCodeGenerator::PcField::decode(entry) + Code::kHeaderSize;
896 ASSERT(pc_offset > 0);
897
898 FrameSummary summary(receiver, function, code, pc_offset, is_constructor);
899 frames->Add(summary);
ulan@chromium.org967e2702012-02-28 09:49:15 +0000900 is_constructor = false;
901 } else if (opcode == Translation::CONSTRUCT_STUB_FRAME) {
902 // The next encountered JS_FRAME will be marked as a constructor call.
903 it.Skip(Translation::NumberOfOperandsFor(opcode));
904 ASSERT(!is_constructor);
905 is_constructor = true;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000906 } else {
907 // Skip over operands to advance to the next opcode.
908 it.Skip(Translation::NumberOfOperandsFor(opcode));
909 }
910 }
ulan@chromium.org967e2702012-02-28 09:49:15 +0000911 ASSERT(!is_constructor);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000912}
913
914
915DeoptimizationInputData* OptimizedFrame::GetDeoptimizationData(
916 int* deopt_index) {
917 ASSERT(is_optimized());
918
919 JSFunction* opt_function = JSFunction::cast(function());
920 Code* code = opt_function->code();
921
922 // The code object may have been replaced by lazy deoptimization. Fall
923 // back to a slow search in this case to find the original optimized
924 // code object.
925 if (!code->contains(pc())) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000926 code = isolate()->inner_pointer_to_code_cache()->
927 GcSafeFindCodeForInnerPointer(pc());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000928 }
929 ASSERT(code != NULL);
930 ASSERT(code->kind() == Code::OPTIMIZED_FUNCTION);
931
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000932 SafepointEntry safepoint_entry = code->GetSafepointEntry(pc());
933 *deopt_index = safepoint_entry.deoptimization_index();
ager@chromium.org378b34e2011-01-28 08:04:38 +0000934 ASSERT(*deopt_index != Safepoint::kNoDeoptimizationIndex);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000935
936 return DeoptimizationInputData::cast(code->deoptimization_data());
937}
938
939
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000940int OptimizedFrame::GetInlineCount() {
941 ASSERT(is_optimized());
942
943 int deopt_index = Safepoint::kNoDeoptimizationIndex;
944 DeoptimizationInputData* data = GetDeoptimizationData(&deopt_index);
945
946 TranslationIterator it(data->TranslationByteArray(),
947 data->TranslationIndex(deopt_index)->value());
948 Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next());
949 ASSERT(opcode == Translation::BEGIN);
950 USE(opcode);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000951 it.Next(); // Drop frame count.
952 int jsframe_count = it.Next();
953 return jsframe_count;
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000954}
955
956
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000957void OptimizedFrame::GetFunctions(List<JSFunction*>* functions) {
958 ASSERT(functions->length() == 0);
959 ASSERT(is_optimized());
960
ager@chromium.org378b34e2011-01-28 08:04:38 +0000961 int deopt_index = Safepoint::kNoDeoptimizationIndex;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000962 DeoptimizationInputData* data = GetDeoptimizationData(&deopt_index);
963
964 TranslationIterator it(data->TranslationByteArray(),
965 data->TranslationIndex(deopt_index)->value());
966 Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next());
967 ASSERT(opcode == Translation::BEGIN);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000968 it.Next(); // Drop frame count.
969 int jsframe_count = it.Next();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000970
971 // We insert the frames in reverse order because the frames
972 // in the deoptimization translation are ordered bottom-to-top.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000973 while (jsframe_count > 0) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000974 opcode = static_cast<Translation::Opcode>(it.Next());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000975 if (opcode == Translation::JS_FRAME) {
976 jsframe_count--;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000977 it.Next(); // Skip ast id.
978 int function_id = it.Next();
979 it.Next(); // Skip height.
980 JSFunction* function =
981 JSFunction::cast(data->LiteralArray()->get(function_id));
982 functions->Add(function);
983 } else {
984 // Skip over operands to advance to the next opcode.
985 it.Skip(Translation::NumberOfOperandsFor(opcode));
986 }
987 }
988}
989
990
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000991int ArgumentsAdaptorFrame::GetNumberOfIncomingArguments() const {
992 return Smi::cast(GetExpression(0))->value();
993}
994
995
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000996Address ArgumentsAdaptorFrame::GetCallerStackPointer() const {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000997 return fp() + StandardFrameConstants::kCallerSPOffset;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000998}
999
1000
1001Address InternalFrame::GetCallerStackPointer() const {
1002 // Internal frames have no arguments. The stack pointer of the
1003 // caller is at a fixed offset from the frame pointer.
1004 return fp() + StandardFrameConstants::kCallerSPOffset;
1005}
1006
1007
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001008Code* ArgumentsAdaptorFrame::unchecked_code() const {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00001009 return isolate()->builtins()->builtin(
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001010 Builtins::kArgumentsAdaptorTrampoline);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001011}
1012
1013
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001014Code* InternalFrame::unchecked_code() const {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001015 const int offset = InternalFrameConstants::kCodeOffset;
1016 Object* code = Memory::Object_at(fp() + offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001017 ASSERT(code != NULL);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001018 return reinterpret_cast<Code*>(code);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001019}
1020
1021
1022void StackFrame::PrintIndex(StringStream* accumulator,
1023 PrintMode mode,
1024 int index) {
1025 accumulator->Add((mode == OVERVIEW) ? "%5d: " : "[%d]: ", index);
1026}
1027
1028
1029void JavaScriptFrame::Print(StringStream* accumulator,
1030 PrintMode mode,
1031 int index) const {
1032 HandleScope scope;
1033 Object* receiver = this->receiver();
1034 Object* function = this->function();
1035
1036 accumulator->PrintSecurityTokenIfChanged(function);
1037 PrintIndex(accumulator, mode, index);
1038 Code* code = NULL;
1039 if (IsConstructor()) accumulator->Add("new ");
1040 accumulator->PrintFunction(function, receiver, &code);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00001041
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001042 // Get scope information for nicer output, if possible. If code is NULL, or
1043 // doesn't contain scope info, scope_info will return 0 for the number of
1044 // parameters, stack local variables, context local variables, stack slots,
1045 // or context slots.
1046 Handle<ScopeInfo> scope_info(ScopeInfo::Empty());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001047
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00001048 if (function->IsJSFunction()) {
1049 Handle<SharedFunctionInfo> shared(JSFunction::cast(function)->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001050 scope_info = Handle<ScopeInfo>(shared->scope_info());
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00001051 Object* script_obj = shared->script();
1052 if (script_obj->IsScript()) {
1053 Handle<Script> script(Script::cast(script_obj));
1054 accumulator->Add(" [");
1055 accumulator->PrintName(script->name());
1056
1057 Address pc = this->pc();
1058 if (code != NULL && code->kind() == Code::FUNCTION &&
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00001059 pc >= code->instruction_start() && pc < code->instruction_end()) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00001060 int source_pos = code->SourcePosition(pc);
1061 int line = GetScriptLineNumberSafe(script, source_pos) + 1;
1062 accumulator->Add(":%d", line);
1063 } else {
1064 int function_start_pos = shared->start_position();
1065 int line = GetScriptLineNumberSafe(script, function_start_pos) + 1;
1066 accumulator->Add(":~%d", line);
1067 }
1068
1069 accumulator->Add("] ");
1070 }
1071 }
1072
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001073 accumulator->Add("(this=%o", receiver);
1074
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001075 // Print the parameters.
1076 int parameters_count = ComputeParametersCount();
1077 for (int i = 0; i < parameters_count; i++) {
1078 accumulator->Add(",");
1079 // If we have a name for the parameter we print it. Nameless
1080 // parameters are either because we have more actual parameters
1081 // than formal parameters or because we have no scope information.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001082 if (i < scope_info->ParameterCount()) {
1083 accumulator->PrintName(scope_info->ParameterName(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001084 accumulator->Add("=");
1085 }
1086 accumulator->Add("%o", GetParameter(i));
1087 }
1088
1089 accumulator->Add(")");
1090 if (mode == OVERVIEW) {
1091 accumulator->Add("\n");
1092 return;
1093 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00001094 if (is_optimized()) {
1095 accumulator->Add(" {\n// optimized frame\n}\n");
1096 return;
1097 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001098 accumulator->Add(" {\n");
1099
1100 // Compute the number of locals and expression stack elements.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001101 int stack_locals_count = scope_info->StackLocalCount();
1102 int heap_locals_count = scope_info->ContextLocalCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001103 int expressions_count = ComputeExpressionsCount();
1104
1105 // Print stack-allocated local variables.
1106 if (stack_locals_count > 0) {
1107 accumulator->Add(" // stack-allocated locals\n");
1108 }
1109 for (int i = 0; i < stack_locals_count; i++) {
1110 accumulator->Add(" var ");
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001111 accumulator->PrintName(scope_info->StackLocalName(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001112 accumulator->Add(" = ");
1113 if (i < expressions_count) {
1114 accumulator->Add("%o", GetExpression(i));
1115 } else {
1116 accumulator->Add("// no expression found - inconsistent frame?");
1117 }
1118 accumulator->Add("\n");
1119 }
1120
1121 // Try to get hold of the context of this frame.
1122 Context* context = NULL;
1123 if (this->context() != NULL && this->context()->IsContext()) {
1124 context = Context::cast(this->context());
1125 }
1126
1127 // Print heap-allocated local variables.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001128 if (heap_locals_count > 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001129 accumulator->Add(" // heap-allocated locals\n");
1130 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001131 for (int i = 0; i < heap_locals_count; i++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001132 accumulator->Add(" var ");
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001133 accumulator->PrintName(scope_info->ContextLocalName(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001134 accumulator->Add(" = ");
1135 if (context != NULL) {
1136 if (i < context->length()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001137 accumulator->Add("%o", context->get(Context::MIN_CONTEXT_SLOTS + i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001138 } else {
1139 accumulator->Add(
1140 "// warning: missing context slot - inconsistent frame?");
1141 }
1142 } else {
1143 accumulator->Add("// warning: no context found - inconsistent frame?");
1144 }
1145 accumulator->Add("\n");
1146 }
1147
1148 // Print the expression stack.
kasper.lund7276f142008-07-30 08:49:36 +00001149 int expressions_start = stack_locals_count;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001150 if (expressions_start < expressions_count) {
1151 accumulator->Add(" // expression stack (top to bottom)\n");
1152 }
1153 for (int i = expressions_count - 1; i >= expressions_start; i--) {
1154 if (IsExpressionInsideHandler(i)) continue;
1155 accumulator->Add(" [%02d] : %o\n", i, GetExpression(i));
1156 }
1157
1158 // Print details about the function.
1159 if (FLAG_max_stack_trace_source_length != 0 && code != NULL) {
1160 SharedFunctionInfo* shared = JSFunction::cast(function)->shared();
1161 accumulator->Add("--------- s o u r c e c o d e ---------\n");
1162 shared->SourceCodePrint(accumulator, FLAG_max_stack_trace_source_length);
1163 accumulator->Add("\n-----------------------------------------\n");
1164 }
1165
1166 accumulator->Add("}\n\n");
1167}
1168
1169
1170void ArgumentsAdaptorFrame::Print(StringStream* accumulator,
1171 PrintMode mode,
1172 int index) const {
1173 int actual = ComputeParametersCount();
1174 int expected = -1;
1175 Object* function = this->function();
1176 if (function->IsJSFunction()) {
1177 expected = JSFunction::cast(function)->shared()->formal_parameter_count();
1178 }
1179
1180 PrintIndex(accumulator, mode, index);
1181 accumulator->Add("arguments adaptor frame: %d->%d", actual, expected);
1182 if (mode == OVERVIEW) {
1183 accumulator->Add("\n");
1184 return;
1185 }
1186 accumulator->Add(" {\n");
1187
1188 // Print actual arguments.
1189 if (actual > 0) accumulator->Add(" // actual arguments\n");
1190 for (int i = 0; i < actual; i++) {
1191 accumulator->Add(" [%02d] : %o", i, GetParameter(i));
1192 if (expected != -1 && i >= expected) {
1193 accumulator->Add(" // not passed to callee");
1194 }
1195 accumulator->Add("\n");
1196 }
1197
1198 accumulator->Add("}\n\n");
1199}
1200
1201
1202void EntryFrame::Iterate(ObjectVisitor* v) const {
1203 StackHandlerIterator it(this, top_handler());
1204 ASSERT(!it.done());
1205 StackHandler* handler = it.handler();
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001206 ASSERT(handler->is_js_entry());
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00001207 handler->Iterate(v, LookupCode());
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001208#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001209 // Make sure that the entry frame does not contain more than one
1210 // stack handler.
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001211 it.Advance();
1212 ASSERT(it.done());
1213#endif
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00001214 IteratePc(v, pc_address(), LookupCode());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001215}
1216
1217
1218void StandardFrame::IterateExpressions(ObjectVisitor* v) const {
1219 const int offset = StandardFrameConstants::kContextOffset;
1220 Object** base = &Memory::Object_at(sp());
1221 Object** limit = &Memory::Object_at(fp() + offset) + 1;
1222 for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) {
1223 StackHandler* handler = it.handler();
1224 // Traverse pointers down to - but not including - the next
1225 // handler in the handler chain. Update the base to skip the
1226 // handler and allow the handler to traverse its own pointers.
1227 const Address address = handler->address();
1228 v->VisitPointers(base, reinterpret_cast<Object**>(address));
1229 base = reinterpret_cast<Object**>(address + StackHandlerConstants::kSize);
1230 // Traverse the pointers in the handler itself.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00001231 handler->Iterate(v, LookupCode());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001232 }
1233 v->VisitPointers(base, limit);
1234}
1235
1236
1237void JavaScriptFrame::Iterate(ObjectVisitor* v) const {
1238 IterateExpressions(v);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00001239 IteratePc(v, pc_address(), LookupCode());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001240}
1241
1242
1243void InternalFrame::Iterate(ObjectVisitor* v) const {
1244 // Internal frames only have object pointers on the expression stack
1245 // as they never have any arguments.
1246 IterateExpressions(v);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00001247 IteratePc(v, pc_address(), LookupCode());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001248}
1249
1250
1251// -------------------------------------------------------------------------
1252
1253
1254JavaScriptFrame* StackFrameLocator::FindJavaScriptFrame(int n) {
1255 ASSERT(n >= 0);
1256 for (int i = 0; i <= n; i++) {
1257 while (!iterator_.frame()->is_java_script()) iterator_.Advance();
1258 if (i == n) return JavaScriptFrame::cast(iterator_.frame());
1259 iterator_.Advance();
1260 }
1261 UNREACHABLE();
1262 return NULL;
1263}
1264
1265
1266// -------------------------------------------------------------------------
1267
1268
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001269static Map* GcSafeMapOfCodeSpaceObject(HeapObject* object) {
1270 MapWord map_word = object->map_word();
1271 return map_word.IsForwardingAddress() ?
1272 map_word.ToForwardingAddress()->map() : map_word.ToMap();
1273}
1274
1275
1276static int GcSafeSizeOfCodeSpaceObject(HeapObject* object) {
1277 return object->SizeFromMap(GcSafeMapOfCodeSpaceObject(object));
1278}
1279
1280
1281#ifdef DEBUG
1282static bool GcSafeCodeContains(HeapObject* code, Address addr) {
1283 Map* map = GcSafeMapOfCodeSpaceObject(code);
1284 ASSERT(map == code->GetHeap()->code_map());
1285 Address start = code->address();
1286 Address end = code->address() + code->SizeFromMap(map);
1287 return start <= addr && addr < end;
1288}
1289#endif
1290
1291
1292Code* InnerPointerToCodeCache::GcSafeCastToCode(HeapObject* object,
1293 Address inner_pointer) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001294 Code* code = reinterpret_cast<Code*>(object);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001295 ASSERT(code != NULL && GcSafeCodeContains(code, inner_pointer));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001296 return code;
1297}
1298
1299
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001300Code* InnerPointerToCodeCache::GcSafeFindCodeForInnerPointer(
1301 Address inner_pointer) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001302 Heap* heap = isolate_->heap();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001303 // Check if the inner pointer points into a large object chunk.
1304 LargePage* large_page = heap->lo_space()->FindPageContainingPc(inner_pointer);
1305 if (large_page != NULL) {
1306 return GcSafeCastToCode(large_page->GetObject(), inner_pointer);
1307 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001308
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001309 // Iterate through the page until we reach the end or find an object starting
1310 // after the inner pointer.
1311 Page* page = Page::FromAddress(inner_pointer);
1312
1313 Address addr = page->skip_list()->StartFor(inner_pointer);
1314
1315 Address top = heap->code_space()->top();
1316 Address limit = heap->code_space()->limit();
1317
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001318 while (true) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001319 if (addr == top && addr != limit) {
1320 addr = limit;
1321 continue;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001322 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001323
1324 HeapObject* obj = HeapObject::FromAddress(addr);
1325 int obj_size = GcSafeSizeOfCodeSpaceObject(obj);
1326 Address next_addr = addr + obj_size;
1327 if (next_addr > inner_pointer) return GcSafeCastToCode(obj, inner_pointer);
1328 addr = next_addr;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001329 }
1330}
1331
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001332
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001333InnerPointerToCodeCache::InnerPointerToCodeCacheEntry*
1334 InnerPointerToCodeCache::GetCacheEntry(Address inner_pointer) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001335 isolate_->counters()->pc_to_code()->Increment();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001336 ASSERT(IsPowerOf2(kInnerPointerToCodeCacheSize));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001337 uint32_t hash = ComputeIntegerHash(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001338 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(inner_pointer)),
1339 v8::internal::kZeroHashSeed);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001340 uint32_t index = hash & (kInnerPointerToCodeCacheSize - 1);
1341 InnerPointerToCodeCacheEntry* entry = cache(index);
1342 if (entry->inner_pointer == inner_pointer) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001343 isolate_->counters()->pc_to_code_cached()->Increment();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001344 ASSERT(entry->code == GcSafeFindCodeForInnerPointer(inner_pointer));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001345 } else {
1346 // Because this code may be interrupted by a profiling signal that
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001347 // also queries the cache, we cannot update inner_pointer before the code
1348 // has been set. Otherwise, we risk trying to use a cache entry before
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001349 // the code has been computed.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001350 entry->code = GcSafeFindCodeForInnerPointer(inner_pointer);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001351 entry->safepoint_entry.Reset();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001352 entry->inner_pointer = inner_pointer;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001353 }
1354 return entry;
1355}
1356
1357
1358// -------------------------------------------------------------------------
1359
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001360int NumRegs(RegList reglist) {
1361 int n = 0;
1362 while (reglist != 0) {
1363 n++;
1364 reglist &= reglist - 1; // clear one bit
1365 }
1366 return n;
1367}
1368
1369
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001370struct JSCallerSavedCodeData {
1371 JSCallerSavedCodeData() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001372 int i = 0;
1373 for (int r = 0; r < kNumRegs; r++)
1374 if ((kJSCallerSaved & (1 << r)) != 0)
1375 reg_code[i++] = r;
1376
1377 ASSERT(i == kNumJSCallerSaved);
1378 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001379 int reg_code[kNumJSCallerSaved];
1380};
1381
1382
1383static const JSCallerSavedCodeData kCallerSavedCodeData;
1384
1385
1386int JSCallerSavedCode(int n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001387 ASSERT(0 <= n && n < kNumJSCallerSaved);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001388 return kCallerSavedCodeData.reg_code[n];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001389}
1390
1391
ager@chromium.org357bf652010-04-12 11:30:10 +00001392#define DEFINE_WRAPPER(type, field) \
1393class field##_Wrapper : public ZoneObject { \
1394 public: /* NOLINT */ \
1395 field##_Wrapper(const field& original) : frame_(original) { \
1396 } \
1397 field frame_; \
1398};
1399STACK_FRAME_TYPE_LIST(DEFINE_WRAPPER)
1400#undef DEFINE_WRAPPER
1401
1402static StackFrame* AllocateFrameCopy(StackFrame* frame) {
1403#define FRAME_TYPE_CASE(type, field) \
1404 case StackFrame::type: { \
1405 field##_Wrapper* wrapper = \
1406 new field##_Wrapper(*(reinterpret_cast<field*>(frame))); \
1407 return &wrapper->frame_; \
1408 }
1409
1410 switch (frame->type()) {
1411 STACK_FRAME_TYPE_LIST(FRAME_TYPE_CASE)
1412 default: UNREACHABLE();
1413 }
1414#undef FRAME_TYPE_CASE
1415 return NULL;
1416}
1417
1418Vector<StackFrame*> CreateStackMap() {
1419 ZoneList<StackFrame*> list(10);
1420 for (StackFrameIterator it; !it.done(); it.Advance()) {
1421 StackFrame* frame = AllocateFrameCopy(it.frame());
1422 list.Add(frame);
1423 }
1424 return list.ToVector();
1425}
1426
1427
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001428} } // namespace v8::internal