1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "src/execution.h"
7 #include "src/bootstrapper.h"
8 #include "src/codegen.h"
9 #include "src/deoptimizer.h"
10 #include "src/isolate-inl.h"
11 #include "src/messages.h"
12 #include "src/parser.h"
13 #include "src/prettyprinter.h"
14 #include "src/vm-state-inl.h"
19 StackGuard::StackGuard()
24 void StackGuard::set_interrupt_limits(const ExecutionAccess& lock) {
25 DCHECK(isolate_ != NULL);
26 thread_local_.set_jslimit(kInterruptLimit);
27 thread_local_.set_climit(kInterruptLimit);
28 isolate_->heap()->SetStackLimits();
32 void StackGuard::reset_limits(const ExecutionAccess& lock) {
33 DCHECK(isolate_ != NULL);
34 thread_local_.set_jslimit(thread_local_.real_jslimit_);
35 thread_local_.set_climit(thread_local_.real_climit_);
36 isolate_->heap()->SetStackLimits();
40 static void PrintDeserializedCodeInfo(Handle<JSFunction> function) {
41 if (function->code() == function->shared()->code() &&
42 function->shared()->deserialized()) {
43 PrintF("[Running deserialized script");
44 Object* script = function->shared()->script();
45 if (script->IsScript()) {
46 Object* name = Script::cast(script)->name();
47 if (name->IsString()) {
48 PrintF(": %s", String::cast(name)->ToCString().get());
58 MUST_USE_RESULT MaybeHandle<Object> Invoke(bool is_construct,
59 Handle<JSFunction> function,
60 Handle<Object> receiver, int argc,
61 Handle<Object> args[]) {
62 Isolate* const isolate = function->GetIsolate();
64 // Convert calls on global objects to be calls on the global
65 // receiver instead to avoid having a 'this' pointer which refers
66 // directly to a global object.
67 if (receiver->IsGlobalObject()) {
69 handle(Handle<GlobalObject>::cast(receiver)->global_proxy(), isolate);
72 // api callbacks can be called directly.
73 if (!is_construct && function->shared()->IsApiFunction()) {
74 SaveContext save(isolate);
75 isolate->set_context(function->context());
76 // Do proper receiver conversion for non-strict mode api functions.
77 if (!receiver->IsJSReceiver() &&
78 is_sloppy(function->shared()->language_mode())) {
79 if (receiver->IsUndefined() || receiver->IsNull()) {
80 receiver = handle(function->global_proxy(), isolate);
82 ASSIGN_RETURN_ON_EXCEPTION(
83 isolate, receiver, Execution::ToObject(isolate, receiver), Object);
86 DCHECK(function->context()->global_object()->IsGlobalObject());
87 auto value = Builtins::InvokeApiFunction(function, receiver, argc, args);
88 bool has_exception = value.is_null();
89 DCHECK(has_exception == isolate->has_pending_exception());
91 isolate->ReportPendingMessages();
92 return MaybeHandle<Object>();
94 isolate->clear_pending_message();
99 // Entering JavaScript.
100 VMState<JS> state(isolate);
101 CHECK(AllowJavascriptExecution::IsAllowed(isolate));
102 if (!ThrowOnJavascriptExecution::IsAllowed(isolate)) {
103 isolate->ThrowIllegalOperation();
104 isolate->ReportPendingMessages();
105 return MaybeHandle<Object>();
108 // Placeholder for return value.
109 Object* value = NULL;
111 typedef Object* (*JSEntryFunction)(byte* entry,
117 Handle<Code> code = is_construct
118 ? isolate->factory()->js_construct_entry_code()
119 : isolate->factory()->js_entry_code();
121 // Make sure that the global object of the context we're about to
122 // make the current one is indeed a global object.
123 DCHECK(function->context()->global_object()->IsGlobalObject());
126 // Save and restore context around invocation and block the
127 // allocation of handles without explicit handle scopes.
128 SaveContext save(isolate);
129 SealHandleScope shs(isolate);
130 JSEntryFunction stub_entry = FUNCTION_CAST<JSEntryFunction>(code->entry());
132 // Call the function through the right JS entry stub.
133 byte* ignored = nullptr; // TODO(bmeurer): Remove this altogether.
134 JSFunction* func = *function;
135 Object* recv = *receiver;
136 Object*** argv = reinterpret_cast<Object***>(args);
137 if (FLAG_profile_deserialization) PrintDeserializedCodeInfo(function);
138 value = CALL_GENERATED_CODE(stub_entry, ignored, func, recv, argc, argv);
142 if (FLAG_verify_heap) {
143 value->ObjectVerify();
147 // Update the pending exception flag and return the value.
148 bool has_exception = value->IsException();
149 DCHECK(has_exception == isolate->has_pending_exception());
151 isolate->ReportPendingMessages();
152 // Reset stepping state when script exits with uncaught exception.
153 if (isolate->debug()->is_active()) {
154 isolate->debug()->ClearStepping();
156 return MaybeHandle<Object>();
158 isolate->clear_pending_message();
161 return Handle<Object>(value, isolate);
167 MaybeHandle<Object> Execution::Call(Isolate* isolate, Handle<Object> callable,
168 Handle<Object> receiver, int argc,
169 Handle<Object> argv[]) {
170 if (!callable->IsJSFunction()) {
171 ASSIGN_RETURN_ON_EXCEPTION(isolate, callable,
172 GetFunctionDelegate(isolate, callable), Object);
174 Handle<JSFunction> func = Handle<JSFunction>::cast(callable);
176 return Invoke(false, func, receiver, argc, argv);
180 MaybeHandle<Object> Execution::New(Handle<JSFunction> func,
182 Handle<Object> argv[]) {
183 return Invoke(true, func, handle(func->global_proxy()), argc, argv);
187 MaybeHandle<Object> Execution::TryCall(Handle<JSFunction> func,
188 Handle<Object> receiver, int argc,
189 Handle<Object> args[],
190 MaybeHandle<Object>* exception_out) {
191 bool is_termination = false;
192 Isolate* isolate = func->GetIsolate();
193 MaybeHandle<Object> maybe_result;
194 if (exception_out != NULL) *exception_out = MaybeHandle<Object>();
195 // Enter a try-block while executing the JavaScript code. To avoid
196 // duplicate error printing it must be non-verbose. Also, to avoid
197 // creating message objects during stack overflow we shouldn't
200 v8::TryCatch catcher(reinterpret_cast<v8::Isolate*>(isolate));
201 catcher.SetVerbose(false);
202 catcher.SetCaptureMessage(false);
204 maybe_result = Call(isolate, func, receiver, argc, args);
206 if (maybe_result.is_null()) {
207 DCHECK(catcher.HasCaught());
208 DCHECK(isolate->has_pending_exception());
209 DCHECK(isolate->external_caught_exception());
210 if (isolate->pending_exception() ==
211 isolate->heap()->termination_exception()) {
212 is_termination = true;
214 if (exception_out != NULL) {
215 *exception_out = v8::Utils::OpenHandle(*catcher.Exception());
218 isolate->OptionalRescheduleException(true);
221 DCHECK(!isolate->has_pending_exception());
224 // Re-request terminate execution interrupt to trigger later.
225 if (is_termination) isolate->stack_guard()->RequestTerminateExecution();
232 MaybeHandle<JSFunction> Execution::GetFunctionDelegate(Isolate* isolate,
233 Handle<Object> object) {
234 DCHECK(!object->IsJSFunction());
235 if (object->IsHeapObject()) {
236 DisallowHeapAllocation no_gc;
238 // If object is a function proxy, get its handler. Iterate if necessary.
239 Object* fun = *object;
240 while (fun->IsJSFunctionProxy()) {
241 fun = JSFunctionProxy::cast(fun)->call_trap();
243 if (fun->IsJSFunction()) {
244 return handle(JSFunction::cast(fun), isolate);
247 // We can also have exotic objects with [[Call]] internal methods.
248 if (fun->IsCallable()) {
249 return handle(isolate->native_context()->call_as_function_delegate(),
254 // If the Object doesn't have an instance-call handler we should
255 // throw a non-callable exception.
256 Handle<String> callsite = RenderCallSite(isolate, object);
257 THROW_NEW_ERROR(isolate,
258 NewTypeError(MessageTemplate::kCalledNonCallable, callsite),
264 MaybeHandle<JSFunction> Execution::GetConstructorDelegate(
265 Isolate* isolate, Handle<Object> object) {
266 // If you return a function from here, it will be called when an
267 // attempt is made to call the given object as a constructor.
269 DCHECK(!object->IsJSFunction());
270 if (object->IsHeapObject()) {
271 DisallowHeapAllocation no_gc;
273 // If object is a function proxies, get its handler. Iterate if necessary.
274 Object* fun = *object;
275 while (fun->IsJSFunctionProxy()) {
276 // TODO(bmeurer): This should work based on [[Construct]]; our proxies
278 fun = JSFunctionProxy::cast(fun)->call_trap();
280 if (fun->IsJSFunction()) {
281 return handle(JSFunction::cast(fun), isolate);
284 // We can also have exotic objects with [[Construct]] internal methods.
285 // TODO(bmeurer): This should use IsConstructor() as dictacted by the spec.
286 if (fun->IsCallable()) {
287 return handle(isolate->native_context()->call_as_constructor_delegate(),
292 // If the Object doesn't have an instance-call handler we should
293 // throw a non-callable exception.
294 Handle<String> callsite = RenderCallSite(isolate, object);
295 THROW_NEW_ERROR(isolate,
296 NewTypeError(MessageTemplate::kCalledNonCallable, callsite),
302 Handle<String> Execution::RenderCallSite(Isolate* isolate,
303 Handle<Object> object) {
304 MessageLocation location;
305 if (isolate->ComputeLocation(&location)) {
307 base::SmartPointer<ParseInfo> info(
308 location.function()->shared()->is_function()
309 ? new ParseInfo(&zone, location.function())
310 : new ParseInfo(&zone, location.script()));
311 if (Parser::ParseStatic(info.get())) {
312 CallPrinter printer(isolate, &zone);
313 const char* string = printer.Print(info->literal(), location.start_pos());
314 return isolate->factory()->NewStringFromAsciiChecked(string);
316 isolate->clear_pending_exception();
319 return Object::TypeOf(isolate, object);
323 void StackGuard::SetStackLimit(uintptr_t limit) {
324 ExecutionAccess access(isolate_);
325 // If the current limits are special (e.g. due to a pending interrupt) then
327 uintptr_t jslimit = SimulatorStack::JsLimitFromCLimit(isolate_, limit);
328 if (thread_local_.jslimit() == thread_local_.real_jslimit_) {
329 thread_local_.set_jslimit(jslimit);
331 if (thread_local_.climit() == thread_local_.real_climit_) {
332 thread_local_.set_climit(limit);
334 thread_local_.real_climit_ = limit;
335 thread_local_.real_jslimit_ = jslimit;
339 void StackGuard::AdjustStackLimitForSimulator() {
340 ExecutionAccess access(isolate_);
341 uintptr_t climit = thread_local_.real_climit_;
342 // If the current limits are special (e.g. due to a pending interrupt) then
344 uintptr_t jslimit = SimulatorStack::JsLimitFromCLimit(isolate_, climit);
345 if (thread_local_.jslimit() == thread_local_.real_jslimit_) {
346 thread_local_.set_jslimit(jslimit);
347 isolate_->heap()->SetStackLimits();
352 void StackGuard::EnableInterrupts() {
353 ExecutionAccess access(isolate_);
354 if (has_pending_interrupts(access)) {
355 set_interrupt_limits(access);
360 void StackGuard::DisableInterrupts() {
361 ExecutionAccess access(isolate_);
362 reset_limits(access);
366 void StackGuard::PushPostponeInterruptsScope(PostponeInterruptsScope* scope) {
367 ExecutionAccess access(isolate_);
368 // Intercept already requested interrupts.
369 int intercepted = thread_local_.interrupt_flags_ & scope->intercept_mask_;
370 scope->intercepted_flags_ = intercepted;
371 thread_local_.interrupt_flags_ &= ~intercepted;
372 if (!has_pending_interrupts(access)) reset_limits(access);
373 // Add scope to the chain.
374 scope->prev_ = thread_local_.postpone_interrupts_;
375 thread_local_.postpone_interrupts_ = scope;
379 void StackGuard::PopPostponeInterruptsScope() {
380 ExecutionAccess access(isolate_);
381 PostponeInterruptsScope* top = thread_local_.postpone_interrupts_;
382 // Make intercepted interrupts active.
383 DCHECK((thread_local_.interrupt_flags_ & top->intercept_mask_) == 0);
384 thread_local_.interrupt_flags_ |= top->intercepted_flags_;
385 if (has_pending_interrupts(access)) set_interrupt_limits(access);
386 // Remove scope from chain.
387 thread_local_.postpone_interrupts_ = top->prev_;
391 bool StackGuard::CheckInterrupt(InterruptFlag flag) {
392 ExecutionAccess access(isolate_);
393 return thread_local_.interrupt_flags_ & flag;
397 void StackGuard::RequestInterrupt(InterruptFlag flag) {
398 ExecutionAccess access(isolate_);
399 // Check the chain of PostponeInterruptsScopes for interception.
400 if (thread_local_.postpone_interrupts_ &&
401 thread_local_.postpone_interrupts_->Intercept(flag)) {
405 // Not intercepted. Set as active interrupt flag.
406 thread_local_.interrupt_flags_ |= flag;
407 set_interrupt_limits(access);
409 // If this isolate is waiting in a futex, notify it to wake up.
410 isolate_->futex_wait_list_node()->NotifyWake();
414 void StackGuard::ClearInterrupt(InterruptFlag flag) {
415 ExecutionAccess access(isolate_);
416 // Clear the interrupt flag from the chain of PostponeInterruptsScopes.
417 for (PostponeInterruptsScope* current = thread_local_.postpone_interrupts_;
419 current = current->prev_) {
420 current->intercepted_flags_ &= ~flag;
423 // Clear the interrupt flag from the active interrupt flags.
424 thread_local_.interrupt_flags_ &= ~flag;
425 if (!has_pending_interrupts(access)) reset_limits(access);
429 bool StackGuard::CheckAndClearInterrupt(InterruptFlag flag) {
430 ExecutionAccess access(isolate_);
431 bool result = (thread_local_.interrupt_flags_ & flag);
432 thread_local_.interrupt_flags_ &= ~flag;
433 if (!has_pending_interrupts(access)) reset_limits(access);
438 char* StackGuard::ArchiveStackGuard(char* to) {
439 ExecutionAccess access(isolate_);
440 MemCopy(to, reinterpret_cast<char*>(&thread_local_), sizeof(ThreadLocal));
443 // Set the stack limits using the old thread_local_.
444 // TODO(isolates): This was the old semantics of constructing a ThreadLocal
445 // (as the ctor called SetStackLimits, which looked at the
446 // current thread_local_ from StackGuard)-- but is this
447 // really what was intended?
448 isolate_->heap()->SetStackLimits();
449 thread_local_ = blank;
451 return to + sizeof(ThreadLocal);
455 char* StackGuard::RestoreStackGuard(char* from) {
456 ExecutionAccess access(isolate_);
457 MemCopy(reinterpret_cast<char*>(&thread_local_), from, sizeof(ThreadLocal));
458 isolate_->heap()->SetStackLimits();
459 return from + sizeof(ThreadLocal);
463 void StackGuard::FreeThreadResources() {
464 Isolate::PerIsolateThreadData* per_thread =
465 isolate_->FindOrAllocatePerThreadDataForThisThread();
466 per_thread->set_stack_limit(thread_local_.real_climit_);
470 void StackGuard::ThreadLocal::Clear() {
471 real_jslimit_ = kIllegalLimit;
472 set_jslimit(kIllegalLimit);
473 real_climit_ = kIllegalLimit;
474 set_climit(kIllegalLimit);
475 postpone_interrupts_ = NULL;
476 interrupt_flags_ = 0;
480 bool StackGuard::ThreadLocal::Initialize(Isolate* isolate) {
481 bool should_set_stack_limits = false;
482 if (real_climit_ == kIllegalLimit) {
483 const uintptr_t kLimitSize = FLAG_stack_size * KB;
484 DCHECK(GetCurrentStackPosition() > kLimitSize);
485 uintptr_t limit = GetCurrentStackPosition() - kLimitSize;
486 real_jslimit_ = SimulatorStack::JsLimitFromCLimit(isolate, limit);
487 set_jslimit(SimulatorStack::JsLimitFromCLimit(isolate, limit));
488 real_climit_ = limit;
490 should_set_stack_limits = true;
492 postpone_interrupts_ = NULL;
493 interrupt_flags_ = 0;
494 return should_set_stack_limits;
498 void StackGuard::ClearThread(const ExecutionAccess& lock) {
499 thread_local_.Clear();
500 isolate_->heap()->SetStackLimits();
504 void StackGuard::InitThread(const ExecutionAccess& lock) {
505 if (thread_local_.Initialize(isolate_)) isolate_->heap()->SetStackLimits();
506 Isolate::PerIsolateThreadData* per_thread =
507 isolate_->FindOrAllocatePerThreadDataForThisThread();
508 uintptr_t stored_limit = per_thread->stack_limit();
509 // You should hold the ExecutionAccess lock when you call this.
510 if (stored_limit != 0) {
511 SetStackLimit(stored_limit);
516 // --- C a l l s t o n a t i v e s ---
518 #define RETURN_NATIVE_CALL(name, args) \
520 Handle<Object> argv[] = args; \
521 return Call(isolate, isolate->name##_fun(), \
522 isolate->factory()->undefined_value(), arraysize(argv), argv); \
526 MaybeHandle<Object> Execution::ToDetailString(
527 Isolate* isolate, Handle<Object> obj) {
528 RETURN_NATIVE_CALL(to_detail_string, { obj });
532 MaybeHandle<Object> Execution::ToInteger(
533 Isolate* isolate, Handle<Object> obj) {
534 RETURN_NATIVE_CALL(to_integer, { obj });
538 MaybeHandle<Object> Execution::ToLength(
539 Isolate* isolate, Handle<Object> obj) {
540 RETURN_NATIVE_CALL(to_length, { obj });
544 MaybeHandle<Object> Execution::NewDate(Isolate* isolate, double time) {
545 Handle<Object> time_obj = isolate->factory()->NewNumber(time);
546 RETURN_NATIVE_CALL(create_date, { time_obj });
550 #undef RETURN_NATIVE_CALL
553 MaybeHandle<Object> Execution::ToInt32(Isolate* isolate, Handle<Object> obj) {
554 ASSIGN_RETURN_ON_EXCEPTION(isolate, obj, Object::ToNumber(obj), Object);
555 return isolate->factory()->NewNumberFromInt(DoubleToInt32(obj->Number()));
559 MaybeHandle<Object> Execution::ToObject(Isolate* isolate, Handle<Object> obj) {
560 Handle<JSReceiver> receiver;
561 if (JSReceiver::ToObject(isolate, obj).ToHandle(&receiver)) {
565 isolate, NewTypeError(MessageTemplate::kUndefinedOrNullToObject), Object);
569 MaybeHandle<Object> Execution::ToUint32(Isolate* isolate, Handle<Object> obj) {
570 ASSIGN_RETURN_ON_EXCEPTION(isolate, obj, Object::ToNumber(obj), Object);
571 return isolate->factory()->NewNumberFromUint(DoubleToUint32(obj->Number()));
575 MaybeHandle<JSRegExp> Execution::NewJSRegExp(Handle<String> pattern,
576 Handle<String> flags) {
577 Isolate* isolate = pattern->GetIsolate();
578 Handle<JSFunction> function = Handle<JSFunction>(
579 isolate->native_context()->regexp_function());
580 Handle<Object> re_obj;
581 ASSIGN_RETURN_ON_EXCEPTION(
583 RegExpImpl::CreateRegExpLiteral(function, pattern, flags),
585 return Handle<JSRegExp>::cast(re_obj);
589 Handle<String> Execution::GetStackTraceLine(Handle<Object> recv,
590 Handle<JSFunction> fun,
592 Handle<Object> is_global) {
593 Isolate* isolate = fun->GetIsolate();
594 Handle<Object> args[] = { recv, fun, pos, is_global };
595 MaybeHandle<Object> maybe_result =
596 TryCall(isolate->get_stack_trace_line_fun(),
597 isolate->factory()->undefined_value(), arraysize(args), args);
598 Handle<Object> result;
599 if (!maybe_result.ToHandle(&result) || !result->IsString()) {
600 return isolate->factory()->empty_string();
603 return Handle<String>::cast(result);
607 void StackGuard::HandleGCInterrupt() {
608 if (CheckAndClearInterrupt(GC_REQUEST)) {
609 isolate_->heap()->HandleGCRequest();
614 Object* StackGuard::HandleInterrupts() {
615 if (CheckAndClearInterrupt(GC_REQUEST)) {
616 isolate_->heap()->HandleGCRequest();
619 if (CheckDebugBreak() || CheckDebugCommand()) {
620 isolate_->debug()->HandleDebugBreak();
623 if (CheckAndClearInterrupt(TERMINATE_EXECUTION)) {
624 return isolate_->TerminateExecution();
627 if (CheckAndClearInterrupt(DEOPT_MARKED_ALLOCATION_SITES)) {
628 isolate_->heap()->DeoptMarkedAllocationSites();
631 if (CheckAndClearInterrupt(INSTALL_CODE)) {
632 DCHECK(isolate_->concurrent_recompilation_enabled());
633 isolate_->optimizing_compile_dispatcher()->InstallOptimizedFunctions();
636 if (CheckAndClearInterrupt(API_INTERRUPT)) {
637 // Callbacks must be invoked outside of ExecusionAccess lock.
638 isolate_->InvokeApiInterruptCallbacks();
641 isolate_->counters()->stack_interrupts()->Increment();
642 isolate_->counters()->runtime_profiler_ticks()->Increment();
643 isolate_->runtime_profiler()->OptimizeNow();
645 return isolate_->heap()->undefined_value();
648 } // namespace internal