blob: 23bcedae1f9fc32d77c45fb15b46df30c7a2222c [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"
jkummerow@chromium.org1456e702012-03-30 08:38:13 +000034#include "lazy-instance.h"
kasperl@chromium.org061ef742009-02-27 12:16:20 +000035#include "mark-compact.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000036#include "safepoint-table.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000037#include "scopeinfo.h"
38#include "string-stream.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000039
whesse@chromium.org030d38e2011-07-13 13:23:34 +000040#include "allocation-inl.h"
41
kasperl@chromium.org71affb52009-05-26 05:44:31 +000042namespace v8 {
43namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000044
ulan@chromium.org967e2702012-02-28 09:49:15 +000045
46static ReturnAddressLocationResolver return_address_location_resolver = NULL;
47
48
49// Resolves pc_address through the resolution address function if one is set.
50static inline Address* ResolveReturnAddressLocation(Address* pc_address) {
51 if (return_address_location_resolver == NULL) {
52 return pc_address;
53 } else {
54 return reinterpret_cast<Address*>(
55 return_address_location_resolver(
56 reinterpret_cast<uintptr_t>(pc_address)));
57 }
58}
59
60
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000061// Iterator that supports traversing the stack handlers of a
62// particular frame. Needs to know the top of the handler chain.
63class StackHandlerIterator BASE_EMBEDDED {
64 public:
65 StackHandlerIterator(const StackFrame* frame, StackHandler* handler)
66 : limit_(frame->fp()), handler_(handler) {
67 // Make sure the handler has already been unwound to this frame.
68 ASSERT(frame->sp() <= handler->address());
69 }
70
71 StackHandler* handler() const { return handler_; }
72
ager@chromium.orgeadaf222009-06-16 09:43:10 +000073 bool done() {
74 return handler_ == NULL || handler_->address() > limit_;
75 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000076 void Advance() {
77 ASSERT(!done());
78 handler_ = handler_->next();
79 }
80
81 private:
82 const Address limit_;
83 StackHandler* handler_;
84};
85
86
87// -------------------------------------------------------------------------
88
89
90#define INITIALIZE_SINGLETON(type, field) field##_(this),
91StackFrameIterator::StackFrameIterator()
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000092 : isolate_(Isolate::Current()),
93 STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000094 frame_(NULL), handler_(NULL),
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000095 thread_(isolate_->thread_local_top()),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000096 fp_(NULL), sp_(NULL), advance_(&StackFrameIterator::AdvanceWithHandler) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000097 Reset();
98}
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000099StackFrameIterator::StackFrameIterator(Isolate* isolate)
100 : isolate_(isolate),
101 STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON)
102 frame_(NULL), handler_(NULL),
103 thread_(isolate_->thread_local_top()),
104 fp_(NULL), sp_(NULL), advance_(&StackFrameIterator::AdvanceWithHandler) {
105 Reset();
106}
107StackFrameIterator::StackFrameIterator(Isolate* isolate, ThreadLocalTop* t)
108 : isolate_(isolate),
109 STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON)
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000110 frame_(NULL), handler_(NULL), thread_(t),
111 fp_(NULL), sp_(NULL), advance_(&StackFrameIterator::AdvanceWithHandler) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000112 Reset();
113}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000114StackFrameIterator::StackFrameIterator(Isolate* isolate,
115 bool use_top, Address fp, Address sp)
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000116 : isolate_(isolate),
117 STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON)
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000118 frame_(NULL), handler_(NULL),
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000119 thread_(use_top ? isolate_->thread_local_top() : NULL),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000120 fp_(use_top ? NULL : fp), sp_(sp),
121 advance_(use_top ? &StackFrameIterator::AdvanceWithHandler :
122 &StackFrameIterator::AdvanceWithoutHandler) {
123 if (use_top || fp != NULL) {
124 Reset();
125 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000126}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000127
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000128#undef INITIALIZE_SINGLETON
129
130
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000131void StackFrameIterator::AdvanceWithHandler() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000132 ASSERT(!done());
133 // Compute the state of the calling frame before restoring
134 // callee-saved registers and unwinding handlers. This allows the
135 // frame code that computes the caller state to access the top
136 // handler and the value of any callee-saved register if needed.
137 StackFrame::State state;
138 StackFrame::Type type = frame_->GetCallerState(&state);
139
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000140 // Unwind handlers corresponding to the current frame.
141 StackHandlerIterator it(frame_, handler_);
142 while (!it.done()) it.Advance();
143 handler_ = it.handler();
144
145 // Advance to the calling frame.
146 frame_ = SingletonFor(type, &state);
147
148 // When we're done iterating over the stack frames, the handler
149 // chain must have been completely unwound.
150 ASSERT(!done() || handler_ == NULL);
151}
152
153
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000154void StackFrameIterator::AdvanceWithoutHandler() {
155 // A simpler version of Advance which doesn't care about handler.
156 ASSERT(!done());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000157 StackFrame::State state;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000158 StackFrame::Type type = frame_->GetCallerState(&state);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000159 frame_ = SingletonFor(type, &state);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000160}
161
162
163void StackFrameIterator::Reset() {
164 StackFrame::State state;
165 StackFrame::Type type;
166 if (thread_ != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000167 type = ExitFrame::GetStateForFramePointer(
168 Isolate::c_entry_fp(thread_), &state);
169 handler_ = StackHandler::FromAddress(
170 Isolate::handler(thread_));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000171 } else {
172 ASSERT(fp_ != NULL);
173 state.fp = fp_;
174 state.sp = sp_;
ulan@chromium.org967e2702012-02-28 09:49:15 +0000175 state.pc_address = ResolveReturnAddressLocation(
176 reinterpret_cast<Address*>(StandardFrame::ComputePCAddress(fp_)));
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000177 type = StackFrame::ComputeType(isolate(), &state);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000178 }
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000179 if (SingletonFor(type) == NULL) return;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000180 frame_ = SingletonFor(type, &state);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000181}
182
183
184StackFrame* StackFrameIterator::SingletonFor(StackFrame::Type type,
185 StackFrame::State* state) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000186 if (type == StackFrame::NONE) return NULL;
187 StackFrame* result = SingletonFor(type);
188 ASSERT(result != NULL);
189 result->state_ = *state;
190 return result;
191}
192
193
194StackFrame* StackFrameIterator::SingletonFor(StackFrame::Type type) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000195#define FRAME_TYPE_CASE(type, field) \
196 case StackFrame::type: result = &field##_; break;
197
198 StackFrame* result = NULL;
199 switch (type) {
200 case StackFrame::NONE: return NULL;
201 STACK_FRAME_TYPE_LIST(FRAME_TYPE_CASE)
202 default: break;
203 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000204 return result;
205
206#undef FRAME_TYPE_CASE
207}
208
209
210// -------------------------------------------------------------------------
211
212
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000213StackTraceFrameIterator::StackTraceFrameIterator() {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000214 if (!done() && !IsValidFrame()) Advance();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000215}
216
217
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000218StackTraceFrameIterator::StackTraceFrameIterator(Isolate* isolate)
219 : JavaScriptFrameIterator(isolate) {
220 if (!done() && !IsValidFrame()) Advance();
221}
222
223
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000224void StackTraceFrameIterator::Advance() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000225 while (true) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000226 JavaScriptFrameIterator::Advance();
227 if (done()) return;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000228 if (IsValidFrame()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000229 }
230}
231
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000232bool StackTraceFrameIterator::IsValidFrame() {
233 if (!frame()->function()->IsJSFunction()) return false;
234 Object* script = JSFunction::cast(frame()->function())->shared()->script();
235 // Don't show functions from native scripts to user.
236 return (script->IsScript() &&
237 Script::TYPE_NATIVE != Script::cast(script)->type()->value());
238}
239
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000240
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000241// -------------------------------------------------------------------------
242
243
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000244bool SafeStackFrameIterator::ExitFrameValidator::IsValidFP(Address fp) {
245 if (!validator_.IsValid(fp)) return false;
246 Address sp = ExitFrame::ComputeStackPointer(fp);
247 if (!validator_.IsValid(sp)) return false;
248 StackFrame::State state;
249 ExitFrame::FillState(fp, sp, &state);
250 if (!validator_.IsValid(reinterpret_cast<Address>(state.pc_address))) {
251 return false;
252 }
253 return *state.pc_address != NULL;
254}
255
256
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000257SafeStackFrameIterator::ActiveCountMaintainer::ActiveCountMaintainer(
258 Isolate* isolate)
259 : isolate_(isolate) {
260 isolate_->set_safe_stack_iterator_counter(
261 isolate_->safe_stack_iterator_counter() + 1);
262}
263
264
265SafeStackFrameIterator::ActiveCountMaintainer::~ActiveCountMaintainer() {
266 isolate_->set_safe_stack_iterator_counter(
267 isolate_->safe_stack_iterator_counter() - 1);
268}
269
270
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000271SafeStackFrameIterator::SafeStackFrameIterator(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000272 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000273 Address fp, Address sp, Address low_bound, Address high_bound) :
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000274 maintainer_(isolate),
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000275 stack_validator_(low_bound, high_bound),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000276 is_valid_top_(IsValidTop(isolate, low_bound, high_bound)),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000277 is_valid_fp_(IsWithinBounds(low_bound, high_bound, fp)),
278 is_working_iterator_(is_valid_top_ || is_valid_fp_),
279 iteration_done_(!is_working_iterator_),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000280 iterator_(isolate, is_valid_top_, is_valid_fp_ ? fp : NULL, sp) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000281}
282
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000283bool SafeStackFrameIterator::is_active(Isolate* isolate) {
284 return isolate->safe_stack_iterator_counter() > 0;
285}
286
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000287
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000288bool SafeStackFrameIterator::IsValidTop(Isolate* isolate,
289 Address low_bound, Address high_bound) {
290 ThreadLocalTop* top = isolate->thread_local_top();
291 Address fp = Isolate::c_entry_fp(top);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000292 ExitFrameValidator validator(low_bound, high_bound);
293 if (!validator.IsValidFP(fp)) return false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000294 return Isolate::handler(top) != NULL;
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000295}
296
297
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000298void SafeStackFrameIterator::Advance() {
299 ASSERT(is_working_iterator_);
300 ASSERT(!done());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000301 StackFrame* last_frame = iterator_.frame();
302 Address last_sp = last_frame->sp(), last_fp = last_frame->fp();
303 // Before advancing to the next stack frame, perform pointer validity tests
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000304 iteration_done_ = !IsValidFrame(last_frame) ||
305 !CanIterateHandles(last_frame, iterator_.handler()) ||
306 !IsValidCaller(last_frame);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000307 if (iteration_done_) return;
308
309 iterator_.Advance();
310 if (iterator_.done()) return;
311 // Check that we have actually moved to the previous frame in the stack
312 StackFrame* prev_frame = iterator_.frame();
313 iteration_done_ = prev_frame->sp() < last_sp || prev_frame->fp() < last_fp;
314}
315
316
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000317bool SafeStackFrameIterator::CanIterateHandles(StackFrame* frame,
318 StackHandler* handler) {
319 // If StackIterator iterates over StackHandles, verify that
320 // StackHandlerIterator can be instantiated (see StackHandlerIterator
321 // constructor.)
322 return !is_valid_top_ || (frame->sp() <= handler->address());
323}
324
325
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000326bool SafeStackFrameIterator::IsValidFrame(StackFrame* frame) const {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000327 return IsValidStackAddress(frame->sp()) && IsValidStackAddress(frame->fp());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000328}
329
330
331bool SafeStackFrameIterator::IsValidCaller(StackFrame* frame) {
332 StackFrame::State state;
ager@chromium.org41826e72009-03-30 13:30:57 +0000333 if (frame->is_entry() || frame->is_entry_construct()) {
334 // See EntryFrame::GetCallerState. It computes the caller FP address
335 // and calls ExitFrame::GetStateForFramePointer on it. We need to be
336 // sure that caller FP address is valid.
337 Address caller_fp = Memory::Address_at(
338 frame->fp() + EntryFrameConstants::kCallerFPOffset);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000339 ExitFrameValidator validator(stack_validator_);
340 if (!validator.IsValidFP(caller_fp)) return false;
ager@chromium.org41826e72009-03-30 13:30:57 +0000341 } else if (frame->is_arguments_adaptor()) {
342 // See ArgumentsAdaptorFrame::GetCallerStackPointer. It assumes that
343 // the number of arguments is stored on stack as Smi. We need to check
344 // that it really an Smi.
345 Object* number_of_args = reinterpret_cast<ArgumentsAdaptorFrame*>(frame)->
346 GetExpression(0);
347 if (!number_of_args->IsSmi()) {
348 return false;
349 }
350 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000351 frame->ComputeCallerState(&state);
352 return IsValidStackAddress(state.sp) && IsValidStackAddress(state.fp) &&
353 iterator_.SingletonFor(frame->GetCallerState(&state)) != NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000354}
355
356
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000357void SafeStackFrameIterator::Reset() {
358 if (is_working_iterator_) {
359 iterator_.Reset();
360 iteration_done_ = false;
361 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000362}
363
364
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000365// -------------------------------------------------------------------------
366
367
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000368SafeStackTraceFrameIterator::SafeStackTraceFrameIterator(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000369 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000370 Address fp, Address sp, Address low_bound, Address high_bound) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000371 SafeJavaScriptFrameIterator(isolate, fp, sp, low_bound, high_bound) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000372 if (!done() && !frame()->is_java_script()) Advance();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000373}
374
375
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000376void SafeStackTraceFrameIterator::Advance() {
377 while (true) {
378 SafeJavaScriptFrameIterator::Advance();
379 if (done()) return;
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000380 if (frame()->is_java_script()) return;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000381 }
382}
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000383
384
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000385Code* StackFrame::GetSafepointData(Isolate* isolate,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000386 Address inner_pointer,
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000387 SafepointEntry* safepoint_entry,
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000388 unsigned* stack_slots) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000389 InnerPointerToCodeCache::InnerPointerToCodeCacheEntry* entry =
390 isolate->inner_pointer_to_code_cache()->GetCacheEntry(inner_pointer);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000391 if (!entry->safepoint_entry.is_valid()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000392 entry->safepoint_entry = entry->code->GetSafepointEntry(inner_pointer);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000393 ASSERT(entry->safepoint_entry.is_valid());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000394 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000395 ASSERT(entry->safepoint_entry.Equals(
396 entry->code->GetSafepointEntry(inner_pointer)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000397 }
398
399 // Fill in the results and return the code.
400 Code* code = entry->code;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000401 *safepoint_entry = entry->safepoint_entry;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000402 *stack_slots = code->stack_slots();
403 return code;
404}
405
406
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000407bool StackFrame::HasHandler() const {
408 StackHandlerIterator it(this, top_handler());
409 return !it.done();
410}
411
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000412
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000413#ifdef DEBUG
414static bool GcSafeCodeContains(HeapObject* object, Address addr);
415#endif
416
417
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000418void StackFrame::IteratePc(ObjectVisitor* v,
419 Address* pc_address,
420 Code* holder) {
421 Address pc = *pc_address;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000422 ASSERT(GcSafeCodeContains(holder, pc));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000423 unsigned pc_offset = static_cast<unsigned>(pc - holder->instruction_start());
424 Object* code = holder;
425 v->VisitPointer(&code);
426 if (code != holder) {
427 holder = reinterpret_cast<Code*>(code);
428 pc = holder->instruction_start() + pc_offset;
429 *pc_address = pc;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000430 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000431}
432
433
ulan@chromium.org967e2702012-02-28 09:49:15 +0000434void StackFrame::SetReturnAddressLocationResolver(
435 ReturnAddressLocationResolver resolver) {
436 ASSERT(return_address_location_resolver == NULL);
437 return_address_location_resolver = resolver;
438}
439
440
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000441StackFrame::Type StackFrame::ComputeType(Isolate* isolate, State* state) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000442 ASSERT(state->fp != NULL);
443 if (StandardFrame::IsArgumentsAdaptorFrame(state->fp)) {
444 return ARGUMENTS_ADAPTOR;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000445 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000446 // The marker and function offsets overlap. If the marker isn't a
447 // smi then the frame is a JavaScript frame -- and the marker is
448 // really the function.
449 const int offset = StandardFrameConstants::kMarkerOffset;
450 Object* marker = Memory::Object_at(state->fp + offset);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000451 if (!marker->IsSmi()) {
452 // If we're using a "safe" stack iterator, we treat optimized
453 // frames as normal JavaScript frames to avoid having to look
454 // into the heap to determine the state. This is safe as long
455 // as nobody tries to GC...
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000456 if (SafeStackFrameIterator::is_active(isolate)) return JAVA_SCRIPT;
457 Code::Kind kind = GetContainingCode(isolate, *(state->pc_address))->kind();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000458 ASSERT(kind == Code::FUNCTION || kind == Code::OPTIMIZED_FUNCTION);
459 return (kind == Code::OPTIMIZED_FUNCTION) ? OPTIMIZED : JAVA_SCRIPT;
460 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000461 return static_cast<StackFrame::Type>(Smi::cast(marker)->value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000462}
463
464
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000465
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000466StackFrame::Type StackFrame::GetCallerState(State* state) const {
467 ComputeCallerState(state);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000468 return ComputeType(isolate(), state);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000469}
470
471
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000472Address StackFrame::UnpaddedFP() const {
473#if defined(V8_TARGET_ARCH_IA32)
474 if (!is_optimized()) return fp();
475 int32_t alignment_state = Memory::int32_at(
476 fp() + JavaScriptFrameConstants::kDynamicAlignmentStateOffset);
477
478 return (alignment_state == kAlignmentPaddingPushed) ?
479 (fp() + kPointerSize) : fp();
480#else
481 return fp();
482#endif
483}
484
485
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000486Code* EntryFrame::unchecked_code() const {
danno@chromium.org72204d52012-10-31 10:02:10 +0000487 return HEAP->js_entry_code();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000488}
489
490
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000491void EntryFrame::ComputeCallerState(State* state) const {
492 GetCallerState(state);
493}
494
495
ager@chromium.org357bf652010-04-12 11:30:10 +0000496void EntryFrame::SetCallerFp(Address caller_fp) {
497 const int offset = EntryFrameConstants::kCallerFPOffset;
498 Memory::Address_at(this->fp() + offset) = caller_fp;
499}
500
501
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000502StackFrame::Type EntryFrame::GetCallerState(State* state) const {
503 const int offset = EntryFrameConstants::kCallerFPOffset;
504 Address fp = Memory::Address_at(this->fp() + offset);
505 return ExitFrame::GetStateForFramePointer(fp, state);
506}
507
508
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000509Code* EntryConstructFrame::unchecked_code() const {
danno@chromium.org72204d52012-10-31 10:02:10 +0000510 return HEAP->js_construct_entry_code();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000511}
512
513
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000514Object*& ExitFrame::code_slot() const {
515 const int offset = ExitFrameConstants::kCodeOffset;
516 return Memory::Object_at(fp() + offset);
517}
518
519
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000520Code* ExitFrame::unchecked_code() const {
521 return reinterpret_cast<Code*>(code_slot());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000522}
523
524
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000525void ExitFrame::ComputeCallerState(State* state) const {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000526 // Set up the caller state.
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000527 state->sp = caller_sp();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000528 state->fp = Memory::Address_at(fp() + ExitFrameConstants::kCallerFPOffset);
ulan@chromium.org967e2702012-02-28 09:49:15 +0000529 state->pc_address = ResolveReturnAddressLocation(
530 reinterpret_cast<Address*>(fp() + ExitFrameConstants::kCallerPCOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000531}
532
533
ager@chromium.org357bf652010-04-12 11:30:10 +0000534void ExitFrame::SetCallerFp(Address caller_fp) {
535 Memory::Address_at(fp() + ExitFrameConstants::kCallerFPOffset) = caller_fp;
536}
537
538
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000539void ExitFrame::Iterate(ObjectVisitor* v) const {
540 // The arguments are traversed as part of the expression stack of
541 // the calling frame.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000542 IteratePc(v, pc_address(), LookupCode());
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000543 v->VisitPointer(&code_slot());
544}
545
546
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000547Address ExitFrame::GetCallerStackPointer() const {
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000548 return fp() + ExitFrameConstants::kCallerSPDisplacement;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000549}
550
551
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000552StackFrame::Type ExitFrame::GetStateForFramePointer(Address fp, State* state) {
553 if (fp == 0) return NONE;
554 Address sp = ComputeStackPointer(fp);
555 FillState(fp, sp, state);
556 ASSERT(*state->pc_address != NULL);
557 return EXIT;
558}
559
560
561void ExitFrame::FillState(Address fp, Address sp, State* state) {
562 state->sp = sp;
563 state->fp = fp;
ulan@chromium.org967e2702012-02-28 09:49:15 +0000564 state->pc_address = ResolveReturnAddressLocation(
565 reinterpret_cast<Address*>(sp - 1 * kPointerSize));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000566}
567
568
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000569Address StandardFrame::GetExpressionAddress(int n) const {
kasper.lund7276f142008-07-30 08:49:36 +0000570 const int offset = StandardFrameConstants::kExpressionsOffset;
571 return fp() + offset - n * kPointerSize;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000572}
573
574
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000575Object* StandardFrame::GetExpression(Address fp, int index) {
576 return Memory::Object_at(GetExpressionAddress(fp, index));
577}
578
579
580Address StandardFrame::GetExpressionAddress(Address fp, int n) {
581 const int offset = StandardFrameConstants::kExpressionsOffset;
582 return fp + offset - n * kPointerSize;
583}
584
585
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000586int StandardFrame::ComputeExpressionsCount() const {
587 const int offset =
588 StandardFrameConstants::kExpressionsOffset + kPointerSize;
589 Address base = fp() + offset;
590 Address limit = sp();
591 ASSERT(base >= limit); // stack grows downwards
592 // Include register-allocated locals in number of expressions.
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000593 return static_cast<int>((base - limit) / kPointerSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000594}
595
596
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000597void StandardFrame::ComputeCallerState(State* state) const {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000598 state->sp = caller_sp();
599 state->fp = caller_fp();
ulan@chromium.org967e2702012-02-28 09:49:15 +0000600 state->pc_address = ResolveReturnAddressLocation(
601 reinterpret_cast<Address*>(ComputePCAddress(fp())));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000602}
603
604
ager@chromium.org357bf652010-04-12 11:30:10 +0000605void StandardFrame::SetCallerFp(Address caller_fp) {
606 Memory::Address_at(fp() + StandardFrameConstants::kCallerFPOffset) =
607 caller_fp;
608}
609
610
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000611bool StandardFrame::IsExpressionInsideHandler(int n) const {
612 Address address = GetExpressionAddress(n);
613 for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) {
614 if (it.handler()->includes(address)) return true;
615 }
616 return false;
617}
618
619
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000620void StandardFrame::IterateCompiledFrame(ObjectVisitor* v) const {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000621 // Make sure that we're not doing "safe" stack frame iteration. We cannot
622 // possibly find pointers in optimized frames in that state.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000623 ASSERT(!SafeStackFrameIterator::is_active(isolate()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000624
625 // Compute the safepoint information.
626 unsigned stack_slots = 0;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000627 SafepointEntry safepoint_entry;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000628 Code* code = StackFrame::GetSafepointData(
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000629 isolate(), pc(), &safepoint_entry, &stack_slots);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000630 unsigned slot_space = stack_slots * kPointerSize;
631
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000632 // Visit the outgoing parameters.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000633 Object** parameters_base = &Memory::Object_at(sp());
634 Object** parameters_limit = &Memory::Object_at(
635 fp() + JavaScriptFrameConstants::kFunctionOffset - slot_space);
636
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000637 // Visit the parameters that may be on top of the saved registers.
638 if (safepoint_entry.argument_count() > 0) {
639 v->VisitPointers(parameters_base,
640 parameters_base + safepoint_entry.argument_count());
641 parameters_base += safepoint_entry.argument_count();
642 }
643
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000644 // Skip saved double registers.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000645 if (safepoint_entry.has_doubles()) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000646 parameters_base += DoubleRegister::NumAllocatableRegisters() *
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000647 kDoubleSize / kPointerSize;
648 }
649
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000650 // Visit the registers that contain pointers if any.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000651 if (safepoint_entry.HasRegisters()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000652 for (int i = kNumSafepointRegisters - 1; i >=0; i--) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000653 if (safepoint_entry.HasRegisterAt(i)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000654 int reg_stack_index = MacroAssembler::SafepointRegisterStackIndex(i);
655 v->VisitPointer(parameters_base + reg_stack_index);
656 }
657 }
658 // Skip the words containing the register values.
659 parameters_base += kNumSafepointRegisters;
660 }
661
662 // We're done dealing with the register bits.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000663 uint8_t* safepoint_bits = safepoint_entry.bits();
664 safepoint_bits += kNumSafepointRegisters >> kBitsPerByteLog2;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000665
666 // Visit the rest of the parameters.
667 v->VisitPointers(parameters_base, parameters_limit);
668
669 // Visit pointer spill slots and locals.
670 for (unsigned index = 0; index < stack_slots; index++) {
671 int byte_index = index >> kBitsPerByteLog2;
672 int bit_index = index & (kBitsPerByte - 1);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000673 if ((safepoint_bits[byte_index] & (1U << bit_index)) != 0) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000674 v->VisitPointer(parameters_limit + index);
675 }
676 }
677
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000678 // Visit the return address in the callee and incoming arguments.
679 IteratePc(v, pc_address(), code);
680}
681
682
683void StubFrame::Iterate(ObjectVisitor* v) const {
684 IterateCompiledFrame(v);
685}
686
687
688Code* StubFrame::unchecked_code() const {
689 return static_cast<Code*>(isolate()->heap()->FindCodeObject(pc()));
690}
691
692
693Address StubFrame::GetCallerStackPointer() const {
694 return fp() + ExitFrameConstants::kCallerSPDisplacement;
695}
696
697
698int StubFrame::GetNumberOfIncomingArguments() const {
699 return 0;
700}
701
702
703void OptimizedFrame::Iterate(ObjectVisitor* v) const {
704#ifdef DEBUG
705 // Make sure that optimized frames do not contain any stack handlers.
706 StackHandlerIterator it(this, top_handler());
707 ASSERT(it.done());
708#endif
709
710 IterateCompiledFrame(v);
711
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000712 // Visit the context and the function.
713 Object** fixed_base = &Memory::Object_at(
714 fp() + JavaScriptFrameConstants::kFunctionOffset);
715 Object** fixed_limit = &Memory::Object_at(fp());
716 v->VisitPointers(fixed_base, fixed_limit);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000717}
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +0000718
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000719
720void JavaScriptFrame::SetParameterValue(int index, Object* value) const {
721 Memory::Object_at(GetParameterSlot(index)) = value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000722}
723
724
725bool JavaScriptFrame::IsConstructor() const {
ager@chromium.org7c537e22008-10-16 08:43:32 +0000726 Address fp = caller_fp();
727 if (has_adapted_arguments()) {
728 // Skip the arguments adaptor frame and look at the real caller.
729 fp = Memory::Address_at(fp + StandardFrameConstants::kCallerFPOffset);
730 }
731 return IsConstructFrame(fp);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000732}
733
734
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000735int JavaScriptFrame::GetArgumentsLength() const {
736 // If there is an arguments adaptor frame get the arguments length from it.
737 if (has_adapted_arguments()) {
738 return Smi::cast(GetExpression(caller_fp(), 0))->value();
739 } else {
740 return GetNumberOfIncomingArguments();
741 }
742}
743
744
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000745Code* JavaScriptFrame::unchecked_code() const {
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000746 JSFunction* function = JSFunction::cast(this->function());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000747 return function->unchecked_code();
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000748}
749
750
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000751int JavaScriptFrame::GetNumberOfIncomingArguments() const {
752 ASSERT(!SafeStackFrameIterator::is_active(isolate()) &&
753 isolate()->heap()->gc_state() == Heap::NOT_IN_GC);
754
755 JSFunction* function = JSFunction::cast(this->function());
756 return function->shared()->formal_parameter_count();
757}
758
759
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000760Address JavaScriptFrame::GetCallerStackPointer() const {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000761 return fp() + StandardFrameConstants::kCallerSPOffset;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000762}
763
764
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000765void JavaScriptFrame::GetFunctions(List<JSFunction*>* functions) {
766 ASSERT(functions->length() == 0);
767 functions->Add(JSFunction::cast(function()));
768}
769
770
771void JavaScriptFrame::Summarize(List<FrameSummary>* functions) {
772 ASSERT(functions->length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000773 Code* code_pointer = LookupCode();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000774 int offset = static_cast<int>(pc() - code_pointer->address());
775 FrameSummary summary(receiver(),
776 JSFunction::cast(function()),
777 code_pointer,
778 offset,
779 IsConstructor());
780 functions->Add(summary);
781}
782
783
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000784void JavaScriptFrame::PrintTop(FILE* file,
785 bool print_args,
786 bool print_line_number) {
787 // constructor calls
788 HandleScope scope;
789 AssertNoAllocation no_allocation;
790 JavaScriptFrameIterator it;
791 while (!it.done()) {
792 if (it.frame()->is_java_script()) {
793 JavaScriptFrame* frame = it.frame();
794 if (frame->IsConstructor()) PrintF(file, "new ");
795 // function name
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000796 Object* maybe_fun = frame->function();
797 if (maybe_fun->IsJSFunction()) {
798 JSFunction* fun = JSFunction::cast(maybe_fun);
799 fun->PrintName();
800 Code* js_code = frame->unchecked_code();
801 Address pc = frame->pc();
802 int code_offset =
803 static_cast<int>(pc - js_code->instruction_start());
804 PrintF("+%d", code_offset);
805 SharedFunctionInfo* shared = fun->shared();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000806 if (print_line_number) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000807 Code* code = Code::cast(
808 v8::internal::Isolate::Current()->heap()->FindCodeObject(pc));
809 int source_pos = code->SourcePosition(pc);
810 Object* maybe_script = shared->script();
811 if (maybe_script->IsScript()) {
812 Handle<Script> script(Script::cast(maybe_script));
813 int line = GetScriptLineNumberSafe(script, source_pos) + 1;
814 Object* script_name_raw = script->name();
815 if (script_name_raw->IsString()) {
816 String* script_name = String::cast(script->name());
817 SmartArrayPointer<char> c_script_name =
818 script_name->ToCString(DISALLOW_NULLS,
819 ROBUST_STRING_TRAVERSAL);
820 PrintF(file, " at %s:%d", *c_script_name, line);
821 } else {
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000822 PrintF(file, " at <unknown>:%d", line);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000823 }
824 } else {
825 PrintF(file, " at <unknown>:<unknown>");
826 }
827 }
828 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000829 PrintF("<unknown>");
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000830 }
831
832 if (print_args) {
833 // function arguments
834 // (we are intentionally only printing the actually
835 // supplied parameters, not all parameters required)
836 PrintF(file, "(this=");
837 frame->receiver()->ShortPrint(file);
838 const int length = frame->ComputeParametersCount();
839 for (int i = 0; i < length; i++) {
840 PrintF(file, ", ");
841 frame->GetParameter(i)->ShortPrint(file);
842 }
843 PrintF(file, ")");
844 }
845 break;
846 }
847 it.Advance();
848 }
849}
850
851
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000852void FrameSummary::Print() {
853 PrintF("receiver: ");
854 receiver_->ShortPrint();
855 PrintF("\nfunction: ");
856 function_->shared()->DebugName()->ShortPrint();
857 PrintF("\ncode: ");
858 code_->ShortPrint();
859 if (code_->kind() == Code::FUNCTION) PrintF(" NON-OPT");
860 if (code_->kind() == Code::OPTIMIZED_FUNCTION) PrintF(" OPT");
861 PrintF("\npc: %d\n", offset_);
862}
863
864
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000865JSFunction* OptimizedFrame::LiteralAt(FixedArray* literal_array,
866 int literal_id) {
867 if (literal_id == Translation::kSelfLiteralId) {
868 return JSFunction::cast(function());
869 }
870
871 return JSFunction::cast(literal_array->get(literal_id));
872}
873
874
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000875void OptimizedFrame::Summarize(List<FrameSummary>* frames) {
876 ASSERT(frames->length() == 0);
877 ASSERT(is_optimized());
878
ager@chromium.org378b34e2011-01-28 08:04:38 +0000879 int deopt_index = Safepoint::kNoDeoptimizationIndex;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000880 DeoptimizationInputData* data = GetDeoptimizationData(&deopt_index);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000881 FixedArray* literal_array = data->LiteralArray();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000882
883 // BUG(3243555): Since we don't have a lazy-deopt registered at
884 // throw-statements, we can't use the translation at the call-site of
885 // throw. An entry with no deoptimization index indicates a call-site
886 // without a lazy-deopt. As a consequence we are not allowed to inline
887 // functions containing throw.
888 if (deopt_index == Safepoint::kNoDeoptimizationIndex) {
889 JavaScriptFrame::Summarize(frames);
890 return;
891 }
892
893 TranslationIterator it(data->TranslationByteArray(),
894 data->TranslationIndex(deopt_index)->value());
895 Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next());
896 ASSERT(opcode == Translation::BEGIN);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000897 it.Next(); // Drop frame count.
898 int jsframe_count = it.Next();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000899
900 // We create the summary in reverse order because the frames
901 // in the deoptimization translation are ordered bottom-to-top.
ulan@chromium.org967e2702012-02-28 09:49:15 +0000902 bool is_constructor = IsConstructor();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000903 int i = jsframe_count;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000904 while (i > 0) {
905 opcode = static_cast<Translation::Opcode>(it.Next());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000906 if (opcode == Translation::JS_FRAME) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000907 i--;
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000908 BailoutId ast_id = BailoutId(it.Next());
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000909 JSFunction* function = LiteralAt(literal_array, it.Next());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000910 it.Next(); // Skip height.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000911
912 // The translation commands are ordered and the receiver is always
913 // at the first position. Since we are always at a call when we need
914 // to construct a stack trace, the receiver is always in a stack slot.
915 opcode = static_cast<Translation::Opcode>(it.Next());
danno@chromium.org40cb8782011-05-25 07:58:50 +0000916 ASSERT(opcode == Translation::STACK_SLOT ||
917 opcode == Translation::LITERAL);
918 int index = it.Next();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000919
920 // Get the correct receiver in the optimized frame.
921 Object* receiver = NULL;
danno@chromium.org40cb8782011-05-25 07:58:50 +0000922 if (opcode == Translation::LITERAL) {
923 receiver = data->LiteralArray()->get(index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000924 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000925 // Positive index means the value is spilled to the locals
926 // area. Negative means it is stored in the incoming parameter
927 // area.
928 if (index >= 0) {
929 receiver = GetExpression(index);
930 } else {
931 // Index -1 overlaps with last parameter, -n with the first parameter,
932 // (-n - 1) with the receiver with n being the number of parameters
933 // of the outermost, optimized frame.
934 int parameter_count = ComputeParametersCount();
935 int parameter_index = index + parameter_count;
936 receiver = (parameter_index == -1)
937 ? this->receiver()
938 : this->GetParameter(parameter_index);
939 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000940 }
941
942 Code* code = function->shared()->code();
943 DeoptimizationOutputData* output_data =
944 DeoptimizationOutputData::cast(code->deoptimization_data());
945 unsigned entry = Deoptimizer::GetOutputInfo(output_data,
946 ast_id,
947 function->shared());
948 unsigned pc_offset =
949 FullCodeGenerator::PcField::decode(entry) + Code::kHeaderSize;
950 ASSERT(pc_offset > 0);
951
952 FrameSummary summary(receiver, function, code, pc_offset, is_constructor);
953 frames->Add(summary);
ulan@chromium.org967e2702012-02-28 09:49:15 +0000954 is_constructor = false;
955 } else if (opcode == Translation::CONSTRUCT_STUB_FRAME) {
956 // The next encountered JS_FRAME will be marked as a constructor call.
957 it.Skip(Translation::NumberOfOperandsFor(opcode));
958 ASSERT(!is_constructor);
959 is_constructor = true;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000960 } else {
961 // Skip over operands to advance to the next opcode.
962 it.Skip(Translation::NumberOfOperandsFor(opcode));
963 }
964 }
ulan@chromium.org967e2702012-02-28 09:49:15 +0000965 ASSERT(!is_constructor);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000966}
967
968
969DeoptimizationInputData* OptimizedFrame::GetDeoptimizationData(
970 int* deopt_index) {
971 ASSERT(is_optimized());
972
973 JSFunction* opt_function = JSFunction::cast(function());
974 Code* code = opt_function->code();
975
976 // The code object may have been replaced by lazy deoptimization. Fall
977 // back to a slow search in this case to find the original optimized
978 // code object.
979 if (!code->contains(pc())) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000980 code = isolate()->inner_pointer_to_code_cache()->
981 GcSafeFindCodeForInnerPointer(pc());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000982 }
983 ASSERT(code != NULL);
984 ASSERT(code->kind() == Code::OPTIMIZED_FUNCTION);
985
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000986 SafepointEntry safepoint_entry = code->GetSafepointEntry(pc());
987 *deopt_index = safepoint_entry.deoptimization_index();
ager@chromium.org378b34e2011-01-28 08:04:38 +0000988 ASSERT(*deopt_index != Safepoint::kNoDeoptimizationIndex);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000989
990 return DeoptimizationInputData::cast(code->deoptimization_data());
991}
992
993
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000994int OptimizedFrame::GetInlineCount() {
995 ASSERT(is_optimized());
996
997 int deopt_index = Safepoint::kNoDeoptimizationIndex;
998 DeoptimizationInputData* data = GetDeoptimizationData(&deopt_index);
999
1000 TranslationIterator it(data->TranslationByteArray(),
1001 data->TranslationIndex(deopt_index)->value());
1002 Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next());
1003 ASSERT(opcode == Translation::BEGIN);
1004 USE(opcode);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001005 it.Next(); // Drop frame count.
1006 int jsframe_count = it.Next();
1007 return jsframe_count;
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001008}
1009
1010
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001011void OptimizedFrame::GetFunctions(List<JSFunction*>* functions) {
1012 ASSERT(functions->length() == 0);
1013 ASSERT(is_optimized());
1014
ager@chromium.org378b34e2011-01-28 08:04:38 +00001015 int deopt_index = Safepoint::kNoDeoptimizationIndex;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001016 DeoptimizationInputData* data = GetDeoptimizationData(&deopt_index);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001017 FixedArray* literal_array = data->LiteralArray();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001018
1019 TranslationIterator it(data->TranslationByteArray(),
1020 data->TranslationIndex(deopt_index)->value());
1021 Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next());
1022 ASSERT(opcode == Translation::BEGIN);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001023 it.Next(); // Drop frame count.
1024 int jsframe_count = it.Next();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001025
1026 // We insert the frames in reverse order because the frames
1027 // in the deoptimization translation are ordered bottom-to-top.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001028 while (jsframe_count > 0) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001029 opcode = static_cast<Translation::Opcode>(it.Next());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001030 if (opcode == Translation::JS_FRAME) {
1031 jsframe_count--;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001032 it.Next(); // Skip ast id.
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001033 JSFunction* function = LiteralAt(literal_array, it.Next());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001034 it.Next(); // Skip height.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001035 functions->Add(function);
1036 } else {
1037 // Skip over operands to advance to the next opcode.
1038 it.Skip(Translation::NumberOfOperandsFor(opcode));
1039 }
1040 }
1041}
1042
1043
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001044int ArgumentsAdaptorFrame::GetNumberOfIncomingArguments() const {
1045 return Smi::cast(GetExpression(0))->value();
1046}
1047
1048
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001049Address ArgumentsAdaptorFrame::GetCallerStackPointer() const {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001050 return fp() + StandardFrameConstants::kCallerSPOffset;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001051}
1052
1053
1054Address InternalFrame::GetCallerStackPointer() const {
1055 // Internal frames have no arguments. The stack pointer of the
1056 // caller is at a fixed offset from the frame pointer.
1057 return fp() + StandardFrameConstants::kCallerSPOffset;
1058}
1059
1060
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001061Code* ArgumentsAdaptorFrame::unchecked_code() const {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00001062 return isolate()->builtins()->builtin(
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001063 Builtins::kArgumentsAdaptorTrampoline);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001064}
1065
1066
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001067Code* InternalFrame::unchecked_code() const {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001068 const int offset = InternalFrameConstants::kCodeOffset;
1069 Object* code = Memory::Object_at(fp() + offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001070 ASSERT(code != NULL);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001071 return reinterpret_cast<Code*>(code);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001072}
1073
1074
1075void StackFrame::PrintIndex(StringStream* accumulator,
1076 PrintMode mode,
1077 int index) {
1078 accumulator->Add((mode == OVERVIEW) ? "%5d: " : "[%d]: ", index);
1079}
1080
1081
1082void JavaScriptFrame::Print(StringStream* accumulator,
1083 PrintMode mode,
1084 int index) const {
1085 HandleScope scope;
1086 Object* receiver = this->receiver();
1087 Object* function = this->function();
1088
1089 accumulator->PrintSecurityTokenIfChanged(function);
1090 PrintIndex(accumulator, mode, index);
1091 Code* code = NULL;
1092 if (IsConstructor()) accumulator->Add("new ");
1093 accumulator->PrintFunction(function, receiver, &code);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00001094
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001095 // Get scope information for nicer output, if possible. If code is NULL, or
1096 // doesn't contain scope info, scope_info will return 0 for the number of
1097 // parameters, stack local variables, context local variables, stack slots,
1098 // or context slots.
1099 Handle<ScopeInfo> scope_info(ScopeInfo::Empty());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001100
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00001101 if (function->IsJSFunction()) {
1102 Handle<SharedFunctionInfo> shared(JSFunction::cast(function)->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001103 scope_info = Handle<ScopeInfo>(shared->scope_info());
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00001104 Object* script_obj = shared->script();
1105 if (script_obj->IsScript()) {
1106 Handle<Script> script(Script::cast(script_obj));
1107 accumulator->Add(" [");
1108 accumulator->PrintName(script->name());
1109
1110 Address pc = this->pc();
1111 if (code != NULL && code->kind() == Code::FUNCTION &&
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00001112 pc >= code->instruction_start() && pc < code->instruction_end()) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00001113 int source_pos = code->SourcePosition(pc);
1114 int line = GetScriptLineNumberSafe(script, source_pos) + 1;
1115 accumulator->Add(":%d", line);
1116 } else {
1117 int function_start_pos = shared->start_position();
1118 int line = GetScriptLineNumberSafe(script, function_start_pos) + 1;
1119 accumulator->Add(":~%d", line);
1120 }
1121
1122 accumulator->Add("] ");
1123 }
1124 }
1125
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001126 accumulator->Add("(this=%o", receiver);
1127
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001128 // Print the parameters.
1129 int parameters_count = ComputeParametersCount();
1130 for (int i = 0; i < parameters_count; i++) {
1131 accumulator->Add(",");
1132 // If we have a name for the parameter we print it. Nameless
1133 // parameters are either because we have more actual parameters
1134 // than formal parameters or because we have no scope information.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001135 if (i < scope_info->ParameterCount()) {
1136 accumulator->PrintName(scope_info->ParameterName(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001137 accumulator->Add("=");
1138 }
1139 accumulator->Add("%o", GetParameter(i));
1140 }
1141
1142 accumulator->Add(")");
1143 if (mode == OVERVIEW) {
1144 accumulator->Add("\n");
1145 return;
1146 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00001147 if (is_optimized()) {
1148 accumulator->Add(" {\n// optimized frame\n}\n");
1149 return;
1150 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001151 accumulator->Add(" {\n");
1152
1153 // Compute the number of locals and expression stack elements.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001154 int stack_locals_count = scope_info->StackLocalCount();
1155 int heap_locals_count = scope_info->ContextLocalCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001156 int expressions_count = ComputeExpressionsCount();
1157
1158 // Print stack-allocated local variables.
1159 if (stack_locals_count > 0) {
1160 accumulator->Add(" // stack-allocated locals\n");
1161 }
1162 for (int i = 0; i < stack_locals_count; i++) {
1163 accumulator->Add(" var ");
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001164 accumulator->PrintName(scope_info->StackLocalName(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001165 accumulator->Add(" = ");
1166 if (i < expressions_count) {
1167 accumulator->Add("%o", GetExpression(i));
1168 } else {
1169 accumulator->Add("// no expression found - inconsistent frame?");
1170 }
1171 accumulator->Add("\n");
1172 }
1173
1174 // Try to get hold of the context of this frame.
1175 Context* context = NULL;
1176 if (this->context() != NULL && this->context()->IsContext()) {
1177 context = Context::cast(this->context());
1178 }
1179
1180 // Print heap-allocated local variables.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001181 if (heap_locals_count > 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001182 accumulator->Add(" // heap-allocated locals\n");
1183 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001184 for (int i = 0; i < heap_locals_count; i++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001185 accumulator->Add(" var ");
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001186 accumulator->PrintName(scope_info->ContextLocalName(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001187 accumulator->Add(" = ");
1188 if (context != NULL) {
1189 if (i < context->length()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001190 accumulator->Add("%o", context->get(Context::MIN_CONTEXT_SLOTS + i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001191 } else {
1192 accumulator->Add(
1193 "// warning: missing context slot - inconsistent frame?");
1194 }
1195 } else {
1196 accumulator->Add("// warning: no context found - inconsistent frame?");
1197 }
1198 accumulator->Add("\n");
1199 }
1200
1201 // Print the expression stack.
kasper.lund7276f142008-07-30 08:49:36 +00001202 int expressions_start = stack_locals_count;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001203 if (expressions_start < expressions_count) {
1204 accumulator->Add(" // expression stack (top to bottom)\n");
1205 }
1206 for (int i = expressions_count - 1; i >= expressions_start; i--) {
1207 if (IsExpressionInsideHandler(i)) continue;
1208 accumulator->Add(" [%02d] : %o\n", i, GetExpression(i));
1209 }
1210
1211 // Print details about the function.
1212 if (FLAG_max_stack_trace_source_length != 0 && code != NULL) {
1213 SharedFunctionInfo* shared = JSFunction::cast(function)->shared();
1214 accumulator->Add("--------- s o u r c e c o d e ---------\n");
1215 shared->SourceCodePrint(accumulator, FLAG_max_stack_trace_source_length);
1216 accumulator->Add("\n-----------------------------------------\n");
1217 }
1218
1219 accumulator->Add("}\n\n");
1220}
1221
1222
1223void ArgumentsAdaptorFrame::Print(StringStream* accumulator,
1224 PrintMode mode,
1225 int index) const {
1226 int actual = ComputeParametersCount();
1227 int expected = -1;
1228 Object* function = this->function();
1229 if (function->IsJSFunction()) {
1230 expected = JSFunction::cast(function)->shared()->formal_parameter_count();
1231 }
1232
1233 PrintIndex(accumulator, mode, index);
1234 accumulator->Add("arguments adaptor frame: %d->%d", actual, expected);
1235 if (mode == OVERVIEW) {
1236 accumulator->Add("\n");
1237 return;
1238 }
1239 accumulator->Add(" {\n");
1240
1241 // Print actual arguments.
1242 if (actual > 0) accumulator->Add(" // actual arguments\n");
1243 for (int i = 0; i < actual; i++) {
1244 accumulator->Add(" [%02d] : %o", i, GetParameter(i));
1245 if (expected != -1 && i >= expected) {
1246 accumulator->Add(" // not passed to callee");
1247 }
1248 accumulator->Add("\n");
1249 }
1250
1251 accumulator->Add("}\n\n");
1252}
1253
1254
1255void EntryFrame::Iterate(ObjectVisitor* v) const {
1256 StackHandlerIterator it(this, top_handler());
1257 ASSERT(!it.done());
1258 StackHandler* handler = it.handler();
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001259 ASSERT(handler->is_js_entry());
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00001260 handler->Iterate(v, LookupCode());
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001261#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001262 // Make sure that the entry frame does not contain more than one
1263 // stack handler.
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001264 it.Advance();
1265 ASSERT(it.done());
1266#endif
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00001267 IteratePc(v, pc_address(), LookupCode());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001268}
1269
1270
1271void StandardFrame::IterateExpressions(ObjectVisitor* v) const {
1272 const int offset = StandardFrameConstants::kContextOffset;
1273 Object** base = &Memory::Object_at(sp());
1274 Object** limit = &Memory::Object_at(fp() + offset) + 1;
1275 for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) {
1276 StackHandler* handler = it.handler();
1277 // Traverse pointers down to - but not including - the next
1278 // handler in the handler chain. Update the base to skip the
1279 // handler and allow the handler to traverse its own pointers.
1280 const Address address = handler->address();
1281 v->VisitPointers(base, reinterpret_cast<Object**>(address));
1282 base = reinterpret_cast<Object**>(address + StackHandlerConstants::kSize);
1283 // Traverse the pointers in the handler itself.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00001284 handler->Iterate(v, LookupCode());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001285 }
1286 v->VisitPointers(base, limit);
1287}
1288
1289
1290void JavaScriptFrame::Iterate(ObjectVisitor* v) const {
1291 IterateExpressions(v);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00001292 IteratePc(v, pc_address(), LookupCode());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001293}
1294
1295
1296void InternalFrame::Iterate(ObjectVisitor* v) const {
1297 // Internal frames only have object pointers on the expression stack
1298 // as they never have any arguments.
1299 IterateExpressions(v);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00001300 IteratePc(v, pc_address(), LookupCode());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001301}
1302
1303
1304// -------------------------------------------------------------------------
1305
1306
1307JavaScriptFrame* StackFrameLocator::FindJavaScriptFrame(int n) {
1308 ASSERT(n >= 0);
1309 for (int i = 0; i <= n; i++) {
1310 while (!iterator_.frame()->is_java_script()) iterator_.Advance();
1311 if (i == n) return JavaScriptFrame::cast(iterator_.frame());
1312 iterator_.Advance();
1313 }
1314 UNREACHABLE();
1315 return NULL;
1316}
1317
1318
1319// -------------------------------------------------------------------------
1320
1321
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001322static Map* GcSafeMapOfCodeSpaceObject(HeapObject* object) {
1323 MapWord map_word = object->map_word();
1324 return map_word.IsForwardingAddress() ?
1325 map_word.ToForwardingAddress()->map() : map_word.ToMap();
1326}
1327
1328
1329static int GcSafeSizeOfCodeSpaceObject(HeapObject* object) {
1330 return object->SizeFromMap(GcSafeMapOfCodeSpaceObject(object));
1331}
1332
1333
1334#ifdef DEBUG
1335static bool GcSafeCodeContains(HeapObject* code, Address addr) {
1336 Map* map = GcSafeMapOfCodeSpaceObject(code);
1337 ASSERT(map == code->GetHeap()->code_map());
1338 Address start = code->address();
1339 Address end = code->address() + code->SizeFromMap(map);
1340 return start <= addr && addr < end;
1341}
1342#endif
1343
1344
1345Code* InnerPointerToCodeCache::GcSafeCastToCode(HeapObject* object,
1346 Address inner_pointer) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001347 Code* code = reinterpret_cast<Code*>(object);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001348 ASSERT(code != NULL && GcSafeCodeContains(code, inner_pointer));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001349 return code;
1350}
1351
1352
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001353Code* InnerPointerToCodeCache::GcSafeFindCodeForInnerPointer(
1354 Address inner_pointer) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001355 Heap* heap = isolate_->heap();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001356 // Check if the inner pointer points into a large object chunk.
jkummerow@chromium.org531dfe82012-03-20 13:01:16 +00001357 LargePage* large_page = heap->lo_space()->FindPage(inner_pointer);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001358 if (large_page != NULL) {
1359 return GcSafeCastToCode(large_page->GetObject(), inner_pointer);
1360 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001361
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001362 // Iterate through the page until we reach the end or find an object starting
1363 // after the inner pointer.
1364 Page* page = Page::FromAddress(inner_pointer);
1365
1366 Address addr = page->skip_list()->StartFor(inner_pointer);
1367
1368 Address top = heap->code_space()->top();
1369 Address limit = heap->code_space()->limit();
1370
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001371 while (true) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001372 if (addr == top && addr != limit) {
1373 addr = limit;
1374 continue;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001375 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001376
1377 HeapObject* obj = HeapObject::FromAddress(addr);
1378 int obj_size = GcSafeSizeOfCodeSpaceObject(obj);
1379 Address next_addr = addr + obj_size;
1380 if (next_addr > inner_pointer) return GcSafeCastToCode(obj, inner_pointer);
1381 addr = next_addr;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001382 }
1383}
1384
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001385
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001386InnerPointerToCodeCache::InnerPointerToCodeCacheEntry*
1387 InnerPointerToCodeCache::GetCacheEntry(Address inner_pointer) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001388 isolate_->counters()->pc_to_code()->Increment();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001389 ASSERT(IsPowerOf2(kInnerPointerToCodeCacheSize));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001390 uint32_t hash = ComputeIntegerHash(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001391 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(inner_pointer)),
1392 v8::internal::kZeroHashSeed);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001393 uint32_t index = hash & (kInnerPointerToCodeCacheSize - 1);
1394 InnerPointerToCodeCacheEntry* entry = cache(index);
1395 if (entry->inner_pointer == inner_pointer) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001396 isolate_->counters()->pc_to_code_cached()->Increment();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001397 ASSERT(entry->code == GcSafeFindCodeForInnerPointer(inner_pointer));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001398 } else {
1399 // Because this code may be interrupted by a profiling signal that
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001400 // also queries the cache, we cannot update inner_pointer before the code
1401 // has been set. Otherwise, we risk trying to use a cache entry before
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001402 // the code has been computed.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001403 entry->code = GcSafeFindCodeForInnerPointer(inner_pointer);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001404 entry->safepoint_entry.Reset();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001405 entry->inner_pointer = inner_pointer;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001406 }
1407 return entry;
1408}
1409
1410
1411// -------------------------------------------------------------------------
1412
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001413int NumRegs(RegList reglist) {
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +00001414 return CompilerIntrinsics::CountSetBits(reglist);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001415}
1416
1417
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001418struct JSCallerSavedCodeData {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001419 int reg_code[kNumJSCallerSaved];
1420};
1421
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001422JSCallerSavedCodeData caller_saved_code_data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001423
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001424void SetUpJSCallerSavedCodeData() {
1425 int i = 0;
1426 for (int r = 0; r < kNumRegs; r++)
1427 if ((kJSCallerSaved & (1 << r)) != 0)
1428 caller_saved_code_data.reg_code[i++] = r;
1429
1430 ASSERT(i == kNumJSCallerSaved);
1431}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001432
1433int JSCallerSavedCode(int n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001434 ASSERT(0 <= n && n < kNumJSCallerSaved);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001435 return caller_saved_code_data.reg_code[n];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001436}
1437
1438
ager@chromium.org357bf652010-04-12 11:30:10 +00001439#define DEFINE_WRAPPER(type, field) \
1440class field##_Wrapper : public ZoneObject { \
1441 public: /* NOLINT */ \
1442 field##_Wrapper(const field& original) : frame_(original) { \
1443 } \
1444 field frame_; \
1445};
1446STACK_FRAME_TYPE_LIST(DEFINE_WRAPPER)
1447#undef DEFINE_WRAPPER
1448
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001449static StackFrame* AllocateFrameCopy(StackFrame* frame, Zone* zone) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001450#define FRAME_TYPE_CASE(type, field) \
1451 case StackFrame::type: { \
1452 field##_Wrapper* wrapper = \
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001453 new(zone) field##_Wrapper(*(reinterpret_cast<field*>(frame))); \
ager@chromium.org357bf652010-04-12 11:30:10 +00001454 return &wrapper->frame_; \
1455 }
1456
1457 switch (frame->type()) {
1458 STACK_FRAME_TYPE_LIST(FRAME_TYPE_CASE)
1459 default: UNREACHABLE();
1460 }
1461#undef FRAME_TYPE_CASE
1462 return NULL;
1463}
1464
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001465Vector<StackFrame*> CreateStackMap(Zone* zone) {
1466 ZoneList<StackFrame*> list(10, zone);
ager@chromium.org357bf652010-04-12 11:30:10 +00001467 for (StackFrameIterator it; !it.done(); it.Advance()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001468 StackFrame* frame = AllocateFrameCopy(it.frame(), zone);
1469 list.Add(frame, zone);
ager@chromium.org357bf652010-04-12 11:30:10 +00001470 }
1471 return list.ToVector();
1472}
1473
1474
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001475} } // namespace v8::internal