blob: 30d0456634e3c6de55f0b647dd81e5ca874026aa [file] [log] [blame]
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001// Copyright 2006-2008 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
kasperl@chromium.org71affb52009-05-26 05:44:31 +000039namespace v8 {
40namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000041
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +000042
43int SafeStackFrameIterator::active_count_ = 0;
44
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000045// Iterator that supports traversing the stack handlers of a
46// particular frame. Needs to know the top of the handler chain.
47class StackHandlerIterator BASE_EMBEDDED {
48 public:
49 StackHandlerIterator(const StackFrame* frame, StackHandler* handler)
50 : limit_(frame->fp()), handler_(handler) {
51 // Make sure the handler has already been unwound to this frame.
52 ASSERT(frame->sp() <= handler->address());
53 }
54
55 StackHandler* handler() const { return handler_; }
56
ager@chromium.orgeadaf222009-06-16 09:43:10 +000057 bool done() {
58 return handler_ == NULL || handler_->address() > limit_;
59 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000060 void Advance() {
61 ASSERT(!done());
62 handler_ = handler_->next();
63 }
64
65 private:
66 const Address limit_;
67 StackHandler* handler_;
68};
69
70
71// -------------------------------------------------------------------------
72
73
74#define INITIALIZE_SINGLETON(type, field) field##_(this),
75StackFrameIterator::StackFrameIterator()
76 : STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000077 frame_(NULL), handler_(NULL),
78 thread_(Isolate::Current()->thread_local_top()),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000079 fp_(NULL), sp_(NULL), advance_(&StackFrameIterator::AdvanceWithHandler) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000080 Reset();
81}
82StackFrameIterator::StackFrameIterator(ThreadLocalTop* t)
83 : STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON)
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000084 frame_(NULL), handler_(NULL), thread_(t),
85 fp_(NULL), sp_(NULL), advance_(&StackFrameIterator::AdvanceWithHandler) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000086 Reset();
87}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000088StackFrameIterator::StackFrameIterator(Isolate* isolate,
89 bool use_top, Address fp, Address sp)
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000090 : STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON)
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000091 frame_(NULL), handler_(NULL),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000092 thread_(use_top ? isolate->thread_local_top() : NULL),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000093 fp_(use_top ? NULL : fp), sp_(sp),
94 advance_(use_top ? &StackFrameIterator::AdvanceWithHandler :
95 &StackFrameIterator::AdvanceWithoutHandler) {
96 if (use_top || fp != NULL) {
97 Reset();
98 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000099}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000100
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000101#undef INITIALIZE_SINGLETON
102
103
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000104void StackFrameIterator::AdvanceWithHandler() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000105 ASSERT(!done());
106 // Compute the state of the calling frame before restoring
107 // callee-saved registers and unwinding handlers. This allows the
108 // frame code that computes the caller state to access the top
109 // handler and the value of any callee-saved register if needed.
110 StackFrame::State state;
111 StackFrame::Type type = frame_->GetCallerState(&state);
112
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000113 // Unwind handlers corresponding to the current frame.
114 StackHandlerIterator it(frame_, handler_);
115 while (!it.done()) it.Advance();
116 handler_ = it.handler();
117
118 // Advance to the calling frame.
119 frame_ = SingletonFor(type, &state);
120
121 // When we're done iterating over the stack frames, the handler
122 // chain must have been completely unwound.
123 ASSERT(!done() || handler_ == NULL);
124}
125
126
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000127void StackFrameIterator::AdvanceWithoutHandler() {
128 // A simpler version of Advance which doesn't care about handler.
129 ASSERT(!done());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000130 StackFrame::State state;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000131 StackFrame::Type type = frame_->GetCallerState(&state);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000132 frame_ = SingletonFor(type, &state);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000133}
134
135
136void StackFrameIterator::Reset() {
137 StackFrame::State state;
138 StackFrame::Type type;
139 if (thread_ != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000140 type = ExitFrame::GetStateForFramePointer(
141 Isolate::c_entry_fp(thread_), &state);
142 handler_ = StackHandler::FromAddress(
143 Isolate::handler(thread_));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000144 } else {
145 ASSERT(fp_ != NULL);
146 state.fp = fp_;
147 state.sp = sp_;
148 state.pc_address =
149 reinterpret_cast<Address*>(StandardFrame::ComputePCAddress(fp_));
150 type = StackFrame::ComputeType(&state);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000151 }
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000152 if (SingletonFor(type) == NULL) return;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000153 frame_ = SingletonFor(type, &state);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000154}
155
156
157StackFrame* StackFrameIterator::SingletonFor(StackFrame::Type type,
158 StackFrame::State* state) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000159 if (type == StackFrame::NONE) return NULL;
160 StackFrame* result = SingletonFor(type);
161 ASSERT(result != NULL);
162 result->state_ = *state;
163 return result;
164}
165
166
167StackFrame* StackFrameIterator::SingletonFor(StackFrame::Type type) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000168#define FRAME_TYPE_CASE(type, field) \
169 case StackFrame::type: result = &field##_; break;
170
171 StackFrame* result = NULL;
172 switch (type) {
173 case StackFrame::NONE: return NULL;
174 STACK_FRAME_TYPE_LIST(FRAME_TYPE_CASE)
175 default: break;
176 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000177 return result;
178
179#undef FRAME_TYPE_CASE
180}
181
182
183// -------------------------------------------------------------------------
184
185
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000186StackTraceFrameIterator::StackTraceFrameIterator() {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000187 if (!done() && !IsValidFrame()) Advance();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000188}
189
190
191void StackTraceFrameIterator::Advance() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000192 while (true) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000193 JavaScriptFrameIterator::Advance();
194 if (done()) return;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000195 if (IsValidFrame()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000196 }
197}
198
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000199bool StackTraceFrameIterator::IsValidFrame() {
200 if (!frame()->function()->IsJSFunction()) return false;
201 Object* script = JSFunction::cast(frame()->function())->shared()->script();
202 // Don't show functions from native scripts to user.
203 return (script->IsScript() &&
204 Script::TYPE_NATIVE != Script::cast(script)->type()->value());
205}
206
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000207
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000208// -------------------------------------------------------------------------
209
210
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000211bool SafeStackFrameIterator::ExitFrameValidator::IsValidFP(Address fp) {
212 if (!validator_.IsValid(fp)) return false;
213 Address sp = ExitFrame::ComputeStackPointer(fp);
214 if (!validator_.IsValid(sp)) return false;
215 StackFrame::State state;
216 ExitFrame::FillState(fp, sp, &state);
217 if (!validator_.IsValid(reinterpret_cast<Address>(state.pc_address))) {
218 return false;
219 }
220 return *state.pc_address != NULL;
221}
222
223
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000224SafeStackFrameIterator::SafeStackFrameIterator(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000225 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000226 Address fp, Address sp, Address low_bound, Address high_bound) :
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000227 maintainer_(),
228 stack_validator_(low_bound, high_bound),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000229 is_valid_top_(IsValidTop(isolate, low_bound, high_bound)),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000230 is_valid_fp_(IsWithinBounds(low_bound, high_bound, fp)),
231 is_working_iterator_(is_valid_top_ || is_valid_fp_),
232 iteration_done_(!is_working_iterator_),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000233 iterator_(isolate, is_valid_top_, is_valid_fp_ ? fp : NULL, sp) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000234}
235
236
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000237bool SafeStackFrameIterator::IsValidTop(Isolate* isolate,
238 Address low_bound, Address high_bound) {
239 ThreadLocalTop* top = isolate->thread_local_top();
240 Address fp = Isolate::c_entry_fp(top);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000241 ExitFrameValidator validator(low_bound, high_bound);
242 if (!validator.IsValidFP(fp)) return false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000243 return Isolate::handler(top) != NULL;
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000244}
245
246
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000247void SafeStackFrameIterator::Advance() {
248 ASSERT(is_working_iterator_);
249 ASSERT(!done());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000250 StackFrame* last_frame = iterator_.frame();
251 Address last_sp = last_frame->sp(), last_fp = last_frame->fp();
252 // Before advancing to the next stack frame, perform pointer validity tests
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000253 iteration_done_ = !IsValidFrame(last_frame) ||
254 !CanIterateHandles(last_frame, iterator_.handler()) ||
255 !IsValidCaller(last_frame);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000256 if (iteration_done_) return;
257
258 iterator_.Advance();
259 if (iterator_.done()) return;
260 // Check that we have actually moved to the previous frame in the stack
261 StackFrame* prev_frame = iterator_.frame();
262 iteration_done_ = prev_frame->sp() < last_sp || prev_frame->fp() < last_fp;
263}
264
265
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000266bool SafeStackFrameIterator::CanIterateHandles(StackFrame* frame,
267 StackHandler* handler) {
268 // If StackIterator iterates over StackHandles, verify that
269 // StackHandlerIterator can be instantiated (see StackHandlerIterator
270 // constructor.)
271 return !is_valid_top_ || (frame->sp() <= handler->address());
272}
273
274
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000275bool SafeStackFrameIterator::IsValidFrame(StackFrame* frame) const {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000276 return IsValidStackAddress(frame->sp()) && IsValidStackAddress(frame->fp());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000277}
278
279
280bool SafeStackFrameIterator::IsValidCaller(StackFrame* frame) {
281 StackFrame::State state;
ager@chromium.org41826e72009-03-30 13:30:57 +0000282 if (frame->is_entry() || frame->is_entry_construct()) {
283 // See EntryFrame::GetCallerState. It computes the caller FP address
284 // and calls ExitFrame::GetStateForFramePointer on it. We need to be
285 // sure that caller FP address is valid.
286 Address caller_fp = Memory::Address_at(
287 frame->fp() + EntryFrameConstants::kCallerFPOffset);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000288 ExitFrameValidator validator(stack_validator_);
289 if (!validator.IsValidFP(caller_fp)) return false;
ager@chromium.org41826e72009-03-30 13:30:57 +0000290 } else if (frame->is_arguments_adaptor()) {
291 // See ArgumentsAdaptorFrame::GetCallerStackPointer. It assumes that
292 // the number of arguments is stored on stack as Smi. We need to check
293 // that it really an Smi.
294 Object* number_of_args = reinterpret_cast<ArgumentsAdaptorFrame*>(frame)->
295 GetExpression(0);
296 if (!number_of_args->IsSmi()) {
297 return false;
298 }
299 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000300 frame->ComputeCallerState(&state);
301 return IsValidStackAddress(state.sp) && IsValidStackAddress(state.fp) &&
302 iterator_.SingletonFor(frame->GetCallerState(&state)) != NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000303}
304
305
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000306void SafeStackFrameIterator::Reset() {
307 if (is_working_iterator_) {
308 iterator_.Reset();
309 iteration_done_ = false;
310 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000311}
312
313
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000314// -------------------------------------------------------------------------
315
316
317#ifdef ENABLE_LOGGING_AND_PROFILING
318SafeStackTraceFrameIterator::SafeStackTraceFrameIterator(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000319 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000320 Address fp, Address sp, Address low_bound, Address high_bound) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000321 SafeJavaScriptFrameIterator(isolate, fp, sp, low_bound, high_bound) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000322 if (!done() && !frame()->is_java_script()) Advance();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000323}
324
325
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000326void SafeStackTraceFrameIterator::Advance() {
327 while (true) {
328 SafeJavaScriptFrameIterator::Advance();
329 if (done()) return;
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000330 if (frame()->is_java_script()) return;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000331 }
332}
333#endif
334
335
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000336Code* StackFrame::GetSafepointData(Address pc,
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000337 SafepointEntry* safepoint_entry,
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000338 unsigned* stack_slots) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000339 Isolate* isolate = Isolate::Current();
340 PcToCodeCache::PcToCodeCacheEntry* entry =
341 isolate->pc_to_code_cache()->GetCacheEntry(pc);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000342 SafepointEntry cached_safepoint_entry = entry->safepoint_entry;
343 if (!entry->safepoint_entry.is_valid()) {
344 entry->safepoint_entry = entry->code->GetSafepointEntry(pc);
345 ASSERT(entry->safepoint_entry.is_valid());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000346 } else {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000347 ASSERT(entry->safepoint_entry.Equals(entry->code->GetSafepointEntry(pc)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000348 }
349
350 // Fill in the results and return the code.
351 Code* code = entry->code;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000352 *safepoint_entry = entry->safepoint_entry;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000353 *stack_slots = code->stack_slots();
354 return code;
355}
356
357
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000358bool StackFrame::HasHandler() const {
359 StackHandlerIterator it(this, top_handler());
360 return !it.done();
361}
362
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000363
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000364void StackFrame::IteratePc(ObjectVisitor* v,
365 Address* pc_address,
366 Code* holder) {
367 Address pc = *pc_address;
368 ASSERT(holder->contains(pc));
369 unsigned pc_offset = static_cast<unsigned>(pc - holder->instruction_start());
370 Object* code = holder;
371 v->VisitPointer(&code);
372 if (code != holder) {
373 holder = reinterpret_cast<Code*>(code);
374 pc = holder->instruction_start() + pc_offset;
375 *pc_address = pc;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000376 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000377}
378
379
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000380StackFrame::Type StackFrame::ComputeType(State* state) {
381 ASSERT(state->fp != NULL);
382 if (StandardFrame::IsArgumentsAdaptorFrame(state->fp)) {
383 return ARGUMENTS_ADAPTOR;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000384 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000385 // The marker and function offsets overlap. If the marker isn't a
386 // smi then the frame is a JavaScript frame -- and the marker is
387 // really the function.
388 const int offset = StandardFrameConstants::kMarkerOffset;
389 Object* marker = Memory::Object_at(state->fp + offset);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000390 if (!marker->IsSmi()) {
391 // If we're using a "safe" stack iterator, we treat optimized
392 // frames as normal JavaScript frames to avoid having to look
393 // into the heap to determine the state. This is safe as long
394 // as nobody tries to GC...
395 if (SafeStackFrameIterator::is_active()) return JAVA_SCRIPT;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000396 Code::Kind kind = GetContainingCode(Isolate::Current(),
397 *(state->pc_address))->kind();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000398 ASSERT(kind == Code::FUNCTION || kind == Code::OPTIMIZED_FUNCTION);
399 return (kind == Code::OPTIMIZED_FUNCTION) ? OPTIMIZED : JAVA_SCRIPT;
400 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000401 return static_cast<StackFrame::Type>(Smi::cast(marker)->value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000402}
403
404
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000405
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000406StackFrame::Type StackFrame::GetCallerState(State* state) const {
407 ComputeCallerState(state);
408 return ComputeType(state);
409}
410
411
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000412Code* EntryFrame::unchecked_code() const {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000413 return HEAP->raw_unchecked_js_entry_code();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000414}
415
416
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000417void EntryFrame::ComputeCallerState(State* state) const {
418 GetCallerState(state);
419}
420
421
ager@chromium.org357bf652010-04-12 11:30:10 +0000422void EntryFrame::SetCallerFp(Address caller_fp) {
423 const int offset = EntryFrameConstants::kCallerFPOffset;
424 Memory::Address_at(this->fp() + offset) = caller_fp;
425}
426
427
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000428StackFrame::Type EntryFrame::GetCallerState(State* state) const {
429 const int offset = EntryFrameConstants::kCallerFPOffset;
430 Address fp = Memory::Address_at(this->fp() + offset);
431 return ExitFrame::GetStateForFramePointer(fp, state);
432}
433
434
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000435Code* EntryConstructFrame::unchecked_code() const {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000436 return HEAP->raw_unchecked_js_construct_entry_code();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000437}
438
439
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000440Object*& ExitFrame::code_slot() const {
441 const int offset = ExitFrameConstants::kCodeOffset;
442 return Memory::Object_at(fp() + offset);
443}
444
445
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000446Code* ExitFrame::unchecked_code() const {
447 return reinterpret_cast<Code*>(code_slot());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000448}
449
450
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000451void ExitFrame::ComputeCallerState(State* state) const {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000452 // Setup the caller state.
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000453 state->sp = caller_sp();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000454 state->fp = Memory::Address_at(fp() + ExitFrameConstants::kCallerFPOffset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000455 state->pc_address
456 = reinterpret_cast<Address*>(fp() + ExitFrameConstants::kCallerPCOffset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000457}
458
459
ager@chromium.org357bf652010-04-12 11:30:10 +0000460void ExitFrame::SetCallerFp(Address caller_fp) {
461 Memory::Address_at(fp() + ExitFrameConstants::kCallerFPOffset) = caller_fp;
462}
463
464
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000465void ExitFrame::Iterate(ObjectVisitor* v) const {
466 // The arguments are traversed as part of the expression stack of
467 // the calling frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000468 IteratePc(v, pc_address(), LookupCode(Isolate::Current()));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000469 v->VisitPointer(&code_slot());
470}
471
472
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000473Address ExitFrame::GetCallerStackPointer() const {
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000474 return fp() + ExitFrameConstants::kCallerSPDisplacement;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000475}
476
477
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000478StackFrame::Type ExitFrame::GetStateForFramePointer(Address fp, State* state) {
479 if (fp == 0) return NONE;
480 Address sp = ComputeStackPointer(fp);
481 FillState(fp, sp, state);
482 ASSERT(*state->pc_address != NULL);
483 return EXIT;
484}
485
486
487void ExitFrame::FillState(Address fp, Address sp, State* state) {
488 state->sp = sp;
489 state->fp = fp;
490 state->pc_address = reinterpret_cast<Address*>(sp - 1 * kPointerSize);
491}
492
493
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000494Address StandardFrame::GetExpressionAddress(int n) const {
kasper.lund7276f142008-07-30 08:49:36 +0000495 const int offset = StandardFrameConstants::kExpressionsOffset;
496 return fp() + offset - n * kPointerSize;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000497}
498
499
500int StandardFrame::ComputeExpressionsCount() const {
501 const int offset =
502 StandardFrameConstants::kExpressionsOffset + kPointerSize;
503 Address base = fp() + offset;
504 Address limit = sp();
505 ASSERT(base >= limit); // stack grows downwards
506 // Include register-allocated locals in number of expressions.
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000507 return static_cast<int>((base - limit) / kPointerSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000508}
509
510
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000511void StandardFrame::ComputeCallerState(State* state) const {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000512 state->sp = caller_sp();
513 state->fp = caller_fp();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000514 state->pc_address = reinterpret_cast<Address*>(ComputePCAddress(fp()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000515}
516
517
ager@chromium.org357bf652010-04-12 11:30:10 +0000518void StandardFrame::SetCallerFp(Address caller_fp) {
519 Memory::Address_at(fp() + StandardFrameConstants::kCallerFPOffset) =
520 caller_fp;
521}
522
523
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000524bool StandardFrame::IsExpressionInsideHandler(int n) const {
525 Address address = GetExpressionAddress(n);
526 for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) {
527 if (it.handler()->includes(address)) return true;
528 }
529 return false;
530}
531
532
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000533void OptimizedFrame::Iterate(ObjectVisitor* v) const {
534#ifdef DEBUG
535 // Make sure that optimized frames do not contain any stack handlers.
536 StackHandlerIterator it(this, top_handler());
537 ASSERT(it.done());
538#endif
539
540 // Make sure that we're not doing "safe" stack frame iteration. We cannot
541 // possibly find pointers in optimized frames in that state.
542 ASSERT(!SafeStackFrameIterator::is_active());
543
544 // Compute the safepoint information.
545 unsigned stack_slots = 0;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000546 SafepointEntry safepoint_entry;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000547 Code* code = StackFrame::GetSafepointData(
548 pc(), &safepoint_entry, &stack_slots);
549 unsigned slot_space = stack_slots * kPointerSize;
550
551 // Visit the outgoing parameters. This is usually dealt with by the
552 // callee, but while GC'ing we artificially lower the number of
553 // arguments to zero and let the caller deal with it.
554 Object** parameters_base = &Memory::Object_at(sp());
555 Object** parameters_limit = &Memory::Object_at(
556 fp() + JavaScriptFrameConstants::kFunctionOffset - slot_space);
557
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000558 // Visit the parameters that may be on top of the saved registers.
559 if (safepoint_entry.argument_count() > 0) {
560 v->VisitPointers(parameters_base,
561 parameters_base + safepoint_entry.argument_count());
562 parameters_base += safepoint_entry.argument_count();
563 }
564
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000565 // Skip saved double registers.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000566 if (safepoint_entry.has_doubles()) {
567 parameters_base += DoubleRegister::kNumAllocatableRegisters *
568 kDoubleSize / kPointerSize;
569 }
570
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000571 // Visit the registers that contain pointers if any.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000572 if (safepoint_entry.HasRegisters()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000573 for (int i = kNumSafepointRegisters - 1; i >=0; i--) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000574 if (safepoint_entry.HasRegisterAt(i)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000575 int reg_stack_index = MacroAssembler::SafepointRegisterStackIndex(i);
576 v->VisitPointer(parameters_base + reg_stack_index);
577 }
578 }
579 // Skip the words containing the register values.
580 parameters_base += kNumSafepointRegisters;
581 }
582
583 // We're done dealing with the register bits.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000584 uint8_t* safepoint_bits = safepoint_entry.bits();
585 safepoint_bits += kNumSafepointRegisters >> kBitsPerByteLog2;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000586
587 // Visit the rest of the parameters.
588 v->VisitPointers(parameters_base, parameters_limit);
589
590 // Visit pointer spill slots and locals.
591 for (unsigned index = 0; index < stack_slots; index++) {
592 int byte_index = index >> kBitsPerByteLog2;
593 int bit_index = index & (kBitsPerByte - 1);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000594 if ((safepoint_bits[byte_index] & (1U << bit_index)) != 0) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000595 v->VisitPointer(parameters_limit + index);
596 }
597 }
598
599 // Visit the context and the function.
600 Object** fixed_base = &Memory::Object_at(
601 fp() + JavaScriptFrameConstants::kFunctionOffset);
602 Object** fixed_limit = &Memory::Object_at(fp());
603 v->VisitPointers(fixed_base, fixed_limit);
604
605 // Visit the return address in the callee and incoming arguments.
606 IteratePc(v, pc_address(), code);
607 IterateArguments(v);
608}
609
610
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000611Object* JavaScriptFrame::GetParameter(int index) const {
612 ASSERT(index >= 0 && index < ComputeParametersCount());
613 const int offset = JavaScriptFrameConstants::kParam0Offset;
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000614 return Memory::Object_at(caller_sp() + offset - (index * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000615}
616
617
618int JavaScriptFrame::ComputeParametersCount() const {
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000619 Address base = caller_sp() + JavaScriptFrameConstants::kReceiverOffset;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000620 Address limit = fp() + JavaScriptFrameConstants::kSavedRegistersOffset;
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000621 return static_cast<int>((base - limit) / kPointerSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000622}
623
624
625bool JavaScriptFrame::IsConstructor() const {
ager@chromium.org7c537e22008-10-16 08:43:32 +0000626 Address fp = caller_fp();
627 if (has_adapted_arguments()) {
628 // Skip the arguments adaptor frame and look at the real caller.
629 fp = Memory::Address_at(fp + StandardFrameConstants::kCallerFPOffset);
630 }
631 return IsConstructFrame(fp);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000632}
633
634
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000635Code* JavaScriptFrame::unchecked_code() const {
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000636 JSFunction* function = JSFunction::cast(this->function());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000637 return function->unchecked_code();
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000638}
639
640
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000641Address JavaScriptFrame::GetCallerStackPointer() const {
642 int arguments;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000643 if (SafeStackFrameIterator::is_active() ||
644 HEAP->gc_state() != Heap::NOT_IN_GC) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000645 // If the we are currently iterating the safe stack the
646 // arguments for frames are traversed as if they were
647 // expression stack elements of the calling frame. The reason for
648 // this rather strange decision is that we cannot access the
649 // function during mark-compact GCs when objects may have been marked.
650 // In fact accessing heap objects (like function->shared() below)
651 // at all during GC is problematic.
652 arguments = 0;
653 } else {
654 // Compute the number of arguments by getting the number of formal
655 // parameters of the function. We must remember to take the
656 // receiver into account (+1).
657 JSFunction* function = JSFunction::cast(this->function());
658 arguments = function->shared()->formal_parameter_count() + 1;
659 }
660 const int offset = StandardFrameConstants::kCallerSPOffset;
661 return fp() + offset + (arguments * kPointerSize);
662}
663
664
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000665void JavaScriptFrame::GetFunctions(List<JSFunction*>* functions) {
666 ASSERT(functions->length() == 0);
667 functions->Add(JSFunction::cast(function()));
668}
669
670
671void JavaScriptFrame::Summarize(List<FrameSummary>* functions) {
672 ASSERT(functions->length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000673 Code* code_pointer = LookupCode(Isolate::Current());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000674 int offset = static_cast<int>(pc() - code_pointer->address());
675 FrameSummary summary(receiver(),
676 JSFunction::cast(function()),
677 code_pointer,
678 offset,
679 IsConstructor());
680 functions->Add(summary);
681}
682
683
684void FrameSummary::Print() {
685 PrintF("receiver: ");
686 receiver_->ShortPrint();
687 PrintF("\nfunction: ");
688 function_->shared()->DebugName()->ShortPrint();
689 PrintF("\ncode: ");
690 code_->ShortPrint();
691 if (code_->kind() == Code::FUNCTION) PrintF(" NON-OPT");
692 if (code_->kind() == Code::OPTIMIZED_FUNCTION) PrintF(" OPT");
693 PrintF("\npc: %d\n", offset_);
694}
695
696
697void OptimizedFrame::Summarize(List<FrameSummary>* frames) {
698 ASSERT(frames->length() == 0);
699 ASSERT(is_optimized());
700
ager@chromium.org378b34e2011-01-28 08:04:38 +0000701 int deopt_index = Safepoint::kNoDeoptimizationIndex;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000702 DeoptimizationInputData* data = GetDeoptimizationData(&deopt_index);
703
704 // BUG(3243555): Since we don't have a lazy-deopt registered at
705 // throw-statements, we can't use the translation at the call-site of
706 // throw. An entry with no deoptimization index indicates a call-site
707 // without a lazy-deopt. As a consequence we are not allowed to inline
708 // functions containing throw.
709 if (deopt_index == Safepoint::kNoDeoptimizationIndex) {
710 JavaScriptFrame::Summarize(frames);
711 return;
712 }
713
714 TranslationIterator it(data->TranslationByteArray(),
715 data->TranslationIndex(deopt_index)->value());
716 Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next());
717 ASSERT(opcode == Translation::BEGIN);
718 int frame_count = it.Next();
719
720 // We create the summary in reverse order because the frames
721 // in the deoptimization translation are ordered bottom-to-top.
722 int i = frame_count;
723 while (i > 0) {
724 opcode = static_cast<Translation::Opcode>(it.Next());
725 if (opcode == Translation::FRAME) {
726 // We don't inline constructor calls, so only the first, outermost
727 // frame can be a constructor frame in case of inlining.
728 bool is_constructor = (i == frame_count) && IsConstructor();
729
730 i--;
731 int ast_id = it.Next();
732 int function_id = it.Next();
733 it.Next(); // Skip height.
734 JSFunction* function =
735 JSFunction::cast(data->LiteralArray()->get(function_id));
736
737 // The translation commands are ordered and the receiver is always
738 // at the first position. Since we are always at a call when we need
739 // to construct a stack trace, the receiver is always in a stack slot.
740 opcode = static_cast<Translation::Opcode>(it.Next());
741 ASSERT(opcode == Translation::STACK_SLOT);
742 int input_slot_index = it.Next();
743
744 // Get the correct receiver in the optimized frame.
745 Object* receiver = NULL;
746 // Positive index means the value is spilled to the locals area. Negative
747 // means it is stored in the incoming parameter area.
748 if (input_slot_index >= 0) {
749 receiver = GetExpression(input_slot_index);
750 } else {
751 // Index -1 overlaps with last parameter, -n with the first parameter,
752 // (-n - 1) with the receiver with n being the number of parameters
753 // of the outermost, optimized frame.
754 int parameter_count = ComputeParametersCount();
755 int parameter_index = input_slot_index + parameter_count;
756 receiver = (parameter_index == -1)
757 ? this->receiver()
758 : this->GetParameter(parameter_index);
759 }
760
761 Code* code = function->shared()->code();
762 DeoptimizationOutputData* output_data =
763 DeoptimizationOutputData::cast(code->deoptimization_data());
764 unsigned entry = Deoptimizer::GetOutputInfo(output_data,
765 ast_id,
766 function->shared());
767 unsigned pc_offset =
768 FullCodeGenerator::PcField::decode(entry) + Code::kHeaderSize;
769 ASSERT(pc_offset > 0);
770
771 FrameSummary summary(receiver, function, code, pc_offset, is_constructor);
772 frames->Add(summary);
773 } else {
774 // Skip over operands to advance to the next opcode.
775 it.Skip(Translation::NumberOfOperandsFor(opcode));
776 }
777 }
778}
779
780
781DeoptimizationInputData* OptimizedFrame::GetDeoptimizationData(
782 int* deopt_index) {
783 ASSERT(is_optimized());
784
785 JSFunction* opt_function = JSFunction::cast(function());
786 Code* code = opt_function->code();
787
788 // The code object may have been replaced by lazy deoptimization. Fall
789 // back to a slow search in this case to find the original optimized
790 // code object.
791 if (!code->contains(pc())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000792 code = Isolate::Current()->pc_to_code_cache()->GcSafeFindCodeForPc(pc());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000793 }
794 ASSERT(code != NULL);
795 ASSERT(code->kind() == Code::OPTIMIZED_FUNCTION);
796
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000797 SafepointEntry safepoint_entry = code->GetSafepointEntry(pc());
798 *deopt_index = safepoint_entry.deoptimization_index();
ager@chromium.org378b34e2011-01-28 08:04:38 +0000799 ASSERT(*deopt_index != Safepoint::kNoDeoptimizationIndex);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000800
801 return DeoptimizationInputData::cast(code->deoptimization_data());
802}
803
804
805void OptimizedFrame::GetFunctions(List<JSFunction*>* functions) {
806 ASSERT(functions->length() == 0);
807 ASSERT(is_optimized());
808
ager@chromium.org378b34e2011-01-28 08:04:38 +0000809 int deopt_index = Safepoint::kNoDeoptimizationIndex;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000810 DeoptimizationInputData* data = GetDeoptimizationData(&deopt_index);
811
812 TranslationIterator it(data->TranslationByteArray(),
813 data->TranslationIndex(deopt_index)->value());
814 Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next());
815 ASSERT(opcode == Translation::BEGIN);
816 int frame_count = it.Next();
817
818 // We insert the frames in reverse order because the frames
819 // in the deoptimization translation are ordered bottom-to-top.
820 while (frame_count > 0) {
821 opcode = static_cast<Translation::Opcode>(it.Next());
822 if (opcode == Translation::FRAME) {
823 frame_count--;
824 it.Next(); // Skip ast id.
825 int function_id = it.Next();
826 it.Next(); // Skip height.
827 JSFunction* function =
828 JSFunction::cast(data->LiteralArray()->get(function_id));
829 functions->Add(function);
830 } else {
831 // Skip over operands to advance to the next opcode.
832 it.Skip(Translation::NumberOfOperandsFor(opcode));
833 }
834 }
835}
836
837
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000838Address ArgumentsAdaptorFrame::GetCallerStackPointer() const {
839 const int arguments = Smi::cast(GetExpression(0))->value();
840 const int offset = StandardFrameConstants::kCallerSPOffset;
841 return fp() + offset + (arguments + 1) * kPointerSize;
842}
843
844
845Address InternalFrame::GetCallerStackPointer() const {
846 // Internal frames have no arguments. The stack pointer of the
847 // caller is at a fixed offset from the frame pointer.
848 return fp() + StandardFrameConstants::kCallerSPOffset;
849}
850
851
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000852Code* ArgumentsAdaptorFrame::unchecked_code() const {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000853 return Isolate::Current()->builtins()->builtin(
854 Builtins::ArgumentsAdaptorTrampoline);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000855}
856
857
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000858Code* InternalFrame::unchecked_code() const {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000859 const int offset = InternalFrameConstants::kCodeOffset;
860 Object* code = Memory::Object_at(fp() + offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000861 ASSERT(code != NULL);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000862 return reinterpret_cast<Code*>(code);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000863}
864
865
866void StackFrame::PrintIndex(StringStream* accumulator,
867 PrintMode mode,
868 int index) {
869 accumulator->Add((mode == OVERVIEW) ? "%5d: " : "[%d]: ", index);
870}
871
872
873void JavaScriptFrame::Print(StringStream* accumulator,
874 PrintMode mode,
875 int index) const {
876 HandleScope scope;
877 Object* receiver = this->receiver();
878 Object* function = this->function();
879
880 accumulator->PrintSecurityTokenIfChanged(function);
881 PrintIndex(accumulator, mode, index);
882 Code* code = NULL;
883 if (IsConstructor()) accumulator->Add("new ");
884 accumulator->PrintFunction(function, receiver, &code);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000885
ager@chromium.orgb5737492010-07-15 09:29:43 +0000886 Handle<SerializedScopeInfo> scope_info(SerializedScopeInfo::Empty());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000887
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000888 if (function->IsJSFunction()) {
889 Handle<SharedFunctionInfo> shared(JSFunction::cast(function)->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +0000890 scope_info = Handle<SerializedScopeInfo>(shared->scope_info());
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000891 Object* script_obj = shared->script();
892 if (script_obj->IsScript()) {
893 Handle<Script> script(Script::cast(script_obj));
894 accumulator->Add(" [");
895 accumulator->PrintName(script->name());
896
897 Address pc = this->pc();
898 if (code != NULL && code->kind() == Code::FUNCTION &&
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000899 pc >= code->instruction_start() && pc < code->instruction_end()) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000900 int source_pos = code->SourcePosition(pc);
901 int line = GetScriptLineNumberSafe(script, source_pos) + 1;
902 accumulator->Add(":%d", line);
903 } else {
904 int function_start_pos = shared->start_position();
905 int line = GetScriptLineNumberSafe(script, function_start_pos) + 1;
906 accumulator->Add(":~%d", line);
907 }
908
909 accumulator->Add("] ");
910 }
911 }
912
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000913 accumulator->Add("(this=%o", receiver);
914
915 // Get scope information for nicer output, if possible. If code is
916 // NULL, or doesn't contain scope info, info will return 0 for the
917 // number of parameters, stack slots, or context slots.
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000918 ScopeInfo<PreallocatedStorage> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000919
920 // Print the parameters.
921 int parameters_count = ComputeParametersCount();
922 for (int i = 0; i < parameters_count; i++) {
923 accumulator->Add(",");
924 // If we have a name for the parameter we print it. Nameless
925 // parameters are either because we have more actual parameters
926 // than formal parameters or because we have no scope information.
927 if (i < info.number_of_parameters()) {
928 accumulator->PrintName(*info.parameter_name(i));
929 accumulator->Add("=");
930 }
931 accumulator->Add("%o", GetParameter(i));
932 }
933
934 accumulator->Add(")");
935 if (mode == OVERVIEW) {
936 accumulator->Add("\n");
937 return;
938 }
939 accumulator->Add(" {\n");
940
941 // Compute the number of locals and expression stack elements.
942 int stack_locals_count = info.number_of_stack_slots();
943 int heap_locals_count = info.number_of_context_slots();
944 int expressions_count = ComputeExpressionsCount();
945
946 // Print stack-allocated local variables.
947 if (stack_locals_count > 0) {
948 accumulator->Add(" // stack-allocated locals\n");
949 }
950 for (int i = 0; i < stack_locals_count; i++) {
951 accumulator->Add(" var ");
952 accumulator->PrintName(*info.stack_slot_name(i));
953 accumulator->Add(" = ");
954 if (i < expressions_count) {
955 accumulator->Add("%o", GetExpression(i));
956 } else {
957 accumulator->Add("// no expression found - inconsistent frame?");
958 }
959 accumulator->Add("\n");
960 }
961
962 // Try to get hold of the context of this frame.
963 Context* context = NULL;
964 if (this->context() != NULL && this->context()->IsContext()) {
965 context = Context::cast(this->context());
966 }
967
968 // Print heap-allocated local variables.
969 if (heap_locals_count > Context::MIN_CONTEXT_SLOTS) {
970 accumulator->Add(" // heap-allocated locals\n");
971 }
972 for (int i = Context::MIN_CONTEXT_SLOTS; i < heap_locals_count; i++) {
973 accumulator->Add(" var ");
974 accumulator->PrintName(*info.context_slot_name(i));
975 accumulator->Add(" = ");
976 if (context != NULL) {
977 if (i < context->length()) {
978 accumulator->Add("%o", context->get(i));
979 } else {
980 accumulator->Add(
981 "// warning: missing context slot - inconsistent frame?");
982 }
983 } else {
984 accumulator->Add("// warning: no context found - inconsistent frame?");
985 }
986 accumulator->Add("\n");
987 }
988
989 // Print the expression stack.
kasper.lund7276f142008-07-30 08:49:36 +0000990 int expressions_start = stack_locals_count;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000991 if (expressions_start < expressions_count) {
992 accumulator->Add(" // expression stack (top to bottom)\n");
993 }
994 for (int i = expressions_count - 1; i >= expressions_start; i--) {
995 if (IsExpressionInsideHandler(i)) continue;
996 accumulator->Add(" [%02d] : %o\n", i, GetExpression(i));
997 }
998
999 // Print details about the function.
1000 if (FLAG_max_stack_trace_source_length != 0 && code != NULL) {
1001 SharedFunctionInfo* shared = JSFunction::cast(function)->shared();
1002 accumulator->Add("--------- s o u r c e c o d e ---------\n");
1003 shared->SourceCodePrint(accumulator, FLAG_max_stack_trace_source_length);
1004 accumulator->Add("\n-----------------------------------------\n");
1005 }
1006
1007 accumulator->Add("}\n\n");
1008}
1009
1010
1011void ArgumentsAdaptorFrame::Print(StringStream* accumulator,
1012 PrintMode mode,
1013 int index) const {
1014 int actual = ComputeParametersCount();
1015 int expected = -1;
1016 Object* function = this->function();
1017 if (function->IsJSFunction()) {
1018 expected = JSFunction::cast(function)->shared()->formal_parameter_count();
1019 }
1020
1021 PrintIndex(accumulator, mode, index);
1022 accumulator->Add("arguments adaptor frame: %d->%d", actual, expected);
1023 if (mode == OVERVIEW) {
1024 accumulator->Add("\n");
1025 return;
1026 }
1027 accumulator->Add(" {\n");
1028
1029 // Print actual arguments.
1030 if (actual > 0) accumulator->Add(" // actual arguments\n");
1031 for (int i = 0; i < actual; i++) {
1032 accumulator->Add(" [%02d] : %o", i, GetParameter(i));
1033 if (expected != -1 && i >= expected) {
1034 accumulator->Add(" // not passed to callee");
1035 }
1036 accumulator->Add("\n");
1037 }
1038
1039 accumulator->Add("}\n\n");
1040}
1041
1042
1043void EntryFrame::Iterate(ObjectVisitor* v) const {
1044 StackHandlerIterator it(this, top_handler());
1045 ASSERT(!it.done());
1046 StackHandler* handler = it.handler();
1047 ASSERT(handler->is_entry());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001048 handler->Iterate(v, LookupCode(Isolate::Current()));
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001049#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001050 // Make sure that the entry frame does not contain more than one
1051 // stack handler.
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001052 it.Advance();
1053 ASSERT(it.done());
1054#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001055 IteratePc(v, pc_address(), LookupCode(Isolate::Current()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001056}
1057
1058
1059void StandardFrame::IterateExpressions(ObjectVisitor* v) const {
1060 const int offset = StandardFrameConstants::kContextOffset;
1061 Object** base = &Memory::Object_at(sp());
1062 Object** limit = &Memory::Object_at(fp() + offset) + 1;
1063 for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) {
1064 StackHandler* handler = it.handler();
1065 // Traverse pointers down to - but not including - the next
1066 // handler in the handler chain. Update the base to skip the
1067 // handler and allow the handler to traverse its own pointers.
1068 const Address address = handler->address();
1069 v->VisitPointers(base, reinterpret_cast<Object**>(address));
1070 base = reinterpret_cast<Object**>(address + StackHandlerConstants::kSize);
1071 // Traverse the pointers in the handler itself.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001072 handler->Iterate(v, LookupCode(Isolate::Current()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001073 }
1074 v->VisitPointers(base, limit);
1075}
1076
1077
1078void JavaScriptFrame::Iterate(ObjectVisitor* v) const {
1079 IterateExpressions(v);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001080 IteratePc(v, pc_address(), LookupCode(Isolate::Current()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001081 IterateArguments(v);
1082}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001083
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001084
1085void JavaScriptFrame::IterateArguments(ObjectVisitor* v) const {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001086 // Traverse callee-saved registers, receiver, and parameters.
1087 const int kBaseOffset = JavaScriptFrameConstants::kSavedRegistersOffset;
1088 const int kLimitOffset = JavaScriptFrameConstants::kReceiverOffset;
1089 Object** base = &Memory::Object_at(fp() + kBaseOffset);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001090 Object** limit = &Memory::Object_at(caller_sp() + kLimitOffset) + 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001091 v->VisitPointers(base, limit);
1092}
1093
1094
1095void InternalFrame::Iterate(ObjectVisitor* v) const {
1096 // Internal frames only have object pointers on the expression stack
1097 // as they never have any arguments.
1098 IterateExpressions(v);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001099 IteratePc(v, pc_address(), LookupCode(Isolate::Current()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001100}
1101
1102
1103// -------------------------------------------------------------------------
1104
1105
1106JavaScriptFrame* StackFrameLocator::FindJavaScriptFrame(int n) {
1107 ASSERT(n >= 0);
1108 for (int i = 0; i <= n; i++) {
1109 while (!iterator_.frame()->is_java_script()) iterator_.Advance();
1110 if (i == n) return JavaScriptFrame::cast(iterator_.frame());
1111 iterator_.Advance();
1112 }
1113 UNREACHABLE();
1114 return NULL;
1115}
1116
1117
1118// -------------------------------------------------------------------------
1119
1120
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001121Code* PcToCodeCache::GcSafeCastToCode(HeapObject* object, Address pc) {
1122 Code* code = reinterpret_cast<Code*>(object);
1123 ASSERT(code != NULL && code->contains(pc));
1124 return code;
1125}
1126
1127
1128Code* PcToCodeCache::GcSafeFindCodeForPc(Address pc) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001129 Heap* heap = isolate_->heap();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001130 // Check if the pc points into a large object chunk.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001131 LargeObjectChunk* chunk = heap->lo_space()->FindChunkContainingPc(pc);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001132 if (chunk != NULL) return GcSafeCastToCode(chunk->GetObject(), pc);
1133
1134 // Iterate through the 8K page until we reach the end or find an
1135 // object starting after the pc.
1136 Page* page = Page::FromAddress(pc);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001137 HeapObjectIterator iterator(page, heap->GcSafeSizeOfOldObjectFunction());
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001138 HeapObject* previous = NULL;
1139 while (true) {
1140 HeapObject* next = iterator.next();
1141 if (next == NULL || next->address() >= pc) {
1142 return GcSafeCastToCode(previous, pc);
1143 }
1144 previous = next;
1145 }
1146}
1147
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001148
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001149PcToCodeCache::PcToCodeCacheEntry* PcToCodeCache::GetCacheEntry(Address pc) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001150 COUNTERS->pc_to_code()->Increment();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001151 ASSERT(IsPowerOf2(kPcToCodeCacheSize));
1152 uint32_t hash = ComputeIntegerHash(
1153 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(pc)));
1154 uint32_t index = hash & (kPcToCodeCacheSize - 1);
1155 PcToCodeCacheEntry* entry = cache(index);
1156 if (entry->pc == pc) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001157 COUNTERS->pc_to_code_cached()->Increment();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001158 ASSERT(entry->code == GcSafeFindCodeForPc(pc));
1159 } else {
1160 // Because this code may be interrupted by a profiling signal that
1161 // also queries the cache, we cannot update pc before the code has
1162 // been set. Otherwise, we risk trying to use a cache entry before
1163 // the code has been computed.
1164 entry->code = GcSafeFindCodeForPc(pc);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001165 entry->safepoint_entry.Reset();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001166 entry->pc = pc;
1167 }
1168 return entry;
1169}
1170
1171
1172// -------------------------------------------------------------------------
1173
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001174int NumRegs(RegList reglist) {
1175 int n = 0;
1176 while (reglist != 0) {
1177 n++;
1178 reglist &= reglist - 1; // clear one bit
1179 }
1180 return n;
1181}
1182
1183
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001184struct JSCallerSavedCodeData {
1185 JSCallerSavedCodeData() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001186 int i = 0;
1187 for (int r = 0; r < kNumRegs; r++)
1188 if ((kJSCallerSaved & (1 << r)) != 0)
1189 reg_code[i++] = r;
1190
1191 ASSERT(i == kNumJSCallerSaved);
1192 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001193 int reg_code[kNumJSCallerSaved];
1194};
1195
1196
1197static const JSCallerSavedCodeData kCallerSavedCodeData;
1198
1199
1200int JSCallerSavedCode(int n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001201 ASSERT(0 <= n && n < kNumJSCallerSaved);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001202 return kCallerSavedCodeData.reg_code[n];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001203}
1204
1205
ager@chromium.org357bf652010-04-12 11:30:10 +00001206#define DEFINE_WRAPPER(type, field) \
1207class field##_Wrapper : public ZoneObject { \
1208 public: /* NOLINT */ \
1209 field##_Wrapper(const field& original) : frame_(original) { \
1210 } \
1211 field frame_; \
1212};
1213STACK_FRAME_TYPE_LIST(DEFINE_WRAPPER)
1214#undef DEFINE_WRAPPER
1215
1216static StackFrame* AllocateFrameCopy(StackFrame* frame) {
1217#define FRAME_TYPE_CASE(type, field) \
1218 case StackFrame::type: { \
1219 field##_Wrapper* wrapper = \
1220 new field##_Wrapper(*(reinterpret_cast<field*>(frame))); \
1221 return &wrapper->frame_; \
1222 }
1223
1224 switch (frame->type()) {
1225 STACK_FRAME_TYPE_LIST(FRAME_TYPE_CASE)
1226 default: UNREACHABLE();
1227 }
1228#undef FRAME_TYPE_CASE
1229 return NULL;
1230}
1231
1232Vector<StackFrame*> CreateStackMap() {
1233 ZoneList<StackFrame*> list(10);
1234 for (StackFrameIterator it; !it.done(); it.Advance()) {
1235 StackFrame* frame = AllocateFrameCopy(it.frame());
1236 list.Add(frame);
1237 }
1238 return list.ToVector();
1239}
1240
1241
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001242} } // namespace v8::internal