blob: 625cc56727d72e9ad3f418fe5dce575c560613f9 [file] [log] [blame]
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001// Copyright 2012 the V8 project authors. All rights reserved.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +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 <stdlib.h>
29
30#include "v8.h"
31
32#include "ast.h"
33#include "bootstrapper.h"
34#include "codegen.h"
35#include "compilation-cache.h"
36#include "debug.h"
37#include "deoptimizer.h"
38#include "heap-profiler.h"
39#include "hydrogen.h"
40#include "isolate.h"
jkummerow@chromium.org1456e702012-03-30 08:38:13 +000041#include "lazy-instance.h"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000042#include "lithium-allocator.h"
43#include "log.h"
vegorov@chromium.org7304bca2011-05-16 12:14:13 +000044#include "messages.h"
jkummerow@chromium.org1456e702012-03-30 08:38:13 +000045#include "platform.h"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000046#include "regexp-stack.h"
47#include "runtime-profiler.h"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000048#include "scopeinfo.h"
49#include "serialize.h"
50#include "simulator.h"
51#include "spaces.h"
52#include "stub-cache.h"
53#include "version.h"
vegorov@chromium.org7304bca2011-05-16 12:14:13 +000054#include "vm-state-inl.h"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000055
56
57namespace v8 {
58namespace internal {
59
jkummerow@chromium.org1456e702012-03-30 08:38:13 +000060struct GlobalState {
61 Thread::LocalStorageKey per_isolate_thread_data_key;
62 Thread::LocalStorageKey isolate_key;
63 Thread::LocalStorageKey thread_id_key;
64 Isolate* default_isolate;
65 Isolate::ThreadDataTable* thread_data_table;
66 Mutex* mutex;
67};
68
69struct InitializeGlobalState {
70 static void Construct(GlobalState* state) {
71 state->isolate_key = Thread::CreateThreadLocalKey();
72 state->thread_id_key = Thread::CreateThreadLocalKey();
73 state->per_isolate_thread_data_key = Thread::CreateThreadLocalKey();
74 state->thread_data_table = new Isolate::ThreadDataTable();
75 state->default_isolate = new Isolate();
76 state->mutex = OS::CreateMutex();
77 // Can't use SetIsolateThreadLocals(default_isolate_, NULL) here
78 // because a non-null thread data may be already set.
79 Thread::SetThreadLocal(state->isolate_key, state->default_isolate);
80 }
81};
82
83static LazyInstance<GlobalState, InitializeGlobalState>::type global_state;
84
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000085Atomic32 ThreadId::highest_thread_id_ = 0;
86
87int ThreadId::AllocateThreadId() {
88 int new_id = NoBarrier_AtomicIncrement(&highest_thread_id_, 1);
89 return new_id;
90}
91
vegorov@chromium.org7304bca2011-05-16 12:14:13 +000092
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000093int ThreadId::GetCurrentThreadId() {
jkummerow@chromium.org1456e702012-03-30 08:38:13 +000094 const GlobalState& global = global_state.Get();
95 int thread_id = Thread::GetThreadLocalInt(global.thread_id_key);
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000096 if (thread_id == 0) {
97 thread_id = AllocateThreadId();
jkummerow@chromium.org1456e702012-03-30 08:38:13 +000098 Thread::SetThreadLocalInt(global.thread_id_key, thread_id);
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000099 }
100 return thread_id;
101}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000102
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000103
104ThreadLocalTop::ThreadLocalTop() {
105 InitializeInternal();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000106 // This flag may be set using v8::V8::IgnoreOutOfMemoryException()
107 // before an isolate is initialized. The initialize methods below do
108 // not touch it to preserve its value.
109 ignore_out_of_memory_ = false;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000110}
111
112
113void ThreadLocalTop::InitializeInternal() {
114 c_entry_fp_ = 0;
115 handler_ = 0;
116#ifdef USE_SIMULATOR
117 simulator_ = NULL;
118#endif
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000119 js_entry_sp_ = NULL;
120 external_callback_ = NULL;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000121 current_vm_state_ = EXTERNAL;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000122 try_catch_handler_address_ = NULL;
123 context_ = NULL;
124 thread_id_ = ThreadId::Invalid();
125 external_caught_exception_ = false;
126 failed_access_check_callback_ = NULL;
127 save_context_ = NULL;
128 catcher_ = NULL;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000129 top_lookup_result_ = NULL;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000130
131 // These members are re-initialized later after deserialization
132 // is complete.
133 pending_exception_ = NULL;
134 has_pending_message_ = false;
135 pending_message_obj_ = NULL;
136 pending_message_script_ = NULL;
137 scheduled_exception_ = NULL;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000138}
139
140
141void ThreadLocalTop::Initialize() {
142 InitializeInternal();
143#ifdef USE_SIMULATOR
144#ifdef V8_TARGET_ARCH_ARM
145 simulator_ = Simulator::current(isolate_);
146#elif V8_TARGET_ARCH_MIPS
147 simulator_ = Simulator::current(isolate_);
148#endif
149#endif
150 thread_id_ = ThreadId::Current();
151}
152
153
154v8::TryCatch* ThreadLocalTop::TryCatchHandler() {
155 return TRY_CATCH_FROM_ADDRESS(try_catch_handler_address());
156}
157
158
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000159// Create a dummy thread that will wait forever on a semaphore. The only
160// purpose for this thread is to have some stack area to save essential data
161// into for use by a stacks only core dump (aka minidump).
162class PreallocatedMemoryThread: public Thread {
163 public:
164 char* data() {
165 if (data_ready_semaphore_ != NULL) {
166 // Initial access is guarded until the data has been published.
167 data_ready_semaphore_->Wait();
168 delete data_ready_semaphore_;
169 data_ready_semaphore_ = NULL;
170 }
171 return data_;
172 }
173
174 unsigned length() {
175 if (data_ready_semaphore_ != NULL) {
176 // Initial access is guarded until the data has been published.
177 data_ready_semaphore_->Wait();
178 delete data_ready_semaphore_;
179 data_ready_semaphore_ = NULL;
180 }
181 return length_;
182 }
183
184 // Stop the PreallocatedMemoryThread and release its resources.
185 void StopThread() {
186 keep_running_ = false;
187 wait_for_ever_semaphore_->Signal();
188
189 // Wait for the thread to terminate.
190 Join();
191
192 if (data_ready_semaphore_ != NULL) {
193 delete data_ready_semaphore_;
194 data_ready_semaphore_ = NULL;
195 }
196
197 delete wait_for_ever_semaphore_;
198 wait_for_ever_semaphore_ = NULL;
199 }
200
201 protected:
202 // When the thread starts running it will allocate a fixed number of bytes
203 // on the stack and publish the location of this memory for others to use.
204 void Run() {
205 EmbeddedVector<char, 15 * 1024> local_buffer;
206
207 // Initialize the buffer with a known good value.
208 OS::StrNCpy(local_buffer, "Trace data was not generated.\n",
209 local_buffer.length());
210
211 // Publish the local buffer and signal its availability.
212 data_ = local_buffer.start();
213 length_ = local_buffer.length();
214 data_ready_semaphore_->Signal();
215
216 while (keep_running_) {
217 // This thread will wait here until the end of time.
218 wait_for_ever_semaphore_->Wait();
219 }
220
221 // Make sure we access the buffer after the wait to remove all possibility
222 // of it being optimized away.
223 OS::StrNCpy(local_buffer, "PreallocatedMemoryThread shutting down.\n",
224 local_buffer.length());
225 }
226
227
228 private:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000229 PreallocatedMemoryThread()
230 : Thread("v8:PreallocMem"),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000231 keep_running_(true),
232 wait_for_ever_semaphore_(OS::CreateSemaphore(0)),
233 data_ready_semaphore_(OS::CreateSemaphore(0)),
234 data_(NULL),
235 length_(0) {
236 }
237
238 // Used to make sure that the thread keeps looping even for spurious wakeups.
239 bool keep_running_;
240
241 // This semaphore is used by the PreallocatedMemoryThread to wait for ever.
242 Semaphore* wait_for_ever_semaphore_;
243 // Semaphore to signal that the data has been initialized.
244 Semaphore* data_ready_semaphore_;
245
246 // Location and size of the preallocated memory block.
247 char* data_;
248 unsigned length_;
249
250 friend class Isolate;
251
252 DISALLOW_COPY_AND_ASSIGN(PreallocatedMemoryThread);
253};
254
255
256void Isolate::PreallocatedMemoryThreadStart() {
257 if (preallocated_memory_thread_ != NULL) return;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000258 preallocated_memory_thread_ = new PreallocatedMemoryThread();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000259 preallocated_memory_thread_->Start();
260}
261
262
263void Isolate::PreallocatedMemoryThreadStop() {
264 if (preallocated_memory_thread_ == NULL) return;
265 preallocated_memory_thread_->StopThread();
266 // Done with the thread entirely.
267 delete preallocated_memory_thread_;
268 preallocated_memory_thread_ = NULL;
269}
270
271
lrn@chromium.org7516f052011-03-30 08:52:27 +0000272void Isolate::PreallocatedStorageInit(size_t size) {
273 ASSERT(free_list_.next_ == &free_list_);
274 ASSERT(free_list_.previous_ == &free_list_);
275 PreallocatedStorage* free_chunk =
276 reinterpret_cast<PreallocatedStorage*>(new char[size]);
277 free_list_.next_ = free_list_.previous_ = free_chunk;
278 free_chunk->next_ = free_chunk->previous_ = &free_list_;
279 free_chunk->size_ = size - sizeof(PreallocatedStorage);
280 preallocated_storage_preallocated_ = true;
281}
282
283
284void* Isolate::PreallocatedStorageNew(size_t size) {
285 if (!preallocated_storage_preallocated_) {
286 return FreeStoreAllocationPolicy::New(size);
287 }
288 ASSERT(free_list_.next_ != &free_list_);
289 ASSERT(free_list_.previous_ != &free_list_);
290
291 size = (size + kPointerSize - 1) & ~(kPointerSize - 1);
292 // Search for exact fit.
293 for (PreallocatedStorage* storage = free_list_.next_;
294 storage != &free_list_;
295 storage = storage->next_) {
296 if (storage->size_ == size) {
297 storage->Unlink();
298 storage->LinkTo(&in_use_list_);
299 return reinterpret_cast<void*>(storage + 1);
300 }
301 }
302 // Search for first fit.
303 for (PreallocatedStorage* storage = free_list_.next_;
304 storage != &free_list_;
305 storage = storage->next_) {
306 if (storage->size_ >= size + sizeof(PreallocatedStorage)) {
307 storage->Unlink();
308 storage->LinkTo(&in_use_list_);
309 PreallocatedStorage* left_over =
310 reinterpret_cast<PreallocatedStorage*>(
311 reinterpret_cast<char*>(storage + 1) + size);
312 left_over->size_ = storage->size_ - size - sizeof(PreallocatedStorage);
313 ASSERT(size + left_over->size_ + sizeof(PreallocatedStorage) ==
314 storage->size_);
315 storage->size_ = size;
316 left_over->LinkTo(&free_list_);
317 return reinterpret_cast<void*>(storage + 1);
318 }
319 }
320 // Allocation failure.
321 ASSERT(false);
322 return NULL;
323}
324
325
326// We don't attempt to coalesce.
327void Isolate::PreallocatedStorageDelete(void* p) {
328 if (p == NULL) {
329 return;
330 }
331 if (!preallocated_storage_preallocated_) {
332 FreeStoreAllocationPolicy::Delete(p);
333 return;
334 }
335 PreallocatedStorage* storage = reinterpret_cast<PreallocatedStorage*>(p) - 1;
336 ASSERT(storage->next_->previous_ == storage);
337 ASSERT(storage->previous_->next_ == storage);
338 storage->Unlink();
339 storage->LinkTo(&free_list_);
340}
341
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000342Isolate::PerIsolateThreadData* Isolate::AllocatePerIsolateThreadData(
343 ThreadId thread_id) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000344 ASSERT(!thread_id.Equals(ThreadId::Invalid()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000345 PerIsolateThreadData* per_thread = new PerIsolateThreadData(this, thread_id);
346 {
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000347 GlobalState* const global = global_state.Pointer();
348 ScopedLock lock(global->mutex);
349 ASSERT(global->thread_data_table->Lookup(this, thread_id) == NULL);
350 global->thread_data_table->Insert(per_thread);
351 ASSERT(global->thread_data_table->Lookup(this, thread_id) == per_thread);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000352 }
353 return per_thread;
354}
355
356
357Isolate::PerIsolateThreadData*
358 Isolate::FindOrAllocatePerThreadDataForThisThread() {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000359 ThreadId thread_id = ThreadId::Current();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000360 PerIsolateThreadData* per_thread = NULL;
361 {
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000362 GlobalState* const global = global_state.Pointer();
363 ScopedLock lock(global->mutex);
364 per_thread = global->thread_data_table->Lookup(this, thread_id);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000365 if (per_thread == NULL) {
366 per_thread = AllocatePerIsolateThreadData(thread_id);
367 }
368 }
369 return per_thread;
370}
371
372
lrn@chromium.org1c092762011-05-09 09:42:16 +0000373Isolate::PerIsolateThreadData* Isolate::FindPerThreadDataForThisThread() {
374 ThreadId thread_id = ThreadId::Current();
375 PerIsolateThreadData* per_thread = NULL;
376 {
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000377 GlobalState* const global = global_state.Pointer();
378 ScopedLock lock(global->mutex);
379 per_thread = global->thread_data_table->Lookup(this, thread_id);
lrn@chromium.org1c092762011-05-09 09:42:16 +0000380 }
381 return per_thread;
382}
383
384
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000385bool Isolate::IsDefaultIsolate() const {
386 return this == global_state.Get().default_isolate;
387}
388
389
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000390void Isolate::EnsureDefaultIsolate() {
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000391 GlobalState* const global = global_state.Pointer();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000392 // Can't use SetIsolateThreadLocals(default_isolate_, NULL) here
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000393 // because a non-null thread data may be already set.
394 if (Thread::GetThreadLocal(global->isolate_key) == NULL) {
395 Thread::SetThreadLocal(global->isolate_key, global->default_isolate);
lrn@chromium.org1c092762011-05-09 09:42:16 +0000396 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000397}
398
399
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +0000400#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000401Debugger* Isolate::GetDefaultIsolateDebugger() {
402 EnsureDefaultIsolate();
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000403 return global_state.Pointer()->default_isolate->debugger();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000404}
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +0000405#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000406
407
408StackGuard* Isolate::GetDefaultIsolateStackGuard() {
409 EnsureDefaultIsolate();
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000410 return global_state.Pointer()->default_isolate->stack_guard();
411}
412
413
414Thread::LocalStorageKey Isolate::isolate_key() {
415 return global_state.Get().isolate_key;
416}
417
418
419Thread::LocalStorageKey Isolate::thread_id_key() {
420 return global_state.Get().thread_id_key;
421}
422
423
424Thread::LocalStorageKey Isolate::per_isolate_thread_data_key() {
425 return global_state.Get().per_isolate_thread_data_key;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000426}
427
428
429void Isolate::EnterDefaultIsolate() {
430 EnsureDefaultIsolate();
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000431 Isolate* const default_isolate = global_state.Pointer()->default_isolate;
432 ASSERT(default_isolate != NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000433
434 PerIsolateThreadData* data = CurrentPerIsolateThreadData();
435 // If not yet in default isolate - enter it.
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000436 if (data == NULL || data->isolate() != default_isolate) {
437 default_isolate->Enter();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000438 }
439}
440
441
442Isolate* Isolate::GetDefaultIsolateForLocking() {
443 EnsureDefaultIsolate();
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000444 return global_state.Pointer()->default_isolate;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000445}
446
447
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000448Address Isolate::get_address_from_id(Isolate::AddressId id) {
449 return isolate_addresses_[id];
450}
451
452
453char* Isolate::Iterate(ObjectVisitor* v, char* thread_storage) {
454 ThreadLocalTop* thread = reinterpret_cast<ThreadLocalTop*>(thread_storage);
455 Iterate(v, thread);
456 return thread_storage + sizeof(ThreadLocalTop);
457}
458
459
460void Isolate::IterateThread(ThreadVisitor* v) {
461 v->VisitThread(this, thread_local_top());
462}
463
464
465void Isolate::IterateThread(ThreadVisitor* v, char* t) {
466 ThreadLocalTop* thread = reinterpret_cast<ThreadLocalTop*>(t);
467 v->VisitThread(this, thread);
468}
469
470
471void Isolate::Iterate(ObjectVisitor* v, ThreadLocalTop* thread) {
472 // Visit the roots from the top for a given thread.
473 Object* pending;
474 // The pending exception can sometimes be a failure. We can't show
475 // that to the GC, which only understands objects.
476 if (thread->pending_exception_->ToObject(&pending)) {
477 v->VisitPointer(&pending);
478 thread->pending_exception_ = pending; // In case GC updated it.
479 }
480 v->VisitPointer(&(thread->pending_message_obj_));
481 v->VisitPointer(BitCast<Object**>(&(thread->pending_message_script_)));
482 v->VisitPointer(BitCast<Object**>(&(thread->context_)));
483 Object* scheduled;
484 if (thread->scheduled_exception_->ToObject(&scheduled)) {
485 v->VisitPointer(&scheduled);
486 thread->scheduled_exception_ = scheduled;
487 }
488
489 for (v8::TryCatch* block = thread->TryCatchHandler();
490 block != NULL;
491 block = TRY_CATCH_FROM_ADDRESS(block->next_)) {
492 v->VisitPointer(BitCast<Object**>(&(block->exception_)));
493 v->VisitPointer(BitCast<Object**>(&(block->message_)));
494 }
495
496 // Iterate over pointers on native execution stack.
497 for (StackFrameIterator it(this, thread); !it.done(); it.Advance()) {
498 it.frame()->Iterate(v);
499 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000500
501 // Iterate pointers in live lookup results.
502 thread->top_lookup_result_->Iterate(v);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000503}
504
505
506void Isolate::Iterate(ObjectVisitor* v) {
507 ThreadLocalTop* current_t = thread_local_top();
508 Iterate(v, current_t);
509}
510
511
512void Isolate::RegisterTryCatchHandler(v8::TryCatch* that) {
513 // The ARM simulator has a separate JS stack. We therefore register
514 // the C++ try catch handler with the simulator and get back an
515 // address that can be used for comparisons with addresses into the
516 // JS stack. When running without the simulator, the address
517 // returned will be the address of the C++ try catch handler itself.
518 Address address = reinterpret_cast<Address>(
519 SimulatorStack::RegisterCTryCatch(reinterpret_cast<uintptr_t>(that)));
520 thread_local_top()->set_try_catch_handler_address(address);
521}
522
523
524void Isolate::UnregisterTryCatchHandler(v8::TryCatch* that) {
525 ASSERT(thread_local_top()->TryCatchHandler() == that);
526 thread_local_top()->set_try_catch_handler_address(
527 reinterpret_cast<Address>(that->next_));
528 thread_local_top()->catcher_ = NULL;
529 SimulatorStack::UnregisterCTryCatch();
530}
531
532
533Handle<String> Isolate::StackTraceString() {
534 if (stack_trace_nesting_level_ == 0) {
535 stack_trace_nesting_level_++;
536 HeapStringAllocator allocator;
537 StringStream::ClearMentionedObjectCache();
538 StringStream accumulator(&allocator);
539 incomplete_message_ = &accumulator;
540 PrintStack(&accumulator);
541 Handle<String> stack_trace = accumulator.ToString();
542 incomplete_message_ = NULL;
543 stack_trace_nesting_level_ = 0;
544 return stack_trace;
545 } else if (stack_trace_nesting_level_ == 1) {
546 stack_trace_nesting_level_++;
547 OS::PrintError(
548 "\n\nAttempt to print stack while printing stack (double fault)\n");
549 OS::PrintError(
550 "If you are lucky you may find a partial stack dump on stdout.\n\n");
551 incomplete_message_->OutputToStdOut();
552 return factory()->empty_symbol();
553 } else {
554 OS::Abort();
555 // Unreachable
556 return factory()->empty_symbol();
557 }
558}
559
560
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +0000561void Isolate::CaptureAndSetCurrentStackTraceFor(Handle<JSObject> error_object) {
562 if (capture_stack_trace_for_uncaught_exceptions_) {
563 // Capture stack trace for a detailed exception message.
564 Handle<String> key = factory()->hidden_stack_trace_symbol();
565 Handle<JSArray> stack_trace = CaptureCurrentStackTrace(
566 stack_trace_for_uncaught_exceptions_frame_limit_,
567 stack_trace_for_uncaught_exceptions_options_);
568 JSObject::SetHiddenProperty(error_object, key, stack_trace);
569 }
570}
571
572
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000573Handle<JSArray> Isolate::CaptureCurrentStackTrace(
574 int frame_limit, StackTrace::StackTraceOptions options) {
575 // Ensure no negative values.
576 int limit = Max(frame_limit, 0);
577 Handle<JSArray> stack_trace = factory()->NewJSArray(frame_limit);
578
579 Handle<String> column_key = factory()->LookupAsciiSymbol("column");
580 Handle<String> line_key = factory()->LookupAsciiSymbol("lineNumber");
581 Handle<String> script_key = factory()->LookupAsciiSymbol("scriptName");
582 Handle<String> name_or_source_url_key =
583 factory()->LookupAsciiSymbol("nameOrSourceURL");
584 Handle<String> script_name_or_source_url_key =
585 factory()->LookupAsciiSymbol("scriptNameOrSourceURL");
586 Handle<String> function_key = factory()->LookupAsciiSymbol("functionName");
587 Handle<String> eval_key = factory()->LookupAsciiSymbol("isEval");
588 Handle<String> constructor_key =
589 factory()->LookupAsciiSymbol("isConstructor");
590
591 StackTraceFrameIterator it(this);
592 int frames_seen = 0;
593 while (!it.done() && (frames_seen < limit)) {
594 JavaScriptFrame* frame = it.frame();
595 // Set initial size to the maximum inlining level + 1 for the outermost
596 // function.
597 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
598 frame->Summarize(&frames);
599 for (int i = frames.length() - 1; i >= 0 && frames_seen < limit; i--) {
600 // Create a JSObject to hold the information for the StackFrame.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000601 Handle<JSObject> stack_frame = factory()->NewJSObject(object_function());
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000602
603 Handle<JSFunction> fun = frames[i].function();
604 Handle<Script> script(Script::cast(fun->shared()->script()));
605
606 if (options & StackTrace::kLineNumber) {
607 int script_line_offset = script->line_offset()->value();
608 int position = frames[i].code()->SourcePosition(frames[i].pc());
609 int line_number = GetScriptLineNumber(script, position);
610 // line_number is already shifted by the script_line_offset.
611 int relative_line_number = line_number - script_line_offset;
612 if (options & StackTrace::kColumnOffset && relative_line_number >= 0) {
613 Handle<FixedArray> line_ends(FixedArray::cast(script->line_ends()));
614 int start = (relative_line_number == 0) ? 0 :
615 Smi::cast(line_ends->get(relative_line_number - 1))->value() + 1;
616 int column_offset = position - start;
617 if (relative_line_number == 0) {
618 // For the case where the code is on the same line as the script
619 // tag.
620 column_offset += script->column_offset()->value();
621 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000622 CHECK_NOT_EMPTY_HANDLE(
623 this,
624 JSObject::SetLocalPropertyIgnoreAttributes(
625 stack_frame, column_key,
626 Handle<Smi>(Smi::FromInt(column_offset + 1)), NONE));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000627 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000628 CHECK_NOT_EMPTY_HANDLE(
629 this,
630 JSObject::SetLocalPropertyIgnoreAttributes(
631 stack_frame, line_key,
632 Handle<Smi>(Smi::FromInt(line_number + 1)), NONE));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000633 }
634
635 if (options & StackTrace::kScriptName) {
636 Handle<Object> script_name(script->name(), this);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000637 CHECK_NOT_EMPTY_HANDLE(this,
638 JSObject::SetLocalPropertyIgnoreAttributes(
639 stack_frame, script_key, script_name, NONE));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000640 }
641
642 if (options & StackTrace::kScriptNameOrSourceURL) {
643 Handle<Object> script_name(script->name(), this);
644 Handle<JSValue> script_wrapper = GetScriptWrapper(script);
645 Handle<Object> property = GetProperty(script_wrapper,
646 name_or_source_url_key);
647 ASSERT(property->IsJSFunction());
648 Handle<JSFunction> method = Handle<JSFunction>::cast(property);
649 bool caught_exception;
650 Handle<Object> result = Execution::TryCall(method, script_wrapper, 0,
651 NULL, &caught_exception);
652 if (caught_exception) {
653 result = factory()->undefined_value();
654 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000655 CHECK_NOT_EMPTY_HANDLE(this,
656 JSObject::SetLocalPropertyIgnoreAttributes(
657 stack_frame, script_name_or_source_url_key,
658 result, NONE));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000659 }
660
661 if (options & StackTrace::kFunctionName) {
662 Handle<Object> fun_name(fun->shared()->name(), this);
663 if (fun_name->ToBoolean()->IsFalse()) {
664 fun_name = Handle<Object>(fun->shared()->inferred_name(), this);
665 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000666 CHECK_NOT_EMPTY_HANDLE(this,
667 JSObject::SetLocalPropertyIgnoreAttributes(
668 stack_frame, function_key, fun_name, NONE));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000669 }
670
671 if (options & StackTrace::kIsEval) {
672 int type = Smi::cast(script->compilation_type())->value();
673 Handle<Object> is_eval = (type == Script::COMPILATION_TYPE_EVAL) ?
674 factory()->true_value() : factory()->false_value();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000675 CHECK_NOT_EMPTY_HANDLE(this,
676 JSObject::SetLocalPropertyIgnoreAttributes(
677 stack_frame, eval_key, is_eval, NONE));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000678 }
679
680 if (options & StackTrace::kIsConstructor) {
681 Handle<Object> is_constructor = (frames[i].is_constructor()) ?
682 factory()->true_value() : factory()->false_value();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000683 CHECK_NOT_EMPTY_HANDLE(this,
684 JSObject::SetLocalPropertyIgnoreAttributes(
685 stack_frame, constructor_key,
686 is_constructor, NONE));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000687 }
688
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000689 FixedArray::cast(stack_trace->elements())->set(frames_seen, *stack_frame);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000690 frames_seen++;
691 }
692 it.Advance();
693 }
694
695 stack_trace->set_length(Smi::FromInt(frames_seen));
696 return stack_trace;
697}
698
699
700void Isolate::PrintStack() {
701 if (stack_trace_nesting_level_ == 0) {
702 stack_trace_nesting_level_++;
703
704 StringAllocator* allocator;
705 if (preallocated_message_space_ == NULL) {
706 allocator = new HeapStringAllocator();
707 } else {
708 allocator = preallocated_message_space_;
709 }
710
711 StringStream::ClearMentionedObjectCache();
712 StringStream accumulator(allocator);
713 incomplete_message_ = &accumulator;
714 PrintStack(&accumulator);
715 accumulator.OutputToStdOut();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000716 InitializeLoggingAndCounters();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000717 accumulator.Log();
718 incomplete_message_ = NULL;
719 stack_trace_nesting_level_ = 0;
720 if (preallocated_message_space_ == NULL) {
721 // Remove the HeapStringAllocator created above.
722 delete allocator;
723 }
724 } else if (stack_trace_nesting_level_ == 1) {
725 stack_trace_nesting_level_++;
726 OS::PrintError(
727 "\n\nAttempt to print stack while printing stack (double fault)\n");
728 OS::PrintError(
729 "If you are lucky you may find a partial stack dump on stdout.\n\n");
730 incomplete_message_->OutputToStdOut();
731 }
732}
733
734
735static void PrintFrames(StringStream* accumulator,
736 StackFrame::PrintMode mode) {
737 StackFrameIterator it;
738 for (int i = 0; !it.done(); it.Advance()) {
739 it.frame()->Print(accumulator, mode, i++);
740 }
741}
742
743
744void Isolate::PrintStack(StringStream* accumulator) {
745 if (!IsInitialized()) {
746 accumulator->Add(
747 "\n==== Stack trace is not available ==========================\n\n");
748 accumulator->Add(
749 "\n==== Isolate for the thread is not initialized =============\n\n");
750 return;
751 }
752 // The MentionedObjectCache is not GC-proof at the moment.
753 AssertNoAllocation nogc;
754 ASSERT(StringStream::IsMentionedObjectCacheClear());
755
756 // Avoid printing anything if there are no frames.
757 if (c_entry_fp(thread_local_top()) == 0) return;
758
759 accumulator->Add(
760 "\n==== Stack trace ============================================\n\n");
761 PrintFrames(accumulator, StackFrame::OVERVIEW);
762
763 accumulator->Add(
764 "\n==== Details ================================================\n\n");
765 PrintFrames(accumulator, StackFrame::DETAILS);
766
767 accumulator->PrintMentionedObjectCache();
768 accumulator->Add("=====================\n\n");
769}
770
771
772void Isolate::SetFailedAccessCheckCallback(
773 v8::FailedAccessCheckCallback callback) {
774 thread_local_top()->failed_access_check_callback_ = callback;
775}
776
777
778void Isolate::ReportFailedAccessCheck(JSObject* receiver, v8::AccessType type) {
779 if (!thread_local_top()->failed_access_check_callback_) return;
780
781 ASSERT(receiver->IsAccessCheckNeeded());
782 ASSERT(context());
783
784 // Get the data object from access check info.
785 JSFunction* constructor = JSFunction::cast(receiver->map()->constructor());
786 if (!constructor->shared()->IsApiFunction()) return;
787 Object* data_obj =
788 constructor->shared()->get_api_func_data()->access_check_info();
789 if (data_obj == heap_.undefined_value()) return;
790
791 HandleScope scope;
792 Handle<JSObject> receiver_handle(receiver);
793 Handle<Object> data(AccessCheckInfo::cast(data_obj)->data());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000794 { VMState state(this, EXTERNAL);
795 thread_local_top()->failed_access_check_callback_(
796 v8::Utils::ToLocal(receiver_handle),
797 type,
798 v8::Utils::ToLocal(data));
799 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000800}
801
802
803enum MayAccessDecision {
804 YES, NO, UNKNOWN
805};
806
807
808static MayAccessDecision MayAccessPreCheck(Isolate* isolate,
809 JSObject* receiver,
810 v8::AccessType type) {
811 // During bootstrapping, callback functions are not enabled yet.
812 if (isolate->bootstrapper()->IsActive()) return YES;
813
814 if (receiver->IsJSGlobalProxy()) {
815 Object* receiver_context = JSGlobalProxy::cast(receiver)->context();
816 if (!receiver_context->IsContext()) return NO;
817
818 // Get the global context of current top context.
819 // avoid using Isolate::global_context() because it uses Handle.
820 Context* global_context = isolate->context()->global()->global_context();
821 if (receiver_context == global_context) return YES;
822
823 if (Context::cast(receiver_context)->security_token() ==
824 global_context->security_token())
825 return YES;
826 }
827
828 return UNKNOWN;
829}
830
831
832bool Isolate::MayNamedAccess(JSObject* receiver, Object* key,
833 v8::AccessType type) {
834 ASSERT(receiver->IsAccessCheckNeeded());
835
836 // The callers of this method are not expecting a GC.
837 AssertNoAllocation no_gc;
838
839 // Skip checks for hidden properties access. Note, we do not
840 // require existence of a context in this case.
841 if (key == heap_.hidden_symbol()) return true;
842
843 // Check for compatibility between the security tokens in the
844 // current lexical context and the accessed object.
845 ASSERT(context());
846
847 MayAccessDecision decision = MayAccessPreCheck(this, receiver, type);
848 if (decision != UNKNOWN) return decision == YES;
849
850 // Get named access check callback
851 JSFunction* constructor = JSFunction::cast(receiver->map()->constructor());
852 if (!constructor->shared()->IsApiFunction()) return false;
853
854 Object* data_obj =
855 constructor->shared()->get_api_func_data()->access_check_info();
856 if (data_obj == heap_.undefined_value()) return false;
857
858 Object* fun_obj = AccessCheckInfo::cast(data_obj)->named_callback();
859 v8::NamedSecurityCallback callback =
860 v8::ToCData<v8::NamedSecurityCallback>(fun_obj);
861
862 if (!callback) return false;
863
864 HandleScope scope(this);
865 Handle<JSObject> receiver_handle(receiver, this);
866 Handle<Object> key_handle(key, this);
867 Handle<Object> data(AccessCheckInfo::cast(data_obj)->data(), this);
868 LOG(this, ApiNamedSecurityCheck(key));
869 bool result = false;
870 {
871 // Leaving JavaScript.
872 VMState state(this, EXTERNAL);
873 result = callback(v8::Utils::ToLocal(receiver_handle),
874 v8::Utils::ToLocal(key_handle),
875 type,
876 v8::Utils::ToLocal(data));
877 }
878 return result;
879}
880
881
882bool Isolate::MayIndexedAccess(JSObject* receiver,
883 uint32_t index,
884 v8::AccessType type) {
885 ASSERT(receiver->IsAccessCheckNeeded());
886 // Check for compatibility between the security tokens in the
887 // current lexical context and the accessed object.
888 ASSERT(context());
889
890 MayAccessDecision decision = MayAccessPreCheck(this, receiver, type);
891 if (decision != UNKNOWN) return decision == YES;
892
893 // Get indexed access check callback
894 JSFunction* constructor = JSFunction::cast(receiver->map()->constructor());
895 if (!constructor->shared()->IsApiFunction()) return false;
896
897 Object* data_obj =
898 constructor->shared()->get_api_func_data()->access_check_info();
899 if (data_obj == heap_.undefined_value()) return false;
900
901 Object* fun_obj = AccessCheckInfo::cast(data_obj)->indexed_callback();
902 v8::IndexedSecurityCallback callback =
903 v8::ToCData<v8::IndexedSecurityCallback>(fun_obj);
904
905 if (!callback) return false;
906
907 HandleScope scope(this);
908 Handle<JSObject> receiver_handle(receiver, this);
909 Handle<Object> data(AccessCheckInfo::cast(data_obj)->data(), this);
910 LOG(this, ApiIndexedSecurityCheck(index));
911 bool result = false;
912 {
913 // Leaving JavaScript.
914 VMState state(this, EXTERNAL);
915 result = callback(v8::Utils::ToLocal(receiver_handle),
916 index,
917 type,
918 v8::Utils::ToLocal(data));
919 }
920 return result;
921}
922
923
924const char* const Isolate::kStackOverflowMessage =
925 "Uncaught RangeError: Maximum call stack size exceeded";
926
927
928Failure* Isolate::StackOverflow() {
929 HandleScope scope;
930 Handle<String> key = factory()->stack_overflow_symbol();
931 Handle<JSObject> boilerplate =
932 Handle<JSObject>::cast(GetProperty(js_builtins_object(), key));
933 Handle<Object> exception = Copy(boilerplate);
934 // TODO(1240995): To avoid having to call JavaScript code to compute
935 // the message for stack overflow exceptions which is very likely to
936 // double fault with another stack overflow exception, we use a
937 // precomputed message.
938 DoThrow(*exception, NULL);
939 return Failure::Exception();
940}
941
942
943Failure* Isolate::TerminateExecution() {
944 DoThrow(heap_.termination_exception(), NULL);
945 return Failure::Exception();
946}
947
948
949Failure* Isolate::Throw(Object* exception, MessageLocation* location) {
950 DoThrow(exception, location);
951 return Failure::Exception();
952}
953
954
955Failure* Isolate::ReThrow(MaybeObject* exception, MessageLocation* location) {
956 bool can_be_caught_externally = false;
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000957 bool catchable_by_javascript = is_catchable_by_javascript(exception);
958 ShouldReportException(&can_be_caught_externally, catchable_by_javascript);
959
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000960 thread_local_top()->catcher_ = can_be_caught_externally ?
961 try_catch_handler() : NULL;
962
963 // Set the exception being re-thrown.
964 set_pending_exception(exception);
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000965 if (exception->IsFailure()) return exception->ToFailureUnchecked();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000966 return Failure::Exception();
967}
968
969
970Failure* Isolate::ThrowIllegalOperation() {
971 return Throw(heap_.illegal_access_symbol());
972}
973
974
975void Isolate::ScheduleThrow(Object* exception) {
976 // When scheduling a throw we first throw the exception to get the
977 // error reporting if it is uncaught before rescheduling it.
978 Throw(exception);
979 thread_local_top()->scheduled_exception_ = pending_exception();
980 thread_local_top()->external_caught_exception_ = false;
981 clear_pending_exception();
982}
983
984
985Failure* Isolate::PromoteScheduledException() {
986 MaybeObject* thrown = scheduled_exception();
987 clear_scheduled_exception();
988 // Re-throw the exception to avoid getting repeated error reporting.
989 return ReThrow(thrown);
990}
991
992
993void Isolate::PrintCurrentStackTrace(FILE* out) {
994 StackTraceFrameIterator it(this);
995 while (!it.done()) {
996 HandleScope scope;
997 // Find code position if recorded in relocation info.
998 JavaScriptFrame* frame = it.frame();
999 int pos = frame->LookupCode()->SourcePosition(frame->pc());
1000 Handle<Object> pos_obj(Smi::FromInt(pos));
1001 // Fetch function and receiver.
1002 Handle<JSFunction> fun(JSFunction::cast(frame->function()));
1003 Handle<Object> recv(frame->receiver());
1004 // Advance to the next JavaScript frame and determine if the
1005 // current frame is the top-level frame.
1006 it.Advance();
1007 Handle<Object> is_top_level = it.done()
1008 ? factory()->true_value()
1009 : factory()->false_value();
1010 // Generate and print stack trace line.
1011 Handle<String> line =
1012 Execution::GetStackTraceLine(recv, fun, pos_obj, is_top_level);
1013 if (line->length() > 0) {
1014 line->PrintOn(out);
1015 fprintf(out, "\n");
1016 }
1017 }
1018}
1019
1020
1021void Isolate::ComputeLocation(MessageLocation* target) {
1022 *target = MessageLocation(Handle<Script>(heap_.empty_script()), -1, -1);
1023 StackTraceFrameIterator it(this);
1024 if (!it.done()) {
1025 JavaScriptFrame* frame = it.frame();
1026 JSFunction* fun = JSFunction::cast(frame->function());
1027 Object* script = fun->shared()->script();
1028 if (script->IsScript() &&
1029 !(Script::cast(script)->source()->IsUndefined())) {
1030 int pos = frame->LookupCode()->SourcePosition(frame->pc());
1031 // Compute the location from the function and the reloc info.
1032 Handle<Script> casted_script(Script::cast(script));
1033 *target = MessageLocation(casted_script, pos, pos + 1);
1034 }
1035 }
1036}
1037
1038
1039bool Isolate::ShouldReportException(bool* can_be_caught_externally,
1040 bool catchable_by_javascript) {
1041 // Find the top-most try-catch handler.
1042 StackHandler* handler =
1043 StackHandler::FromAddress(Isolate::handler(thread_local_top()));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001044 while (handler != NULL && !handler->is_catch()) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001045 handler = handler->next();
1046 }
1047
1048 // Get the address of the external handler so we can compare the address to
1049 // determine which one is closer to the top of the stack.
1050 Address external_handler_address =
1051 thread_local_top()->try_catch_handler_address();
1052
1053 // The exception has been externally caught if and only if there is
1054 // an external handler which is on top of the top-most try-catch
1055 // handler.
1056 *can_be_caught_externally = external_handler_address != NULL &&
1057 (handler == NULL || handler->address() > external_handler_address ||
1058 !catchable_by_javascript);
1059
1060 if (*can_be_caught_externally) {
1061 // Only report the exception if the external handler is verbose.
1062 return try_catch_handler()->is_verbose_;
1063 } else {
1064 // Report the exception if it isn't caught by JavaScript code.
1065 return handler == NULL;
1066 }
1067}
1068
1069
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +00001070bool Isolate::IsErrorObject(Handle<Object> obj) {
1071 if (!obj->IsJSObject()) return false;
1072
1073 String* error_key = *(factory()->LookupAsciiSymbol("$Error"));
1074 Object* error_constructor =
1075 js_builtins_object()->GetPropertyNoExceptionThrown(error_key);
1076
1077 for (Object* prototype = *obj; !prototype->IsNull();
1078 prototype = prototype->GetPrototype()) {
1079 if (!prototype->IsJSObject()) return false;
1080 if (JSObject::cast(prototype)->map()->constructor() == error_constructor) {
1081 return true;
1082 }
1083 }
1084 return false;
1085}
1086
1087
1088void Isolate::DoThrow(Object* exception, MessageLocation* location) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001089 ASSERT(!has_pending_exception());
1090
1091 HandleScope scope;
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +00001092 Handle<Object> exception_handle(exception);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001093
1094 // Determine reporting and whether the exception is caught externally.
1095 bool catchable_by_javascript = is_catchable_by_javascript(exception);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001096 bool can_be_caught_externally = false;
1097 bool should_report_exception =
1098 ShouldReportException(&can_be_caught_externally, catchable_by_javascript);
1099 bool report_exception = catchable_by_javascript && should_report_exception;
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +00001100 bool try_catch_needs_message =
1101 can_be_caught_externally && try_catch_handler()->capture_message_;
1102 bool bootstrapping = bootstrapper()->IsActive();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001103
1104#ifdef ENABLE_DEBUGGER_SUPPORT
1105 // Notify debugger of exception.
1106 if (catchable_by_javascript) {
1107 debugger_->OnException(exception_handle, report_exception);
1108 }
1109#endif
1110
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +00001111 // Generate the message if required.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001112 if (report_exception || try_catch_needs_message) {
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +00001113 MessageLocation potential_computed_location;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001114 if (location == NULL) {
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +00001115 // If no location was specified we use a computed one instead.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001116 ComputeLocation(&potential_computed_location);
1117 location = &potential_computed_location;
1118 }
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +00001119 // It's not safe to try to make message objects or collect stack traces
1120 // while the bootstrapper is active since the infrastructure may not have
1121 // been properly initialized.
1122 if (!bootstrapping) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001123 Handle<String> stack_trace;
1124 if (FLAG_trace_exception) stack_trace = StackTraceString();
1125 Handle<JSArray> stack_trace_object;
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +00001126 if (capture_stack_trace_for_uncaught_exceptions_) {
1127 if (IsErrorObject(exception_handle)) {
1128 // We fetch the stack trace that corresponds to this error object.
1129 String* key = heap()->hidden_stack_trace_symbol();
1130 Object* stack_property =
1131 JSObject::cast(*exception_handle)->GetHiddenProperty(key);
1132 // Property lookup may have failed. In this case it's probably not
1133 // a valid Error object.
1134 if (stack_property->IsJSArray()) {
1135 stack_trace_object = Handle<JSArray>(JSArray::cast(stack_property));
1136 }
1137 }
1138 if (stack_trace_object.is_null()) {
1139 // Not an error object, we capture at throw site.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001140 stack_trace_object = CaptureCurrentStackTrace(
1141 stack_trace_for_uncaught_exceptions_frame_limit_,
1142 stack_trace_for_uncaught_exceptions_options_);
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +00001143 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001144 }
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +00001145 Handle<Object> message_obj = MessageHandler::MakeMessageObject(
1146 "uncaught_exception",
1147 location,
1148 HandleVector<Object>(&exception_handle, 1),
1149 stack_trace,
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001150 stack_trace_object);
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +00001151 thread_local_top()->pending_message_obj_ = *message_obj;
1152 if (location != NULL) {
1153 thread_local_top()->pending_message_script_ = *location->script();
1154 thread_local_top()->pending_message_start_pos_ = location->start_pos();
1155 thread_local_top()->pending_message_end_pos_ = location->end_pos();
1156 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001157 } else if (location != NULL && !location->script().is_null()) {
1158 // We are bootstrapping and caught an error where the location is set
1159 // and we have a script for the location.
1160 // In this case we could have an extension (or an internal error
1161 // somewhere) and we print out the line number at which the error occured
1162 // to the console for easier debugging.
1163 int line_number = GetScriptLineNumberSafe(location->script(),
1164 location->start_pos());
1165 OS::PrintError("Extension or internal compilation error at line %d.\n",
1166 line_number);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001167 }
1168 }
1169
1170 // Save the message for reporting if the the exception remains uncaught.
1171 thread_local_top()->has_pending_message_ = report_exception;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001172
1173 // Do not forget to clean catcher_ if currently thrown exception cannot
1174 // be caught. If necessary, ReThrow will update the catcher.
1175 thread_local_top()->catcher_ = can_be_caught_externally ?
1176 try_catch_handler() : NULL;
1177
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +00001178 set_pending_exception(*exception_handle);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001179}
1180
1181
1182bool Isolate::IsExternallyCaught() {
1183 ASSERT(has_pending_exception());
1184
1185 if ((thread_local_top()->catcher_ == NULL) ||
1186 (try_catch_handler() != thread_local_top()->catcher_)) {
1187 // When throwing the exception, we found no v8::TryCatch
1188 // which should care about this exception.
1189 return false;
1190 }
1191
1192 if (!is_catchable_by_javascript(pending_exception())) {
1193 return true;
1194 }
1195
1196 // Get the address of the external handler so we can compare the address to
1197 // determine which one is closer to the top of the stack.
1198 Address external_handler_address =
1199 thread_local_top()->try_catch_handler_address();
1200 ASSERT(external_handler_address != NULL);
1201
1202 // The exception has been externally caught if and only if there is
1203 // an external handler which is on top of the top-most try-finally
1204 // handler.
1205 // There should be no try-catch blocks as they would prohibit us from
1206 // finding external catcher in the first place (see catcher_ check above).
1207 //
1208 // Note, that finally clause would rethrow an exception unless it's
1209 // aborted by jumps in control flow like return, break, etc. and we'll
1210 // have another chances to set proper v8::TryCatch.
1211 StackHandler* handler =
1212 StackHandler::FromAddress(Isolate::handler(thread_local_top()));
1213 while (handler != NULL && handler->address() < external_handler_address) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001214 ASSERT(!handler->is_catch());
1215 if (handler->is_finally()) return false;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001216
1217 handler = handler->next();
1218 }
1219
1220 return true;
1221}
1222
1223
1224void Isolate::ReportPendingMessages() {
1225 ASSERT(has_pending_exception());
1226 PropagatePendingExceptionToExternalTryCatch();
1227
1228 // If the pending exception is OutOfMemoryException set out_of_memory in
1229 // the global context. Note: We have to mark the global context here
1230 // since the GenerateThrowOutOfMemory stub cannot make a RuntimeCall to
1231 // set it.
1232 HandleScope scope;
1233 if (thread_local_top_.pending_exception_ == Failure::OutOfMemoryException()) {
1234 context()->mark_out_of_memory();
1235 } else if (thread_local_top_.pending_exception_ ==
1236 heap()->termination_exception()) {
1237 // Do nothing: if needed, the exception has been already propagated to
1238 // v8::TryCatch.
1239 } else {
1240 if (thread_local_top_.has_pending_message_) {
1241 thread_local_top_.has_pending_message_ = false;
1242 if (!thread_local_top_.pending_message_obj_->IsTheHole()) {
1243 HandleScope scope;
1244 Handle<Object> message_obj(thread_local_top_.pending_message_obj_);
1245 if (thread_local_top_.pending_message_script_ != NULL) {
1246 Handle<Script> script(thread_local_top_.pending_message_script_);
1247 int start_pos = thread_local_top_.pending_message_start_pos_;
1248 int end_pos = thread_local_top_.pending_message_end_pos_;
1249 MessageLocation location(script, start_pos, end_pos);
1250 MessageHandler::ReportMessage(this, &location, message_obj);
1251 } else {
1252 MessageHandler::ReportMessage(this, NULL, message_obj);
1253 }
1254 }
1255 }
1256 }
1257 clear_pending_message();
1258}
1259
1260
1261void Isolate::TraceException(bool flag) {
1262 FLAG_trace_exception = flag; // TODO(isolates): This is an unfortunate use.
1263}
1264
1265
1266bool Isolate::OptionalRescheduleException(bool is_bottom_call) {
1267 ASSERT(has_pending_exception());
1268 PropagatePendingExceptionToExternalTryCatch();
1269
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001270 // Always reschedule out of memory exceptions.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001271 if (!is_out_of_memory()) {
1272 bool is_termination_exception =
1273 pending_exception() == heap_.termination_exception();
1274
1275 // Do not reschedule the exception if this is the bottom call.
1276 bool clear_exception = is_bottom_call;
1277
1278 if (is_termination_exception) {
1279 if (is_bottom_call) {
1280 thread_local_top()->external_caught_exception_ = false;
1281 clear_pending_exception();
1282 return false;
1283 }
1284 } else if (thread_local_top()->external_caught_exception_) {
1285 // If the exception is externally caught, clear it if there are no
1286 // JavaScript frames on the way to the C++ frame that has the
1287 // external handler.
1288 ASSERT(thread_local_top()->try_catch_handler_address() != NULL);
1289 Address external_handler_address =
1290 thread_local_top()->try_catch_handler_address();
1291 JavaScriptFrameIterator it;
1292 if (it.done() || (it.frame()->sp() > external_handler_address)) {
1293 clear_exception = true;
1294 }
1295 }
1296
1297 // Clear the exception if needed.
1298 if (clear_exception) {
1299 thread_local_top()->external_caught_exception_ = false;
1300 clear_pending_exception();
1301 return false;
1302 }
1303 }
1304
1305 // Reschedule the exception.
1306 thread_local_top()->scheduled_exception_ = pending_exception();
1307 clear_pending_exception();
1308 return true;
1309}
1310
1311
1312void Isolate::SetCaptureStackTraceForUncaughtExceptions(
1313 bool capture,
1314 int frame_limit,
1315 StackTrace::StackTraceOptions options) {
1316 capture_stack_trace_for_uncaught_exceptions_ = capture;
1317 stack_trace_for_uncaught_exceptions_frame_limit_ = frame_limit;
1318 stack_trace_for_uncaught_exceptions_options_ = options;
1319}
1320
1321
1322bool Isolate::is_out_of_memory() {
1323 if (has_pending_exception()) {
1324 MaybeObject* e = pending_exception();
1325 if (e->IsFailure() && Failure::cast(e)->IsOutOfMemoryException()) {
1326 return true;
1327 }
1328 }
1329 if (has_scheduled_exception()) {
1330 MaybeObject* e = scheduled_exception();
1331 if (e->IsFailure() && Failure::cast(e)->IsOutOfMemoryException()) {
1332 return true;
1333 }
1334 }
1335 return false;
1336}
1337
1338
1339Handle<Context> Isolate::global_context() {
1340 GlobalObject* global = thread_local_top()->context_->global();
1341 return Handle<Context>(global->global_context());
1342}
1343
1344
1345Handle<Context> Isolate::GetCallingGlobalContext() {
1346 JavaScriptFrameIterator it;
1347#ifdef ENABLE_DEBUGGER_SUPPORT
1348 if (debug_->InDebugger()) {
1349 while (!it.done()) {
1350 JavaScriptFrame* frame = it.frame();
1351 Context* context = Context::cast(frame->context());
1352 if (context->global_context() == *debug_->debug_context()) {
1353 it.Advance();
1354 } else {
1355 break;
1356 }
1357 }
1358 }
1359#endif // ENABLE_DEBUGGER_SUPPORT
1360 if (it.done()) return Handle<Context>::null();
1361 JavaScriptFrame* frame = it.frame();
1362 Context* context = Context::cast(frame->context());
1363 return Handle<Context>(context->global_context());
1364}
1365
1366
1367char* Isolate::ArchiveThread(char* to) {
1368 if (RuntimeProfiler::IsEnabled() && current_vm_state() == JS) {
1369 RuntimeProfiler::IsolateExitedJS(this);
1370 }
1371 memcpy(to, reinterpret_cast<char*>(thread_local_top()),
1372 sizeof(ThreadLocalTop));
1373 InitializeThreadLocal();
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001374 clear_pending_exception();
1375 clear_pending_message();
1376 clear_scheduled_exception();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001377 return to + sizeof(ThreadLocalTop);
1378}
1379
1380
1381char* Isolate::RestoreThread(char* from) {
1382 memcpy(reinterpret_cast<char*>(thread_local_top()), from,
1383 sizeof(ThreadLocalTop));
1384 // This might be just paranoia, but it seems to be needed in case a
1385 // thread_local_top_ is restored on a separate OS thread.
1386#ifdef USE_SIMULATOR
1387#ifdef V8_TARGET_ARCH_ARM
1388 thread_local_top()->simulator_ = Simulator::current(this);
1389#elif V8_TARGET_ARCH_MIPS
1390 thread_local_top()->simulator_ = Simulator::current(this);
1391#endif
1392#endif
1393 if (RuntimeProfiler::IsEnabled() && current_vm_state() == JS) {
1394 RuntimeProfiler::IsolateEnteredJS(this);
1395 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00001396 ASSERT(context() == NULL || context()->IsContext());
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001397 return from + sizeof(ThreadLocalTop);
1398}
1399
1400
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001401Isolate::ThreadDataTable::ThreadDataTable()
1402 : list_(NULL) {
1403}
1404
1405
1406Isolate::PerIsolateThreadData*
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001407 Isolate::ThreadDataTable::Lookup(Isolate* isolate,
1408 ThreadId thread_id) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001409 for (PerIsolateThreadData* data = list_; data != NULL; data = data->next_) {
1410 if (data->Matches(isolate, thread_id)) return data;
1411 }
1412 return NULL;
1413}
1414
1415
1416void Isolate::ThreadDataTable::Insert(Isolate::PerIsolateThreadData* data) {
1417 if (list_ != NULL) list_->prev_ = data;
1418 data->next_ = list_;
1419 list_ = data;
1420}
1421
1422
1423void Isolate::ThreadDataTable::Remove(PerIsolateThreadData* data) {
1424 if (list_ == data) list_ = data->next_;
1425 if (data->next_ != NULL) data->next_->prev_ = data->prev_;
1426 if (data->prev_ != NULL) data->prev_->next_ = data->next_;
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001427 delete data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001428}
1429
1430
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001431void Isolate::ThreadDataTable::Remove(Isolate* isolate,
1432 ThreadId thread_id) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001433 PerIsolateThreadData* data = Lookup(isolate, thread_id);
1434 if (data != NULL) {
1435 Remove(data);
1436 }
1437}
1438
1439
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00001440void Isolate::ThreadDataTable::RemoveAllThreads(Isolate* isolate) {
1441 PerIsolateThreadData* data = list_;
1442 while (data != NULL) {
1443 PerIsolateThreadData* next = data->next_;
1444 if (data->isolate() == isolate) Remove(data);
1445 data = next;
1446 }
1447}
1448
1449
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001450#ifdef DEBUG
1451#define TRACE_ISOLATE(tag) \
1452 do { \
1453 if (FLAG_trace_isolates) { \
1454 PrintF("Isolate %p " #tag "\n", reinterpret_cast<void*>(this)); \
1455 } \
1456 } while (false)
1457#else
1458#define TRACE_ISOLATE(tag)
1459#endif
1460
1461
1462Isolate::Isolate()
1463 : state_(UNINITIALIZED),
1464 entry_stack_(NULL),
1465 stack_trace_nesting_level_(0),
1466 incomplete_message_(NULL),
1467 preallocated_memory_thread_(NULL),
1468 preallocated_message_space_(NULL),
1469 bootstrapper_(NULL),
1470 runtime_profiler_(NULL),
1471 compilation_cache_(NULL),
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001472 counters_(NULL),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001473 code_range_(NULL),
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001474 // Must be initialized early to allow v8::SetResourceConstraints calls.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001475 break_access_(OS::CreateMutex()),
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001476 debugger_initialized_(false),
1477 // Must be initialized early to allow v8::Debug calls.
1478 debugger_access_(OS::CreateMutex()),
1479 logger_(NULL),
1480 stats_table_(NULL),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001481 stub_cache_(NULL),
1482 deoptimizer_data_(NULL),
1483 capture_stack_trace_for_uncaught_exceptions_(false),
1484 stack_trace_for_uncaught_exceptions_frame_limit_(0),
1485 stack_trace_for_uncaught_exceptions_options_(StackTrace::kOverview),
1486 transcendental_cache_(NULL),
1487 memory_allocator_(NULL),
1488 keyed_lookup_cache_(NULL),
1489 context_slot_cache_(NULL),
1490 descriptor_lookup_cache_(NULL),
1491 handle_scope_implementer_(NULL),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001492 unicode_cache_(NULL),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001493 in_use_list_(0),
1494 free_list_(0),
1495 preallocated_storage_preallocated_(false),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001496 inner_pointer_to_code_cache_(NULL),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001497 write_input_buffer_(NULL),
1498 global_handles_(NULL),
1499 context_switcher_(NULL),
1500 thread_manager_(NULL),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001501 fp_stubs_generated_(false),
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001502 has_installed_extensions_(false),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001503 string_tracker_(NULL),
1504 regexp_stack_(NULL),
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001505 date_cache_(NULL),
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001506 embedder_data_(NULL),
1507 context_exit_happened_(false) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001508 TRACE_ISOLATE(constructor);
1509
1510 memset(isolate_addresses_, 0,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00001511 sizeof(isolate_addresses_[0]) * (kIsolateAddressCount + 1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001512
1513 heap_.isolate_ = this;
1514 zone_.isolate_ = this;
1515 stack_guard_.isolate_ = this;
1516
lrn@chromium.org1c092762011-05-09 09:42:16 +00001517 // ThreadManager is initialized early to support locking an isolate
1518 // before it is entered.
1519 thread_manager_ = new ThreadManager();
1520 thread_manager_->isolate_ = this;
1521
lrn@chromium.org7516f052011-03-30 08:52:27 +00001522#if defined(V8_TARGET_ARCH_ARM) && !defined(__arm__) || \
1523 defined(V8_TARGET_ARCH_MIPS) && !defined(__mips__)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001524 simulator_initialized_ = false;
1525 simulator_i_cache_ = NULL;
1526 simulator_redirection_ = NULL;
1527#endif
1528
1529#ifdef DEBUG
1530 // heap_histograms_ initializes itself.
1531 memset(&js_spill_information_, 0, sizeof(js_spill_information_));
1532 memset(code_kind_statistics_, 0,
1533 sizeof(code_kind_statistics_[0]) * Code::NUMBER_OF_KINDS);
1534#endif
1535
1536#ifdef ENABLE_DEBUGGER_SUPPORT
1537 debug_ = NULL;
1538 debugger_ = NULL;
1539#endif
1540
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001541 handle_scope_data_.Initialize();
1542
1543#define ISOLATE_INIT_EXECUTE(type, name, initial_value) \
1544 name##_ = (initial_value);
1545 ISOLATE_INIT_LIST(ISOLATE_INIT_EXECUTE)
1546#undef ISOLATE_INIT_EXECUTE
1547
1548#define ISOLATE_INIT_ARRAY_EXECUTE(type, name, length) \
1549 memset(name##_, 0, sizeof(type) * length);
1550 ISOLATE_INIT_ARRAY_LIST(ISOLATE_INIT_ARRAY_EXECUTE)
1551#undef ISOLATE_INIT_ARRAY_EXECUTE
1552}
1553
1554void Isolate::TearDown() {
1555 TRACE_ISOLATE(tear_down);
1556
1557 // Temporarily set this isolate as current so that various parts of
1558 // the isolate can access it in their destructors without having a
1559 // direct pointer. We don't use Enter/Exit here to avoid
1560 // initializing the thread data.
1561 PerIsolateThreadData* saved_data = CurrentPerIsolateThreadData();
1562 Isolate* saved_isolate = UncheckedCurrent();
1563 SetIsolateThreadLocals(this, NULL);
1564
1565 Deinit();
1566
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00001567 { ScopedLock lock(global_state.Pointer()->mutex);
1568 global_state.Pointer()->thread_data_table->RemoveAllThreads(this);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00001569 }
1570
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001571 if (!IsDefaultIsolate()) {
1572 delete this;
1573 }
1574
1575 // Restore the previous current isolate.
1576 SetIsolateThreadLocals(saved_isolate, saved_data);
1577}
1578
1579
1580void Isolate::Deinit() {
1581 if (state_ == INITIALIZED) {
1582 TRACE_ISOLATE(deinit);
1583
1584 if (FLAG_hydrogen_stats) HStatistics::Instance()->Print();
1585
1586 // We must stop the logger before we tear down other components.
1587 logger_->EnsureTickerStopped();
1588
1589 delete deoptimizer_data_;
1590 deoptimizer_data_ = NULL;
1591 if (FLAG_preemption) {
1592 v8::Locker locker;
1593 v8::Locker::StopPreemption();
1594 }
1595 builtins_.TearDown();
1596 bootstrapper_->TearDown();
1597
1598 // Remove the external reference to the preallocated stack memory.
1599 delete preallocated_message_space_;
1600 preallocated_message_space_ = NULL;
1601 PreallocatedMemoryThreadStop();
1602
1603 HeapProfiler::TearDown();
1604 CpuProfiler::TearDown();
1605 if (runtime_profiler_ != NULL) {
1606 runtime_profiler_->TearDown();
1607 delete runtime_profiler_;
1608 runtime_profiler_ = NULL;
1609 }
1610 heap_.TearDown();
1611 logger_->TearDown();
1612
1613 // The default isolate is re-initializable due to legacy API.
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001614 state_ = UNINITIALIZED;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001615 }
1616}
1617
1618
1619void Isolate::SetIsolateThreadLocals(Isolate* isolate,
1620 PerIsolateThreadData* data) {
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00001621 const GlobalState& global = global_state.Get();
1622 Thread::SetThreadLocal(global.isolate_key, isolate);
1623 Thread::SetThreadLocal(global.per_isolate_thread_data_key, data);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001624}
1625
1626
1627Isolate::~Isolate() {
1628 TRACE_ISOLATE(destructor);
1629
danno@chromium.orgb6451162011-08-17 14:33:23 +00001630 // Has to be called while counters_ are still alive.
1631 zone_.DeleteKeptSegment();
1632
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001633 delete[] assembler_spare_buffer_;
1634 assembler_spare_buffer_ = NULL;
1635
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001636 delete unicode_cache_;
1637 unicode_cache_ = NULL;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001638
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001639 delete date_cache_;
1640 date_cache_ = NULL;
1641
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001642 delete regexp_stack_;
1643 regexp_stack_ = NULL;
1644
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001645 delete descriptor_lookup_cache_;
1646 descriptor_lookup_cache_ = NULL;
1647 delete context_slot_cache_;
1648 context_slot_cache_ = NULL;
1649 delete keyed_lookup_cache_;
1650 keyed_lookup_cache_ = NULL;
1651
1652 delete transcendental_cache_;
1653 transcendental_cache_ = NULL;
1654 delete stub_cache_;
1655 stub_cache_ = NULL;
1656 delete stats_table_;
1657 stats_table_ = NULL;
1658
1659 delete logger_;
1660 logger_ = NULL;
1661
1662 delete counters_;
1663 counters_ = NULL;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001664
1665 delete handle_scope_implementer_;
1666 handle_scope_implementer_ = NULL;
1667 delete break_access_;
1668 break_access_ = NULL;
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001669 delete debugger_access_;
1670 debugger_access_ = NULL;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001671
1672 delete compilation_cache_;
1673 compilation_cache_ = NULL;
1674 delete bootstrapper_;
1675 bootstrapper_ = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001676 delete inner_pointer_to_code_cache_;
1677 inner_pointer_to_code_cache_ = NULL;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001678 delete write_input_buffer_;
1679 write_input_buffer_ = NULL;
1680
1681 delete context_switcher_;
1682 context_switcher_ = NULL;
1683 delete thread_manager_;
1684 thread_manager_ = NULL;
1685
1686 delete string_tracker_;
1687 string_tracker_ = NULL;
1688
1689 delete memory_allocator_;
1690 memory_allocator_ = NULL;
1691 delete code_range_;
1692 code_range_ = NULL;
1693 delete global_handles_;
1694 global_handles_ = NULL;
1695
danno@chromium.orgb6451162011-08-17 14:33:23 +00001696 delete external_reference_table_;
1697 external_reference_table_ = NULL;
1698
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001699#ifdef ENABLE_DEBUGGER_SUPPORT
1700 delete debugger_;
1701 debugger_ = NULL;
1702 delete debug_;
1703 debug_ = NULL;
1704#endif
1705}
1706
1707
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001708void Isolate::InitializeThreadLocal() {
lrn@chromium.org1c092762011-05-09 09:42:16 +00001709 thread_local_top_.isolate_ = this;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001710 thread_local_top_.Initialize();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001711}
1712
1713
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001714void Isolate::PropagatePendingExceptionToExternalTryCatch() {
1715 ASSERT(has_pending_exception());
1716
1717 bool external_caught = IsExternallyCaught();
1718 thread_local_top_.external_caught_exception_ = external_caught;
1719
1720 if (!external_caught) return;
1721
1722 if (thread_local_top_.pending_exception_ == Failure::OutOfMemoryException()) {
1723 // Do not propagate OOM exception: we should kill VM asap.
1724 } else if (thread_local_top_.pending_exception_ ==
1725 heap()->termination_exception()) {
1726 try_catch_handler()->can_continue_ = false;
1727 try_catch_handler()->exception_ = heap()->null_value();
1728 } else {
1729 // At this point all non-object (failure) exceptions have
1730 // been dealt with so this shouldn't fail.
1731 ASSERT(!pending_exception()->IsFailure());
1732 try_catch_handler()->can_continue_ = true;
1733 try_catch_handler()->exception_ = pending_exception();
1734 if (!thread_local_top_.pending_message_obj_->IsTheHole()) {
1735 try_catch_handler()->message_ = thread_local_top_.pending_message_obj_;
1736 }
1737 }
1738}
1739
1740
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001741void Isolate::InitializeLoggingAndCounters() {
1742 if (logger_ == NULL) {
1743 logger_ = new Logger;
1744 }
1745 if (counters_ == NULL) {
1746 counters_ = new Counters;
1747 }
1748}
1749
1750
1751void Isolate::InitializeDebugger() {
1752#ifdef ENABLE_DEBUGGER_SUPPORT
1753 ScopedLock lock(debugger_access_);
1754 if (NoBarrier_Load(&debugger_initialized_)) return;
1755 InitializeLoggingAndCounters();
1756 debug_ = new Debug(this);
1757 debugger_ = new Debugger(this);
1758 Release_Store(&debugger_initialized_, true);
1759#endif
1760}
1761
1762
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001763bool Isolate::Init(Deserializer* des) {
1764 ASSERT(state_ != INITIALIZED);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001765 ASSERT(Isolate::Current() == this);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001766 TRACE_ISOLATE(init);
1767
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001768#ifdef DEBUG
1769 // The initialization process does not handle memory exhaustion.
1770 DisallowAllocationFailure disallow_allocation_failure;
1771#endif
1772
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001773 InitializeLoggingAndCounters();
1774
1775 InitializeDebugger();
1776
1777 memory_allocator_ = new MemoryAllocator(this);
1778 code_range_ = new CodeRange(this);
1779
1780 // Safe after setting Heap::isolate_, initializing StackGuard and
1781 // ensuring that Isolate::Current() == this.
1782 heap_.SetStackLimits();
1783
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00001784#define ASSIGN_ELEMENT(CamelName, hacker_name) \
1785 isolate_addresses_[Isolate::k##CamelName##Address] = \
1786 reinterpret_cast<Address>(hacker_name##_address());
1787 FOR_EACH_ISOLATE_ADDRESS_NAME(ASSIGN_ELEMENT)
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001788#undef C
1789
1790 string_tracker_ = new StringTracker();
1791 string_tracker_->isolate_ = this;
1792 compilation_cache_ = new CompilationCache(this);
1793 transcendental_cache_ = new TranscendentalCache();
1794 keyed_lookup_cache_ = new KeyedLookupCache();
1795 context_slot_cache_ = new ContextSlotCache();
1796 descriptor_lookup_cache_ = new DescriptorLookupCache();
1797 unicode_cache_ = new UnicodeCache();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001798 inner_pointer_to_code_cache_ = new InnerPointerToCodeCache(this);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001799 write_input_buffer_ = new StringInputBuffer();
1800 global_handles_ = new GlobalHandles(this);
1801 bootstrapper_ = new Bootstrapper();
1802 handle_scope_implementer_ = new HandleScopeImplementer(this);
1803 stub_cache_ = new StubCache(this);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001804 regexp_stack_ = new RegExpStack();
1805 regexp_stack_->isolate_ = this;
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001806 date_cache_ = new DateCache();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001807
1808 // Enable logging before setting up the heap
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001809 logger_->SetUp();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001810
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001811 CpuProfiler::SetUp();
1812 HeapProfiler::SetUp();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001813
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001814 // Initialize other runtime facilities
1815#if defined(USE_SIMULATOR)
lrn@chromium.org7516f052011-03-30 08:52:27 +00001816#if defined(V8_TARGET_ARCH_ARM) || defined(V8_TARGET_ARCH_MIPS)
lrn@chromium.org1c092762011-05-09 09:42:16 +00001817 Simulator::Initialize(this);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001818#endif
1819#endif
1820
1821 { // NOLINT
1822 // Ensure that the thread has a valid stack guard. The v8::Locker object
1823 // will ensure this too, but we don't have to use lockers if we are only
1824 // using one thread.
1825 ExecutionAccess lock(this);
1826 stack_guard_.InitThread(lock);
1827 }
1828
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001829 // SetUp the object heap.
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001830 const bool create_heap_objects = (des == NULL);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001831 ASSERT(!heap_.HasBeenSetUp());
1832 if (!heap_.SetUp(create_heap_objects)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001833 V8::SetFatalError();
1834 return false;
1835 }
1836
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001837 InitializeThreadLocal();
1838
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001839 bootstrapper_->Initialize(create_heap_objects);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001840 builtins_.SetUp(create_heap_objects);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001841
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001842 // Only preallocate on the first initialization.
1843 if (FLAG_preallocate_message_memory && preallocated_message_space_ == NULL) {
1844 // Start the thread which will set aside some memory.
1845 PreallocatedMemoryThreadStart();
1846 preallocated_message_space_ =
1847 new NoAllocationStringAllocator(
1848 preallocated_memory_thread_->data(),
1849 preallocated_memory_thread_->length());
1850 PreallocatedStorageInit(preallocated_memory_thread_->length() / 4);
1851 }
1852
1853 if (FLAG_preemption) {
1854 v8::Locker locker;
1855 v8::Locker::StartPreemption(100);
1856 }
1857
1858#ifdef ENABLE_DEBUGGER_SUPPORT
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001859 debug_->SetUp(create_heap_objects);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001860#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001861
1862 // If we are deserializing, read the state into the now-empty heap.
1863 if (des != NULL) {
1864 des->Deserialize();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001865 }
ulan@chromium.org812308e2012-02-29 15:58:45 +00001866 stub_cache_->Initialize();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001867
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001868 // Finish initialization of ThreadLocal after deserialization is done.
1869 clear_pending_exception();
1870 clear_pending_message();
1871 clear_scheduled_exception();
1872
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001873 // Deserializing may put strange things in the root array's copy of the
1874 // stack guard.
1875 heap_.SetStackLimits();
1876
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001877 deoptimizer_data_ = new DeoptimizerData;
1878 runtime_profiler_ = new RuntimeProfiler(this);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001879 runtime_profiler_->SetUp();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001880
1881 // If we are deserializing, log non-function code objects and compiled
1882 // functions found in the snapshot.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001883 if (des != NULL && (FLAG_log_code || FLAG_ll_prof)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001884 HandleScope scope;
1885 LOG(this, LogCodeObjects());
1886 LOG(this, LogCompiledFunctions());
1887 }
1888
1889 state_ = INITIALIZED;
rossberg@chromium.org994edf62012-02-06 10:12:55 +00001890 time_millis_at_init_ = OS::TimeCurrentMillis();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001891 return true;
1892}
1893
1894
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001895// Initialized lazily to allow early
1896// v8::V8::SetAddHistogramSampleFunction calls.
1897StatsTable* Isolate::stats_table() {
1898 if (stats_table_ == NULL) {
1899 stats_table_ = new StatsTable;
1900 }
1901 return stats_table_;
1902}
1903
1904
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001905void Isolate::Enter() {
1906 Isolate* current_isolate = NULL;
1907 PerIsolateThreadData* current_data = CurrentPerIsolateThreadData();
1908 if (current_data != NULL) {
1909 current_isolate = current_data->isolate_;
1910 ASSERT(current_isolate != NULL);
1911 if (current_isolate == this) {
1912 ASSERT(Current() == this);
1913 ASSERT(entry_stack_ != NULL);
1914 ASSERT(entry_stack_->previous_thread_data == NULL ||
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001915 entry_stack_->previous_thread_data->thread_id().Equals(
1916 ThreadId::Current()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001917 // Same thread re-enters the isolate, no need to re-init anything.
1918 entry_stack_->entry_count++;
1919 return;
1920 }
1921 }
1922
1923 // Threads can have default isolate set into TLS as Current but not yet have
1924 // PerIsolateThreadData for it, as it requires more advanced phase of the
1925 // initialization. For example, a thread might be the one that system used for
1926 // static initializers - in this case the default isolate is set in TLS but
1927 // the thread did not yet Enter the isolate. If PerisolateThreadData is not
1928 // there, use the isolate set in TLS.
1929 if (current_isolate == NULL) {
1930 current_isolate = Isolate::UncheckedCurrent();
1931 }
1932
1933 PerIsolateThreadData* data = FindOrAllocatePerThreadDataForThisThread();
1934 ASSERT(data != NULL);
1935 ASSERT(data->isolate_ == this);
1936
1937 EntryStackItem* item = new EntryStackItem(current_data,
1938 current_isolate,
1939 entry_stack_);
1940 entry_stack_ = item;
1941
1942 SetIsolateThreadLocals(this, data);
1943
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001944 // In case it's the first time some thread enters the isolate.
1945 set_thread_id(data->thread_id());
1946}
1947
1948
1949void Isolate::Exit() {
1950 ASSERT(entry_stack_ != NULL);
1951 ASSERT(entry_stack_->previous_thread_data == NULL ||
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001952 entry_stack_->previous_thread_data->thread_id().Equals(
1953 ThreadId::Current()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001954
1955 if (--entry_stack_->entry_count > 0) return;
1956
1957 ASSERT(CurrentPerIsolateThreadData() != NULL);
1958 ASSERT(CurrentPerIsolateThreadData()->isolate_ == this);
1959
1960 // Pop the stack.
1961 EntryStackItem* item = entry_stack_;
1962 entry_stack_ = item->previous_item;
1963
1964 PerIsolateThreadData* previous_thread_data = item->previous_thread_data;
1965 Isolate* previous_isolate = item->previous_isolate;
1966
1967 delete item;
1968
1969 // Reinit the current thread for the isolate it was running before this one.
1970 SetIsolateThreadLocals(previous_isolate, previous_thread_data);
1971}
1972
1973
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001974#ifdef DEBUG
1975#define ISOLATE_FIELD_OFFSET(type, name, ignored) \
1976const intptr_t Isolate::name##_debug_offset_ = OFFSET_OF(Isolate, name##_);
1977ISOLATE_INIT_LIST(ISOLATE_FIELD_OFFSET)
1978ISOLATE_INIT_ARRAY_LIST(ISOLATE_FIELD_OFFSET)
1979#undef ISOLATE_FIELD_OFFSET
1980#endif
1981
1982} } // namespace v8::internal