execution.cc revision d0582a6c46733687d045e4188a1bcd0123c758a1
1// Copyright 2006-2008 the V8 project authors. All rights reserved. 2// Redistribution and use in source and binary forms, with or without 3// modification, are permitted provided that the following conditions are 4// met: 5// 6// * Redistributions of source code must retain the above copyright 7// notice, this list of conditions and the following disclaimer. 8// * Redistributions in binary form must reproduce the above 9// copyright notice, this list of conditions and the following 10// disclaimer in the documentation and/or other materials provided 11// with the distribution. 12// * Neither the name of Google Inc. nor the names of its 13// contributors may be used to endorse or promote products derived 14// from this software without specific prior written permission. 15// 16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28#include <stdlib.h> 29 30#include "v8.h" 31 32#include "api.h" 33#include "codegen-inl.h" 34#include "debug.h" 35#include "simulator.h" 36#include "v8threads.h" 37 38namespace v8 { 39namespace internal { 40 41 42static Handle<Object> Invoke(bool construct, 43 Handle<JSFunction> func, 44 Handle<Object> receiver, 45 int argc, 46 Object*** args, 47 bool* has_pending_exception) { 48 // Make sure we have a real function, not a boilerplate function. 49 ASSERT(!func->IsBoilerplate()); 50 51 // Entering JavaScript. 52 VMState state(JS); 53 54 // Placeholder for return value. 55 Object* value = reinterpret_cast<Object*>(kZapValue); 56 57 typedef Object* (*JSEntryFunction)( 58 byte* entry, 59 Object* function, 60 Object* receiver, 61 int argc, 62 Object*** args); 63 64 Handle<Code> code; 65 if (construct) { 66 JSConstructEntryStub stub; 67 code = stub.GetCode(); 68 } else { 69 JSEntryStub stub; 70 code = stub.GetCode(); 71 } 72 73 // Convert calls on global objects to be calls on the global 74 // receiver instead to avoid having a 'this' pointer which refers 75 // directly to a global object. 76 if (receiver->IsGlobalObject()) { 77 Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver); 78 receiver = Handle<JSObject>(global->global_receiver()); 79 } 80 81 { 82 // Save and restore context around invocation and block the 83 // allocation of handles without explicit handle scopes. 84 SaveContext save; 85 NoHandleAllocation na; 86 JSEntryFunction entry = FUNCTION_CAST<JSEntryFunction>(code->entry()); 87 88 // Call the function through the right JS entry stub. 89 byte* entry_address= func->code()->entry(); 90 JSFunction* function = *func; 91 Object* receiver_pointer = *receiver; 92 value = CALL_GENERATED_CODE(entry, entry_address, function, 93 receiver_pointer, argc, args); 94 } 95 96#ifdef DEBUG 97 value->Verify(); 98#endif 99 100 // Update the pending exception flag and return the value. 101 *has_pending_exception = value->IsException(); 102 ASSERT(*has_pending_exception == Top::has_pending_exception()); 103 if (*has_pending_exception) { 104 Top::ReportPendingMessages(); 105 return Handle<Object>(); 106 } else { 107 Top::clear_pending_message(); 108 } 109 110 return Handle<Object>(value); 111} 112 113 114Handle<Object> Execution::Call(Handle<JSFunction> func, 115 Handle<Object> receiver, 116 int argc, 117 Object*** args, 118 bool* pending_exception) { 119 return Invoke(false, func, receiver, argc, args, pending_exception); 120} 121 122 123Handle<Object> Execution::New(Handle<JSFunction> func, int argc, 124 Object*** args, bool* pending_exception) { 125 return Invoke(true, func, Top::global(), argc, args, pending_exception); 126} 127 128 129Handle<Object> Execution::TryCall(Handle<JSFunction> func, 130 Handle<Object> receiver, 131 int argc, 132 Object*** args, 133 bool* caught_exception) { 134 // Enter a try-block while executing the JavaScript code. To avoid 135 // duplicate error printing it must be non-verbose. Also, to avoid 136 // creating message objects during stack overflow we shouldn't 137 // capture messages. 138 v8::TryCatch catcher; 139 catcher.SetVerbose(false); 140 catcher.SetCaptureMessage(false); 141 142 Handle<Object> result = Invoke(false, func, receiver, argc, args, 143 caught_exception); 144 145 if (*caught_exception) { 146 ASSERT(catcher.HasCaught()); 147 ASSERT(Top::has_pending_exception()); 148 ASSERT(Top::external_caught_exception()); 149 if (Top::pending_exception() == Heap::termination_exception()) { 150 result = Factory::termination_exception(); 151 } else { 152 result = v8::Utils::OpenHandle(*catcher.Exception()); 153 } 154 Top::OptionalRescheduleException(true); 155 } 156 157 ASSERT(!Top::has_pending_exception()); 158 ASSERT(!Top::external_caught_exception()); 159 return result; 160} 161 162 163Handle<Object> Execution::GetFunctionDelegate(Handle<Object> object) { 164 ASSERT(!object->IsJSFunction()); 165 166 // If you return a function from here, it will be called when an 167 // attempt is made to call the given object as a function. 168 169 // Regular expressions can be called as functions in both Firefox 170 // and Safari so we allow it too. 171 if (object->IsJSRegExp()) { 172 Handle<String> exec = Factory::exec_symbol(); 173 return Handle<Object>(object->GetProperty(*exec)); 174 } 175 176 // Objects created through the API can have an instance-call handler 177 // that should be used when calling the object as a function. 178 if (object->IsHeapObject() && 179 HeapObject::cast(*object)->map()->has_instance_call_handler()) { 180 return Handle<JSFunction>( 181 Top::global_context()->call_as_function_delegate()); 182 } 183 184 return Factory::undefined_value(); 185} 186 187 188Handle<Object> Execution::GetConstructorDelegate(Handle<Object> object) { 189 ASSERT(!object->IsJSFunction()); 190 191 // If you return a function from here, it will be called when an 192 // attempt is made to call the given object as a constructor. 193 194 // Objects created through the API can have an instance-call handler 195 // that should be used when calling the object as a function. 196 if (object->IsHeapObject() && 197 HeapObject::cast(*object)->map()->has_instance_call_handler()) { 198 return Handle<JSFunction>( 199 Top::global_context()->call_as_constructor_delegate()); 200 } 201 202 return Factory::undefined_value(); 203} 204 205 206// Static state for stack guards. 207StackGuard::ThreadLocal StackGuard::thread_local_; 208 209 210bool StackGuard::IsStackOverflow() { 211 ExecutionAccess access; 212 return (thread_local_.jslimit_ != kInterruptLimit && 213 thread_local_.climit_ != kInterruptLimit); 214} 215 216 217void StackGuard::EnableInterrupts() { 218 ExecutionAccess access; 219 if (IsSet(access)) { 220 set_limits(kInterruptLimit, access); 221 } 222} 223 224 225void StackGuard::SetStackLimit(uintptr_t limit) { 226 ExecutionAccess access; 227 // If the current limits are special (eg due to a pending interrupt) then 228 // leave them alone. 229 uintptr_t jslimit = SimulatorStack::JsLimitFromCLimit(limit); 230 if (thread_local_.jslimit_ == thread_local_.real_jslimit_) { 231 thread_local_.jslimit_ = jslimit; 232 } 233 if (thread_local_.climit_ == thread_local_.real_climit_) { 234 thread_local_.climit_ = limit; 235 } 236 thread_local_.real_climit_ = limit; 237 thread_local_.real_jslimit_ = jslimit; 238} 239 240 241void StackGuard::DisableInterrupts() { 242 ExecutionAccess access; 243 reset_limits(access); 244} 245 246 247bool StackGuard::IsSet(const ExecutionAccess& lock) { 248 return thread_local_.interrupt_flags_ != 0; 249} 250 251 252bool StackGuard::IsInterrupted() { 253 ExecutionAccess access; 254 return thread_local_.interrupt_flags_ & INTERRUPT; 255} 256 257 258void StackGuard::Interrupt() { 259 ExecutionAccess access; 260 thread_local_.interrupt_flags_ |= INTERRUPT; 261 set_limits(kInterruptLimit, access); 262} 263 264 265bool StackGuard::IsPreempted() { 266 ExecutionAccess access; 267 return thread_local_.interrupt_flags_ & PREEMPT; 268} 269 270 271void StackGuard::Preempt() { 272 ExecutionAccess access; 273 thread_local_.interrupt_flags_ |= PREEMPT; 274 set_limits(kInterruptLimit, access); 275} 276 277 278bool StackGuard::IsTerminateExecution() { 279 ExecutionAccess access; 280 return thread_local_.interrupt_flags_ & TERMINATE; 281} 282 283 284void StackGuard::TerminateExecution() { 285 ExecutionAccess access; 286 thread_local_.interrupt_flags_ |= TERMINATE; 287 set_limits(kInterruptLimit, access); 288} 289 290 291#ifdef ENABLE_DEBUGGER_SUPPORT 292bool StackGuard::IsDebugBreak() { 293 ExecutionAccess access; 294 return thread_local_.interrupt_flags_ & DEBUGBREAK; 295} 296 297 298void StackGuard::DebugBreak() { 299 ExecutionAccess access; 300 thread_local_.interrupt_flags_ |= DEBUGBREAK; 301 set_limits(kInterruptLimit, access); 302} 303 304 305bool StackGuard::IsDebugCommand() { 306 ExecutionAccess access; 307 return thread_local_.interrupt_flags_ & DEBUGCOMMAND; 308} 309 310 311void StackGuard::DebugCommand() { 312 if (FLAG_debugger_auto_break) { 313 ExecutionAccess access; 314 thread_local_.interrupt_flags_ |= DEBUGCOMMAND; 315 set_limits(kInterruptLimit, access); 316 } 317} 318#endif 319 320void StackGuard::Continue(InterruptFlag after_what) { 321 ExecutionAccess access; 322 thread_local_.interrupt_flags_ &= ~static_cast<int>(after_what); 323 if (thread_local_.interrupt_flags_ == 0) { 324 reset_limits(access); 325 } 326} 327 328 329int StackGuard::ArchiveSpacePerThread() { 330 return sizeof(ThreadLocal); 331} 332 333 334char* StackGuard::ArchiveStackGuard(char* to) { 335 ExecutionAccess access; 336 memcpy(to, reinterpret_cast<char*>(&thread_local_), sizeof(ThreadLocal)); 337 ThreadLocal blank; 338 thread_local_ = blank; 339 return to + sizeof(ThreadLocal); 340} 341 342 343char* StackGuard::RestoreStackGuard(char* from) { 344 ExecutionAccess access; 345 memcpy(reinterpret_cast<char*>(&thread_local_), from, sizeof(ThreadLocal)); 346 Heap::SetStackLimits(); 347 return from + sizeof(ThreadLocal); 348} 349 350 351static internal::Thread::LocalStorageKey stack_limit_key = 352 internal::Thread::CreateThreadLocalKey(); 353 354 355void StackGuard::FreeThreadResources() { 356 Thread::SetThreadLocal( 357 stack_limit_key, 358 reinterpret_cast<void*>(thread_local_.real_climit_)); 359} 360 361 362void StackGuard::ThreadLocal::Clear() { 363 real_jslimit_ = kIllegalLimit; 364 jslimit_ = kIllegalLimit; 365 real_climit_ = kIllegalLimit; 366 climit_ = kIllegalLimit; 367 nesting_ = 0; 368 postpone_interrupts_nesting_ = 0; 369 interrupt_flags_ = 0; 370 Heap::SetStackLimits(); 371} 372 373 374void StackGuard::ThreadLocal::Initialize() { 375 if (real_climit_ == kIllegalLimit) { 376 // Takes the address of the limit variable in order to find out where 377 // the top of stack is right now. 378 uintptr_t limit = reinterpret_cast<uintptr_t>(&limit) - kLimitSize; 379 ASSERT(reinterpret_cast<uintptr_t>(&limit) > kLimitSize); 380 real_jslimit_ = SimulatorStack::JsLimitFromCLimit(limit); 381 jslimit_ = SimulatorStack::JsLimitFromCLimit(limit); 382 real_climit_ = limit; 383 climit_ = limit; 384 Heap::SetStackLimits(); 385 } 386 nesting_ = 0; 387 postpone_interrupts_nesting_ = 0; 388 interrupt_flags_ = 0; 389} 390 391 392void StackGuard::ClearThread(const ExecutionAccess& lock) { 393 thread_local_.Clear(); 394} 395 396 397void StackGuard::InitThread(const ExecutionAccess& lock) { 398 thread_local_.Initialize(); 399 void* stored_limit = Thread::GetThreadLocal(stack_limit_key); 400 // You should hold the ExecutionAccess lock when you call this. 401 if (stored_limit != NULL) { 402 StackGuard::SetStackLimit(reinterpret_cast<intptr_t>(stored_limit)); 403 } 404} 405 406 407// --- C a l l s t o n a t i v e s --- 408 409#define RETURN_NATIVE_CALL(name, argc, argv, has_pending_exception) \ 410 do { \ 411 Object** args[argc] = argv; \ 412 ASSERT(has_pending_exception != NULL); \ 413 return Call(Top::name##_fun(), Top::builtins(), argc, args, \ 414 has_pending_exception); \ 415 } while (false) 416 417 418Handle<Object> Execution::ToBoolean(Handle<Object> obj) { 419 // See the similar code in runtime.js:ToBoolean. 420 if (obj->IsBoolean()) return obj; 421 bool result = true; 422 if (obj->IsString()) { 423 result = Handle<String>::cast(obj)->length() != 0; 424 } else if (obj->IsNull() || obj->IsUndefined()) { 425 result = false; 426 } else if (obj->IsNumber()) { 427 double value = obj->Number(); 428 result = !((value == 0) || isnan(value)); 429 } 430 return Handle<Object>(Heap::ToBoolean(result)); 431} 432 433 434Handle<Object> Execution::ToNumber(Handle<Object> obj, bool* exc) { 435 RETURN_NATIVE_CALL(to_number, 1, { obj.location() }, exc); 436} 437 438 439Handle<Object> Execution::ToString(Handle<Object> obj, bool* exc) { 440 RETURN_NATIVE_CALL(to_string, 1, { obj.location() }, exc); 441} 442 443 444Handle<Object> Execution::ToDetailString(Handle<Object> obj, bool* exc) { 445 RETURN_NATIVE_CALL(to_detail_string, 1, { obj.location() }, exc); 446} 447 448 449Handle<Object> Execution::ToObject(Handle<Object> obj, bool* exc) { 450 if (obj->IsJSObject()) return obj; 451 RETURN_NATIVE_CALL(to_object, 1, { obj.location() }, exc); 452} 453 454 455Handle<Object> Execution::ToInteger(Handle<Object> obj, bool* exc) { 456 RETURN_NATIVE_CALL(to_integer, 1, { obj.location() }, exc); 457} 458 459 460Handle<Object> Execution::ToUint32(Handle<Object> obj, bool* exc) { 461 RETURN_NATIVE_CALL(to_uint32, 1, { obj.location() }, exc); 462} 463 464 465Handle<Object> Execution::ToInt32(Handle<Object> obj, bool* exc) { 466 RETURN_NATIVE_CALL(to_int32, 1, { obj.location() }, exc); 467} 468 469 470Handle<Object> Execution::NewDate(double time, bool* exc) { 471 Handle<Object> time_obj = Factory::NewNumber(time); 472 RETURN_NATIVE_CALL(create_date, 1, { time_obj.location() }, exc); 473} 474 475 476#undef RETURN_NATIVE_CALL 477 478 479Handle<Object> Execution::CharAt(Handle<String> string, uint32_t index) { 480 int int_index = static_cast<int>(index); 481 if (int_index < 0 || int_index >= string->length()) { 482 return Factory::undefined_value(); 483 } 484 485 Handle<Object> char_at = 486 GetProperty(Top::builtins(), Factory::char_at_symbol()); 487 if (!char_at->IsJSFunction()) { 488 return Factory::undefined_value(); 489 } 490 491 bool caught_exception; 492 Handle<Object> index_object = Factory::NewNumberFromInt(int_index); 493 Object** index_arg[] = { index_object.location() }; 494 Handle<Object> result = TryCall(Handle<JSFunction>::cast(char_at), 495 string, 496 ARRAY_SIZE(index_arg), 497 index_arg, 498 &caught_exception); 499 if (caught_exception) { 500 return Factory::undefined_value(); 501 } 502 return result; 503} 504 505 506Handle<JSFunction> Execution::InstantiateFunction( 507 Handle<FunctionTemplateInfo> data, bool* exc) { 508 // Fast case: see if the function has already been instantiated 509 int serial_number = Smi::cast(data->serial_number())->value(); 510 Object* elm = 511 Top::global_context()->function_cache()->GetElement(serial_number); 512 if (elm->IsJSFunction()) return Handle<JSFunction>(JSFunction::cast(elm)); 513 // The function has not yet been instantiated in this context; do it. 514 Object** args[1] = { Handle<Object>::cast(data).location() }; 515 Handle<Object> result = 516 Call(Top::instantiate_fun(), Top::builtins(), 1, args, exc); 517 if (*exc) return Handle<JSFunction>::null(); 518 return Handle<JSFunction>::cast(result); 519} 520 521 522Handle<JSObject> Execution::InstantiateObject(Handle<ObjectTemplateInfo> data, 523 bool* exc) { 524 if (data->property_list()->IsUndefined() && 525 !data->constructor()->IsUndefined()) { 526 // Initialization to make gcc happy. 527 Object* result = NULL; 528 { 529 HandleScope scope; 530 Handle<FunctionTemplateInfo> cons_template = 531 Handle<FunctionTemplateInfo>( 532 FunctionTemplateInfo::cast(data->constructor())); 533 Handle<JSFunction> cons = InstantiateFunction(cons_template, exc); 534 if (*exc) return Handle<JSObject>::null(); 535 Handle<Object> value = New(cons, 0, NULL, exc); 536 if (*exc) return Handle<JSObject>::null(); 537 result = *value; 538 } 539 ASSERT(!*exc); 540 return Handle<JSObject>(JSObject::cast(result)); 541 } else { 542 Object** args[1] = { Handle<Object>::cast(data).location() }; 543 Handle<Object> result = 544 Call(Top::instantiate_fun(), Top::builtins(), 1, args, exc); 545 if (*exc) return Handle<JSObject>::null(); 546 return Handle<JSObject>::cast(result); 547 } 548} 549 550 551void Execution::ConfigureInstance(Handle<Object> instance, 552 Handle<Object> instance_template, 553 bool* exc) { 554 Object** args[2] = { instance.location(), instance_template.location() }; 555 Execution::Call(Top::configure_instance_fun(), Top::builtins(), 2, args, exc); 556} 557 558 559Handle<String> Execution::GetStackTraceLine(Handle<Object> recv, 560 Handle<JSFunction> fun, 561 Handle<Object> pos, 562 Handle<Object> is_global) { 563 const int argc = 4; 564 Object** args[argc] = { recv.location(), 565 Handle<Object>::cast(fun).location(), 566 pos.location(), 567 is_global.location() }; 568 bool caught_exception = false; 569 Handle<Object> result = TryCall(Top::get_stack_trace_line_fun(), 570 Top::builtins(), argc, args, 571 &caught_exception); 572 if (caught_exception || !result->IsString()) return Factory::empty_symbol(); 573 return Handle<String>::cast(result); 574} 575 576 577static Object* RuntimePreempt() { 578 // Clear the preempt request flag. 579 StackGuard::Continue(PREEMPT); 580 581 ContextSwitcher::PreemptionReceived(); 582 583#ifdef ENABLE_DEBUGGER_SUPPORT 584 if (Debug::InDebugger()) { 585 // If currently in the debugger don't do any actual preemption but record 586 // that preemption occoured while in the debugger. 587 Debug::PreemptionWhileInDebugger(); 588 } else { 589 // Perform preemption. 590 v8::Unlocker unlocker; 591 Thread::YieldCPU(); 592 } 593#else 594 // Perform preemption. 595 v8::Unlocker unlocker; 596 Thread::YieldCPU(); 597#endif 598 599 return Heap::undefined_value(); 600} 601 602 603#ifdef ENABLE_DEBUGGER_SUPPORT 604Object* Execution::DebugBreakHelper() { 605 // Just continue if breaks are disabled. 606 if (Debug::disable_break()) { 607 return Heap::undefined_value(); 608 } 609 610 { 611 JavaScriptFrameIterator it; 612 ASSERT(!it.done()); 613 Object* fun = it.frame()->function(); 614 if (fun && fun->IsJSFunction()) { 615 // Don't stop in builtin functions. 616 if (JSFunction::cast(fun)->IsBuiltin()) { 617 return Heap::undefined_value(); 618 } 619 GlobalObject* global = JSFunction::cast(fun)->context()->global(); 620 // Don't stop in debugger functions. 621 if (Debug::IsDebugGlobal(global)) { 622 return Heap::undefined_value(); 623 } 624 } 625 } 626 627 // Collect the break state before clearing the flags. 628 bool debug_command_only = 629 StackGuard::IsDebugCommand() && !StackGuard::IsDebugBreak(); 630 631 // Clear the debug request flags. 632 StackGuard::Continue(DEBUGBREAK); 633 StackGuard::Continue(DEBUGCOMMAND); 634 635 HandleScope scope; 636 // Enter the debugger. Just continue if we fail to enter the debugger. 637 EnterDebugger debugger; 638 if (debugger.FailedToEnter()) { 639 return Heap::undefined_value(); 640 } 641 642 // Notify the debug event listeners. Indicate auto continue if the break was 643 // a debug command break. 644 Debugger::OnDebugBreak(Factory::undefined_value(), debug_command_only); 645 646 // Return to continue execution. 647 return Heap::undefined_value(); 648} 649#endif 650 651Object* Execution::HandleStackGuardInterrupt() { 652#ifdef ENABLE_DEBUGGER_SUPPORT 653 if (StackGuard::IsDebugBreak() || StackGuard::IsDebugCommand()) { 654 DebugBreakHelper(); 655 } 656#endif 657 if (StackGuard::IsPreempted()) RuntimePreempt(); 658 if (StackGuard::IsTerminateExecution()) { 659 StackGuard::Continue(TERMINATE); 660 return Top::TerminateExecution(); 661 } 662 if (StackGuard::IsInterrupted()) { 663 // interrupt 664 StackGuard::Continue(INTERRUPT); 665 return Top::StackOverflow(); 666 } 667 return Heap::undefined_value(); 668} 669 670// --- G C E x t e n s i o n --- 671 672const char* GCExtension::kSource = "native function gc();"; 673 674 675v8::Handle<v8::FunctionTemplate> GCExtension::GetNativeFunction( 676 v8::Handle<v8::String> str) { 677 return v8::FunctionTemplate::New(GCExtension::GC); 678} 679 680 681v8::Handle<v8::Value> GCExtension::GC(const v8::Arguments& args) { 682 // All allocation spaces other than NEW_SPACE have the same effect. 683 Heap::CollectAllGarbage(false); 684 return v8::Undefined(); 685} 686 687 688static GCExtension kGCExtension; 689v8::DeclareExtension kGCExtensionDeclaration(&kGCExtension); 690 691} } // namespace v8::internal 692