blob: debaf3ba72729d622c6a05f585283e7ed962e798 [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),
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000091StackFrameIterator::StackFrameIterator(Isolate* isolate)
92 : isolate_(isolate),
93 STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON)
94 frame_(NULL), handler_(NULL),
95 thread_(isolate_->thread_local_top()),
96 fp_(NULL), sp_(NULL), advance_(&StackFrameIterator::AdvanceWithHandler) {
97 Reset();
98}
99StackFrameIterator::StackFrameIterator(Isolate* isolate, ThreadLocalTop* t)
100 : isolate_(isolate),
101 STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON)
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000102 frame_(NULL), handler_(NULL), thread_(t),
103 fp_(NULL), sp_(NULL), advance_(&StackFrameIterator::AdvanceWithHandler) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000104 Reset();
105}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000106StackFrameIterator::StackFrameIterator(Isolate* isolate,
107 bool use_top, Address fp, Address sp)
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000108 : isolate_(isolate),
109 STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON)
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000110 frame_(NULL), handler_(NULL),
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000111 thread_(use_top ? isolate_->thread_local_top() : NULL),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000112 fp_(use_top ? NULL : fp), sp_(sp),
113 advance_(use_top ? &StackFrameIterator::AdvanceWithHandler :
114 &StackFrameIterator::AdvanceWithoutHandler) {
115 if (use_top || fp != NULL) {
116 Reset();
117 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000118}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000119
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000120#undef INITIALIZE_SINGLETON
121
122
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000123void StackFrameIterator::AdvanceWithHandler() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000124 ASSERT(!done());
125 // Compute the state of the calling frame before restoring
126 // callee-saved registers and unwinding handlers. This allows the
127 // frame code that computes the caller state to access the top
128 // handler and the value of any callee-saved register if needed.
129 StackFrame::State state;
130 StackFrame::Type type = frame_->GetCallerState(&state);
131
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000132 // Unwind handlers corresponding to the current frame.
133 StackHandlerIterator it(frame_, handler_);
134 while (!it.done()) it.Advance();
135 handler_ = it.handler();
136
137 // Advance to the calling frame.
138 frame_ = SingletonFor(type, &state);
139
140 // When we're done iterating over the stack frames, the handler
141 // chain must have been completely unwound.
142 ASSERT(!done() || handler_ == NULL);
143}
144
145
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000146void StackFrameIterator::AdvanceWithoutHandler() {
147 // A simpler version of Advance which doesn't care about handler.
148 ASSERT(!done());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000149 StackFrame::State state;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000150 StackFrame::Type type = frame_->GetCallerState(&state);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000151 frame_ = SingletonFor(type, &state);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000152}
153
154
155void StackFrameIterator::Reset() {
156 StackFrame::State state;
157 StackFrame::Type type;
158 if (thread_ != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000159 type = ExitFrame::GetStateForFramePointer(
160 Isolate::c_entry_fp(thread_), &state);
161 handler_ = StackHandler::FromAddress(
162 Isolate::handler(thread_));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000163 } else {
164 ASSERT(fp_ != NULL);
165 state.fp = fp_;
166 state.sp = sp_;
ulan@chromium.org967e2702012-02-28 09:49:15 +0000167 state.pc_address = ResolveReturnAddressLocation(
168 reinterpret_cast<Address*>(StandardFrame::ComputePCAddress(fp_)));
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000169 type = StackFrame::ComputeType(isolate(), &state);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000170 }
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000171 if (SingletonFor(type) == NULL) return;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000172 frame_ = SingletonFor(type, &state);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000173}
174
175
176StackFrame* StackFrameIterator::SingletonFor(StackFrame::Type type,
177 StackFrame::State* state) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000178 if (type == StackFrame::NONE) return NULL;
179 StackFrame* result = SingletonFor(type);
180 ASSERT(result != NULL);
181 result->state_ = *state;
182 return result;
183}
184
185
186StackFrame* StackFrameIterator::SingletonFor(StackFrame::Type type) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000187#define FRAME_TYPE_CASE(type, field) \
188 case StackFrame::type: result = &field##_; break;
189
190 StackFrame* result = NULL;
191 switch (type) {
192 case StackFrame::NONE: return NULL;
193 STACK_FRAME_TYPE_LIST(FRAME_TYPE_CASE)
194 default: break;
195 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000196 return result;
197
198#undef FRAME_TYPE_CASE
199}
200
201
202// -------------------------------------------------------------------------
203
204
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000205StackTraceFrameIterator::StackTraceFrameIterator(Isolate* isolate)
206 : JavaScriptFrameIterator(isolate) {
207 if (!done() && !IsValidFrame()) Advance();
208}
209
210
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000211void StackTraceFrameIterator::Advance() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000212 while (true) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000213 JavaScriptFrameIterator::Advance();
214 if (done()) return;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000215 if (IsValidFrame()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000216 }
217}
218
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000219bool StackTraceFrameIterator::IsValidFrame() {
220 if (!frame()->function()->IsJSFunction()) return false;
221 Object* script = JSFunction::cast(frame()->function())->shared()->script();
222 // Don't show functions from native scripts to user.
223 return (script->IsScript() &&
224 Script::TYPE_NATIVE != Script::cast(script)->type()->value());
225}
226
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000227
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000228// -------------------------------------------------------------------------
229
230
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000231bool SafeStackFrameIterator::ExitFrameValidator::IsValidFP(Address fp) {
232 if (!validator_.IsValid(fp)) return false;
233 Address sp = ExitFrame::ComputeStackPointer(fp);
234 if (!validator_.IsValid(sp)) return false;
235 StackFrame::State state;
236 ExitFrame::FillState(fp, sp, &state);
237 if (!validator_.IsValid(reinterpret_cast<Address>(state.pc_address))) {
238 return false;
239 }
240 return *state.pc_address != NULL;
241}
242
243
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000244SafeStackFrameIterator::ActiveCountMaintainer::ActiveCountMaintainer(
245 Isolate* isolate)
246 : isolate_(isolate) {
247 isolate_->set_safe_stack_iterator_counter(
248 isolate_->safe_stack_iterator_counter() + 1);
249}
250
251
252SafeStackFrameIterator::ActiveCountMaintainer::~ActiveCountMaintainer() {
253 isolate_->set_safe_stack_iterator_counter(
254 isolate_->safe_stack_iterator_counter() - 1);
255}
256
257
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000258SafeStackFrameIterator::SafeStackFrameIterator(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000259 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000260 Address fp, Address sp, Address low_bound, Address high_bound) :
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000261 maintainer_(isolate),
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000262 stack_validator_(low_bound, high_bound),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000263 is_valid_top_(IsValidTop(isolate, low_bound, high_bound)),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000264 is_valid_fp_(IsWithinBounds(low_bound, high_bound, fp)),
265 is_working_iterator_(is_valid_top_ || is_valid_fp_),
266 iteration_done_(!is_working_iterator_),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000267 iterator_(isolate, is_valid_top_, is_valid_fp_ ? fp : NULL, sp) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000268}
269
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000270bool SafeStackFrameIterator::is_active(Isolate* isolate) {
271 return isolate->safe_stack_iterator_counter() > 0;
272}
273
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000274
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000275bool SafeStackFrameIterator::IsValidTop(Isolate* isolate,
276 Address low_bound, Address high_bound) {
277 ThreadLocalTop* top = isolate->thread_local_top();
278 Address fp = Isolate::c_entry_fp(top);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000279 ExitFrameValidator validator(low_bound, high_bound);
280 if (!validator.IsValidFP(fp)) return false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000281 return Isolate::handler(top) != NULL;
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000282}
283
284
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000285void SafeStackFrameIterator::Advance() {
286 ASSERT(is_working_iterator_);
287 ASSERT(!done());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000288 StackFrame* last_frame = iterator_.frame();
289 Address last_sp = last_frame->sp(), last_fp = last_frame->fp();
290 // Before advancing to the next stack frame, perform pointer validity tests
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000291 iteration_done_ = !IsValidFrame(last_frame) ||
292 !CanIterateHandles(last_frame, iterator_.handler()) ||
293 !IsValidCaller(last_frame);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000294 if (iteration_done_) return;
295
296 iterator_.Advance();
297 if (iterator_.done()) return;
298 // Check that we have actually moved to the previous frame in the stack
299 StackFrame* prev_frame = iterator_.frame();
300 iteration_done_ = prev_frame->sp() < last_sp || prev_frame->fp() < last_fp;
301}
302
303
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000304bool SafeStackFrameIterator::CanIterateHandles(StackFrame* frame,
305 StackHandler* handler) {
306 // If StackIterator iterates over StackHandles, verify that
307 // StackHandlerIterator can be instantiated (see StackHandlerIterator
308 // constructor.)
309 return !is_valid_top_ || (frame->sp() <= handler->address());
310}
311
312
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000313bool SafeStackFrameIterator::IsValidFrame(StackFrame* frame) const {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000314 return IsValidStackAddress(frame->sp()) && IsValidStackAddress(frame->fp());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000315}
316
317
318bool SafeStackFrameIterator::IsValidCaller(StackFrame* frame) {
319 StackFrame::State state;
ager@chromium.org41826e72009-03-30 13:30:57 +0000320 if (frame->is_entry() || frame->is_entry_construct()) {
321 // See EntryFrame::GetCallerState. It computes the caller FP address
322 // and calls ExitFrame::GetStateForFramePointer on it. We need to be
323 // sure that caller FP address is valid.
324 Address caller_fp = Memory::Address_at(
325 frame->fp() + EntryFrameConstants::kCallerFPOffset);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000326 ExitFrameValidator validator(stack_validator_);
327 if (!validator.IsValidFP(caller_fp)) return false;
ager@chromium.org41826e72009-03-30 13:30:57 +0000328 } else if (frame->is_arguments_adaptor()) {
329 // See ArgumentsAdaptorFrame::GetCallerStackPointer. It assumes that
330 // the number of arguments is stored on stack as Smi. We need to check
331 // that it really an Smi.
332 Object* number_of_args = reinterpret_cast<ArgumentsAdaptorFrame*>(frame)->
333 GetExpression(0);
334 if (!number_of_args->IsSmi()) {
335 return false;
336 }
337 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000338 frame->ComputeCallerState(&state);
339 return IsValidStackAddress(state.sp) && IsValidStackAddress(state.fp) &&
340 iterator_.SingletonFor(frame->GetCallerState(&state)) != NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000341}
342
343
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000344void SafeStackFrameIterator::Reset() {
345 if (is_working_iterator_) {
346 iterator_.Reset();
347 iteration_done_ = false;
348 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000349}
350
351
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000352// -------------------------------------------------------------------------
353
354
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000355SafeStackTraceFrameIterator::SafeStackTraceFrameIterator(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000356 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000357 Address fp, Address sp, Address low_bound, Address high_bound) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000358 SafeJavaScriptFrameIterator(isolate, fp, sp, low_bound, high_bound) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000359 if (!done() && !frame()->is_java_script()) Advance();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000360}
361
362
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000363void SafeStackTraceFrameIterator::Advance() {
364 while (true) {
365 SafeJavaScriptFrameIterator::Advance();
366 if (done()) return;
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000367 if (frame()->is_java_script()) return;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000368 }
369}
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000370
371
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000372Code* StackFrame::GetSafepointData(Isolate* isolate,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000373 Address inner_pointer,
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000374 SafepointEntry* safepoint_entry,
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000375 unsigned* stack_slots) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000376 InnerPointerToCodeCache::InnerPointerToCodeCacheEntry* entry =
377 isolate->inner_pointer_to_code_cache()->GetCacheEntry(inner_pointer);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000378 if (!entry->safepoint_entry.is_valid()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000379 entry->safepoint_entry = entry->code->GetSafepointEntry(inner_pointer);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000380 ASSERT(entry->safepoint_entry.is_valid());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000381 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000382 ASSERT(entry->safepoint_entry.Equals(
383 entry->code->GetSafepointEntry(inner_pointer)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000384 }
385
386 // Fill in the results and return the code.
387 Code* code = entry->code;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000388 *safepoint_entry = entry->safepoint_entry;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000389 *stack_slots = code->stack_slots();
390 return code;
391}
392
393
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000394bool StackFrame::HasHandler() const {
395 StackHandlerIterator it(this, top_handler());
396 return !it.done();
397}
398
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000399
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000400#ifdef DEBUG
401static bool GcSafeCodeContains(HeapObject* object, Address addr);
402#endif
403
404
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000405void StackFrame::IteratePc(ObjectVisitor* v,
406 Address* pc_address,
407 Code* holder) {
408 Address pc = *pc_address;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000409 ASSERT(GcSafeCodeContains(holder, pc));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000410 unsigned pc_offset = static_cast<unsigned>(pc - holder->instruction_start());
411 Object* code = holder;
412 v->VisitPointer(&code);
413 if (code != holder) {
414 holder = reinterpret_cast<Code*>(code);
415 pc = holder->instruction_start() + pc_offset;
416 *pc_address = pc;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000417 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000418}
419
420
ulan@chromium.org967e2702012-02-28 09:49:15 +0000421void StackFrame::SetReturnAddressLocationResolver(
422 ReturnAddressLocationResolver resolver) {
423 ASSERT(return_address_location_resolver == NULL);
424 return_address_location_resolver = resolver;
425}
426
427
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000428StackFrame::Type StackFrame::ComputeType(Isolate* isolate, State* state) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000429 ASSERT(state->fp != NULL);
430 if (StandardFrame::IsArgumentsAdaptorFrame(state->fp)) {
431 return ARGUMENTS_ADAPTOR;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000432 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000433 // The marker and function offsets overlap. If the marker isn't a
434 // smi then the frame is a JavaScript frame -- and the marker is
435 // really the function.
436 const int offset = StandardFrameConstants::kMarkerOffset;
437 Object* marker = Memory::Object_at(state->fp + offset);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000438 if (!marker->IsSmi()) {
439 // If we're using a "safe" stack iterator, we treat optimized
440 // frames as normal JavaScript frames to avoid having to look
441 // into the heap to determine the state. This is safe as long
442 // as nobody tries to GC...
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000443 if (SafeStackFrameIterator::is_active(isolate)) return JAVA_SCRIPT;
444 Code::Kind kind = GetContainingCode(isolate, *(state->pc_address))->kind();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000445 ASSERT(kind == Code::FUNCTION || kind == Code::OPTIMIZED_FUNCTION);
446 return (kind == Code::OPTIMIZED_FUNCTION) ? OPTIMIZED : JAVA_SCRIPT;
447 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000448 return static_cast<StackFrame::Type>(Smi::cast(marker)->value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000449}
450
451
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000452
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000453StackFrame::Type StackFrame::GetCallerState(State* state) const {
454 ComputeCallerState(state);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000455 return ComputeType(isolate(), state);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000456}
457
458
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000459Address StackFrame::UnpaddedFP() const {
460#if defined(V8_TARGET_ARCH_IA32)
461 if (!is_optimized()) return fp();
462 int32_t alignment_state = Memory::int32_at(
463 fp() + JavaScriptFrameConstants::kDynamicAlignmentStateOffset);
464
465 return (alignment_state == kAlignmentPaddingPushed) ?
466 (fp() + kPointerSize) : fp();
467#else
468 return fp();
469#endif
470}
471
472
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000473Code* EntryFrame::unchecked_code() const {
danno@chromium.org72204d52012-10-31 10:02:10 +0000474 return HEAP->js_entry_code();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000475}
476
477
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000478void EntryFrame::ComputeCallerState(State* state) const {
479 GetCallerState(state);
480}
481
482
ager@chromium.org357bf652010-04-12 11:30:10 +0000483void EntryFrame::SetCallerFp(Address caller_fp) {
484 const int offset = EntryFrameConstants::kCallerFPOffset;
485 Memory::Address_at(this->fp() + offset) = caller_fp;
486}
487
488
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000489StackFrame::Type EntryFrame::GetCallerState(State* state) const {
490 const int offset = EntryFrameConstants::kCallerFPOffset;
491 Address fp = Memory::Address_at(this->fp() + offset);
492 return ExitFrame::GetStateForFramePointer(fp, state);
493}
494
495
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000496Code* EntryConstructFrame::unchecked_code() const {
danno@chromium.org72204d52012-10-31 10:02:10 +0000497 return HEAP->js_construct_entry_code();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000498}
499
500
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000501Object*& ExitFrame::code_slot() const {
502 const int offset = ExitFrameConstants::kCodeOffset;
503 return Memory::Object_at(fp() + offset);
504}
505
506
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000507Code* ExitFrame::unchecked_code() const {
508 return reinterpret_cast<Code*>(code_slot());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000509}
510
511
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000512void ExitFrame::ComputeCallerState(State* state) const {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000513 // Set up the caller state.
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000514 state->sp = caller_sp();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000515 state->fp = Memory::Address_at(fp() + ExitFrameConstants::kCallerFPOffset);
ulan@chromium.org967e2702012-02-28 09:49:15 +0000516 state->pc_address = ResolveReturnAddressLocation(
517 reinterpret_cast<Address*>(fp() + ExitFrameConstants::kCallerPCOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000518}
519
520
ager@chromium.org357bf652010-04-12 11:30:10 +0000521void ExitFrame::SetCallerFp(Address caller_fp) {
522 Memory::Address_at(fp() + ExitFrameConstants::kCallerFPOffset) = caller_fp;
523}
524
525
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000526void ExitFrame::Iterate(ObjectVisitor* v) const {
527 // The arguments are traversed as part of the expression stack of
528 // the calling frame.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000529 IteratePc(v, pc_address(), LookupCode());
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000530 v->VisitPointer(&code_slot());
531}
532
533
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000534Address ExitFrame::GetCallerStackPointer() const {
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000535 return fp() + ExitFrameConstants::kCallerSPDisplacement;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000536}
537
538
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000539StackFrame::Type ExitFrame::GetStateForFramePointer(Address fp, State* state) {
540 if (fp == 0) return NONE;
541 Address sp = ComputeStackPointer(fp);
542 FillState(fp, sp, state);
543 ASSERT(*state->pc_address != NULL);
544 return EXIT;
545}
546
547
548void ExitFrame::FillState(Address fp, Address sp, State* state) {
549 state->sp = sp;
550 state->fp = fp;
ulan@chromium.org967e2702012-02-28 09:49:15 +0000551 state->pc_address = ResolveReturnAddressLocation(
552 reinterpret_cast<Address*>(sp - 1 * kPointerSize));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000553}
554
555
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000556Address StandardFrame::GetExpressionAddress(int n) const {
kasper.lund7276f142008-07-30 08:49:36 +0000557 const int offset = StandardFrameConstants::kExpressionsOffset;
558 return fp() + offset - n * kPointerSize;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000559}
560
561
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000562Object* StandardFrame::GetExpression(Address fp, int index) {
563 return Memory::Object_at(GetExpressionAddress(fp, index));
564}
565
566
567Address StandardFrame::GetExpressionAddress(Address fp, int n) {
568 const int offset = StandardFrameConstants::kExpressionsOffset;
569 return fp + offset - n * kPointerSize;
570}
571
572
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000573int StandardFrame::ComputeExpressionsCount() const {
574 const int offset =
575 StandardFrameConstants::kExpressionsOffset + kPointerSize;
576 Address base = fp() + offset;
577 Address limit = sp();
578 ASSERT(base >= limit); // stack grows downwards
579 // Include register-allocated locals in number of expressions.
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000580 return static_cast<int>((base - limit) / kPointerSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000581}
582
583
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000584void StandardFrame::ComputeCallerState(State* state) const {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000585 state->sp = caller_sp();
586 state->fp = caller_fp();
ulan@chromium.org967e2702012-02-28 09:49:15 +0000587 state->pc_address = ResolveReturnAddressLocation(
588 reinterpret_cast<Address*>(ComputePCAddress(fp())));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000589}
590
591
ager@chromium.org357bf652010-04-12 11:30:10 +0000592void StandardFrame::SetCallerFp(Address caller_fp) {
593 Memory::Address_at(fp() + StandardFrameConstants::kCallerFPOffset) =
594 caller_fp;
595}
596
597
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000598bool StandardFrame::IsExpressionInsideHandler(int n) const {
599 Address address = GetExpressionAddress(n);
600 for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) {
601 if (it.handler()->includes(address)) return true;
602 }
603 return false;
604}
605
606
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000607void StandardFrame::IterateCompiledFrame(ObjectVisitor* v) const {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000608 // Make sure that we're not doing "safe" stack frame iteration. We cannot
609 // possibly find pointers in optimized frames in that state.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000610 ASSERT(!SafeStackFrameIterator::is_active(isolate()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000611
612 // Compute the safepoint information.
613 unsigned stack_slots = 0;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000614 SafepointEntry safepoint_entry;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000615 Code* code = StackFrame::GetSafepointData(
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000616 isolate(), pc(), &safepoint_entry, &stack_slots);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000617 unsigned slot_space = stack_slots * kPointerSize;
618
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000619 // Visit the outgoing parameters.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000620 Object** parameters_base = &Memory::Object_at(sp());
621 Object** parameters_limit = &Memory::Object_at(
622 fp() + JavaScriptFrameConstants::kFunctionOffset - slot_space);
623
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000624 // Visit the parameters that may be on top of the saved registers.
625 if (safepoint_entry.argument_count() > 0) {
626 v->VisitPointers(parameters_base,
627 parameters_base + safepoint_entry.argument_count());
628 parameters_base += safepoint_entry.argument_count();
629 }
630
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000631 // Skip saved double registers.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000632 if (safepoint_entry.has_doubles()) {
yangguo@chromium.org003650e2013-01-24 16:31:08 +0000633 // Number of doubles not known at snapshot time.
634 ASSERT(!Serializer::enabled());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000635 parameters_base += DoubleRegister::NumAllocatableRegisters() *
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000636 kDoubleSize / kPointerSize;
637 }
638
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000639 // Visit the registers that contain pointers if any.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000640 if (safepoint_entry.HasRegisters()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000641 for (int i = kNumSafepointRegisters - 1; i >=0; i--) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000642 if (safepoint_entry.HasRegisterAt(i)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000643 int reg_stack_index = MacroAssembler::SafepointRegisterStackIndex(i);
644 v->VisitPointer(parameters_base + reg_stack_index);
645 }
646 }
647 // Skip the words containing the register values.
648 parameters_base += kNumSafepointRegisters;
649 }
650
651 // We're done dealing with the register bits.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000652 uint8_t* safepoint_bits = safepoint_entry.bits();
653 safepoint_bits += kNumSafepointRegisters >> kBitsPerByteLog2;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000654
655 // Visit the rest of the parameters.
656 v->VisitPointers(parameters_base, parameters_limit);
657
658 // Visit pointer spill slots and locals.
659 for (unsigned index = 0; index < stack_slots; index++) {
660 int byte_index = index >> kBitsPerByteLog2;
661 int bit_index = index & (kBitsPerByte - 1);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000662 if ((safepoint_bits[byte_index] & (1U << bit_index)) != 0) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000663 v->VisitPointer(parameters_limit + index);
664 }
665 }
666
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000667 // Visit the return address in the callee and incoming arguments.
668 IteratePc(v, pc_address(), code);
669}
670
671
672void StubFrame::Iterate(ObjectVisitor* v) const {
673 IterateCompiledFrame(v);
674}
675
676
677Code* StubFrame::unchecked_code() const {
678 return static_cast<Code*>(isolate()->heap()->FindCodeObject(pc()));
679}
680
681
682Address StubFrame::GetCallerStackPointer() const {
683 return fp() + ExitFrameConstants::kCallerSPDisplacement;
684}
685
686
687int StubFrame::GetNumberOfIncomingArguments() const {
688 return 0;
689}
690
691
692void OptimizedFrame::Iterate(ObjectVisitor* v) const {
693#ifdef DEBUG
694 // Make sure that optimized frames do not contain any stack handlers.
695 StackHandlerIterator it(this, top_handler());
696 ASSERT(it.done());
697#endif
698
699 IterateCompiledFrame(v);
700
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000701 // Visit the context and the function.
702 Object** fixed_base = &Memory::Object_at(
703 fp() + JavaScriptFrameConstants::kFunctionOffset);
704 Object** fixed_limit = &Memory::Object_at(fp());
705 v->VisitPointers(fixed_base, fixed_limit);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000706}
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +0000707
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000708
709void JavaScriptFrame::SetParameterValue(int index, Object* value) const {
710 Memory::Object_at(GetParameterSlot(index)) = value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000711}
712
713
714bool JavaScriptFrame::IsConstructor() const {
ager@chromium.org7c537e22008-10-16 08:43:32 +0000715 Address fp = caller_fp();
716 if (has_adapted_arguments()) {
717 // Skip the arguments adaptor frame and look at the real caller.
718 fp = Memory::Address_at(fp + StandardFrameConstants::kCallerFPOffset);
719 }
720 return IsConstructFrame(fp);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000721}
722
723
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000724int JavaScriptFrame::GetArgumentsLength() const {
725 // If there is an arguments adaptor frame get the arguments length from it.
726 if (has_adapted_arguments()) {
727 return Smi::cast(GetExpression(caller_fp(), 0))->value();
728 } else {
729 return GetNumberOfIncomingArguments();
730 }
731}
732
733
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000734Code* JavaScriptFrame::unchecked_code() const {
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000735 JSFunction* function = JSFunction::cast(this->function());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000736 return function->unchecked_code();
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000737}
738
739
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000740int JavaScriptFrame::GetNumberOfIncomingArguments() const {
741 ASSERT(!SafeStackFrameIterator::is_active(isolate()) &&
742 isolate()->heap()->gc_state() == Heap::NOT_IN_GC);
743
744 JSFunction* function = JSFunction::cast(this->function());
745 return function->shared()->formal_parameter_count();
746}
747
748
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000749Address JavaScriptFrame::GetCallerStackPointer() const {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000750 return fp() + StandardFrameConstants::kCallerSPOffset;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000751}
752
753
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000754void JavaScriptFrame::GetFunctions(List<JSFunction*>* functions) {
755 ASSERT(functions->length() == 0);
756 functions->Add(JSFunction::cast(function()));
757}
758
759
760void JavaScriptFrame::Summarize(List<FrameSummary>* functions) {
761 ASSERT(functions->length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000762 Code* code_pointer = LookupCode();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000763 int offset = static_cast<int>(pc() - code_pointer->address());
764 FrameSummary summary(receiver(),
765 JSFunction::cast(function()),
766 code_pointer,
767 offset,
768 IsConstructor());
769 functions->Add(summary);
770}
771
772
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000773void JavaScriptFrame::PrintTop(Isolate* isolate,
774 FILE* file,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000775 bool print_args,
776 bool print_line_number) {
777 // constructor calls
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000778 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000779 AssertNoAllocation no_allocation;
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000780 JavaScriptFrameIterator it(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000781 while (!it.done()) {
782 if (it.frame()->is_java_script()) {
783 JavaScriptFrame* frame = it.frame();
784 if (frame->IsConstructor()) PrintF(file, "new ");
785 // function name
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000786 Object* maybe_fun = frame->function();
787 if (maybe_fun->IsJSFunction()) {
788 JSFunction* fun = JSFunction::cast(maybe_fun);
789 fun->PrintName();
790 Code* js_code = frame->unchecked_code();
791 Address pc = frame->pc();
792 int code_offset =
793 static_cast<int>(pc - js_code->instruction_start());
794 PrintF("+%d", code_offset);
795 SharedFunctionInfo* shared = fun->shared();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000796 if (print_line_number) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000797 Code* code = Code::cast(
798 v8::internal::Isolate::Current()->heap()->FindCodeObject(pc));
799 int source_pos = code->SourcePosition(pc);
800 Object* maybe_script = shared->script();
801 if (maybe_script->IsScript()) {
802 Handle<Script> script(Script::cast(maybe_script));
803 int line = GetScriptLineNumberSafe(script, source_pos) + 1;
804 Object* script_name_raw = script->name();
805 if (script_name_raw->IsString()) {
806 String* script_name = String::cast(script->name());
807 SmartArrayPointer<char> c_script_name =
808 script_name->ToCString(DISALLOW_NULLS,
809 ROBUST_STRING_TRAVERSAL);
810 PrintF(file, " at %s:%d", *c_script_name, line);
811 } else {
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000812 PrintF(file, " at <unknown>:%d", line);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000813 }
814 } else {
815 PrintF(file, " at <unknown>:<unknown>");
816 }
817 }
818 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000819 PrintF("<unknown>");
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000820 }
821
822 if (print_args) {
823 // function arguments
824 // (we are intentionally only printing the actually
825 // supplied parameters, not all parameters required)
826 PrintF(file, "(this=");
827 frame->receiver()->ShortPrint(file);
828 const int length = frame->ComputeParametersCount();
829 for (int i = 0; i < length; i++) {
830 PrintF(file, ", ");
831 frame->GetParameter(i)->ShortPrint(file);
832 }
833 PrintF(file, ")");
834 }
835 break;
836 }
837 it.Advance();
838 }
839}
840
841
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000842void FrameSummary::Print() {
843 PrintF("receiver: ");
844 receiver_->ShortPrint();
845 PrintF("\nfunction: ");
846 function_->shared()->DebugName()->ShortPrint();
847 PrintF("\ncode: ");
848 code_->ShortPrint();
849 if (code_->kind() == Code::FUNCTION) PrintF(" NON-OPT");
850 if (code_->kind() == Code::OPTIMIZED_FUNCTION) PrintF(" OPT");
851 PrintF("\npc: %d\n", offset_);
852}
853
854
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000855JSFunction* OptimizedFrame::LiteralAt(FixedArray* literal_array,
856 int literal_id) {
857 if (literal_id == Translation::kSelfLiteralId) {
858 return JSFunction::cast(function());
859 }
860
861 return JSFunction::cast(literal_array->get(literal_id));
862}
863
864
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000865void OptimizedFrame::Summarize(List<FrameSummary>* frames) {
866 ASSERT(frames->length() == 0);
867 ASSERT(is_optimized());
868
ager@chromium.org378b34e2011-01-28 08:04:38 +0000869 int deopt_index = Safepoint::kNoDeoptimizationIndex;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000870 DeoptimizationInputData* data = GetDeoptimizationData(&deopt_index);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000871 FixedArray* literal_array = data->LiteralArray();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000872
873 // BUG(3243555): Since we don't have a lazy-deopt registered at
874 // throw-statements, we can't use the translation at the call-site of
875 // throw. An entry with no deoptimization index indicates a call-site
876 // without a lazy-deopt. As a consequence we are not allowed to inline
877 // functions containing throw.
878 if (deopt_index == Safepoint::kNoDeoptimizationIndex) {
879 JavaScriptFrame::Summarize(frames);
880 return;
881 }
882
883 TranslationIterator it(data->TranslationByteArray(),
884 data->TranslationIndex(deopt_index)->value());
885 Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next());
886 ASSERT(opcode == Translation::BEGIN);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000887 it.Next(); // Drop frame count.
888 int jsframe_count = it.Next();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000889
890 // We create the summary in reverse order because the frames
891 // in the deoptimization translation are ordered bottom-to-top.
ulan@chromium.org967e2702012-02-28 09:49:15 +0000892 bool is_constructor = IsConstructor();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000893 int i = jsframe_count;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000894 while (i > 0) {
895 opcode = static_cast<Translation::Opcode>(it.Next());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000896 if (opcode == Translation::JS_FRAME) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000897 i--;
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000898 BailoutId ast_id = BailoutId(it.Next());
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000899 JSFunction* function = LiteralAt(literal_array, it.Next());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000900 it.Next(); // Skip height.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000901
902 // The translation commands are ordered and the receiver is always
903 // at the first position. Since we are always at a call when we need
904 // to construct a stack trace, the receiver is always in a stack slot.
905 opcode = static_cast<Translation::Opcode>(it.Next());
danno@chromium.org40cb8782011-05-25 07:58:50 +0000906 ASSERT(opcode == Translation::STACK_SLOT ||
907 opcode == Translation::LITERAL);
908 int index = it.Next();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000909
910 // Get the correct receiver in the optimized frame.
911 Object* receiver = NULL;
danno@chromium.org40cb8782011-05-25 07:58:50 +0000912 if (opcode == Translation::LITERAL) {
913 receiver = data->LiteralArray()->get(index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000914 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000915 // Positive index means the value is spilled to the locals
916 // area. Negative means it is stored in the incoming parameter
917 // area.
918 if (index >= 0) {
919 receiver = GetExpression(index);
920 } else {
921 // Index -1 overlaps with last parameter, -n with the first parameter,
922 // (-n - 1) with the receiver with n being the number of parameters
923 // of the outermost, optimized frame.
924 int parameter_count = ComputeParametersCount();
925 int parameter_index = index + parameter_count;
926 receiver = (parameter_index == -1)
927 ? this->receiver()
928 : this->GetParameter(parameter_index);
929 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000930 }
931
932 Code* code = function->shared()->code();
933 DeoptimizationOutputData* output_data =
934 DeoptimizationOutputData::cast(code->deoptimization_data());
935 unsigned entry = Deoptimizer::GetOutputInfo(output_data,
936 ast_id,
937 function->shared());
938 unsigned pc_offset =
939 FullCodeGenerator::PcField::decode(entry) + Code::kHeaderSize;
940 ASSERT(pc_offset > 0);
941
942 FrameSummary summary(receiver, function, code, pc_offset, is_constructor);
943 frames->Add(summary);
ulan@chromium.org967e2702012-02-28 09:49:15 +0000944 is_constructor = false;
945 } else if (opcode == Translation::CONSTRUCT_STUB_FRAME) {
946 // The next encountered JS_FRAME will be marked as a constructor call.
947 it.Skip(Translation::NumberOfOperandsFor(opcode));
948 ASSERT(!is_constructor);
949 is_constructor = true;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000950 } else {
951 // Skip over operands to advance to the next opcode.
952 it.Skip(Translation::NumberOfOperandsFor(opcode));
953 }
954 }
ulan@chromium.org967e2702012-02-28 09:49:15 +0000955 ASSERT(!is_constructor);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000956}
957
958
959DeoptimizationInputData* OptimizedFrame::GetDeoptimizationData(
960 int* deopt_index) {
961 ASSERT(is_optimized());
962
963 JSFunction* opt_function = JSFunction::cast(function());
964 Code* code = opt_function->code();
965
966 // The code object may have been replaced by lazy deoptimization. Fall
967 // back to a slow search in this case to find the original optimized
968 // code object.
969 if (!code->contains(pc())) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000970 code = isolate()->inner_pointer_to_code_cache()->
971 GcSafeFindCodeForInnerPointer(pc());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000972 }
973 ASSERT(code != NULL);
974 ASSERT(code->kind() == Code::OPTIMIZED_FUNCTION);
975
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000976 SafepointEntry safepoint_entry = code->GetSafepointEntry(pc());
977 *deopt_index = safepoint_entry.deoptimization_index();
ager@chromium.org378b34e2011-01-28 08:04:38 +0000978 ASSERT(*deopt_index != Safepoint::kNoDeoptimizationIndex);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000979
980 return DeoptimizationInputData::cast(code->deoptimization_data());
981}
982
983
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000984int OptimizedFrame::GetInlineCount() {
985 ASSERT(is_optimized());
986
987 int deopt_index = Safepoint::kNoDeoptimizationIndex;
988 DeoptimizationInputData* data = GetDeoptimizationData(&deopt_index);
989
990 TranslationIterator it(data->TranslationByteArray(),
991 data->TranslationIndex(deopt_index)->value());
992 Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next());
993 ASSERT(opcode == Translation::BEGIN);
994 USE(opcode);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000995 it.Next(); // Drop frame count.
996 int jsframe_count = it.Next();
997 return jsframe_count;
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000998}
999
1000
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001001void OptimizedFrame::GetFunctions(List<JSFunction*>* functions) {
1002 ASSERT(functions->length() == 0);
1003 ASSERT(is_optimized());
1004
ager@chromium.org378b34e2011-01-28 08:04:38 +00001005 int deopt_index = Safepoint::kNoDeoptimizationIndex;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001006 DeoptimizationInputData* data = GetDeoptimizationData(&deopt_index);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001007 FixedArray* literal_array = data->LiteralArray();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001008
1009 TranslationIterator it(data->TranslationByteArray(),
1010 data->TranslationIndex(deopt_index)->value());
1011 Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next());
1012 ASSERT(opcode == Translation::BEGIN);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001013 it.Next(); // Drop frame count.
1014 int jsframe_count = it.Next();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001015
1016 // We insert the frames in reverse order because the frames
1017 // in the deoptimization translation are ordered bottom-to-top.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001018 while (jsframe_count > 0) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001019 opcode = static_cast<Translation::Opcode>(it.Next());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001020 if (opcode == Translation::JS_FRAME) {
1021 jsframe_count--;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001022 it.Next(); // Skip ast id.
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001023 JSFunction* function = LiteralAt(literal_array, it.Next());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001024 it.Next(); // Skip height.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001025 functions->Add(function);
1026 } else {
1027 // Skip over operands to advance to the next opcode.
1028 it.Skip(Translation::NumberOfOperandsFor(opcode));
1029 }
1030 }
1031}
1032
1033
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001034int ArgumentsAdaptorFrame::GetNumberOfIncomingArguments() const {
1035 return Smi::cast(GetExpression(0))->value();
1036}
1037
1038
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001039Address ArgumentsAdaptorFrame::GetCallerStackPointer() const {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001040 return fp() + StandardFrameConstants::kCallerSPOffset;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001041}
1042
1043
1044Address InternalFrame::GetCallerStackPointer() const {
1045 // Internal frames have no arguments. The stack pointer of the
1046 // caller is at a fixed offset from the frame pointer.
1047 return fp() + StandardFrameConstants::kCallerSPOffset;
1048}
1049
1050
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001051Code* ArgumentsAdaptorFrame::unchecked_code() const {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00001052 return isolate()->builtins()->builtin(
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001053 Builtins::kArgumentsAdaptorTrampoline);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001054}
1055
1056
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001057Code* InternalFrame::unchecked_code() const {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001058 const int offset = InternalFrameConstants::kCodeOffset;
1059 Object* code = Memory::Object_at(fp() + offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001060 ASSERT(code != NULL);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001061 return reinterpret_cast<Code*>(code);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001062}
1063
1064
1065void StackFrame::PrintIndex(StringStream* accumulator,
1066 PrintMode mode,
1067 int index) {
1068 accumulator->Add((mode == OVERVIEW) ? "%5d: " : "[%d]: ", index);
1069}
1070
1071
1072void JavaScriptFrame::Print(StringStream* accumulator,
1073 PrintMode mode,
1074 int index) const {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001075 HandleScope scope(isolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001076 Object* receiver = this->receiver();
1077 Object* function = this->function();
1078
1079 accumulator->PrintSecurityTokenIfChanged(function);
1080 PrintIndex(accumulator, mode, index);
1081 Code* code = NULL;
1082 if (IsConstructor()) accumulator->Add("new ");
1083 accumulator->PrintFunction(function, receiver, &code);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00001084
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001085 // Get scope information for nicer output, if possible. If code is NULL, or
1086 // doesn't contain scope info, scope_info will return 0 for the number of
1087 // parameters, stack local variables, context local variables, stack slots,
1088 // or context slots.
1089 Handle<ScopeInfo> scope_info(ScopeInfo::Empty());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001090
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00001091 if (function->IsJSFunction()) {
1092 Handle<SharedFunctionInfo> shared(JSFunction::cast(function)->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001093 scope_info = Handle<ScopeInfo>(shared->scope_info());
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00001094 Object* script_obj = shared->script();
1095 if (script_obj->IsScript()) {
1096 Handle<Script> script(Script::cast(script_obj));
1097 accumulator->Add(" [");
1098 accumulator->PrintName(script->name());
1099
1100 Address pc = this->pc();
1101 if (code != NULL && code->kind() == Code::FUNCTION &&
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00001102 pc >= code->instruction_start() && pc < code->instruction_end()) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00001103 int source_pos = code->SourcePosition(pc);
1104 int line = GetScriptLineNumberSafe(script, source_pos) + 1;
1105 accumulator->Add(":%d", line);
1106 } else {
1107 int function_start_pos = shared->start_position();
1108 int line = GetScriptLineNumberSafe(script, function_start_pos) + 1;
1109 accumulator->Add(":~%d", line);
1110 }
1111
1112 accumulator->Add("] ");
1113 }
1114 }
1115
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001116 accumulator->Add("(this=%o", receiver);
1117
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001118 // Print the parameters.
1119 int parameters_count = ComputeParametersCount();
1120 for (int i = 0; i < parameters_count; i++) {
1121 accumulator->Add(",");
1122 // If we have a name for the parameter we print it. Nameless
1123 // parameters are either because we have more actual parameters
1124 // than formal parameters or because we have no scope information.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001125 if (i < scope_info->ParameterCount()) {
1126 accumulator->PrintName(scope_info->ParameterName(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001127 accumulator->Add("=");
1128 }
1129 accumulator->Add("%o", GetParameter(i));
1130 }
1131
1132 accumulator->Add(")");
1133 if (mode == OVERVIEW) {
1134 accumulator->Add("\n");
1135 return;
1136 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00001137 if (is_optimized()) {
1138 accumulator->Add(" {\n// optimized frame\n}\n");
1139 return;
1140 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001141 accumulator->Add(" {\n");
1142
1143 // Compute the number of locals and expression stack elements.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001144 int stack_locals_count = scope_info->StackLocalCount();
1145 int heap_locals_count = scope_info->ContextLocalCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001146 int expressions_count = ComputeExpressionsCount();
1147
1148 // Print stack-allocated local variables.
1149 if (stack_locals_count > 0) {
1150 accumulator->Add(" // stack-allocated locals\n");
1151 }
1152 for (int i = 0; i < stack_locals_count; i++) {
1153 accumulator->Add(" var ");
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001154 accumulator->PrintName(scope_info->StackLocalName(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001155 accumulator->Add(" = ");
1156 if (i < expressions_count) {
1157 accumulator->Add("%o", GetExpression(i));
1158 } else {
1159 accumulator->Add("// no expression found - inconsistent frame?");
1160 }
1161 accumulator->Add("\n");
1162 }
1163
1164 // Try to get hold of the context of this frame.
1165 Context* context = NULL;
1166 if (this->context() != NULL && this->context()->IsContext()) {
1167 context = Context::cast(this->context());
1168 }
1169
1170 // Print heap-allocated local variables.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001171 if (heap_locals_count > 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001172 accumulator->Add(" // heap-allocated locals\n");
1173 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001174 for (int i = 0; i < heap_locals_count; i++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001175 accumulator->Add(" var ");
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001176 accumulator->PrintName(scope_info->ContextLocalName(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001177 accumulator->Add(" = ");
1178 if (context != NULL) {
1179 if (i < context->length()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001180 accumulator->Add("%o", context->get(Context::MIN_CONTEXT_SLOTS + i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001181 } else {
1182 accumulator->Add(
1183 "// warning: missing context slot - inconsistent frame?");
1184 }
1185 } else {
1186 accumulator->Add("// warning: no context found - inconsistent frame?");
1187 }
1188 accumulator->Add("\n");
1189 }
1190
1191 // Print the expression stack.
kasper.lund7276f142008-07-30 08:49:36 +00001192 int expressions_start = stack_locals_count;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001193 if (expressions_start < expressions_count) {
1194 accumulator->Add(" // expression stack (top to bottom)\n");
1195 }
1196 for (int i = expressions_count - 1; i >= expressions_start; i--) {
1197 if (IsExpressionInsideHandler(i)) continue;
1198 accumulator->Add(" [%02d] : %o\n", i, GetExpression(i));
1199 }
1200
1201 // Print details about the function.
1202 if (FLAG_max_stack_trace_source_length != 0 && code != NULL) {
1203 SharedFunctionInfo* shared = JSFunction::cast(function)->shared();
1204 accumulator->Add("--------- s o u r c e c o d e ---------\n");
1205 shared->SourceCodePrint(accumulator, FLAG_max_stack_trace_source_length);
1206 accumulator->Add("\n-----------------------------------------\n");
1207 }
1208
1209 accumulator->Add("}\n\n");
1210}
1211
1212
1213void ArgumentsAdaptorFrame::Print(StringStream* accumulator,
1214 PrintMode mode,
1215 int index) const {
1216 int actual = ComputeParametersCount();
1217 int expected = -1;
1218 Object* function = this->function();
1219 if (function->IsJSFunction()) {
1220 expected = JSFunction::cast(function)->shared()->formal_parameter_count();
1221 }
1222
1223 PrintIndex(accumulator, mode, index);
1224 accumulator->Add("arguments adaptor frame: %d->%d", actual, expected);
1225 if (mode == OVERVIEW) {
1226 accumulator->Add("\n");
1227 return;
1228 }
1229 accumulator->Add(" {\n");
1230
1231 // Print actual arguments.
1232 if (actual > 0) accumulator->Add(" // actual arguments\n");
1233 for (int i = 0; i < actual; i++) {
1234 accumulator->Add(" [%02d] : %o", i, GetParameter(i));
1235 if (expected != -1 && i >= expected) {
1236 accumulator->Add(" // not passed to callee");
1237 }
1238 accumulator->Add("\n");
1239 }
1240
1241 accumulator->Add("}\n\n");
1242}
1243
1244
1245void EntryFrame::Iterate(ObjectVisitor* v) const {
1246 StackHandlerIterator it(this, top_handler());
1247 ASSERT(!it.done());
1248 StackHandler* handler = it.handler();
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001249 ASSERT(handler->is_js_entry());
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00001250 handler->Iterate(v, LookupCode());
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001251#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001252 // Make sure that the entry frame does not contain more than one
1253 // stack handler.
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001254 it.Advance();
1255 ASSERT(it.done());
1256#endif
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00001257 IteratePc(v, pc_address(), LookupCode());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001258}
1259
1260
1261void StandardFrame::IterateExpressions(ObjectVisitor* v) const {
1262 const int offset = StandardFrameConstants::kContextOffset;
1263 Object** base = &Memory::Object_at(sp());
1264 Object** limit = &Memory::Object_at(fp() + offset) + 1;
1265 for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) {
1266 StackHandler* handler = it.handler();
1267 // Traverse pointers down to - but not including - the next
1268 // handler in the handler chain. Update the base to skip the
1269 // handler and allow the handler to traverse its own pointers.
1270 const Address address = handler->address();
1271 v->VisitPointers(base, reinterpret_cast<Object**>(address));
1272 base = reinterpret_cast<Object**>(address + StackHandlerConstants::kSize);
1273 // Traverse the pointers in the handler itself.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00001274 handler->Iterate(v, LookupCode());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001275 }
1276 v->VisitPointers(base, limit);
1277}
1278
1279
1280void JavaScriptFrame::Iterate(ObjectVisitor* v) const {
1281 IterateExpressions(v);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00001282 IteratePc(v, pc_address(), LookupCode());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001283}
1284
1285
1286void InternalFrame::Iterate(ObjectVisitor* v) const {
1287 // Internal frames only have object pointers on the expression stack
1288 // as they never have any arguments.
1289 IterateExpressions(v);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00001290 IteratePc(v, pc_address(), LookupCode());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001291}
1292
1293
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00001294void StubFailureTrampolineFrame::Iterate(ObjectVisitor* v) const {
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00001295 Object** base = &Memory::Object_at(sp());
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00001296 Object** limit = &Memory::Object_at(fp() +
1297 kFirstRegisterParameterFrameOffset);
1298 v->VisitPointers(base, limit);
1299 base = &Memory::Object_at(fp() + StandardFrameConstants::kMarkerOffset);
1300 const int offset = StandardFrameConstants::kContextOffset;
1301 limit = &Memory::Object_at(fp() + offset) + 1;
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00001302 v->VisitPointers(base, limit);
1303 IteratePc(v, pc_address(), LookupCode());
1304}
1305
1306
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00001307Address StubFailureTrampolineFrame::GetCallerStackPointer() const {
1308 return fp() + StandardFrameConstants::kCallerSPOffset;
1309}
1310
1311
1312Code* StubFailureTrampolineFrame::unchecked_code() const {
1313 int i = 0;
1314 for (; i <= StubFailureTrampolineStub::kMaxExtraExpressionStackCount; ++i) {
1315 Code* trampoline;
1316 StubFailureTrampolineStub(i).FindCodeInCache(&trampoline, isolate());
1317 ASSERT(trampoline != NULL);
1318 Address current_pc = pc();
1319 Address code_start = trampoline->instruction_start();
1320 Address code_end = code_start + trampoline->instruction_size();
1321 if (code_start <= current_pc && current_pc < code_end) {
1322 return trampoline;
1323 }
1324 }
1325 UNREACHABLE();
1326 return NULL;
1327}
1328
1329
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001330// -------------------------------------------------------------------------
1331
1332
1333JavaScriptFrame* StackFrameLocator::FindJavaScriptFrame(int n) {
1334 ASSERT(n >= 0);
1335 for (int i = 0; i <= n; i++) {
1336 while (!iterator_.frame()->is_java_script()) iterator_.Advance();
1337 if (i == n) return JavaScriptFrame::cast(iterator_.frame());
1338 iterator_.Advance();
1339 }
1340 UNREACHABLE();
1341 return NULL;
1342}
1343
1344
1345// -------------------------------------------------------------------------
1346
1347
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001348static Map* GcSafeMapOfCodeSpaceObject(HeapObject* object) {
1349 MapWord map_word = object->map_word();
1350 return map_word.IsForwardingAddress() ?
1351 map_word.ToForwardingAddress()->map() : map_word.ToMap();
1352}
1353
1354
1355static int GcSafeSizeOfCodeSpaceObject(HeapObject* object) {
1356 return object->SizeFromMap(GcSafeMapOfCodeSpaceObject(object));
1357}
1358
1359
1360#ifdef DEBUG
1361static bool GcSafeCodeContains(HeapObject* code, Address addr) {
1362 Map* map = GcSafeMapOfCodeSpaceObject(code);
1363 ASSERT(map == code->GetHeap()->code_map());
1364 Address start = code->address();
1365 Address end = code->address() + code->SizeFromMap(map);
1366 return start <= addr && addr < end;
1367}
1368#endif
1369
1370
1371Code* InnerPointerToCodeCache::GcSafeCastToCode(HeapObject* object,
1372 Address inner_pointer) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001373 Code* code = reinterpret_cast<Code*>(object);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001374 ASSERT(code != NULL && GcSafeCodeContains(code, inner_pointer));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001375 return code;
1376}
1377
1378
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001379Code* InnerPointerToCodeCache::GcSafeFindCodeForInnerPointer(
1380 Address inner_pointer) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001381 Heap* heap = isolate_->heap();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001382 // Check if the inner pointer points into a large object chunk.
jkummerow@chromium.org531dfe82012-03-20 13:01:16 +00001383 LargePage* large_page = heap->lo_space()->FindPage(inner_pointer);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001384 if (large_page != NULL) {
1385 return GcSafeCastToCode(large_page->GetObject(), inner_pointer);
1386 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001387
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001388 // Iterate through the page until we reach the end or find an object starting
1389 // after the inner pointer.
1390 Page* page = Page::FromAddress(inner_pointer);
1391
1392 Address addr = page->skip_list()->StartFor(inner_pointer);
1393
1394 Address top = heap->code_space()->top();
1395 Address limit = heap->code_space()->limit();
1396
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001397 while (true) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001398 if (addr == top && addr != limit) {
1399 addr = limit;
1400 continue;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001401 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001402
1403 HeapObject* obj = HeapObject::FromAddress(addr);
1404 int obj_size = GcSafeSizeOfCodeSpaceObject(obj);
1405 Address next_addr = addr + obj_size;
1406 if (next_addr > inner_pointer) return GcSafeCastToCode(obj, inner_pointer);
1407 addr = next_addr;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001408 }
1409}
1410
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001411
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001412InnerPointerToCodeCache::InnerPointerToCodeCacheEntry*
1413 InnerPointerToCodeCache::GetCacheEntry(Address inner_pointer) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001414 isolate_->counters()->pc_to_code()->Increment();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001415 ASSERT(IsPowerOf2(kInnerPointerToCodeCacheSize));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001416 uint32_t hash = ComputeIntegerHash(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001417 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(inner_pointer)),
1418 v8::internal::kZeroHashSeed);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001419 uint32_t index = hash & (kInnerPointerToCodeCacheSize - 1);
1420 InnerPointerToCodeCacheEntry* entry = cache(index);
1421 if (entry->inner_pointer == inner_pointer) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001422 isolate_->counters()->pc_to_code_cached()->Increment();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001423 ASSERT(entry->code == GcSafeFindCodeForInnerPointer(inner_pointer));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001424 } else {
1425 // Because this code may be interrupted by a profiling signal that
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001426 // also queries the cache, we cannot update inner_pointer before the code
1427 // has been set. Otherwise, we risk trying to use a cache entry before
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001428 // the code has been computed.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001429 entry->code = GcSafeFindCodeForInnerPointer(inner_pointer);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001430 entry->safepoint_entry.Reset();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001431 entry->inner_pointer = inner_pointer;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001432 }
1433 return entry;
1434}
1435
1436
1437// -------------------------------------------------------------------------
1438
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001439int NumRegs(RegList reglist) {
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +00001440 return CompilerIntrinsics::CountSetBits(reglist);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001441}
1442
1443
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001444struct JSCallerSavedCodeData {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001445 int reg_code[kNumJSCallerSaved];
1446};
1447
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001448JSCallerSavedCodeData caller_saved_code_data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001449
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001450void SetUpJSCallerSavedCodeData() {
1451 int i = 0;
1452 for (int r = 0; r < kNumRegs; r++)
1453 if ((kJSCallerSaved & (1 << r)) != 0)
1454 caller_saved_code_data.reg_code[i++] = r;
1455
1456 ASSERT(i == kNumJSCallerSaved);
1457}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001458
1459int JSCallerSavedCode(int n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001460 ASSERT(0 <= n && n < kNumJSCallerSaved);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001461 return caller_saved_code_data.reg_code[n];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001462}
1463
1464
ager@chromium.org357bf652010-04-12 11:30:10 +00001465#define DEFINE_WRAPPER(type, field) \
1466class field##_Wrapper : public ZoneObject { \
1467 public: /* NOLINT */ \
1468 field##_Wrapper(const field& original) : frame_(original) { \
1469 } \
1470 field frame_; \
1471};
1472STACK_FRAME_TYPE_LIST(DEFINE_WRAPPER)
1473#undef DEFINE_WRAPPER
1474
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001475static StackFrame* AllocateFrameCopy(StackFrame* frame, Zone* zone) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001476#define FRAME_TYPE_CASE(type, field) \
1477 case StackFrame::type: { \
1478 field##_Wrapper* wrapper = \
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001479 new(zone) field##_Wrapper(*(reinterpret_cast<field*>(frame))); \
ager@chromium.org357bf652010-04-12 11:30:10 +00001480 return &wrapper->frame_; \
1481 }
1482
1483 switch (frame->type()) {
1484 STACK_FRAME_TYPE_LIST(FRAME_TYPE_CASE)
1485 default: UNREACHABLE();
1486 }
1487#undef FRAME_TYPE_CASE
1488 return NULL;
1489}
1490
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001491Vector<StackFrame*> CreateStackMap(Isolate* isolate, Zone* zone) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001492 ZoneList<StackFrame*> list(10, zone);
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001493 for (StackFrameIterator it(isolate); !it.done(); it.Advance()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001494 StackFrame* frame = AllocateFrameCopy(it.frame(), zone);
1495 list.Add(frame, zone);
ager@chromium.org357bf652010-04-12 11:30:10 +00001496 }
1497 return list.ToVector();
1498}
1499
1500
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001501} } // namespace v8::internal