1 // Copyright 2012 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 #ifndef V8_API_H_ 29 #define V8_API_H_ 30 31 #include "v8.h" 32 33 #include "../include/v8-testing.h" 34 #include "apiutils.h" 35 #include "contexts.h" 36 #include "factory.h" 37 #include "isolate.h" 38 #include "list-inl.h" 39 40 namespace v8 { 41 42 // Constants used in the implementation of the API. The most natural thing 43 // would usually be to place these with the classes that use them, but 44 // we want to keep them out of v8.h because it is an externally 45 // visible file. 46 class Consts { 47 public: 48 enum TemplateType { 49 FUNCTION_TEMPLATE = 0, 50 OBJECT_TEMPLATE = 1 51 }; 52 }; 53 54 55 // Utilities for working with neander-objects, primitive 56 // env-independent JSObjects used by the api. 57 class NeanderObject { 58 public: 59 explicit NeanderObject(int size); 60 explicit inline NeanderObject(v8::internal::Handle<v8::internal::Object> obj); 61 explicit inline NeanderObject(v8::internal::Object* obj); 62 inline v8::internal::Object* get(int index); 63 inline void set(int index, v8::internal::Object* value); 64 inline v8::internal::Handle<v8::internal::JSObject> value() { return value_; } 65 int size(); 66 private: 67 v8::internal::Handle<v8::internal::JSObject> value_; 68 }; 69 70 71 // Utilities for working with neander-arrays, a simple extensible 72 // array abstraction built on neander-objects. 73 class NeanderArray { 74 public: 75 NeanderArray(); 76 explicit inline NeanderArray(v8::internal::Handle<v8::internal::Object> obj); 77 inline v8::internal::Handle<v8::internal::JSObject> value() { 78 return obj_.value(); 79 } 80 81 void add(v8::internal::Handle<v8::internal::Object> value); 82 83 int length(); 84 85 v8::internal::Object* get(int index); 86 // Change the value at an index to undefined value. If the index is 87 // out of bounds, the request is ignored. Returns the old value. 88 void set(int index, v8::internal::Object* value); 89 private: 90 NeanderObject obj_; 91 }; 92 93 94 NeanderObject::NeanderObject(v8::internal::Handle<v8::internal::Object> obj) 95 : value_(v8::internal::Handle<v8::internal::JSObject>::cast(obj)) { } 96 97 98 NeanderObject::NeanderObject(v8::internal::Object* obj) 99 : value_(v8::internal::Handle<v8::internal::JSObject>( 100 v8::internal::JSObject::cast(obj))) { } 101 102 103 NeanderArray::NeanderArray(v8::internal::Handle<v8::internal::Object> obj) 104 : obj_(obj) { } 105 106 107 v8::internal::Object* NeanderObject::get(int offset) { 108 ASSERT(value()->HasFastElements()); 109 return v8::internal::FixedArray::cast(value()->elements())->get(offset); 110 } 111 112 113 void NeanderObject::set(int offset, v8::internal::Object* value) { 114 ASSERT(value_->HasFastElements()); 115 v8::internal::FixedArray::cast(value_->elements())->set(offset, value); 116 } 117 118 119 template <typename T> inline T ToCData(v8::internal::Object* obj) { 120 STATIC_ASSERT(sizeof(T) == sizeof(v8::internal::Address)); 121 return reinterpret_cast<T>( 122 reinterpret_cast<intptr_t>( 123 v8::internal::Foreign::cast(obj)->foreign_address())); 124 } 125 126 127 template <typename T> 128 inline v8::internal::Handle<v8::internal::Object> FromCData(T obj) { 129 STATIC_ASSERT(sizeof(T) == sizeof(v8::internal::Address)); 130 return FACTORY->NewForeign( 131 reinterpret_cast<v8::internal::Address>(reinterpret_cast<intptr_t>(obj))); 132 } 133 134 135 class ApiFunction { 136 public: 137 explicit ApiFunction(v8::internal::Address addr) : addr_(addr) { } 138 v8::internal::Address address() { return addr_; } 139 private: 140 v8::internal::Address addr_; 141 }; 142 143 144 145 class RegisteredExtension { 146 public: 147 explicit RegisteredExtension(Extension* extension); 148 static void Register(RegisteredExtension* that); 149 Extension* extension() { return extension_; } 150 RegisteredExtension* next() { return next_; } 151 RegisteredExtension* next_auto() { return next_auto_; } 152 static RegisteredExtension* first_extension() { return first_extension_; } 153 private: 154 Extension* extension_; 155 RegisteredExtension* next_; 156 RegisteredExtension* next_auto_; 157 static RegisteredExtension* first_extension_; 158 }; 159 160 161 class Utils { 162 public: 163 static bool ReportApiFailure(const char* location, const char* message); 164 165 static Local<FunctionTemplate> ToFunctionTemplate(NeanderObject obj); 166 static Local<ObjectTemplate> ToObjectTemplate(NeanderObject obj); 167 168 static inline Local<Context> ToLocal( 169 v8::internal::Handle<v8::internal::Context> obj); 170 static inline Local<Value> ToLocal( 171 v8::internal::Handle<v8::internal::Object> obj); 172 static inline Local<Function> ToLocal( 173 v8::internal::Handle<v8::internal::JSFunction> obj); 174 static inline Local<String> ToLocal( 175 v8::internal::Handle<v8::internal::String> obj); 176 static inline Local<RegExp> ToLocal( 177 v8::internal::Handle<v8::internal::JSRegExp> obj); 178 static inline Local<Object> ToLocal( 179 v8::internal::Handle<v8::internal::JSObject> obj); 180 static inline Local<Array> ToLocal( 181 v8::internal::Handle<v8::internal::JSArray> obj); 182 static inline Local<External> ToLocal( 183 v8::internal::Handle<v8::internal::Foreign> obj); 184 static inline Local<Message> MessageToLocal( 185 v8::internal::Handle<v8::internal::Object> obj); 186 static inline Local<StackTrace> StackTraceToLocal( 187 v8::internal::Handle<v8::internal::JSArray> obj); 188 static inline Local<StackFrame> StackFrameToLocal( 189 v8::internal::Handle<v8::internal::JSObject> obj); 190 static inline Local<Number> NumberToLocal( 191 v8::internal::Handle<v8::internal::Object> obj); 192 static inline Local<Integer> IntegerToLocal( 193 v8::internal::Handle<v8::internal::Object> obj); 194 static inline Local<Uint32> Uint32ToLocal( 195 v8::internal::Handle<v8::internal::Object> obj); 196 static inline Local<FunctionTemplate> ToLocal( 197 v8::internal::Handle<v8::internal::FunctionTemplateInfo> obj); 198 static inline Local<ObjectTemplate> ToLocal( 199 v8::internal::Handle<v8::internal::ObjectTemplateInfo> obj); 200 static inline Local<Signature> ToLocal( 201 v8::internal::Handle<v8::internal::SignatureInfo> obj); 202 static inline Local<TypeSwitch> ToLocal( 203 v8::internal::Handle<v8::internal::TypeSwitchInfo> obj); 204 205 static inline v8::internal::Handle<v8::internal::TemplateInfo> 206 OpenHandle(const Template* that); 207 static inline v8::internal::Handle<v8::internal::FunctionTemplateInfo> 208 OpenHandle(const FunctionTemplate* that); 209 static inline v8::internal::Handle<v8::internal::ObjectTemplateInfo> 210 OpenHandle(const ObjectTemplate* that); 211 static inline v8::internal::Handle<v8::internal::Object> 212 OpenHandle(const Data* data); 213 static inline v8::internal::Handle<v8::internal::JSRegExp> 214 OpenHandle(const RegExp* data); 215 static inline v8::internal::Handle<v8::internal::JSObject> 216 OpenHandle(const v8::Object* data); 217 static inline v8::internal::Handle<v8::internal::JSArray> 218 OpenHandle(const v8::Array* data); 219 static inline v8::internal::Handle<v8::internal::String> 220 OpenHandle(const String* data); 221 static inline v8::internal::Handle<v8::internal::Object> 222 OpenHandle(const Script* data); 223 static inline v8::internal::Handle<v8::internal::JSFunction> 224 OpenHandle(const Function* data); 225 static inline v8::internal::Handle<v8::internal::JSObject> 226 OpenHandle(const Message* message); 227 static inline v8::internal::Handle<v8::internal::JSArray> 228 OpenHandle(const StackTrace* stack_trace); 229 static inline v8::internal::Handle<v8::internal::JSObject> 230 OpenHandle(const StackFrame* stack_frame); 231 static inline v8::internal::Handle<v8::internal::Context> 232 OpenHandle(const v8::Context* context); 233 static inline v8::internal::Handle<v8::internal::SignatureInfo> 234 OpenHandle(const v8::Signature* sig); 235 static inline v8::internal::Handle<v8::internal::TypeSwitchInfo> 236 OpenHandle(const v8::TypeSwitch* that); 237 static inline v8::internal::Handle<v8::internal::Foreign> 238 OpenHandle(const v8::External* that); 239 }; 240 241 242 template <class T> 243 inline T* ToApi(v8::internal::Handle<v8::internal::Object> obj) { 244 return reinterpret_cast<T*>(obj.location()); 245 } 246 247 248 template <class T> 249 v8::internal::Handle<T> v8::internal::Handle<T>::EscapeFrom( 250 v8::HandleScope* scope) { 251 v8::internal::Handle<T> handle; 252 if (!is_null()) { 253 handle = *this; 254 } 255 return Utils::OpenHandle(*scope->Close(Utils::ToLocal(handle))); 256 } 257 258 259 // Implementations of ToLocal 260 261 #define MAKE_TO_LOCAL(Name, From, To) \ 262 Local<v8::To> Utils::Name(v8::internal::Handle<v8::internal::From> obj) { \ 263 ASSERT(obj.is_null() || !obj->IsTheHole()); \ 264 return Local<To>(reinterpret_cast<To*>(obj.location())); \ 265 } 266 267 MAKE_TO_LOCAL(ToLocal, Context, Context) 268 MAKE_TO_LOCAL(ToLocal, Object, Value) 269 MAKE_TO_LOCAL(ToLocal, JSFunction, Function) 270 MAKE_TO_LOCAL(ToLocal, String, String) 271 MAKE_TO_LOCAL(ToLocal, JSRegExp, RegExp) 272 MAKE_TO_LOCAL(ToLocal, JSObject, Object) 273 MAKE_TO_LOCAL(ToLocal, JSArray, Array) 274 MAKE_TO_LOCAL(ToLocal, Foreign, External) 275 MAKE_TO_LOCAL(ToLocal, FunctionTemplateInfo, FunctionTemplate) 276 MAKE_TO_LOCAL(ToLocal, ObjectTemplateInfo, ObjectTemplate) 277 MAKE_TO_LOCAL(ToLocal, SignatureInfo, Signature) 278 MAKE_TO_LOCAL(ToLocal, TypeSwitchInfo, TypeSwitch) 279 MAKE_TO_LOCAL(MessageToLocal, Object, Message) 280 MAKE_TO_LOCAL(StackTraceToLocal, JSArray, StackTrace) 281 MAKE_TO_LOCAL(StackFrameToLocal, JSObject, StackFrame) 282 MAKE_TO_LOCAL(NumberToLocal, Object, Number) 283 MAKE_TO_LOCAL(IntegerToLocal, Object, Integer) 284 MAKE_TO_LOCAL(Uint32ToLocal, Object, Uint32) 285 286 #undef MAKE_TO_LOCAL 287 288 289 // Implementations of OpenHandle 290 291 #define MAKE_OPEN_HANDLE(From, To) \ 292 v8::internal::Handle<v8::internal::To> Utils::OpenHandle(\ 293 const v8::From* that) { \ 294 return v8::internal::Handle<v8::internal::To>( \ 295 reinterpret_cast<v8::internal::To**>(const_cast<v8::From*>(that))); \ 296 } 297 298 MAKE_OPEN_HANDLE(Template, TemplateInfo) 299 MAKE_OPEN_HANDLE(FunctionTemplate, FunctionTemplateInfo) 300 MAKE_OPEN_HANDLE(ObjectTemplate, ObjectTemplateInfo) 301 MAKE_OPEN_HANDLE(Signature, SignatureInfo) 302 MAKE_OPEN_HANDLE(TypeSwitch, TypeSwitchInfo) 303 MAKE_OPEN_HANDLE(Data, Object) 304 MAKE_OPEN_HANDLE(RegExp, JSRegExp) 305 MAKE_OPEN_HANDLE(Object, JSObject) 306 MAKE_OPEN_HANDLE(Array, JSArray) 307 MAKE_OPEN_HANDLE(String, String) 308 MAKE_OPEN_HANDLE(Script, Object) 309 MAKE_OPEN_HANDLE(Function, JSFunction) 310 MAKE_OPEN_HANDLE(Message, JSObject) 311 MAKE_OPEN_HANDLE(Context, Context) 312 MAKE_OPEN_HANDLE(External, Foreign) 313 MAKE_OPEN_HANDLE(StackTrace, JSArray) 314 MAKE_OPEN_HANDLE(StackFrame, JSObject) 315 316 #undef MAKE_OPEN_HANDLE 317 318 319 namespace internal { 320 321 // Tracks string usage to help make better decisions when 322 // externalizing strings. 323 // 324 // Implementation note: internally this class only tracks fresh 325 // strings and keeps a single use counter for them. 326 class StringTracker { 327 public: 328 // Records that the given string's characters were copied to some 329 // external buffer. If this happens often we should honor 330 // externalization requests for the string. 331 void RecordWrite(Handle<String> string) { 332 Address address = reinterpret_cast<Address>(*string); 333 Address top = isolate_->heap()->NewSpaceTop(); 334 if (IsFreshString(address, top)) { 335 IncrementUseCount(top); 336 } 337 } 338 339 // Estimates freshness and use frequency of the given string based 340 // on how close it is to the new space top and the recorded usage 341 // history. 342 inline bool IsFreshUnusedString(Handle<String> string) { 343 Address address = reinterpret_cast<Address>(*string); 344 Address top = isolate_->heap()->NewSpaceTop(); 345 return IsFreshString(address, top) && IsUseCountLow(top); 346 } 347 348 private: 349 StringTracker() : use_count_(0), last_top_(NULL), isolate_(NULL) { } 350 351 static inline bool IsFreshString(Address string, Address top) { 352 return top - kFreshnessLimit <= string && string <= top; 353 } 354 355 inline bool IsUseCountLow(Address top) { 356 if (last_top_ != top) return true; 357 return use_count_ < kUseLimit; 358 } 359 360 inline void IncrementUseCount(Address top) { 361 if (last_top_ != top) { 362 use_count_ = 0; 363 last_top_ = top; 364 } 365 ++use_count_; 366 } 367 368 // Single use counter shared by all fresh strings. 369 int use_count_; 370 371 // Last new space top when the use count above was valid. 372 Address last_top_; 373 374 Isolate* isolate_; 375 376 // How close to the new space top a fresh string has to be. 377 static const int kFreshnessLimit = 1024; 378 379 // The number of uses required to consider a string useful. 380 static const int kUseLimit = 32; 381 382 friend class Isolate; 383 384 DISALLOW_COPY_AND_ASSIGN(StringTracker); 385 }; 386 387 388 // This class is here in order to be able to declare it a friend of 389 // HandleScope. Moving these methods to be members of HandleScope would be 390 // neat in some ways, but it would expose internal implementation details in 391 // our public header file, which is undesirable. 392 // 393 // An isolate has a single instance of this class to hold the current thread's 394 // data. In multithreaded V8 programs this data is copied in and out of storage 395 // so that the currently executing thread always has its own copy of this 396 // data. 397 class HandleScopeImplementer { 398 public: 399 explicit HandleScopeImplementer(Isolate* isolate) 400 : isolate_(isolate), 401 blocks_(0), 402 entered_contexts_(0), 403 saved_contexts_(0), 404 spare_(NULL), 405 call_depth_(0) { } 406 407 ~HandleScopeImplementer() { 408 DeleteArray(spare_); 409 } 410 411 // Threading support for handle data. 412 static int ArchiveSpacePerThread(); 413 char* RestoreThread(char* from); 414 char* ArchiveThread(char* to); 415 void FreeThreadResources(); 416 417 // Garbage collection support. 418 void Iterate(v8::internal::ObjectVisitor* v); 419 static char* Iterate(v8::internal::ObjectVisitor* v, char* data); 420 421 422 inline internal::Object** GetSpareOrNewBlock(); 423 inline void DeleteExtensions(internal::Object** prev_limit); 424 425 inline void IncrementCallDepth() {call_depth_++;} 426 inline void DecrementCallDepth() {call_depth_--;} 427 inline bool CallDepthIsZero() { return call_depth_ == 0; } 428 429 inline void EnterContext(Handle<Object> context); 430 inline bool LeaveLastContext(); 431 432 // Returns the last entered context or an empty handle if no 433 // contexts have been entered. 434 inline Handle<Object> LastEnteredContext(); 435 436 inline void SaveContext(Context* context); 437 inline Context* RestoreContext(); 438 inline bool HasSavedContexts(); 439 440 inline List<internal::Object**>* blocks() { return &blocks_; } 441 442 private: 443 void ResetAfterArchive() { 444 blocks_.Initialize(0); 445 entered_contexts_.Initialize(0); 446 saved_contexts_.Initialize(0); 447 spare_ = NULL; 448 call_depth_ = 0; 449 } 450 451 void Free() { 452 ASSERT(blocks_.length() == 0); 453 ASSERT(entered_contexts_.length() == 0); 454 ASSERT(saved_contexts_.length() == 0); 455 blocks_.Free(); 456 entered_contexts_.Free(); 457 saved_contexts_.Free(); 458 if (spare_ != NULL) { 459 DeleteArray(spare_); 460 spare_ = NULL; 461 } 462 ASSERT(call_depth_ == 0); 463 } 464 465 Isolate* isolate_; 466 List<internal::Object**> blocks_; 467 // Used as a stack to keep track of entered contexts. 468 List<Handle<Object> > entered_contexts_; 469 // Used as a stack to keep track of saved contexts. 470 List<Context*> saved_contexts_; 471 Object** spare_; 472 int call_depth_; 473 // This is only used for threading support. 474 v8::ImplementationUtilities::HandleScopeData handle_scope_data_; 475 476 void IterateThis(ObjectVisitor* v); 477 char* RestoreThreadHelper(char* from); 478 char* ArchiveThreadHelper(char* to); 479 480 DISALLOW_COPY_AND_ASSIGN(HandleScopeImplementer); 481 }; 482 483 484 const int kHandleBlockSize = v8::internal::KB - 2; // fit in one page 485 486 487 void HandleScopeImplementer::SaveContext(Context* context) { 488 saved_contexts_.Add(context); 489 } 490 491 492 Context* HandleScopeImplementer::RestoreContext() { 493 return saved_contexts_.RemoveLast(); 494 } 495 496 497 bool HandleScopeImplementer::HasSavedContexts() { 498 return !saved_contexts_.is_empty(); 499 } 500 501 502 void HandleScopeImplementer::EnterContext(Handle<Object> context) { 503 entered_contexts_.Add(context); 504 } 505 506 507 bool HandleScopeImplementer::LeaveLastContext() { 508 if (entered_contexts_.is_empty()) return false; 509 entered_contexts_.RemoveLast(); 510 return true; 511 } 512 513 514 Handle<Object> HandleScopeImplementer::LastEnteredContext() { 515 if (entered_contexts_.is_empty()) return Handle<Object>::null(); 516 return entered_contexts_.last(); 517 } 518 519 520 // If there's a spare block, use it for growing the current scope. 521 internal::Object** HandleScopeImplementer::GetSpareOrNewBlock() { 522 internal::Object** block = (spare_ != NULL) ? 523 spare_ : 524 NewArray<internal::Object*>(kHandleBlockSize); 525 spare_ = NULL; 526 return block; 527 } 528 529 530 void HandleScopeImplementer::DeleteExtensions(internal::Object** prev_limit) { 531 while (!blocks_.is_empty()) { 532 internal::Object** block_start = blocks_.last(); 533 internal::Object** block_limit = block_start + kHandleBlockSize; 534 #ifdef DEBUG 535 // NoHandleAllocation may make the prev_limit to point inside the block. 536 if (block_start <= prev_limit && prev_limit <= block_limit) break; 537 #else 538 if (prev_limit == block_limit) break; 539 #endif 540 541 blocks_.RemoveLast(); 542 #ifdef DEBUG 543 v8::ImplementationUtilities::ZapHandleRange(block_start, block_limit); 544 #endif 545 if (spare_ != NULL) { 546 DeleteArray(spare_); 547 } 548 spare_ = block_start; 549 } 550 ASSERT((blocks_.is_empty() && prev_limit == NULL) || 551 (!blocks_.is_empty() && prev_limit != NULL)); 552 } 553 554 555 class Testing { 556 public: 557 static v8::Testing::StressType stress_type() { return stress_type_; } 558 static void set_stress_type(v8::Testing::StressType stress_type) { 559 stress_type_ = stress_type; 560 } 561 562 private: 563 static v8::Testing::StressType stress_type_; 564 }; 565 566 } } // namespace v8::internal 567 568 #endif // V8_API_H_ 569