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