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