blob: 93807a7c72c1401f7c7b5faa92b560aae07f640b [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +00001// Copyright 2009 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 "v8.h"
29
30#include "api.h"
31#include "arguments.h"
32#include "bootstrapper.h"
33#include "compiler.h"
34#include "debug.h"
35#include "execution.h"
36#include "global-handles.h"
37#include "platform.h"
38#include "serialize.h"
39#include "snapshot.h"
Steve Blockd0582a62009-12-15 09:54:21 +000040#include "utils.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000041#include "v8threads.h"
42#include "version.h"
43
44
45#define LOG_API(expr) LOG(ApiEntryCall(expr))
46
47#ifdef ENABLE_HEAP_PROTECTION
48#define ENTER_V8 i::VMState __state__(i::OTHER)
49#define LEAVE_V8 i::VMState __state__(i::EXTERNAL)
50#else
51#define ENTER_V8 ((void) 0)
52#define LEAVE_V8 ((void) 0)
53#endif
54
55namespace v8 {
56
57
58#define ON_BAILOUT(location, code) \
59 if (IsDeadCheck(location)) { \
60 code; \
61 UNREACHABLE(); \
62 }
63
64
65#define EXCEPTION_PREAMBLE() \
66 thread_local.IncrementCallDepth(); \
67 ASSERT(!i::Top::external_caught_exception()); \
68 bool has_pending_exception = false
69
70
71#define EXCEPTION_BAILOUT_CHECK(value) \
72 do { \
73 thread_local.DecrementCallDepth(); \
74 if (has_pending_exception) { \
75 if (thread_local.CallDepthIsZero() && i::Top::is_out_of_memory()) { \
76 if (!thread_local.ignore_out_of_memory()) \
77 i::V8::FatalProcessOutOfMemory(NULL); \
78 } \
79 bool call_depth_is_zero = thread_local.CallDepthIsZero(); \
80 i::Top::OptionalRescheduleException(call_depth_is_zero); \
81 return value; \
82 } \
83 } while (false)
84
85
86#define API_ENTRY_CHECK(msg) \
87 do { \
88 if (v8::Locker::IsActive()) { \
89 ApiCheck(i::ThreadManager::IsLockedByCurrentThread(), \
90 msg, \
91 "Entering the V8 API without proper locking in place"); \
92 } \
93 } while (false)
94
95// --- D a t a t h a t i s s p e c i f i c t o a t h r e a d ---
96
97
98static i::HandleScopeImplementer thread_local;
99
100
101// --- E x c e p t i o n B e h a v i o r ---
102
103
104static FatalErrorCallback exception_behavior = NULL;
105int i::Internals::kJSObjectType = JS_OBJECT_TYPE;
106int i::Internals::kFirstNonstringType = FIRST_NONSTRING_TYPE;
107int i::Internals::kProxyType = PROXY_TYPE;
108
109static void DefaultFatalErrorHandler(const char* location,
110 const char* message) {
111 ENTER_V8;
112 API_Fatal(location, message);
113}
114
115
116
117static FatalErrorCallback& GetFatalErrorHandler() {
118 if (exception_behavior == NULL) {
119 exception_behavior = DefaultFatalErrorHandler;
120 }
121 return exception_behavior;
122}
123
124
125
126// When V8 cannot allocated memory FatalProcessOutOfMemory is called.
127// The default fatal error handler is called and execution is stopped.
128void i::V8::FatalProcessOutOfMemory(const char* location) {
Steve Blockd0582a62009-12-15 09:54:21 +0000129 i::HeapStats heap_stats;
130 int start_marker;
131 heap_stats.start_marker = &start_marker;
132 int new_space_size;
133 heap_stats.new_space_size = &new_space_size;
134 int new_space_capacity;
135 heap_stats.new_space_capacity = &new_space_capacity;
136 int old_pointer_space_size;
137 heap_stats.old_pointer_space_size = &old_pointer_space_size;
138 int old_pointer_space_capacity;
139 heap_stats.old_pointer_space_capacity = &old_pointer_space_capacity;
140 int old_data_space_size;
141 heap_stats.old_data_space_size = &old_data_space_size;
142 int old_data_space_capacity;
143 heap_stats.old_data_space_capacity = &old_data_space_capacity;
144 int code_space_size;
145 heap_stats.code_space_size = &code_space_size;
146 int code_space_capacity;
147 heap_stats.code_space_capacity = &code_space_capacity;
148 int map_space_size;
149 heap_stats.map_space_size = &map_space_size;
150 int map_space_capacity;
151 heap_stats.map_space_capacity = &map_space_capacity;
152 int cell_space_size;
153 heap_stats.cell_space_size = &cell_space_size;
154 int cell_space_capacity;
155 heap_stats.cell_space_capacity = &cell_space_capacity;
156 int lo_space_size;
157 heap_stats.lo_space_size = &lo_space_size;
158 int global_handle_count;
159 heap_stats.global_handle_count = &global_handle_count;
160 int weak_global_handle_count;
161 heap_stats.weak_global_handle_count = &weak_global_handle_count;
162 int pending_global_handle_count;
163 heap_stats.pending_global_handle_count = &pending_global_handle_count;
164 int near_death_global_handle_count;
165 heap_stats.near_death_global_handle_count = &near_death_global_handle_count;
166 int destroyed_global_handle_count;
167 heap_stats.destroyed_global_handle_count = &destroyed_global_handle_count;
168 int end_marker;
169 heap_stats.end_marker = &end_marker;
170 i::Heap::RecordStats(&heap_stats);
Steve Blocka7e24c12009-10-30 11:49:00 +0000171 i::V8::SetFatalError();
172 FatalErrorCallback callback = GetFatalErrorHandler();
173 {
174 LEAVE_V8;
175 callback(location, "Allocation failed - process out of memory");
176 }
177 // If the callback returns, we stop execution.
178 UNREACHABLE();
179}
180
181
182void V8::SetFatalErrorHandler(FatalErrorCallback that) {
183 exception_behavior = that;
184}
185
186
187bool Utils::ReportApiFailure(const char* location, const char* message) {
188 FatalErrorCallback callback = GetFatalErrorHandler();
189 callback(location, message);
190 i::V8::SetFatalError();
191 return false;
192}
193
194
195bool V8::IsDead() {
196 return i::V8::IsDead();
197}
198
199
200static inline bool ApiCheck(bool condition,
201 const char* location,
202 const char* message) {
203 return condition ? true : Utils::ReportApiFailure(location, message);
204}
205
206
207static bool ReportV8Dead(const char* location) {
208 FatalErrorCallback callback = GetFatalErrorHandler();
209 callback(location, "V8 is no longer usable");
210 return true;
211}
212
213
214static bool ReportEmptyHandle(const char* location) {
215 FatalErrorCallback callback = GetFatalErrorHandler();
216 callback(location, "Reading from empty handle");
217 return true;
218}
219
220
221/**
222 * IsDeadCheck checks that the vm is usable. If, for instance, the vm has been
223 * out of memory at some point this check will fail. It should be called on
224 * entry to all methods that touch anything in the heap, except destructors
225 * which you sometimes can't avoid calling after the vm has crashed. Functions
226 * that call EnsureInitialized or ON_BAILOUT don't have to also call
227 * IsDeadCheck. ON_BAILOUT has the advantage over EnsureInitialized that you
228 * can arrange to return if the VM is dead. This is needed to ensure that no VM
229 * heap allocations are attempted on a dead VM. EnsureInitialized has the
230 * advantage over ON_BAILOUT that it actually initializes the VM if this has not
231 * yet been done.
232 */
233static inline bool IsDeadCheck(const char* location) {
234 return !i::V8::IsRunning()
235 && i::V8::IsDead() ? ReportV8Dead(location) : false;
236}
237
238
239static inline bool EmptyCheck(const char* location, v8::Handle<v8::Data> obj) {
240 return obj.IsEmpty() ? ReportEmptyHandle(location) : false;
241}
242
243
244static inline bool EmptyCheck(const char* location, const v8::Data* obj) {
245 return (obj == 0) ? ReportEmptyHandle(location) : false;
246}
247
248// --- S t a t i c s ---
249
250
251static i::StringInputBuffer write_input_buffer;
252
253
254static inline bool EnsureInitialized(const char* location) {
255 if (i::V8::IsRunning()) {
256 return true;
257 }
258 if (IsDeadCheck(location)) {
259 return false;
260 }
261 return ApiCheck(v8::V8::Initialize(), location, "Error initializing V8");
262}
263
264
265ImplementationUtilities::HandleScopeData*
266 ImplementationUtilities::CurrentHandleScope() {
267 return &i::HandleScope::current_;
268}
269
270
271#ifdef DEBUG
272void ImplementationUtilities::ZapHandleRange(i::Object** begin,
273 i::Object** end) {
274 i::HandleScope::ZapRange(begin, end);
275}
276#endif
277
278
279v8::Handle<v8::Primitive> ImplementationUtilities::Undefined() {
280 if (!EnsureInitialized("v8::Undefined()")) return v8::Handle<v8::Primitive>();
281 return v8::Handle<Primitive>(ToApi<Primitive>(i::Factory::undefined_value()));
282}
283
284
285v8::Handle<v8::Primitive> ImplementationUtilities::Null() {
286 if (!EnsureInitialized("v8::Null()")) return v8::Handle<v8::Primitive>();
287 return v8::Handle<Primitive>(ToApi<Primitive>(i::Factory::null_value()));
288}
289
290
291v8::Handle<v8::Boolean> ImplementationUtilities::True() {
292 if (!EnsureInitialized("v8::True()")) return v8::Handle<v8::Boolean>();
293 return v8::Handle<v8::Boolean>(ToApi<Boolean>(i::Factory::true_value()));
294}
295
296
297v8::Handle<v8::Boolean> ImplementationUtilities::False() {
298 if (!EnsureInitialized("v8::False()")) return v8::Handle<v8::Boolean>();
299 return v8::Handle<v8::Boolean>(ToApi<Boolean>(i::Factory::false_value()));
300}
301
302
303void V8::SetFlagsFromString(const char* str, int length) {
304 i::FlagList::SetFlagsFromString(str, length);
305}
306
307
308void V8::SetFlagsFromCommandLine(int* argc, char** argv, bool remove_flags) {
309 i::FlagList::SetFlagsFromCommandLine(argc, argv, remove_flags);
310}
311
312
313v8::Handle<Value> ThrowException(v8::Handle<v8::Value> value) {
314 if (IsDeadCheck("v8::ThrowException()")) return v8::Handle<Value>();
315 ENTER_V8;
316 // If we're passed an empty handle, we throw an undefined exception
317 // to deal more gracefully with out of memory situations.
318 if (value.IsEmpty()) {
319 i::Top::ScheduleThrow(i::Heap::undefined_value());
320 } else {
321 i::Top::ScheduleThrow(*Utils::OpenHandle(*value));
322 }
323 return v8::Undefined();
324}
325
326
327RegisteredExtension* RegisteredExtension::first_extension_ = NULL;
328
329
330RegisteredExtension::RegisteredExtension(Extension* extension)
331 : extension_(extension), state_(UNVISITED) { }
332
333
334void RegisteredExtension::Register(RegisteredExtension* that) {
335 that->next_ = RegisteredExtension::first_extension_;
336 RegisteredExtension::first_extension_ = that;
337}
338
339
340void RegisterExtension(Extension* that) {
341 RegisteredExtension* extension = new RegisteredExtension(that);
342 RegisteredExtension::Register(extension);
343}
344
345
346Extension::Extension(const char* name,
347 const char* source,
348 int dep_count,
349 const char** deps)
350 : name_(name),
351 source_(source),
352 dep_count_(dep_count),
353 deps_(deps),
354 auto_enable_(false) { }
355
356
357v8::Handle<Primitive> Undefined() {
358 LOG_API("Undefined");
359 return ImplementationUtilities::Undefined();
360}
361
362
363v8::Handle<Primitive> Null() {
364 LOG_API("Null");
365 return ImplementationUtilities::Null();
366}
367
368
369v8::Handle<Boolean> True() {
370 LOG_API("True");
371 return ImplementationUtilities::True();
372}
373
374
375v8::Handle<Boolean> False() {
376 LOG_API("False");
377 return ImplementationUtilities::False();
378}
379
380
381ResourceConstraints::ResourceConstraints()
382 : max_young_space_size_(0),
383 max_old_space_size_(0),
384 stack_limit_(NULL) { }
385
386
387bool SetResourceConstraints(ResourceConstraints* constraints) {
Steve Block3ce2e202009-11-05 08:53:23 +0000388 int young_space_size = constraints->max_young_space_size();
Steve Blocka7e24c12009-10-30 11:49:00 +0000389 int old_gen_size = constraints->max_old_space_size();
Steve Block3ce2e202009-11-05 08:53:23 +0000390 if (young_space_size != 0 || old_gen_size != 0) {
391 bool result = i::Heap::ConfigureHeap(young_space_size / 2, old_gen_size);
Steve Blocka7e24c12009-10-30 11:49:00 +0000392 if (!result) return false;
393 }
394 if (constraints->stack_limit() != NULL) {
395 uintptr_t limit = reinterpret_cast<uintptr_t>(constraints->stack_limit());
396 i::StackGuard::SetStackLimit(limit);
397 }
398 return true;
399}
400
401
402i::Object** V8::GlobalizeReference(i::Object** obj) {
403 if (IsDeadCheck("V8::Persistent::New")) return NULL;
404 LOG_API("Persistent::New");
405 i::Handle<i::Object> result =
406 i::GlobalHandles::Create(*obj);
407 return result.location();
408}
409
410
411void V8::MakeWeak(i::Object** object, void* parameters,
412 WeakReferenceCallback callback) {
413 LOG_API("MakeWeak");
414 i::GlobalHandles::MakeWeak(object, parameters, callback);
415}
416
417
418void V8::ClearWeak(i::Object** obj) {
419 LOG_API("ClearWeak");
420 i::GlobalHandles::ClearWeakness(obj);
421}
422
423
424bool V8::IsGlobalNearDeath(i::Object** obj) {
425 LOG_API("IsGlobalNearDeath");
426 if (!i::V8::IsRunning()) return false;
427 return i::GlobalHandles::IsNearDeath(obj);
428}
429
430
431bool V8::IsGlobalWeak(i::Object** obj) {
432 LOG_API("IsGlobalWeak");
433 if (!i::V8::IsRunning()) return false;
434 return i::GlobalHandles::IsWeak(obj);
435}
436
437
438void V8::DisposeGlobal(i::Object** obj) {
439 LOG_API("DisposeGlobal");
440 if (!i::V8::IsRunning()) return;
441 if ((*obj)->IsGlobalContext()) i::Heap::NotifyContextDisposed();
442 i::GlobalHandles::Destroy(obj);
443}
444
445// --- H a n d l e s ---
446
447
448HandleScope::HandleScope() : is_closed_(false) {
449 API_ENTRY_CHECK("HandleScope::HandleScope");
450 i::HandleScope::Enter(&previous_);
451}
452
453
454HandleScope::~HandleScope() {
455 if (!is_closed_) {
456 i::HandleScope::Leave(&previous_);
457 }
458}
459
460
461int HandleScope::NumberOfHandles() {
462 return i::HandleScope::NumberOfHandles();
463}
464
465
466i::Object** v8::HandleScope::CreateHandle(i::Object* value) {
467 return i::HandleScope::CreateHandle(value);
468}
469
470
471void Context::Enter() {
472 if (IsDeadCheck("v8::Context::Enter()")) return;
473 ENTER_V8;
474 i::Handle<i::Context> env = Utils::OpenHandle(this);
475 thread_local.EnterContext(env);
476
477 thread_local.SaveContext(i::Top::context());
478 i::Top::set_context(*env);
479}
480
481
482void Context::Exit() {
483 if (!i::V8::IsRunning()) return;
484 if (!ApiCheck(thread_local.LeaveLastContext(),
485 "v8::Context::Exit()",
486 "Cannot exit non-entered context")) {
487 return;
488 }
489
490 // Content of 'last_context' could be NULL.
491 i::Context* last_context = thread_local.RestoreContext();
492 i::Top::set_context(last_context);
493}
494
495
Steve Blockd0582a62009-12-15 09:54:21 +0000496void Context::SetData(v8::Handle<String> data) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000497 if (IsDeadCheck("v8::Context::SetData()")) return;
498 ENTER_V8;
499 {
500 HandleScope scope;
501 i::Handle<i::Context> env = Utils::OpenHandle(this);
502 i::Handle<i::Object> raw_data = Utils::OpenHandle(*data);
503 ASSERT(env->IsGlobalContext());
504 if (env->IsGlobalContext()) {
505 env->set_data(*raw_data);
506 }
507 }
508}
509
510
511v8::Local<v8::Value> Context::GetData() {
512 if (IsDeadCheck("v8::Context::GetData()")) return v8::Local<Value>();
513 ENTER_V8;
514 i::Object* raw_result = NULL;
515 {
516 HandleScope scope;
517 i::Handle<i::Context> env = Utils::OpenHandle(this);
518 ASSERT(env->IsGlobalContext());
519 if (env->IsGlobalContext()) {
520 raw_result = env->data();
521 } else {
522 return Local<Value>();
523 }
524 }
525 i::Handle<i::Object> result(raw_result);
526 return Utils::ToLocal(result);
527}
528
529
530i::Object** v8::HandleScope::RawClose(i::Object** value) {
531 if (!ApiCheck(!is_closed_,
532 "v8::HandleScope::Close()",
533 "Local scope has already been closed")) {
534 return 0;
535 }
536 LOG_API("CloseHandleScope");
537
538 // Read the result before popping the handle block.
539 i::Object* result = *value;
540 is_closed_ = true;
541 i::HandleScope::Leave(&previous_);
542
543 // Allocate a new handle on the previous handle block.
544 i::Handle<i::Object> handle(result);
545 return handle.location();
546}
547
548
549// --- N e a n d e r ---
550
551
552// A constructor cannot easily return an error value, therefore it is necessary
553// to check for a dead VM with ON_BAILOUT before constructing any Neander
554// objects. To remind you about this there is no HandleScope in the
555// NeanderObject constructor. When you add one to the site calling the
556// constructor you should check that you ensured the VM was not dead first.
557NeanderObject::NeanderObject(int size) {
558 EnsureInitialized("v8::Nowhere");
559 ENTER_V8;
560 value_ = i::Factory::NewNeanderObject();
561 i::Handle<i::FixedArray> elements = i::Factory::NewFixedArray(size);
562 value_->set_elements(*elements);
563}
564
565
566int NeanderObject::size() {
567 return i::FixedArray::cast(value_->elements())->length();
568}
569
570
571NeanderArray::NeanderArray() : obj_(2) {
572 obj_.set(0, i::Smi::FromInt(0));
573}
574
575
576int NeanderArray::length() {
577 return i::Smi::cast(obj_.get(0))->value();
578}
579
580
581i::Object* NeanderArray::get(int offset) {
582 ASSERT(0 <= offset);
583 ASSERT(offset < length());
584 return obj_.get(offset + 1);
585}
586
587
588// This method cannot easily return an error value, therefore it is necessary
589// to check for a dead VM with ON_BAILOUT before calling it. To remind you
590// about this there is no HandleScope in this method. When you add one to the
591// site calling this method you should check that you ensured the VM was not
592// dead first.
593void NeanderArray::add(i::Handle<i::Object> value) {
594 int length = this->length();
595 int size = obj_.size();
596 if (length == size - 1) {
597 i::Handle<i::FixedArray> new_elms = i::Factory::NewFixedArray(2 * size);
598 for (int i = 0; i < length; i++)
599 new_elms->set(i + 1, get(i));
600 obj_.value()->set_elements(*new_elms);
601 }
602 obj_.set(length + 1, *value);
603 obj_.set(0, i::Smi::FromInt(length + 1));
604}
605
606
607void NeanderArray::set(int index, i::Object* value) {
608 if (index < 0 || index >= this->length()) return;
609 obj_.set(index + 1, value);
610}
611
612
613// --- T e m p l a t e ---
614
615
616static void InitializeTemplate(i::Handle<i::TemplateInfo> that, int type) {
617 that->set_tag(i::Smi::FromInt(type));
618}
619
620
621void Template::Set(v8::Handle<String> name, v8::Handle<Data> value,
622 v8::PropertyAttribute attribute) {
623 if (IsDeadCheck("v8::Template::SetProperty()")) return;
624 ENTER_V8;
625 HandleScope scope;
626 i::Handle<i::Object> list(Utils::OpenHandle(this)->property_list());
627 if (list->IsUndefined()) {
628 list = NeanderArray().value();
629 Utils::OpenHandle(this)->set_property_list(*list);
630 }
631 NeanderArray array(list);
632 array.add(Utils::OpenHandle(*name));
633 array.add(Utils::OpenHandle(*value));
634 array.add(Utils::OpenHandle(*v8::Integer::New(attribute)));
635}
636
637
638// --- F u n c t i o n T e m p l a t e ---
639static void InitializeFunctionTemplate(
640 i::Handle<i::FunctionTemplateInfo> info) {
641 info->set_tag(i::Smi::FromInt(Consts::FUNCTION_TEMPLATE));
642 info->set_flag(0);
643}
644
645
646Local<ObjectTemplate> FunctionTemplate::PrototypeTemplate() {
647 if (IsDeadCheck("v8::FunctionTemplate::PrototypeTemplate()")) {
648 return Local<ObjectTemplate>();
649 }
650 ENTER_V8;
651 i::Handle<i::Object> result(Utils::OpenHandle(this)->prototype_template());
652 if (result->IsUndefined()) {
653 result = Utils::OpenHandle(*ObjectTemplate::New());
654 Utils::OpenHandle(this)->set_prototype_template(*result);
655 }
656 return Local<ObjectTemplate>(ToApi<ObjectTemplate>(result));
657}
658
659
660void FunctionTemplate::Inherit(v8::Handle<FunctionTemplate> value) {
661 if (IsDeadCheck("v8::FunctionTemplate::Inherit()")) return;
662 ENTER_V8;
663 Utils::OpenHandle(this)->set_parent_template(*Utils::OpenHandle(*value));
664}
665
666
667// To distinguish the function templates, so that we can find them in the
668// function cache of the global context.
669static int next_serial_number = 0;
670
671
672Local<FunctionTemplate> FunctionTemplate::New(InvocationCallback callback,
673 v8::Handle<Value> data, v8::Handle<Signature> signature) {
674 EnsureInitialized("v8::FunctionTemplate::New()");
675 LOG_API("FunctionTemplate::New");
676 ENTER_V8;
677 i::Handle<i::Struct> struct_obj =
678 i::Factory::NewStruct(i::FUNCTION_TEMPLATE_INFO_TYPE);
679 i::Handle<i::FunctionTemplateInfo> obj =
680 i::Handle<i::FunctionTemplateInfo>::cast(struct_obj);
681 InitializeFunctionTemplate(obj);
682 obj->set_serial_number(i::Smi::FromInt(next_serial_number++));
683 if (callback != 0) {
684 if (data.IsEmpty()) data = v8::Undefined();
685 Utils::ToLocal(obj)->SetCallHandler(callback, data);
686 }
687 obj->set_undetectable(false);
688 obj->set_needs_access_check(false);
689
690 if (!signature.IsEmpty())
691 obj->set_signature(*Utils::OpenHandle(*signature));
692 return Utils::ToLocal(obj);
693}
694
695
696Local<Signature> Signature::New(Handle<FunctionTemplate> receiver,
697 int argc, Handle<FunctionTemplate> argv[]) {
698 EnsureInitialized("v8::Signature::New()");
699 LOG_API("Signature::New");
700 ENTER_V8;
701 i::Handle<i::Struct> struct_obj =
702 i::Factory::NewStruct(i::SIGNATURE_INFO_TYPE);
703 i::Handle<i::SignatureInfo> obj =
704 i::Handle<i::SignatureInfo>::cast(struct_obj);
705 if (!receiver.IsEmpty()) obj->set_receiver(*Utils::OpenHandle(*receiver));
706 if (argc > 0) {
707 i::Handle<i::FixedArray> args = i::Factory::NewFixedArray(argc);
708 for (int i = 0; i < argc; i++) {
709 if (!argv[i].IsEmpty())
710 args->set(i, *Utils::OpenHandle(*argv[i]));
711 }
712 obj->set_args(*args);
713 }
714 return Utils::ToLocal(obj);
715}
716
717
718Local<TypeSwitch> TypeSwitch::New(Handle<FunctionTemplate> type) {
719 Handle<FunctionTemplate> types[1] = { type };
720 return TypeSwitch::New(1, types);
721}
722
723
724Local<TypeSwitch> TypeSwitch::New(int argc, Handle<FunctionTemplate> types[]) {
725 EnsureInitialized("v8::TypeSwitch::New()");
726 LOG_API("TypeSwitch::New");
727 ENTER_V8;
728 i::Handle<i::FixedArray> vector = i::Factory::NewFixedArray(argc);
729 for (int i = 0; i < argc; i++)
730 vector->set(i, *Utils::OpenHandle(*types[i]));
731 i::Handle<i::Struct> struct_obj =
732 i::Factory::NewStruct(i::TYPE_SWITCH_INFO_TYPE);
733 i::Handle<i::TypeSwitchInfo> obj =
734 i::Handle<i::TypeSwitchInfo>::cast(struct_obj);
735 obj->set_types(*vector);
736 return Utils::ToLocal(obj);
737}
738
739
740int TypeSwitch::match(v8::Handle<Value> value) {
741 LOG_API("TypeSwitch::match");
742 i::Handle<i::Object> obj = Utils::OpenHandle(*value);
743 i::Handle<i::TypeSwitchInfo> info = Utils::OpenHandle(this);
744 i::FixedArray* types = i::FixedArray::cast(info->types());
745 for (int i = 0; i < types->length(); i++) {
746 if (obj->IsInstanceOf(i::FunctionTemplateInfo::cast(types->get(i))))
747 return i + 1;
748 }
749 return 0;
750}
751
752
753void FunctionTemplate::SetCallHandler(InvocationCallback callback,
754 v8::Handle<Value> data) {
755 if (IsDeadCheck("v8::FunctionTemplate::SetCallHandler()")) return;
756 ENTER_V8;
757 HandleScope scope;
758 i::Handle<i::Struct> struct_obj =
759 i::Factory::NewStruct(i::CALL_HANDLER_INFO_TYPE);
760 i::Handle<i::CallHandlerInfo> obj =
761 i::Handle<i::CallHandlerInfo>::cast(struct_obj);
762 obj->set_callback(*FromCData(callback));
763 if (data.IsEmpty()) data = v8::Undefined();
764 obj->set_data(*Utils::OpenHandle(*data));
765 Utils::OpenHandle(this)->set_call_code(*obj);
766}
767
768
769void FunctionTemplate::AddInstancePropertyAccessor(
770 v8::Handle<String> name,
771 AccessorGetter getter,
772 AccessorSetter setter,
773 v8::Handle<Value> data,
774 v8::AccessControl settings,
775 v8::PropertyAttribute attributes) {
776 if (IsDeadCheck("v8::FunctionTemplate::AddInstancePropertyAccessor()")) {
777 return;
778 }
779 ENTER_V8;
780 HandleScope scope;
781 i::Handle<i::AccessorInfo> obj = i::Factory::NewAccessorInfo();
782 ASSERT(getter != NULL);
783 obj->set_getter(*FromCData(getter));
784 obj->set_setter(*FromCData(setter));
785 if (data.IsEmpty()) data = v8::Undefined();
786 obj->set_data(*Utils::OpenHandle(*data));
787 obj->set_name(*Utils::OpenHandle(*name));
788 if (settings & ALL_CAN_READ) obj->set_all_can_read(true);
789 if (settings & ALL_CAN_WRITE) obj->set_all_can_write(true);
790 if (settings & PROHIBITS_OVERWRITING) obj->set_prohibits_overwriting(true);
791 obj->set_property_attributes(static_cast<PropertyAttributes>(attributes));
792
793 i::Handle<i::Object> list(Utils::OpenHandle(this)->property_accessors());
794 if (list->IsUndefined()) {
795 list = NeanderArray().value();
796 Utils::OpenHandle(this)->set_property_accessors(*list);
797 }
798 NeanderArray array(list);
799 array.add(obj);
800}
801
802
803Local<ObjectTemplate> FunctionTemplate::InstanceTemplate() {
804 if (IsDeadCheck("v8::FunctionTemplate::InstanceTemplate()")
805 || EmptyCheck("v8::FunctionTemplate::InstanceTemplate()", this))
806 return Local<ObjectTemplate>();
807 ENTER_V8;
808 if (Utils::OpenHandle(this)->instance_template()->IsUndefined()) {
809 Local<ObjectTemplate> templ =
810 ObjectTemplate::New(v8::Handle<FunctionTemplate>(this));
811 Utils::OpenHandle(this)->set_instance_template(*Utils::OpenHandle(*templ));
812 }
813 i::Handle<i::ObjectTemplateInfo> result(i::ObjectTemplateInfo::cast(
814 Utils::OpenHandle(this)->instance_template()));
815 return Utils::ToLocal(result);
816}
817
818
819void FunctionTemplate::SetClassName(Handle<String> name) {
820 if (IsDeadCheck("v8::FunctionTemplate::SetClassName()")) return;
821 ENTER_V8;
822 Utils::OpenHandle(this)->set_class_name(*Utils::OpenHandle(*name));
823}
824
825
826void FunctionTemplate::SetHiddenPrototype(bool value) {
827 if (IsDeadCheck("v8::FunctionTemplate::SetHiddenPrototype()")) return;
828 ENTER_V8;
829 Utils::OpenHandle(this)->set_hidden_prototype(value);
830}
831
832
833void FunctionTemplate::SetNamedInstancePropertyHandler(
834 NamedPropertyGetter getter,
835 NamedPropertySetter setter,
836 NamedPropertyQuery query,
837 NamedPropertyDeleter remover,
838 NamedPropertyEnumerator enumerator,
839 Handle<Value> data) {
840 if (IsDeadCheck("v8::FunctionTemplate::SetNamedInstancePropertyHandler()")) {
841 return;
842 }
843 ENTER_V8;
844 HandleScope scope;
845 i::Handle<i::Struct> struct_obj =
846 i::Factory::NewStruct(i::INTERCEPTOR_INFO_TYPE);
847 i::Handle<i::InterceptorInfo> obj =
848 i::Handle<i::InterceptorInfo>::cast(struct_obj);
849 if (getter != 0) obj->set_getter(*FromCData(getter));
850 if (setter != 0) obj->set_setter(*FromCData(setter));
851 if (query != 0) obj->set_query(*FromCData(query));
852 if (remover != 0) obj->set_deleter(*FromCData(remover));
853 if (enumerator != 0) obj->set_enumerator(*FromCData(enumerator));
854 if (data.IsEmpty()) data = v8::Undefined();
855 obj->set_data(*Utils::OpenHandle(*data));
856 Utils::OpenHandle(this)->set_named_property_handler(*obj);
857}
858
859
860void FunctionTemplate::SetIndexedInstancePropertyHandler(
861 IndexedPropertyGetter getter,
862 IndexedPropertySetter setter,
863 IndexedPropertyQuery query,
864 IndexedPropertyDeleter remover,
865 IndexedPropertyEnumerator enumerator,
866 Handle<Value> data) {
867 if (IsDeadCheck(
868 "v8::FunctionTemplate::SetIndexedInstancePropertyHandler()")) {
869 return;
870 }
871 ENTER_V8;
872 HandleScope scope;
873 i::Handle<i::Struct> struct_obj =
874 i::Factory::NewStruct(i::INTERCEPTOR_INFO_TYPE);
875 i::Handle<i::InterceptorInfo> obj =
876 i::Handle<i::InterceptorInfo>::cast(struct_obj);
877 if (getter != 0) obj->set_getter(*FromCData(getter));
878 if (setter != 0) obj->set_setter(*FromCData(setter));
879 if (query != 0) obj->set_query(*FromCData(query));
880 if (remover != 0) obj->set_deleter(*FromCData(remover));
881 if (enumerator != 0) obj->set_enumerator(*FromCData(enumerator));
882 if (data.IsEmpty()) data = v8::Undefined();
883 obj->set_data(*Utils::OpenHandle(*data));
884 Utils::OpenHandle(this)->set_indexed_property_handler(*obj);
885}
886
887
888void FunctionTemplate::SetInstanceCallAsFunctionHandler(
889 InvocationCallback callback,
890 Handle<Value> data) {
891 if (IsDeadCheck("v8::FunctionTemplate::SetInstanceCallAsFunctionHandler()")) {
892 return;
893 }
894 ENTER_V8;
895 HandleScope scope;
896 i::Handle<i::Struct> struct_obj =
897 i::Factory::NewStruct(i::CALL_HANDLER_INFO_TYPE);
898 i::Handle<i::CallHandlerInfo> obj =
899 i::Handle<i::CallHandlerInfo>::cast(struct_obj);
900 obj->set_callback(*FromCData(callback));
901 if (data.IsEmpty()) data = v8::Undefined();
902 obj->set_data(*Utils::OpenHandle(*data));
903 Utils::OpenHandle(this)->set_instance_call_handler(*obj);
904}
905
906
907// --- O b j e c t T e m p l a t e ---
908
909
910Local<ObjectTemplate> ObjectTemplate::New() {
911 return New(Local<FunctionTemplate>());
912}
913
914
915Local<ObjectTemplate> ObjectTemplate::New(
916 v8::Handle<FunctionTemplate> constructor) {
917 if (IsDeadCheck("v8::ObjectTemplate::New()")) return Local<ObjectTemplate>();
918 EnsureInitialized("v8::ObjectTemplate::New()");
919 LOG_API("ObjectTemplate::New");
920 ENTER_V8;
921 i::Handle<i::Struct> struct_obj =
922 i::Factory::NewStruct(i::OBJECT_TEMPLATE_INFO_TYPE);
923 i::Handle<i::ObjectTemplateInfo> obj =
924 i::Handle<i::ObjectTemplateInfo>::cast(struct_obj);
925 InitializeTemplate(obj, Consts::OBJECT_TEMPLATE);
926 if (!constructor.IsEmpty())
927 obj->set_constructor(*Utils::OpenHandle(*constructor));
928 obj->set_internal_field_count(i::Smi::FromInt(0));
929 return Utils::ToLocal(obj);
930}
931
932
933// Ensure that the object template has a constructor. If no
934// constructor is available we create one.
935static void EnsureConstructor(ObjectTemplate* object_template) {
936 if (Utils::OpenHandle(object_template)->constructor()->IsUndefined()) {
937 Local<FunctionTemplate> templ = FunctionTemplate::New();
938 i::Handle<i::FunctionTemplateInfo> constructor = Utils::OpenHandle(*templ);
939 constructor->set_instance_template(*Utils::OpenHandle(object_template));
940 Utils::OpenHandle(object_template)->set_constructor(*constructor);
941 }
942}
943
944
945void ObjectTemplate::SetAccessor(v8::Handle<String> name,
946 AccessorGetter getter,
947 AccessorSetter setter,
948 v8::Handle<Value> data,
949 AccessControl settings,
950 PropertyAttribute attribute) {
951 if (IsDeadCheck("v8::ObjectTemplate::SetAccessor()")) return;
952 ENTER_V8;
953 HandleScope scope;
954 EnsureConstructor(this);
955 i::FunctionTemplateInfo* constructor =
956 i::FunctionTemplateInfo::cast(Utils::OpenHandle(this)->constructor());
957 i::Handle<i::FunctionTemplateInfo> cons(constructor);
958 Utils::ToLocal(cons)->AddInstancePropertyAccessor(name,
959 getter,
960 setter,
961 data,
962 settings,
963 attribute);
964}
965
966
967void ObjectTemplate::SetNamedPropertyHandler(NamedPropertyGetter getter,
968 NamedPropertySetter setter,
969 NamedPropertyQuery query,
970 NamedPropertyDeleter remover,
971 NamedPropertyEnumerator enumerator,
972 Handle<Value> data) {
973 if (IsDeadCheck("v8::ObjectTemplate::SetNamedPropertyHandler()")) return;
974 ENTER_V8;
975 HandleScope scope;
976 EnsureConstructor(this);
977 i::FunctionTemplateInfo* constructor =
978 i::FunctionTemplateInfo::cast(Utils::OpenHandle(this)->constructor());
979 i::Handle<i::FunctionTemplateInfo> cons(constructor);
980 Utils::ToLocal(cons)->SetNamedInstancePropertyHandler(getter,
981 setter,
982 query,
983 remover,
984 enumerator,
985 data);
986}
987
988
989void ObjectTemplate::MarkAsUndetectable() {
990 if (IsDeadCheck("v8::ObjectTemplate::MarkAsUndetectable()")) return;
991 ENTER_V8;
992 HandleScope scope;
993 EnsureConstructor(this);
994 i::FunctionTemplateInfo* constructor =
995 i::FunctionTemplateInfo::cast(Utils::OpenHandle(this)->constructor());
996 i::Handle<i::FunctionTemplateInfo> cons(constructor);
997 cons->set_undetectable(true);
998}
999
1000
1001void ObjectTemplate::SetAccessCheckCallbacks(
1002 NamedSecurityCallback named_callback,
1003 IndexedSecurityCallback indexed_callback,
1004 Handle<Value> data,
1005 bool turned_on_by_default) {
1006 if (IsDeadCheck("v8::ObjectTemplate::SetAccessCheckCallbacks()")) return;
1007 ENTER_V8;
1008 HandleScope scope;
1009 EnsureConstructor(this);
1010
1011 i::Handle<i::Struct> struct_info =
1012 i::Factory::NewStruct(i::ACCESS_CHECK_INFO_TYPE);
1013 i::Handle<i::AccessCheckInfo> info =
1014 i::Handle<i::AccessCheckInfo>::cast(struct_info);
1015 info->set_named_callback(*FromCData(named_callback));
1016 info->set_indexed_callback(*FromCData(indexed_callback));
1017 if (data.IsEmpty()) data = v8::Undefined();
1018 info->set_data(*Utils::OpenHandle(*data));
1019
1020 i::FunctionTemplateInfo* constructor =
1021 i::FunctionTemplateInfo::cast(Utils::OpenHandle(this)->constructor());
1022 i::Handle<i::FunctionTemplateInfo> cons(constructor);
1023 cons->set_access_check_info(*info);
1024 cons->set_needs_access_check(turned_on_by_default);
1025}
1026
1027
1028void ObjectTemplate::SetIndexedPropertyHandler(
1029 IndexedPropertyGetter getter,
1030 IndexedPropertySetter setter,
1031 IndexedPropertyQuery query,
1032 IndexedPropertyDeleter remover,
1033 IndexedPropertyEnumerator enumerator,
1034 Handle<Value> data) {
1035 if (IsDeadCheck("v8::ObjectTemplate::SetIndexedPropertyHandler()")) return;
1036 ENTER_V8;
1037 HandleScope scope;
1038 EnsureConstructor(this);
1039 i::FunctionTemplateInfo* constructor =
1040 i::FunctionTemplateInfo::cast(Utils::OpenHandle(this)->constructor());
1041 i::Handle<i::FunctionTemplateInfo> cons(constructor);
1042 Utils::ToLocal(cons)->SetIndexedInstancePropertyHandler(getter,
1043 setter,
1044 query,
1045 remover,
1046 enumerator,
1047 data);
1048}
1049
1050
1051void ObjectTemplate::SetCallAsFunctionHandler(InvocationCallback callback,
1052 Handle<Value> data) {
1053 if (IsDeadCheck("v8::ObjectTemplate::SetCallAsFunctionHandler()")) return;
1054 ENTER_V8;
1055 HandleScope scope;
1056 EnsureConstructor(this);
1057 i::FunctionTemplateInfo* constructor =
1058 i::FunctionTemplateInfo::cast(Utils::OpenHandle(this)->constructor());
1059 i::Handle<i::FunctionTemplateInfo> cons(constructor);
1060 Utils::ToLocal(cons)->SetInstanceCallAsFunctionHandler(callback, data);
1061}
1062
1063
1064int ObjectTemplate::InternalFieldCount() {
1065 if (IsDeadCheck("v8::ObjectTemplate::InternalFieldCount()")) {
1066 return 0;
1067 }
1068 return i::Smi::cast(Utils::OpenHandle(this)->internal_field_count())->value();
1069}
1070
1071
1072void ObjectTemplate::SetInternalFieldCount(int value) {
1073 if (IsDeadCheck("v8::ObjectTemplate::SetInternalFieldCount()")) return;
1074 if (!ApiCheck(i::Smi::IsValid(value),
1075 "v8::ObjectTemplate::SetInternalFieldCount()",
1076 "Invalid internal field count")) {
1077 return;
1078 }
1079 ENTER_V8;
1080 if (value > 0) {
1081 // The internal field count is set by the constructor function's
1082 // construct code, so we ensure that there is a constructor
1083 // function to do the setting.
1084 EnsureConstructor(this);
1085 }
1086 Utils::OpenHandle(this)->set_internal_field_count(i::Smi::FromInt(value));
1087}
1088
1089
1090// --- S c r i p t D a t a ---
1091
1092
1093ScriptData* ScriptData::PreCompile(const char* input, int length) {
1094 unibrow::Utf8InputBuffer<> buf(input, length);
1095 return i::PreParse(i::Handle<i::String>(), &buf, NULL);
1096}
1097
1098
1099ScriptData* ScriptData::New(unsigned* data, int length) {
1100 return new i::ScriptDataImpl(i::Vector<unsigned>(data, length));
1101}
1102
1103
1104// --- S c r i p t ---
1105
1106
1107Local<Script> Script::New(v8::Handle<String> source,
1108 v8::ScriptOrigin* origin,
1109 v8::ScriptData* script_data) {
1110 ON_BAILOUT("v8::Script::New()", return Local<Script>());
1111 LOG_API("Script::New");
1112 ENTER_V8;
1113 i::Handle<i::String> str = Utils::OpenHandle(*source);
1114 i::Handle<i::Object> name_obj;
1115 int line_offset = 0;
1116 int column_offset = 0;
1117 if (origin != NULL) {
1118 if (!origin->ResourceName().IsEmpty()) {
1119 name_obj = Utils::OpenHandle(*origin->ResourceName());
1120 }
1121 if (!origin->ResourceLineOffset().IsEmpty()) {
1122 line_offset = static_cast<int>(origin->ResourceLineOffset()->Value());
1123 }
1124 if (!origin->ResourceColumnOffset().IsEmpty()) {
1125 column_offset = static_cast<int>(origin->ResourceColumnOffset()->Value());
1126 }
1127 }
1128 EXCEPTION_PREAMBLE();
1129 i::ScriptDataImpl* pre_data = static_cast<i::ScriptDataImpl*>(script_data);
1130 // We assert that the pre-data is sane, even though we can actually
1131 // handle it if it turns out not to be in release mode.
1132 ASSERT(pre_data == NULL || pre_data->SanityCheck());
1133 // If the pre-data isn't sane we simply ignore it
1134 if (pre_data != NULL && !pre_data->SanityCheck()) {
1135 pre_data = NULL;
1136 }
1137 i::Handle<i::JSFunction> boilerplate = i::Compiler::Compile(str,
1138 name_obj,
1139 line_offset,
1140 column_offset,
1141 NULL,
1142 pre_data);
1143 has_pending_exception = boilerplate.is_null();
1144 EXCEPTION_BAILOUT_CHECK(Local<Script>());
1145 return Local<Script>(ToApi<Script>(boilerplate));
1146}
1147
1148
1149Local<Script> Script::New(v8::Handle<String> source,
1150 v8::Handle<Value> file_name) {
1151 ScriptOrigin origin(file_name);
1152 return New(source, &origin);
1153}
1154
1155
1156Local<Script> Script::Compile(v8::Handle<String> source,
1157 v8::ScriptOrigin* origin,
1158 v8::ScriptData* script_data) {
1159 ON_BAILOUT("v8::Script::Compile()", return Local<Script>());
1160 LOG_API("Script::Compile");
1161 ENTER_V8;
1162 Local<Script> generic = New(source, origin, script_data);
1163 if (generic.IsEmpty())
1164 return generic;
1165 i::Handle<i::JSFunction> boilerplate = Utils::OpenHandle(*generic);
1166 i::Handle<i::JSFunction> result =
1167 i::Factory::NewFunctionFromBoilerplate(boilerplate,
1168 i::Top::global_context());
1169 return Local<Script>(ToApi<Script>(result));
1170}
1171
1172
1173Local<Script> Script::Compile(v8::Handle<String> source,
1174 v8::Handle<Value> file_name) {
1175 ScriptOrigin origin(file_name);
1176 return Compile(source, &origin);
1177}
1178
1179
1180Local<Value> Script::Run() {
1181 ON_BAILOUT("v8::Script::Run()", return Local<Value>());
1182 LOG_API("Script::Run");
1183 ENTER_V8;
1184 i::Object* raw_result = NULL;
1185 {
1186 HandleScope scope;
1187 i::Handle<i::JSFunction> fun = Utils::OpenHandle(this);
1188 if (fun->IsBoilerplate()) {
1189 fun = i::Factory::NewFunctionFromBoilerplate(fun,
1190 i::Top::global_context());
1191 }
1192 EXCEPTION_PREAMBLE();
1193 i::Handle<i::Object> receiver(i::Top::context()->global_proxy());
1194 i::Handle<i::Object> result =
1195 i::Execution::Call(fun, receiver, 0, NULL, &has_pending_exception);
1196 EXCEPTION_BAILOUT_CHECK(Local<Value>());
1197 raw_result = *result;
1198 }
1199 i::Handle<i::Object> result(raw_result);
1200 return Utils::ToLocal(result);
1201}
1202
1203
1204Local<Value> Script::Id() {
1205 ON_BAILOUT("v8::Script::Id()", return Local<Value>());
1206 LOG_API("Script::Id");
1207 i::Object* raw_id = NULL;
1208 {
1209 HandleScope scope;
1210 i::Handle<i::JSFunction> fun = Utils::OpenHandle(this);
1211 i::Handle<i::Script> script(i::Script::cast(fun->shared()->script()));
1212 i::Handle<i::Object> id(script->id());
1213 raw_id = *id;
1214 }
1215 i::Handle<i::Object> id(raw_id);
1216 return Utils::ToLocal(id);
1217}
1218
1219
Steve Blockd0582a62009-12-15 09:54:21 +00001220void Script::SetData(v8::Handle<String> data) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001221 ON_BAILOUT("v8::Script::SetData()", return);
1222 LOG_API("Script::SetData");
1223 {
1224 HandleScope scope;
1225 i::Handle<i::JSFunction> fun = Utils::OpenHandle(this);
1226 i::Handle<i::Object> raw_data = Utils::OpenHandle(*data);
1227 i::Handle<i::Script> script(i::Script::cast(fun->shared()->script()));
1228 script->set_data(*raw_data);
1229 }
1230}
1231
1232
1233// --- E x c e p t i o n s ---
1234
1235
1236v8::TryCatch::TryCatch()
Steve Blockd0582a62009-12-15 09:54:21 +00001237 : next_(i::Top::try_catch_handler_address()),
Steve Blocka7e24c12009-10-30 11:49:00 +00001238 exception_(i::Heap::the_hole_value()),
1239 message_(i::Smi::FromInt(0)),
1240 is_verbose_(false),
1241 can_continue_(true),
1242 capture_message_(true),
Steve Blockd0582a62009-12-15 09:54:21 +00001243 rethrow_(false) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001244 i::Top::RegisterTryCatchHandler(this);
1245}
1246
1247
1248v8::TryCatch::~TryCatch() {
Steve Blockd0582a62009-12-15 09:54:21 +00001249 if (rethrow_) {
1250 v8::HandleScope scope;
1251 v8::Local<v8::Value> exc = v8::Local<v8::Value>::New(Exception());
1252 i::Top::UnregisterTryCatchHandler(this);
1253 v8::ThrowException(exc);
1254 } else {
1255 i::Top::UnregisterTryCatchHandler(this);
1256 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001257}
1258
1259
1260bool v8::TryCatch::HasCaught() const {
1261 return !reinterpret_cast<i::Object*>(exception_)->IsTheHole();
1262}
1263
1264
1265bool v8::TryCatch::CanContinue() const {
1266 return can_continue_;
1267}
1268
1269
Steve Blockd0582a62009-12-15 09:54:21 +00001270v8::Handle<v8::Value> v8::TryCatch::ReThrow() {
1271 if (!HasCaught()) return v8::Local<v8::Value>();
1272 rethrow_ = true;
1273 return v8::Undefined();
1274}
1275
1276
Steve Blocka7e24c12009-10-30 11:49:00 +00001277v8::Local<Value> v8::TryCatch::Exception() const {
1278 if (HasCaught()) {
1279 // Check for out of memory exception.
1280 i::Object* exception = reinterpret_cast<i::Object*>(exception_);
1281 return v8::Utils::ToLocal(i::Handle<i::Object>(exception));
1282 } else {
1283 return v8::Local<Value>();
1284 }
1285}
1286
1287
1288v8::Local<Value> v8::TryCatch::StackTrace() const {
1289 if (HasCaught()) {
1290 i::Object* raw_obj = reinterpret_cast<i::Object*>(exception_);
1291 if (!raw_obj->IsJSObject()) return v8::Local<Value>();
1292 v8::HandleScope scope;
1293 i::Handle<i::JSObject> obj(i::JSObject::cast(raw_obj));
1294 i::Handle<i::String> name = i::Factory::LookupAsciiSymbol("stack");
1295 if (!obj->HasProperty(*name))
1296 return v8::Local<Value>();
1297 return scope.Close(v8::Utils::ToLocal(i::GetProperty(obj, name)));
1298 } else {
1299 return v8::Local<Value>();
1300 }
1301}
1302
1303
1304v8::Local<v8::Message> v8::TryCatch::Message() const {
1305 if (HasCaught() && message_ != i::Smi::FromInt(0)) {
1306 i::Object* message = reinterpret_cast<i::Object*>(message_);
1307 return v8::Utils::MessageToLocal(i::Handle<i::Object>(message));
1308 } else {
1309 return v8::Local<v8::Message>();
1310 }
1311}
1312
1313
1314void v8::TryCatch::Reset() {
1315 exception_ = i::Heap::the_hole_value();
1316 message_ = i::Smi::FromInt(0);
1317}
1318
1319
1320void v8::TryCatch::SetVerbose(bool value) {
1321 is_verbose_ = value;
1322}
1323
1324
1325void v8::TryCatch::SetCaptureMessage(bool value) {
1326 capture_message_ = value;
1327}
1328
1329
1330// --- M e s s a g e ---
1331
1332
1333Local<String> Message::Get() const {
1334 ON_BAILOUT("v8::Message::Get()", return Local<String>());
1335 ENTER_V8;
1336 HandleScope scope;
1337 i::Handle<i::Object> obj = Utils::OpenHandle(this);
1338 i::Handle<i::String> raw_result = i::MessageHandler::GetMessage(obj);
1339 Local<String> result = Utils::ToLocal(raw_result);
1340 return scope.Close(result);
1341}
1342
1343
1344v8::Handle<Value> Message::GetScriptResourceName() const {
1345 if (IsDeadCheck("v8::Message::GetScriptResourceName()")) {
1346 return Local<String>();
1347 }
1348 ENTER_V8;
1349 HandleScope scope;
1350 i::Handle<i::JSObject> obj =
1351 i::Handle<i::JSObject>::cast(Utils::OpenHandle(this));
1352 // Return this.script.name.
1353 i::Handle<i::JSValue> script =
1354 i::Handle<i::JSValue>::cast(GetProperty(obj, "script"));
1355 i::Handle<i::Object> resource_name(i::Script::cast(script->value())->name());
1356 return scope.Close(Utils::ToLocal(resource_name));
1357}
1358
1359
1360v8::Handle<Value> Message::GetScriptData() const {
1361 if (IsDeadCheck("v8::Message::GetScriptResourceData()")) {
1362 return Local<Value>();
1363 }
1364 ENTER_V8;
1365 HandleScope scope;
1366 i::Handle<i::JSObject> obj =
1367 i::Handle<i::JSObject>::cast(Utils::OpenHandle(this));
1368 // Return this.script.data.
1369 i::Handle<i::JSValue> script =
1370 i::Handle<i::JSValue>::cast(GetProperty(obj, "script"));
1371 i::Handle<i::Object> data(i::Script::cast(script->value())->data());
1372 return scope.Close(Utils::ToLocal(data));
1373}
1374
1375
1376static i::Handle<i::Object> CallV8HeapFunction(const char* name,
1377 i::Handle<i::Object> recv,
1378 int argc,
1379 i::Object** argv[],
1380 bool* has_pending_exception) {
1381 i::Handle<i::String> fmt_str = i::Factory::LookupAsciiSymbol(name);
1382 i::Object* object_fun = i::Top::builtins()->GetProperty(*fmt_str);
1383 i::Handle<i::JSFunction> fun =
1384 i::Handle<i::JSFunction>(i::JSFunction::cast(object_fun));
1385 i::Handle<i::Object> value =
1386 i::Execution::Call(fun, recv, argc, argv, has_pending_exception);
1387 return value;
1388}
1389
1390
1391static i::Handle<i::Object> CallV8HeapFunction(const char* name,
1392 i::Handle<i::Object> data,
1393 bool* has_pending_exception) {
1394 i::Object** argv[1] = { data.location() };
1395 return CallV8HeapFunction(name,
1396 i::Top::builtins(),
1397 1,
1398 argv,
1399 has_pending_exception);
1400}
1401
1402
1403int Message::GetLineNumber() const {
1404 ON_BAILOUT("v8::Message::GetLineNumber()", return -1);
1405 ENTER_V8;
1406 HandleScope scope;
1407 EXCEPTION_PREAMBLE();
1408 i::Handle<i::Object> result = CallV8HeapFunction("GetLineNumber",
1409 Utils::OpenHandle(this),
1410 &has_pending_exception);
1411 EXCEPTION_BAILOUT_CHECK(0);
1412 return static_cast<int>(result->Number());
1413}
1414
1415
1416int Message::GetStartPosition() const {
1417 if (IsDeadCheck("v8::Message::GetStartPosition()")) return 0;
1418 ENTER_V8;
1419 HandleScope scope;
1420
1421 i::Handle<i::JSObject> data_obj = Utils::OpenHandle(this);
1422 return static_cast<int>(GetProperty(data_obj, "startPos")->Number());
1423}
1424
1425
1426int Message::GetEndPosition() const {
1427 if (IsDeadCheck("v8::Message::GetEndPosition()")) return 0;
1428 ENTER_V8;
1429 HandleScope scope;
1430 i::Handle<i::JSObject> data_obj = Utils::OpenHandle(this);
1431 return static_cast<int>(GetProperty(data_obj, "endPos")->Number());
1432}
1433
1434
1435int Message::GetStartColumn() const {
1436 if (IsDeadCheck("v8::Message::GetStartColumn()")) return 0;
1437 ENTER_V8;
1438 HandleScope scope;
1439 i::Handle<i::JSObject> data_obj = Utils::OpenHandle(this);
1440 EXCEPTION_PREAMBLE();
1441 i::Handle<i::Object> start_col_obj = CallV8HeapFunction(
1442 "GetPositionInLine",
1443 data_obj,
1444 &has_pending_exception);
1445 EXCEPTION_BAILOUT_CHECK(0);
1446 return static_cast<int>(start_col_obj->Number());
1447}
1448
1449
1450int Message::GetEndColumn() const {
1451 if (IsDeadCheck("v8::Message::GetEndColumn()")) return 0;
1452 ENTER_V8;
1453 HandleScope scope;
1454 i::Handle<i::JSObject> data_obj = Utils::OpenHandle(this);
1455 EXCEPTION_PREAMBLE();
1456 i::Handle<i::Object> start_col_obj = CallV8HeapFunction(
1457 "GetPositionInLine",
1458 data_obj,
1459 &has_pending_exception);
1460 EXCEPTION_BAILOUT_CHECK(0);
1461 int start = static_cast<int>(GetProperty(data_obj, "startPos")->Number());
1462 int end = static_cast<int>(GetProperty(data_obj, "endPos")->Number());
1463 return static_cast<int>(start_col_obj->Number()) + (end - start);
1464}
1465
1466
1467Local<String> Message::GetSourceLine() const {
1468 ON_BAILOUT("v8::Message::GetSourceLine()", return Local<String>());
1469 ENTER_V8;
1470 HandleScope scope;
1471 EXCEPTION_PREAMBLE();
1472 i::Handle<i::Object> result = CallV8HeapFunction("GetSourceLine",
1473 Utils::OpenHandle(this),
1474 &has_pending_exception);
1475 EXCEPTION_BAILOUT_CHECK(Local<v8::String>());
1476 if (result->IsString()) {
1477 return scope.Close(Utils::ToLocal(i::Handle<i::String>::cast(result)));
1478 } else {
1479 return Local<String>();
1480 }
1481}
1482
1483
1484void Message::PrintCurrentStackTrace(FILE* out) {
1485 if (IsDeadCheck("v8::Message::PrintCurrentStackTrace()")) return;
1486 ENTER_V8;
1487 i::Top::PrintCurrentStackTrace(out);
1488}
1489
1490
1491// --- D a t a ---
1492
1493bool Value::IsUndefined() const {
1494 if (IsDeadCheck("v8::Value::IsUndefined()")) return false;
1495 return Utils::OpenHandle(this)->IsUndefined();
1496}
1497
1498
1499bool Value::IsNull() const {
1500 if (IsDeadCheck("v8::Value::IsNull()")) return false;
1501 return Utils::OpenHandle(this)->IsNull();
1502}
1503
1504
1505bool Value::IsTrue() const {
1506 if (IsDeadCheck("v8::Value::IsTrue()")) return false;
1507 return Utils::OpenHandle(this)->IsTrue();
1508}
1509
1510
1511bool Value::IsFalse() const {
1512 if (IsDeadCheck("v8::Value::IsFalse()")) return false;
1513 return Utils::OpenHandle(this)->IsFalse();
1514}
1515
1516
1517bool Value::IsFunction() const {
1518 if (IsDeadCheck("v8::Value::IsFunction()")) return false;
1519 return Utils::OpenHandle(this)->IsJSFunction();
1520}
1521
1522
1523bool Value::FullIsString() const {
1524 if (IsDeadCheck("v8::Value::IsString()")) return false;
1525 bool result = Utils::OpenHandle(this)->IsString();
1526 ASSERT_EQ(result, QuickIsString());
1527 return result;
1528}
1529
1530
1531bool Value::IsArray() const {
1532 if (IsDeadCheck("v8::Value::IsArray()")) return false;
1533 return Utils::OpenHandle(this)->IsJSArray();
1534}
1535
1536
1537bool Value::IsObject() const {
1538 if (IsDeadCheck("v8::Value::IsObject()")) return false;
1539 return Utils::OpenHandle(this)->IsJSObject();
1540}
1541
1542
1543bool Value::IsNumber() const {
1544 if (IsDeadCheck("v8::Value::IsNumber()")) return false;
1545 return Utils::OpenHandle(this)->IsNumber();
1546}
1547
1548
1549bool Value::IsBoolean() const {
1550 if (IsDeadCheck("v8::Value::IsBoolean()")) return false;
1551 return Utils::OpenHandle(this)->IsBoolean();
1552}
1553
1554
1555bool Value::IsExternal() const {
1556 if (IsDeadCheck("v8::Value::IsExternal()")) return false;
1557 return Utils::OpenHandle(this)->IsProxy();
1558}
1559
1560
1561bool Value::IsInt32() const {
1562 if (IsDeadCheck("v8::Value::IsInt32()")) return false;
1563 i::Handle<i::Object> obj = Utils::OpenHandle(this);
1564 if (obj->IsSmi()) return true;
1565 if (obj->IsNumber()) {
1566 double value = obj->Number();
1567 return i::FastI2D(i::FastD2I(value)) == value;
1568 }
1569 return false;
1570}
1571
1572
1573bool Value::IsDate() const {
1574 if (IsDeadCheck("v8::Value::IsDate()")) return false;
1575 i::Handle<i::Object> obj = Utils::OpenHandle(this);
1576 return obj->HasSpecificClassOf(i::Heap::Date_symbol());
1577}
1578
1579
1580Local<String> Value::ToString() const {
1581 if (IsDeadCheck("v8::Value::ToString()")) return Local<String>();
1582 LOG_API("ToString");
1583 i::Handle<i::Object> obj = Utils::OpenHandle(this);
1584 i::Handle<i::Object> str;
1585 if (obj->IsString()) {
1586 str = obj;
1587 } else {
1588 ENTER_V8;
1589 EXCEPTION_PREAMBLE();
1590 str = i::Execution::ToString(obj, &has_pending_exception);
1591 EXCEPTION_BAILOUT_CHECK(Local<String>());
1592 }
1593 return Local<String>(ToApi<String>(str));
1594}
1595
1596
1597Local<String> Value::ToDetailString() const {
1598 if (IsDeadCheck("v8::Value::ToDetailString()")) return Local<String>();
1599 LOG_API("ToDetailString");
1600 i::Handle<i::Object> obj = Utils::OpenHandle(this);
1601 i::Handle<i::Object> str;
1602 if (obj->IsString()) {
1603 str = obj;
1604 } else {
1605 ENTER_V8;
1606 EXCEPTION_PREAMBLE();
1607 str = i::Execution::ToDetailString(obj, &has_pending_exception);
1608 EXCEPTION_BAILOUT_CHECK(Local<String>());
1609 }
1610 return Local<String>(ToApi<String>(str));
1611}
1612
1613
1614Local<v8::Object> Value::ToObject() const {
1615 if (IsDeadCheck("v8::Value::ToObject()")) return Local<v8::Object>();
1616 LOG_API("ToObject");
1617 i::Handle<i::Object> obj = Utils::OpenHandle(this);
1618 i::Handle<i::Object> val;
1619 if (obj->IsJSObject()) {
1620 val = obj;
1621 } else {
1622 ENTER_V8;
1623 EXCEPTION_PREAMBLE();
1624 val = i::Execution::ToObject(obj, &has_pending_exception);
1625 EXCEPTION_BAILOUT_CHECK(Local<v8::Object>());
1626 }
1627 return Local<v8::Object>(ToApi<Object>(val));
1628}
1629
1630
1631Local<Boolean> Value::ToBoolean() const {
1632 if (IsDeadCheck("v8::Value::ToBoolean()")) return Local<Boolean>();
1633 LOG_API("ToBoolean");
1634 i::Handle<i::Object> obj = Utils::OpenHandle(this);
1635 if (obj->IsBoolean()) {
1636 return Local<Boolean>(ToApi<Boolean>(obj));
1637 } else {
1638 ENTER_V8;
1639 i::Handle<i::Object> val = i::Execution::ToBoolean(obj);
1640 return Local<Boolean>(ToApi<Boolean>(val));
1641 }
1642}
1643
1644
1645Local<Number> Value::ToNumber() const {
1646 if (IsDeadCheck("v8::Value::ToNumber()")) return Local<Number>();
1647 LOG_API("ToNumber");
1648 i::Handle<i::Object> obj = Utils::OpenHandle(this);
1649 i::Handle<i::Object> num;
1650 if (obj->IsNumber()) {
1651 num = obj;
1652 } else {
1653 ENTER_V8;
1654 EXCEPTION_PREAMBLE();
1655 num = i::Execution::ToNumber(obj, &has_pending_exception);
1656 EXCEPTION_BAILOUT_CHECK(Local<Number>());
1657 }
1658 return Local<Number>(ToApi<Number>(num));
1659}
1660
1661
1662Local<Integer> Value::ToInteger() const {
1663 if (IsDeadCheck("v8::Value::ToInteger()")) return Local<Integer>();
1664 LOG_API("ToInteger");
1665 i::Handle<i::Object> obj = Utils::OpenHandle(this);
1666 i::Handle<i::Object> num;
1667 if (obj->IsSmi()) {
1668 num = obj;
1669 } else {
1670 ENTER_V8;
1671 EXCEPTION_PREAMBLE();
1672 num = i::Execution::ToInteger(obj, &has_pending_exception);
1673 EXCEPTION_BAILOUT_CHECK(Local<Integer>());
1674 }
1675 return Local<Integer>(ToApi<Integer>(num));
1676}
1677
1678
1679void External::CheckCast(v8::Value* that) {
1680 if (IsDeadCheck("v8::External::Cast()")) return;
1681 i::Handle<i::Object> obj = Utils::OpenHandle(that);
1682 ApiCheck(obj->IsProxy(),
1683 "v8::External::Cast()",
1684 "Could not convert to external");
1685}
1686
1687
1688void v8::Object::CheckCast(Value* that) {
1689 if (IsDeadCheck("v8::Object::Cast()")) return;
1690 i::Handle<i::Object> obj = Utils::OpenHandle(that);
1691 ApiCheck(obj->IsJSObject(),
1692 "v8::Object::Cast()",
1693 "Could not convert to object");
1694}
1695
1696
1697void v8::Function::CheckCast(Value* that) {
1698 if (IsDeadCheck("v8::Function::Cast()")) return;
1699 i::Handle<i::Object> obj = Utils::OpenHandle(that);
1700 ApiCheck(obj->IsJSFunction(),
1701 "v8::Function::Cast()",
1702 "Could not convert to function");
1703}
1704
1705
1706void v8::String::CheckCast(v8::Value* that) {
1707 if (IsDeadCheck("v8::String::Cast()")) return;
1708 i::Handle<i::Object> obj = Utils::OpenHandle(that);
1709 ApiCheck(obj->IsString(),
1710 "v8::String::Cast()",
1711 "Could not convert to string");
1712}
1713
1714
1715void v8::Number::CheckCast(v8::Value* that) {
1716 if (IsDeadCheck("v8::Number::Cast()")) return;
1717 i::Handle<i::Object> obj = Utils::OpenHandle(that);
1718 ApiCheck(obj->IsNumber(),
1719 "v8::Number::Cast()",
1720 "Could not convert to number");
1721}
1722
1723
1724void v8::Integer::CheckCast(v8::Value* that) {
1725 if (IsDeadCheck("v8::Integer::Cast()")) return;
1726 i::Handle<i::Object> obj = Utils::OpenHandle(that);
1727 ApiCheck(obj->IsNumber(),
1728 "v8::Integer::Cast()",
1729 "Could not convert to number");
1730}
1731
1732
1733void v8::Array::CheckCast(Value* that) {
1734 if (IsDeadCheck("v8::Array::Cast()")) return;
1735 i::Handle<i::Object> obj = Utils::OpenHandle(that);
1736 ApiCheck(obj->IsJSArray(),
1737 "v8::Array::Cast()",
1738 "Could not convert to array");
1739}
1740
1741
1742void v8::Date::CheckCast(v8::Value* that) {
1743 if (IsDeadCheck("v8::Date::Cast()")) return;
1744 i::Handle<i::Object> obj = Utils::OpenHandle(that);
1745 ApiCheck(obj->HasSpecificClassOf(i::Heap::Date_symbol()),
1746 "v8::Date::Cast()",
1747 "Could not convert to date");
1748}
1749
1750
1751bool Value::BooleanValue() const {
1752 if (IsDeadCheck("v8::Value::BooleanValue()")) return false;
1753 LOG_API("BooleanValue");
1754 i::Handle<i::Object> obj = Utils::OpenHandle(this);
1755 if (obj->IsBoolean()) {
1756 return obj->IsTrue();
1757 } else {
1758 ENTER_V8;
1759 i::Handle<i::Object> value = i::Execution::ToBoolean(obj);
1760 return value->IsTrue();
1761 }
1762}
1763
1764
1765double Value::NumberValue() const {
1766 if (IsDeadCheck("v8::Value::NumberValue()")) return i::OS::nan_value();
1767 LOG_API("NumberValue");
1768 i::Handle<i::Object> obj = Utils::OpenHandle(this);
1769 i::Handle<i::Object> num;
1770 if (obj->IsNumber()) {
1771 num = obj;
1772 } else {
1773 ENTER_V8;
1774 EXCEPTION_PREAMBLE();
1775 num = i::Execution::ToNumber(obj, &has_pending_exception);
1776 EXCEPTION_BAILOUT_CHECK(i::OS::nan_value());
1777 }
1778 return num->Number();
1779}
1780
1781
1782int64_t Value::IntegerValue() const {
1783 if (IsDeadCheck("v8::Value::IntegerValue()")) return 0;
1784 LOG_API("IntegerValue");
1785 i::Handle<i::Object> obj = Utils::OpenHandle(this);
1786 i::Handle<i::Object> num;
1787 if (obj->IsNumber()) {
1788 num = obj;
1789 } else {
1790 ENTER_V8;
1791 EXCEPTION_PREAMBLE();
1792 num = i::Execution::ToInteger(obj, &has_pending_exception);
1793 EXCEPTION_BAILOUT_CHECK(0);
1794 }
1795 if (num->IsSmi()) {
1796 return i::Smi::cast(*num)->value();
1797 } else {
1798 return static_cast<int64_t>(num->Number());
1799 }
1800}
1801
1802
1803Local<Int32> Value::ToInt32() const {
1804 if (IsDeadCheck("v8::Value::ToInt32()")) return Local<Int32>();
1805 LOG_API("ToInt32");
1806 i::Handle<i::Object> obj = Utils::OpenHandle(this);
1807 i::Handle<i::Object> num;
1808 if (obj->IsSmi()) {
1809 num = obj;
1810 } else {
1811 ENTER_V8;
1812 EXCEPTION_PREAMBLE();
1813 num = i::Execution::ToInt32(obj, &has_pending_exception);
1814 EXCEPTION_BAILOUT_CHECK(Local<Int32>());
1815 }
1816 return Local<Int32>(ToApi<Int32>(num));
1817}
1818
1819
1820Local<Uint32> Value::ToUint32() const {
1821 if (IsDeadCheck("v8::Value::ToUint32()")) return Local<Uint32>();
1822 LOG_API("ToUInt32");
1823 i::Handle<i::Object> obj = Utils::OpenHandle(this);
1824 i::Handle<i::Object> num;
1825 if (obj->IsSmi()) {
1826 num = obj;
1827 } else {
1828 ENTER_V8;
1829 EXCEPTION_PREAMBLE();
1830 num = i::Execution::ToUint32(obj, &has_pending_exception);
1831 EXCEPTION_BAILOUT_CHECK(Local<Uint32>());
1832 }
1833 return Local<Uint32>(ToApi<Uint32>(num));
1834}
1835
1836
1837Local<Uint32> Value::ToArrayIndex() const {
1838 if (IsDeadCheck("v8::Value::ToArrayIndex()")) return Local<Uint32>();
1839 LOG_API("ToArrayIndex");
1840 i::Handle<i::Object> obj = Utils::OpenHandle(this);
1841 if (obj->IsSmi()) {
1842 if (i::Smi::cast(*obj)->value() >= 0) return Utils::Uint32ToLocal(obj);
1843 return Local<Uint32>();
1844 }
1845 ENTER_V8;
1846 EXCEPTION_PREAMBLE();
1847 i::Handle<i::Object> string_obj =
1848 i::Execution::ToString(obj, &has_pending_exception);
1849 EXCEPTION_BAILOUT_CHECK(Local<Uint32>());
1850 i::Handle<i::String> str = i::Handle<i::String>::cast(string_obj);
1851 uint32_t index;
1852 if (str->AsArrayIndex(&index)) {
1853 i::Handle<i::Object> value;
1854 if (index <= static_cast<uint32_t>(i::Smi::kMaxValue)) {
1855 value = i::Handle<i::Object>(i::Smi::FromInt(index));
1856 } else {
1857 value = i::Factory::NewNumber(index);
1858 }
1859 return Utils::Uint32ToLocal(value);
1860 }
1861 return Local<Uint32>();
1862}
1863
1864
1865int32_t Value::Int32Value() const {
1866 if (IsDeadCheck("v8::Value::Int32Value()")) return 0;
1867 LOG_API("Int32Value");
1868 i::Handle<i::Object> obj = Utils::OpenHandle(this);
1869 if (obj->IsSmi()) {
1870 return i::Smi::cast(*obj)->value();
1871 } else {
1872 LOG_API("Int32Value (slow)");
1873 ENTER_V8;
1874 EXCEPTION_PREAMBLE();
1875 i::Handle<i::Object> num =
1876 i::Execution::ToInt32(obj, &has_pending_exception);
1877 EXCEPTION_BAILOUT_CHECK(0);
1878 if (num->IsSmi()) {
1879 return i::Smi::cast(*num)->value();
1880 } else {
1881 return static_cast<int32_t>(num->Number());
1882 }
1883 }
1884}
1885
1886
1887bool Value::Equals(Handle<Value> that) const {
1888 if (IsDeadCheck("v8::Value::Equals()")
1889 || EmptyCheck("v8::Value::Equals()", this)
1890 || EmptyCheck("v8::Value::Equals()", that)) {
1891 return false;
1892 }
1893 LOG_API("Equals");
1894 ENTER_V8;
1895 i::Handle<i::Object> obj = Utils::OpenHandle(this);
1896 i::Handle<i::Object> other = Utils::OpenHandle(*that);
1897 i::Object** args[1] = { other.location() };
1898 EXCEPTION_PREAMBLE();
1899 i::Handle<i::Object> result =
1900 CallV8HeapFunction("EQUALS", obj, 1, args, &has_pending_exception);
1901 EXCEPTION_BAILOUT_CHECK(false);
1902 return *result == i::Smi::FromInt(i::EQUAL);
1903}
1904
1905
1906bool Value::StrictEquals(Handle<Value> that) const {
1907 if (IsDeadCheck("v8::Value::StrictEquals()")
1908 || EmptyCheck("v8::Value::StrictEquals()", this)
1909 || EmptyCheck("v8::Value::StrictEquals()", that)) {
1910 return false;
1911 }
1912 LOG_API("StrictEquals");
1913 i::Handle<i::Object> obj = Utils::OpenHandle(this);
1914 i::Handle<i::Object> other = Utils::OpenHandle(*that);
1915 // Must check HeapNumber first, since NaN !== NaN.
1916 if (obj->IsHeapNumber()) {
1917 if (!other->IsNumber()) return false;
1918 double x = obj->Number();
1919 double y = other->Number();
1920 // Must check explicitly for NaN:s on Windows, but -0 works fine.
1921 return x == y && !isnan(x) && !isnan(y);
1922 } else if (*obj == *other) { // Also covers Booleans.
1923 return true;
1924 } else if (obj->IsSmi()) {
1925 return other->IsNumber() && obj->Number() == other->Number();
1926 } else if (obj->IsString()) {
1927 return other->IsString() &&
1928 i::String::cast(*obj)->Equals(i::String::cast(*other));
1929 } else if (obj->IsUndefined() || obj->IsUndetectableObject()) {
1930 return other->IsUndefined() || other->IsUndetectableObject();
1931 } else {
1932 return false;
1933 }
1934}
1935
1936
1937uint32_t Value::Uint32Value() const {
1938 if (IsDeadCheck("v8::Value::Uint32Value()")) return 0;
1939 LOG_API("Uint32Value");
1940 i::Handle<i::Object> obj = Utils::OpenHandle(this);
1941 if (obj->IsSmi()) {
1942 return i::Smi::cast(*obj)->value();
1943 } else {
1944 ENTER_V8;
1945 EXCEPTION_PREAMBLE();
1946 i::Handle<i::Object> num =
1947 i::Execution::ToUint32(obj, &has_pending_exception);
1948 EXCEPTION_BAILOUT_CHECK(0);
1949 if (num->IsSmi()) {
1950 return i::Smi::cast(*num)->value();
1951 } else {
1952 return static_cast<uint32_t>(num->Number());
1953 }
1954 }
1955}
1956
1957
1958bool v8::Object::Set(v8::Handle<Value> key, v8::Handle<Value> value,
1959 v8::PropertyAttribute attribs) {
1960 ON_BAILOUT("v8::Object::Set()", return false);
1961 ENTER_V8;
1962 HandleScope scope;
1963 i::Handle<i::Object> self = Utils::OpenHandle(this);
1964 i::Handle<i::Object> key_obj = Utils::OpenHandle(*key);
1965 i::Handle<i::Object> value_obj = Utils::OpenHandle(*value);
1966 EXCEPTION_PREAMBLE();
1967 i::Handle<i::Object> obj = i::SetProperty(
1968 self,
1969 key_obj,
1970 value_obj,
1971 static_cast<PropertyAttributes>(attribs));
1972 has_pending_exception = obj.is_null();
1973 EXCEPTION_BAILOUT_CHECK(false);
1974 return true;
1975}
1976
1977
1978bool v8::Object::ForceSet(v8::Handle<Value> key,
1979 v8::Handle<Value> value,
1980 v8::PropertyAttribute attribs) {
1981 ON_BAILOUT("v8::Object::ForceSet()", return false);
1982 ENTER_V8;
1983 HandleScope scope;
1984 i::Handle<i::JSObject> self = Utils::OpenHandle(this);
1985 i::Handle<i::Object> key_obj = Utils::OpenHandle(*key);
1986 i::Handle<i::Object> value_obj = Utils::OpenHandle(*value);
1987 EXCEPTION_PREAMBLE();
1988 i::Handle<i::Object> obj = i::ForceSetProperty(
1989 self,
1990 key_obj,
1991 value_obj,
1992 static_cast<PropertyAttributes>(attribs));
1993 has_pending_exception = obj.is_null();
1994 EXCEPTION_BAILOUT_CHECK(false);
1995 return true;
1996}
1997
1998
1999bool v8::Object::ForceDelete(v8::Handle<Value> key) {
2000 ON_BAILOUT("v8::Object::ForceDelete()", return false);
2001 ENTER_V8;
2002 HandleScope scope;
2003 i::Handle<i::JSObject> self = Utils::OpenHandle(this);
2004 i::Handle<i::Object> key_obj = Utils::OpenHandle(*key);
2005 EXCEPTION_PREAMBLE();
2006 i::Handle<i::Object> obj = i::ForceDeleteProperty(self, key_obj);
2007 has_pending_exception = obj.is_null();
2008 EXCEPTION_BAILOUT_CHECK(false);
2009 return obj->IsTrue();
2010}
2011
2012
2013Local<Value> v8::Object::Get(v8::Handle<Value> key) {
2014 ON_BAILOUT("v8::Object::Get()", return Local<v8::Value>());
2015 ENTER_V8;
2016 i::Handle<i::Object> self = Utils::OpenHandle(this);
2017 i::Handle<i::Object> key_obj = Utils::OpenHandle(*key);
2018 EXCEPTION_PREAMBLE();
2019 i::Handle<i::Object> result = i::GetProperty(self, key_obj);
2020 has_pending_exception = result.is_null();
2021 EXCEPTION_BAILOUT_CHECK(Local<Value>());
2022 return Utils::ToLocal(result);
2023}
2024
2025
2026Local<Value> v8::Object::GetPrototype() {
2027 ON_BAILOUT("v8::Object::GetPrototype()", return Local<v8::Value>());
2028 ENTER_V8;
2029 i::Handle<i::Object> self = Utils::OpenHandle(this);
2030 i::Handle<i::Object> result = i::GetPrototype(self);
2031 return Utils::ToLocal(result);
2032}
2033
2034
2035Local<Object> v8::Object::FindInstanceInPrototypeChain(
2036 v8::Handle<FunctionTemplate> tmpl) {
2037 ON_BAILOUT("v8::Object::FindInstanceInPrototypeChain()",
2038 return Local<v8::Object>());
2039 ENTER_V8;
2040 i::JSObject* object = *Utils::OpenHandle(this);
2041 i::FunctionTemplateInfo* tmpl_info = *Utils::OpenHandle(*tmpl);
2042 while (!object->IsInstanceOf(tmpl_info)) {
2043 i::Object* prototype = object->GetPrototype();
2044 if (!prototype->IsJSObject()) return Local<Object>();
2045 object = i::JSObject::cast(prototype);
2046 }
2047 return Utils::ToLocal(i::Handle<i::JSObject>(object));
2048}
2049
2050
2051Local<Array> v8::Object::GetPropertyNames() {
2052 ON_BAILOUT("v8::Object::GetPropertyNames()", return Local<v8::Array>());
2053 ENTER_V8;
2054 v8::HandleScope scope;
2055 i::Handle<i::JSObject> self = Utils::OpenHandle(this);
2056 i::Handle<i::FixedArray> value =
2057 i::GetKeysInFixedArrayFor(self, i::INCLUDE_PROTOS);
2058 // Because we use caching to speed up enumeration it is important
2059 // to never change the result of the basic enumeration function so
2060 // we clone the result.
2061 i::Handle<i::FixedArray> elms = i::Factory::CopyFixedArray(value);
2062 i::Handle<i::JSArray> result = i::Factory::NewJSArrayWithElements(elms);
2063 return scope.Close(Utils::ToLocal(result));
2064}
2065
2066
2067Local<String> v8::Object::ObjectProtoToString() {
2068 ON_BAILOUT("v8::Object::ObjectProtoToString()", return Local<v8::String>());
2069 ENTER_V8;
2070 i::Handle<i::JSObject> self = Utils::OpenHandle(this);
2071
2072 i::Handle<i::Object> name(self->class_name());
2073
2074 // Native implementation of Object.prototype.toString (v8natives.js):
2075 // var c = %ClassOf(this);
2076 // if (c === 'Arguments') c = 'Object';
2077 // return "[object " + c + "]";
2078
2079 if (!name->IsString()) {
2080 return v8::String::New("[object ]");
2081
2082 } else {
2083 i::Handle<i::String> class_name = i::Handle<i::String>::cast(name);
2084 if (class_name->IsEqualTo(i::CStrVector("Arguments"))) {
2085 return v8::String::New("[object Object]");
2086
2087 } else {
2088 const char* prefix = "[object ";
2089 Local<String> str = Utils::ToLocal(class_name);
2090 const char* postfix = "]";
2091
Steve Blockd0582a62009-12-15 09:54:21 +00002092 int prefix_len = i::StrLength(prefix);
2093 int str_len = str->Length();
2094 int postfix_len = i::StrLength(postfix);
Steve Blocka7e24c12009-10-30 11:49:00 +00002095
Steve Blockd0582a62009-12-15 09:54:21 +00002096 int buf_len = prefix_len + str_len + postfix_len;
Steve Blocka7e24c12009-10-30 11:49:00 +00002097 char* buf = i::NewArray<char>(buf_len);
2098
2099 // Write prefix.
2100 char* ptr = buf;
2101 memcpy(ptr, prefix, prefix_len * v8::internal::kCharSize);
2102 ptr += prefix_len;
2103
2104 // Write real content.
2105 str->WriteAscii(ptr, 0, str_len);
2106 ptr += str_len;
2107
2108 // Write postfix.
2109 memcpy(ptr, postfix, postfix_len * v8::internal::kCharSize);
2110
2111 // Copy the buffer into a heap-allocated string and return it.
2112 Local<String> result = v8::String::New(buf, buf_len);
2113 i::DeleteArray(buf);
2114 return result;
2115 }
2116 }
2117}
2118
2119
2120bool v8::Object::Delete(v8::Handle<String> key) {
2121 ON_BAILOUT("v8::Object::Delete()", return false);
2122 ENTER_V8;
2123 HandleScope scope;
2124 i::Handle<i::JSObject> self = Utils::OpenHandle(this);
2125 i::Handle<i::String> key_obj = Utils::OpenHandle(*key);
2126 return i::DeleteProperty(self, key_obj)->IsTrue();
2127}
2128
2129
2130bool v8::Object::Has(v8::Handle<String> key) {
2131 ON_BAILOUT("v8::Object::Has()", return false);
2132 ENTER_V8;
2133 i::Handle<i::JSObject> self = Utils::OpenHandle(this);
2134 i::Handle<i::String> key_obj = Utils::OpenHandle(*key);
2135 return self->HasProperty(*key_obj);
2136}
2137
2138
2139bool v8::Object::Delete(uint32_t index) {
2140 ON_BAILOUT("v8::Object::DeleteProperty()", return false);
2141 ENTER_V8;
2142 HandleScope scope;
2143 i::Handle<i::JSObject> self = Utils::OpenHandle(this);
2144 return i::DeleteElement(self, index)->IsTrue();
2145}
2146
2147
2148bool v8::Object::Has(uint32_t index) {
2149 ON_BAILOUT("v8::Object::HasProperty()", return false);
2150 i::Handle<i::JSObject> self = Utils::OpenHandle(this);
2151 return self->HasElement(index);
2152}
2153
2154
2155bool v8::Object::HasRealNamedProperty(Handle<String> key) {
2156 ON_BAILOUT("v8::Object::HasRealNamedProperty()", return false);
2157 return Utils::OpenHandle(this)->HasRealNamedProperty(
2158 *Utils::OpenHandle(*key));
2159}
2160
2161
2162bool v8::Object::HasRealIndexedProperty(uint32_t index) {
2163 ON_BAILOUT("v8::Object::HasRealIndexedProperty()", return false);
2164 return Utils::OpenHandle(this)->HasRealElementProperty(index);
2165}
2166
2167
2168bool v8::Object::HasRealNamedCallbackProperty(Handle<String> key) {
2169 ON_BAILOUT("v8::Object::HasRealNamedCallbackProperty()", return false);
2170 ENTER_V8;
2171 return Utils::OpenHandle(this)->HasRealNamedCallbackProperty(
2172 *Utils::OpenHandle(*key));
2173}
2174
2175
2176bool v8::Object::HasNamedLookupInterceptor() {
2177 ON_BAILOUT("v8::Object::HasNamedLookupInterceptor()", return false);
2178 return Utils::OpenHandle(this)->HasNamedInterceptor();
2179}
2180
2181
2182bool v8::Object::HasIndexedLookupInterceptor() {
2183 ON_BAILOUT("v8::Object::HasIndexedLookupInterceptor()", return false);
2184 return Utils::OpenHandle(this)->HasIndexedInterceptor();
2185}
2186
2187
2188Local<Value> v8::Object::GetRealNamedPropertyInPrototypeChain(
2189 Handle<String> key) {
2190 ON_BAILOUT("v8::Object::GetRealNamedPropertyInPrototypeChain()",
2191 return Local<Value>());
2192 ENTER_V8;
2193 i::Handle<i::JSObject> self_obj = Utils::OpenHandle(this);
2194 i::Handle<i::String> key_obj = Utils::OpenHandle(*key);
2195 i::LookupResult lookup;
2196 self_obj->LookupRealNamedPropertyInPrototypes(*key_obj, &lookup);
2197 if (lookup.IsValid()) {
2198 PropertyAttributes attributes;
2199 i::Handle<i::Object> result(self_obj->GetProperty(*self_obj,
2200 &lookup,
2201 *key_obj,
2202 &attributes));
2203 return Utils::ToLocal(result);
2204 }
2205 return Local<Value>(); // No real property was found in prototype chain.
2206}
2207
2208
2209Local<Value> v8::Object::GetRealNamedProperty(Handle<String> key) {
2210 ON_BAILOUT("v8::Object::GetRealNamedProperty()", return Local<Value>());
2211 ENTER_V8;
2212 i::Handle<i::JSObject> self_obj = Utils::OpenHandle(this);
2213 i::Handle<i::String> key_obj = Utils::OpenHandle(*key);
2214 i::LookupResult lookup;
2215 self_obj->LookupRealNamedProperty(*key_obj, &lookup);
2216 if (lookup.IsValid()) {
2217 PropertyAttributes attributes;
2218 i::Handle<i::Object> result(self_obj->GetProperty(*self_obj,
2219 &lookup,
2220 *key_obj,
2221 &attributes));
2222 return Utils::ToLocal(result);
2223 }
2224 return Local<Value>(); // No real property was found in prototype chain.
2225}
2226
2227
2228// Turns on access checks by copying the map and setting the check flag.
2229// Because the object gets a new map, existing inline cache caching
2230// the old map of this object will fail.
2231void v8::Object::TurnOnAccessCheck() {
2232 ON_BAILOUT("v8::Object::TurnOnAccessCheck()", return);
2233 ENTER_V8;
2234 HandleScope scope;
2235 i::Handle<i::JSObject> obj = Utils::OpenHandle(this);
2236
2237 i::Handle<i::Map> new_map =
2238 i::Factory::CopyMapDropTransitions(i::Handle<i::Map>(obj->map()));
2239 new_map->set_is_access_check_needed(true);
2240 obj->set_map(*new_map);
2241}
2242
2243
2244bool v8::Object::IsDirty() {
2245 return Utils::OpenHandle(this)->IsDirty();
2246}
2247
2248
2249Local<v8::Object> v8::Object::Clone() {
2250 ON_BAILOUT("v8::Object::Clone()", return Local<Object>());
2251 ENTER_V8;
2252 i::Handle<i::JSObject> self = Utils::OpenHandle(this);
2253 EXCEPTION_PREAMBLE();
2254 i::Handle<i::JSObject> result = i::Copy(self);
2255 has_pending_exception = result.is_null();
2256 EXCEPTION_BAILOUT_CHECK(Local<Object>());
2257 return Utils::ToLocal(result);
2258}
2259
2260
2261int v8::Object::GetIdentityHash() {
2262 ON_BAILOUT("v8::Object::GetIdentityHash()", return 0);
2263 ENTER_V8;
2264 HandleScope scope;
2265 i::Handle<i::JSObject> self = Utils::OpenHandle(this);
2266 i::Handle<i::Object> hidden_props(i::GetHiddenProperties(self, true));
2267 i::Handle<i::Object> hash_symbol = i::Factory::identity_hash_symbol();
2268 i::Handle<i::Object> hash = i::GetProperty(hidden_props, hash_symbol);
2269 int hash_value;
2270 if (hash->IsSmi()) {
2271 hash_value = i::Smi::cast(*hash)->value();
2272 } else {
2273 int attempts = 0;
2274 do {
2275 // Generate a random 32-bit hash value but limit range to fit
2276 // within a smi.
2277 hash_value = i::V8::Random() & i::Smi::kMaxValue;
2278 attempts++;
2279 } while (hash_value == 0 && attempts < 30);
2280 hash_value = hash_value != 0 ? hash_value : 1; // never return 0
2281 i::SetProperty(hidden_props,
2282 hash_symbol,
2283 i::Handle<i::Object>(i::Smi::FromInt(hash_value)),
2284 static_cast<PropertyAttributes>(None));
2285 }
2286 return hash_value;
2287}
2288
2289
2290bool v8::Object::SetHiddenValue(v8::Handle<v8::String> key,
2291 v8::Handle<v8::Value> value) {
2292 ON_BAILOUT("v8::Object::SetHiddenValue()", return false);
2293 ENTER_V8;
2294 HandleScope scope;
2295 i::Handle<i::JSObject> self = Utils::OpenHandle(this);
2296 i::Handle<i::Object> hidden_props(i::GetHiddenProperties(self, true));
2297 i::Handle<i::Object> key_obj = Utils::OpenHandle(*key);
2298 i::Handle<i::Object> value_obj = Utils::OpenHandle(*value);
2299 EXCEPTION_PREAMBLE();
2300 i::Handle<i::Object> obj = i::SetProperty(
2301 hidden_props,
2302 key_obj,
2303 value_obj,
2304 static_cast<PropertyAttributes>(None));
2305 has_pending_exception = obj.is_null();
2306 EXCEPTION_BAILOUT_CHECK(false);
2307 return true;
2308}
2309
2310
2311v8::Local<v8::Value> v8::Object::GetHiddenValue(v8::Handle<v8::String> key) {
2312 ON_BAILOUT("v8::Object::GetHiddenValue()", return Local<v8::Value>());
2313 ENTER_V8;
2314 i::Handle<i::JSObject> self = Utils::OpenHandle(this);
2315 i::Handle<i::Object> hidden_props(i::GetHiddenProperties(self, false));
2316 if (hidden_props->IsUndefined()) {
2317 return v8::Local<v8::Value>();
2318 }
2319 i::Handle<i::String> key_obj = Utils::OpenHandle(*key);
2320 EXCEPTION_PREAMBLE();
2321 i::Handle<i::Object> result = i::GetProperty(hidden_props, key_obj);
2322 has_pending_exception = result.is_null();
2323 EXCEPTION_BAILOUT_CHECK(v8::Local<v8::Value>());
2324 if (result->IsUndefined()) {
2325 return v8::Local<v8::Value>();
2326 }
2327 return Utils::ToLocal(result);
2328}
2329
2330
2331bool v8::Object::DeleteHiddenValue(v8::Handle<v8::String> key) {
2332 ON_BAILOUT("v8::DeleteHiddenValue()", return false);
2333 ENTER_V8;
2334 HandleScope scope;
2335 i::Handle<i::JSObject> self = Utils::OpenHandle(this);
2336 i::Handle<i::Object> hidden_props(i::GetHiddenProperties(self, false));
2337 if (hidden_props->IsUndefined()) {
2338 return true;
2339 }
2340 i::Handle<i::JSObject> js_obj(i::JSObject::cast(*hidden_props));
2341 i::Handle<i::String> key_obj = Utils::OpenHandle(*key);
2342 return i::DeleteProperty(js_obj, key_obj)->IsTrue();
2343}
2344
2345
2346void v8::Object::SetIndexedPropertiesToPixelData(uint8_t* data, int length) {
2347 ON_BAILOUT("v8::SetElementsToPixelData()", return);
2348 ENTER_V8;
2349 HandleScope scope;
Steve Block3ce2e202009-11-05 08:53:23 +00002350 if (!ApiCheck(length <= i::PixelArray::kMaxLength,
Steve Blocka7e24c12009-10-30 11:49:00 +00002351 "v8::Object::SetIndexedPropertiesToPixelData()",
2352 "length exceeds max acceptable value")) {
2353 return;
2354 }
2355 i::Handle<i::JSObject> self = Utils::OpenHandle(this);
2356 if (!ApiCheck(!self->IsJSArray(),
2357 "v8::Object::SetIndexedPropertiesToPixelData()",
2358 "JSArray is not supported")) {
2359 return;
2360 }
2361 i::Handle<i::PixelArray> pixels = i::Factory::NewPixelArray(length, data);
2362 self->set_elements(*pixels);
2363}
2364
2365
Steve Block3ce2e202009-11-05 08:53:23 +00002366void v8::Object::SetIndexedPropertiesToExternalArrayData(
2367 void* data,
2368 ExternalArrayType array_type,
2369 int length) {
2370 ON_BAILOUT("v8::SetIndexedPropertiesToExternalArrayData()", return);
2371 ENTER_V8;
2372 HandleScope scope;
2373 if (!ApiCheck(length <= i::ExternalArray::kMaxLength,
2374 "v8::Object::SetIndexedPropertiesToExternalArrayData()",
2375 "length exceeds max acceptable value")) {
2376 return;
2377 }
2378 i::Handle<i::JSObject> self = Utils::OpenHandle(this);
2379 if (!ApiCheck(!self->IsJSArray(),
2380 "v8::Object::SetIndexedPropertiesToExternalArrayData()",
2381 "JSArray is not supported")) {
2382 return;
2383 }
2384 i::Handle<i::ExternalArray> array =
2385 i::Factory::NewExternalArray(length, array_type, data);
2386 self->set_elements(*array);
2387}
2388
2389
Steve Blocka7e24c12009-10-30 11:49:00 +00002390Local<v8::Object> Function::NewInstance() const {
2391 return NewInstance(0, NULL);
2392}
2393
2394
2395Local<v8::Object> Function::NewInstance(int argc,
2396 v8::Handle<v8::Value> argv[]) const {
2397 ON_BAILOUT("v8::Function::NewInstance()", return Local<v8::Object>());
2398 LOG_API("Function::NewInstance");
2399 ENTER_V8;
2400 HandleScope scope;
2401 i::Handle<i::JSFunction> function = Utils::OpenHandle(this);
2402 STATIC_ASSERT(sizeof(v8::Handle<v8::Value>) == sizeof(i::Object**));
2403 i::Object*** args = reinterpret_cast<i::Object***>(argv);
2404 EXCEPTION_PREAMBLE();
2405 i::Handle<i::Object> returned =
2406 i::Execution::New(function, argc, args, &has_pending_exception);
2407 EXCEPTION_BAILOUT_CHECK(Local<v8::Object>());
2408 return scope.Close(Utils::ToLocal(i::Handle<i::JSObject>::cast(returned)));
2409}
2410
2411
2412Local<v8::Value> Function::Call(v8::Handle<v8::Object> recv, int argc,
2413 v8::Handle<v8::Value> argv[]) {
2414 ON_BAILOUT("v8::Function::Call()", return Local<v8::Value>());
2415 LOG_API("Function::Call");
2416 ENTER_V8;
2417 i::Object* raw_result = NULL;
2418 {
2419 HandleScope scope;
2420 i::Handle<i::JSFunction> fun = Utils::OpenHandle(this);
2421 i::Handle<i::Object> recv_obj = Utils::OpenHandle(*recv);
2422 STATIC_ASSERT(sizeof(v8::Handle<v8::Value>) == sizeof(i::Object**));
2423 i::Object*** args = reinterpret_cast<i::Object***>(argv);
2424 EXCEPTION_PREAMBLE();
2425 i::Handle<i::Object> returned =
2426 i::Execution::Call(fun, recv_obj, argc, args, &has_pending_exception);
2427 EXCEPTION_BAILOUT_CHECK(Local<Object>());
2428 raw_result = *returned;
2429 }
2430 i::Handle<i::Object> result(raw_result);
2431 return Utils::ToLocal(result);
2432}
2433
2434
2435void Function::SetName(v8::Handle<v8::String> name) {
2436 ENTER_V8;
2437 i::Handle<i::JSFunction> func = Utils::OpenHandle(this);
2438 func->shared()->set_name(*Utils::OpenHandle(*name));
2439}
2440
2441
2442Handle<Value> Function::GetName() const {
2443 i::Handle<i::JSFunction> func = Utils::OpenHandle(this);
2444 return Utils::ToLocal(i::Handle<i::Object>(func->shared()->name()));
2445}
2446
2447
2448int String::Length() const {
2449 if (IsDeadCheck("v8::String::Length()")) return 0;
2450 return Utils::OpenHandle(this)->length();
2451}
2452
2453
2454int String::Utf8Length() const {
2455 if (IsDeadCheck("v8::String::Utf8Length()")) return 0;
2456 return Utils::OpenHandle(this)->Utf8Length();
2457}
2458
2459
2460int String::WriteUtf8(char* buffer, int capacity) const {
2461 if (IsDeadCheck("v8::String::WriteUtf8()")) return 0;
2462 LOG_API("String::WriteUtf8");
2463 ENTER_V8;
2464 i::Handle<i::String> str = Utils::OpenHandle(this);
2465 write_input_buffer.Reset(0, *str);
2466 int len = str->length();
2467 // Encode the first K - 3 bytes directly into the buffer since we
2468 // know there's room for them. If no capacity is given we copy all
2469 // of them here.
2470 int fast_end = capacity - (unibrow::Utf8::kMaxEncodedSize - 1);
2471 int i;
2472 int pos = 0;
2473 for (i = 0; i < len && (capacity == -1 || pos < fast_end); i++) {
2474 i::uc32 c = write_input_buffer.GetNext();
2475 int written = unibrow::Utf8::Encode(buffer + pos, c);
2476 pos += written;
2477 }
2478 if (i < len) {
2479 // For the last characters we need to check the length for each one
2480 // because they may be longer than the remaining space in the
2481 // buffer.
2482 char intermediate[unibrow::Utf8::kMaxEncodedSize];
2483 for (; i < len && pos < capacity; i++) {
2484 i::uc32 c = write_input_buffer.GetNext();
2485 int written = unibrow::Utf8::Encode(intermediate, c);
2486 if (pos + written <= capacity) {
2487 for (int j = 0; j < written; j++)
2488 buffer[pos + j] = intermediate[j];
2489 pos += written;
2490 } else {
2491 // We've reached the end of the buffer
2492 break;
2493 }
2494 }
2495 }
2496 if (i == len && (capacity == -1 || pos < capacity))
2497 buffer[pos++] = '\0';
2498 return pos;
2499}
2500
2501
2502int String::WriteAscii(char* buffer, int start, int length) const {
2503 if (IsDeadCheck("v8::String::WriteAscii()")) return 0;
2504 LOG_API("String::WriteAscii");
2505 ENTER_V8;
2506 ASSERT(start >= 0 && length >= -1);
2507 i::Handle<i::String> str = Utils::OpenHandle(this);
2508 // Flatten the string for efficiency. This applies whether we are
2509 // using StringInputBuffer or Get(i) to access the characters.
2510 str->TryFlattenIfNotFlat();
2511 int end = length;
2512 if ( (length == -1) || (length > str->length() - start) )
2513 end = str->length() - start;
2514 if (end < 0) return 0;
2515 write_input_buffer.Reset(start, *str);
2516 int i;
2517 for (i = 0; i < end; i++) {
2518 char c = static_cast<char>(write_input_buffer.GetNext());
2519 if (c == '\0') c = ' ';
2520 buffer[i] = c;
2521 }
2522 if (length == -1 || i < length)
2523 buffer[i] = '\0';
2524 return i;
2525}
2526
2527
2528int String::Write(uint16_t* buffer, int start, int length) const {
2529 if (IsDeadCheck("v8::String::Write()")) return 0;
2530 LOG_API("String::Write");
2531 ENTER_V8;
2532 ASSERT(start >= 0 && length >= -1);
2533 i::Handle<i::String> str = Utils::OpenHandle(this);
2534 int end = length;
2535 if ( (length == -1) || (length > str->length() - start) )
2536 end = str->length() - start;
2537 if (end < 0) return 0;
2538 i::String::WriteToFlat(*str, buffer, start, end);
2539 if (length == -1 || end < length)
2540 buffer[end] = '\0';
2541 return end;
2542}
2543
2544
2545bool v8::String::IsExternal() const {
2546 EnsureInitialized("v8::String::IsExternal()");
2547 i::Handle<i::String> str = Utils::OpenHandle(this);
2548 return i::StringShape(*str).IsExternalTwoByte();
2549}
2550
2551
2552bool v8::String::IsExternalAscii() const {
2553 EnsureInitialized("v8::String::IsExternalAscii()");
2554 i::Handle<i::String> str = Utils::OpenHandle(this);
2555 return i::StringShape(*str).IsExternalAscii();
2556}
2557
2558
2559void v8::String::VerifyExternalStringResource(
2560 v8::String::ExternalStringResource* value) const {
2561 i::Handle<i::String> str = Utils::OpenHandle(this);
2562 v8::String::ExternalStringResource* expected;
2563 if (i::StringShape(*str).IsExternalTwoByte()) {
2564 void* resource = i::Handle<i::ExternalTwoByteString>::cast(str)->resource();
2565 expected = reinterpret_cast<ExternalStringResource*>(resource);
2566 } else {
2567 expected = NULL;
2568 }
2569 CHECK_EQ(expected, value);
2570}
2571
2572
2573v8::String::ExternalAsciiStringResource*
2574 v8::String::GetExternalAsciiStringResource() const {
2575 EnsureInitialized("v8::String::GetExternalAsciiStringResource()");
2576 i::Handle<i::String> str = Utils::OpenHandle(this);
2577 if (i::StringShape(*str).IsExternalAscii()) {
2578 void* resource = i::Handle<i::ExternalAsciiString>::cast(str)->resource();
2579 return reinterpret_cast<ExternalAsciiStringResource*>(resource);
2580 } else {
2581 return NULL;
2582 }
2583}
2584
2585
2586double Number::Value() const {
2587 if (IsDeadCheck("v8::Number::Value()")) return 0;
2588 i::Handle<i::Object> obj = Utils::OpenHandle(this);
2589 return obj->Number();
2590}
2591
2592
2593bool Boolean::Value() const {
2594 if (IsDeadCheck("v8::Boolean::Value()")) return false;
2595 i::Handle<i::Object> obj = Utils::OpenHandle(this);
2596 return obj->IsTrue();
2597}
2598
2599
2600int64_t Integer::Value() const {
2601 if (IsDeadCheck("v8::Integer::Value()")) return 0;
2602 i::Handle<i::Object> obj = Utils::OpenHandle(this);
2603 if (obj->IsSmi()) {
2604 return i::Smi::cast(*obj)->value();
2605 } else {
2606 return static_cast<int64_t>(obj->Number());
2607 }
2608}
2609
2610
2611int32_t Int32::Value() const {
2612 if (IsDeadCheck("v8::Int32::Value()")) return 0;
2613 i::Handle<i::Object> obj = Utils::OpenHandle(this);
2614 if (obj->IsSmi()) {
2615 return i::Smi::cast(*obj)->value();
2616 } else {
2617 return static_cast<int32_t>(obj->Number());
2618 }
2619}
2620
2621
2622int v8::Object::InternalFieldCount() {
2623 if (IsDeadCheck("v8::Object::InternalFieldCount()")) return 0;
2624 i::Handle<i::JSObject> obj = Utils::OpenHandle(this);
2625 return obj->GetInternalFieldCount();
2626}
2627
2628
2629Local<Value> v8::Object::CheckedGetInternalField(int index) {
2630 if (IsDeadCheck("v8::Object::GetInternalField()")) return Local<Value>();
2631 i::Handle<i::JSObject> obj = Utils::OpenHandle(this);
2632 if (!ApiCheck(index < obj->GetInternalFieldCount(),
2633 "v8::Object::GetInternalField()",
2634 "Reading internal field out of bounds")) {
2635 return Local<Value>();
2636 }
2637 i::Handle<i::Object> value(obj->GetInternalField(index));
2638 Local<Value> result = Utils::ToLocal(value);
2639#ifdef DEBUG
2640 Local<Value> unchecked = UncheckedGetInternalField(index);
2641 ASSERT(unchecked.IsEmpty() || (unchecked == result));
2642#endif
2643 return result;
2644}
2645
2646
2647void v8::Object::SetInternalField(int index, v8::Handle<Value> value) {
2648 if (IsDeadCheck("v8::Object::SetInternalField()")) return;
2649 i::Handle<i::JSObject> obj = Utils::OpenHandle(this);
2650 if (!ApiCheck(index < obj->GetInternalFieldCount(),
2651 "v8::Object::SetInternalField()",
2652 "Writing internal field out of bounds")) {
2653 return;
2654 }
2655 ENTER_V8;
2656 i::Handle<i::Object> val = Utils::OpenHandle(*value);
2657 obj->SetInternalField(index, *val);
2658}
2659
2660
2661void v8::Object::SetPointerInInternalField(int index, void* value) {
Steve Block3ce2e202009-11-05 08:53:23 +00002662 i::Object* as_object = reinterpret_cast<i::Object*>(value);
2663 if (as_object->IsSmi()) {
2664 Utils::OpenHandle(this)->SetInternalField(index, as_object);
2665 return;
2666 }
2667 HandleScope scope;
2668 i::Handle<i::Proxy> proxy =
2669 i::Factory::NewProxy(reinterpret_cast<i::Address>(value), i::TENURED);
2670 if (!proxy.is_null())
2671 Utils::OpenHandle(this)->SetInternalField(index, *proxy);
Steve Blocka7e24c12009-10-30 11:49:00 +00002672}
2673
2674
2675// --- E n v i r o n m e n t ---
2676
2677bool v8::V8::Initialize() {
2678 if (i::V8::IsRunning()) return true;
2679 ENTER_V8;
2680 HandleScope scope;
Steve Blockd0582a62009-12-15 09:54:21 +00002681 if (i::Snapshot::Initialize()) return true;
2682 return i::V8::Initialize(NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +00002683}
2684
2685
2686bool v8::V8::Dispose() {
2687 i::V8::TearDown();
2688 return true;
2689}
2690
2691
Steve Block3ce2e202009-11-05 08:53:23 +00002692HeapStatistics::HeapStatistics(): total_heap_size_(0), used_heap_size_(0) { }
2693
2694
2695void v8::V8::GetHeapStatistics(HeapStatistics* heap_statistics) {
2696 heap_statistics->set_total_heap_size(i::Heap::CommittedMemory());
2697 heap_statistics->set_used_heap_size(i::Heap::SizeOfObjects());
2698}
2699
2700
2701bool v8::V8::IdleNotification() {
Steve Blocka7e24c12009-10-30 11:49:00 +00002702 // Returning true tells the caller that it need not
2703 // continue to call IdleNotification.
2704 if (!i::V8::IsRunning()) return true;
Steve Block3ce2e202009-11-05 08:53:23 +00002705 return i::V8::IdleNotification();
Steve Blocka7e24c12009-10-30 11:49:00 +00002706}
2707
2708
2709void v8::V8::LowMemoryNotification() {
Steve Blocka7e24c12009-10-30 11:49:00 +00002710 if (!i::V8::IsRunning()) return;
2711 i::Heap::CollectAllGarbage(true);
Steve Blocka7e24c12009-10-30 11:49:00 +00002712}
2713
2714
2715const char* v8::V8::GetVersion() {
2716 static v8::internal::EmbeddedVector<char, 128> buffer;
2717 v8::internal::Version::GetString(buffer);
2718 return buffer.start();
2719}
2720
2721
2722static i::Handle<i::FunctionTemplateInfo>
2723 EnsureConstructor(i::Handle<i::ObjectTemplateInfo> templ) {
2724 if (templ->constructor()->IsUndefined()) {
2725 Local<FunctionTemplate> constructor = FunctionTemplate::New();
2726 Utils::OpenHandle(*constructor)->set_instance_template(*templ);
2727 templ->set_constructor(*Utils::OpenHandle(*constructor));
2728 }
2729 return i::Handle<i::FunctionTemplateInfo>(
2730 i::FunctionTemplateInfo::cast(templ->constructor()));
2731}
2732
2733
2734Persistent<Context> v8::Context::New(
2735 v8::ExtensionConfiguration* extensions,
2736 v8::Handle<ObjectTemplate> global_template,
2737 v8::Handle<Value> global_object) {
2738 EnsureInitialized("v8::Context::New()");
2739 LOG_API("Context::New");
2740 ON_BAILOUT("v8::Context::New()", return Persistent<Context>());
2741
2742 // Enter V8 via an ENTER_V8 scope.
2743 i::Handle<i::Context> env;
2744 {
2745 ENTER_V8;
2746#if defined(ANDROID)
2747 // On mobile device, full GC is expensive, leave it to the system to
2748 // decide when should make a full GC.
2749#else
2750 // Give the heap a chance to cleanup if we've disposed contexts.
2751 i::Heap::CollectAllGarbageIfContextDisposed();
2752#endif
2753 v8::Handle<ObjectTemplate> proxy_template = global_template;
2754 i::Handle<i::FunctionTemplateInfo> proxy_constructor;
2755 i::Handle<i::FunctionTemplateInfo> global_constructor;
2756
2757 if (!global_template.IsEmpty()) {
2758 // Make sure that the global_template has a constructor.
2759 global_constructor =
2760 EnsureConstructor(Utils::OpenHandle(*global_template));
2761
2762 // Create a fresh template for the global proxy object.
2763 proxy_template = ObjectTemplate::New();
2764 proxy_constructor =
2765 EnsureConstructor(Utils::OpenHandle(*proxy_template));
2766
2767 // Set the global template to be the prototype template of
2768 // global proxy template.
2769 proxy_constructor->set_prototype_template(
2770 *Utils::OpenHandle(*global_template));
2771
2772 // Migrate security handlers from global_template to
2773 // proxy_template. Temporarily removing access check
2774 // information from the global template.
2775 if (!global_constructor->access_check_info()->IsUndefined()) {
2776 proxy_constructor->set_access_check_info(
2777 global_constructor->access_check_info());
2778 proxy_constructor->set_needs_access_check(
2779 global_constructor->needs_access_check());
2780 global_constructor->set_needs_access_check(false);
2781 global_constructor->set_access_check_info(i::Heap::undefined_value());
2782 }
2783 }
2784
2785 // Create the environment.
2786 env = i::Bootstrapper::CreateEnvironment(
2787 Utils::OpenHandle(*global_object),
2788 proxy_template,
2789 extensions);
2790
2791 // Restore the access check info on the global template.
2792 if (!global_template.IsEmpty()) {
2793 ASSERT(!global_constructor.is_null());
2794 ASSERT(!proxy_constructor.is_null());
2795 global_constructor->set_access_check_info(
2796 proxy_constructor->access_check_info());
2797 global_constructor->set_needs_access_check(
2798 proxy_constructor->needs_access_check());
2799 }
2800 }
2801 // Leave V8.
2802
2803 if (env.is_null())
2804 return Persistent<Context>();
2805 return Persistent<Context>(Utils::ToLocal(env));
2806}
2807
2808
2809void v8::Context::SetSecurityToken(Handle<Value> token) {
2810 if (IsDeadCheck("v8::Context::SetSecurityToken()")) return;
2811 ENTER_V8;
2812 i::Handle<i::Context> env = Utils::OpenHandle(this);
2813 i::Handle<i::Object> token_handle = Utils::OpenHandle(*token);
2814 env->set_security_token(*token_handle);
2815}
2816
2817
2818void v8::Context::UseDefaultSecurityToken() {
2819 if (IsDeadCheck("v8::Context::UseDefaultSecurityToken()")) return;
2820 ENTER_V8;
2821 i::Handle<i::Context> env = Utils::OpenHandle(this);
2822 env->set_security_token(env->global());
2823}
2824
2825
2826Handle<Value> v8::Context::GetSecurityToken() {
2827 if (IsDeadCheck("v8::Context::GetSecurityToken()")) return Handle<Value>();
2828 i::Handle<i::Context> env = Utils::OpenHandle(this);
2829 i::Object* security_token = env->security_token();
2830 i::Handle<i::Object> token_handle(security_token);
2831 return Utils::ToLocal(token_handle);
2832}
2833
2834
2835bool Context::HasOutOfMemoryException() {
2836 i::Handle<i::Context> env = Utils::OpenHandle(this);
2837 return env->has_out_of_memory();
2838}
2839
2840
2841bool Context::InContext() {
2842 return i::Top::context() != NULL;
2843}
2844
2845
2846v8::Local<v8::Context> Context::GetEntered() {
2847 if (IsDeadCheck("v8::Context::GetEntered()")) return Local<Context>();
2848 i::Handle<i::Object> last = thread_local.LastEnteredContext();
2849 if (last.is_null()) return Local<Context>();
2850 i::Handle<i::Context> context = i::Handle<i::Context>::cast(last);
2851 return Utils::ToLocal(context);
2852}
2853
2854
2855v8::Local<v8::Context> Context::GetCurrent() {
2856 if (IsDeadCheck("v8::Context::GetCurrent()")) return Local<Context>();
Steve Block3ce2e202009-11-05 08:53:23 +00002857 i::Handle<i::Object> current = i::Top::global_context();
2858 if (current.is_null()) return Local<Context>();
2859 i::Handle<i::Context> context = i::Handle<i::Context>::cast(current);
Steve Blocka7e24c12009-10-30 11:49:00 +00002860 return Utils::ToLocal(context);
2861}
2862
2863
2864v8::Local<v8::Context> Context::GetCalling() {
2865 if (IsDeadCheck("v8::Context::GetCalling()")) return Local<Context>();
2866 i::Handle<i::Object> calling = i::Top::GetCallingGlobalContext();
2867 if (calling.is_null()) return Local<Context>();
2868 i::Handle<i::Context> context = i::Handle<i::Context>::cast(calling);
2869 return Utils::ToLocal(context);
2870}
2871
2872
2873v8::Local<v8::Object> Context::Global() {
2874 if (IsDeadCheck("v8::Context::Global()")) return Local<v8::Object>();
2875 i::Object** ctx = reinterpret_cast<i::Object**>(this);
2876 i::Handle<i::Context> context =
2877 i::Handle<i::Context>::cast(i::Handle<i::Object>(ctx));
2878 i::Handle<i::Object> global(context->global_proxy());
2879 return Utils::ToLocal(i::Handle<i::JSObject>::cast(global));
2880}
2881
2882
2883void Context::DetachGlobal() {
2884 if (IsDeadCheck("v8::Context::DetachGlobal()")) return;
2885 ENTER_V8;
2886 i::Object** ctx = reinterpret_cast<i::Object**>(this);
2887 i::Handle<i::Context> context =
2888 i::Handle<i::Context>::cast(i::Handle<i::Object>(ctx));
2889 i::Bootstrapper::DetachGlobal(context);
2890}
2891
2892
2893Local<v8::Object> ObjectTemplate::NewInstance() {
2894 ON_BAILOUT("v8::ObjectTemplate::NewInstance()", return Local<v8::Object>());
2895 LOG_API("ObjectTemplate::NewInstance");
2896 ENTER_V8;
2897 EXCEPTION_PREAMBLE();
2898 i::Handle<i::Object> obj =
2899 i::Execution::InstantiateObject(Utils::OpenHandle(this),
2900 &has_pending_exception);
2901 EXCEPTION_BAILOUT_CHECK(Local<v8::Object>());
2902 return Utils::ToLocal(i::Handle<i::JSObject>::cast(obj));
2903}
2904
2905
2906Local<v8::Function> FunctionTemplate::GetFunction() {
2907 ON_BAILOUT("v8::FunctionTemplate::GetFunction()",
2908 return Local<v8::Function>());
2909 LOG_API("FunctionTemplate::GetFunction");
2910 ENTER_V8;
2911 EXCEPTION_PREAMBLE();
2912 i::Handle<i::Object> obj =
2913 i::Execution::InstantiateFunction(Utils::OpenHandle(this),
2914 &has_pending_exception);
2915 EXCEPTION_BAILOUT_CHECK(Local<v8::Function>());
2916 return Utils::ToLocal(i::Handle<i::JSFunction>::cast(obj));
2917}
2918
2919
2920bool FunctionTemplate::HasInstance(v8::Handle<v8::Value> value) {
2921 ON_BAILOUT("v8::FunctionTemplate::HasInstanceOf()", return false);
2922 i::Object* obj = *Utils::OpenHandle(*value);
2923 return obj->IsInstanceOf(*Utils::OpenHandle(this));
2924}
2925
2926
2927static Local<External> ExternalNewImpl(void* data) {
2928 return Utils::ToLocal(i::Factory::NewProxy(static_cast<i::Address>(data)));
2929}
2930
2931static void* ExternalValueImpl(i::Handle<i::Object> obj) {
2932 return reinterpret_cast<void*>(i::Proxy::cast(*obj)->proxy());
2933}
2934
2935
Steve Blocka7e24c12009-10-30 11:49:00 +00002936Local<Value> v8::External::Wrap(void* data) {
2937 STATIC_ASSERT(sizeof(data) == sizeof(i::Address));
2938 LOG_API("External::Wrap");
2939 EnsureInitialized("v8::External::Wrap()");
2940 ENTER_V8;
Steve Block3ce2e202009-11-05 08:53:23 +00002941 i::Object* as_object = reinterpret_cast<i::Object*>(data);
2942 if (as_object->IsSmi()) {
2943 return Utils::ToLocal(i::Handle<i::Object>(as_object));
Steve Blocka7e24c12009-10-30 11:49:00 +00002944 }
2945 return ExternalNewImpl(data);
2946}
2947
2948
Steve Block3ce2e202009-11-05 08:53:23 +00002949void* v8::Object::SlowGetPointerFromInternalField(int index) {
2950 i::Handle<i::JSObject> obj = Utils::OpenHandle(this);
2951 i::Object* value = obj->GetInternalField(index);
2952 if (value->IsSmi()) {
2953 return value;
2954 } else if (value->IsProxy()) {
2955 return reinterpret_cast<void*>(i::Proxy::cast(value)->proxy());
2956 } else {
2957 return NULL;
2958 }
2959}
2960
2961
Steve Blocka7e24c12009-10-30 11:49:00 +00002962void* v8::External::FullUnwrap(v8::Handle<v8::Value> wrapper) {
2963 if (IsDeadCheck("v8::External::Unwrap()")) return 0;
2964 i::Handle<i::Object> obj = Utils::OpenHandle(*wrapper);
2965 void* result;
2966 if (obj->IsSmi()) {
2967 // The external value was an aligned pointer.
Steve Block3ce2e202009-11-05 08:53:23 +00002968 result = *obj;
Steve Blocka7e24c12009-10-30 11:49:00 +00002969 } else if (obj->IsProxy()) {
2970 result = ExternalValueImpl(obj);
2971 } else {
2972 result = NULL;
2973 }
2974 ASSERT_EQ(result, QuickUnwrap(wrapper));
2975 return result;
2976}
2977
2978
2979Local<External> v8::External::New(void* data) {
2980 STATIC_ASSERT(sizeof(data) == sizeof(i::Address));
2981 LOG_API("External::New");
2982 EnsureInitialized("v8::External::New()");
2983 ENTER_V8;
2984 return ExternalNewImpl(data);
2985}
2986
2987
2988void* External::Value() const {
2989 if (IsDeadCheck("v8::External::Value()")) return 0;
2990 i::Handle<i::Object> obj = Utils::OpenHandle(this);
2991 return ExternalValueImpl(obj);
2992}
2993
2994
2995Local<String> v8::String::Empty() {
2996 EnsureInitialized("v8::String::Empty()");
2997 LOG_API("String::Empty()");
2998 return Utils::ToLocal(i::Factory::empty_symbol());
2999}
3000
3001
3002Local<String> v8::String::New(const char* data, int length) {
3003 EnsureInitialized("v8::String::New()");
3004 LOG_API("String::New(char)");
3005 if (length == 0) return Empty();
3006 ENTER_V8;
Steve Blockd0582a62009-12-15 09:54:21 +00003007 if (length == -1) length = i::StrLength(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00003008 i::Handle<i::String> result =
3009 i::Factory::NewStringFromUtf8(i::Vector<const char>(data, length));
3010 return Utils::ToLocal(result);
3011}
3012
3013
Steve Block3ce2e202009-11-05 08:53:23 +00003014Local<String> v8::String::Concat(Handle<String> left, Handle<String> right) {
3015 EnsureInitialized("v8::String::New()");
3016 LOG_API("String::New(char)");
3017 ENTER_V8;
3018 i::Handle<i::String> left_string = Utils::OpenHandle(*left);
3019 i::Handle<i::String> right_string = Utils::OpenHandle(*right);
3020 i::Handle<i::String> result = i::Factory::NewConsString(left_string,
3021 right_string);
3022 return Utils::ToLocal(result);
3023}
3024
3025
Steve Blocka7e24c12009-10-30 11:49:00 +00003026Local<String> v8::String::NewUndetectable(const char* data, int length) {
3027 EnsureInitialized("v8::String::NewUndetectable()");
3028 LOG_API("String::NewUndetectable(char)");
3029 ENTER_V8;
Steve Blockd0582a62009-12-15 09:54:21 +00003030 if (length == -1) length = i::StrLength(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00003031 i::Handle<i::String> result =
3032 i::Factory::NewStringFromUtf8(i::Vector<const char>(data, length));
3033 result->MarkAsUndetectable();
3034 return Utils::ToLocal(result);
3035}
3036
3037
3038static int TwoByteStringLength(const uint16_t* data) {
3039 int length = 0;
3040 while (data[length] != '\0') length++;
3041 return length;
3042}
3043
3044
3045Local<String> v8::String::New(const uint16_t* data, int length) {
3046 EnsureInitialized("v8::String::New()");
3047 LOG_API("String::New(uint16_)");
3048 if (length == 0) return Empty();
3049 ENTER_V8;
3050 if (length == -1) length = TwoByteStringLength(data);
3051 i::Handle<i::String> result =
3052 i::Factory::NewStringFromTwoByte(i::Vector<const uint16_t>(data, length));
3053 return Utils::ToLocal(result);
3054}
3055
3056
3057Local<String> v8::String::NewUndetectable(const uint16_t* data, int length) {
3058 EnsureInitialized("v8::String::NewUndetectable()");
3059 LOG_API("String::NewUndetectable(uint16_)");
3060 ENTER_V8;
3061 if (length == -1) length = TwoByteStringLength(data);
3062 i::Handle<i::String> result =
3063 i::Factory::NewStringFromTwoByte(i::Vector<const uint16_t>(data, length));
3064 result->MarkAsUndetectable();
3065 return Utils::ToLocal(result);
3066}
3067
3068
3069i::Handle<i::String> NewExternalStringHandle(
3070 v8::String::ExternalStringResource* resource) {
3071 i::Handle<i::String> result =
3072 i::Factory::NewExternalStringFromTwoByte(resource);
3073 return result;
3074}
3075
3076
3077i::Handle<i::String> NewExternalAsciiStringHandle(
3078 v8::String::ExternalAsciiStringResource* resource) {
3079 i::Handle<i::String> result =
3080 i::Factory::NewExternalStringFromAscii(resource);
3081 return result;
3082}
3083
3084
3085static void DisposeExternalString(v8::Persistent<v8::Value> obj,
3086 void* parameter) {
3087 ENTER_V8;
3088 i::ExternalTwoByteString* str =
3089 i::ExternalTwoByteString::cast(*Utils::OpenHandle(*obj));
3090
3091 // External symbols are deleted when they are pruned out of the symbol
3092 // table. Generally external symbols are not registered with the weak handle
3093 // callbacks unless they are upgraded to a symbol after being externalized.
3094 if (!str->IsSymbol()) {
3095 v8::String::ExternalStringResource* resource =
3096 reinterpret_cast<v8::String::ExternalStringResource*>(parameter);
3097 if (resource != NULL) {
Steve Blockd0582a62009-12-15 09:54:21 +00003098 const int total_size =
3099 static_cast<int>(resource->length() * sizeof(*resource->data()));
Steve Blocka7e24c12009-10-30 11:49:00 +00003100 i::Counters::total_external_string_memory.Decrement(total_size);
3101
3102 // The object will continue to live in the JavaScript heap until the
3103 // handle is entirely cleaned out by the next GC. For example the
3104 // destructor for the resource below could bring it back to life again.
3105 // Which is why we make sure to not have a dangling pointer here.
3106 str->set_resource(NULL);
3107 delete resource;
3108 }
3109 }
3110
3111 // In any case we do not need this handle any longer.
3112 obj.Dispose();
3113}
3114
3115
3116static void DisposeExternalAsciiString(v8::Persistent<v8::Value> obj,
3117 void* parameter) {
3118 ENTER_V8;
3119 i::ExternalAsciiString* str =
3120 i::ExternalAsciiString::cast(*Utils::OpenHandle(*obj));
3121
3122 // External symbols are deleted when they are pruned out of the symbol
3123 // table. Generally external symbols are not registered with the weak handle
3124 // callbacks unless they are upgraded to a symbol after being externalized.
3125 if (!str->IsSymbol()) {
3126 v8::String::ExternalAsciiStringResource* resource =
3127 reinterpret_cast<v8::String::ExternalAsciiStringResource*>(parameter);
3128 if (resource != NULL) {
Steve Blockd0582a62009-12-15 09:54:21 +00003129 const int total_size =
3130 static_cast<int>(resource->length() * sizeof(*resource->data()));
Steve Blocka7e24c12009-10-30 11:49:00 +00003131 i::Counters::total_external_string_memory.Decrement(total_size);
3132
3133 // The object will continue to live in the JavaScript heap until the
3134 // handle is entirely cleaned out by the next GC. For example the
3135 // destructor for the resource below could bring it back to life again.
3136 // Which is why we make sure to not have a dangling pointer here.
3137 str->set_resource(NULL);
3138 delete resource;
3139 }
3140 }
3141
3142 // In any case we do not need this handle any longer.
3143 obj.Dispose();
3144}
3145
3146
3147Local<String> v8::String::NewExternal(
3148 v8::String::ExternalStringResource* resource) {
3149 EnsureInitialized("v8::String::NewExternal()");
3150 LOG_API("String::NewExternal");
3151 ENTER_V8;
Steve Blockd0582a62009-12-15 09:54:21 +00003152 const int total_size =
3153 static_cast<int>(resource->length() * sizeof(*resource->data()));
Steve Blocka7e24c12009-10-30 11:49:00 +00003154 i::Counters::total_external_string_memory.Increment(total_size);
3155 i::Handle<i::String> result = NewExternalStringHandle(resource);
3156 i::Handle<i::Object> handle = i::GlobalHandles::Create(*result);
3157 i::GlobalHandles::MakeWeak(handle.location(),
3158 resource,
3159 &DisposeExternalString);
3160 return Utils::ToLocal(result);
3161}
3162
3163
3164bool v8::String::MakeExternal(v8::String::ExternalStringResource* resource) {
3165 if (IsDeadCheck("v8::String::MakeExternal()")) return false;
3166 if (this->IsExternal()) return false; // Already an external string.
3167 ENTER_V8;
3168 i::Handle<i::String> obj = Utils::OpenHandle(this);
3169 bool result = obj->MakeExternal(resource);
3170 if (result && !obj->IsSymbol()) {
3171 // Operation was successful and the string is not a symbol. In this case
3172 // we need to make sure that the we call the destructor for the external
3173 // resource when no strong references to the string remain.
3174 i::Handle<i::Object> handle = i::GlobalHandles::Create(*obj);
3175 i::GlobalHandles::MakeWeak(handle.location(),
3176 resource,
3177 &DisposeExternalString);
3178 }
3179 return result;
3180}
3181
3182
3183Local<String> v8::String::NewExternal(
3184 v8::String::ExternalAsciiStringResource* resource) {
3185 EnsureInitialized("v8::String::NewExternal()");
3186 LOG_API("String::NewExternal");
3187 ENTER_V8;
Steve Blockd0582a62009-12-15 09:54:21 +00003188 const int total_size =
3189 static_cast<int>(resource->length() * sizeof(*resource->data()));
Steve Blocka7e24c12009-10-30 11:49:00 +00003190 i::Counters::total_external_string_memory.Increment(total_size);
3191 i::Handle<i::String> result = NewExternalAsciiStringHandle(resource);
3192 i::Handle<i::Object> handle = i::GlobalHandles::Create(*result);
3193 i::GlobalHandles::MakeWeak(handle.location(),
3194 resource,
3195 &DisposeExternalAsciiString);
3196 return Utils::ToLocal(result);
3197}
3198
3199
3200bool v8::String::MakeExternal(
3201 v8::String::ExternalAsciiStringResource* resource) {
3202 if (IsDeadCheck("v8::String::MakeExternal()")) return false;
3203 if (this->IsExternal()) return false; // Already an external string.
3204 ENTER_V8;
3205 i::Handle<i::String> obj = Utils::OpenHandle(this);
3206 bool result = obj->MakeExternal(resource);
3207 if (result && !obj->IsSymbol()) {
3208 // Operation was successful and the string is not a symbol. In this case
3209 // we need to make sure that the we call the destructor for the external
3210 // resource when no strong references to the string remain.
3211 i::Handle<i::Object> handle = i::GlobalHandles::Create(*obj);
3212 i::GlobalHandles::MakeWeak(handle.location(),
3213 resource,
3214 &DisposeExternalAsciiString);
3215 }
3216 return result;
3217}
3218
3219
3220bool v8::String::CanMakeExternal() {
3221 if (IsDeadCheck("v8::String::CanMakeExternal()")) return false;
3222 i::Handle<i::String> obj = Utils::OpenHandle(this);
3223 int size = obj->Size(); // Byte size of the original string.
3224 if (size < i::ExternalString::kSize)
3225 return false;
3226 i::StringShape shape(*obj);
3227 return !shape.IsExternal();
3228}
3229
3230
3231Local<v8::Object> v8::Object::New() {
3232 EnsureInitialized("v8::Object::New()");
3233 LOG_API("Object::New");
3234 ENTER_V8;
3235 i::Handle<i::JSObject> obj =
3236 i::Factory::NewJSObject(i::Top::object_function());
3237 return Utils::ToLocal(obj);
3238}
3239
3240
3241Local<v8::Value> v8::Date::New(double time) {
3242 EnsureInitialized("v8::Date::New()");
3243 LOG_API("Date::New");
Steve Blockd0582a62009-12-15 09:54:21 +00003244 if (isnan(time)) {
3245 // Introduce only canonical NaN value into the VM, to avoid signaling NaNs.
3246 time = i::OS::nan_value();
3247 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003248 ENTER_V8;
3249 EXCEPTION_PREAMBLE();
3250 i::Handle<i::Object> obj =
3251 i::Execution::NewDate(time, &has_pending_exception);
3252 EXCEPTION_BAILOUT_CHECK(Local<v8::Value>());
3253 return Utils::ToLocal(obj);
3254}
3255
3256
3257double v8::Date::NumberValue() const {
3258 if (IsDeadCheck("v8::Date::NumberValue()")) return 0;
3259 LOG_API("Date::NumberValue");
3260 i::Handle<i::Object> obj = Utils::OpenHandle(this);
3261 i::Handle<i::JSValue> jsvalue = i::Handle<i::JSValue>::cast(obj);
3262 return jsvalue->value()->Number();
3263}
3264
3265
3266Local<v8::Array> v8::Array::New(int length) {
3267 EnsureInitialized("v8::Array::New()");
3268 LOG_API("Array::New");
3269 ENTER_V8;
3270 i::Handle<i::JSArray> obj = i::Factory::NewJSArray(length);
3271 return Utils::ToLocal(obj);
3272}
3273
3274
3275uint32_t v8::Array::Length() const {
3276 if (IsDeadCheck("v8::Array::Length()")) return 0;
3277 i::Handle<i::JSArray> obj = Utils::OpenHandle(this);
3278 i::Object* length = obj->length();
3279 if (length->IsSmi()) {
3280 return i::Smi::cast(length)->value();
3281 } else {
3282 return static_cast<uint32_t>(length->Number());
3283 }
3284}
3285
3286
3287Local<Object> Array::CloneElementAt(uint32_t index) {
3288 ON_BAILOUT("v8::Array::CloneElementAt()", return Local<Object>());
3289 i::Handle<i::JSObject> self = Utils::OpenHandle(this);
3290 if (!self->HasFastElements()) {
3291 return Local<Object>();
3292 }
3293 i::FixedArray* elms = i::FixedArray::cast(self->elements());
3294 i::Object* paragon = elms->get(index);
3295 if (!paragon->IsJSObject()) {
3296 return Local<Object>();
3297 }
3298 i::Handle<i::JSObject> paragon_handle(i::JSObject::cast(paragon));
3299 EXCEPTION_PREAMBLE();
3300 i::Handle<i::JSObject> result = i::Copy(paragon_handle);
3301 has_pending_exception = result.is_null();
3302 EXCEPTION_BAILOUT_CHECK(Local<Object>());
3303 return Utils::ToLocal(result);
3304}
3305
3306
3307Local<String> v8::String::NewSymbol(const char* data, int length) {
3308 EnsureInitialized("v8::String::NewSymbol()");
3309 LOG_API("String::NewSymbol(char)");
3310 ENTER_V8;
Steve Blockd0582a62009-12-15 09:54:21 +00003311 if (length == -1) length = i::StrLength(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00003312 i::Handle<i::String> result =
3313 i::Factory::LookupSymbol(i::Vector<const char>(data, length));
3314 return Utils::ToLocal(result);
3315}
3316
3317
3318Local<Number> v8::Number::New(double value) {
3319 EnsureInitialized("v8::Number::New()");
Steve Blockd0582a62009-12-15 09:54:21 +00003320 if (isnan(value)) {
3321 // Introduce only canonical NaN value into the VM, to avoid signaling NaNs.
3322 value = i::OS::nan_value();
3323 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003324 ENTER_V8;
3325 i::Handle<i::Object> result = i::Factory::NewNumber(value);
3326 return Utils::NumberToLocal(result);
3327}
3328
3329
3330Local<Integer> v8::Integer::New(int32_t value) {
3331 EnsureInitialized("v8::Integer::New()");
3332 if (i::Smi::IsValid(value)) {
3333 return Utils::IntegerToLocal(i::Handle<i::Object>(i::Smi::FromInt(value)));
3334 }
3335 ENTER_V8;
3336 i::Handle<i::Object> result = i::Factory::NewNumber(value);
3337 return Utils::IntegerToLocal(result);
3338}
3339
3340
Steve Block3ce2e202009-11-05 08:53:23 +00003341Local<Integer> Integer::NewFromUnsigned(uint32_t value) {
3342 bool fits_into_int32_t = (value & (1 << 31)) == 0;
3343 if (fits_into_int32_t) {
3344 return Integer::New(static_cast<int32_t>(value));
3345 }
3346 ENTER_V8;
3347 i::Handle<i::Object> result = i::Factory::NewNumber(value);
3348 return Utils::IntegerToLocal(result);
3349}
3350
3351
Steve Blocka7e24c12009-10-30 11:49:00 +00003352void V8::IgnoreOutOfMemoryException() {
3353 thread_local.set_ignore_out_of_memory(true);
3354}
3355
3356
3357bool V8::AddMessageListener(MessageCallback that, Handle<Value> data) {
3358 EnsureInitialized("v8::V8::AddMessageListener()");
3359 ON_BAILOUT("v8::V8::AddMessageListener()", return false);
3360 ENTER_V8;
3361 HandleScope scope;
3362 NeanderArray listeners(i::Factory::message_listeners());
3363 NeanderObject obj(2);
3364 obj.set(0, *i::Factory::NewProxy(FUNCTION_ADDR(that)));
3365 obj.set(1, data.IsEmpty() ?
3366 i::Heap::undefined_value() :
3367 *Utils::OpenHandle(*data));
3368 listeners.add(obj.value());
3369 return true;
3370}
3371
3372
3373void V8::RemoveMessageListeners(MessageCallback that) {
3374 EnsureInitialized("v8::V8::RemoveMessageListener()");
3375 ON_BAILOUT("v8::V8::RemoveMessageListeners()", return);
3376 ENTER_V8;
3377 HandleScope scope;
3378 NeanderArray listeners(i::Factory::message_listeners());
3379 for (int i = 0; i < listeners.length(); i++) {
3380 if (listeners.get(i)->IsUndefined()) continue; // skip deleted ones
3381
3382 NeanderObject listener(i::JSObject::cast(listeners.get(i)));
3383 i::Handle<i::Proxy> callback_obj(i::Proxy::cast(listener.get(0)));
3384 if (callback_obj->proxy() == FUNCTION_ADDR(that)) {
3385 listeners.set(i, i::Heap::undefined_value());
3386 }
3387 }
3388}
3389
3390
3391void V8::SetCounterFunction(CounterLookupCallback callback) {
3392 if (IsDeadCheck("v8::V8::SetCounterFunction()")) return;
3393 i::StatsTable::SetCounterFunction(callback);
3394}
3395
3396void V8::SetCreateHistogramFunction(CreateHistogramCallback callback) {
3397 if (IsDeadCheck("v8::V8::SetCreateHistogramFunction()")) return;
3398 i::StatsTable::SetCreateHistogramFunction(callback);
3399}
3400
3401void V8::SetAddHistogramSampleFunction(AddHistogramSampleCallback callback) {
3402 if (IsDeadCheck("v8::V8::SetAddHistogramSampleFunction()")) return;
3403 i::StatsTable::SetAddHistogramSampleFunction(callback);
3404}
3405
3406void V8::EnableSlidingStateWindow() {
3407 if (IsDeadCheck("v8::V8::EnableSlidingStateWindow()")) return;
3408 i::Logger::EnableSlidingStateWindow();
3409}
3410
3411
3412void V8::SetFailedAccessCheckCallbackFunction(
3413 FailedAccessCheckCallback callback) {
3414 if (IsDeadCheck("v8::V8::SetFailedAccessCheckCallbackFunction()")) return;
3415 i::Top::SetFailedAccessCheckCallback(callback);
3416}
3417
3418
3419void V8::AddObjectGroup(Persistent<Value>* objects, size_t length) {
3420 if (IsDeadCheck("v8::V8::AddObjectGroup()")) return;
3421 STATIC_ASSERT(sizeof(Persistent<Value>) == sizeof(i::Object**));
3422 i::GlobalHandles::AddGroup(reinterpret_cast<i::Object***>(objects), length);
3423}
3424
3425
3426int V8::AdjustAmountOfExternalAllocatedMemory(int change_in_bytes) {
3427 if (IsDeadCheck("v8::V8::AdjustAmountOfExternalAllocatedMemory()")) return 0;
3428 return i::Heap::AdjustAmountOfExternalAllocatedMemory(change_in_bytes);
3429}
3430
3431
3432void V8::SetGlobalGCPrologueCallback(GCCallback callback) {
3433 if (IsDeadCheck("v8::V8::SetGlobalGCPrologueCallback()")) return;
3434 i::Heap::SetGlobalGCPrologueCallback(callback);
3435}
3436
3437
3438void V8::SetGlobalGCEpilogueCallback(GCCallback callback) {
3439 if (IsDeadCheck("v8::V8::SetGlobalGCEpilogueCallback()")) return;
3440 i::Heap::SetGlobalGCEpilogueCallback(callback);
3441}
3442
3443
3444void V8::PauseProfiler() {
3445#ifdef ENABLE_LOGGING_AND_PROFILING
3446 i::Logger::PauseProfiler(PROFILER_MODULE_CPU);
3447#endif
3448}
3449
3450
3451void V8::ResumeProfiler() {
3452#ifdef ENABLE_LOGGING_AND_PROFILING
3453 i::Logger::ResumeProfiler(PROFILER_MODULE_CPU);
3454#endif
3455}
3456
3457
3458bool V8::IsProfilerPaused() {
3459#ifdef ENABLE_LOGGING_AND_PROFILING
3460 return i::Logger::GetActiveProfilerModules() & PROFILER_MODULE_CPU;
3461#else
3462 return true;
3463#endif
3464}
3465
3466
3467void V8::ResumeProfilerEx(int flags) {
3468#ifdef ENABLE_LOGGING_AND_PROFILING
3469 if (flags & PROFILER_MODULE_HEAP_SNAPSHOT) {
3470 // Snapshot mode: resume modules, perform GC, then pause only
3471 // those modules which haven't been started prior to making a
3472 // snapshot.
3473
3474 // Reset snapshot flag and CPU module flags.
3475 flags &= ~(PROFILER_MODULE_HEAP_SNAPSHOT | PROFILER_MODULE_CPU);
3476 const int current_flags = i::Logger::GetActiveProfilerModules();
3477 i::Logger::ResumeProfiler(flags);
3478 i::Heap::CollectAllGarbage(false);
3479 i::Logger::PauseProfiler(~current_flags & flags);
3480 } else {
3481 i::Logger::ResumeProfiler(flags);
3482 }
3483#endif
3484}
3485
3486
3487void V8::PauseProfilerEx(int flags) {
3488#ifdef ENABLE_LOGGING_AND_PROFILING
3489 i::Logger::PauseProfiler(flags);
3490#endif
3491}
3492
3493
3494int V8::GetActiveProfilerModules() {
3495#ifdef ENABLE_LOGGING_AND_PROFILING
3496 return i::Logger::GetActiveProfilerModules();
3497#else
3498 return PROFILER_MODULE_NONE;
3499#endif
3500}
3501
3502
3503int V8::GetLogLines(int from_pos, char* dest_buf, int max_size) {
3504#ifdef ENABLE_LOGGING_AND_PROFILING
3505 return i::Logger::GetLogLines(from_pos, dest_buf, max_size);
3506#endif
3507 return 0;
3508}
3509
3510
3511int V8::GetCurrentThreadId() {
3512 API_ENTRY_CHECK("V8::GetCurrentThreadId()");
3513 EnsureInitialized("V8::GetCurrentThreadId()");
3514 return i::Top::thread_id();
3515}
3516
3517
3518void V8::TerminateExecution(int thread_id) {
3519 if (!i::V8::IsRunning()) return;
3520 API_ENTRY_CHECK("V8::GetCurrentThreadId()");
3521 // If the thread_id identifies the current thread just terminate
3522 // execution right away. Otherwise, ask the thread manager to
3523 // terminate the thread with the given id if any.
3524 if (thread_id == i::Top::thread_id()) {
3525 i::StackGuard::TerminateExecution();
3526 } else {
3527 i::ThreadManager::TerminateExecution(thread_id);
3528 }
3529}
3530
3531
3532void V8::TerminateExecution() {
3533 if (!i::V8::IsRunning()) return;
3534 i::StackGuard::TerminateExecution();
3535}
3536
3537
3538String::Utf8Value::Utf8Value(v8::Handle<v8::Value> obj) {
3539 EnsureInitialized("v8::String::Utf8Value::Utf8Value()");
3540 if (obj.IsEmpty()) {
3541 str_ = NULL;
3542 length_ = 0;
3543 return;
3544 }
3545 ENTER_V8;
3546 HandleScope scope;
3547 TryCatch try_catch;
3548 Handle<String> str = obj->ToString();
3549 if (str.IsEmpty()) {
3550 str_ = NULL;
3551 length_ = 0;
3552 } else {
3553 length_ = str->Utf8Length();
3554 str_ = i::NewArray<char>(length_ + 1);
3555 str->WriteUtf8(str_);
3556 }
3557}
3558
3559
3560String::Utf8Value::~Utf8Value() {
3561 i::DeleteArray(str_);
3562}
3563
3564
3565String::AsciiValue::AsciiValue(v8::Handle<v8::Value> obj) {
3566 EnsureInitialized("v8::String::AsciiValue::AsciiValue()");
3567 if (obj.IsEmpty()) {
3568 str_ = NULL;
3569 length_ = 0;
3570 return;
3571 }
3572 ENTER_V8;
3573 HandleScope scope;
3574 TryCatch try_catch;
3575 Handle<String> str = obj->ToString();
3576 if (str.IsEmpty()) {
3577 str_ = NULL;
3578 length_ = 0;
3579 } else {
3580 length_ = str->Length();
3581 str_ = i::NewArray<char>(length_ + 1);
3582 str->WriteAscii(str_);
3583 }
3584}
3585
3586
3587String::AsciiValue::~AsciiValue() {
3588 i::DeleteArray(str_);
3589}
3590
3591
3592String::Value::Value(v8::Handle<v8::Value> obj) {
3593 EnsureInitialized("v8::String::Value::Value()");
3594 if (obj.IsEmpty()) {
3595 str_ = NULL;
3596 length_ = 0;
3597 return;
3598 }
3599 ENTER_V8;
3600 HandleScope scope;
3601 TryCatch try_catch;
3602 Handle<String> str = obj->ToString();
3603 if (str.IsEmpty()) {
3604 str_ = NULL;
3605 length_ = 0;
3606 } else {
3607 length_ = str->Length();
3608 str_ = i::NewArray<uint16_t>(length_ + 1);
3609 str->Write(str_);
3610 }
3611}
3612
3613
3614String::Value::~Value() {
3615 i::DeleteArray(str_);
3616}
3617
3618Local<Value> Exception::RangeError(v8::Handle<v8::String> raw_message) {
3619 LOG_API("RangeError");
3620 ON_BAILOUT("v8::Exception::RangeError()", return Local<Value>());
3621 ENTER_V8;
3622 i::Object* error;
3623 {
3624 HandleScope scope;
3625 i::Handle<i::String> message = Utils::OpenHandle(*raw_message);
3626 i::Handle<i::Object> result = i::Factory::NewRangeError(message);
3627 error = *result;
3628 }
3629 i::Handle<i::Object> result(error);
3630 return Utils::ToLocal(result);
3631}
3632
3633Local<Value> Exception::ReferenceError(v8::Handle<v8::String> raw_message) {
3634 LOG_API("ReferenceError");
3635 ON_BAILOUT("v8::Exception::ReferenceError()", return Local<Value>());
3636 ENTER_V8;
3637 i::Object* error;
3638 {
3639 HandleScope scope;
3640 i::Handle<i::String> message = Utils::OpenHandle(*raw_message);
3641 i::Handle<i::Object> result = i::Factory::NewReferenceError(message);
3642 error = *result;
3643 }
3644 i::Handle<i::Object> result(error);
3645 return Utils::ToLocal(result);
3646}
3647
3648Local<Value> Exception::SyntaxError(v8::Handle<v8::String> raw_message) {
3649 LOG_API("SyntaxError");
3650 ON_BAILOUT("v8::Exception::SyntaxError()", return Local<Value>());
3651 ENTER_V8;
3652 i::Object* error;
3653 {
3654 HandleScope scope;
3655 i::Handle<i::String> message = Utils::OpenHandle(*raw_message);
3656 i::Handle<i::Object> result = i::Factory::NewSyntaxError(message);
3657 error = *result;
3658 }
3659 i::Handle<i::Object> result(error);
3660 return Utils::ToLocal(result);
3661}
3662
3663Local<Value> Exception::TypeError(v8::Handle<v8::String> raw_message) {
3664 LOG_API("TypeError");
3665 ON_BAILOUT("v8::Exception::TypeError()", return Local<Value>());
3666 ENTER_V8;
3667 i::Object* error;
3668 {
3669 HandleScope scope;
3670 i::Handle<i::String> message = Utils::OpenHandle(*raw_message);
3671 i::Handle<i::Object> result = i::Factory::NewTypeError(message);
3672 error = *result;
3673 }
3674 i::Handle<i::Object> result(error);
3675 return Utils::ToLocal(result);
3676}
3677
3678Local<Value> Exception::Error(v8::Handle<v8::String> raw_message) {
3679 LOG_API("Error");
3680 ON_BAILOUT("v8::Exception::Error()", return Local<Value>());
3681 ENTER_V8;
3682 i::Object* error;
3683 {
3684 HandleScope scope;
3685 i::Handle<i::String> message = Utils::OpenHandle(*raw_message);
3686 i::Handle<i::Object> result = i::Factory::NewError(message);
3687 error = *result;
3688 }
3689 i::Handle<i::Object> result(error);
3690 return Utils::ToLocal(result);
3691}
3692
3693
3694// --- D e b u g S u p p o r t ---
3695
3696#ifdef ENABLE_DEBUGGER_SUPPORT
3697bool Debug::SetDebugEventListener(EventCallback that, Handle<Value> data) {
3698 EnsureInitialized("v8::Debug::SetDebugEventListener()");
3699 ON_BAILOUT("v8::Debug::SetDebugEventListener()", return false);
3700 ENTER_V8;
3701 HandleScope scope;
3702 i::Handle<i::Object> proxy = i::Factory::undefined_value();
3703 if (that != NULL) {
3704 proxy = i::Factory::NewProxy(FUNCTION_ADDR(that));
3705 }
3706 i::Debugger::SetEventListener(proxy, Utils::OpenHandle(*data));
3707 return true;
3708}
3709
3710
3711bool Debug::SetDebugEventListener(v8::Handle<v8::Object> that,
3712 Handle<Value> data) {
3713 ON_BAILOUT("v8::Debug::SetDebugEventListener()", return false);
3714 ENTER_V8;
3715 i::Debugger::SetEventListener(Utils::OpenHandle(*that),
3716 Utils::OpenHandle(*data));
3717 return true;
3718}
3719
3720
3721void Debug::DebugBreak() {
3722 if (!i::V8::IsRunning()) return;
3723 i::StackGuard::DebugBreak();
3724}
3725
3726
3727static v8::Debug::MessageHandler message_handler = NULL;
3728
3729static void MessageHandlerWrapper(const v8::Debug::Message& message) {
3730 if (message_handler) {
3731 v8::String::Value json(message.GetJSON());
3732 message_handler(*json, json.length(), message.GetClientData());
3733 }
3734}
3735
3736
3737void Debug::SetMessageHandler(v8::Debug::MessageHandler handler,
3738 bool message_handler_thread) {
3739 EnsureInitialized("v8::Debug::SetMessageHandler");
3740 ENTER_V8;
3741 // Message handler thread not supported any more. Parameter temporally left in
3742 // the API for client compatability reasons.
3743 CHECK(!message_handler_thread);
3744
3745 // TODO(sgjesse) support the old message handler API through a simple wrapper.
3746 message_handler = handler;
3747 if (message_handler != NULL) {
3748 i::Debugger::SetMessageHandler(MessageHandlerWrapper);
3749 } else {
3750 i::Debugger::SetMessageHandler(NULL);
3751 }
3752}
3753
3754
3755void Debug::SetMessageHandler2(v8::Debug::MessageHandler2 handler) {
3756 EnsureInitialized("v8::Debug::SetMessageHandler");
3757 ENTER_V8;
3758 HandleScope scope;
3759 i::Debugger::SetMessageHandler(handler);
3760}
3761
3762
3763void Debug::SendCommand(const uint16_t* command, int length,
3764 ClientData* client_data) {
3765 if (!i::V8::IsRunning()) return;
3766 i::Debugger::ProcessCommand(i::Vector<const uint16_t>(command, length),
3767 client_data);
3768}
3769
3770
3771void Debug::SetHostDispatchHandler(HostDispatchHandler handler,
3772 int period) {
3773 EnsureInitialized("v8::Debug::SetHostDispatchHandler");
3774 ENTER_V8;
3775 i::Debugger::SetHostDispatchHandler(handler, period);
3776}
3777
3778
Steve Blockd0582a62009-12-15 09:54:21 +00003779void Debug::SetDebugMessageDispatchHandler(
3780 DebugMessageDispatchHandler handler) {
3781 EnsureInitialized("v8::Debug::SetDebugMessageDispatchHandler");
3782 ENTER_V8;
3783 i::Debugger::SetDebugMessageDispatchHandler(handler);
3784}
3785
3786
Steve Blocka7e24c12009-10-30 11:49:00 +00003787Local<Value> Debug::Call(v8::Handle<v8::Function> fun,
3788 v8::Handle<v8::Value> data) {
3789 if (!i::V8::IsRunning()) return Local<Value>();
3790 ON_BAILOUT("v8::Debug::Call()", return Local<Value>());
3791 ENTER_V8;
3792 i::Handle<i::Object> result;
3793 EXCEPTION_PREAMBLE();
3794 if (data.IsEmpty()) {
3795 result = i::Debugger::Call(Utils::OpenHandle(*fun),
3796 i::Factory::undefined_value(),
3797 &has_pending_exception);
3798 } else {
3799 result = i::Debugger::Call(Utils::OpenHandle(*fun),
3800 Utils::OpenHandle(*data),
3801 &has_pending_exception);
3802 }
3803 EXCEPTION_BAILOUT_CHECK(Local<Value>());
3804 return Utils::ToLocal(result);
3805}
3806
3807
3808Local<Value> Debug::GetMirror(v8::Handle<v8::Value> obj) {
3809 if (!i::V8::IsRunning()) return Local<Value>();
3810 ON_BAILOUT("v8::Debug::GetMirror()", return Local<Value>());
3811 ENTER_V8;
3812 v8::HandleScope scope;
3813 i::Debug::Load();
3814 i::Handle<i::JSObject> debug(i::Debug::debug_context()->global());
3815 i::Handle<i::String> name = i::Factory::LookupAsciiSymbol("MakeMirror");
3816 i::Handle<i::Object> fun_obj = i::GetProperty(debug, name);
3817 i::Handle<i::JSFunction> fun = i::Handle<i::JSFunction>::cast(fun_obj);
3818 v8::Handle<v8::Function> v8_fun = Utils::ToLocal(fun);
3819 const int kArgc = 1;
3820 v8::Handle<v8::Value> argv[kArgc] = { obj };
3821 EXCEPTION_PREAMBLE();
3822 v8::Handle<v8::Value> result = v8_fun->Call(Utils::ToLocal(debug),
3823 kArgc,
3824 argv);
3825 EXCEPTION_BAILOUT_CHECK(Local<Value>());
3826 return scope.Close(result);
3827}
3828
3829
3830bool Debug::EnableAgent(const char* name, int port) {
3831 return i::Debugger::StartAgent(name, port);
3832}
3833#endif // ENABLE_DEBUGGER_SUPPORT
3834
3835namespace internal {
3836
3837
3838HandleScopeImplementer* HandleScopeImplementer::instance() {
3839 return &thread_local;
3840}
3841
3842
3843void HandleScopeImplementer::FreeThreadResources() {
3844 thread_local.Free();
3845}
3846
3847
3848char* HandleScopeImplementer::ArchiveThread(char* storage) {
3849 return thread_local.ArchiveThreadHelper(storage);
3850}
3851
3852
3853char* HandleScopeImplementer::ArchiveThreadHelper(char* storage) {
3854 v8::ImplementationUtilities::HandleScopeData* current =
3855 v8::ImplementationUtilities::CurrentHandleScope();
3856 handle_scope_data_ = *current;
3857 memcpy(storage, this, sizeof(*this));
3858
3859 ResetAfterArchive();
3860 current->Initialize();
3861
3862 return storage + ArchiveSpacePerThread();
3863}
3864
3865
3866int HandleScopeImplementer::ArchiveSpacePerThread() {
3867 return sizeof(thread_local);
3868}
3869
3870
3871char* HandleScopeImplementer::RestoreThread(char* storage) {
3872 return thread_local.RestoreThreadHelper(storage);
3873}
3874
3875
3876char* HandleScopeImplementer::RestoreThreadHelper(char* storage) {
3877 memcpy(this, storage, sizeof(*this));
3878 *v8::ImplementationUtilities::CurrentHandleScope() = handle_scope_data_;
3879 return storage + ArchiveSpacePerThread();
3880}
3881
3882
3883void HandleScopeImplementer::IterateThis(ObjectVisitor* v) {
3884 // Iterate over all handles in the blocks except for the last.
3885 for (int i = blocks()->length() - 2; i >= 0; --i) {
3886 Object** block = blocks()->at(i);
3887 v->VisitPointers(block, &block[kHandleBlockSize]);
3888 }
3889
3890 // Iterate over live handles in the last block (if any).
3891 if (!blocks()->is_empty()) {
3892 v->VisitPointers(blocks()->last(), handle_scope_data_.next);
3893 }
3894
3895 if (!saved_contexts_.is_empty()) {
3896 Object** start = reinterpret_cast<Object**>(&saved_contexts_.first());
3897 v->VisitPointers(start, start + saved_contexts_.length());
3898 }
3899}
3900
3901
3902void HandleScopeImplementer::Iterate(ObjectVisitor* v) {
3903 v8::ImplementationUtilities::HandleScopeData* current =
3904 v8::ImplementationUtilities::CurrentHandleScope();
3905 thread_local.handle_scope_data_ = *current;
3906 thread_local.IterateThis(v);
3907}
3908
3909
3910char* HandleScopeImplementer::Iterate(ObjectVisitor* v, char* storage) {
3911 HandleScopeImplementer* thread_local =
3912 reinterpret_cast<HandleScopeImplementer*>(storage);
3913 thread_local->IterateThis(v);
3914 return storage + ArchiveSpacePerThread();
3915}
3916
3917} } // namespace v8::internal