Line data Source code
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.
4 :
5 : #include "src/execution.h"
6 :
7 : #include "src/api.h"
8 : #include "src/bootstrapper.h"
9 : #include "src/compiler-dispatcher/optimizing-compile-dispatcher.h"
10 : #include "src/debug/debug.h"
11 : #include "src/isolate-inl.h"
12 : #include "src/messages.h"
13 : #include "src/runtime-profiler.h"
14 : #include "src/vm-state-inl.h"
15 :
16 : namespace v8 {
17 : namespace internal {
18 :
19 109998 : StackGuard::StackGuard() : isolate_(nullptr) {}
20 :
21 72440 : void StackGuard::set_interrupt_limits(const ExecutionAccess& lock) {
22 : DCHECK_NOT_NULL(isolate_);
23 : thread_local_.set_jslimit(kInterruptLimit);
24 : thread_local_.set_climit(kInterruptLimit);
25 72440 : isolate_->heap()->SetStackLimits();
26 72440 : }
27 :
28 :
29 4068803 : void StackGuard::reset_limits(const ExecutionAccess& lock) {
30 : DCHECK_NOT_NULL(isolate_);
31 4068803 : thread_local_.set_jslimit(thread_local_.real_jslimit_);
32 4068803 : thread_local_.set_climit(thread_local_.real_climit_);
33 4068803 : isolate_->heap()->SetStackLimits();
34 4068801 : }
35 :
36 :
37 0 : static void PrintDeserializedCodeInfo(Handle<JSFunction> function) {
38 0 : if (function->code() == function->shared()->code() &&
39 : function->shared()->deserialized()) {
40 0 : PrintF("[Running deserialized script");
41 : Object* script = function->shared()->script();
42 0 : if (script->IsScript()) {
43 : Object* name = Script::cast(script)->name();
44 0 : if (name->IsString()) {
45 0 : PrintF(": %s", String::cast(name)->ToCString().get());
46 : }
47 : }
48 0 : PrintF("]\n");
49 : }
50 0 : }
51 :
52 :
53 : namespace {
54 :
55 23052416 : MUST_USE_RESULT MaybeHandle<Object> Invoke(
56 : Isolate* isolate, bool is_construct, Handle<Object> target,
57 : Handle<Object> receiver, int argc, Handle<Object> args[],
58 : Handle<Object> new_target, Execution::MessageHandling message_handling) {
59 : DCHECK(!receiver->IsJSGlobalObject());
60 :
61 : #ifdef USE_SIMULATOR
62 : // Simulators use separate stacks for C++ and JS. JS stack overflow checks
63 : // are performed whenever a JS function is called. However, it can be the case
64 : // that the C++ stack grows faster than the JS stack, resulting in an overflow
65 : // there. Add a check here to make that less likely.
66 : StackLimitCheck check(isolate);
67 : if (check.HasOverflowed()) {
68 : isolate->StackOverflow();
69 : if (message_handling == Execution::MessageHandling::kReport) {
70 : isolate->ReportPendingMessages();
71 : }
72 : return MaybeHandle<Object>();
73 : }
74 : #endif
75 :
76 : // api callbacks can be called directly.
77 23052415 : if (target->IsJSFunction()) {
78 : Handle<JSFunction> function = Handle<JSFunction>::cast(target);
79 46027877 : if ((!is_construct || function->IsConstructor()) &&
80 23007714 : function->shared()->IsApiFunction()) {
81 12126 : SaveContext save(isolate);
82 : isolate->set_context(function->context());
83 : DCHECK(function->context()->global_object()->IsJSGlobalObject());
84 12126 : if (is_construct) receiver = isolate->factory()->the_hole_value();
85 : auto value = Builtins::InvokeApiFunction(
86 : isolate, is_construct, function, receiver, argc, args,
87 12126 : Handle<HeapObject>::cast(new_target));
88 : bool has_exception = value.is_null();
89 : DCHECK(has_exception == isolate->has_pending_exception());
90 12126 : if (has_exception) {
91 134 : if (message_handling == Execution::MessageHandling::kReport) {
92 134 : isolate->ReportPendingMessages();
93 : }
94 134 : return MaybeHandle<Object>();
95 : } else {
96 : isolate->clear_pending_message();
97 : }
98 11992 : return value;
99 : }
100 : }
101 :
102 : // Entering JavaScript.
103 : VMState<JS> state(isolate);
104 23040288 : CHECK(AllowJavascriptExecution::IsAllowed(isolate));
105 23040303 : if (!ThrowOnJavascriptExecution::IsAllowed(isolate)) {
106 5 : isolate->ThrowIllegalOperation();
107 5 : if (message_handling == Execution::MessageHandling::kReport) {
108 5 : isolate->ReportPendingMessages();
109 : }
110 5 : return MaybeHandle<Object>();
111 : }
112 :
113 : // Placeholder for return value.
114 : Object* value = nullptr;
115 :
116 : typedef Object* (*JSEntryFunction)(Object* new_target, Object* target,
117 : Object* receiver, int argc,
118 : Object*** args);
119 :
120 : Handle<Code> code = is_construct
121 : ? isolate->factory()->js_construct_entry_code()
122 23040298 : : isolate->factory()->js_entry_code();
123 :
124 : {
125 : // Save and restore context around invocation and block the
126 : // allocation of handles without explicit handle scopes.
127 23040298 : SaveContext save(isolate);
128 : SealHandleScope shs(isolate);
129 23040310 : JSEntryFunction stub_entry = FUNCTION_CAST<JSEntryFunction>(code->entry());
130 :
131 23040310 : if (FLAG_clear_exceptions_on_js_entry) isolate->clear_pending_exception();
132 :
133 : // Call the function through the right JS entry stub.
134 : Object* orig_func = *new_target;
135 : Object* func = *target;
136 : Object* recv = *receiver;
137 : Object*** argv = reinterpret_cast<Object***>(args);
138 23040310 : if (FLAG_profile_deserialization && target->IsJSFunction()) {
139 0 : PrintDeserializedCodeInfo(Handle<JSFunction>::cast(target));
140 : }
141 23040310 : RuntimeCallTimerScope timer(isolate, &RuntimeCallStats::JS_Execution);
142 : value = CALL_GENERATED_CODE(isolate, stub_entry, orig_func, func, recv,
143 46080635 : argc, argv);
144 : }
145 :
146 : #ifdef VERIFY_HEAP
147 : if (FLAG_verify_heap) {
148 : value->ObjectVerify();
149 : }
150 : #endif
151 :
152 : // Update the pending exception flag and return the value.
153 : bool has_exception = value->IsException(isolate);
154 : DCHECK(has_exception == isolate->has_pending_exception());
155 23040324 : if (has_exception) {
156 61393 : if (message_handling == Execution::MessageHandling::kReport) {
157 61388 : isolate->ReportPendingMessages();
158 : }
159 61393 : return MaybeHandle<Object>();
160 : } else {
161 : isolate->clear_pending_message();
162 : }
163 :
164 22978933 : return Handle<Object>(value, isolate);
165 : }
166 :
167 23039906 : MaybeHandle<Object> CallInternal(Isolate* isolate, Handle<Object> callable,
168 : Handle<Object> receiver, int argc,
169 : Handle<Object> argv[],
170 : Execution::MessageHandling message_handling) {
171 : // Convert calls on global objects to be calls on the global
172 : // receiver instead to avoid having a 'this' pointer which refers
173 : // directly to a global object.
174 23039917 : if (receiver->IsJSGlobalObject()) {
175 : receiver =
176 : handle(Handle<JSGlobalObject>::cast(receiver)->global_proxy(), isolate);
177 : }
178 : return Invoke(isolate, false, callable, receiver, argc, argv,
179 23039917 : isolate->factory()->undefined_value(), message_handling);
180 : }
181 :
182 : } // namespace
183 :
184 : // static
185 22691197 : MaybeHandle<Object> Execution::Call(Isolate* isolate, Handle<Object> callable,
186 : Handle<Object> receiver, int argc,
187 : Handle<Object> argv[]) {
188 : return CallInternal(isolate, callable, receiver, argc, argv,
189 22691197 : MessageHandling::kReport);
190 : }
191 :
192 :
193 : // static
194 11332 : MaybeHandle<Object> Execution::New(Isolate* isolate, Handle<Object> constructor,
195 : int argc, Handle<Object> argv[]) {
196 11332 : return New(isolate, constructor, constructor, argc, argv);
197 : }
198 :
199 :
200 : // static
201 1167 : MaybeHandle<Object> Execution::New(Isolate* isolate, Handle<Object> constructor,
202 : Handle<Object> new_target, int argc,
203 : Handle<Object> argv[]) {
204 : return Invoke(isolate, true, constructor,
205 : isolate->factory()->undefined_value(), argc, argv, new_target,
206 12499 : MessageHandling::kReport);
207 : }
208 :
209 348837 : MaybeHandle<Object> Execution::TryCall(Isolate* isolate,
210 : Handle<Object> callable,
211 : Handle<Object> receiver, int argc,
212 : Handle<Object> args[],
213 : MessageHandling message_handling,
214 : MaybeHandle<Object>* exception_out) {
215 : bool is_termination = false;
216 : MaybeHandle<Object> maybe_result;
217 348713 : if (exception_out != nullptr) *exception_out = MaybeHandle<Object>();
218 : DCHECK_IMPLIES(message_handling == MessageHandling::kKeepPending,
219 : exception_out == nullptr);
220 : // Enter a try-block while executing the JavaScript code. To avoid
221 : // duplicate error printing it must be non-verbose. Also, to avoid
222 : // creating message objects during stack overflow we shouldn't
223 : // capture messages.
224 : {
225 348713 : v8::TryCatch catcher(reinterpret_cast<v8::Isolate*>(isolate));
226 348713 : catcher.SetVerbose(false);
227 348713 : catcher.SetCaptureMessage(false);
228 :
229 : maybe_result =
230 348713 : CallInternal(isolate, callable, receiver, argc, args, message_handling);
231 :
232 348716 : if (maybe_result.is_null()) {
233 : DCHECK(isolate->has_pending_exception());
234 124 : if (isolate->pending_exception() ==
235 124 : isolate->heap()->termination_exception()) {
236 : is_termination = true;
237 : } else {
238 112 : if (exception_out != nullptr) {
239 : DCHECK(catcher.HasCaught());
240 : DCHECK(isolate->external_caught_exception());
241 214 : *exception_out = v8::Utils::OpenHandle(*catcher.Exception());
242 : }
243 : }
244 124 : if (message_handling == MessageHandling::kReport) {
245 119 : isolate->OptionalRescheduleException(true);
246 : }
247 348716 : }
248 : }
249 :
250 : // Re-request terminate execution interrupt to trigger later.
251 348716 : if (is_termination) isolate->stack_guard()->RequestTerminateExecution();
252 :
253 348716 : return maybe_result;
254 : }
255 :
256 :
257 1636 : void StackGuard::SetStackLimit(uintptr_t limit) {
258 1636 : ExecutionAccess access(isolate_);
259 : // If the current limits are special (e.g. due to a pending interrupt) then
260 : // leave them alone.
261 : uintptr_t jslimit = SimulatorStack::JsLimitFromCLimit(isolate_, limit);
262 1636 : if (thread_local_.jslimit() == thread_local_.real_jslimit_) {
263 : thread_local_.set_jslimit(jslimit);
264 : }
265 1636 : if (thread_local_.climit() == thread_local_.real_climit_) {
266 : thread_local_.set_climit(limit);
267 : }
268 1636 : thread_local_.real_climit_ = limit;
269 1636 : thread_local_.real_jslimit_ = jslimit;
270 1636 : }
271 :
272 :
273 0 : void StackGuard::AdjustStackLimitForSimulator() {
274 0 : ExecutionAccess access(isolate_);
275 0 : uintptr_t climit = thread_local_.real_climit_;
276 : // If the current limits are special (e.g. due to a pending interrupt) then
277 : // leave them alone.
278 : uintptr_t jslimit = SimulatorStack::JsLimitFromCLimit(isolate_, climit);
279 0 : if (thread_local_.jslimit() == thread_local_.real_jslimit_) {
280 : thread_local_.set_jslimit(jslimit);
281 0 : isolate_->heap()->SetStackLimits();
282 : }
283 0 : }
284 :
285 :
286 0 : void StackGuard::EnableInterrupts() {
287 0 : ExecutionAccess access(isolate_);
288 0 : if (has_pending_interrupts(access)) {
289 0 : set_interrupt_limits(access);
290 : }
291 0 : }
292 :
293 :
294 0 : void StackGuard::DisableInterrupts() {
295 0 : ExecutionAccess access(isolate_);
296 0 : reset_limits(access);
297 0 : }
298 :
299 :
300 3178442 : void StackGuard::PushPostponeInterruptsScope(PostponeInterruptsScope* scope) {
301 3178442 : ExecutionAccess access(isolate_);
302 : // Intercept already requested interrupts.
303 3178444 : int intercepted = thread_local_.interrupt_flags_ & scope->intercept_mask_;
304 3178444 : scope->intercepted_flags_ = intercepted;
305 3178444 : thread_local_.interrupt_flags_ &= ~intercepted;
306 3178444 : if (!has_pending_interrupts(access)) reset_limits(access);
307 : // Add scope to the chain.
308 3178442 : scope->prev_ = thread_local_.postpone_interrupts_;
309 3178442 : thread_local_.postpone_interrupts_ = scope;
310 3178444 : }
311 :
312 :
313 3178441 : void StackGuard::PopPostponeInterruptsScope() {
314 3178441 : ExecutionAccess access(isolate_);
315 3178444 : PostponeInterruptsScope* top = thread_local_.postpone_interrupts_;
316 : // Make intercepted interrupts active.
317 : DCHECK_EQ(thread_local_.interrupt_flags_ & top->intercept_mask_, 0);
318 3178444 : thread_local_.interrupt_flags_ |= top->intercepted_flags_;
319 3178444 : if (has_pending_interrupts(access)) set_interrupt_limits(access);
320 : // Remove scope from chain.
321 3178444 : thread_local_.postpone_interrupts_ = top->prev_;
322 3178444 : }
323 :
324 :
325 594 : bool StackGuard::CheckInterrupt(InterruptFlag flag) {
326 594 : ExecutionAccess access(isolate_);
327 291215 : return thread_local_.interrupt_flags_ & flag;
328 : }
329 :
330 :
331 42823 : void StackGuard::RequestInterrupt(InterruptFlag flag) {
332 42823 : ExecutionAccess access(isolate_);
333 : // Check the chain of PostponeInterruptsScopes for interception.
334 62737 : if (thread_local_.postpone_interrupts_ &&
335 19914 : thread_local_.postpone_interrupts_->Intercept(flag)) {
336 42823 : return;
337 : }
338 :
339 : // Not intercepted. Set as active interrupt flag.
340 22916 : thread_local_.interrupt_flags_ |= flag;
341 22916 : set_interrupt_limits(access);
342 :
343 : // If this isolate is waiting in a futex, notify it to wake up.
344 22916 : isolate_->futex_wait_list_node()->NotifyWake();
345 : }
346 :
347 :
348 43456 : void StackGuard::ClearInterrupt(InterruptFlag flag) {
349 43456 : ExecutionAccess access(isolate_);
350 : // Clear the interrupt flag from the chain of PostponeInterruptsScopes.
351 60164 : for (PostponeInterruptsScope* current = thread_local_.postpone_interrupts_;
352 : current != nullptr; current = current->prev_) {
353 16708 : current->intercepted_flags_ &= ~flag;
354 : }
355 :
356 : // Clear the interrupt flag from the active interrupt flags.
357 43456 : thread_local_.interrupt_flags_ &= ~flag;
358 43456 : if (!has_pending_interrupts(access)) reset_limits(access);
359 43456 : }
360 :
361 :
362 1446829 : bool StackGuard::CheckAndClearInterrupt(InterruptFlag flag) {
363 1446829 : ExecutionAccess access(isolate_);
364 1446829 : bool result = (thread_local_.interrupt_flags_ & flag);
365 1446829 : thread_local_.interrupt_flags_ &= ~flag;
366 1446829 : if (!has_pending_interrupts(access)) reset_limits(access);
367 1446829 : return result;
368 : }
369 :
370 :
371 24163 : char* StackGuard::ArchiveStackGuard(char* to) {
372 24163 : ExecutionAccess access(isolate_);
373 24163 : MemCopy(to, reinterpret_cast<char*>(&thread_local_), sizeof(ThreadLocal));
374 : ThreadLocal blank;
375 :
376 : // Set the stack limits using the old thread_local_.
377 : // TODO(isolates): This was the old semantics of constructing a ThreadLocal
378 : // (as the ctor called SetStackLimits, which looked at the
379 : // current thread_local_ from StackGuard)-- but is this
380 : // really what was intended?
381 24163 : isolate_->heap()->SetStackLimits();
382 24163 : thread_local_ = blank;
383 :
384 48326 : return to + sizeof(ThreadLocal);
385 : }
386 :
387 :
388 24163 : char* StackGuard::RestoreStackGuard(char* from) {
389 24163 : ExecutionAccess access(isolate_);
390 24163 : MemCopy(reinterpret_cast<char*>(&thread_local_), from, sizeof(ThreadLocal));
391 24163 : isolate_->heap()->SetStackLimits();
392 48326 : return from + sizeof(ThreadLocal);
393 : }
394 :
395 :
396 5856 : void StackGuard::FreeThreadResources() {
397 : Isolate::PerIsolateThreadData* per_thread =
398 5856 : isolate_->FindOrAllocatePerThreadDataForThisThread();
399 5856 : per_thread->set_stack_limit(thread_local_.real_climit_);
400 5856 : }
401 :
402 :
403 85018 : void StackGuard::ThreadLocal::Clear() {
404 85018 : real_jslimit_ = kIllegalLimit;
405 : set_jslimit(kIllegalLimit);
406 85018 : real_climit_ = kIllegalLimit;
407 : set_climit(kIllegalLimit);
408 85018 : postpone_interrupts_ = nullptr;
409 85018 : interrupt_flags_ = 0;
410 85018 : }
411 :
412 :
413 66710 : bool StackGuard::ThreadLocal::Initialize(Isolate* isolate) {
414 : bool should_set_stack_limits = false;
415 66710 : if (real_climit_ == kIllegalLimit) {
416 62076 : const uintptr_t kLimitSize = FLAG_stack_size * KB;
417 : DCHECK_GT(GetCurrentStackPosition(), kLimitSize);
418 62076 : uintptr_t limit = GetCurrentStackPosition() - kLimitSize;
419 62076 : real_jslimit_ = SimulatorStack::JsLimitFromCLimit(isolate, limit);
420 : set_jslimit(SimulatorStack::JsLimitFromCLimit(isolate, limit));
421 62076 : real_climit_ = limit;
422 : set_climit(limit);
423 : should_set_stack_limits = true;
424 : }
425 66710 : postpone_interrupts_ = nullptr;
426 66710 : interrupt_flags_ = 0;
427 66710 : return should_set_stack_limits;
428 : }
429 :
430 :
431 5856 : void StackGuard::ClearThread(const ExecutionAccess& lock) {
432 5856 : thread_local_.Clear();
433 5856 : isolate_->heap()->SetStackLimits();
434 5856 : }
435 :
436 :
437 66710 : void StackGuard::InitThread(const ExecutionAccess& lock) {
438 66710 : if (thread_local_.Initialize(isolate_)) isolate_->heap()->SetStackLimits();
439 66711 : Isolate::PerIsolateThreadData* per_thread =
440 66711 : isolate_->FindOrAllocatePerThreadDataForThisThread();
441 : uintptr_t stored_limit = per_thread->stack_limit();
442 : // You should hold the ExecutionAccess lock when you call this.
443 66711 : if (stored_limit != 0) {
444 150 : SetStackLimit(stored_limit);
445 : }
446 66711 : }
447 :
448 :
449 : // --- C a l l s t o n a t i v e s ---
450 :
451 :
452 0 : void StackGuard::HandleGCInterrupt() {
453 0 : if (CheckAndClearInterrupt(GC_REQUEST)) {
454 0 : isolate_->heap()->HandleGCRequest();
455 : }
456 0 : }
457 :
458 :
459 580054 : Object* StackGuard::HandleInterrupts() {
460 : if (FLAG_verify_predictable) {
461 : // Advance synthetic time by making a time request.
462 415678 : isolate_->heap()->MonotonicallyIncreasingTimeInMs();
463 : }
464 :
465 : bool any_interrupt_handled = false;
466 290027 : if (FLAG_trace_interrupts) {
467 0 : PrintF("[Handling interrupts: ");
468 : }
469 :
470 290027 : if (CheckAndClearInterrupt(GC_REQUEST)) {
471 1860 : if (FLAG_trace_interrupts) {
472 0 : PrintF("GC_REQUEST");
473 : any_interrupt_handled = true;
474 : }
475 1860 : isolate_->heap()->HandleGCRequest();
476 : }
477 :
478 290027 : if (CheckDebugBreak()) {
479 119627 : if (FLAG_trace_interrupts) {
480 0 : if (any_interrupt_handled) PrintF(", ");
481 0 : PrintF("DEBUG_BREAK");
482 : any_interrupt_handled = true;
483 : }
484 239254 : isolate_->debug()->HandleDebugBreak(kIgnoreIfTopFrameBlackboxed);
485 : }
486 :
487 290027 : if (CheckAndClearInterrupt(TERMINATE_EXECUTION)) {
488 1102 : if (FLAG_trace_interrupts) {
489 0 : if (any_interrupt_handled) PrintF(", ");
490 0 : PrintF("TERMINATE_EXECUTION");
491 : any_interrupt_handled = true;
492 : }
493 1102 : return isolate_->TerminateExecution();
494 : }
495 :
496 288925 : if (CheckAndClearInterrupt(DEOPT_MARKED_ALLOCATION_SITES)) {
497 32 : if (FLAG_trace_interrupts) {
498 0 : if (any_interrupt_handled) PrintF(", ");
499 0 : PrintF("DEOPT_MARKED_ALLOCATION_SITES");
500 : any_interrupt_handled = true;
501 : }
502 32 : isolate_->heap()->DeoptMarkedAllocationSites();
503 : }
504 :
505 288925 : if (CheckAndClearInterrupt(INSTALL_CODE)) {
506 7126 : if (FLAG_trace_interrupts) {
507 0 : if (any_interrupt_handled) PrintF(", ");
508 0 : PrintF("INSTALL_CODE");
509 : any_interrupt_handled = true;
510 : }
511 : DCHECK(isolate_->concurrent_recompilation_enabled());
512 14252 : isolate_->optimizing_compile_dispatcher()->InstallOptimizedFunctions();
513 : }
514 :
515 288925 : if (CheckAndClearInterrupt(API_INTERRUPT)) {
516 78 : if (FLAG_trace_interrupts) {
517 0 : if (any_interrupt_handled) PrintF(", ");
518 0 : PrintF("API_INTERRUPT");
519 : any_interrupt_handled = true;
520 : }
521 : // Callbacks must be invoked outside of ExecusionAccess lock.
522 78 : isolate_->InvokeApiInterruptCallbacks();
523 : }
524 :
525 288925 : if (FLAG_trace_interrupts) {
526 0 : if (!any_interrupt_handled) {
527 0 : PrintF("No interrupt flags set");
528 : }
529 0 : PrintF("]\n");
530 : }
531 :
532 577850 : isolate_->counters()->stack_interrupts()->Increment();
533 577850 : isolate_->counters()->runtime_profiler_ticks()->Increment();
534 577850 : isolate_->runtime_profiler()->MarkCandidatesForOptimization();
535 :
536 288925 : return isolate_->heap()->undefined_value();
537 : }
538 :
539 : } // namespace internal
540 : } // namespace v8
|