blob: 152cd30d5b125789da857ca98abb3dd7d914d087 [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 }
danno@chromium.orgd43f6452013-04-30 16:42:35 +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);
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +0000669
670 // Visit the context in stub frame and JavaScript frame.
671 // Visit the function in JavaScript frame.
672 Object** fixed_base = &Memory::Object_at(
673 fp() + StandardFrameConstants::kMarkerOffset);
674 Object** fixed_limit = &Memory::Object_at(fp());
675 v->VisitPointers(fixed_base, fixed_limit);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000676}
677
678
679void StubFrame::Iterate(ObjectVisitor* v) const {
680 IterateCompiledFrame(v);
681}
682
683
684Code* StubFrame::unchecked_code() const {
685 return static_cast<Code*>(isolate()->heap()->FindCodeObject(pc()));
686}
687
688
689Address StubFrame::GetCallerStackPointer() const {
690 return fp() + ExitFrameConstants::kCallerSPDisplacement;
691}
692
693
694int StubFrame::GetNumberOfIncomingArguments() const {
695 return 0;
696}
697
698
699void OptimizedFrame::Iterate(ObjectVisitor* v) const {
700#ifdef DEBUG
701 // Make sure that optimized frames do not contain any stack handlers.
702 StackHandlerIterator it(this, top_handler());
703 ASSERT(it.done());
704#endif
705
706 IterateCompiledFrame(v);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000707}
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +0000708
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000709
710void JavaScriptFrame::SetParameterValue(int index, Object* value) const {
711 Memory::Object_at(GetParameterSlot(index)) = value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000712}
713
714
715bool JavaScriptFrame::IsConstructor() const {
ager@chromium.org7c537e22008-10-16 08:43:32 +0000716 Address fp = caller_fp();
717 if (has_adapted_arguments()) {
718 // Skip the arguments adaptor frame and look at the real caller.
719 fp = Memory::Address_at(fp + StandardFrameConstants::kCallerFPOffset);
720 }
721 return IsConstructFrame(fp);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000722}
723
724
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000725int JavaScriptFrame::GetArgumentsLength() const {
726 // If there is an arguments adaptor frame get the arguments length from it.
727 if (has_adapted_arguments()) {
728 return Smi::cast(GetExpression(caller_fp(), 0))->value();
729 } else {
730 return GetNumberOfIncomingArguments();
731 }
732}
733
734
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000735Code* JavaScriptFrame::unchecked_code() const {
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000736 JSFunction* function = JSFunction::cast(this->function());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000737 return function->unchecked_code();
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000738}
739
740
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000741int JavaScriptFrame::GetNumberOfIncomingArguments() const {
742 ASSERT(!SafeStackFrameIterator::is_active(isolate()) &&
743 isolate()->heap()->gc_state() == Heap::NOT_IN_GC);
744
745 JSFunction* function = JSFunction::cast(this->function());
746 return function->shared()->formal_parameter_count();
747}
748
749
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000750Address JavaScriptFrame::GetCallerStackPointer() const {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000751 return fp() + StandardFrameConstants::kCallerSPOffset;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000752}
753
754
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000755void JavaScriptFrame::GetFunctions(List<JSFunction*>* functions) {
756 ASSERT(functions->length() == 0);
757 functions->Add(JSFunction::cast(function()));
758}
759
760
761void JavaScriptFrame::Summarize(List<FrameSummary>* functions) {
762 ASSERT(functions->length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000763 Code* code_pointer = LookupCode();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000764 int offset = static_cast<int>(pc() - code_pointer->address());
765 FrameSummary summary(receiver(),
766 JSFunction::cast(function()),
767 code_pointer,
768 offset,
769 IsConstructor());
770 functions->Add(summary);
771}
772
773
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000774void JavaScriptFrame::PrintTop(Isolate* isolate,
775 FILE* file,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000776 bool print_args,
777 bool print_line_number) {
778 // constructor calls
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000779 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000780 AssertNoAllocation no_allocation;
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000781 JavaScriptFrameIterator it(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000782 while (!it.done()) {
783 if (it.frame()->is_java_script()) {
784 JavaScriptFrame* frame = it.frame();
785 if (frame->IsConstructor()) PrintF(file, "new ");
786 // function name
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000787 Object* maybe_fun = frame->function();
788 if (maybe_fun->IsJSFunction()) {
789 JSFunction* fun = JSFunction::cast(maybe_fun);
790 fun->PrintName();
791 Code* js_code = frame->unchecked_code();
792 Address pc = frame->pc();
793 int code_offset =
794 static_cast<int>(pc - js_code->instruction_start());
795 PrintF("+%d", code_offset);
796 SharedFunctionInfo* shared = fun->shared();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000797 if (print_line_number) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000798 Code* code = Code::cast(
799 v8::internal::Isolate::Current()->heap()->FindCodeObject(pc));
800 int source_pos = code->SourcePosition(pc);
801 Object* maybe_script = shared->script();
802 if (maybe_script->IsScript()) {
803 Handle<Script> script(Script::cast(maybe_script));
804 int line = GetScriptLineNumberSafe(script, source_pos) + 1;
805 Object* script_name_raw = script->name();
806 if (script_name_raw->IsString()) {
807 String* script_name = String::cast(script->name());
808 SmartArrayPointer<char> c_script_name =
809 script_name->ToCString(DISALLOW_NULLS,
810 ROBUST_STRING_TRAVERSAL);
811 PrintF(file, " at %s:%d", *c_script_name, line);
812 } else {
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000813 PrintF(file, " at <unknown>:%d", line);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000814 }
815 } else {
816 PrintF(file, " at <unknown>:<unknown>");
817 }
818 }
819 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000820 PrintF("<unknown>");
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000821 }
822
823 if (print_args) {
824 // function arguments
825 // (we are intentionally only printing the actually
826 // supplied parameters, not all parameters required)
827 PrintF(file, "(this=");
828 frame->receiver()->ShortPrint(file);
829 const int length = frame->ComputeParametersCount();
830 for (int i = 0; i < length; i++) {
831 PrintF(file, ", ");
832 frame->GetParameter(i)->ShortPrint(file);
833 }
834 PrintF(file, ")");
835 }
836 break;
837 }
838 it.Advance();
839 }
840}
841
842
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000843void JavaScriptFrame::SaveOperandStack(FixedArray* store,
844 int* stack_handler_index) const {
845 int operands_count = store->length();
846 ASSERT_LE(operands_count, ComputeOperandsCount());
847
848 // Visit the stack in LIFO order, saving operands and stack handlers into the
849 // array. The saved stack handlers store a link to the next stack handler,
850 // which will allow RestoreOperandStack to rewind the handlers.
851 StackHandlerIterator it(this, top_handler());
852 int i = operands_count - 1;
853 *stack_handler_index = -1;
854 for (; !it.done(); it.Advance()) {
855 StackHandler* handler = it.handler();
856 // Save operands pushed after the handler was pushed.
857 for (; GetOperandSlot(i) < handler->address(); i--) {
858 store->set(i, GetOperand(i));
859 }
860 ASSERT_GE(i + 1, StackHandlerConstants::kSlotCount);
861 ASSERT_EQ(handler->address(), GetOperandSlot(i));
862 int next_stack_handler_index = i + 1 - StackHandlerConstants::kSlotCount;
863 handler->Unwind(isolate(), store, next_stack_handler_index,
864 *stack_handler_index);
865 *stack_handler_index = next_stack_handler_index;
866 i -= StackHandlerConstants::kSlotCount;
867 }
868
869 // Save any remaining operands.
870 for (; i >= 0; i--) {
871 store->set(i, GetOperand(i));
872 }
873}
874
875
876void JavaScriptFrame::RestoreOperandStack(FixedArray* store,
877 int stack_handler_index) {
878 int operands_count = store->length();
879 ASSERT_LE(operands_count, ComputeOperandsCount());
880 int i = 0;
881 while (i <= stack_handler_index) {
882 if (i < stack_handler_index) {
883 // An operand.
884 ASSERT_EQ(GetOperand(i), isolate()->heap()->the_hole_value());
885 Memory::Object_at(GetOperandSlot(i)) = store->get(i);
886 i++;
887 } else {
888 // A stack handler.
889 ASSERT_EQ(i, stack_handler_index);
890 // The FixedArray store grows up. The stack grows down. So the operand
891 // slot for i actually points to the bottom of the top word in the
892 // handler. The base of the StackHandler* is the address of the bottom
893 // word, which will be the last slot that is in the handler.
894 int handler_slot_index = i + StackHandlerConstants::kSlotCount - 1;
895 StackHandler *handler =
896 StackHandler::FromAddress(GetOperandSlot(handler_slot_index));
897 stack_handler_index = handler->Rewind(isolate(), store, i, fp());
898 i += StackHandlerConstants::kSlotCount;
899 }
900 }
901
902 for (; i < operands_count; i++) {
903 ASSERT_EQ(GetOperand(i), isolate()->heap()->the_hole_value());
904 Memory::Object_at(GetOperandSlot(i)) = store->get(i);
905 }
906}
907
908
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000909void FrameSummary::Print() {
910 PrintF("receiver: ");
911 receiver_->ShortPrint();
912 PrintF("\nfunction: ");
913 function_->shared()->DebugName()->ShortPrint();
914 PrintF("\ncode: ");
915 code_->ShortPrint();
916 if (code_->kind() == Code::FUNCTION) PrintF(" NON-OPT");
917 if (code_->kind() == Code::OPTIMIZED_FUNCTION) PrintF(" OPT");
918 PrintF("\npc: %d\n", offset_);
919}
920
921
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000922JSFunction* OptimizedFrame::LiteralAt(FixedArray* literal_array,
923 int literal_id) {
924 if (literal_id == Translation::kSelfLiteralId) {
925 return JSFunction::cast(function());
926 }
927
928 return JSFunction::cast(literal_array->get(literal_id));
929}
930
931
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000932void OptimizedFrame::Summarize(List<FrameSummary>* frames) {
933 ASSERT(frames->length() == 0);
934 ASSERT(is_optimized());
935
ager@chromium.org378b34e2011-01-28 08:04:38 +0000936 int deopt_index = Safepoint::kNoDeoptimizationIndex;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000937 DeoptimizationInputData* data = GetDeoptimizationData(&deopt_index);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000938 FixedArray* literal_array = data->LiteralArray();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000939
940 // BUG(3243555): Since we don't have a lazy-deopt registered at
941 // throw-statements, we can't use the translation at the call-site of
942 // throw. An entry with no deoptimization index indicates a call-site
943 // without a lazy-deopt. As a consequence we are not allowed to inline
944 // functions containing throw.
945 if (deopt_index == Safepoint::kNoDeoptimizationIndex) {
946 JavaScriptFrame::Summarize(frames);
947 return;
948 }
949
950 TranslationIterator it(data->TranslationByteArray(),
951 data->TranslationIndex(deopt_index)->value());
952 Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next());
953 ASSERT(opcode == Translation::BEGIN);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000954 it.Next(); // Drop frame count.
955 int jsframe_count = it.Next();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000956
957 // We create the summary in reverse order because the frames
958 // in the deoptimization translation are ordered bottom-to-top.
ulan@chromium.org967e2702012-02-28 09:49:15 +0000959 bool is_constructor = IsConstructor();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000960 int i = jsframe_count;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000961 while (i > 0) {
962 opcode = static_cast<Translation::Opcode>(it.Next());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000963 if (opcode == Translation::JS_FRAME) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000964 i--;
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000965 BailoutId ast_id = BailoutId(it.Next());
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000966 JSFunction* function = LiteralAt(literal_array, it.Next());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000967 it.Next(); // Skip height.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000968
969 // The translation commands are ordered and the receiver is always
970 // at the first position. Since we are always at a call when we need
971 // to construct a stack trace, the receiver is always in a stack slot.
972 opcode = static_cast<Translation::Opcode>(it.Next());
danno@chromium.org40cb8782011-05-25 07:58:50 +0000973 ASSERT(opcode == Translation::STACK_SLOT ||
974 opcode == Translation::LITERAL);
975 int index = it.Next();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000976
977 // Get the correct receiver in the optimized frame.
978 Object* receiver = NULL;
danno@chromium.org40cb8782011-05-25 07:58:50 +0000979 if (opcode == Translation::LITERAL) {
980 receiver = data->LiteralArray()->get(index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000981 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000982 // Positive index means the value is spilled to the locals
983 // area. Negative means it is stored in the incoming parameter
984 // area.
985 if (index >= 0) {
986 receiver = GetExpression(index);
987 } else {
988 // Index -1 overlaps with last parameter, -n with the first parameter,
989 // (-n - 1) with the receiver with n being the number of parameters
990 // of the outermost, optimized frame.
991 int parameter_count = ComputeParametersCount();
992 int parameter_index = index + parameter_count;
993 receiver = (parameter_index == -1)
994 ? this->receiver()
995 : this->GetParameter(parameter_index);
996 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000997 }
998
999 Code* code = function->shared()->code();
1000 DeoptimizationOutputData* output_data =
1001 DeoptimizationOutputData::cast(code->deoptimization_data());
1002 unsigned entry = Deoptimizer::GetOutputInfo(output_data,
1003 ast_id,
1004 function->shared());
1005 unsigned pc_offset =
1006 FullCodeGenerator::PcField::decode(entry) + Code::kHeaderSize;
1007 ASSERT(pc_offset > 0);
1008
1009 FrameSummary summary(receiver, function, code, pc_offset, is_constructor);
1010 frames->Add(summary);
ulan@chromium.org967e2702012-02-28 09:49:15 +00001011 is_constructor = false;
1012 } else if (opcode == Translation::CONSTRUCT_STUB_FRAME) {
1013 // The next encountered JS_FRAME will be marked as a constructor call.
1014 it.Skip(Translation::NumberOfOperandsFor(opcode));
1015 ASSERT(!is_constructor);
1016 is_constructor = true;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001017 } else {
1018 // Skip over operands to advance to the next opcode.
1019 it.Skip(Translation::NumberOfOperandsFor(opcode));
1020 }
1021 }
ulan@chromium.org967e2702012-02-28 09:49:15 +00001022 ASSERT(!is_constructor);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001023}
1024
1025
1026DeoptimizationInputData* OptimizedFrame::GetDeoptimizationData(
1027 int* deopt_index) {
1028 ASSERT(is_optimized());
1029
1030 JSFunction* opt_function = JSFunction::cast(function());
1031 Code* code = opt_function->code();
1032
1033 // The code object may have been replaced by lazy deoptimization. Fall
1034 // back to a slow search in this case to find the original optimized
1035 // code object.
1036 if (!code->contains(pc())) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001037 code = isolate()->inner_pointer_to_code_cache()->
1038 GcSafeFindCodeForInnerPointer(pc());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001039 }
1040 ASSERT(code != NULL);
1041 ASSERT(code->kind() == Code::OPTIMIZED_FUNCTION);
1042
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001043 SafepointEntry safepoint_entry = code->GetSafepointEntry(pc());
1044 *deopt_index = safepoint_entry.deoptimization_index();
ager@chromium.org378b34e2011-01-28 08:04:38 +00001045 ASSERT(*deopt_index != Safepoint::kNoDeoptimizationIndex);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001046
1047 return DeoptimizationInputData::cast(code->deoptimization_data());
1048}
1049
1050
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001051int OptimizedFrame::GetInlineCount() {
1052 ASSERT(is_optimized());
1053
1054 int deopt_index = Safepoint::kNoDeoptimizationIndex;
1055 DeoptimizationInputData* data = GetDeoptimizationData(&deopt_index);
1056
1057 TranslationIterator it(data->TranslationByteArray(),
1058 data->TranslationIndex(deopt_index)->value());
1059 Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next());
1060 ASSERT(opcode == Translation::BEGIN);
1061 USE(opcode);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001062 it.Next(); // Drop frame count.
1063 int jsframe_count = it.Next();
1064 return jsframe_count;
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001065}
1066
1067
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001068void OptimizedFrame::GetFunctions(List<JSFunction*>* functions) {
1069 ASSERT(functions->length() == 0);
1070 ASSERT(is_optimized());
1071
ager@chromium.org378b34e2011-01-28 08:04:38 +00001072 int deopt_index = Safepoint::kNoDeoptimizationIndex;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001073 DeoptimizationInputData* data = GetDeoptimizationData(&deopt_index);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001074 FixedArray* literal_array = data->LiteralArray();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001075
1076 TranslationIterator it(data->TranslationByteArray(),
1077 data->TranslationIndex(deopt_index)->value());
1078 Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next());
1079 ASSERT(opcode == Translation::BEGIN);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001080 it.Next(); // Drop frame count.
1081 int jsframe_count = it.Next();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001082
1083 // We insert the frames in reverse order because the frames
1084 // in the deoptimization translation are ordered bottom-to-top.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001085 while (jsframe_count > 0) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001086 opcode = static_cast<Translation::Opcode>(it.Next());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001087 if (opcode == Translation::JS_FRAME) {
1088 jsframe_count--;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001089 it.Next(); // Skip ast id.
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001090 JSFunction* function = LiteralAt(literal_array, it.Next());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001091 it.Next(); // Skip height.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001092 functions->Add(function);
1093 } else {
1094 // Skip over operands to advance to the next opcode.
1095 it.Skip(Translation::NumberOfOperandsFor(opcode));
1096 }
1097 }
1098}
1099
1100
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001101int ArgumentsAdaptorFrame::GetNumberOfIncomingArguments() const {
1102 return Smi::cast(GetExpression(0))->value();
1103}
1104
1105
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001106Address ArgumentsAdaptorFrame::GetCallerStackPointer() const {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001107 return fp() + StandardFrameConstants::kCallerSPOffset;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001108}
1109
1110
1111Address InternalFrame::GetCallerStackPointer() const {
1112 // Internal frames have no arguments. The stack pointer of the
1113 // caller is at a fixed offset from the frame pointer.
1114 return fp() + StandardFrameConstants::kCallerSPOffset;
1115}
1116
1117
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001118Code* ArgumentsAdaptorFrame::unchecked_code() const {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00001119 return isolate()->builtins()->builtin(
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001120 Builtins::kArgumentsAdaptorTrampoline);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001121}
1122
1123
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001124Code* InternalFrame::unchecked_code() const {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001125 const int offset = InternalFrameConstants::kCodeOffset;
1126 Object* code = Memory::Object_at(fp() + offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001127 ASSERT(code != NULL);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001128 return reinterpret_cast<Code*>(code);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001129}
1130
1131
1132void StackFrame::PrintIndex(StringStream* accumulator,
1133 PrintMode mode,
1134 int index) {
1135 accumulator->Add((mode == OVERVIEW) ? "%5d: " : "[%d]: ", index);
1136}
1137
1138
1139void JavaScriptFrame::Print(StringStream* accumulator,
1140 PrintMode mode,
1141 int index) const {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001142 HandleScope scope(isolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001143 Object* receiver = this->receiver();
1144 Object* function = this->function();
1145
1146 accumulator->PrintSecurityTokenIfChanged(function);
1147 PrintIndex(accumulator, mode, index);
1148 Code* code = NULL;
1149 if (IsConstructor()) accumulator->Add("new ");
1150 accumulator->PrintFunction(function, receiver, &code);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00001151
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001152 // Get scope information for nicer output, if possible. If code is NULL, or
1153 // doesn't contain scope info, scope_info will return 0 for the number of
1154 // parameters, stack local variables, context local variables, stack slots,
1155 // or context slots.
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001156 Handle<ScopeInfo> scope_info(ScopeInfo::Empty(isolate()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001157
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00001158 if (function->IsJSFunction()) {
1159 Handle<SharedFunctionInfo> shared(JSFunction::cast(function)->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001160 scope_info = Handle<ScopeInfo>(shared->scope_info());
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00001161 Object* script_obj = shared->script();
1162 if (script_obj->IsScript()) {
1163 Handle<Script> script(Script::cast(script_obj));
1164 accumulator->Add(" [");
1165 accumulator->PrintName(script->name());
1166
1167 Address pc = this->pc();
1168 if (code != NULL && code->kind() == Code::FUNCTION &&
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00001169 pc >= code->instruction_start() && pc < code->instruction_end()) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00001170 int source_pos = code->SourcePosition(pc);
1171 int line = GetScriptLineNumberSafe(script, source_pos) + 1;
1172 accumulator->Add(":%d", line);
1173 } else {
1174 int function_start_pos = shared->start_position();
1175 int line = GetScriptLineNumberSafe(script, function_start_pos) + 1;
1176 accumulator->Add(":~%d", line);
1177 }
1178
1179 accumulator->Add("] ");
1180 }
1181 }
1182
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001183 accumulator->Add("(this=%o", receiver);
1184
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001185 // Print the parameters.
1186 int parameters_count = ComputeParametersCount();
1187 for (int i = 0; i < parameters_count; i++) {
1188 accumulator->Add(",");
1189 // If we have a name for the parameter we print it. Nameless
1190 // parameters are either because we have more actual parameters
1191 // than formal parameters or because we have no scope information.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001192 if (i < scope_info->ParameterCount()) {
1193 accumulator->PrintName(scope_info->ParameterName(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001194 accumulator->Add("=");
1195 }
1196 accumulator->Add("%o", GetParameter(i));
1197 }
1198
1199 accumulator->Add(")");
1200 if (mode == OVERVIEW) {
1201 accumulator->Add("\n");
1202 return;
1203 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00001204 if (is_optimized()) {
1205 accumulator->Add(" {\n// optimized frame\n}\n");
1206 return;
1207 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001208 accumulator->Add(" {\n");
1209
1210 // Compute the number of locals and expression stack elements.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001211 int stack_locals_count = scope_info->StackLocalCount();
1212 int heap_locals_count = scope_info->ContextLocalCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001213 int expressions_count = ComputeExpressionsCount();
1214
1215 // Print stack-allocated local variables.
1216 if (stack_locals_count > 0) {
1217 accumulator->Add(" // stack-allocated locals\n");
1218 }
1219 for (int i = 0; i < stack_locals_count; i++) {
1220 accumulator->Add(" var ");
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001221 accumulator->PrintName(scope_info->StackLocalName(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001222 accumulator->Add(" = ");
1223 if (i < expressions_count) {
1224 accumulator->Add("%o", GetExpression(i));
1225 } else {
1226 accumulator->Add("// no expression found - inconsistent frame?");
1227 }
1228 accumulator->Add("\n");
1229 }
1230
1231 // Try to get hold of the context of this frame.
1232 Context* context = NULL;
1233 if (this->context() != NULL && this->context()->IsContext()) {
1234 context = Context::cast(this->context());
1235 }
1236
1237 // Print heap-allocated local variables.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001238 if (heap_locals_count > 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001239 accumulator->Add(" // heap-allocated locals\n");
1240 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001241 for (int i = 0; i < heap_locals_count; i++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001242 accumulator->Add(" var ");
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001243 accumulator->PrintName(scope_info->ContextLocalName(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001244 accumulator->Add(" = ");
1245 if (context != NULL) {
1246 if (i < context->length()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001247 accumulator->Add("%o", context->get(Context::MIN_CONTEXT_SLOTS + i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001248 } else {
1249 accumulator->Add(
1250 "// warning: missing context slot - inconsistent frame?");
1251 }
1252 } else {
1253 accumulator->Add("// warning: no context found - inconsistent frame?");
1254 }
1255 accumulator->Add("\n");
1256 }
1257
1258 // Print the expression stack.
kasper.lund7276f142008-07-30 08:49:36 +00001259 int expressions_start = stack_locals_count;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001260 if (expressions_start < expressions_count) {
1261 accumulator->Add(" // expression stack (top to bottom)\n");
1262 }
1263 for (int i = expressions_count - 1; i >= expressions_start; i--) {
1264 if (IsExpressionInsideHandler(i)) continue;
1265 accumulator->Add(" [%02d] : %o\n", i, GetExpression(i));
1266 }
1267
1268 // Print details about the function.
1269 if (FLAG_max_stack_trace_source_length != 0 && code != NULL) {
1270 SharedFunctionInfo* shared = JSFunction::cast(function)->shared();
1271 accumulator->Add("--------- s o u r c e c o d e ---------\n");
1272 shared->SourceCodePrint(accumulator, FLAG_max_stack_trace_source_length);
1273 accumulator->Add("\n-----------------------------------------\n");
1274 }
1275
1276 accumulator->Add("}\n\n");
1277}
1278
1279
1280void ArgumentsAdaptorFrame::Print(StringStream* accumulator,
1281 PrintMode mode,
1282 int index) const {
1283 int actual = ComputeParametersCount();
1284 int expected = -1;
1285 Object* function = this->function();
1286 if (function->IsJSFunction()) {
1287 expected = JSFunction::cast(function)->shared()->formal_parameter_count();
1288 }
1289
1290 PrintIndex(accumulator, mode, index);
1291 accumulator->Add("arguments adaptor frame: %d->%d", actual, expected);
1292 if (mode == OVERVIEW) {
1293 accumulator->Add("\n");
1294 return;
1295 }
1296 accumulator->Add(" {\n");
1297
1298 // Print actual arguments.
1299 if (actual > 0) accumulator->Add(" // actual arguments\n");
1300 for (int i = 0; i < actual; i++) {
1301 accumulator->Add(" [%02d] : %o", i, GetParameter(i));
1302 if (expected != -1 && i >= expected) {
1303 accumulator->Add(" // not passed to callee");
1304 }
1305 accumulator->Add("\n");
1306 }
1307
1308 accumulator->Add("}\n\n");
1309}
1310
1311
1312void EntryFrame::Iterate(ObjectVisitor* v) const {
1313 StackHandlerIterator it(this, top_handler());
1314 ASSERT(!it.done());
1315 StackHandler* handler = it.handler();
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001316 ASSERT(handler->is_js_entry());
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00001317 handler->Iterate(v, LookupCode());
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001318#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001319 // Make sure that the entry frame does not contain more than one
1320 // stack handler.
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001321 it.Advance();
1322 ASSERT(it.done());
1323#endif
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00001324 IteratePc(v, pc_address(), LookupCode());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001325}
1326
1327
1328void StandardFrame::IterateExpressions(ObjectVisitor* v) const {
1329 const int offset = StandardFrameConstants::kContextOffset;
1330 Object** base = &Memory::Object_at(sp());
1331 Object** limit = &Memory::Object_at(fp() + offset) + 1;
1332 for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) {
1333 StackHandler* handler = it.handler();
1334 // Traverse pointers down to - but not including - the next
1335 // handler in the handler chain. Update the base to skip the
1336 // handler and allow the handler to traverse its own pointers.
1337 const Address address = handler->address();
1338 v->VisitPointers(base, reinterpret_cast<Object**>(address));
1339 base = reinterpret_cast<Object**>(address + StackHandlerConstants::kSize);
1340 // Traverse the pointers in the handler itself.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00001341 handler->Iterate(v, LookupCode());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001342 }
1343 v->VisitPointers(base, limit);
1344}
1345
1346
1347void JavaScriptFrame::Iterate(ObjectVisitor* v) const {
1348 IterateExpressions(v);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00001349 IteratePc(v, pc_address(), LookupCode());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001350}
1351
1352
1353void InternalFrame::Iterate(ObjectVisitor* v) const {
1354 // Internal frames only have object pointers on the expression stack
1355 // as they never have any arguments.
1356 IterateExpressions(v);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00001357 IteratePc(v, pc_address(), LookupCode());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001358}
1359
1360
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00001361void StubFailureTrampolineFrame::Iterate(ObjectVisitor* v) const {
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00001362 Object** base = &Memory::Object_at(sp());
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00001363 Object** limit = &Memory::Object_at(fp() +
1364 kFirstRegisterParameterFrameOffset);
1365 v->VisitPointers(base, limit);
1366 base = &Memory::Object_at(fp() + StandardFrameConstants::kMarkerOffset);
1367 const int offset = StandardFrameConstants::kContextOffset;
1368 limit = &Memory::Object_at(fp() + offset) + 1;
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00001369 v->VisitPointers(base, limit);
1370 IteratePc(v, pc_address(), LookupCode());
1371}
1372
1373
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00001374Address StubFailureTrampolineFrame::GetCallerStackPointer() const {
1375 return fp() + StandardFrameConstants::kCallerSPOffset;
1376}
1377
1378
1379Code* StubFailureTrampolineFrame::unchecked_code() const {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001380 Code* trampoline;
1381 StubFailureTrampolineStub(NOT_JS_FUNCTION_STUB_MODE).
1382 FindCodeInCache(&trampoline, isolate());
1383 if (trampoline->contains(pc())) {
1384 return trampoline;
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00001385 }
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001386
1387 StubFailureTrampolineStub(JS_FUNCTION_STUB_MODE).
1388 FindCodeInCache(&trampoline, isolate());
1389 if (trampoline->contains(pc())) {
1390 return trampoline;
1391 }
1392
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00001393 UNREACHABLE();
1394 return NULL;
1395}
1396
1397
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001398// -------------------------------------------------------------------------
1399
1400
1401JavaScriptFrame* StackFrameLocator::FindJavaScriptFrame(int n) {
1402 ASSERT(n >= 0);
1403 for (int i = 0; i <= n; i++) {
1404 while (!iterator_.frame()->is_java_script()) iterator_.Advance();
1405 if (i == n) return JavaScriptFrame::cast(iterator_.frame());
1406 iterator_.Advance();
1407 }
1408 UNREACHABLE();
1409 return NULL;
1410}
1411
1412
1413// -------------------------------------------------------------------------
1414
1415
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001416static Map* GcSafeMapOfCodeSpaceObject(HeapObject* object) {
1417 MapWord map_word = object->map_word();
1418 return map_word.IsForwardingAddress() ?
1419 map_word.ToForwardingAddress()->map() : map_word.ToMap();
1420}
1421
1422
1423static int GcSafeSizeOfCodeSpaceObject(HeapObject* object) {
1424 return object->SizeFromMap(GcSafeMapOfCodeSpaceObject(object));
1425}
1426
1427
1428#ifdef DEBUG
1429static bool GcSafeCodeContains(HeapObject* code, Address addr) {
1430 Map* map = GcSafeMapOfCodeSpaceObject(code);
1431 ASSERT(map == code->GetHeap()->code_map());
1432 Address start = code->address();
1433 Address end = code->address() + code->SizeFromMap(map);
1434 return start <= addr && addr < end;
1435}
1436#endif
1437
1438
1439Code* InnerPointerToCodeCache::GcSafeCastToCode(HeapObject* object,
1440 Address inner_pointer) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001441 Code* code = reinterpret_cast<Code*>(object);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001442 ASSERT(code != NULL && GcSafeCodeContains(code, inner_pointer));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001443 return code;
1444}
1445
1446
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001447Code* InnerPointerToCodeCache::GcSafeFindCodeForInnerPointer(
1448 Address inner_pointer) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001449 Heap* heap = isolate_->heap();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001450 // Check if the inner pointer points into a large object chunk.
jkummerow@chromium.org531dfe82012-03-20 13:01:16 +00001451 LargePage* large_page = heap->lo_space()->FindPage(inner_pointer);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001452 if (large_page != NULL) {
1453 return GcSafeCastToCode(large_page->GetObject(), inner_pointer);
1454 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001455
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001456 // Iterate through the page until we reach the end or find an object starting
1457 // after the inner pointer.
1458 Page* page = Page::FromAddress(inner_pointer);
1459
1460 Address addr = page->skip_list()->StartFor(inner_pointer);
1461
1462 Address top = heap->code_space()->top();
1463 Address limit = heap->code_space()->limit();
1464
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001465 while (true) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001466 if (addr == top && addr != limit) {
1467 addr = limit;
1468 continue;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001469 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001470
1471 HeapObject* obj = HeapObject::FromAddress(addr);
1472 int obj_size = GcSafeSizeOfCodeSpaceObject(obj);
1473 Address next_addr = addr + obj_size;
1474 if (next_addr > inner_pointer) return GcSafeCastToCode(obj, inner_pointer);
1475 addr = next_addr;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001476 }
1477}
1478
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001479
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001480InnerPointerToCodeCache::InnerPointerToCodeCacheEntry*
1481 InnerPointerToCodeCache::GetCacheEntry(Address inner_pointer) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001482 isolate_->counters()->pc_to_code()->Increment();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001483 ASSERT(IsPowerOf2(kInnerPointerToCodeCacheSize));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001484 uint32_t hash = ComputeIntegerHash(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001485 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(inner_pointer)),
1486 v8::internal::kZeroHashSeed);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001487 uint32_t index = hash & (kInnerPointerToCodeCacheSize - 1);
1488 InnerPointerToCodeCacheEntry* entry = cache(index);
1489 if (entry->inner_pointer == inner_pointer) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001490 isolate_->counters()->pc_to_code_cached()->Increment();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001491 ASSERT(entry->code == GcSafeFindCodeForInnerPointer(inner_pointer));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001492 } else {
1493 // Because this code may be interrupted by a profiling signal that
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001494 // also queries the cache, we cannot update inner_pointer before the code
1495 // has been set. Otherwise, we risk trying to use a cache entry before
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001496 // the code has been computed.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001497 entry->code = GcSafeFindCodeForInnerPointer(inner_pointer);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001498 entry->safepoint_entry.Reset();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001499 entry->inner_pointer = inner_pointer;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001500 }
1501 return entry;
1502}
1503
1504
1505// -------------------------------------------------------------------------
1506
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001507
1508void StackHandler::Unwind(Isolate* isolate,
1509 FixedArray* array,
1510 int offset,
1511 int previous_handler_offset) const {
1512 STATIC_ASSERT(StackHandlerConstants::kSlotCount == 5);
1513 ASSERT_LE(0, offset);
1514 ASSERT_GE(array->length(), offset + 5);
1515 // Unwinding a stack handler into an array chains it in the opposite
1516 // direction, re-using the "next" slot as a "previous" link, so that stack
1517 // handlers can be later re-wound in the correct order. Decode the "state"
1518 // slot into "index" and "kind" and store them separately, using the fp slot.
1519 array->set(offset, Smi::FromInt(previous_handler_offset)); // next
1520 array->set(offset + 1, *code_address()); // code
1521 array->set(offset + 2, Smi::FromInt(static_cast<int>(index()))); // state
1522 array->set(offset + 3, *context_address()); // context
1523 array->set(offset + 4, Smi::FromInt(static_cast<int>(kind()))); // fp
1524
1525 *isolate->handler_address() = next()->address();
1526}
1527
1528
1529int StackHandler::Rewind(Isolate* isolate,
1530 FixedArray* array,
1531 int offset,
1532 Address fp) {
1533 STATIC_ASSERT(StackHandlerConstants::kSlotCount == 5);
1534 ASSERT_LE(0, offset);
1535 ASSERT_GE(array->length(), offset + 5);
1536 Smi* prev_handler_offset = Smi::cast(array->get(offset));
1537 Code* code = Code::cast(array->get(offset + 1));
1538 Smi* smi_index = Smi::cast(array->get(offset + 2));
1539 Object* context = array->get(offset + 3);
1540 Smi* smi_kind = Smi::cast(array->get(offset + 4));
1541
1542 unsigned state = KindField::encode(static_cast<Kind>(smi_kind->value())) |
1543 IndexField::encode(static_cast<unsigned>(smi_index->value()));
1544
1545 Memory::Address_at(address() + StackHandlerConstants::kNextOffset) =
1546 *isolate->handler_address();
1547 Memory::Object_at(address() + StackHandlerConstants::kCodeOffset) = code;
1548 Memory::uintptr_at(address() + StackHandlerConstants::kStateOffset) = state;
1549 Memory::Object_at(address() + StackHandlerConstants::kContextOffset) =
1550 context;
1551 Memory::Address_at(address() + StackHandlerConstants::kFPOffset) = fp;
1552
1553 *isolate->handler_address() = address();
1554
1555 return prev_handler_offset->value();
1556}
1557
1558
1559// -------------------------------------------------------------------------
1560
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001561int NumRegs(RegList reglist) {
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +00001562 return CompilerIntrinsics::CountSetBits(reglist);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001563}
1564
1565
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001566struct JSCallerSavedCodeData {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001567 int reg_code[kNumJSCallerSaved];
1568};
1569
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001570JSCallerSavedCodeData caller_saved_code_data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001571
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001572void SetUpJSCallerSavedCodeData() {
1573 int i = 0;
1574 for (int r = 0; r < kNumRegs; r++)
1575 if ((kJSCallerSaved & (1 << r)) != 0)
1576 caller_saved_code_data.reg_code[i++] = r;
1577
1578 ASSERT(i == kNumJSCallerSaved);
1579}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001580
1581int JSCallerSavedCode(int n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001582 ASSERT(0 <= n && n < kNumJSCallerSaved);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001583 return caller_saved_code_data.reg_code[n];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001584}
1585
1586
ager@chromium.org357bf652010-04-12 11:30:10 +00001587#define DEFINE_WRAPPER(type, field) \
1588class field##_Wrapper : public ZoneObject { \
1589 public: /* NOLINT */ \
1590 field##_Wrapper(const field& original) : frame_(original) { \
1591 } \
1592 field frame_; \
1593};
1594STACK_FRAME_TYPE_LIST(DEFINE_WRAPPER)
1595#undef DEFINE_WRAPPER
1596
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001597static StackFrame* AllocateFrameCopy(StackFrame* frame, Zone* zone) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001598#define FRAME_TYPE_CASE(type, field) \
1599 case StackFrame::type: { \
1600 field##_Wrapper* wrapper = \
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001601 new(zone) field##_Wrapper(*(reinterpret_cast<field*>(frame))); \
ager@chromium.org357bf652010-04-12 11:30:10 +00001602 return &wrapper->frame_; \
1603 }
1604
1605 switch (frame->type()) {
1606 STACK_FRAME_TYPE_LIST(FRAME_TYPE_CASE)
1607 default: UNREACHABLE();
1608 }
1609#undef FRAME_TYPE_CASE
1610 return NULL;
1611}
1612
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001613Vector<StackFrame*> CreateStackMap(Isolate* isolate, Zone* zone) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001614 ZoneList<StackFrame*> list(10, zone);
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001615 for (StackFrameIterator it(isolate); !it.done(); it.Advance()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001616 StackFrame* frame = AllocateFrameCopy(it.frame(), zone);
1617 list.Add(frame, zone);
ager@chromium.org357bf652010-04-12 11:30:10 +00001618 }
1619 return list.ToVector();
1620}
1621
1622
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001623} } // namespace v8::internal