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