2011-04-01 08:01:33 +00:00
|
|
|
// Copyright 2011 the V8 project authors. All rights reserved.
|
2008-07-03 15:10:15 +00:00
|
|
|
// Redistribution and use in source and binary forms, with or without
|
|
|
|
// modification, are permitted provided that the following conditions are
|
|
|
|
// met:
|
|
|
|
//
|
|
|
|
// * Redistributions of source code must retain the above copyright
|
|
|
|
// notice, this list of conditions and the following disclaimer.
|
|
|
|
// * Redistributions in binary form must reproduce the above
|
|
|
|
// copyright notice, this list of conditions and the following
|
|
|
|
// disclaimer in the documentation and/or other materials provided
|
|
|
|
// with the distribution.
|
|
|
|
// * Neither the name of Google Inc. nor the names of its
|
|
|
|
// contributors may be used to endorse or promote products derived
|
|
|
|
// from this software without specific prior written permission.
|
|
|
|
//
|
|
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
|
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
|
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
|
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
|
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
|
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
|
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
#include "v8.h"
|
|
|
|
|
|
|
|
#include "api.h"
|
2009-12-15 09:17:15 +00:00
|
|
|
#include "bootstrapper.h"
|
2011-04-07 14:42:37 +00:00
|
|
|
#include "codegen.h"
|
2008-12-12 10:49:00 +00:00
|
|
|
#include "debug.h"
|
2010-12-07 11:31:57 +00:00
|
|
|
#include "runtime-profiler.h"
|
2009-11-05 13:27:21 +00:00
|
|
|
#include "simulator.h"
|
2008-12-12 10:49:00 +00:00
|
|
|
#include "v8threads.h"
|
2010-12-07 11:31:57 +00:00
|
|
|
#include "vm-state-inl.h"
|
2008-12-12 10:49:00 +00:00
|
|
|
|
2009-05-25 10:05:56 +00:00
|
|
|
namespace v8 {
|
|
|
|
namespace internal {
|
2008-07-03 15:10:15 +00:00
|
|
|
|
|
|
|
|
2011-03-18 20:35:07 +00:00
|
|
|
StackGuard::StackGuard()
|
|
|
|
: isolate_(NULL) {
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void StackGuard::set_interrupt_limits(const ExecutionAccess& lock) {
|
|
|
|
ASSERT(isolate_ != NULL);
|
|
|
|
// Ignore attempts to interrupt when interrupts are postponed.
|
|
|
|
if (should_postpone_interrupts(lock)) return;
|
|
|
|
thread_local_.jslimit_ = kInterruptLimit;
|
|
|
|
thread_local_.climit_ = kInterruptLimit;
|
|
|
|
isolate_->heap()->SetStackLimits();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void StackGuard::reset_limits(const ExecutionAccess& lock) {
|
|
|
|
ASSERT(isolate_ != NULL);
|
|
|
|
thread_local_.jslimit_ = thread_local_.real_jslimit_;
|
|
|
|
thread_local_.climit_ = thread_local_.real_climit_;
|
|
|
|
isolate_->heap()->SetStackLimits();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-07-03 15:10:15 +00:00
|
|
|
static Handle<Object> Invoke(bool construct,
|
|
|
|
Handle<JSFunction> func,
|
|
|
|
Handle<Object> receiver,
|
|
|
|
int argc,
|
|
|
|
Object*** args,
|
|
|
|
bool* has_pending_exception) {
|
2011-03-18 20:35:07 +00:00
|
|
|
Isolate* isolate = func->GetIsolate();
|
|
|
|
|
2008-07-03 15:10:15 +00:00
|
|
|
// Entering JavaScript.
|
2011-03-18 20:35:07 +00:00
|
|
|
VMState state(isolate, JS);
|
2008-07-03 15:10:15 +00:00
|
|
|
|
|
|
|
// Placeholder for return value.
|
2010-10-25 15:22:03 +00:00
|
|
|
MaybeObject* value = reinterpret_cast<Object*>(kZapValue);
|
2008-07-03 15:10:15 +00:00
|
|
|
|
|
|
|
typedef Object* (*JSEntryFunction)(
|
|
|
|
byte* entry,
|
|
|
|
Object* function,
|
|
|
|
Object* receiver,
|
|
|
|
int argc,
|
|
|
|
Object*** args);
|
|
|
|
|
|
|
|
Handle<Code> code;
|
|
|
|
if (construct) {
|
|
|
|
JSConstructEntryStub stub;
|
|
|
|
code = stub.GetCode();
|
|
|
|
} else {
|
|
|
|
JSEntryStub stub;
|
|
|
|
code = stub.GetCode();
|
|
|
|
}
|
|
|
|
|
2009-08-07 07:15:16 +00:00
|
|
|
// Convert calls on global objects to be calls on the global
|
|
|
|
// receiver instead to avoid having a 'this' pointer which refers
|
|
|
|
// directly to a global object.
|
|
|
|
if (receiver->IsGlobalObject()) {
|
|
|
|
Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver);
|
|
|
|
receiver = Handle<JSObject>(global->global_receiver());
|
|
|
|
}
|
|
|
|
|
2009-12-21 10:24:11 +00:00
|
|
|
// Make sure that the global object of the context we're about to
|
|
|
|
// make the current one is indeed a global object.
|
|
|
|
ASSERT(func->context()->global()->IsGlobalObject());
|
|
|
|
|
2008-07-25 07:37:58 +00:00
|
|
|
{
|
|
|
|
// Save and restore context around invocation and block the
|
2008-07-03 15:10:15 +00:00
|
|
|
// allocation of handles without explicit handle scopes.
|
2011-03-18 20:35:07 +00:00
|
|
|
SaveContext save(isolate);
|
2008-07-03 15:10:15 +00:00
|
|
|
NoHandleAllocation na;
|
|
|
|
JSEntryFunction entry = FUNCTION_CAST<JSEntryFunction>(code->entry());
|
|
|
|
|
|
|
|
// Call the function through the right JS entry stub.
|
2010-02-16 12:14:23 +00:00
|
|
|
byte* entry_address = func->code()->entry();
|
2009-10-08 12:36:12 +00:00
|
|
|
JSFunction* function = *func;
|
|
|
|
Object* receiver_pointer = *receiver;
|
|
|
|
value = CALL_GENERATED_CODE(entry, entry_address, function,
|
|
|
|
receiver_pointer, argc, args);
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
value->Verify();
|
|
|
|
#endif
|
|
|
|
|
2008-10-28 07:30:10 +00:00
|
|
|
// Update the pending exception flag and return the value.
|
2008-07-03 15:10:15 +00:00
|
|
|
*has_pending_exception = value->IsException();
|
2011-03-18 20:35:07 +00:00
|
|
|
ASSERT(*has_pending_exception == Isolate::Current()->has_pending_exception());
|
2008-10-28 07:30:10 +00:00
|
|
|
if (*has_pending_exception) {
|
2011-03-18 20:35:07 +00:00
|
|
|
isolate->ReportPendingMessages();
|
|
|
|
if (isolate->pending_exception() == Failure::OutOfMemoryException()) {
|
2011-08-04 15:18:18 +00:00
|
|
|
if (!isolate->ignore_out_of_memory()) {
|
2011-02-17 17:21:59 +00:00
|
|
|
V8::FatalProcessOutOfMemory("JS", true);
|
|
|
|
}
|
|
|
|
}
|
2008-11-04 16:23:56 +00:00
|
|
|
return Handle<Object>();
|
2008-12-05 08:35:52 +00:00
|
|
|
} else {
|
2011-03-18 20:35:07 +00:00
|
|
|
isolate->clear_pending_message();
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
2011-03-18 20:35:07 +00:00
|
|
|
return Handle<Object>(value->ToObjectUnchecked(), isolate);
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-05-16 16:33:58 +00:00
|
|
|
Handle<Object> Execution::Call(Handle<Object> callable,
|
2008-07-03 15:10:15 +00:00
|
|
|
Handle<Object> receiver,
|
|
|
|
int argc,
|
|
|
|
Object*** args,
|
2011-09-13 11:42:57 +00:00
|
|
|
bool* pending_exception,
|
|
|
|
bool convert_receiver) {
|
2011-05-16 16:33:58 +00:00
|
|
|
if (!callable->IsJSFunction()) {
|
|
|
|
callable = TryGetFunctionDelegate(callable, pending_exception);
|
|
|
|
if (*pending_exception) return callable;
|
|
|
|
}
|
|
|
|
Handle<JSFunction> func = Handle<JSFunction>::cast(callable);
|
2011-09-13 11:42:57 +00:00
|
|
|
|
|
|
|
// In non-strict mode, convert receiver.
|
|
|
|
if (convert_receiver && !receiver->IsJSReceiver() &&
|
|
|
|
!func->shared()->native() && !func->shared()->strict_mode()) {
|
|
|
|
if (receiver->IsUndefined() || receiver->IsNull()) {
|
2011-09-13 17:14:39 +00:00
|
|
|
Object* global = func->context()->global()->global_receiver();
|
2011-09-14 07:30:51 +00:00
|
|
|
// Under some circumstances, 'global' can be the JSBuiltinsObject
|
|
|
|
// In that case, don't rewrite.
|
|
|
|
// (FWIW, the same holds for GetIsolate()->global()->global_receiver().)
|
2011-09-13 17:14:39 +00:00
|
|
|
if (!global->IsJSBuiltinsObject()) receiver = Handle<Object>(global);
|
2011-09-13 11:42:57 +00:00
|
|
|
} else {
|
|
|
|
receiver = ToObject(receiver, pending_exception);
|
|
|
|
}
|
|
|
|
if (*pending_exception) return callable;
|
|
|
|
}
|
|
|
|
|
2008-07-03 15:10:15 +00:00
|
|
|
return Invoke(false, func, receiver, argc, args, pending_exception);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Handle<Object> Execution::New(Handle<JSFunction> func, int argc,
|
|
|
|
Object*** args, bool* pending_exception) {
|
2011-03-18 20:35:07 +00:00
|
|
|
return Invoke(true, func, Isolate::Current()->global(), argc, args,
|
|
|
|
pending_exception);
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Handle<Object> Execution::TryCall(Handle<JSFunction> func,
|
|
|
|
Handle<Object> receiver,
|
|
|
|
int argc,
|
|
|
|
Object*** args,
|
|
|
|
bool* caught_exception) {
|
|
|
|
// Enter a try-block while executing the JavaScript code. To avoid
|
2008-09-10 14:54:15 +00:00
|
|
|
// duplicate error printing it must be non-verbose. Also, to avoid
|
|
|
|
// creating message objects during stack overflow we shouldn't
|
|
|
|
// capture messages.
|
2008-07-03 15:10:15 +00:00
|
|
|
v8::TryCatch catcher;
|
|
|
|
catcher.SetVerbose(false);
|
2008-09-10 14:54:15 +00:00
|
|
|
catcher.SetCaptureMessage(false);
|
2008-07-03 15:10:15 +00:00
|
|
|
|
|
|
|
Handle<Object> result = Invoke(false, func, receiver, argc, args,
|
|
|
|
caught_exception);
|
|
|
|
|
|
|
|
if (*caught_exception) {
|
|
|
|
ASSERT(catcher.HasCaught());
|
2011-03-18 20:35:07 +00:00
|
|
|
Isolate* isolate = Isolate::Current();
|
|
|
|
ASSERT(isolate->has_pending_exception());
|
|
|
|
ASSERT(isolate->external_caught_exception());
|
|
|
|
if (isolate->pending_exception() ==
|
|
|
|
isolate->heap()->termination_exception()) {
|
|
|
|
result = isolate->factory()->termination_exception();
|
2009-09-01 13:55:45 +00:00
|
|
|
} else {
|
|
|
|
result = v8::Utils::OpenHandle(*catcher.Exception());
|
|
|
|
}
|
2011-03-18 20:35:07 +00:00
|
|
|
isolate->OptionalRescheduleException(true);
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
2011-03-18 20:35:07 +00:00
|
|
|
ASSERT(!Isolate::Current()->has_pending_exception());
|
|
|
|
ASSERT(!Isolate::Current()->external_caught_exception());
|
2008-07-03 15:10:15 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Handle<Object> Execution::GetFunctionDelegate(Handle<Object> object) {
|
|
|
|
ASSERT(!object->IsJSFunction());
|
2011-04-01 08:01:33 +00:00
|
|
|
Isolate* isolate = Isolate::Current();
|
|
|
|
Factory* factory = isolate->factory();
|
2008-07-03 15:10:15 +00:00
|
|
|
|
|
|
|
// If you return a function from here, it will be called when an
|
|
|
|
// attempt is made to call the given object as a function.
|
|
|
|
|
2011-09-14 12:33:57 +00:00
|
|
|
// If object is a function proxy, get its handler. Iterate if necessary.
|
2011-09-13 11:42:57 +00:00
|
|
|
Object* fun = *object;
|
|
|
|
while (fun->IsJSFunctionProxy()) {
|
|
|
|
fun = JSFunctionProxy::cast(fun)->call_trap();
|
|
|
|
}
|
|
|
|
if (fun->IsJSFunction()) return Handle<Object>(fun);
|
|
|
|
|
2008-07-03 15:10:15 +00:00
|
|
|
// Objects created through the API can have an instance-call handler
|
|
|
|
// that should be used when calling the object as a function.
|
2011-09-13 11:42:57 +00:00
|
|
|
if (fun->IsHeapObject() &&
|
|
|
|
HeapObject::cast(fun)->map()->has_instance_call_handler()) {
|
2008-07-03 15:10:15 +00:00
|
|
|
return Handle<JSFunction>(
|
2011-04-01 08:01:33 +00:00
|
|
|
isolate->global_context()->call_as_function_delegate());
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
2011-04-01 08:01:33 +00:00
|
|
|
return factory->undefined_value();
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-05-04 13:03:08 +00:00
|
|
|
Handle<Object> Execution::TryGetFunctionDelegate(Handle<Object> object,
|
|
|
|
bool* has_pending_exception) {
|
|
|
|
ASSERT(!object->IsJSFunction());
|
|
|
|
Isolate* isolate = Isolate::Current();
|
|
|
|
|
2011-09-14 12:33:57 +00:00
|
|
|
// If object is a function proxy, get its handler. Iterate if necessary.
|
2011-09-13 11:42:57 +00:00
|
|
|
Object* fun = *object;
|
|
|
|
while (fun->IsJSFunctionProxy()) {
|
|
|
|
fun = JSFunctionProxy::cast(fun)->call_trap();
|
|
|
|
}
|
|
|
|
if (fun->IsJSFunction()) return Handle<Object>(fun);
|
|
|
|
|
2011-05-04 13:03:08 +00:00
|
|
|
// Objects created through the API can have an instance-call handler
|
|
|
|
// that should be used when calling the object as a function.
|
2011-09-13 11:42:57 +00:00
|
|
|
if (fun->IsHeapObject() &&
|
|
|
|
HeapObject::cast(fun)->map()->has_instance_call_handler()) {
|
2011-05-04 13:03:08 +00:00
|
|
|
return Handle<JSFunction>(
|
|
|
|
isolate->global_context()->call_as_function_delegate());
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the Object doesn't have an instance-call handler we should
|
|
|
|
// throw a non-callable exception.
|
|
|
|
i::Handle<i::Object> error_obj = isolate->factory()->NewTypeError(
|
|
|
|
"called_non_callable", i::HandleVector<i::Object>(&object, 1));
|
|
|
|
isolate->Throw(*error_obj);
|
|
|
|
*has_pending_exception = true;
|
|
|
|
|
|
|
|
return isolate->factory()->undefined_value();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-05-20 19:33:44 +00:00
|
|
|
Handle<Object> Execution::GetConstructorDelegate(Handle<Object> object) {
|
|
|
|
ASSERT(!object->IsJSFunction());
|
2011-04-01 08:01:33 +00:00
|
|
|
Isolate* isolate = Isolate::Current();
|
2009-05-20 19:33:44 +00:00
|
|
|
|
|
|
|
// If you return a function from here, it will be called when an
|
|
|
|
// attempt is made to call the given object as a constructor.
|
|
|
|
|
2011-09-13 11:42:57 +00:00
|
|
|
// If object is a function proxies, get its handler. Iterate if necessary.
|
|
|
|
Object* fun = *object;
|
|
|
|
while (fun->IsJSFunctionProxy()) {
|
|
|
|
fun = JSFunctionProxy::cast(fun)->call_trap();
|
|
|
|
}
|
|
|
|
if (fun->IsJSFunction()) return Handle<Object>(fun);
|
|
|
|
|
2009-05-20 19:33:44 +00:00
|
|
|
// Objects created through the API can have an instance-call handler
|
|
|
|
// that should be used when calling the object as a function.
|
2011-09-13 11:42:57 +00:00
|
|
|
if (fun->IsHeapObject() &&
|
|
|
|
HeapObject::cast(fun)->map()->has_instance_call_handler()) {
|
2009-05-20 19:33:44 +00:00
|
|
|
return Handle<JSFunction>(
|
2011-04-01 08:01:33 +00:00
|
|
|
isolate->global_context()->call_as_constructor_delegate());
|
2009-05-20 19:33:44 +00:00
|
|
|
}
|
|
|
|
|
2011-04-01 08:01:33 +00:00
|
|
|
return isolate->factory()->undefined_value();
|
2009-05-20 19:33:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-05-06 11:07:52 +00:00
|
|
|
Handle<Object> Execution::TryGetConstructorDelegate(
|
|
|
|
Handle<Object> object,
|
|
|
|
bool* has_pending_exception) {
|
|
|
|
ASSERT(!object->IsJSFunction());
|
|
|
|
Isolate* isolate = Isolate::Current();
|
|
|
|
|
|
|
|
// If you return a function from here, it will be called when an
|
|
|
|
// attempt is made to call the given object as a constructor.
|
|
|
|
|
2011-09-13 11:42:57 +00:00
|
|
|
// If object is a function proxies, get its handler. Iterate if necessary.
|
|
|
|
Object* fun = *object;
|
|
|
|
while (fun->IsJSFunctionProxy()) {
|
|
|
|
fun = JSFunctionProxy::cast(fun)->call_trap();
|
|
|
|
}
|
|
|
|
if (fun->IsJSFunction()) return Handle<Object>(fun);
|
|
|
|
|
2011-05-06 11:07:52 +00:00
|
|
|
// Objects created through the API can have an instance-call handler
|
|
|
|
// that should be used when calling the object as a function.
|
2011-09-13 11:42:57 +00:00
|
|
|
if (fun->IsHeapObject() &&
|
|
|
|
HeapObject::cast(fun)->map()->has_instance_call_handler()) {
|
2011-05-06 11:07:52 +00:00
|
|
|
return Handle<JSFunction>(
|
|
|
|
isolate->global_context()->call_as_constructor_delegate());
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the Object doesn't have an instance-call handler we should
|
|
|
|
// throw a non-callable exception.
|
|
|
|
i::Handle<i::Object> error_obj = isolate->factory()->NewTypeError(
|
|
|
|
"called_non_callable", i::HandleVector<i::Object>(&object, 1));
|
|
|
|
isolate->Throw(*error_obj);
|
|
|
|
*has_pending_exception = true;
|
|
|
|
|
|
|
|
return isolate->factory()->undefined_value();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-07-03 15:10:15 +00:00
|
|
|
bool StackGuard::IsStackOverflow() {
|
2011-03-18 20:35:07 +00:00
|
|
|
ExecutionAccess access(isolate_);
|
2008-07-03 15:10:15 +00:00
|
|
|
return (thread_local_.jslimit_ != kInterruptLimit &&
|
|
|
|
thread_local_.climit_ != kInterruptLimit);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void StackGuard::EnableInterrupts() {
|
2011-03-18 20:35:07 +00:00
|
|
|
ExecutionAccess access(isolate_);
|
2010-04-14 07:36:49 +00:00
|
|
|
if (has_pending_interrupts(access)) {
|
|
|
|
set_interrupt_limits(access);
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void StackGuard::SetStackLimit(uintptr_t limit) {
|
2011-03-18 20:35:07 +00:00
|
|
|
ExecutionAccess access(isolate_);
|
2008-07-03 15:10:15 +00:00
|
|
|
// If the current limits are special (eg due to a pending interrupt) then
|
|
|
|
// leave them alone.
|
2011-05-05 18:55:31 +00:00
|
|
|
uintptr_t jslimit = SimulatorStack::JsLimitFromCLimit(isolate_, limit);
|
2009-11-05 13:59:40 +00:00
|
|
|
if (thread_local_.jslimit_ == thread_local_.real_jslimit_) {
|
2009-10-01 10:33:05 +00:00
|
|
|
thread_local_.jslimit_ = jslimit;
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
2009-11-05 13:59:40 +00:00
|
|
|
if (thread_local_.climit_ == thread_local_.real_climit_) {
|
2008-07-03 15:10:15 +00:00
|
|
|
thread_local_.climit_ = limit;
|
|
|
|
}
|
2009-11-05 13:59:40 +00:00
|
|
|
thread_local_.real_climit_ = limit;
|
|
|
|
thread_local_.real_jslimit_ = jslimit;
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void StackGuard::DisableInterrupts() {
|
2011-03-18 20:35:07 +00:00
|
|
|
ExecutionAccess access(isolate_);
|
2008-07-03 15:10:15 +00:00
|
|
|
reset_limits(access);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool StackGuard::IsInterrupted() {
|
2011-03-18 20:35:07 +00:00
|
|
|
ExecutionAccess access(isolate_);
|
2008-07-03 15:10:15 +00:00
|
|
|
return thread_local_.interrupt_flags_ & INTERRUPT;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void StackGuard::Interrupt() {
|
2011-03-18 20:35:07 +00:00
|
|
|
ExecutionAccess access(isolate_);
|
2008-07-03 15:10:15 +00:00
|
|
|
thread_local_.interrupt_flags_ |= INTERRUPT;
|
2010-04-14 07:36:49 +00:00
|
|
|
set_interrupt_limits(access);
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool StackGuard::IsPreempted() {
|
2011-03-18 20:35:07 +00:00
|
|
|
ExecutionAccess access(isolate_);
|
2008-07-03 15:10:15 +00:00
|
|
|
return thread_local_.interrupt_flags_ & PREEMPT;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void StackGuard::Preempt() {
|
2011-03-18 20:35:07 +00:00
|
|
|
ExecutionAccess access(isolate_);
|
2008-07-03 15:10:15 +00:00
|
|
|
thread_local_.interrupt_flags_ |= PREEMPT;
|
2010-04-14 07:36:49 +00:00
|
|
|
set_interrupt_limits(access);
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-08-19 15:14:11 +00:00
|
|
|
bool StackGuard::IsTerminateExecution() {
|
2011-03-18 20:35:07 +00:00
|
|
|
ExecutionAccess access(isolate_);
|
2009-08-19 15:14:11 +00:00
|
|
|
return thread_local_.interrupt_flags_ & TERMINATE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void StackGuard::TerminateExecution() {
|
2011-03-18 20:35:07 +00:00
|
|
|
ExecutionAccess access(isolate_);
|
2009-08-19 15:14:11 +00:00
|
|
|
thread_local_.interrupt_flags_ |= TERMINATE;
|
2010-04-14 07:36:49 +00:00
|
|
|
set_interrupt_limits(access);
|
2009-08-19 15:14:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-12-07 11:31:57 +00:00
|
|
|
bool StackGuard::IsRuntimeProfilerTick() {
|
2011-03-18 20:35:07 +00:00
|
|
|
ExecutionAccess access(isolate_);
|
2010-12-07 11:31:57 +00:00
|
|
|
return thread_local_.interrupt_flags_ & RUNTIME_PROFILER_TICK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void StackGuard::RequestRuntimeProfilerTick() {
|
|
|
|
// Ignore calls if we're not optimizing or if we can't get the lock.
|
2011-03-18 20:35:07 +00:00
|
|
|
if (FLAG_opt && ExecutionAccess::TryLock(isolate_)) {
|
2010-12-07 11:31:57 +00:00
|
|
|
thread_local_.interrupt_flags_ |= RUNTIME_PROFILER_TICK;
|
|
|
|
if (thread_local_.postpone_interrupts_nesting_ == 0) {
|
|
|
|
thread_local_.jslimit_ = thread_local_.climit_ = kInterruptLimit;
|
2011-03-18 20:35:07 +00:00
|
|
|
isolate_->heap()->SetStackLimits();
|
2010-12-07 11:31:57 +00:00
|
|
|
}
|
2011-03-18 20:35:07 +00:00
|
|
|
ExecutionAccess::Unlock(isolate_);
|
2010-12-07 11:31:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-04-20 16:36:13 +00:00
|
|
|
#ifdef ENABLE_DEBUGGER_SUPPORT
|
2008-07-03 15:10:15 +00:00
|
|
|
bool StackGuard::IsDebugBreak() {
|
2011-03-18 20:35:07 +00:00
|
|
|
ExecutionAccess access(isolate_);
|
2008-07-03 15:10:15 +00:00
|
|
|
return thread_local_.interrupt_flags_ & DEBUGBREAK;
|
|
|
|
}
|
|
|
|
|
2008-07-25 07:37:58 +00:00
|
|
|
|
2008-07-03 15:10:15 +00:00
|
|
|
void StackGuard::DebugBreak() {
|
2011-03-18 20:35:07 +00:00
|
|
|
ExecutionAccess access(isolate_);
|
2008-07-30 08:49:36 +00:00
|
|
|
thread_local_.interrupt_flags_ |= DEBUGBREAK;
|
2010-04-14 07:36:49 +00:00
|
|
|
set_interrupt_limits(access);
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-13 13:26:21 +00:00
|
|
|
bool StackGuard::IsDebugCommand() {
|
2011-03-18 20:35:07 +00:00
|
|
|
ExecutionAccess access(isolate_);
|
2009-03-13 13:26:21 +00:00
|
|
|
return thread_local_.interrupt_flags_ & DEBUGCOMMAND;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void StackGuard::DebugCommand() {
|
|
|
|
if (FLAG_debugger_auto_break) {
|
2011-03-18 20:35:07 +00:00
|
|
|
ExecutionAccess access(isolate_);
|
2009-03-13 13:26:21 +00:00
|
|
|
thread_local_.interrupt_flags_ |= DEBUGCOMMAND;
|
2010-04-14 07:36:49 +00:00
|
|
|
set_interrupt_limits(access);
|
2009-03-13 13:26:21 +00:00
|
|
|
}
|
|
|
|
}
|
2009-04-20 16:36:13 +00:00
|
|
|
#endif
|
2009-03-13 13:26:21 +00:00
|
|
|
|
2008-07-03 15:10:15 +00:00
|
|
|
void StackGuard::Continue(InterruptFlag after_what) {
|
2011-03-18 20:35:07 +00:00
|
|
|
ExecutionAccess access(isolate_);
|
2008-07-03 15:10:15 +00:00
|
|
|
thread_local_.interrupt_flags_ &= ~static_cast<int>(after_what);
|
2010-04-14 07:36:49 +00:00
|
|
|
if (!should_postpone_interrupts(access) && !has_pending_interrupts(access)) {
|
2008-07-03 15:10:15 +00:00
|
|
|
reset_limits(access);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
char* StackGuard::ArchiveStackGuard(char* to) {
|
2011-03-18 20:35:07 +00:00
|
|
|
ExecutionAccess access(isolate_);
|
2008-07-03 15:10:15 +00:00
|
|
|
memcpy(to, reinterpret_cast<char*>(&thread_local_), sizeof(ThreadLocal));
|
|
|
|
ThreadLocal blank;
|
2011-03-18 20:35:07 +00:00
|
|
|
|
|
|
|
// Set the stack limits using the old thread_local_.
|
|
|
|
// TODO(isolates): This was the old semantics of constructing a ThreadLocal
|
|
|
|
// (as the ctor called SetStackLimits, which looked at the
|
|
|
|
// current thread_local_ from StackGuard)-- but is this
|
|
|
|
// really what was intended?
|
|
|
|
isolate_->heap()->SetStackLimits();
|
2008-07-03 15:10:15 +00:00
|
|
|
thread_local_ = blank;
|
2011-03-18 20:35:07 +00:00
|
|
|
|
2008-07-03 15:10:15 +00:00
|
|
|
return to + sizeof(ThreadLocal);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
char* StackGuard::RestoreStackGuard(char* from) {
|
2011-03-18 20:35:07 +00:00
|
|
|
ExecutionAccess access(isolate_);
|
2008-07-03 15:10:15 +00:00
|
|
|
memcpy(reinterpret_cast<char*>(&thread_local_), from, sizeof(ThreadLocal));
|
2011-03-18 20:35:07 +00:00
|
|
|
isolate_->heap()->SetStackLimits();
|
2008-07-03 15:10:15 +00:00
|
|
|
return from + sizeof(ThreadLocal);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-09-28 12:25:21 +00:00
|
|
|
void StackGuard::FreeThreadResources() {
|
2011-07-05 15:49:39 +00:00
|
|
|
Isolate::PerIsolateThreadData* per_thread =
|
|
|
|
isolate_->FindOrAllocatePerThreadDataForThisThread();
|
|
|
|
per_thread->set_stack_limit(thread_local_.real_climit_);
|
2009-10-01 10:33:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void StackGuard::ThreadLocal::Clear() {
|
2009-11-05 13:59:40 +00:00
|
|
|
real_jslimit_ = kIllegalLimit;
|
2009-10-01 10:33:05 +00:00
|
|
|
jslimit_ = kIllegalLimit;
|
2009-11-05 13:59:40 +00:00
|
|
|
real_climit_ = kIllegalLimit;
|
2009-10-01 10:33:05 +00:00
|
|
|
climit_ = kIllegalLimit;
|
|
|
|
nesting_ = 0;
|
|
|
|
postpone_interrupts_nesting_ = 0;
|
|
|
|
interrupt_flags_ = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-05-05 18:55:31 +00:00
|
|
|
bool StackGuard::ThreadLocal::Initialize(Isolate* isolate) {
|
2011-03-18 20:35:07 +00:00
|
|
|
bool should_set_stack_limits = false;
|
2009-11-05 13:59:40 +00:00
|
|
|
if (real_climit_ == kIllegalLimit) {
|
2009-10-01 10:33:05 +00:00
|
|
|
// Takes the address of the limit variable in order to find out where
|
|
|
|
// the top of stack is right now.
|
2011-02-11 14:26:56 +00:00
|
|
|
const uintptr_t kLimitSize = FLAG_stack_size * KB;
|
2009-10-13 10:56:13 +00:00
|
|
|
uintptr_t limit = reinterpret_cast<uintptr_t>(&limit) - kLimitSize;
|
|
|
|
ASSERT(reinterpret_cast<uintptr_t>(&limit) > kLimitSize);
|
2011-05-05 18:55:31 +00:00
|
|
|
real_jslimit_ = SimulatorStack::JsLimitFromCLimit(isolate, limit);
|
|
|
|
jslimit_ = SimulatorStack::JsLimitFromCLimit(isolate, limit);
|
2009-11-05 13:59:40 +00:00
|
|
|
real_climit_ = limit;
|
2009-10-01 10:33:05 +00:00
|
|
|
climit_ = limit;
|
2011-03-18 20:35:07 +00:00
|
|
|
should_set_stack_limits = true;
|
2009-10-01 10:33:05 +00:00
|
|
|
}
|
|
|
|
nesting_ = 0;
|
|
|
|
postpone_interrupts_nesting_ = 0;
|
|
|
|
interrupt_flags_ = 0;
|
2011-03-18 20:35:07 +00:00
|
|
|
return should_set_stack_limits;
|
2009-10-01 10:33:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void StackGuard::ClearThread(const ExecutionAccess& lock) {
|
|
|
|
thread_local_.Clear();
|
2011-03-18 20:35:07 +00:00
|
|
|
isolate_->heap()->SetStackLimits();
|
2009-10-01 10:33:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void StackGuard::InitThread(const ExecutionAccess& lock) {
|
2011-05-05 18:55:31 +00:00
|
|
|
if (thread_local_.Initialize(isolate_)) isolate_->heap()->SetStackLimits();
|
|
|
|
Isolate::PerIsolateThreadData* per_thread =
|
|
|
|
isolate_->FindOrAllocatePerThreadDataForThisThread();
|
|
|
|
uintptr_t stored_limit = per_thread->stack_limit();
|
2009-10-01 10:33:05 +00:00
|
|
|
// You should hold the ExecutionAccess lock when you call this.
|
2011-03-18 20:35:07 +00:00
|
|
|
if (stored_limit != 0) {
|
2011-07-05 15:49:39 +00:00
|
|
|
SetStackLimit(stored_limit);
|
2009-10-01 10:33:05 +00:00
|
|
|
}
|
2009-09-28 12:25:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-07-03 15:10:15 +00:00
|
|
|
// --- C a l l s t o n a t i v e s ---
|
|
|
|
|
2011-03-18 20:35:07 +00:00
|
|
|
#define RETURN_NATIVE_CALL(name, argc, argv, has_pending_exception) \
|
|
|
|
do { \
|
2011-04-01 08:01:33 +00:00
|
|
|
Isolate* isolate = Isolate::Current(); \
|
2011-03-18 20:35:07 +00:00
|
|
|
Object** args[argc] = argv; \
|
|
|
|
ASSERT(has_pending_exception != NULL); \
|
2011-04-01 08:01:33 +00:00
|
|
|
return Call(isolate->name##_fun(), \
|
|
|
|
isolate->js_builtins_object(), argc, args, \
|
2011-03-18 20:35:07 +00:00
|
|
|
has_pending_exception); \
|
2008-07-03 15:10:15 +00:00
|
|
|
} while (false)
|
|
|
|
|
|
|
|
|
|
|
|
Handle<Object> Execution::ToBoolean(Handle<Object> obj) {
|
|
|
|
// See the similar code in runtime.js:ToBoolean.
|
|
|
|
if (obj->IsBoolean()) return obj;
|
|
|
|
bool result = true;
|
|
|
|
if (obj->IsString()) {
|
|
|
|
result = Handle<String>::cast(obj)->length() != 0;
|
|
|
|
} else if (obj->IsNull() || obj->IsUndefined()) {
|
|
|
|
result = false;
|
|
|
|
} else if (obj->IsNumber()) {
|
|
|
|
double value = obj->Number();
|
|
|
|
result = !((value == 0) || isnan(value));
|
|
|
|
}
|
2011-03-18 20:35:07 +00:00
|
|
|
return Handle<Object>(HEAP->ToBoolean(result));
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Handle<Object> Execution::ToNumber(Handle<Object> obj, bool* exc) {
|
|
|
|
RETURN_NATIVE_CALL(to_number, 1, { obj.location() }, exc);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Handle<Object> Execution::ToString(Handle<Object> obj, bool* exc) {
|
|
|
|
RETURN_NATIVE_CALL(to_string, 1, { obj.location() }, exc);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Handle<Object> Execution::ToDetailString(Handle<Object> obj, bool* exc) {
|
|
|
|
RETURN_NATIVE_CALL(to_detail_string, 1, { obj.location() }, exc);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Handle<Object> Execution::ToObject(Handle<Object> obj, bool* exc) {
|
2011-09-13 11:42:57 +00:00
|
|
|
if (obj->IsSpecObject()) return obj;
|
2008-07-03 15:10:15 +00:00
|
|
|
RETURN_NATIVE_CALL(to_object, 1, { obj.location() }, exc);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Handle<Object> Execution::ToInteger(Handle<Object> obj, bool* exc) {
|
|
|
|
RETURN_NATIVE_CALL(to_integer, 1, { obj.location() }, exc);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Handle<Object> Execution::ToUint32(Handle<Object> obj, bool* exc) {
|
|
|
|
RETURN_NATIVE_CALL(to_uint32, 1, { obj.location() }, exc);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Handle<Object> Execution::ToInt32(Handle<Object> obj, bool* exc) {
|
|
|
|
RETURN_NATIVE_CALL(to_int32, 1, { obj.location() }, exc);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Handle<Object> Execution::NewDate(double time, bool* exc) {
|
2011-03-18 20:35:07 +00:00
|
|
|
Handle<Object> time_obj = FACTORY->NewNumber(time);
|
2008-07-03 15:10:15 +00:00
|
|
|
RETURN_NATIVE_CALL(create_date, 1, { time_obj.location() }, exc);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#undef RETURN_NATIVE_CALL
|
|
|
|
|
|
|
|
|
2010-10-05 11:51:41 +00:00
|
|
|
Handle<JSRegExp> Execution::NewJSRegExp(Handle<String> pattern,
|
|
|
|
Handle<String> flags,
|
|
|
|
bool* exc) {
|
2011-03-18 20:35:07 +00:00
|
|
|
Handle<JSFunction> function = Handle<JSFunction>(
|
|
|
|
pattern->GetIsolate()->global_context()->regexp_function());
|
2010-10-05 11:51:41 +00:00
|
|
|
Handle<Object> re_obj = RegExpImpl::CreateRegExpLiteral(
|
2011-03-18 20:35:07 +00:00
|
|
|
function, pattern, flags, exc);
|
2010-10-05 11:51:41 +00:00
|
|
|
if (*exc) return Handle<JSRegExp>();
|
|
|
|
return Handle<JSRegExp>::cast(re_obj);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-07-03 15:10:15 +00:00
|
|
|
Handle<Object> Execution::CharAt(Handle<String> string, uint32_t index) {
|
2011-04-01 08:01:33 +00:00
|
|
|
Isolate* isolate = string->GetIsolate();
|
|
|
|
Factory* factory = isolate->factory();
|
|
|
|
|
2008-07-03 15:10:15 +00:00
|
|
|
int int_index = static_cast<int>(index);
|
|
|
|
if (int_index < 0 || int_index >= string->length()) {
|
2011-04-01 08:01:33 +00:00
|
|
|
return factory->undefined_value();
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Handle<Object> char_at =
|
2011-04-01 08:01:33 +00:00
|
|
|
GetProperty(isolate->js_builtins_object(),
|
|
|
|
factory->char_at_symbol());
|
2008-07-03 15:10:15 +00:00
|
|
|
if (!char_at->IsJSFunction()) {
|
2011-04-01 08:01:33 +00:00
|
|
|
return factory->undefined_value();
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool caught_exception;
|
2011-04-01 08:01:33 +00:00
|
|
|
Handle<Object> index_object = factory->NewNumberFromInt(int_index);
|
2008-07-03 15:10:15 +00:00
|
|
|
Object** index_arg[] = { index_object.location() };
|
|
|
|
Handle<Object> result = TryCall(Handle<JSFunction>::cast(char_at),
|
|
|
|
string,
|
|
|
|
ARRAY_SIZE(index_arg),
|
|
|
|
index_arg,
|
|
|
|
&caught_exception);
|
|
|
|
if (caught_exception) {
|
2011-04-01 08:01:33 +00:00
|
|
|
return factory->undefined_value();
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Handle<JSFunction> Execution::InstantiateFunction(
|
|
|
|
Handle<FunctionTemplateInfo> data, bool* exc) {
|
2011-04-01 08:01:33 +00:00
|
|
|
Isolate* isolate = data->GetIsolate();
|
2008-07-03 15:10:15 +00:00
|
|
|
// Fast case: see if the function has already been instantiated
|
|
|
|
int serial_number = Smi::cast(data->serial_number())->value();
|
2011-03-18 20:35:07 +00:00
|
|
|
Object* elm =
|
2011-04-01 08:01:33 +00:00
|
|
|
isolate->global_context()->function_cache()->
|
2011-03-18 20:35:07 +00:00
|
|
|
GetElementNoExceptionThrown(serial_number);
|
2009-01-13 07:13:33 +00:00
|
|
|
if (elm->IsJSFunction()) return Handle<JSFunction>(JSFunction::cast(elm));
|
2008-07-03 15:10:15 +00:00
|
|
|
// The function has not yet been instantiated in this context; do it.
|
|
|
|
Object** args[1] = { Handle<Object>::cast(data).location() };
|
|
|
|
Handle<Object> result =
|
2011-04-01 08:01:33 +00:00
|
|
|
Call(isolate->instantiate_fun(),
|
|
|
|
isolate->js_builtins_object(), 1, args, exc);
|
2008-07-03 15:10:15 +00:00
|
|
|
if (*exc) return Handle<JSFunction>::null();
|
|
|
|
return Handle<JSFunction>::cast(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Handle<JSObject> Execution::InstantiateObject(Handle<ObjectTemplateInfo> data,
|
|
|
|
bool* exc) {
|
2011-04-01 08:01:33 +00:00
|
|
|
Isolate* isolate = data->GetIsolate();
|
2008-07-03 15:10:15 +00:00
|
|
|
if (data->property_list()->IsUndefined() &&
|
|
|
|
!data->constructor()->IsUndefined()) {
|
2009-03-23 12:37:53 +00:00
|
|
|
// Initialization to make gcc happy.
|
|
|
|
Object* result = NULL;
|
2008-07-03 15:10:15 +00:00
|
|
|
{
|
2011-04-01 08:01:33 +00:00
|
|
|
HandleScope scope(isolate);
|
2008-07-03 15:10:15 +00:00
|
|
|
Handle<FunctionTemplateInfo> cons_template =
|
|
|
|
Handle<FunctionTemplateInfo>(
|
|
|
|
FunctionTemplateInfo::cast(data->constructor()));
|
|
|
|
Handle<JSFunction> cons = InstantiateFunction(cons_template, exc);
|
|
|
|
if (*exc) return Handle<JSObject>::null();
|
|
|
|
Handle<Object> value = New(cons, 0, NULL, exc);
|
|
|
|
if (*exc) return Handle<JSObject>::null();
|
|
|
|
result = *value;
|
|
|
|
}
|
|
|
|
ASSERT(!*exc);
|
|
|
|
return Handle<JSObject>(JSObject::cast(result));
|
|
|
|
} else {
|
|
|
|
Object** args[1] = { Handle<Object>::cast(data).location() };
|
|
|
|
Handle<Object> result =
|
2011-04-01 08:01:33 +00:00
|
|
|
Call(isolate->instantiate_fun(),
|
|
|
|
isolate->js_builtins_object(), 1, args, exc);
|
2008-07-03 15:10:15 +00:00
|
|
|
if (*exc) return Handle<JSObject>::null();
|
|
|
|
return Handle<JSObject>::cast(result);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Execution::ConfigureInstance(Handle<Object> instance,
|
|
|
|
Handle<Object> instance_template,
|
|
|
|
bool* exc) {
|
2011-04-01 08:01:33 +00:00
|
|
|
Isolate* isolate = Isolate::Current();
|
2008-07-03 15:10:15 +00:00
|
|
|
Object** args[2] = { instance.location(), instance_template.location() };
|
2011-04-01 08:01:33 +00:00
|
|
|
Execution::Call(isolate->configure_instance_fun(),
|
|
|
|
isolate->js_builtins_object(), 2, args, exc);
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Handle<String> Execution::GetStackTraceLine(Handle<Object> recv,
|
|
|
|
Handle<JSFunction> fun,
|
|
|
|
Handle<Object> pos,
|
|
|
|
Handle<Object> is_global) {
|
2011-04-01 08:01:33 +00:00
|
|
|
Isolate* isolate = fun->GetIsolate();
|
2008-07-03 15:10:15 +00:00
|
|
|
const int argc = 4;
|
|
|
|
Object** args[argc] = { recv.location(),
|
|
|
|
Handle<Object>::cast(fun).location(),
|
|
|
|
pos.location(),
|
|
|
|
is_global.location() };
|
|
|
|
bool caught_exception = false;
|
2011-03-18 20:35:07 +00:00
|
|
|
Handle<Object> result =
|
2011-04-01 08:01:33 +00:00
|
|
|
TryCall(isolate->get_stack_trace_line_fun(),
|
|
|
|
isolate->js_builtins_object(), argc, args,
|
2011-03-18 20:35:07 +00:00
|
|
|
&caught_exception);
|
2011-04-01 08:01:33 +00:00
|
|
|
if (caught_exception || !result->IsString()) {
|
|
|
|
return isolate->factory()->empty_symbol();
|
|
|
|
}
|
|
|
|
|
2008-07-03 15:10:15 +00:00
|
|
|
return Handle<String>::cast(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-12-12 10:49:00 +00:00
|
|
|
static Object* RuntimePreempt() {
|
2011-03-18 20:35:07 +00:00
|
|
|
Isolate* isolate = Isolate::Current();
|
|
|
|
|
2008-12-12 10:49:00 +00:00
|
|
|
// Clear the preempt request flag.
|
2011-03-18 20:35:07 +00:00
|
|
|
isolate->stack_guard()->Continue(PREEMPT);
|
2008-12-12 10:49:00 +00:00
|
|
|
|
|
|
|
ContextSwitcher::PreemptionReceived();
|
|
|
|
|
2009-04-20 16:36:13 +00:00
|
|
|
#ifdef ENABLE_DEBUGGER_SUPPORT
|
2011-03-18 20:35:07 +00:00
|
|
|
if (isolate->debug()->InDebugger()) {
|
2009-03-06 11:03:14 +00:00
|
|
|
// If currently in the debugger don't do any actual preemption but record
|
|
|
|
// that preemption occoured while in the debugger.
|
2011-03-18 20:35:07 +00:00
|
|
|
isolate->debug()->PreemptionWhileInDebugger();
|
2009-03-06 11:03:14 +00:00
|
|
|
} else {
|
|
|
|
// Perform preemption.
|
2011-05-05 18:55:31 +00:00
|
|
|
v8::Unlocker unlocker(reinterpret_cast<v8::Isolate*>(isolate));
|
2008-12-12 10:49:00 +00:00
|
|
|
Thread::YieldCPU();
|
|
|
|
}
|
2009-04-20 16:36:13 +00:00
|
|
|
#else
|
2011-03-18 20:35:07 +00:00
|
|
|
{ // NOLINT
|
|
|
|
// Perform preemption.
|
2011-05-05 18:55:31 +00:00
|
|
|
v8::Unlocker unlocker(reinterpret_cast<v8::Isolate*>(isolate));
|
2011-03-18 20:35:07 +00:00
|
|
|
Thread::YieldCPU();
|
|
|
|
}
|
2009-04-20 16:36:13 +00:00
|
|
|
#endif
|
2008-12-12 10:49:00 +00:00
|
|
|
|
2011-03-18 20:35:07 +00:00
|
|
|
return isolate->heap()->undefined_value();
|
2008-12-12 10:49:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-04-20 16:36:13 +00:00
|
|
|
#ifdef ENABLE_DEBUGGER_SUPPORT
|
2008-12-12 10:49:00 +00:00
|
|
|
Object* Execution::DebugBreakHelper() {
|
2011-03-18 20:35:07 +00:00
|
|
|
Isolate* isolate = Isolate::Current();
|
|
|
|
|
2008-12-12 10:49:00 +00:00
|
|
|
// Just continue if breaks are disabled.
|
2011-03-18 20:35:07 +00:00
|
|
|
if (isolate->debug()->disable_break()) {
|
|
|
|
return isolate->heap()->undefined_value();
|
2008-12-12 10:49:00 +00:00
|
|
|
}
|
|
|
|
|
2009-12-15 09:17:15 +00:00
|
|
|
// Ignore debug break during bootstrapping.
|
2011-03-18 20:35:07 +00:00
|
|
|
if (isolate->bootstrapper()->IsActive()) {
|
|
|
|
return isolate->heap()->undefined_value();
|
2009-12-15 09:17:15 +00:00
|
|
|
}
|
|
|
|
|
2009-07-24 06:14:23 +00:00
|
|
|
{
|
Simplify isolates access during stack iteration (WAS: Move SafeStackFrameIterator::active_count_...)
While trying to fix Mac and Windows versions for this change:
http://codereview.chromium.org/6771047/, I figured out, that we
already store an isolate in StackFrameIterator, so we can use it in
frame objects, instead of requiring it from caller.
I've changed iterators usage to the following scheme: whenever a
caller maintains an isolate pointer, it just passes it to stack
iterator, and no more worries about passing it to frame content
accessors. If a caller uses current isolate, it can omit passing it
to iterator, in this case, an iterator will use the current isolate,
too.
There was a special case with LiveEdit, which creates
detached copies of frame objects.
R=vitalyr@chromium.org
BUG=none
TEST=none
Review URL: http://codereview.chromium.org/6794019
git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@7499 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
2011-04-05 09:01:47 +00:00
|
|
|
JavaScriptFrameIterator it(isolate);
|
2009-07-24 06:14:23 +00:00
|
|
|
ASSERT(!it.done());
|
|
|
|
Object* fun = it.frame()->function();
|
|
|
|
if (fun && fun->IsJSFunction()) {
|
|
|
|
// Don't stop in builtin functions.
|
2009-07-29 11:55:26 +00:00
|
|
|
if (JSFunction::cast(fun)->IsBuiltin()) {
|
2011-03-18 20:35:07 +00:00
|
|
|
return isolate->heap()->undefined_value();
|
2009-07-24 06:14:23 +00:00
|
|
|
}
|
2009-07-29 11:55:26 +00:00
|
|
|
GlobalObject* global = JSFunction::cast(fun)->context()->global();
|
2009-07-24 06:14:23 +00:00
|
|
|
// Don't stop in debugger functions.
|
2011-03-18 20:35:07 +00:00
|
|
|
if (isolate->debug()->IsDebugGlobal(global)) {
|
|
|
|
return isolate->heap()->undefined_value();
|
2009-07-24 06:14:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-29 08:42:02 +00:00
|
|
|
// Collect the break state before clearing the flags.
|
2009-03-13 13:26:21 +00:00
|
|
|
bool debug_command_only =
|
2011-03-18 20:35:07 +00:00
|
|
|
isolate->stack_guard()->IsDebugCommand() &&
|
|
|
|
!isolate->stack_guard()->IsDebugBreak();
|
2009-03-13 13:26:21 +00:00
|
|
|
|
2010-01-15 21:14:56 +00:00
|
|
|
// Clear the debug break request flag.
|
2011-03-18 20:35:07 +00:00
|
|
|
isolate->stack_guard()->Continue(DEBUGBREAK);
|
2010-01-15 21:14:56 +00:00
|
|
|
|
|
|
|
ProcessDebugMesssages(debug_command_only);
|
|
|
|
|
|
|
|
// Return to continue execution.
|
2011-03-18 20:35:07 +00:00
|
|
|
return isolate->heap()->undefined_value();
|
2010-01-15 21:14:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Execution::ProcessDebugMesssages(bool debug_command_only) {
|
2011-04-01 08:01:33 +00:00
|
|
|
Isolate* isolate = Isolate::Current();
|
2010-01-15 21:14:56 +00:00
|
|
|
// Clear the debug command request flag.
|
2011-04-01 08:01:33 +00:00
|
|
|
isolate->stack_guard()->Continue(DEBUGCOMMAND);
|
2009-03-13 13:26:21 +00:00
|
|
|
|
2011-04-01 08:01:33 +00:00
|
|
|
HandleScope scope(isolate);
|
2008-12-12 10:49:00 +00:00
|
|
|
// Enter the debugger. Just continue if we fail to enter the debugger.
|
|
|
|
EnterDebugger debugger;
|
|
|
|
if (debugger.FailedToEnter()) {
|
2010-01-15 21:14:56 +00:00
|
|
|
return;
|
2008-12-12 10:49:00 +00:00
|
|
|
}
|
|
|
|
|
2009-05-29 08:42:02 +00:00
|
|
|
// Notify the debug event listeners. Indicate auto continue if the break was
|
|
|
|
// a debug command break.
|
2011-04-01 08:01:33 +00:00
|
|
|
isolate->debugger()->OnDebugBreak(isolate->factory()->undefined_value(),
|
|
|
|
debug_command_only);
|
2008-12-12 10:49:00 +00:00
|
|
|
}
|
2010-01-15 21:14:56 +00:00
|
|
|
|
|
|
|
|
2009-04-20 16:36:13 +00:00
|
|
|
#endif
|
2008-12-12 10:49:00 +00:00
|
|
|
|
2010-10-25 15:22:03 +00:00
|
|
|
MaybeObject* Execution::HandleStackGuardInterrupt() {
|
2011-03-18 20:35:07 +00:00
|
|
|
Isolate* isolate = Isolate::Current();
|
|
|
|
StackGuard* stack_guard = isolate->stack_guard();
|
|
|
|
isolate->counters()->stack_interrupts()->Increment();
|
|
|
|
if (stack_guard->IsRuntimeProfilerTick()) {
|
|
|
|
isolate->counters()->runtime_profiler_ticks()->Increment();
|
|
|
|
stack_guard->Continue(RUNTIME_PROFILER_TICK);
|
|
|
|
isolate->runtime_profiler()->OptimizeNow();
|
2010-12-07 11:31:57 +00:00
|
|
|
}
|
2009-04-20 16:36:13 +00:00
|
|
|
#ifdef ENABLE_DEBUGGER_SUPPORT
|
2011-03-18 20:35:07 +00:00
|
|
|
if (stack_guard->IsDebugBreak() || stack_guard->IsDebugCommand()) {
|
2009-03-13 13:26:21 +00:00
|
|
|
DebugBreakHelper();
|
|
|
|
}
|
2009-04-20 16:36:13 +00:00
|
|
|
#endif
|
2011-03-18 20:35:07 +00:00
|
|
|
if (stack_guard->IsPreempted()) RuntimePreempt();
|
|
|
|
if (stack_guard->IsTerminateExecution()) {
|
|
|
|
stack_guard->Continue(TERMINATE);
|
|
|
|
return isolate->TerminateExecution();
|
2009-08-19 15:14:11 +00:00
|
|
|
}
|
2011-03-18 20:35:07 +00:00
|
|
|
if (stack_guard->IsInterrupted()) {
|
|
|
|
stack_guard->Continue(INTERRUPT);
|
|
|
|
return isolate->StackOverflow();
|
2008-12-12 10:49:00 +00:00
|
|
|
}
|
2011-03-18 20:35:07 +00:00
|
|
|
return isolate->heap()->undefined_value();
|
2008-12-12 10:49:00 +00:00
|
|
|
}
|
|
|
|
|
2008-07-03 15:10:15 +00:00
|
|
|
} } // namespace v8::internal
|