Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(101)

Side by Side Diff: src/top.cc

Issue 6969042: Isolates cleanup: move top.cc to isolate.cc. (Closed)
Patch Set: Created 9 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/isolate.cc ('k') | tools/gyp/v8.gyp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2006-2008 the V8 project authors. All rights reserved.
2 // 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
30 #include "api.h"
31 #include "bootstrapper.h"
32 #include "compiler.h"
33 #include "debug.h"
34 #include "execution.h"
35 #include "messages.h"
36 #include "platform.h"
37 #include "simulator.h"
38 #include "string-stream.h"
39 #include "vm-state-inl.h"
40
41
42 // TODO(isolates): move to isolate.cc. This stuff is kept here to
43 // simplify merging.
44
45 namespace v8 {
46 namespace internal {
47
48 ThreadLocalTop::ThreadLocalTop() {
49 InitializeInternal();
50 }
51
52
53 void ThreadLocalTop::InitializeInternal() {
54 c_entry_fp_ = 0;
55 handler_ = 0;
56 #ifdef USE_SIMULATOR
57 simulator_ = NULL;
58 #endif
59 #ifdef ENABLE_LOGGING_AND_PROFILING
60 js_entry_sp_ = NULL;
61 external_callback_ = NULL;
62 #endif
63 #ifdef ENABLE_VMSTATE_TRACKING
64 current_vm_state_ = EXTERNAL;
65 #endif
66 try_catch_handler_address_ = NULL;
67 context_ = NULL;
68 thread_id_ = ThreadId::Invalid();
69 external_caught_exception_ = false;
70 failed_access_check_callback_ = NULL;
71 save_context_ = NULL;
72 catcher_ = NULL;
73 }
74
75
76 void ThreadLocalTop::Initialize() {
77 InitializeInternal();
78 #ifdef USE_SIMULATOR
79 #ifdef V8_TARGET_ARCH_ARM
80 simulator_ = Simulator::current(isolate_);
81 #elif V8_TARGET_ARCH_MIPS
82 simulator_ = Simulator::current(isolate_);
83 #endif
84 #endif
85 thread_id_ = ThreadId::Current();
86 }
87
88
89 v8::TryCatch* ThreadLocalTop::TryCatchHandler() {
90 return TRY_CATCH_FROM_ADDRESS(try_catch_handler_address());
91 }
92
93
94 Address Isolate::get_address_from_id(Isolate::AddressId id) {
95 return isolate_addresses_[id];
96 }
97
98
99 char* Isolate::Iterate(ObjectVisitor* v, char* thread_storage) {
100 ThreadLocalTop* thread = reinterpret_cast<ThreadLocalTop*>(thread_storage);
101 Iterate(v, thread);
102 return thread_storage + sizeof(ThreadLocalTop);
103 }
104
105
106 void Isolate::IterateThread(ThreadVisitor* v) {
107 v->VisitThread(this, thread_local_top());
108 }
109
110
111 void Isolate::IterateThread(ThreadVisitor* v, char* t) {
112 ThreadLocalTop* thread = reinterpret_cast<ThreadLocalTop*>(t);
113 v->VisitThread(this, thread);
114 }
115
116
117 void Isolate::Iterate(ObjectVisitor* v, ThreadLocalTop* thread) {
118 // Visit the roots from the top for a given thread.
119 Object* pending;
120 // The pending exception can sometimes be a failure. We can't show
121 // that to the GC, which only understands objects.
122 if (thread->pending_exception_->ToObject(&pending)) {
123 v->VisitPointer(&pending);
124 thread->pending_exception_ = pending; // In case GC updated it.
125 }
126 v->VisitPointer(&(thread->pending_message_obj_));
127 v->VisitPointer(BitCast<Object**>(&(thread->pending_message_script_)));
128 v->VisitPointer(BitCast<Object**>(&(thread->context_)));
129 Object* scheduled;
130 if (thread->scheduled_exception_->ToObject(&scheduled)) {
131 v->VisitPointer(&scheduled);
132 thread->scheduled_exception_ = scheduled;
133 }
134
135 for (v8::TryCatch* block = thread->TryCatchHandler();
136 block != NULL;
137 block = TRY_CATCH_FROM_ADDRESS(block->next_)) {
138 v->VisitPointer(BitCast<Object**>(&(block->exception_)));
139 v->VisitPointer(BitCast<Object**>(&(block->message_)));
140 }
141
142 // Iterate over pointers on native execution stack.
143 for (StackFrameIterator it(this, thread); !it.done(); it.Advance()) {
144 it.frame()->Iterate(v);
145 }
146 }
147
148
149 void Isolate::Iterate(ObjectVisitor* v) {
150 ThreadLocalTop* current_t = thread_local_top();
151 Iterate(v, current_t);
152 }
153
154
155 void Isolate::RegisterTryCatchHandler(v8::TryCatch* that) {
156 // The ARM simulator has a separate JS stack. We therefore register
157 // the C++ try catch handler with the simulator and get back an
158 // address that can be used for comparisons with addresses into the
159 // JS stack. When running without the simulator, the address
160 // returned will be the address of the C++ try catch handler itself.
161 Address address = reinterpret_cast<Address>(
162 SimulatorStack::RegisterCTryCatch(reinterpret_cast<uintptr_t>(that)));
163 thread_local_top()->set_try_catch_handler_address(address);
164 }
165
166
167 void Isolate::UnregisterTryCatchHandler(v8::TryCatch* that) {
168 ASSERT(thread_local_top()->TryCatchHandler() == that);
169 thread_local_top()->set_try_catch_handler_address(
170 reinterpret_cast<Address>(that->next_));
171 thread_local_top()->catcher_ = NULL;
172 SimulatorStack::UnregisterCTryCatch();
173 }
174
175
176 Handle<String> Isolate::StackTraceString() {
177 if (stack_trace_nesting_level_ == 0) {
178 stack_trace_nesting_level_++;
179 HeapStringAllocator allocator;
180 StringStream::ClearMentionedObjectCache();
181 StringStream accumulator(&allocator);
182 incomplete_message_ = &accumulator;
183 PrintStack(&accumulator);
184 Handle<String> stack_trace = accumulator.ToString();
185 incomplete_message_ = NULL;
186 stack_trace_nesting_level_ = 0;
187 return stack_trace;
188 } else if (stack_trace_nesting_level_ == 1) {
189 stack_trace_nesting_level_++;
190 OS::PrintError(
191 "\n\nAttempt to print stack while printing stack (double fault)\n");
192 OS::PrintError(
193 "If you are lucky you may find a partial stack dump on stdout.\n\n");
194 incomplete_message_->OutputToStdOut();
195 return factory()->empty_symbol();
196 } else {
197 OS::Abort();
198 // Unreachable
199 return factory()->empty_symbol();
200 }
201 }
202
203
204 Handle<JSArray> Isolate::CaptureCurrentStackTrace(
205 int frame_limit, StackTrace::StackTraceOptions options) {
206 // Ensure no negative values.
207 int limit = Max(frame_limit, 0);
208 Handle<JSArray> stack_trace = factory()->NewJSArray(frame_limit);
209
210 Handle<String> column_key = factory()->LookupAsciiSymbol("column");
211 Handle<String> line_key = factory()->LookupAsciiSymbol("lineNumber");
212 Handle<String> script_key = factory()->LookupAsciiSymbol("scriptName");
213 Handle<String> name_or_source_url_key =
214 factory()->LookupAsciiSymbol("nameOrSourceURL");
215 Handle<String> script_name_or_source_url_key =
216 factory()->LookupAsciiSymbol("scriptNameOrSourceURL");
217 Handle<String> function_key = factory()->LookupAsciiSymbol("functionName");
218 Handle<String> eval_key = factory()->LookupAsciiSymbol("isEval");
219 Handle<String> constructor_key =
220 factory()->LookupAsciiSymbol("isConstructor");
221
222 StackTraceFrameIterator it(this);
223 int frames_seen = 0;
224 while (!it.done() && (frames_seen < limit)) {
225 JavaScriptFrame* frame = it.frame();
226 // Set initial size to the maximum inlining level + 1 for the outermost
227 // function.
228 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
229 frame->Summarize(&frames);
230 for (int i = frames.length() - 1; i >= 0 && frames_seen < limit; i--) {
231 // Create a JSObject to hold the information for the StackFrame.
232 Handle<JSObject> stackFrame = factory()->NewJSObject(object_function());
233
234 Handle<JSFunction> fun = frames[i].function();
235 Handle<Script> script(Script::cast(fun->shared()->script()));
236
237 if (options & StackTrace::kLineNumber) {
238 int script_line_offset = script->line_offset()->value();
239 int position = frames[i].code()->SourcePosition(frames[i].pc());
240 int line_number = GetScriptLineNumber(script, position);
241 // line_number is already shifted by the script_line_offset.
242 int relative_line_number = line_number - script_line_offset;
243 if (options & StackTrace::kColumnOffset && relative_line_number >= 0) {
244 Handle<FixedArray> line_ends(FixedArray::cast(script->line_ends()));
245 int start = (relative_line_number == 0) ? 0 :
246 Smi::cast(line_ends->get(relative_line_number - 1))->value() + 1;
247 int column_offset = position - start;
248 if (relative_line_number == 0) {
249 // For the case where the code is on the same line as the script
250 // tag.
251 column_offset += script->column_offset()->value();
252 }
253 SetLocalPropertyNoThrow(stackFrame, column_key,
254 Handle<Smi>(Smi::FromInt(column_offset + 1)));
255 }
256 SetLocalPropertyNoThrow(stackFrame, line_key,
257 Handle<Smi>(Smi::FromInt(line_number + 1)));
258 }
259
260 if (options & StackTrace::kScriptName) {
261 Handle<Object> script_name(script->name(), this);
262 SetLocalPropertyNoThrow(stackFrame, script_key, script_name);
263 }
264
265 if (options & StackTrace::kScriptNameOrSourceURL) {
266 Handle<Object> script_name(script->name(), this);
267 Handle<JSValue> script_wrapper = GetScriptWrapper(script);
268 Handle<Object> property = GetProperty(script_wrapper,
269 name_or_source_url_key);
270 ASSERT(property->IsJSFunction());
271 Handle<JSFunction> method = Handle<JSFunction>::cast(property);
272 bool caught_exception;
273 Handle<Object> result = Execution::TryCall(method, script_wrapper, 0,
274 NULL, &caught_exception);
275 if (caught_exception) {
276 result = factory()->undefined_value();
277 }
278 SetLocalPropertyNoThrow(stackFrame, script_name_or_source_url_key,
279 result);
280 }
281
282 if (options & StackTrace::kFunctionName) {
283 Handle<Object> fun_name(fun->shared()->name(), this);
284 if (fun_name->ToBoolean()->IsFalse()) {
285 fun_name = Handle<Object>(fun->shared()->inferred_name(), this);
286 }
287 SetLocalPropertyNoThrow(stackFrame, function_key, fun_name);
288 }
289
290 if (options & StackTrace::kIsEval) {
291 int type = Smi::cast(script->compilation_type())->value();
292 Handle<Object> is_eval = (type == Script::COMPILATION_TYPE_EVAL) ?
293 factory()->true_value() : factory()->false_value();
294 SetLocalPropertyNoThrow(stackFrame, eval_key, is_eval);
295 }
296
297 if (options & StackTrace::kIsConstructor) {
298 Handle<Object> is_constructor = (frames[i].is_constructor()) ?
299 factory()->true_value() : factory()->false_value();
300 SetLocalPropertyNoThrow(stackFrame, constructor_key, is_constructor);
301 }
302
303 FixedArray::cast(stack_trace->elements())->set(frames_seen, *stackFrame);
304 frames_seen++;
305 }
306 it.Advance();
307 }
308
309 stack_trace->set_length(Smi::FromInt(frames_seen));
310 return stack_trace;
311 }
312
313
314 void Isolate::PrintStack() {
315 if (stack_trace_nesting_level_ == 0) {
316 stack_trace_nesting_level_++;
317
318 StringAllocator* allocator;
319 if (preallocated_message_space_ == NULL) {
320 allocator = new HeapStringAllocator();
321 } else {
322 allocator = preallocated_message_space_;
323 }
324
325 StringStream::ClearMentionedObjectCache();
326 StringStream accumulator(allocator);
327 incomplete_message_ = &accumulator;
328 PrintStack(&accumulator);
329 accumulator.OutputToStdOut();
330 accumulator.Log();
331 incomplete_message_ = NULL;
332 stack_trace_nesting_level_ = 0;
333 if (preallocated_message_space_ == NULL) {
334 // Remove the HeapStringAllocator created above.
335 delete allocator;
336 }
337 } else if (stack_trace_nesting_level_ == 1) {
338 stack_trace_nesting_level_++;
339 OS::PrintError(
340 "\n\nAttempt to print stack while printing stack (double fault)\n");
341 OS::PrintError(
342 "If you are lucky you may find a partial stack dump on stdout.\n\n");
343 incomplete_message_->OutputToStdOut();
344 }
345 }
346
347
348 static void PrintFrames(StringStream* accumulator,
349 StackFrame::PrintMode mode) {
350 StackFrameIterator it;
351 for (int i = 0; !it.done(); it.Advance()) {
352 it.frame()->Print(accumulator, mode, i++);
353 }
354 }
355
356
357 void Isolate::PrintStack(StringStream* accumulator) {
358 if (!IsInitialized()) {
359 accumulator->Add(
360 "\n==== Stack trace is not available ==========================\n\n");
361 accumulator->Add(
362 "\n==== Isolate for the thread is not initialized =============\n\n");
363 return;
364 }
365 // The MentionedObjectCache is not GC-proof at the moment.
366 AssertNoAllocation nogc;
367 ASSERT(StringStream::IsMentionedObjectCacheClear());
368
369 // Avoid printing anything if there are no frames.
370 if (c_entry_fp(thread_local_top()) == 0) return;
371
372 accumulator->Add(
373 "\n==== Stack trace ============================================\n\n");
374 PrintFrames(accumulator, StackFrame::OVERVIEW);
375
376 accumulator->Add(
377 "\n==== Details ================================================\n\n");
378 PrintFrames(accumulator, StackFrame::DETAILS);
379
380 accumulator->PrintMentionedObjectCache();
381 accumulator->Add("=====================\n\n");
382 }
383
384
385 void Isolate::SetFailedAccessCheckCallback(
386 v8::FailedAccessCheckCallback callback) {
387 thread_local_top()->failed_access_check_callback_ = callback;
388 }
389
390
391 void Isolate::ReportFailedAccessCheck(JSObject* receiver, v8::AccessType type) {
392 if (!thread_local_top()->failed_access_check_callback_) return;
393
394 ASSERT(receiver->IsAccessCheckNeeded());
395 ASSERT(context());
396
397 // Get the data object from access check info.
398 JSFunction* constructor = JSFunction::cast(receiver->map()->constructor());
399 if (!constructor->shared()->IsApiFunction()) return;
400 Object* data_obj =
401 constructor->shared()->get_api_func_data()->access_check_info();
402 if (data_obj == heap_.undefined_value()) return;
403
404 HandleScope scope;
405 Handle<JSObject> receiver_handle(receiver);
406 Handle<Object> data(AccessCheckInfo::cast(data_obj)->data());
407 thread_local_top()->failed_access_check_callback_(
408 v8::Utils::ToLocal(receiver_handle),
409 type,
410 v8::Utils::ToLocal(data));
411 }
412
413
414 enum MayAccessDecision {
415 YES, NO, UNKNOWN
416 };
417
418
419 static MayAccessDecision MayAccessPreCheck(Isolate* isolate,
420 JSObject* receiver,
421 v8::AccessType type) {
422 // During bootstrapping, callback functions are not enabled yet.
423 if (isolate->bootstrapper()->IsActive()) return YES;
424
425 if (receiver->IsJSGlobalProxy()) {
426 Object* receiver_context = JSGlobalProxy::cast(receiver)->context();
427 if (!receiver_context->IsContext()) return NO;
428
429 // Get the global context of current top context.
430 // avoid using Isolate::global_context() because it uses Handle.
431 Context* global_context = isolate->context()->global()->global_context();
432 if (receiver_context == global_context) return YES;
433
434 if (Context::cast(receiver_context)->security_token() ==
435 global_context->security_token())
436 return YES;
437 }
438
439 return UNKNOWN;
440 }
441
442
443 bool Isolate::MayNamedAccess(JSObject* receiver, Object* key,
444 v8::AccessType type) {
445 ASSERT(receiver->IsAccessCheckNeeded());
446
447 // The callers of this method are not expecting a GC.
448 AssertNoAllocation no_gc;
449
450 // Skip checks for hidden properties access. Note, we do not
451 // require existence of a context in this case.
452 if (key == heap_.hidden_symbol()) return true;
453
454 // Check for compatibility between the security tokens in the
455 // current lexical context and the accessed object.
456 ASSERT(context());
457
458 MayAccessDecision decision = MayAccessPreCheck(this, receiver, type);
459 if (decision != UNKNOWN) return decision == YES;
460
461 // Get named access check callback
462 JSFunction* constructor = JSFunction::cast(receiver->map()->constructor());
463 if (!constructor->shared()->IsApiFunction()) return false;
464
465 Object* data_obj =
466 constructor->shared()->get_api_func_data()->access_check_info();
467 if (data_obj == heap_.undefined_value()) return false;
468
469 Object* fun_obj = AccessCheckInfo::cast(data_obj)->named_callback();
470 v8::NamedSecurityCallback callback =
471 v8::ToCData<v8::NamedSecurityCallback>(fun_obj);
472
473 if (!callback) return false;
474
475 HandleScope scope(this);
476 Handle<JSObject> receiver_handle(receiver, this);
477 Handle<Object> key_handle(key, this);
478 Handle<Object> data(AccessCheckInfo::cast(data_obj)->data(), this);
479 LOG(this, ApiNamedSecurityCheck(key));
480 bool result = false;
481 {
482 // Leaving JavaScript.
483 VMState state(this, EXTERNAL);
484 result = callback(v8::Utils::ToLocal(receiver_handle),
485 v8::Utils::ToLocal(key_handle),
486 type,
487 v8::Utils::ToLocal(data));
488 }
489 return result;
490 }
491
492
493 bool Isolate::MayIndexedAccess(JSObject* receiver,
494 uint32_t index,
495 v8::AccessType type) {
496 ASSERT(receiver->IsAccessCheckNeeded());
497 // Check for compatibility between the security tokens in the
498 // current lexical context and the accessed object.
499 ASSERT(context());
500
501 MayAccessDecision decision = MayAccessPreCheck(this, receiver, type);
502 if (decision != UNKNOWN) return decision == YES;
503
504 // Get indexed access check callback
505 JSFunction* constructor = JSFunction::cast(receiver->map()->constructor());
506 if (!constructor->shared()->IsApiFunction()) return false;
507
508 Object* data_obj =
509 constructor->shared()->get_api_func_data()->access_check_info();
510 if (data_obj == heap_.undefined_value()) return false;
511
512 Object* fun_obj = AccessCheckInfo::cast(data_obj)->indexed_callback();
513 v8::IndexedSecurityCallback callback =
514 v8::ToCData<v8::IndexedSecurityCallback>(fun_obj);
515
516 if (!callback) return false;
517
518 HandleScope scope(this);
519 Handle<JSObject> receiver_handle(receiver, this);
520 Handle<Object> data(AccessCheckInfo::cast(data_obj)->data(), this);
521 LOG(this, ApiIndexedSecurityCheck(index));
522 bool result = false;
523 {
524 // Leaving JavaScript.
525 VMState state(this, EXTERNAL);
526 result = callback(v8::Utils::ToLocal(receiver_handle),
527 index,
528 type,
529 v8::Utils::ToLocal(data));
530 }
531 return result;
532 }
533
534
535 const char* const Isolate::kStackOverflowMessage =
536 "Uncaught RangeError: Maximum call stack size exceeded";
537
538
539 Failure* Isolate::StackOverflow() {
540 HandleScope scope;
541 Handle<String> key = factory()->stack_overflow_symbol();
542 Handle<JSObject> boilerplate =
543 Handle<JSObject>::cast(GetProperty(js_builtins_object(), key));
544 Handle<Object> exception = Copy(boilerplate);
545 // TODO(1240995): To avoid having to call JavaScript code to compute
546 // the message for stack overflow exceptions which is very likely to
547 // double fault with another stack overflow exception, we use a
548 // precomputed message.
549 DoThrow(*exception, NULL);
550 return Failure::Exception();
551 }
552
553
554 Failure* Isolate::TerminateExecution() {
555 DoThrow(heap_.termination_exception(), NULL);
556 return Failure::Exception();
557 }
558
559
560 Failure* Isolate::Throw(Object* exception, MessageLocation* location) {
561 DoThrow(exception, location);
562 return Failure::Exception();
563 }
564
565
566 Failure* Isolate::ReThrow(MaybeObject* exception, MessageLocation* location) {
567 bool can_be_caught_externally = false;
568 ShouldReportException(&can_be_caught_externally,
569 is_catchable_by_javascript(exception));
570 thread_local_top()->catcher_ = can_be_caught_externally ?
571 try_catch_handler() : NULL;
572
573 // Set the exception being re-thrown.
574 set_pending_exception(exception);
575 return Failure::Exception();
576 }
577
578
579 Failure* Isolate::ThrowIllegalOperation() {
580 return Throw(heap_.illegal_access_symbol());
581 }
582
583
584 void Isolate::ScheduleThrow(Object* exception) {
585 // When scheduling a throw we first throw the exception to get the
586 // error reporting if it is uncaught before rescheduling it.
587 Throw(exception);
588 thread_local_top()->scheduled_exception_ = pending_exception();
589 thread_local_top()->external_caught_exception_ = false;
590 clear_pending_exception();
591 }
592
593
594 Failure* Isolate::PromoteScheduledException() {
595 MaybeObject* thrown = scheduled_exception();
596 clear_scheduled_exception();
597 // Re-throw the exception to avoid getting repeated error reporting.
598 return ReThrow(thrown);
599 }
600
601
602 void Isolate::PrintCurrentStackTrace(FILE* out) {
603 StackTraceFrameIterator it(this);
604 while (!it.done()) {
605 HandleScope scope;
606 // Find code position if recorded in relocation info.
607 JavaScriptFrame* frame = it.frame();
608 int pos = frame->LookupCode()->SourcePosition(frame->pc());
609 Handle<Object> pos_obj(Smi::FromInt(pos));
610 // Fetch function and receiver.
611 Handle<JSFunction> fun(JSFunction::cast(frame->function()));
612 Handle<Object> recv(frame->receiver());
613 // Advance to the next JavaScript frame and determine if the
614 // current frame is the top-level frame.
615 it.Advance();
616 Handle<Object> is_top_level = it.done()
617 ? factory()->true_value()
618 : factory()->false_value();
619 // Generate and print stack trace line.
620 Handle<String> line =
621 Execution::GetStackTraceLine(recv, fun, pos_obj, is_top_level);
622 if (line->length() > 0) {
623 line->PrintOn(out);
624 fprintf(out, "\n");
625 }
626 }
627 }
628
629
630 void Isolate::ComputeLocation(MessageLocation* target) {
631 *target = MessageLocation(Handle<Script>(heap_.empty_script()), -1, -1);
632 StackTraceFrameIterator it(this);
633 if (!it.done()) {
634 JavaScriptFrame* frame = it.frame();
635 JSFunction* fun = JSFunction::cast(frame->function());
636 Object* script = fun->shared()->script();
637 if (script->IsScript() &&
638 !(Script::cast(script)->source()->IsUndefined())) {
639 int pos = frame->LookupCode()->SourcePosition(frame->pc());
640 // Compute the location from the function and the reloc info.
641 Handle<Script> casted_script(Script::cast(script));
642 *target = MessageLocation(casted_script, pos, pos + 1);
643 }
644 }
645 }
646
647
648 bool Isolate::ShouldReportException(bool* can_be_caught_externally,
649 bool catchable_by_javascript) {
650 // Find the top-most try-catch handler.
651 StackHandler* handler =
652 StackHandler::FromAddress(Isolate::handler(thread_local_top()));
653 while (handler != NULL && !handler->is_try_catch()) {
654 handler = handler->next();
655 }
656
657 // Get the address of the external handler so we can compare the address to
658 // determine which one is closer to the top of the stack.
659 Address external_handler_address =
660 thread_local_top()->try_catch_handler_address();
661
662 // The exception has been externally caught if and only if there is
663 // an external handler which is on top of the top-most try-catch
664 // handler.
665 *can_be_caught_externally = external_handler_address != NULL &&
666 (handler == NULL || handler->address() > external_handler_address ||
667 !catchable_by_javascript);
668
669 if (*can_be_caught_externally) {
670 // Only report the exception if the external handler is verbose.
671 return try_catch_handler()->is_verbose_;
672 } else {
673 // Report the exception if it isn't caught by JavaScript code.
674 return handler == NULL;
675 }
676 }
677
678
679 void Isolate::DoThrow(MaybeObject* exception, MessageLocation* location) {
680 ASSERT(!has_pending_exception());
681
682 HandleScope scope;
683 Object* exception_object = Smi::FromInt(0);
684 bool is_object = exception->ToObject(&exception_object);
685 Handle<Object> exception_handle(exception_object);
686
687 // Determine reporting and whether the exception is caught externally.
688 bool catchable_by_javascript = is_catchable_by_javascript(exception);
689 // Only real objects can be caught by JS.
690 ASSERT(!catchable_by_javascript || is_object);
691 bool can_be_caught_externally = false;
692 bool should_report_exception =
693 ShouldReportException(&can_be_caught_externally, catchable_by_javascript);
694 bool report_exception = catchable_by_javascript && should_report_exception;
695
696 #ifdef ENABLE_DEBUGGER_SUPPORT
697 // Notify debugger of exception.
698 if (catchable_by_javascript) {
699 debugger_->OnException(exception_handle, report_exception);
700 }
701 #endif
702
703 // Generate the message.
704 Handle<Object> message_obj;
705 MessageLocation potential_computed_location;
706 bool try_catch_needs_message =
707 can_be_caught_externally &&
708 try_catch_handler()->capture_message_;
709 if (report_exception || try_catch_needs_message) {
710 if (location == NULL) {
711 // If no location was specified we use a computed one instead
712 ComputeLocation(&potential_computed_location);
713 location = &potential_computed_location;
714 }
715 if (!bootstrapper()->IsActive()) {
716 // It's not safe to try to make message objects or collect stack
717 // traces while the bootstrapper is active since the infrastructure
718 // may not have been properly initialized.
719 Handle<String> stack_trace;
720 if (FLAG_trace_exception) stack_trace = StackTraceString();
721 Handle<JSArray> stack_trace_object;
722 if (report_exception && capture_stack_trace_for_uncaught_exceptions_) {
723 stack_trace_object = CaptureCurrentStackTrace(
724 stack_trace_for_uncaught_exceptions_frame_limit_,
725 stack_trace_for_uncaught_exceptions_options_);
726 }
727 ASSERT(is_object); // Can't use the handle unless there's a real object.
728 message_obj = MessageHandler::MakeMessageObject("uncaught_exception",
729 location, HandleVector<Object>(&exception_handle, 1), stack_trace,
730 stack_trace_object);
731 }
732 }
733
734 // Save the message for reporting if the the exception remains uncaught.
735 thread_local_top()->has_pending_message_ = report_exception;
736 if (!message_obj.is_null()) {
737 thread_local_top()->pending_message_obj_ = *message_obj;
738 if (location != NULL) {
739 thread_local_top()->pending_message_script_ = *location->script();
740 thread_local_top()->pending_message_start_pos_ = location->start_pos();
741 thread_local_top()->pending_message_end_pos_ = location->end_pos();
742 }
743 }
744
745 // Do not forget to clean catcher_ if currently thrown exception cannot
746 // be caught. If necessary, ReThrow will update the catcher.
747 thread_local_top()->catcher_ = can_be_caught_externally ?
748 try_catch_handler() : NULL;
749
750 // NOTE: Notifying the debugger or generating the message
751 // may have caused new exceptions. For now, we just ignore
752 // that and set the pending exception to the original one.
753 if (is_object) {
754 set_pending_exception(*exception_handle);
755 } else {
756 // Failures are not on the heap so they neither need nor work with handles.
757 ASSERT(exception_handle->IsFailure());
758 set_pending_exception(exception);
759 }
760 }
761
762
763 bool Isolate::IsExternallyCaught() {
764 ASSERT(has_pending_exception());
765
766 if ((thread_local_top()->catcher_ == NULL) ||
767 (try_catch_handler() != thread_local_top()->catcher_)) {
768 // When throwing the exception, we found no v8::TryCatch
769 // which should care about this exception.
770 return false;
771 }
772
773 if (!is_catchable_by_javascript(pending_exception())) {
774 return true;
775 }
776
777 // Get the address of the external handler so we can compare the address to
778 // determine which one is closer to the top of the stack.
779 Address external_handler_address =
780 thread_local_top()->try_catch_handler_address();
781 ASSERT(external_handler_address != NULL);
782
783 // The exception has been externally caught if and only if there is
784 // an external handler which is on top of the top-most try-finally
785 // handler.
786 // There should be no try-catch blocks as they would prohibit us from
787 // finding external catcher in the first place (see catcher_ check above).
788 //
789 // Note, that finally clause would rethrow an exception unless it's
790 // aborted by jumps in control flow like return, break, etc. and we'll
791 // have another chances to set proper v8::TryCatch.
792 StackHandler* handler =
793 StackHandler::FromAddress(Isolate::handler(thread_local_top()));
794 while (handler != NULL && handler->address() < external_handler_address) {
795 ASSERT(!handler->is_try_catch());
796 if (handler->is_try_finally()) return false;
797
798 handler = handler->next();
799 }
800
801 return true;
802 }
803
804
805 void Isolate::ReportPendingMessages() {
806 ASSERT(has_pending_exception());
807 PropagatePendingExceptionToExternalTryCatch();
808
809 // If the pending exception is OutOfMemoryException set out_of_memory in
810 // the global context. Note: We have to mark the global context here
811 // since the GenerateThrowOutOfMemory stub cannot make a RuntimeCall to
812 // set it.
813 HandleScope scope;
814 if (thread_local_top_.pending_exception_ == Failure::OutOfMemoryException()) {
815 context()->mark_out_of_memory();
816 } else if (thread_local_top_.pending_exception_ ==
817 heap()->termination_exception()) {
818 // Do nothing: if needed, the exception has been already propagated to
819 // v8::TryCatch.
820 } else {
821 if (thread_local_top_.has_pending_message_) {
822 thread_local_top_.has_pending_message_ = false;
823 if (!thread_local_top_.pending_message_obj_->IsTheHole()) {
824 HandleScope scope;
825 Handle<Object> message_obj(thread_local_top_.pending_message_obj_);
826 if (thread_local_top_.pending_message_script_ != NULL) {
827 Handle<Script> script(thread_local_top_.pending_message_script_);
828 int start_pos = thread_local_top_.pending_message_start_pos_;
829 int end_pos = thread_local_top_.pending_message_end_pos_;
830 MessageLocation location(script, start_pos, end_pos);
831 MessageHandler::ReportMessage(this, &location, message_obj);
832 } else {
833 MessageHandler::ReportMessage(this, NULL, message_obj);
834 }
835 }
836 }
837 }
838 clear_pending_message();
839 }
840
841
842 void Isolate::TraceException(bool flag) {
843 FLAG_trace_exception = flag; // TODO(isolates): This is an unfortunate use.
844 }
845
846
847 bool Isolate::OptionalRescheduleException(bool is_bottom_call) {
848 ASSERT(has_pending_exception());
849 PropagatePendingExceptionToExternalTryCatch();
850
851 // Allways reschedule out of memory exceptions.
852 if (!is_out_of_memory()) {
853 bool is_termination_exception =
854 pending_exception() == heap_.termination_exception();
855
856 // Do not reschedule the exception if this is the bottom call.
857 bool clear_exception = is_bottom_call;
858
859 if (is_termination_exception) {
860 if (is_bottom_call) {
861 thread_local_top()->external_caught_exception_ = false;
862 clear_pending_exception();
863 return false;
864 }
865 } else if (thread_local_top()->external_caught_exception_) {
866 // If the exception is externally caught, clear it if there are no
867 // JavaScript frames on the way to the C++ frame that has the
868 // external handler.
869 ASSERT(thread_local_top()->try_catch_handler_address() != NULL);
870 Address external_handler_address =
871 thread_local_top()->try_catch_handler_address();
872 JavaScriptFrameIterator it;
873 if (it.done() || (it.frame()->sp() > external_handler_address)) {
874 clear_exception = true;
875 }
876 }
877
878 // Clear the exception if needed.
879 if (clear_exception) {
880 thread_local_top()->external_caught_exception_ = false;
881 clear_pending_exception();
882 return false;
883 }
884 }
885
886 // Reschedule the exception.
887 thread_local_top()->scheduled_exception_ = pending_exception();
888 clear_pending_exception();
889 return true;
890 }
891
892
893 void Isolate::SetCaptureStackTraceForUncaughtExceptions(
894 bool capture,
895 int frame_limit,
896 StackTrace::StackTraceOptions options) {
897 capture_stack_trace_for_uncaught_exceptions_ = capture;
898 stack_trace_for_uncaught_exceptions_frame_limit_ = frame_limit;
899 stack_trace_for_uncaught_exceptions_options_ = options;
900 }
901
902
903 bool Isolate::is_out_of_memory() {
904 if (has_pending_exception()) {
905 MaybeObject* e = pending_exception();
906 if (e->IsFailure() && Failure::cast(e)->IsOutOfMemoryException()) {
907 return true;
908 }
909 }
910 if (has_scheduled_exception()) {
911 MaybeObject* e = scheduled_exception();
912 if (e->IsFailure() && Failure::cast(e)->IsOutOfMemoryException()) {
913 return true;
914 }
915 }
916 return false;
917 }
918
919
920 Handle<Context> Isolate::global_context() {
921 GlobalObject* global = thread_local_top()->context_->global();
922 return Handle<Context>(global->global_context());
923 }
924
925
926 Handle<Context> Isolate::GetCallingGlobalContext() {
927 JavaScriptFrameIterator it;
928 #ifdef ENABLE_DEBUGGER_SUPPORT
929 if (debug_->InDebugger()) {
930 while (!it.done()) {
931 JavaScriptFrame* frame = it.frame();
932 Context* context = Context::cast(frame->context());
933 if (context->global_context() == *debug_->debug_context()) {
934 it.Advance();
935 } else {
936 break;
937 }
938 }
939 }
940 #endif // ENABLE_DEBUGGER_SUPPORT
941 if (it.done()) return Handle<Context>::null();
942 JavaScriptFrame* frame = it.frame();
943 Context* context = Context::cast(frame->context());
944 return Handle<Context>(context->global_context());
945 }
946
947
948 char* Isolate::ArchiveThread(char* to) {
949 if (RuntimeProfiler::IsEnabled() && current_vm_state() == JS) {
950 RuntimeProfiler::IsolateExitedJS(this);
951 }
952 memcpy(to, reinterpret_cast<char*>(thread_local_top()),
953 sizeof(ThreadLocalTop));
954 InitializeThreadLocal();
955 return to + sizeof(ThreadLocalTop);
956 }
957
958
959 char* Isolate::RestoreThread(char* from) {
960 memcpy(reinterpret_cast<char*>(thread_local_top()), from,
961 sizeof(ThreadLocalTop));
962 // This might be just paranoia, but it seems to be needed in case a
963 // thread_local_top_ is restored on a separate OS thread.
964 #ifdef USE_SIMULATOR
965 #ifdef V8_TARGET_ARCH_ARM
966 thread_local_top()->simulator_ = Simulator::current(this);
967 #elif V8_TARGET_ARCH_MIPS
968 thread_local_top()->simulator_ = Simulator::current(this);
969 #endif
970 #endif
971 if (RuntimeProfiler::IsEnabled() && current_vm_state() == JS) {
972 RuntimeProfiler::IsolateEnteredJS(this);
973 }
974 return from + sizeof(ThreadLocalTop);
975 }
976
977 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/isolate.cc ('k') | tools/gyp/v8.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698