isolate.cc 101 KB
Newer Older
1
// Copyright 2012 the V8 project authors. All rights reserved.
2 3
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
4

5 6
#include "src/isolate.h"

7 8
#include <stdlib.h>

9
#include <fstream>  // NOLINT(readability/streams)
10
#include <sstream>
11

12 13
#include "src/ast/ast.h"
#include "src/ast/scopeinfo.h"
14
#include "src/base/platform/platform.h"
15
#include "src/base/sys-info.h"
16
#include "src/base/utils/random-number-generator.h"
17
#include "src/basic-block-profiler.h"
18 19 20
#include "src/bootstrapper.h"
#include "src/codegen.h"
#include "src/compilation-cache.h"
21
#include "src/compilation-statistics.h"
22
#include "src/crankshaft/hydrogen.h"
23
#include "src/debug/debug.h"
24
#include "src/deoptimizer.h"
25
#include "src/external-reference-table.h"
26
#include "src/frames-inl.h"
27
#include "src/ic/stub-cache.h"
28
#include "src/interpreter/interpreter.h"
29
#include "src/isolate-inl.h"
30 31
#include "src/log.h"
#include "src/messages.h"
32 33
#include "src/profiler/cpu-profiler.h"
#include "src/profiler/sampler.h"
34
#include "src/prototype.h"
35
#include "src/regexp/regexp-stack.h"
36 37
#include "src/runtime-profiler.h"
#include "src/simulator.h"
38
#include "src/snapshot/deserializer.h"
39
#include "src/v8.h"
40 41
#include "src/version.h"
#include "src/vm-state-inl.h"
42 43 44 45 46


namespace v8 {
namespace internal {

47
base::Atomic32 ThreadId::highest_thread_id_ = 0;
48 49

int ThreadId::AllocateThreadId() {
50
  int new_id = base::NoBarrier_AtomicIncrement(&highest_thread_id_, 1);
51 52 53
  return new_id;
}

54

55
int ThreadId::GetCurrentThreadId() {
56
  int thread_id = base::Thread::GetThreadLocalInt(Isolate::thread_id_key_);
57 58
  if (thread_id == 0) {
    thread_id = AllocateThreadId();
59
    base::Thread::SetThreadLocalInt(Isolate::thread_id_key_, thread_id);
60 61 62
  }
  return thread_id;
}
63

64 65 66 67 68 69 70 71

ThreadLocalTop::ThreadLocalTop() {
  InitializeInternal();
}


void ThreadLocalTop::InitializeInternal() {
  c_entry_fp_ = 0;
72
  c_function_ = 0;
73 74 75 76 77
  handler_ = 0;
#ifdef USE_SIMULATOR
  simulator_ = NULL;
#endif
  js_entry_sp_ = NULL;
78
  external_callback_scope_ = NULL;
79
  current_vm_state_ = EXTERNAL;
80
  try_catch_handler_ = NULL;
81 82 83 84 85
  context_ = NULL;
  thread_id_ = ThreadId::Invalid();
  external_caught_exception_ = false;
  failed_access_check_callback_ = NULL;
  save_context_ = NULL;
86
  promise_on_stack_ = NULL;
87 88 89 90

  // These members are re-initialized later after deserialization
  // is complete.
  pending_exception_ = NULL;
91
  rethrowing_message_ = false;
92 93
  pending_message_obj_ = NULL;
  scheduled_exception_ = NULL;
94 95 96 97 98 99 100 101 102 103 104 105
}


void ThreadLocalTop::Initialize() {
  InitializeInternal();
#ifdef USE_SIMULATOR
  simulator_ = Simulator::current(isolate_);
#endif
  thread_id_ = ThreadId::Current();
}


106 107 108 109 110 111
void ThreadLocalTop::Free() {
  // Match unmatched PopPromise calls.
  while (promise_on_stack_) isolate_->PopPromise();
}


112 113 114
base::Thread::LocalStorageKey Isolate::isolate_key_;
base::Thread::LocalStorageKey Isolate::thread_id_key_;
base::Thread::LocalStorageKey Isolate::per_isolate_thread_data_key_;
115
base::LazyMutex Isolate::thread_data_table_mutex_ = LAZY_MUTEX_INITIALIZER;
116
Isolate::ThreadDataTable* Isolate::thread_data_table_ = NULL;
117
base::Atomic32 Isolate::isolate_counter_ = 0;
118 119 120
#if DEBUG
base::Atomic32 Isolate::isolate_key_created_ = 0;
#endif
121

122 123
Isolate::PerIsolateThreadData*
    Isolate::FindOrAllocatePerThreadDataForThisThread() {
124
  ThreadId thread_id = ThreadId::Current();
125 126
  PerIsolateThreadData* per_thread = NULL;
  {
127
    base::LockGuard<base::Mutex> lock_guard(thread_data_table_mutex_.Pointer());
128
    per_thread = thread_data_table_->Lookup(this, thread_id);
129
    if (per_thread == NULL) {
130 131
      per_thread = new PerIsolateThreadData(this, thread_id);
      thread_data_table_->Insert(per_thread);
132
    }
133
    DCHECK(thread_data_table_->Lookup(this, thread_id) == per_thread);
134 135 136 137 138
  }
  return per_thread;
}


139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
void Isolate::DiscardPerThreadDataForThisThread() {
  int thread_id_int = base::Thread::GetThreadLocalInt(Isolate::thread_id_key_);
  if (thread_id_int) {
    ThreadId thread_id = ThreadId(thread_id_int);
    DCHECK(!thread_manager_->mutex_owner_.Equals(thread_id));
    base::LockGuard<base::Mutex> lock_guard(thread_data_table_mutex_.Pointer());
    PerIsolateThreadData* per_thread =
        thread_data_table_->Lookup(this, thread_id);
    if (per_thread) {
      DCHECK(!per_thread->thread_state_);
      thread_data_table_->Remove(per_thread);
    }
  }
}


155 156
Isolate::PerIsolateThreadData* Isolate::FindPerThreadDataForThisThread() {
  ThreadId thread_id = ThreadId::Current();
157 158 159 160 161 162
  return FindPerThreadDataForThread(thread_id);
}


Isolate::PerIsolateThreadData* Isolate::FindPerThreadDataForThread(
    ThreadId thread_id) {
163 164
  PerIsolateThreadData* per_thread = NULL;
  {
165
    base::LockGuard<base::Mutex> lock_guard(thread_data_table_mutex_.Pointer());
166
    per_thread = thread_data_table_->Lookup(this, thread_id);
167 168 169 170 171
  }
  return per_thread;
}


172 173 174 175
void Isolate::InitializeOncePerProcess() {
  base::LockGuard<base::Mutex> lock_guard(thread_data_table_mutex_.Pointer());
  CHECK(thread_data_table_ == NULL);
  isolate_key_ = base::Thread::CreateThreadLocalKey();
176 177 178
#if DEBUG
  base::NoBarrier_Store(&isolate_key_created_, 1);
#endif
179 180 181
  thread_id_key_ = base::Thread::CreateThreadLocalKey();
  per_isolate_thread_data_key_ = base::Thread::CreateThreadLocalKey();
  thread_data_table_ = new Isolate::ThreadDataTable();
182 183
}

184

185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
Address Isolate::get_address_from_id(Isolate::AddressId id) {
  return isolate_addresses_[id];
}


char* Isolate::Iterate(ObjectVisitor* v, char* thread_storage) {
  ThreadLocalTop* thread = reinterpret_cast<ThreadLocalTop*>(thread_storage);
  Iterate(v, thread);
  return thread_storage + sizeof(ThreadLocalTop);
}


void Isolate::IterateThread(ThreadVisitor* v, char* t) {
  ThreadLocalTop* thread = reinterpret_cast<ThreadLocalTop*>(t);
  v->VisitThread(this, thread);
}


void Isolate::Iterate(ObjectVisitor* v, ThreadLocalTop* thread) {
  // Visit the roots from the top for a given thread.
205
  v->VisitPointer(&thread->pending_exception_);
206
  v->VisitPointer(&(thread->pending_message_obj_));
207
  v->VisitPointer(bit_cast<Object**>(&(thread->context_)));
208
  v->VisitPointer(&thread->scheduled_exception_);
209

210
  for (v8::TryCatch* block = thread->try_catch_handler();
211
       block != NULL;
212
       block = block->next_) {
213 214
    v->VisitPointer(bit_cast<Object**>(&(block->exception_)));
    v->VisitPointer(bit_cast<Object**>(&(block->message_obj_)));
215 216 217 218 219 220 221 222 223 224 225 226 227 228
  }

  // Iterate over pointers on native execution stack.
  for (StackFrameIterator it(this, thread); !it.done(); it.Advance()) {
    it.frame()->Iterate(v);
  }
}


void Isolate::Iterate(ObjectVisitor* v) {
  ThreadLocalTop* current_t = thread_local_top();
  Iterate(v, current_t);
}

229

230 231 232 233 234 235 236 237
void Isolate::IterateDeferredHandles(ObjectVisitor* visitor) {
  for (DeferredHandles* deferred = deferred_handles_head_;
       deferred != NULL;
       deferred = deferred->next_) {
    deferred->Iterate(visitor);
  }
}

238

239 240 241
#ifdef DEBUG
bool Isolate::IsDeferredHandle(Object** handle) {
  // Each DeferredHandles instance keeps the handles to one job in the
242
  // concurrent recompilation queue, containing a list of blocks.  Each block
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261
  // contains kHandleBlockSize handles except for the first block, which may
  // not be fully filled.
  // We iterate through all the blocks to see whether the argument handle
  // belongs to one of the blocks.  If so, it is deferred.
  for (DeferredHandles* deferred = deferred_handles_head_;
       deferred != NULL;
       deferred = deferred->next_) {
    List<Object**>* blocks = &deferred->blocks_;
    for (int i = 0; i < blocks->length(); i++) {
      Object** block_limit = (i == 0) ? deferred->first_block_limit_
                                      : blocks->at(i) + kHandleBlockSize;
      if (blocks->at(i) <= handle && handle < block_limit) return true;
    }
  }
  return false;
}
#endif  // DEBUG


262
void Isolate::RegisterTryCatchHandler(v8::TryCatch* that) {
263
  thread_local_top()->set_try_catch_handler(that);
264 265 266 267
}


void Isolate::UnregisterTryCatchHandler(v8::TryCatch* that) {
268
  DCHECK(thread_local_top()->try_catch_handler() == that);
269
  thread_local_top()->set_try_catch_handler(that->next_);
270 271 272 273 274 275 276
}


Handle<String> Isolate::StackTraceString() {
  if (stack_trace_nesting_level_ == 0) {
    stack_trace_nesting_level_++;
    HeapStringAllocator allocator;
277
    StringStream::ClearMentionedObjectCache(this);
278 279 280
    StringStream accumulator(&allocator);
    incomplete_message_ = &accumulator;
    PrintStack(&accumulator);
281
    Handle<String> stack_trace = accumulator.ToString(this);
282 283 284 285 286
    incomplete_message_ = NULL;
    stack_trace_nesting_level_ = 0;
    return stack_trace;
  } else if (stack_trace_nesting_level_ == 1) {
    stack_trace_nesting_level_++;
287
    base::OS::PrintError(
288
      "\n\nAttempt to print stack while printing stack (double fault)\n");
289
    base::OS::PrintError(
290 291
      "If you are lucky you may find a partial stack dump on stdout.\n\n");
    incomplete_message_->OutputToStdOut();
292
    return factory()->empty_string();
293
  } else {
294
    base::OS::Abort();
295
    // Unreachable
296
    return factory()->empty_string();
297 298 299 300
  }
}


301
void Isolate::PushStackTraceAndDie(unsigned int magic, void* ptr1, void* ptr2,
302
                                   unsigned int magic2) {
303
  const int kMaxStackTraceSize = 32 * KB;
304
  Handle<String> trace = StackTraceString();
305
  uint8_t buffer[kMaxStackTraceSize];
306 307 308
  int length = Min(kMaxStackTraceSize - 1, trace->length());
  String::WriteToFlat(*trace, buffer, 0, length);
  buffer[length] = '\0';
309
  // TODO(dcarney): convert buffer to utf8?
310 311
  base::OS::PrintError("Stacktrace (%x-%x) %p %p: %s\n", magic, magic2, ptr1,
                       ptr2, reinterpret_cast<char*>(buffer));
312
  base::OS::Abort();
313 314 315
}


316 317 318 319 320 321
// Determines whether the given stack frame should be displayed in
// a stack trace.  The caller is the error constructor that asked
// for the stack trace to be collected.  The first time a construct
// call to this function is encountered it is skipped.  The seen_caller
// in/out parameter is used to remember if the caller has been seen
// yet.
322
static bool IsVisibleInStackTrace(JSFunction* fun,
323
                                  Object* caller,
324
                                  Object* receiver,
325
                                  bool* seen_caller) {
326
  if ((fun == caller) && !(*seen_caller)) {
327 328 329 330 331
    *seen_caller = true;
    return false;
  }
  // Skip all frames until we've seen the caller.
  if (!(*seen_caller)) return false;
332 333
  // Functions defined in native scripts are not visible unless directly
  // exposed, in which case the native flag is set.
334 335
  // The --builtins-in-stack-traces command line flag allows including
  // internal call sites in the stack trace for debugging purposes.
336
  if (!FLAG_builtins_in_stack_traces && fun->shared()->IsBuiltin()) {
yangguo's avatar
yangguo committed
337
    return fun->shared()->native();
338 339 340 341
  }
  return true;
}

342 343 344 345 346 347 348 349 350 351 352 353 354 355 356
static Handle<FixedArray> MaybeGrow(Isolate* isolate,
                                    Handle<FixedArray> elements,
                                    int cur_position, int new_size) {
  if (new_size > elements->length()) {
    int new_capacity = JSObject::NewElementsCapacity(elements->length());
    Handle<FixedArray> new_elements =
        isolate->factory()->NewFixedArrayWithHoles(new_capacity);
    for (int i = 0; i < cur_position; i++) {
      new_elements->set(i, elements->get(i));
    }
    elements = new_elements;
  }
  DCHECK(new_size <= elements->length());
  return elements;
}
357

358 359 360
Handle<Object> Isolate::CaptureSimpleStackTrace(Handle<JSObject> error_object,
                                                Handle<Object> caller) {
  // Get stack trace limit.
361
  Handle<JSObject> error = error_function();
362 363
  Handle<String> stackTraceLimit =
      factory()->InternalizeUtf8String("stackTraceLimit");
364
  DCHECK(!stackTraceLimit.is_null());
365 366
  Handle<Object> stack_trace_limit =
      JSReceiver::GetDataProperty(error, stackTraceLimit);
367 368
  if (!stack_trace_limit->IsNumber()) return factory()->undefined_value();
  int limit = FastD2IChecked(stack_trace_limit->Number());
369
  limit = Max(limit, 0);  // Ensure that limit is not negative.
370

371 372
  int initial_size = Min(limit, 10);
  Handle<FixedArray> elements =
373
      factory()->NewFixedArrayWithHoles(initial_size * 4 + 1);
374 375 376 377

  // If the caller parameter is a function we skip frames until we're
  // under it before starting to collect.
  bool seen_caller = !caller->IsJSFunction();
378
  // First element is reserved to store the number of sloppy frames.
379
  int cursor = 1;
380
  int frames_seen = 0;
381
  int sloppy_frames = 0;
382
  bool encountered_strict_function = false;
383
  for (StackFrameIterator iter(this); !iter.done() && frames_seen < limit;
384
       iter.Advance()) {
385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427
    StackFrame* frame = iter.frame();

    switch (frame->type()) {
      case StackFrame::JAVA_SCRIPT:
      case StackFrame::OPTIMIZED:
      case StackFrame::INTERPRETED: {
        JavaScriptFrame* js_frame = JavaScriptFrame::cast(frame);
        // Set initial size to the maximum inlining level + 1 for the outermost
        // function.
        List<FrameSummary> frames(FLAG_max_inlining_levels + 1);
        js_frame->Summarize(&frames);
        for (int i = frames.length() - 1; i >= 0; i--) {
          Handle<JSFunction> fun = frames[i].function();
          Handle<Object> recv = frames[i].receiver();
          // Filter out internal frames that we do not want to show.
          if (!IsVisibleInStackTrace(*fun, *caller, *recv, &seen_caller)) {
            continue;
          }
          // Filter out frames from other security contexts.
          if (!this->context()->HasSameSecurityTokenAs(fun->context())) {
            continue;
          }
          elements = MaybeGrow(this, elements, cursor, cursor + 4);

          Handle<AbstractCode> abstract_code = frames[i].abstract_code();

          Handle<Smi> offset(Smi::FromInt(frames[i].code_offset()), this);
          // The stack trace API should not expose receivers and function
          // objects on frames deeper than the top-most one with a strict mode
          // function. The number of sloppy frames is stored as first element in
          // the result array.
          if (!encountered_strict_function) {
            if (is_strict(fun->shared()->language_mode())) {
              encountered_strict_function = true;
            } else {
              sloppy_frames++;
            }
          }
          elements->set(cursor++, *recv);
          elements->set(cursor++, *fun);
          elements->set(cursor++, *abstract_code);
          elements->set(cursor++, *offset);
          frames_seen++;
428
        }
429 430 431
      } break;

      case StackFrame::WASM: {
jfb's avatar
jfb committed
432 433 434 435
        WasmFrame* wasm_frame = WasmFrame::cast(frame);
        Code* code = wasm_frame->unchecked_code();
        Handle<AbstractCode> abstract_code =
            Handle<AbstractCode>(AbstractCode::cast(code));
436 437 438 439 440 441
        Handle<JSFunction> fun = factory()->NewFunction(
            factory()->NewStringFromAsciiChecked("<WASM>"));
        elements = MaybeGrow(this, elements, cursor, cursor + 4);
        // TODO(jfb) Pass module object.
        elements->set(cursor++, *factory()->undefined_value());
        elements->set(cursor++, *fun);
jfb's avatar
jfb committed
442
        elements->set(cursor++, *abstract_code);
443 444 445 446 447 448
        elements->set(cursor++, Internals::IntToSmi(0));
        frames_seen++;
      } break;

      default:
        break;
449 450
    }
  }
451
  elements->set(0, Smi::FromInt(sloppy_frames));
452
  elements->Shrink(cursor);
453 454
  Handle<JSArray> result = factory()->NewJSArrayWithElements(elements);
  result->set_length(Smi::FromInt(cursor));
455
  // TODO(yangguo): Queue this structured stack trace for preprocessing on GC.
456 457 458
  return result;
}

459 460
MaybeHandle<JSObject> Isolate::CaptureAndSetDetailedStackTrace(
    Handle<JSObject> error_object) {
461 462
  if (capture_stack_trace_for_uncaught_exceptions_) {
    // Capture stack trace for a detailed exception message.
463
    Handle<Name> key = factory()->detailed_stack_trace_symbol();
464 465 466
    Handle<JSArray> stack_trace = CaptureCurrentStackTrace(
        stack_trace_for_uncaught_exceptions_frame_limit_,
        stack_trace_for_uncaught_exceptions_options_);
467 468 469
    RETURN_ON_EXCEPTION(
        this, JSObject::SetProperty(error_object, key, stack_trace, STRICT),
        JSObject);
470
  }
471
  return error_object;
472 473 474
}


475 476
MaybeHandle<JSObject> Isolate::CaptureAndSetSimpleStackTrace(
    Handle<JSObject> error_object, Handle<Object> caller) {
477 478 479
  // Capture stack trace for simple stack trace string formatting.
  Handle<Name> key = factory()->stack_trace_symbol();
  Handle<Object> stack_trace = CaptureSimpleStackTrace(error_object, caller);
480 481 482 483
  RETURN_ON_EXCEPTION(
      this, JSObject::SetProperty(error_object, key, stack_trace, STRICT),
      JSObject);
  return error_object;
484 485 486
}


487 488 489
Handle<JSArray> Isolate::GetDetailedStackTrace(Handle<JSObject> error_object) {
  Handle<Name> key_detailed = factory()->detailed_stack_trace_symbol();
  Handle<Object> stack_trace =
490
      JSReceiver::GetDataProperty(error_object, key_detailed);
491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545
  if (stack_trace->IsJSArray()) return Handle<JSArray>::cast(stack_trace);

  if (!capture_stack_trace_for_uncaught_exceptions_) return Handle<JSArray>();

  // Try to get details from simple stack trace.
  Handle<JSArray> detailed_stack_trace =
      GetDetailedFromSimpleStackTrace(error_object);
  if (!detailed_stack_trace.is_null()) {
    // Save the detailed stack since the simple one might be withdrawn later.
    JSObject::SetProperty(error_object, key_detailed, detailed_stack_trace,
                          STRICT).Assert();
  }
  return detailed_stack_trace;
}


class CaptureStackTraceHelper {
 public:
  CaptureStackTraceHelper(Isolate* isolate,
                          StackTrace::StackTraceOptions options)
      : isolate_(isolate) {
    if (options & StackTrace::kColumnOffset) {
      column_key_ =
          factory()->InternalizeOneByteString(STATIC_CHAR_VECTOR("column"));
    }
    if (options & StackTrace::kLineNumber) {
      line_key_ =
          factory()->InternalizeOneByteString(STATIC_CHAR_VECTOR("lineNumber"));
    }
    if (options & StackTrace::kScriptId) {
      script_id_key_ =
          factory()->InternalizeOneByteString(STATIC_CHAR_VECTOR("scriptId"));
    }
    if (options & StackTrace::kScriptName) {
      script_name_key_ =
          factory()->InternalizeOneByteString(STATIC_CHAR_VECTOR("scriptName"));
    }
    if (options & StackTrace::kScriptNameOrSourceURL) {
      script_name_or_source_url_key_ = factory()->InternalizeOneByteString(
          STATIC_CHAR_VECTOR("scriptNameOrSourceURL"));
    }
    if (options & StackTrace::kFunctionName) {
      function_key_ = factory()->InternalizeOneByteString(
          STATIC_CHAR_VECTOR("functionName"));
    }
    if (options & StackTrace::kIsEval) {
      eval_key_ =
          factory()->InternalizeOneByteString(STATIC_CHAR_VECTOR("isEval"));
    }
    if (options & StackTrace::kIsConstructor) {
      constructor_key_ = factory()->InternalizeOneByteString(
          STATIC_CHAR_VECTOR("isConstructor"));
    }
  }

546
  Handle<JSObject> NewStackFrameObject(Handle<JSFunction> fun, int position,
547 548 549 550 551 552 553
                                       bool is_constructor) {
    Handle<JSObject> stack_frame =
        factory()->NewJSObject(isolate_->object_function());

    Handle<Script> script(Script::cast(fun->shared()->script()));

    if (!line_key_.is_null()) {
554
      int script_line_offset = script->line_offset();
555 556 557 558
      int line_number = Script::GetLineNumber(script, position);
      // line_number is already shifted by the script_line_offset.
      int relative_line_number = line_number - script_line_offset;
      if (!column_key_.is_null() && relative_line_number >= 0) {
559 560 561 562 563 564 565
        Handle<FixedArray> line_ends(FixedArray::cast(script->line_ends()));
        int start = (relative_line_number == 0) ? 0 :
            Smi::cast(line_ends->get(relative_line_number - 1))->value() + 1;
        int column_offset = position - start;
        if (relative_line_number == 0) {
          // For the case where the code is on the same line as the script
          // tag.
566
          column_offset += script->column_offset();
567
        }
568
        JSObject::AddProperty(stack_frame, column_key_,
569 570
                              handle(Smi::FromInt(column_offset + 1), isolate_),
                              NONE);
571 572 573 574 575 576 577 578
      }
      JSObject::AddProperty(stack_frame, line_key_,
                            handle(Smi::FromInt(line_number + 1), isolate_),
                            NONE);
    }

    if (!script_id_key_.is_null()) {
      JSObject::AddProperty(stack_frame, script_id_key_,
579
                            handle(Smi::FromInt(script->id()), isolate_), NONE);
580 581 582 583 584 585 586 587 588 589 590 591 592 593
    }

    if (!script_name_key_.is_null()) {
      JSObject::AddProperty(stack_frame, script_name_key_,
                            handle(script->name(), isolate_), NONE);
    }

    if (!script_name_or_source_url_key_.is_null()) {
      Handle<Object> result = Script::GetNameOrSourceURL(script);
      JSObject::AddProperty(stack_frame, script_name_or_source_url_key_, result,
                            NONE);
    }

    if (!function_key_.is_null()) {
594
      Handle<Object> fun_name = JSFunction::GetDebugName(fun);
595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627
      JSObject::AddProperty(stack_frame, function_key_, fun_name, NONE);
    }

    if (!eval_key_.is_null()) {
      Handle<Object> is_eval = factory()->ToBoolean(
          script->compilation_type() == Script::COMPILATION_TYPE_EVAL);
      JSObject::AddProperty(stack_frame, eval_key_, is_eval, NONE);
    }

    if (!constructor_key_.is_null()) {
      Handle<Object> is_constructor_obj = factory()->ToBoolean(is_constructor);
      JSObject::AddProperty(stack_frame, constructor_key_, is_constructor_obj,
                            NONE);
    }

    return stack_frame;
  }

 private:
  inline Factory* factory() { return isolate_->factory(); }

  Isolate* isolate_;
  Handle<String> column_key_;
  Handle<String> line_key_;
  Handle<String> script_id_key_;
  Handle<String> script_name_key_;
  Handle<String> script_name_or_source_url_key_;
  Handle<String> function_key_;
  Handle<String> eval_key_;
  Handle<String> constructor_key_;
};


628 629 630 631 632 633
int PositionFromStackTrace(Handle<FixedArray> elements, int index) {
  DisallowHeapAllocation no_gc;
  Object* maybe_code = elements->get(index + 2);
  if (maybe_code->IsSmi()) {
    return Smi::cast(maybe_code)->value();
  } else {
634 635 636
    AbstractCode* abstract_code = AbstractCode::cast(maybe_code);
    int code_offset = Smi::cast(elements->get(index + 3))->value();
    return abstract_code->SourcePosition(code_offset);
637 638 639 640
  }
}


641 642 643
Handle<JSArray> Isolate::GetDetailedFromSimpleStackTrace(
    Handle<JSObject> error_object) {
  Handle<Name> key = factory()->stack_trace_symbol();
644
  Handle<Object> property = JSReceiver::GetDataProperty(error_object, key);
645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664
  if (!property->IsJSArray()) return Handle<JSArray>();
  Handle<JSArray> simple_stack_trace = Handle<JSArray>::cast(property);

  CaptureStackTraceHelper helper(this,
                                 stack_trace_for_uncaught_exceptions_options_);

  int frames_seen = 0;
  Handle<FixedArray> elements(FixedArray::cast(simple_stack_trace->elements()));
  int elements_limit = Smi::cast(simple_stack_trace->length())->value();

  int frame_limit = stack_trace_for_uncaught_exceptions_frame_limit_;
  if (frame_limit < 0) frame_limit = (elements_limit - 1) / 4;

  Handle<JSArray> stack_trace = factory()->NewJSArray(frame_limit);
  for (int i = 1; i < elements_limit && frames_seen < frame_limit; i += 4) {
    Handle<Object> recv = handle(elements->get(i), this);
    Handle<JSFunction> fun =
        handle(JSFunction::cast(elements->get(i + 1)), this);
    bool is_constructor =
        recv->IsJSObject() &&
665
        Handle<JSObject>::cast(recv)->map()->GetConstructor() == *fun;
666
    int position = PositionFromStackTrace(elements, i);
667 668

    Handle<JSObject> stack_frame =
669
        helper.NewStackFrameObject(fun, position, is_constructor);
670 671 672 673 674 675 676 677 678 679

    FixedArray::cast(stack_trace->elements())->set(frames_seen, *stack_frame);
    frames_seen++;
  }

  stack_trace->set_length(Smi::FromInt(frames_seen));
  return stack_trace;
}


680 681
Handle<JSArray> Isolate::CaptureCurrentStackTrace(
    int frame_limit, StackTrace::StackTraceOptions options) {
682 683
  CaptureStackTraceHelper helper(this, options);

684 685 686 687 688 689 690 691 692 693
  // Ensure no negative values.
  int limit = Max(frame_limit, 0);
  Handle<JSArray> stack_trace = factory()->NewJSArray(frame_limit);

  StackTraceFrameIterator it(this);
  int frames_seen = 0;
  while (!it.done() && (frames_seen < limit)) {
    JavaScriptFrame* frame = it.frame();
    // Set initial size to the maximum inlining level + 1 for the outermost
    // function.
694
    List<FrameSummary> frames(FLAG_max_inlining_levels + 1);
695 696
    frame->Summarize(&frames);
    for (int i = frames.length() - 1; i >= 0 && frames_seen < limit; i--) {
697 698 699 700
      Handle<JSFunction> fun = frames[i].function();
      // Filter frames from other security contexts.
      if (!(options & StackTrace::kExposeFramesAcrossSecurityOrigins) &&
          !this->context()->HasSameSecurityTokenAs(fun->context())) continue;
701 702
      int position =
          frames[i].abstract_code()->SourcePosition(frames[i].code_offset());
703 704
      Handle<JSObject> stack_frame =
          helper.NewStackFrameObject(fun, position, frames[i].is_constructor());
705

706
      FixedArray::cast(stack_trace->elements())->set(frames_seen, *stack_frame);
707 708 709 710 711 712 713 714 715 716
      frames_seen++;
    }
    it.Advance();
  }

  stack_trace->set_length(Smi::FromInt(frames_seen));
  return stack_trace;
}


717
void Isolate::PrintStack(FILE* out, PrintStackMode mode) {
718 719
  if (stack_trace_nesting_level_ == 0) {
    stack_trace_nesting_level_++;
720
    StringStream::ClearMentionedObjectCache(this);
721 722
    HeapStringAllocator allocator;
    StringStream accumulator(&allocator);
723
    incomplete_message_ = &accumulator;
724
    PrintStack(&accumulator, mode);
725
    accumulator.OutputToFile(out);
726
    InitializeLoggingAndCounters();
727
    accumulator.Log(this);
728 729 730 731
    incomplete_message_ = NULL;
    stack_trace_nesting_level_ = 0;
  } else if (stack_trace_nesting_level_ == 1) {
    stack_trace_nesting_level_++;
732
    base::OS::PrintError(
733
      "\n\nAttempt to print stack while printing stack (double fault)\n");
734
    base::OS::PrintError(
735
      "If you are lucky you may find a partial stack dump on stdout.\n\n");
736
    incomplete_message_->OutputToFile(out);
737 738 739 740
  }
}


741 742
static void PrintFrames(Isolate* isolate,
                        StringStream* accumulator,
743
                        StackFrame::PrintMode mode) {
744
  StackFrameIterator it(isolate);
745 746 747 748 749 750
  for (int i = 0; !it.done(); it.Advance()) {
    it.frame()->Print(accumulator, mode, i++);
  }
}


751
void Isolate::PrintStack(StringStream* accumulator, PrintStackMode mode) {
752
  // The MentionedObjectCache is not GC-proof at the moment.
753
  DisallowHeapAllocation no_gc;
754
  DCHECK(accumulator->IsMentionedObjectCacheClear(this));
755 756 757 758 759

  // Avoid printing anything if there are no frames.
  if (c_entry_fp(thread_local_top()) == 0) return;

  accumulator->Add(
760
      "\n==== JS stack trace =========================================\n\n");
761
  PrintFrames(this, accumulator, StackFrame::OVERVIEW);
762 763 764 765 766 767
  if (mode == kPrintStackVerbose) {
    accumulator->Add(
        "\n==== Details ================================================\n\n");
    PrintFrames(this, accumulator, StackFrame::DETAILS);
    accumulator->PrintMentionedObjectCache(this);
  }
768 769 770 771 772 773 774 775 776 777
  accumulator->Add("=====================\n\n");
}


void Isolate::SetFailedAccessCheckCallback(
    v8::FailedAccessCheckCallback callback) {
  thread_local_top()->failed_access_check_callback_ = callback;
}


778 779
static inline AccessCheckInfo* GetAccessCheckInfo(Isolate* isolate,
                                                  Handle<JSObject> receiver) {
780 781 782
  Object* maybe_constructor = receiver->map()->GetConstructor();
  if (!maybe_constructor->IsJSFunction()) return NULL;
  JSFunction* constructor = JSFunction::cast(maybe_constructor);
783 784 785 786 787 788 789 790 791 792
  if (!constructor->shared()->IsApiFunction()) return NULL;

  Object* data_obj =
     constructor->shared()->get_api_func_data()->access_check_info();
  if (data_obj == isolate->heap()->undefined_value()) return NULL;

  return AccessCheckInfo::cast(data_obj);
}


793
void Isolate::ReportFailedAccessCheck(Handle<JSObject> receiver) {
794
  if (!thread_local_top()->failed_access_check_callback_) {
795
    return ScheduleThrow(*factory()->NewTypeError(MessageTemplate::kNoAccess));
796
  }
797

798 799
  DCHECK(receiver->IsAccessCheckNeeded());
  DCHECK(context());
800 801

  // Get the data object from access check info.
802
  HandleScope scope(this);
803 804 805
  Handle<Object> data;
  { DisallowHeapAllocation no_gc;
    AccessCheckInfo* access_check_info = GetAccessCheckInfo(this, receiver);
806 807
    if (!access_check_info) {
      AllowHeapAllocation doesnt_matter_anymore;
808 809
      return ScheduleThrow(
          *factory()->NewTypeError(MessageTemplate::kNoAccess));
810
    }
811 812 813 814 815 816
    data = handle(access_check_info->data(), this);
  }

  // Leaving JavaScript.
  VMState<EXTERNAL> state(this);
  thread_local_top()->failed_access_check_callback_(
817
      v8::Utils::ToLocal(receiver), v8::ACCESS_HAS, v8::Utils::ToLocal(data));
818 819 820
}


821 822
bool Isolate::MayAccess(Handle<Context> accessing_context,
                        Handle<JSObject> receiver) {
823
  DCHECK(receiver->IsJSGlobalProxy() || receiver->IsAccessCheckNeeded());
824 825 826 827

  // Check for compatibility between the security tokens in the
  // current lexical context and the accessed object.

828 829
  // During bootstrapping, callback functions are not enabled yet.
  if (bootstrapper()->IsActive()) return true;
830 831 832 833 834 835 836 837 838 839
  {
    DisallowHeapAllocation no_gc;

    if (receiver->IsJSGlobalProxy()) {
      Object* receiver_context =
          JSGlobalProxy::cast(*receiver)->native_context();
      if (!receiver_context->IsContext()) return false;

      // Get the native context of current top context.
      // avoid using Isolate::native_context() because it uses Handle.
840 841
      Context* native_context =
          accessing_context->global_object()->native_context();
842 843 844 845 846 847 848
      if (receiver_context == native_context) return true;

      if (Context::cast(receiver_context)->security_token() ==
          native_context->security_token())
        return true;
    }
  }
849 850

  HandleScope scope(this);
851
  Handle<Object> data;
852 853
  v8::AccessCheckCallback callback = nullptr;
  v8::NamedSecurityCallback named_callback = nullptr;
854 855 856
  { DisallowHeapAllocation no_gc;
    AccessCheckInfo* access_check_info = GetAccessCheckInfo(this, receiver);
    if (!access_check_info) return false;
857 858
    Object* fun_obj = access_check_info->callback();
    callback = v8::ToCData<v8::AccessCheckCallback>(fun_obj);
859
    data = handle(access_check_info->data(), this);
860 861 862 863 864
    if (!callback) {
      fun_obj = access_check_info->named_callback();
      named_callback = v8::ToCData<v8::NamedSecurityCallback>(fun_obj);
      if (!named_callback) return false;
    }
865
  }
866

867
  LOG(this, ApiSecurityCheck());
868

869 870 871
  {
    // Leaving JavaScript.
    VMState<EXTERNAL> state(this);
872 873
    if (callback) {
      return callback(v8::Utils::ToLocal(accessing_context),
874
                      v8::Utils::ToLocal(receiver), v8::Utils::ToLocal(data));
875
    }
876
    Handle<Object> key = factory()->undefined_value();
877 878
    return named_callback(v8::Utils::ToLocal(receiver), v8::Utils::ToLocal(key),
                          v8::ACCESS_HAS, v8::Utils::ToLocal(data));
879
  }
880 881 882 883 884 885 886
}


const char* const Isolate::kStackOverflowMessage =
  "Uncaught RangeError: Maximum call stack size exceeded";


887
Object* Isolate::StackOverflow() {
888
  HandleScope scope(this);
889 890 891
  // At this point we cannot create an Error object using its javascript
  // constructor.  Instead, we copy the pre-constructed boilerplate and
  // attach the stack trace as a hidden property.
892 893 894 895 896 897 898 899 900 901
  Handle<Object> exception;
  if (bootstrapper()->IsActive()) {
    // There is no boilerplate to use during bootstrapping.
    exception = factory()->NewStringFromAsciiChecked(
        MessageTemplate::TemplateString(MessageTemplate::kStackOverflow));
  } else {
    Handle<JSObject> boilerplate = stack_overflow_boilerplate();
    Handle<JSObject> copy = factory()->CopyJSObject(boilerplate);
    CaptureAndSetSimpleStackTrace(copy, factory()->undefined_value());
    exception = copy;
902
  }
903
  Throw(*exception, nullptr);
904

905 906
#ifdef VERIFY_HEAP
  if (FLAG_verify_heap && FLAG_stress_compaction) {
907
    heap()->CollectAllGarbage(Heap::kNoGCFlags, "trigger compaction");
908 909 910
  }
#endif  // VERIFY_HEAP

911
  return heap()->exception();
912 913 914
}


915
Object* Isolate::TerminateExecution() {
916
  return Throw(heap_.termination_exception(), nullptr);
917 918 919
}


920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936
void Isolate::CancelTerminateExecution() {
  if (try_catch_handler()) {
    try_catch_handler()->has_terminated_ = false;
  }
  if (has_pending_exception() &&
      pending_exception() == heap_.termination_exception()) {
    thread_local_top()->external_caught_exception_ = false;
    clear_pending_exception();
  }
  if (has_scheduled_exception() &&
      scheduled_exception() == heap_.termination_exception()) {
    thread_local_top()->external_caught_exception_ = false;
    clear_scheduled_exception();
  }
}


937 938 939 940 941
void Isolate::RequestInterrupt(InterruptCallback callback, void* data) {
  ExecutionAccess access(this);
  api_interrupts_queue_.push(InterruptEntry(callback, data));
  stack_guard()->RequestApiInterrupt();
}
942

943 944 945 946 947 948 949 950 951 952 953

void Isolate::InvokeApiInterruptCallbacks() {
  // Note: callback below should be called outside of execution access lock.
  while (true) {
    InterruptEntry entry;
    {
      ExecutionAccess access(this);
      if (api_interrupts_queue_.empty()) return;
      entry = api_interrupts_queue_.front();
      api_interrupts_queue_.pop();
    }
954 955
    VMState<EXTERNAL> state(this);
    HandleScope handle_scope(this);
956
    entry.first(reinterpret_cast<v8::Isolate*>(this), entry.second);
957 958 959 960
  }
}


961 962
void ReportBootstrappingException(Handle<Object> exception,
                                  MessageLocation* location) {
963
  base::OS::PrintError("Exception thrown during bootstrapping\n");
964
  if (location == NULL || location->script().is_null()) return;
965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982
  // We are bootstrapping and caught an error where the location is set
  // and we have a script for the location.
  // In this case we could have an extension (or an internal error
  // somewhere) and we print out the line number at which the error occured
  // to the console for easier debugging.
  int line_number =
      location->script()->GetLineNumber(location->start_pos()) + 1;
  if (exception->IsString() && location->script()->name()->IsString()) {
    base::OS::PrintError(
        "Extension or internal compilation error: %s in %s at line %d.\n",
        String::cast(*exception)->ToCString().get(),
        String::cast(location->script()->name())->ToCString().get(),
        line_number);
  } else if (location->script()->name()->IsString()) {
    base::OS::PrintError(
        "Extension or internal compilation error in %s at line %d.\n",
        String::cast(location->script()->name())->ToCString().get(),
        line_number);
983 984 985
  } else if (exception->IsString()) {
    base::OS::PrintError("Extension or internal compilation error: %s.\n",
                         String::cast(*exception)->ToCString().get());
986 987 988 989 990 991 992 993
  } else {
    base::OS::PrintError("Extension or internal compilation error.\n");
  }
#ifdef OBJECT_PRINT
  // Since comments and empty lines have been stripped from the source of
  // builtins, print the actual source here so that line numbers match.
  if (location->script()->source()->IsString()) {
    Handle<String> src(String::cast(location->script()->source()));
994
    PrintF("Failing script:");
995
    int len = src->length();
996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007
    if (len == 0) {
      PrintF(" <not available>\n");
    } else {
      PrintF("\n");
      int line_number = 1;
      PrintF("%5d: ", line_number);
      for (int i = 0; i < len; i++) {
        uint16_t character = src->Get(i);
        PrintF("%c", character);
        if (character == '\n' && i < len - 2) {
          PrintF("%5d: ", ++line_number);
        }
1008
      }
1009
      PrintF("\n");
1010 1011 1012 1013 1014 1015
    }
  }
#endif
}


1016
Object* Isolate::Throw(Object* exception, MessageLocation* location) {
1017 1018 1019 1020 1021
  DCHECK(!has_pending_exception());

  HandleScope scope(this);
  Handle<Object> exception_handle(exception, this);

1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032
  // Determine whether a message needs to be created for the given exception
  // depending on the following criteria:
  // 1) External v8::TryCatch missing: Always create a message because any
  //    JavaScript handler for a finally-block might re-throw to top-level.
  // 2) External v8::TryCatch exists: Only create a message if the handler
  //    captures messages or is verbose (which reports despite the catch).
  // 3) ReThrow from v8::TryCatch: The message from a previous throw still
  //    exists and we preserve it instead of creating a new message.
  bool requires_message = try_catch_handler() == nullptr ||
                          try_catch_handler()->is_verbose_ ||
                          try_catch_handler()->capture_message_;
1033 1034 1035 1036 1037
  bool rethrowing_message = thread_local_top()->rethrowing_message_;

  thread_local_top()->rethrowing_message_ = false;

  // Notify debugger of exception.
1038 1039
  if (is_catchable_by_javascript(exception)) {
    debug()->OnThrow(exception_handle);
1040 1041
  }

1042 1043
  // Generate the message if required.
  if (requires_message && !rethrowing_message) {
1044 1045 1046 1047
    MessageLocation computed_location;
    // If no location was specified we try to use a computed one instead.
    if (location == NULL && ComputeLocation(&computed_location)) {
      location = &computed_location;
1048 1049
    }

1050 1051 1052 1053 1054 1055 1056 1057 1058
    if (bootstrapper()->IsActive()) {
      // It's not safe to try to make message objects or collect stack traces
      // while the bootstrapper is active since the infrastructure may not have
      // been properly initialized.
      ReportBootstrappingException(exception_handle, location);
    } else {
      Handle<Object> message_obj = CreateMessage(exception_handle, location);
      thread_local_top()->pending_message_obj_ = *message_obj;

1059 1060 1061 1062 1063 1064
      // For any exception not caught by JavaScript, even when an external
      // handler is present:
      // If the abort-on-uncaught-exception flag is specified, and if the
      // embedder didn't specify a custom uncaught exception callback,
      // or if the custom callback determined that V8 should abort, then
      // abort.
1065
      if (FLAG_abort_on_uncaught_exception &&
1066 1067 1068 1069 1070 1071 1072 1073
          PredictExceptionCatcher() != CAUGHT_BY_JAVASCRIPT &&
          (!abort_on_uncaught_exception_callback_ ||
           abort_on_uncaught_exception_callback_(
               reinterpret_cast<v8::Isolate*>(this)))) {
        // Prevent endless recursion.
        FLAG_abort_on_uncaught_exception = false;
        // This flag is intended for use by JavaScript developers, so
        // print a user-friendly stack trace (not an internal one).
1074 1075 1076 1077 1078
        PrintF(stderr, "%s\n\nFROM\n",
               MessageHandler::GetLocalizedMessage(this, message_obj).get());
        PrintCurrentStackTrace(stderr);
        base::OS::Abort();
      }
1079 1080 1081
    }
  }

1082
  // Set the exception being thrown.
1083
  set_pending_exception(*exception_handle);
1084
  return heap()->exception();
1085 1086 1087
}


1088
Object* Isolate::ReThrow(Object* exception) {
1089
  DCHECK(!has_pending_exception());
1090 1091 1092

  // Set the exception being re-thrown.
  set_pending_exception(exception);
1093
  return heap()->exception();
1094 1095 1096
}


1097
Object* Isolate::UnwindAndFindHandler() {
1098 1099
  Object* exception = pending_exception();

1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122
  Code* code = nullptr;
  Context* context = nullptr;
  intptr_t offset = 0;
  Address handler_sp = nullptr;
  Address handler_fp = nullptr;

  // Special handling of termination exceptions, uncatchable by JavaScript code,
  // we unwind the handlers until the top ENTRY handler is found.
  bool catchable_by_js = is_catchable_by_javascript(exception);

  // Compute handler and stack unwinding information by performing a full walk
  // over the stack and dispatching according to the frame type.
  for (StackFrameIterator iter(this); !iter.done(); iter.Advance()) {
    StackFrame* frame = iter.frame();

    // For JSEntryStub frames we always have a handler.
    if (frame->is_entry() || frame->is_entry_construct()) {
      StackHandler* handler = frame->top_handler();

      // Restore the next handler.
      thread_local_top()->handler_ = handler->next()->address();

      // Gather information from the handler.
1123
      code = frame->LookupCode();
1124 1125 1126 1127 1128
      handler_sp = handler->address() + StackHandlerConstants::kSize;
      offset = Smi::cast(code->handler_table()->get(0))->value();
      break;
    }

1129 1130 1131 1132
    // For optimized frames we perform a lookup in the handler table.
    if (frame->is_optimized() && catchable_by_js) {
      OptimizedFrame* js_frame = static_cast<OptimizedFrame*>(frame);
      int stack_slots = 0;  // Will contain stack slot count of frame.
1133
      offset = js_frame->LookupExceptionHandlerInTable(&stack_slots, nullptr);
1134 1135 1136
      if (offset >= 0) {
        // Compute the stack pointer from the frame pointer. This ensures that
        // argument slots on the stack are dropped as returning would.
1137 1138
        Address return_sp = frame->fp() +
                            StandardFrameConstants::kFixedFrameSizeAboveFp -
1139 1140 1141 1142
                            stack_slots * kPointerSize;

        // Gather information from the frame.
        code = frame->LookupCode();
1143 1144 1145 1146 1147 1148 1149
        if (code->marked_for_deoptimization()) {
          // If the target code is lazy deoptimized, we jump to the original
          // return address, but we make a note that we are throwing, so that
          // the deoptimizer can do the right thing.
          offset = static_cast<int>(frame->pc() - code->entry());
          set_deoptimizer_lazy_throw(true);
        }
1150 1151 1152 1153
        handler_sp = return_sp;
        handler_fp = frame->fp();
        break;
      }
1154 1155
    }

1156 1157 1158
    // For interpreted frame we perform a range lookup in the handler table.
    if (frame->is_interpreted() && catchable_by_js) {
      InterpretedFrame* js_frame = static_cast<InterpretedFrame*>(frame);
1159 1160
      int context_reg = 0;  // Will contain register index holding context.
      offset = js_frame->LookupExceptionHandlerInTable(&context_reg, nullptr);
1161 1162 1163
      if (offset >= 0) {
        // Patch the bytecode offset in the interpreted frame to reflect the
        // position of the exception handler. The special builtin below will
1164 1165 1166
        // take care of continuing to dispatch at that position. Also restore
        // the correct context for the handler from the interpreter register.
        context = Context::cast(js_frame->GetInterpreterRegister(context_reg));
1167 1168 1169 1170
        js_frame->PatchBytecodeOffset(static_cast<int>(offset));
        offset = 0;

        // Gather information from the frame.
1171
        code = *builtins()->InterpreterEnterBytecodeDispatch();
1172 1173 1174 1175 1176 1177
        handler_sp = frame->sp();
        handler_fp = frame->fp();
        break;
      }
    }

1178 1179 1180
    // For JavaScript frames we perform a range lookup in the handler table.
    if (frame->is_java_script() && catchable_by_js) {
      JavaScriptFrame* js_frame = static_cast<JavaScriptFrame*>(frame);
1181 1182
      int stack_depth = 0;  // Will contain operand stack depth of handler.
      offset = js_frame->LookupExceptionHandlerInTable(&stack_depth, nullptr);
1183 1184 1185 1186 1187 1188
      if (offset >= 0) {
        // Compute the stack pointer from the frame pointer. This ensures that
        // operand stack slots are dropped for nested statements. Also restore
        // correct context for the handler which is pushed within the try-block.
        Address return_sp = frame->fp() -
                            StandardFrameConstants::kFixedFrameSizeFromFp -
1189
                            stack_depth * kPointerSize;
1190 1191 1192 1193 1194 1195 1196 1197 1198
        STATIC_ASSERT(TryBlockConstant::kElementCount == 1);
        context = Context::cast(Memory::Object_at(return_sp - kPointerSize));

        // Gather information from the frame.
        code = frame->LookupCode();
        handler_sp = return_sp;
        handler_fp = frame->fp();
        break;
      }
1199
    }
1200 1201

    RemoveMaterializedObjectsOnUnwind(frame);
1202 1203
  }

1204 1205
  // Handler must exist.
  CHECK(code != nullptr);
1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219

  // Store information to be consumed by the CEntryStub.
  thread_local_top()->pending_handler_context_ = context;
  thread_local_top()->pending_handler_code_ = code;
  thread_local_top()->pending_handler_offset_ = offset;
  thread_local_top()->pending_handler_fp_ = handler_fp;
  thread_local_top()->pending_handler_sp_ = handler_sp;

  // Return and clear pending exception.
  clear_pending_exception();
  return exception;
}


1220 1221 1222 1223
Isolate::CatchType Isolate::PredictExceptionCatcher() {
  Address external_handler = thread_local_top()->try_catch_handler_address();
  Address entry_handler = Isolate::handler(thread_local_top());
  if (IsExternalHandlerOnTop(nullptr)) return CAUGHT_BY_EXTERNAL;
1224

1225
  // Search for an exception handler by performing a full walk over the stack.
1226 1227 1228
  for (StackFrameIterator iter(this); !iter.done(); iter.Advance()) {
    StackFrame* frame = iter.frame();

1229 1230 1231
    // For JSEntryStub frames we update the JS_ENTRY handler.
    if (frame->is_entry() || frame->is_entry_construct()) {
      entry_handler = frame->top_handler()->next()->address();
1232 1233
    }

1234 1235 1236
    // For JavaScript frames we perform a lookup in the handler table.
    if (frame->is_java_script()) {
      JavaScriptFrame* js_frame = static_cast<JavaScriptFrame*>(frame);
1237
      HandlerTable::CatchPrediction prediction;
1238
      if (js_frame->LookupExceptionHandlerInTable(nullptr, &prediction) > 0) {
1239 1240 1241
        // We are conservative with our prediction: try-finally is considered
        // to always rethrow, to meet the expectation of the debugger.
        if (prediction == HandlerTable::CAUGHT) return CAUGHT_BY_JAVASCRIPT;
1242 1243 1244 1245 1246 1247 1248 1249 1250
      }
    }

    // The exception has been externally caught if and only if there is an
    // external handler which is on top of the top-most JS_ENTRY handler.
    if (external_handler != nullptr && !try_catch_handler()->is_verbose_) {
      if (entry_handler == nullptr || entry_handler > external_handler) {
        return CAUGHT_BY_EXTERNAL;
      }
1251 1252 1253 1254
    }
  }

  // Handler not found.
1255
  return NOT_CAUGHT;
1256 1257 1258
}


1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269
void Isolate::RemoveMaterializedObjectsOnUnwind(StackFrame* frame) {
  if (frame->is_optimized()) {
    bool removed = materialized_object_store_->Remove(frame->fp());
    USE(removed);
    // If there were any materialized objects, the code should be
    // marked for deopt.
    DCHECK(!removed || frame->LookupCode()->marked_for_deoptimization());
  }
}


1270
Object* Isolate::ThrowIllegalOperation() {
1271
  if (FLAG_stack_trace_on_illegal) PrintStack(stdout);
1272
  return Throw(heap()->illegal_access_string());
1273 1274 1275 1276 1277 1278 1279
}


void Isolate::ScheduleThrow(Object* exception) {
  // When scheduling a throw we first throw the exception to get the
  // error reporting if it is uncaught before rescheduling it.
  Throw(exception);
1280
  PropagatePendingExceptionToExternalTryCatch();
1281 1282 1283 1284 1285
  if (has_pending_exception()) {
    thread_local_top()->scheduled_exception_ = pending_exception();
    thread_local_top()->external_caught_exception_ = false;
    clear_pending_exception();
  }
1286 1287 1288
}


1289
void Isolate::RestorePendingMessageFromTryCatch(v8::TryCatch* handler) {
1290 1291 1292 1293
  DCHECK(handler == try_catch_handler());
  DCHECK(handler->HasCaught());
  DCHECK(handler->rethrow_);
  DCHECK(handler->capture_message_);
1294
  Object* message = reinterpret_cast<Object*>(handler->message_obj_);
1295
  DCHECK(message->IsJSMessageObject() || message->IsTheHole());
1296 1297 1298 1299
  thread_local_top()->pending_message_obj_ = message;
}


1300
void Isolate::CancelScheduledExceptionFromTryCatch(v8::TryCatch* handler) {
1301
  DCHECK(has_scheduled_exception());
1302
  if (scheduled_exception() == handler->exception_) {
1303
    DCHECK(scheduled_exception() != heap()->termination_exception());
1304 1305 1306 1307 1308
    clear_scheduled_exception();
  }
}


1309
Object* Isolate::PromoteScheduledException() {
1310
  Object* thrown = scheduled_exception();
1311 1312 1313 1314 1315 1316 1317 1318 1319
  clear_scheduled_exception();
  // Re-throw the exception to avoid getting repeated error reporting.
  return ReThrow(thrown);
}


void Isolate::PrintCurrentStackTrace(FILE* out) {
  StackTraceFrameIterator it(this);
  while (!it.done()) {
1320
    HandleScope scope(this);
1321 1322
    // Find code position if recorded in relocation info.
    JavaScriptFrame* frame = it.frame();
1323 1324 1325
    Code* code = frame->LookupCode();
    int offset = static_cast<int>(frame->pc() - code->instruction_start());
    int pos = frame->LookupCode()->SourcePosition(offset);
1326
    Handle<Object> pos_obj(Smi::FromInt(pos), this);
1327
    // Fetch function and receiver.
1328
    Handle<JSFunction> fun(frame->function());
1329
    Handle<Object> recv(frame->receiver(), this);
1330 1331 1332
    // Advance to the next JavaScript frame and determine if the
    // current frame is the top-level frame.
    it.Advance();
1333
    Handle<Object> is_top_level = factory()->ToBoolean(it.done());
1334 1335 1336 1337 1338
    // Generate and print stack trace line.
    Handle<String> line =
        Execution::GetStackTraceLine(recv, fun, pos_obj, is_top_level);
    if (line->length() > 0) {
      line->PrintOn(out);
1339
      PrintF(out, "\n");
1340 1341 1342 1343 1344
    }
  }
}


1345
bool Isolate::ComputeLocation(MessageLocation* target) {
1346 1347 1348
  StackTraceFrameIterator it(this);
  if (!it.done()) {
    JavaScriptFrame* frame = it.frame();
1349
    JSFunction* fun = frame->function();
1350 1351 1352 1353
    Object* script = fun->shared()->script();
    if (script->IsScript() &&
        !(Script::cast(script)->source()->IsUndefined())) {
      Handle<Script> casted_script(Script::cast(script));
1354 1355 1356 1357 1358 1359
      // Compute the location from the function and the relocation info of the
      // baseline code. For optimized code this will use the deoptimization
      // information to get canonical location information.
      List<FrameSummary> frames(FLAG_max_inlining_levels + 1);
      it.frame()->Summarize(&frames);
      FrameSummary& summary = frames.last();
1360
      int pos = summary.abstract_code()->SourcePosition(summary.code_offset());
1361
      *target = MessageLocation(casted_script, pos, pos + 1, handle(fun));
1362
      return true;
1363 1364
    }
  }
1365
  return false;
1366 1367 1368
}


1369 1370 1371 1372 1373
bool Isolate::ComputeLocationFromException(MessageLocation* target,
                                           Handle<Object> exception) {
  if (!exception->IsJSObject()) return false;

  Handle<Name> start_pos_symbol = factory()->error_start_pos_symbol();
1374
  Handle<Object> start_pos = JSReceiver::GetDataProperty(
1375 1376 1377 1378 1379
      Handle<JSObject>::cast(exception), start_pos_symbol);
  if (!start_pos->IsSmi()) return false;
  int start_pos_value = Handle<Smi>::cast(start_pos)->value();

  Handle<Name> end_pos_symbol = factory()->error_end_pos_symbol();
1380
  Handle<Object> end_pos = JSReceiver::GetDataProperty(
1381 1382 1383 1384 1385
      Handle<JSObject>::cast(exception), end_pos_symbol);
  if (!end_pos->IsSmi()) return false;
  int end_pos_value = Handle<Smi>::cast(end_pos)->value();

  Handle<Name> script_symbol = factory()->error_script_symbol();
1386
  Handle<Object> script = JSReceiver::GetDataProperty(
1387 1388 1389 1390 1391 1392 1393 1394 1395
      Handle<JSObject>::cast(exception), script_symbol);
  if (!script->IsScript()) return false;

  Handle<Script> cast_script(Script::cast(*script));
  *target = MessageLocation(cast_script, start_pos_value, end_pos_value);
  return true;
}


1396
bool Isolate::ComputeLocationFromStackTrace(MessageLocation* target,
1397
                                            Handle<Object> exception) {
1398
  if (!exception->IsJSObject()) return false;
1399 1400
  Handle<Name> key = factory()->stack_trace_symbol();
  Handle<Object> property =
1401
      JSReceiver::GetDataProperty(Handle<JSObject>::cast(exception), key);
1402
  if (!property->IsJSArray()) return false;
1403 1404 1405 1406 1407 1408 1409 1410
  Handle<JSArray> simple_stack_trace = Handle<JSArray>::cast(property);

  Handle<FixedArray> elements(FixedArray::cast(simple_stack_trace->elements()));
  int elements_limit = Smi::cast(simple_stack_trace->length())->value();

  for (int i = 1; i < elements_limit; i += 4) {
    Handle<JSFunction> fun =
        handle(JSFunction::cast(elements->get(i + 1)), this);
1411
    if (!fun->shared()->IsSubjectToDebugging()) continue;
1412 1413 1414 1415

    Object* script = fun->shared()->script();
    if (script->IsScript() &&
        !(Script::cast(script)->source()->IsUndefined())) {
1416
      int pos = PositionFromStackTrace(elements, i);
1417 1418
      Handle<Script> casted_script(Script::cast(script));
      *target = MessageLocation(casted_script, pos, pos + 1);
1419
      return true;
1420 1421
    }
  }
1422
  return false;
1423 1424 1425
}


1426 1427 1428 1429
Handle<JSMessageObject> Isolate::CreateMessage(Handle<Object> exception,
                                               MessageLocation* location) {
  Handle<JSArray> stack_trace_object;
  if (capture_stack_trace_for_uncaught_exceptions_) {
1430
    if (Object::IsErrorObject(this, exception)) {
1431
      // We fetch the stack trace that corresponds to this error object.
1432 1433 1434 1435 1436
      // If the lookup fails, the exception is probably not a valid Error
      // object. In that case, we fall through and capture the stack trace
      // at this throw site.
      stack_trace_object =
          GetDetailedStackTrace(Handle<JSObject>::cast(exception));
1437 1438
    }
    if (stack_trace_object.is_null()) {
1439
      // Not an error object, we capture stack and location at throw site.
1440 1441 1442 1443 1444
      stack_trace_object = CaptureCurrentStackTrace(
          stack_trace_for_uncaught_exceptions_frame_limit_,
          stack_trace_for_uncaught_exceptions_options_);
    }
  }
1445 1446 1447 1448 1449 1450
  MessageLocation computed_location;
  if (location == NULL &&
      (ComputeLocationFromException(&computed_location, exception) ||
       ComputeLocationFromStackTrace(&computed_location, exception) ||
       ComputeLocation(&computed_location))) {
    location = &computed_location;
1451
  }
1452

1453 1454 1455
  return MessageHandler::MakeMessageObject(
      this, MessageTemplate::kUncaughtException, location, exception,
      stack_trace_object);
1456 1457 1458
}


1459 1460 1461 1462 1463 1464 1465 1466 1467 1468
bool Isolate::IsJavaScriptHandlerOnTop(Object* exception) {
  DCHECK_NE(heap()->the_hole_value(), exception);

  // For uncatchable exceptions, the JavaScript handler cannot be on top.
  if (!is_catchable_by_javascript(exception)) return false;

  // Get the top-most JS_ENTRY handler, cannot be on top if it doesn't exist.
  Address entry_handler = Isolate::handler(thread_local_top());
  if (entry_handler == nullptr) return false;

1469 1470
  // Get the address of the external handler so we can compare the address to
  // determine which one is closer to the top of the stack.
1471 1472 1473 1474 1475
  Address external_handler = thread_local_top()->try_catch_handler_address();
  if (external_handler == nullptr) return true;

  // The exception has been externally caught if and only if there is an
  // external handler which is on top of the top-most JS_ENTRY handler.
1476
  //
1477 1478 1479 1480 1481
  // Note, that finally clauses would re-throw an exception unless it's aborted
  // by jumps in control flow (like return, break, etc.) and we'll have another
  // chance to set proper v8::TryCatch later.
  return (entry_handler < external_handler);
}
1482

1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505

bool Isolate::IsExternalHandlerOnTop(Object* exception) {
  DCHECK_NE(heap()->the_hole_value(), exception);

  // Get the address of the external handler so we can compare the address to
  // determine which one is closer to the top of the stack.
  Address external_handler = thread_local_top()->try_catch_handler_address();
  if (external_handler == nullptr) return false;

  // For uncatchable exceptions, the external handler is always on top.
  if (!is_catchable_by_javascript(exception)) return true;

  // Get the top-most JS_ENTRY handler, cannot be on top if it doesn't exist.
  Address entry_handler = Isolate::handler(thread_local_top());
  if (entry_handler == nullptr) return true;

  // The exception has been externally caught if and only if there is an
  // external handler which is on top of the top-most JS_ENTRY handler.
  //
  // Note, that finally clauses would re-throw an exception unless it's aborted
  // by jumps in control flow (like return, break, etc.) and we'll have another
  // chance to set proper v8::TryCatch later.
  return (entry_handler > external_handler);
1506 1507 1508 1509
}


void Isolate::ReportPendingMessages() {
1510
  Object* exception = pending_exception();
1511

1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524
  // Try to propagate the exception to an external v8::TryCatch handler. If
  // propagation was unsuccessful, then we will get another chance at reporting
  // the pending message if the exception is re-thrown.
  bool has_been_propagated = PropagatePendingExceptionToExternalTryCatch();
  if (!has_been_propagated) return;

  // Clear the pending message object early to avoid endless recursion.
  Object* message_obj = thread_local_top_.pending_message_obj_;
  clear_pending_message();

  // For uncatchable exceptions we do nothing. If needed, the exception and the
  // message have already been propagated to v8::TryCatch.
  if (!is_catchable_by_javascript(exception)) return;
1525

1526
  // Determine whether the message needs to be reported to all message handlers
1527 1528
  // depending on whether and external v8::TryCatch or an internal JavaScript
  // handler is on top.
1529 1530 1531 1532
  bool should_report_exception;
  if (IsExternalHandlerOnTop(exception)) {
    // Only report the exception if the external handler is verbose.
    should_report_exception = try_catch_handler()->is_verbose_;
1533
  } else {
1534 1535
    // Report the exception if it isn't caught by JavaScript code.
    should_report_exception = !IsJavaScriptHandlerOnTop(exception);
1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547
  }

  // Actually report the pending message to all message handlers.
  if (!message_obj->IsTheHole() && should_report_exception) {
    HandleScope scope(this);
    Handle<JSMessageObject> message(JSMessageObject::cast(message_obj));
    Handle<JSValue> script_wrapper(JSValue::cast(message->script()));
    Handle<Script> script(Script::cast(script_wrapper->value()));
    int start_pos = message->start_position();
    int end_pos = message->end_position();
    MessageLocation location(script, start_pos, end_pos);
    MessageHandler::ReportMessage(this, &location, message);
1548 1549 1550 1551
  }
}


1552
MessageLocation Isolate::GetMessageLocation() {
1553
  DCHECK(has_pending_exception());
1554

1555
  if (thread_local_top_.pending_exception_ != heap()->termination_exception() &&
1556
      !thread_local_top_.pending_message_obj_->IsTheHole()) {
1557 1558
    Handle<JSMessageObject> message_obj(
        JSMessageObject::cast(thread_local_top_.pending_message_obj_));
1559 1560
    Handle<JSValue> script_wrapper(JSValue::cast(message_obj->script()));
    Handle<Script> script(Script::cast(script_wrapper->value()));
1561 1562
    int start_pos = message_obj->start_position();
    int end_pos = message_obj->end_position();
1563 1564 1565 1566 1567 1568 1569
    return MessageLocation(script, start_pos, end_pos);
  }

  return MessageLocation();
}


1570
bool Isolate::OptionalRescheduleException(bool is_bottom_call) {
1571
  DCHECK(has_pending_exception());
1572
  PropagatePendingExceptionToExternalTryCatch();
1573

1574 1575
  bool is_termination_exception =
      pending_exception() == heap_.termination_exception();
1576

1577 1578
  // Do not reschedule the exception if this is the bottom call.
  bool clear_exception = is_bottom_call;
1579

1580 1581
  if (is_termination_exception) {
    if (is_bottom_call) {
1582 1583 1584 1585
      thread_local_top()->external_caught_exception_ = false;
      clear_pending_exception();
      return false;
    }
1586 1587 1588 1589
  } else if (thread_local_top()->external_caught_exception_) {
    // If the exception is externally caught, clear it if there are no
    // JavaScript frames on the way to the C++ frame that has the
    // external handler.
1590
    DCHECK(thread_local_top()->try_catch_handler_address() != NULL);
1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603
    Address external_handler_address =
        thread_local_top()->try_catch_handler_address();
    JavaScriptFrameIterator it(this);
    if (it.done() || (it.frame()->sp() > external_handler_address)) {
      clear_exception = true;
    }
  }

  // Clear the exception if needed.
  if (clear_exception) {
    thread_local_top()->external_caught_exception_ = false;
    clear_pending_exception();
    return false;
1604 1605 1606 1607 1608 1609 1610 1611 1612
  }

  // Reschedule the exception.
  thread_local_top()->scheduled_exception_ = pending_exception();
  clear_pending_exception();
  return true;
}


1613 1614
void Isolate::PushPromise(Handle<JSObject> promise,
                          Handle<JSFunction> function) {
1615 1616
  ThreadLocalTop* tltop = thread_local_top();
  PromiseOnStack* prev = tltop->promise_on_stack_;
1617
  Handle<JSObject> global_promise =
1618
      Handle<JSObject>::cast(global_handles()->Create(*promise));
1619 1620 1621 1622
  Handle<JSFunction> global_function =
      Handle<JSFunction>::cast(global_handles()->Create(*function));
  tltop->promise_on_stack_ =
      new PromiseOnStack(global_function, global_promise, prev);
1623 1624 1625 1626 1627 1628 1629
}


void Isolate::PopPromise() {
  ThreadLocalTop* tltop = thread_local_top();
  if (tltop->promise_on_stack_ == NULL) return;
  PromiseOnStack* prev = tltop->promise_on_stack_->prev();
1630 1631
  Handle<Object> global_function = tltop->promise_on_stack_->function();
  Handle<Object> global_promise = tltop->promise_on_stack_->promise();
1632 1633
  delete tltop->promise_on_stack_;
  tltop->promise_on_stack_ = prev;
1634 1635
  global_handles()->Destroy(global_function.location());
  global_handles()->Destroy(global_promise.location());
1636 1637 1638 1639 1640 1641 1642
}


Handle<Object> Isolate::GetPromiseOnStackOnThrow() {
  Handle<Object> undefined = factory()->undefined_value();
  ThreadLocalTop* tltop = thread_local_top();
  if (tltop->promise_on_stack_ == NULL) return undefined;
1643 1644 1645 1646 1647
  Handle<JSFunction> promise_function = tltop->promise_on_stack_->function();
  // Find the top-most try-catch or try-finally handler.
  if (PredictExceptionCatcher() != CAUGHT_BY_JAVASCRIPT) return undefined;
  for (JavaScriptFrameIterator it(this); !it.done(); it.Advance()) {
    JavaScriptFrame* frame = it.frame();
1648
    if (frame->LookupExceptionHandlerInTable(nullptr, nullptr) > 0) {
1649 1650 1651 1652 1653 1654 1655 1656
      // Throwing inside a Promise only leads to a reject if not caught by an
      // inner try-catch or try-finally.
      if (frame->function() == *promise_function) {
        return tltop->promise_on_stack_->promise();
      }
      return undefined;
    }
  }
1657 1658 1659 1660
  return undefined;
}


1661 1662 1663 1664 1665 1666 1667 1668 1669 1670
void Isolate::SetCaptureStackTraceForUncaughtExceptions(
      bool capture,
      int frame_limit,
      StackTrace::StackTraceOptions options) {
  capture_stack_trace_for_uncaught_exceptions_ = capture;
  stack_trace_for_uncaught_exceptions_frame_limit_ = frame_limit;
  stack_trace_for_uncaught_exceptions_options_ = options;
}


1671 1672 1673 1674 1675 1676
void Isolate::SetAbortOnUncaughtExceptionCallback(
    v8::Isolate::AbortOnUncaughtExceptionCallback callback) {
  abort_on_uncaught_exception_callback_ = callback;
}


1677
Handle<Context> Isolate::native_context() {
1678
  return handle(context()->native_context());
1679 1680 1681
}


1682
Handle<Context> Isolate::GetCallingNativeContext() {
1683
  JavaScriptFrameIterator it(this);
1684
  if (debug_->in_debug_scope()) {
1685 1686 1687
    while (!it.done()) {
      JavaScriptFrame* frame = it.frame();
      Context* context = Context::cast(frame->context());
1688
      if (context->native_context() == *debug_->debug_context()) {
1689 1690 1691 1692 1693 1694 1695 1696 1697
        it.Advance();
      } else {
        break;
      }
    }
  }
  if (it.done()) return Handle<Context>::null();
  JavaScriptFrame* frame = it.frame();
  Context* context = Context::cast(frame->context());
1698
  return Handle<Context>(context->native_context());
1699 1700 1701 1702
}


char* Isolate::ArchiveThread(char* to) {
1703 1704
  MemCopy(to, reinterpret_cast<char*>(thread_local_top()),
          sizeof(ThreadLocalTop));
1705
  InitializeThreadLocal();
1706 1707 1708
  clear_pending_exception();
  clear_pending_message();
  clear_scheduled_exception();
1709 1710 1711 1712 1713
  return to + sizeof(ThreadLocalTop);
}


char* Isolate::RestoreThread(char* from) {
1714 1715 1716 1717
  MemCopy(reinterpret_cast<char*>(thread_local_top()), from,
          sizeof(ThreadLocalTop));
// This might be just paranoia, but it seems to be needed in case a
// thread_local_top_ is restored on a separate OS thread.
1718 1719 1720
#ifdef USE_SIMULATOR
  thread_local_top()->simulator_ = Simulator::current(this);
#endif
1721
  DCHECK(context() == NULL || context()->IsContext());
1722 1723 1724 1725
  return from + sizeof(ThreadLocalTop);
}


1726 1727 1728 1729 1730
Isolate::ThreadDataTable::ThreadDataTable()
    : list_(NULL) {
}


1731 1732 1733 1734
Isolate::ThreadDataTable::~ThreadDataTable() {
  // TODO(svenpanne) The assertion below would fire if an embedder does not
  // cleanly dispose all Isolates before disposing v8, so we are conservative
  // and leave it out for now.
1735
  // DCHECK_NULL(list_);
1736 1737 1738
}


1739 1740 1741 1742 1743 1744 1745
Isolate::PerIsolateThreadData::~PerIsolateThreadData() {
#if defined(USE_SIMULATOR)
  delete simulator_;
#endif
}


1746
Isolate::PerIsolateThreadData*
1747 1748
    Isolate::ThreadDataTable::Lookup(Isolate* isolate,
                                     ThreadId thread_id) {
1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766
  for (PerIsolateThreadData* data = list_; data != NULL; data = data->next_) {
    if (data->Matches(isolate, thread_id)) return data;
  }
  return NULL;
}


void Isolate::ThreadDataTable::Insert(Isolate::PerIsolateThreadData* data) {
  if (list_ != NULL) list_->prev_ = data;
  data->next_ = list_;
  list_ = data;
}


void Isolate::ThreadDataTable::Remove(PerIsolateThreadData* data) {
  if (list_ == data) list_ = data->next_;
  if (data->next_ != NULL) data->next_->prev_ = data->prev_;
  if (data->prev_ != NULL) data->prev_->next_ = data->next_;
1767
  delete data;
1768 1769 1770
}


1771 1772 1773 1774 1775 1776 1777 1778 1779 1780
void Isolate::ThreadDataTable::RemoveAllThreads(Isolate* isolate) {
  PerIsolateThreadData* data = list_;
  while (data != NULL) {
    PerIsolateThreadData* next = data->next_;
    if (data->isolate() == isolate) Remove(data);
    data = next;
  }
}


1781 1782 1783 1784
#ifdef DEBUG
#define TRACE_ISOLATE(tag)                                              \
  do {                                                                  \
    if (FLAG_trace_isolates) {                                          \
1785 1786
      PrintF("Isolate %p (id %d)" #tag "\n",                            \
             reinterpret_cast<void*>(this), id());                      \
1787 1788 1789 1790 1791 1792
    }                                                                   \
  } while (false)
#else
#define TRACE_ISOLATE(tag)
#endif

1793
Isolate::Isolate(bool enable_serializer)
1794
    : embedder_data_(),
1795 1796 1797 1798 1799 1800
      entry_stack_(NULL),
      stack_trace_nesting_level_(0),
      incomplete_message_(NULL),
      bootstrapper_(NULL),
      runtime_profiler_(NULL),
      compilation_cache_(NULL),
1801
      counters_(NULL),
1802
      code_range_(NULL),
1803 1804
      logger_(NULL),
      stats_table_(NULL),
1805
      stub_cache_(NULL),
1806
      code_aging_helper_(NULL),
1807
      deoptimizer_data_(NULL),
1808
      deoptimizer_lazy_throw_(false),
jarin@chromium.org's avatar
jarin@chromium.org committed
1809
      materialized_object_store_(NULL),
1810 1811 1812 1813 1814 1815 1816 1817
      capture_stack_trace_for_uncaught_exceptions_(false),
      stack_trace_for_uncaught_exceptions_frame_limit_(0),
      stack_trace_for_uncaught_exceptions_options_(StackTrace::kOverview),
      memory_allocator_(NULL),
      keyed_lookup_cache_(NULL),
      context_slot_cache_(NULL),
      descriptor_lookup_cache_(NULL),
      handle_scope_implementer_(NULL),
1818
      unicode_cache_(NULL),
1819
      inner_pointer_to_code_cache_(NULL),
1820
      global_handles_(NULL),
1821
      eternal_handles_(NULL),
1822
      thread_manager_(NULL),
1823
      has_installed_extensions_(false),
1824
      regexp_stack_(NULL),
1825
      date_cache_(NULL),
1826
      call_descriptor_data_(NULL),
1827 1828 1829
      // TODO(bmeurer) Initialized lazily because it depends on flags; can
      // be fixed once the default isolate cleanup is done.
      random_number_generator_(NULL),
1830
      serializer_enabled_(enable_serializer),
1831
      has_fatal_error_(false),
1832
      initialized_from_snapshot_(false),
1833
      is_tail_call_elimination_enabled_(true),
1834
      cpu_profiler_(NULL),
1835
      heap_profiler_(NULL),
1836
      function_entry_hook_(NULL),
1837
      deferred_handles_head_(NULL),
1838
      optimizing_compile_dispatcher_(NULL),
1839
      stress_deopt_count_(0),
1840 1841
      virtual_handler_register_(NULL),
      virtual_slot_register_(NULL),
1842
      next_optimization_id_(0),
1843
      js_calls_from_api_counter_(0),
1844 1845 1846
#if TRACE_MAPS
      next_unique_sfi_id_(0),
#endif
1847
      use_counter_callback_(NULL),
1848
      basic_block_profiler_(NULL),
1849
      cancelable_task_manager_(new CancelableTaskManager()),
1850
      abort_on_uncaught_exception_callback_(NULL) {
1851 1852 1853 1854
  {
    base::LockGuard<base::Mutex> lock_guard(thread_data_table_mutex_.Pointer());
    CHECK(thread_data_table_);
  }
1855
  id_ = base::NoBarrier_AtomicIncrement(&isolate_counter_, 1);
1856 1857 1858
  TRACE_ISOLATE(constructor);

  memset(isolate_addresses_, 0,
1859
      sizeof(isolate_addresses_[0]) * (kIsolateAddressCount + 1));
1860 1861 1862 1863

  heap_.isolate_ = this;
  stack_guard_.isolate_ = this;

1864 1865 1866 1867 1868
  // ThreadManager is initialized early to support locking an isolate
  // before it is entered.
  thread_manager_ = new ThreadManager();
  thread_manager_->isolate_ = this;

1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884
#ifdef DEBUG
  // heap_histograms_ initializes itself.
  memset(&js_spill_information_, 0, sizeof(js_spill_information_));
#endif

  handle_scope_data_.Initialize();

#define ISOLATE_INIT_EXECUTE(type, name, initial_value)                        \
  name##_ = (initial_value);
  ISOLATE_INIT_LIST(ISOLATE_INIT_EXECUTE)
#undef ISOLATE_INIT_EXECUTE

#define ISOLATE_INIT_ARRAY_EXECUTE(type, name, length)                         \
  memset(name##_, 0, sizeof(type) * length);
  ISOLATE_INIT_ARRAY_LIST(ISOLATE_INIT_ARRAY_EXECUTE)
#undef ISOLATE_INIT_ARRAY_EXECUTE
1885 1886 1887

  InitializeLoggingAndCounters();
  debug_ = new Debug(this);
1888 1889

  init_memcopy_functions(this);
1890 1891
}

1892

1893 1894 1895 1896 1897 1898 1899 1900
void Isolate::TearDown() {
  TRACE_ISOLATE(tear_down);

  // Temporarily set this isolate as current so that various parts of
  // the isolate can access it in their destructors without having a
  // direct pointer. We don't use Enter/Exit here to avoid
  // initializing the thread data.
  PerIsolateThreadData* saved_data = CurrentPerIsolateThreadData();
1901 1902 1903
  DCHECK(base::NoBarrier_Load(&isolate_key_created_) == 1);
  Isolate* saved_isolate =
      reinterpret_cast<Isolate*>(base::Thread::GetThreadLocal(isolate_key_));
1904 1905 1906 1907
  SetIsolateThreadLocals(this, NULL);

  Deinit();

1908
  {
1909
    base::LockGuard<base::Mutex> lock_guard(thread_data_table_mutex_.Pointer());
1910
    thread_data_table_->RemoveAllThreads(this);
1911 1912
  }

1913
  delete this;
1914 1915 1916 1917 1918 1919

  // Restore the previous current isolate.
  SetIsolateThreadLocals(saved_isolate, saved_data);
}


1920 1921
void Isolate::GlobalTearDown() {
  delete thread_data_table_;
1922
  thread_data_table_ = NULL;
1923 1924 1925
}


1926 1927 1928 1929 1930 1931 1932 1933
void Isolate::ClearSerializerData() {
  delete external_reference_table_;
  external_reference_table_ = NULL;
  delete external_reference_map_;
  external_reference_map_ = NULL;
}


1934
void Isolate::Deinit() {
1935
  TRACE_ISOLATE(deinit);
1936

1937
  debug()->Unload();
1938

1939
  FreeThreadResources();
1940

1941
  if (concurrent_recompilation_enabled()) {
1942 1943 1944
    optimizing_compile_dispatcher_->Stop();
    delete optimizing_compile_dispatcher_;
    optimizing_compile_dispatcher_ = NULL;
1945
  }
1946

1947 1948 1949
  if (heap_.mark_compact_collector()->sweeping_in_progress()) {
    heap_.mark_compact_collector()->EnsureSweepingCompleted();
  }
1950

1951
  DumpAndResetCompilationStats();
1952

1953 1954 1955
  if (FLAG_print_deopt_stress) {
    PrintF(stdout, "=== Stress deopt counter: %u\n", stress_deopt_count_);
  }
1956

1957 1958 1959 1960
  if (cpu_profiler_) {
    cpu_profiler_->DeleteAllProfiles();
  }

1961 1962 1963
  // We must stop the logger before we tear down other components.
  Sampler* sampler = logger_->sampler();
  if (sampler && sampler->IsActive()) sampler->Stop();
1964

1965 1966 1967 1968
  delete deoptimizer_data_;
  deoptimizer_data_ = NULL;
  builtins_.TearDown();
  bootstrapper_->TearDown();
1969

1970 1971 1972 1973
  if (runtime_profiler_ != NULL) {
    delete runtime_profiler_;
    runtime_profiler_ = NULL;
  }
1974

1975 1976
  delete basic_block_profiler_;
  basic_block_profiler_ = NULL;
1977

1978 1979 1980
  delete heap_profiler_;
  heap_profiler_ = NULL;

1981 1982
  heap_.TearDown();
  logger_->TearDown();
1983

1984 1985 1986
  delete interpreter_;
  interpreter_ = NULL;

1987 1988
  cancelable_task_manager()->CancelAndWait();

1989 1990
  delete cpu_profiler_;
  cpu_profiler_ = NULL;
1991

1992 1993 1994
  delete root_index_map_;
  root_index_map_ = NULL;

1995
  ClearSerializerData();
1996 1997 1998 1999 2000
}


void Isolate::SetIsolateThreadLocals(Isolate* isolate,
                                     PerIsolateThreadData* data) {
2001 2002
  base::Thread::SetThreadLocal(isolate_key_, isolate);
  base::Thread::SetThreadLocal(per_isolate_thread_data_key_, data);
2003 2004 2005 2006 2007 2008
}


Isolate::~Isolate() {
  TRACE_ISOLATE(destructor);

2009 2010 2011
  // Has to be called while counters_ are still alive
  runtime_zone_.DeleteKeptSegment();

2012
  // The entry stack must be empty when we get here.
2013
  DCHECK(entry_stack_ == NULL || entry_stack_->previous_item == NULL);
2014 2015 2016 2017

  delete entry_stack_;
  entry_stack_ = NULL;

2018 2019
  delete unicode_cache_;
  unicode_cache_ = NULL;
2020

2021 2022 2023
  delete date_cache_;
  date_cache_ = NULL;

2024 2025
  delete[] call_descriptor_data_;
  call_descriptor_data_ = NULL;
2026

2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038
  delete regexp_stack_;
  regexp_stack_ = NULL;

  delete descriptor_lookup_cache_;
  descriptor_lookup_cache_ = NULL;
  delete context_slot_cache_;
  context_slot_cache_ = NULL;
  delete keyed_lookup_cache_;
  keyed_lookup_cache_ = NULL;

  delete stub_cache_;
  stub_cache_ = NULL;
2039 2040
  delete code_aging_helper_;
  code_aging_helper_ = NULL;
2041 2042 2043
  delete stats_table_;
  stats_table_ = NULL;

jarin@chromium.org's avatar
jarin@chromium.org committed
2044 2045 2046
  delete materialized_object_store_;
  materialized_object_store_ = NULL;

2047 2048 2049 2050 2051 2052 2053 2054 2055
  delete logger_;
  logger_ = NULL;

  delete counters_;
  counters_ = NULL;

  delete handle_scope_implementer_;
  handle_scope_implementer_ = NULL;

2056 2057 2058
  delete code_tracer();
  set_code_tracer(NULL);

2059 2060 2061 2062
  delete compilation_cache_;
  compilation_cache_ = NULL;
  delete bootstrapper_;
  bootstrapper_ = NULL;
2063 2064
  delete inner_pointer_to_code_cache_;
  inner_pointer_to_code_cache_ = NULL;
2065 2066 2067 2068 2069 2070 2071 2072 2073 2074

  delete thread_manager_;
  thread_manager_ = NULL;

  delete memory_allocator_;
  memory_allocator_ = NULL;
  delete code_range_;
  code_range_ = NULL;
  delete global_handles_;
  global_handles_ = NULL;
2075 2076
  delete eternal_handles_;
  eternal_handles_ = NULL;
2077

2078
  delete string_stream_debug_object_cache_;
2079 2080
  string_stream_debug_object_cache_ = NULL;

2081 2082 2083
  delete random_number_generator_;
  random_number_generator_ = NULL;

2084 2085
  delete debug_;
  debug_ = NULL;
2086

2087 2088 2089
  delete cancelable_task_manager_;
  cancelable_task_manager_ = nullptr;

2090 2091 2092 2093 2094
#if USE_SIMULATOR
  Simulator::TearDown(simulator_i_cache_, simulator_redirection_);
  simulator_i_cache_ = nullptr;
  simulator_redirection_ = nullptr;
#endif
2095 2096 2097 2098
}


void Isolate::InitializeThreadLocal() {
2099
  thread_local_top_.isolate_ = this;
2100 2101 2102 2103
  thread_local_top_.Initialize();
}


2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137
bool Isolate::PropagatePendingExceptionToExternalTryCatch() {
  Object* exception = pending_exception();

  if (IsJavaScriptHandlerOnTop(exception)) {
    thread_local_top_.external_caught_exception_ = false;
    return false;
  }

  if (!IsExternalHandlerOnTop(exception)) {
    thread_local_top_.external_caught_exception_ = false;
    return true;
  }

  thread_local_top_.external_caught_exception_ = true;
  if (!is_catchable_by_javascript(exception)) {
    try_catch_handler()->can_continue_ = false;
    try_catch_handler()->has_terminated_ = true;
    try_catch_handler()->exception_ = heap()->null_value();
  } else {
    v8::TryCatch* handler = try_catch_handler();
    DCHECK(thread_local_top_.pending_message_obj_->IsJSMessageObject() ||
           thread_local_top_.pending_message_obj_->IsTheHole());
    handler->can_continue_ = true;
    handler->has_terminated_ = false;
    handler->exception_ = pending_exception();
    // Propagate to the external try-catch only if we got an actual message.
    if (thread_local_top_.pending_message_obj_->IsTheHole()) return true;

    handler->message_obj_ = thread_local_top_.pending_message_obj_;
  }
  return true;
}


2138 2139
void Isolate::InitializeLoggingAndCounters() {
  if (logger_ == NULL) {
2140
    logger_ = new Logger(this);
2141 2142
  }
  if (counters_ == NULL) {
2143
    counters_ = new Counters(this);
2144 2145 2146 2147
  }
}


2148 2149 2150
bool Isolate::Init(Deserializer* des) {
  TRACE_ISOLATE(init);

2151 2152
  stress_deopt_count_ = FLAG_deopt_every_n_times;

2153 2154
  has_fatal_error_ = false;

2155 2156 2157 2158 2159
  if (function_entry_hook() != NULL) {
    // When function entry hooking is in effect, we have to create the code
    // stubs from scratch to get entry hooks, rather than loading the previously
    // generated stubs from disk.
    // If this assert fires, the initialization path has regressed.
2160
    DCHECK(des == NULL);
2161 2162
  }

2163
  // The initialization process does not handle memory exhaustion.
2164
  AlwaysAllocateScope always_allocate(this);
2165

2166 2167 2168
  memory_allocator_ = new MemoryAllocator(this);
  code_range_ = new CodeRange(this);

2169
  // Safe after setting Heap::isolate_, and initializing StackGuard
2170 2171
  heap_.SetStackLimits();

2172 2173 2174 2175
#define ASSIGN_ELEMENT(CamelName, hacker_name)                  \
  isolate_addresses_[Isolate::k##CamelName##Address] =          \
      reinterpret_cast<Address>(hacker_name##_address());
  FOR_EACH_ISOLATE_ADDRESS_NAME(ASSIGN_ELEMENT)
2176
#undef ASSIGN_ELEMENT
2177 2178 2179 2180 2181 2182

  compilation_cache_ = new CompilationCache(this);
  keyed_lookup_cache_ = new KeyedLookupCache();
  context_slot_cache_ = new ContextSlotCache();
  descriptor_lookup_cache_ = new DescriptorLookupCache();
  unicode_cache_ = new UnicodeCache();
2183
  inner_pointer_to_code_cache_ = new InnerPointerToCodeCache(this);
2184
  global_handles_ = new GlobalHandles(this);
2185
  eternal_handles_ = new EternalHandles();
2186
  bootstrapper_ = new Bootstrapper(this);
2187
  handle_scope_implementer_ = new HandleScopeImplementer(this);
2188
  stub_cache_ = new StubCache(this);
jarin@chromium.org's avatar
jarin@chromium.org committed
2189
  materialized_object_store_ = new MaterializedObjectStore(this);
2190 2191
  regexp_stack_ = new RegExpStack();
  regexp_stack_->isolate_ = this;
2192
  date_cache_ = new DateCache();
2193 2194
  call_descriptor_data_ =
      new CallInterfaceDescriptorData[CallDescriptors::NUMBER_OF_DESCRIPTORS];
2195 2196
  cpu_profiler_ = new CpuProfiler(this);
  heap_profiler_ = new HeapProfiler(heap());
2197
  interpreter_ = new interpreter::Interpreter(this);
2198 2199

  // Enable logging before setting up the heap
2200
  logger_->SetUp(this);
2201 2202 2203

  // Initialize other runtime facilities
#if defined(USE_SIMULATOR)
2204
#if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_ARM64 || V8_TARGET_ARCH_MIPS || \
2205
    V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_S390
2206
  Simulator::Initialize(this);
2207 2208 2209
#endif
#endif

2210
  code_aging_helper_ = new CodeAgingHelper(this);
2211

2212 2213 2214 2215 2216 2217 2218 2219
  { // NOLINT
    // Ensure that the thread has a valid stack guard.  The v8::Locker object
    // will ensure this too, but we don't have to use lockers if we are only
    // using one thread.
    ExecutionAccess lock(this);
    stack_guard_.InitThread(lock);
  }

2220
  // SetUp the object heap.
2221
  DCHECK(!heap_.HasBeenSetUp());
2222
  if (!heap_.SetUp()) {
2223
    V8::FatalProcessOutOfMemory("heap setup");
2224 2225 2226
    return false;
  }

2227
  deoptimizer_data_ = new DeoptimizerData(memory_allocator_);
2228 2229 2230 2231 2232 2233 2234

  const bool create_heap_objects = (des == NULL);
  if (create_heap_objects && !heap_.CreateHeapObjects()) {
    V8::FatalProcessOutOfMemory("heap object creation");
    return false;
  }

2235
  if (create_heap_objects) {
2236
    // Terminate the partial snapshot cache so we can iterate.
2237
    partial_snapshot_cache_.Add(heap_.undefined_value());
2238 2239
  }

2240 2241
  InitializeThreadLocal();

2242
  bootstrapper_->Initialize(create_heap_objects);
2243
  builtins_.SetUp(this, create_heap_objects);
2244

2245 2246 2247 2248
  if (FLAG_log_internal_timer_events) {
    set_event_logger(Logger::DefaultEventLoggerSentinel);
  }

2249 2250
  if (FLAG_trace_hydrogen || FLAG_trace_hydrogen_stubs) {
    PrintF("Concurrent recompilation has been disabled for tracing.\n");
2251
  } else if (OptimizingCompileDispatcher::Enabled()) {
2252
    optimizing_compile_dispatcher_ = new OptimizingCompileDispatcher(this);
2253 2254
  }

2255 2256 2257 2258
  // Initialize runtime profiler before deserialization, because collections may
  // occur, clearing/updating ICs.
  runtime_profiler_ = new RuntimeProfiler(this);

2259
  // If we are deserializing, read the state into the now-empty heap.
2260
  if (!create_heap_objects) {
2261
    des->Deserialize(this);
2262
  }
2263
  stub_cache_->Initialize();
2264 2265 2266 2267

  if (FLAG_ignition) {
    interpreter_->Initialize();
  }
2268

2269 2270 2271 2272 2273
  // Finish initialization of ThreadLocal after deserialization is done.
  clear_pending_exception();
  clear_pending_message();
  clear_scheduled_exception();

2274 2275 2276 2277
  // Deserializing may put strange things in the root array's copy of the
  // stack guard.
  heap_.SetStackLimits();

2278
  // Quiet the heap NaN if needed on target platform.
2279
  if (!create_heap_objects) Assembler::QuietNaN(heap_.nan_value());
2280

2281
  if (FLAG_trace_turbo) {
2282 2283
    // Create an empty file.
    std::ofstream(GetTurboCfgFileName().c_str(), std::ios_base::trunc);
2284 2285
  }

2286 2287 2288 2289
  CHECK_EQ(static_cast<int>(OFFSET_OF(Isolate, embedder_data_)),
           Internals::kIsolateEmbedderDataOffset);
  CHECK_EQ(static_cast<int>(OFFSET_OF(Isolate, heap_.roots_)),
           Internals::kIsolateRootsOffset);
2290 2291 2292 2293 2294 2295 2296
  CHECK_EQ(static_cast<int>(
               OFFSET_OF(Isolate, heap_.amount_of_external_allocated_memory_)),
           Internals::kAmountOfExternalAllocatedMemoryOffset);
  CHECK_EQ(static_cast<int>(OFFSET_OF(
               Isolate,
               heap_.amount_of_external_allocated_memory_at_last_global_gc_)),
           Internals::kAmountOfExternalAllocatedMemoryAtLastGlobalGCOffset);
2297

2298
  time_millis_at_init_ = heap_.MonotonicallyIncreasingTimeInMs();
2299

2300 2301
  heap_.NotifyDeserializationComplete();

2302 2303 2304 2305 2306 2307
  if (!create_heap_objects) {
    // Now that the heap is consistent, it's OK to generate the code for the
    // deopt entry table that might have been referred to by optimized code in
    // the snapshot.
    HandleScope scope(this);
    Deoptimizer::EnsureCodeForDeoptimizationEntry(
2308 2309
        this, Deoptimizer::LAZY,
        ExternalReferenceTable::kDeoptTableSerializeEntryCount - 1);
2310
  }
2311

2312
  if (!serializer_enabled()) {
2313 2314
    // Ensure that all stubs which need to be generated ahead of time, but
    // cannot be serialized into the snapshot have been generated.
2315
    HandleScope scope(this);
2316
    CodeStub::GenerateFPStubs(this);
2317
    StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(this);
2318
    StubFailureTrampolineStub::GenerateAheadOfTime(this);
2319 2320
  }

2321 2322
  initialized_from_snapshot_ = (des != NULL);

2323 2324
  if (!FLAG_inline_new) heap_.DisableInlineAllocation();

2325 2326 2327 2328
  return true;
}


2329 2330 2331 2332 2333 2334 2335 2336 2337 2338
// Initialized lazily to allow early
// v8::V8::SetAddHistogramSampleFunction calls.
StatsTable* Isolate::stats_table() {
  if (stats_table_ == NULL) {
    stats_table_ = new StatsTable;
  }
  return stats_table_;
}


2339 2340 2341 2342 2343
void Isolate::Enter() {
  Isolate* current_isolate = NULL;
  PerIsolateThreadData* current_data = CurrentPerIsolateThreadData();
  if (current_data != NULL) {
    current_isolate = current_data->isolate_;
2344
    DCHECK(current_isolate != NULL);
2345
    if (current_isolate == this) {
2346 2347 2348
      DCHECK(Current() == this);
      DCHECK(entry_stack_ != NULL);
      DCHECK(entry_stack_->previous_thread_data == NULL ||
2349 2350
             entry_stack_->previous_thread_data->thread_id().Equals(
                 ThreadId::Current()));
2351 2352 2353 2354 2355 2356 2357
      // Same thread re-enters the isolate, no need to re-init anything.
      entry_stack_->entry_count++;
      return;
    }
  }

  PerIsolateThreadData* data = FindOrAllocatePerThreadDataForThisThread();
2358 2359
  DCHECK(data != NULL);
  DCHECK(data->isolate_ == this);
2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373

  EntryStackItem* item = new EntryStackItem(current_data,
                                            current_isolate,
                                            entry_stack_);
  entry_stack_ = item;

  SetIsolateThreadLocals(this, data);

  // In case it's the first time some thread enters the isolate.
  set_thread_id(data->thread_id());
}


void Isolate::Exit() {
2374 2375
  DCHECK(entry_stack_ != NULL);
  DCHECK(entry_stack_->previous_thread_data == NULL ||
2376 2377
         entry_stack_->previous_thread_data->thread_id().Equals(
             ThreadId::Current()));
2378 2379 2380

  if (--entry_stack_->entry_count > 0) return;

2381 2382
  DCHECK(CurrentPerIsolateThreadData() != NULL);
  DCHECK(CurrentPerIsolateThreadData()->isolate_ == this);
2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397

  // Pop the stack.
  EntryStackItem* item = entry_stack_;
  entry_stack_ = item->previous_item;

  PerIsolateThreadData* previous_thread_data = item->previous_thread_data;
  Isolate* previous_isolate = item->previous_isolate;

  delete item;

  // Reinit the current thread for the isolate it was running before this one.
  SetIsolateThreadLocals(previous_isolate, previous_thread_data);
}


2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413
void Isolate::LinkDeferredHandles(DeferredHandles* deferred) {
  deferred->next_ = deferred_handles_head_;
  if (deferred_handles_head_ != NULL) {
    deferred_handles_head_->previous_ = deferred;
  }
  deferred_handles_head_ = deferred;
}


void Isolate::UnlinkDeferredHandles(DeferredHandles* deferred) {
#ifdef DEBUG
  // In debug mode assert that the linked list is well-formed.
  DeferredHandles* deferred_iterator = deferred;
  while (deferred_iterator->previous_ != NULL) {
    deferred_iterator = deferred_iterator->previous_;
  }
2414
  DCHECK(deferred_handles_head_ == deferred_iterator);
2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427
#endif
  if (deferred_handles_head_ == deferred) {
    deferred_handles_head_ = deferred_handles_head_->next_;
  }
  if (deferred->next_ != NULL) {
    deferred->next_->previous_ = deferred->previous_;
  }
  if (deferred->previous_ != NULL) {
    deferred->previous_->next_ = deferred->next_;
  }
}


2428 2429 2430 2431 2432 2433 2434 2435 2436 2437
void Isolate::DumpAndResetCompilationStats() {
  if (turbo_statistics() != nullptr) {
    OFStream os(stdout);
    os << *turbo_statistics() << std::endl;
  }
  if (hstatistics() != nullptr) hstatistics()->Print();
  delete turbo_statistics_;
  turbo_statistics_ = nullptr;
  delete hstatistics_;
  hstatistics_ = nullptr;
2438 2439
  if (FLAG_runtime_call_stats) {
    OFStream os(stdout);
2440 2441
    counters()->runtime_call_stats()->Print(os);
    counters()->runtime_call_stats()->Reset();
2442
  }
2443 2444 2445
}


2446 2447 2448 2449 2450 2451
HStatistics* Isolate::GetHStatistics() {
  if (hstatistics() == NULL) set_hstatistics(new HStatistics());
  return hstatistics();
}


2452 2453 2454 2455
CompilationStatistics* Isolate::GetTurboStatistics() {
  if (turbo_statistics() == NULL)
    set_turbo_statistics(new CompilationStatistics());
  return turbo_statistics();
2456 2457 2458
}


2459 2460 2461 2462 2463 2464
HTracer* Isolate::GetHTracer() {
  if (htracer() == NULL) set_htracer(new HTracer(id()));
  return htracer();
}


2465 2466 2467 2468 2469
CodeTracer* Isolate::GetCodeTracer() {
  if (code_tracer() == NULL) set_code_tracer(new CodeTracer(id()));
  return code_tracer();
}

2470
Map* Isolate::get_initial_js_array_map(ElementsKind kind) {
2471 2472
  if (IsFastElementsKind(kind)) {
    DisallowHeapAllocation no_gc;
2473 2474
    Object* const initial_js_array_map =
        context()->native_context()->get(Context::ArrayMapIndex(kind));
2475 2476
    if (!initial_js_array_map->IsUndefined()) {
      return Map::cast(initial_js_array_map);
2477 2478
    }
  }
2479
  return nullptr;
2480 2481 2482
}


2483 2484 2485 2486 2487 2488 2489
bool Isolate::use_crankshaft() const {
  return FLAG_crankshaft &&
         !serializer_enabled_ &&
         CpuFeatures::SupportsCrankshaft();
}


2490
bool Isolate::IsFastArrayConstructorPrototypeChainIntact() {
2491
  PropertyCell* no_elements_cell = heap()->array_protector();
2492 2493 2494
  bool cell_reports_intact =
      no_elements_cell->value()->IsSmi() &&
      Smi::cast(no_elements_cell->value())->value() == kArrayProtectorValid;
2495 2496

#ifdef DEBUG
2497 2498
  Map* root_array_map =
      get_initial_js_array_map(GetInitialFastElementsKind());
2499 2500 2501 2502 2503
  Context* native_context = context()->native_context();
  JSObject* initial_array_proto = JSObject::cast(
      native_context->get(Context::INITIAL_ARRAY_PROTOTYPE_INDEX));
  JSObject* initial_object_proto = JSObject::cast(
      native_context->get(Context::INITIAL_OBJECT_PROTOTYPE_INDEX));
2504 2505 2506 2507 2508 2509

  if (root_array_map == NULL || initial_array_proto == initial_object_proto) {
    // We are in the bootstrapping process, and the entire check sequence
    // shouldn't be performed.
    return cell_reports_intact;
  }
2510 2511

  // Check that the array prototype hasn't been altered WRT empty elements.
2512 2513 2514 2515 2516
  if (root_array_map->prototype() != initial_array_proto) {
    DCHECK_EQ(false, cell_reports_intact);
    return cell_reports_intact;
  }

2517 2518 2519
  FixedArrayBase* elements = initial_array_proto->elements();
  if (elements != heap()->empty_fixed_array() &&
      elements != heap()->empty_slow_element_dictionary()) {
2520 2521
    DCHECK_EQ(false, cell_reports_intact);
    return cell_reports_intact;
2522 2523 2524
  }

  // Check that the object prototype hasn't been altered WRT empty elements.
2525 2526
  PrototypeIterator iter(this, initial_array_proto);
  if (iter.IsAtEnd() || iter.GetCurrent() != initial_object_proto) {
2527 2528
    DCHECK_EQ(false, cell_reports_intact);
    return cell_reports_intact;
2529
  }
2530 2531 2532 2533

  elements = initial_object_proto->elements();
  if (elements != heap()->empty_fixed_array() &&
      elements != heap()->empty_slow_element_dictionary()) {
2534 2535
    DCHECK_EQ(false, cell_reports_intact);
    return cell_reports_intact;
2536 2537
  }

2538
  iter.Advance();
2539 2540 2541 2542 2543 2544 2545 2546 2547 2548
  if (!iter.IsAtEnd()) {
    DCHECK_EQ(false, cell_reports_intact);
    return cell_reports_intact;
  }

#endif

  return cell_reports_intact;
}

2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574
bool Isolate::IsArraySpeciesLookupChainIntact() {
  // Note: It would be nice to have debug checks to make sure that the
  // species protector is accurate, but this would be hard to do for most of
  // what the protector stands for:
  // - You'd need to traverse the heap to check that no Array instance has
  //   a constructor property or a modified __proto__
  // - To check that Array[Symbol.species] == Array, JS code has to execute,
  //   but JS cannot be invoked in callstack overflow situations
  // All that could be checked reliably is that
  // Array.prototype.constructor == Array. Given that limitation, no check is
  // done here. In place, there are mjsunit tests harmony/array-species* which
  // ensure that behavior is correct in various invalid protector cases.

  PropertyCell* species_cell = heap()->species_protector();
  return species_cell->value()->IsSmi() &&
         Smi::cast(species_cell->value())->value() == kArrayProtectorValid;
}

void Isolate::InvalidateArraySpeciesProtector() {
  DCHECK(factory()->species_protector()->value()->IsSmi());
  DCHECK(IsArraySpeciesLookupChainIntact());
  PropertyCell::SetValueWithInvalidation(
      factory()->species_protector(),
      handle(Smi::FromInt(kArrayProtectorInvalid), this));
  DCHECK(!IsArraySpeciesLookupChainIntact());
}
2575 2576

void Isolate::UpdateArrayProtectorOnSetElement(Handle<JSObject> object) {
2577
  DisallowHeapAllocation no_gc;
2578 2579 2580 2581 2582 2583 2584 2585 2586
  if (IsFastArrayConstructorPrototypeChainIntact() &&
      object->map()->is_prototype_map()) {
    Object* context = heap()->native_contexts_list();
    while (!context->IsUndefined()) {
      Context* current_context = Context::cast(context);
      if (current_context->get(Context::INITIAL_OBJECT_PROTOTYPE_INDEX) ==
              *object ||
          current_context->get(Context::INITIAL_ARRAY_PROTOTYPE_INDEX) ==
              *object) {
2587
        CountUsage(v8::Isolate::UseCounterFeature::kArrayProtectorDirtied);
2588 2589 2590
        PropertyCell::SetValueWithInvalidation(
            factory()->array_protector(),
            handle(Smi::FromInt(kArrayProtectorInvalid), this));
2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611
        break;
      }
      context = current_context->get(Context::NEXT_CONTEXT_LINK);
    }
  }
}


bool Isolate::IsAnyInitialArrayPrototype(Handle<JSArray> array) {
  if (array->map()->is_prototype_map()) {
    Object* context = heap()->native_contexts_list();
    while (!context->IsUndefined()) {
      Context* current_context = Context::cast(context);
      if (current_context->get(Context::INITIAL_ARRAY_PROTOTYPE_INDEX) ==
          *array) {
        return true;
      }
      context = current_context->get(Context::NEXT_CONTEXT_LINK);
    }
  }
  return false;
2612 2613 2614
}


2615 2616 2617
CallInterfaceDescriptorData* Isolate::call_descriptor_data(int index) {
  DCHECK(0 <= index && index < CallDescriptors::NUMBER_OF_DESCRIPTORS);
  return &call_descriptor_data_[index];
2618 2619 2620
}


2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633
base::RandomNumberGenerator* Isolate::random_number_generator() {
  if (random_number_generator_ == NULL) {
    if (FLAG_random_seed != 0) {
      random_number_generator_ =
          new base::RandomNumberGenerator(FLAG_random_seed);
    } else {
      random_number_generator_ = new base::RandomNumberGenerator();
    }
  }
  return random_number_generator_;
}


2634 2635 2636 2637 2638
Object* Isolate::FindCodeObject(Address a) {
  return inner_pointer_to_code_cache()->GcSafeFindCodeForInnerPointer(a);
}


2639 2640 2641 2642 2643 2644 2645 2646
#ifdef DEBUG
#define ISOLATE_FIELD_OFFSET(type, name, ignored)                       \
const intptr_t Isolate::name##_debug_offset_ = OFFSET_OF(Isolate, name##_);
ISOLATE_INIT_LIST(ISOLATE_FIELD_OFFSET)
ISOLATE_INIT_ARRAY_LIST(ISOLATE_FIELD_OFFSET)
#undef ISOLATE_FIELD_OFFSET
#endif

2647

2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658
Handle<JSObject> Isolate::SetUpSubregistry(Handle<JSObject> registry,
                                           Handle<Map> map, const char* cname) {
  Handle<String> name = factory()->InternalizeUtf8String(cname);
  Handle<JSObject> obj = factory()->NewJSObjectFromMap(map);
  JSObject::NormalizeProperties(obj, CLEAR_INOBJECT_PROPERTIES, 0,
                                "SetupSymbolRegistry");
  JSObject::AddProperty(registry, name, obj, NONE);
  return obj;
}


2659
Handle<JSObject> Isolate::GetSymbolRegistry() {
2660
  if (heap()->symbol_registry()->IsSmi()) {
2661 2662 2663 2664
    Handle<Map> map = factory()->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
    Handle<JSObject> registry = factory()->NewJSObjectFromMap(map);
    heap()->set_symbol_registry(*registry);

2665 2666 2667
    SetUpSubregistry(registry, map, "for");
    SetUpSubregistry(registry, map, "for_api");
    SetUpSubregistry(registry, map, "keyFor");
2668
    SetUpSubregistry(registry, map, "private_api");
2669 2670 2671 2672 2673
  }
  return Handle<JSObject>::cast(factory()->symbol_registry());
}


2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698
void Isolate::AddBeforeCallEnteredCallback(BeforeCallEnteredCallback callback) {
  for (int i = 0; i < before_call_entered_callbacks_.length(); i++) {
    if (callback == before_call_entered_callbacks_.at(i)) return;
  }
  before_call_entered_callbacks_.Add(callback);
}


void Isolate::RemoveBeforeCallEnteredCallback(
    BeforeCallEnteredCallback callback) {
  for (int i = 0; i < before_call_entered_callbacks_.length(); i++) {
    if (callback == before_call_entered_callbacks_.at(i)) {
      before_call_entered_callbacks_.Remove(i);
    }
  }
}


void Isolate::FireBeforeCallEnteredCallback() {
  for (int i = 0; i < before_call_entered_callbacks_.length(); i++) {
    before_call_entered_callbacks_.at(i)(reinterpret_cast<v8::Isolate*>(this));
  }
}


2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717
void Isolate::AddCallCompletedCallback(CallCompletedCallback callback) {
  for (int i = 0; i < call_completed_callbacks_.length(); i++) {
    if (callback == call_completed_callbacks_.at(i)) return;
  }
  call_completed_callbacks_.Add(callback);
}


void Isolate::RemoveCallCompletedCallback(CallCompletedCallback callback) {
  for (int i = 0; i < call_completed_callbacks_.length(); i++) {
    if (callback == call_completed_callbacks_.at(i)) {
      call_completed_callbacks_.Remove(i);
    }
  }
}


void Isolate::FireCallCompletedCallback() {
  bool has_call_completed_callbacks = !call_completed_callbacks_.is_empty();
2718 2719 2720 2721 2722
  bool run_microtasks =
      pending_microtask_count() &&
      !handle_scope_implementer()->HasMicrotasksSuppressions() &&
      handle_scope_implementer()->microtasks_policy() ==
          v8::MicrotasksPolicy::kAuto;
2723 2724 2725
  if (!has_call_completed_callbacks && !run_microtasks) return;

  if (!handle_scope_implementer()->CallDepthIsZero()) return;
2726
  if (run_microtasks) RunMicrotasks();
2727
  // Fire callbacks.  Increase call depth to prevent recursive callbacks.
2728 2729
  v8::Isolate* isolate = reinterpret_cast<v8::Isolate*>(this);
  v8::Isolate::SuppressMicrotaskExecutionScope suppress(isolate);
2730
  for (int i = 0; i < call_completed_callbacks_.length(); i++) {
2731
    call_completed_callbacks_.at(i)(isolate);
2732 2733 2734 2735
  }
}


2736 2737 2738 2739 2740 2741 2742 2743 2744
void Isolate::SetPromiseRejectCallback(PromiseRejectCallback callback) {
  promise_reject_callback_ = callback;
}


void Isolate::ReportPromiseReject(Handle<JSObject> promise,
                                  Handle<Object> value,
                                  v8::PromiseRejectEvent event) {
  if (promise_reject_callback_ == NULL) return;
2745 2746
  Handle<JSArray> stack_trace;
  if (event == v8::kPromiseRejectWithNoHandler && value->IsJSObject()) {
2747
    stack_trace = GetDetailedStackTrace(Handle<JSObject>::cast(value));
2748 2749 2750 2751
  }
  promise_reject_callback_(v8::PromiseRejectMessage(
      v8::Utils::PromiseToLocal(promise), event, v8::Utils::ToLocal(value),
      v8::Utils::StackTraceToLocal(stack_trace)));
2752 2753 2754
}


2755
void Isolate::EnqueueMicrotask(Handle<Object> microtask) {
2756
  DCHECK(microtask->IsJSFunction() || microtask->IsCallHandlerInfo());
2757 2758
  Handle<FixedArray> queue(heap()->microtask_queue(), this);
  int num_tasks = pending_microtask_count();
2759
  DCHECK(num_tasks <= queue->length());
2760 2761 2762 2763
  if (num_tasks == 0) {
    queue = factory()->NewFixedArray(8);
    heap()->set_microtask_queue(*queue);
  } else if (num_tasks == queue->length()) {
2764
    queue = factory()->CopyFixedArrayAndGrow(queue, num_tasks);
2765 2766
    heap()->set_microtask_queue(*queue);
  }
2767
  DCHECK(queue->get(num_tasks)->IsUndefined());
2768 2769 2770 2771
  queue->set(num_tasks, *microtask);
  set_pending_microtask_count(num_tasks + 1);
}

2772

2773
void Isolate::RunMicrotasks() {
2774
  // Increase call depth to prevent recursive callbacks.
2775 2776
  v8::Isolate::SuppressMicrotaskExecutionScope suppress(
      reinterpret_cast<v8::Isolate*>(this));
2777 2778 2779 2780
  RunMicrotasksInternal();
  FireMicrotasksCompletedCallback();
}

2781

2782
void Isolate::RunMicrotasksInternal() {
2783 2784 2785 2786
  while (pending_microtask_count() > 0) {
    HandleScope scope(this);
    int num_tasks = pending_microtask_count();
    Handle<FixedArray> queue(heap()->microtask_queue(), this);
2787
    DCHECK(num_tasks <= queue->length());
2788 2789 2790
    set_pending_microtask_count(0);
    heap()->set_microtask_queue(heap()->empty_fixed_array());

2791 2792
    Isolate* isolate = this;
    FOR_WITH_HANDLE_SCOPE(isolate, int, i = 0, i, i < num_tasks, i++, {
2793 2794 2795 2796
      Handle<Object> microtask(queue->get(i), this);
      if (microtask->IsJSFunction()) {
        Handle<JSFunction> microtask_function =
            Handle<JSFunction>::cast(microtask);
2797 2798
        SaveContext save(this);
        set_context(microtask_function->context()->native_context());
2799
        MaybeHandle<Object> maybe_exception;
2800 2801 2802
        MaybeHandle<Object> result = Execution::TryCall(
            this, microtask_function, factory()->undefined_value(), 0, NULL,
            &maybe_exception);
2803
        // If execution is terminating, just bail out.
2804 2805
        Handle<Object> exception;
        if (result.is_null() && maybe_exception.is_null()) {
2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817
          // Clear out any remaining callbacks in the queue.
          heap()->set_microtask_queue(heap()->empty_fixed_array());
          set_pending_microtask_count(0);
          return;
        }
      } else {
        Handle<CallHandlerInfo> callback_info =
            Handle<CallHandlerInfo>::cast(microtask);
        v8::MicrotaskCallback callback =
            v8::ToCData<v8::MicrotaskCallback>(callback_info->callback());
        void* data = v8::ToCData<void*>(callback_info->data());
        callback(data);
2818
      }
2819
    });
2820
  }
2821 2822 2823
}


2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849
void Isolate::AddMicrotasksCompletedCallback(
    MicrotasksCompletedCallback callback) {
  for (int i = 0; i < microtasks_completed_callbacks_.length(); i++) {
    if (callback == microtasks_completed_callbacks_.at(i)) return;
  }
  microtasks_completed_callbacks_.Add(callback);
}


void Isolate::RemoveMicrotasksCompletedCallback(
    MicrotasksCompletedCallback callback) {
  for (int i = 0; i < microtasks_completed_callbacks_.length(); i++) {
    if (callback == microtasks_completed_callbacks_.at(i)) {
      microtasks_completed_callbacks_.Remove(i);
    }
  }
}


void Isolate::FireMicrotasksCompletedCallback() {
  for (int i = 0; i < microtasks_completed_callbacks_.length(); i++) {
    microtasks_completed_callbacks_.at(i)(reinterpret_cast<v8::Isolate*>(this));
  }
}


2850
void Isolate::SetUseCounterCallback(v8::Isolate::UseCounterCallback callback) {
2851
  DCHECK(!use_counter_callback_);
2852 2853 2854 2855 2856
  use_counter_callback_ = callback;
}


void Isolate::CountUsage(v8::Isolate::UseCounterFeature feature) {
2857 2858 2859 2860 2861 2862 2863 2864 2865
  // The counter callback may cause the embedder to call into V8, which is not
  // generally possible during GC.
  if (heap_.gc_state() == Heap::NOT_IN_GC) {
    if (use_counter_callback_) {
      HandleScope handle_scope(this);
      use_counter_callback_(reinterpret_cast<v8::Isolate*>(this), feature);
    }
  } else {
    heap_.IncrementDeferredCount(feature);
2866 2867 2868 2869
  }
}


2870 2871 2872 2873 2874 2875 2876 2877
BasicBlockProfiler* Isolate::GetOrCreateBasicBlockProfiler() {
  if (basic_block_profiler_ == NULL) {
    basic_block_profiler_ = new BasicBlockProfiler();
  }
  return basic_block_profiler_;
}


2878
std::string Isolate::GetTurboCfgFileName() {
2879
  if (FLAG_trace_turbo_cfg_file == NULL) {
2880 2881 2882
    std::ostringstream os;
    os << "turbo-" << base::OS::GetCurrentProcessId() << "-" << id() << ".cfg";
    return os.str();
2883
  } else {
2884
    return FLAG_trace_turbo_cfg_file;
2885
  }
2886 2887 2888
}


2889 2890 2891 2892 2893 2894 2895
// Heap::detached_contexts tracks detached contexts as pairs
// (number of GC since the context was detached, the context).
void Isolate::AddDetachedContext(Handle<Context> context) {
  HandleScope scope(this);
  Handle<WeakCell> cell = factory()->NewWeakCell(context);
  Handle<FixedArray> detached_contexts(heap()->detached_contexts());
  int length = detached_contexts->length();
2896
  detached_contexts = factory()->CopyFixedArrayAndGrow(detached_contexts, 2);
2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910
  detached_contexts->set(length, Smi::FromInt(0));
  detached_contexts->set(length + 1, *cell);
  heap()->set_detached_contexts(*detached_contexts);
}


void Isolate::CheckDetachedContextsAfterGC() {
  HandleScope scope(this);
  Handle<FixedArray> detached_contexts(heap()->detached_contexts());
  int length = detached_contexts->length();
  if (length == 0) return;
  int new_length = 0;
  for (int i = 0; i < length; i += 2) {
    int mark_sweeps = Smi::cast(detached_contexts->get(i))->value();
2911
    DCHECK(detached_contexts->get(i + 1)->IsWeakCell());
2912 2913 2914 2915 2916 2917
    WeakCell* cell = WeakCell::cast(detached_contexts->get(i + 1));
    if (!cell->cleared()) {
      detached_contexts->set(new_length, Smi::FromInt(mark_sweeps + 1));
      detached_contexts->set(new_length + 1, cell);
      new_length += 2;
    }
2918
    counters()->detached_context_age_in_gc()->AddSample(mark_sweeps + 1);
2919
  }
2920 2921 2922 2923 2924
  if (FLAG_trace_detached_contexts) {
    PrintF("%d detached contexts are collected out of %d\n",
           length - new_length, length);
    for (int i = 0; i < new_length; i += 2) {
      int mark_sweeps = Smi::cast(detached_contexts->get(i))->value();
2925
      DCHECK(detached_contexts->get(i + 1)->IsWeakCell());
2926 2927 2928 2929 2930
      WeakCell* cell = WeakCell::cast(detached_contexts->get(i + 1));
      if (mark_sweeps > 3) {
        PrintF("detached context 0x%p\n survived %d GCs (leak?)\n",
               static_cast<void*>(cell->value()), mark_sweeps);
      }
2931 2932
    }
  }
2933
  if (new_length == 0) {
2934
    heap()->set_detached_contexts(heap()->empty_fixed_array());
2935
  } else if (new_length < length) {
2936 2937
    heap()->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(
        *detached_contexts, length - new_length);
2938 2939 2940 2941
  }
}


2942
bool StackLimitCheck::JsHasOverflowed(uintptr_t gap) const {
2943 2944 2945 2946 2947
  StackGuard* stack_guard = isolate_->stack_guard();
#ifdef USE_SIMULATOR
  // The simulator uses a separate JS stack.
  Address jssp_address = Simulator::current(isolate_)->get_sp();
  uintptr_t jssp = reinterpret_cast<uintptr_t>(jssp_address);
2948
  if (jssp - gap < stack_guard->real_jslimit()) return true;
2949
#endif  // USE_SIMULATOR
2950
  return GetCurrentStackPosition() - gap < stack_guard->real_climit();
2951 2952 2953
}


2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964
SaveContext::SaveContext(Isolate* isolate)
    : isolate_(isolate), prev_(isolate->save_context()) {
  if (isolate->context() != NULL) {
    context_ = Handle<Context>(isolate->context());
  }
  isolate->set_save_context(this);

  c_entry_fp_ = isolate->c_entry_fp(isolate->thread_local_top());
}


2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976
SaveContext::~SaveContext() {
  isolate_->set_context(context_.is_null() ? NULL : *context_);
  isolate_->set_save_context(prev_);
}


#ifdef DEBUG
AssertNoContextChange::AssertNoContextChange(Isolate* isolate)
    : isolate_(isolate), context_(isolate->context(), isolate) {}
#endif  // DEBUG


2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987
bool PostponeInterruptsScope::Intercept(StackGuard::InterruptFlag flag) {
  // First check whether the previous scope intercepts.
  if (prev_ && prev_->Intercept(flag)) return true;
  // Then check whether this scope intercepts.
  if ((flag & intercept_mask_)) {
    intercepted_flags_ |= flag;
    return true;
  }
  return false;
}

2988 2989
}  // namespace internal
}  // namespace v8