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