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