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