1 // Copyright 2008 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 #ifndef V8_API_H_ 29 #define V8_API_H_ 30 31 #include "apiutils.h" 32 #include "factory.h" 33 34 namespace v8 { 35 36 // Constants used in the implementation of the API. The most natural thing 37 // would usually be to place these with the classes that use them, but 38 // we want to keep them out of v8.h because it is an externally 39 // visible file. 40 class Consts { 41 public: 42 enum TemplateType { 43 FUNCTION_TEMPLATE = 0, 44 OBJECT_TEMPLATE = 1 45 }; 46 }; 47 48 49 // Utilities for working with neander-objects, primitive 50 // env-independent JSObjects used by the api. 51 class NeanderObject { 52 public: 53 explicit NeanderObject(int size); 54 inline NeanderObject(v8::internal::Handle<v8::internal::Object> obj); 55 inline NeanderObject(v8::internal::Object* obj); 56 inline v8::internal::Object* get(int index); 57 inline void set(int index, v8::internal::Object* value); 58 inline v8::internal::Handle<v8::internal::JSObject> value() { return value_; } 59 int size(); 60 private: 61 v8::internal::Handle<v8::internal::JSObject> value_; 62 }; 63 64 65 // Utilities for working with neander-arrays, a simple extensible 66 // array abstraction built on neander-objects. 67 class NeanderArray { 68 public: 69 NeanderArray(); 70 inline NeanderArray(v8::internal::Handle<v8::internal::Object> obj); 71 inline v8::internal::Handle<v8::internal::JSObject> value() { 72 return obj_.value(); 73 } 74 75 void add(v8::internal::Handle<v8::internal::Object> value); 76 77 int length(); 78 79 v8::internal::Object* get(int index); 80 // Change the value at an index to undefined value. If the index is 81 // out of bounds, the request is ignored. Returns the old value. 82 void set(int index, v8::internal::Object* value); 83 private: 84 NeanderObject obj_; 85 }; 86 87 88 NeanderObject::NeanderObject(v8::internal::Handle<v8::internal::Object> obj) 89 : value_(v8::internal::Handle<v8::internal::JSObject>::cast(obj)) { } 90 91 92 NeanderObject::NeanderObject(v8::internal::Object* obj) 93 : value_(v8::internal::Handle<v8::internal::JSObject>( 94 v8::internal::JSObject::cast(obj))) { } 95 96 97 NeanderArray::NeanderArray(v8::internal::Handle<v8::internal::Object> obj) 98 : obj_(obj) { } 99 100 101 v8::internal::Object* NeanderObject::get(int offset) { 102 ASSERT(value()->HasFastElements()); 103 return v8::internal::FixedArray::cast(value()->elements())->get(offset); 104 } 105 106 107 void NeanderObject::set(int offset, v8::internal::Object* value) { 108 ASSERT(value_->HasFastElements()); 109 v8::internal::FixedArray::cast(value_->elements())->set(offset, value); 110 } 111 112 113 template <typename T> static inline T ToCData(v8::internal::Object* obj) { 114 STATIC_ASSERT(sizeof(T) == sizeof(v8::internal::Address)); 115 return reinterpret_cast<T>( 116 reinterpret_cast<intptr_t>(v8::internal::Proxy::cast(obj)->proxy())); 117 } 118 119 120 template <typename T> 121 static inline v8::internal::Handle<v8::internal::Object> FromCData(T obj) { 122 STATIC_ASSERT(sizeof(T) == sizeof(v8::internal::Address)); 123 return v8::internal::Factory::NewProxy( 124 reinterpret_cast<v8::internal::Address>(reinterpret_cast<intptr_t>(obj))); 125 } 126 127 128 class ApiFunction { 129 public: 130 explicit ApiFunction(v8::internal::Address addr) : addr_(addr) { } 131 v8::internal::Address address() { return addr_; } 132 private: 133 v8::internal::Address addr_; 134 }; 135 136 137 v8::Arguments::Arguments(v8::Local<v8::Value> data, 138 v8::Local<v8::Object> holder, 139 v8::Local<v8::Function> callee, 140 bool is_construct_call, 141 void** values, int length) 142 : data_(data), holder_(holder), callee_(callee), 143 is_construct_call_(is_construct_call), 144 values_(values), length_(length) { } 145 146 147 enum ExtensionTraversalState { 148 UNVISITED, VISITED, INSTALLED 149 }; 150 151 152 class RegisteredExtension { 153 public: 154 explicit RegisteredExtension(Extension* extension); 155 static void Register(RegisteredExtension* that); 156 Extension* extension() { return extension_; } 157 RegisteredExtension* next() { return next_; } 158 RegisteredExtension* next_auto() { return next_auto_; } 159 ExtensionTraversalState state() { return state_; } 160 void set_state(ExtensionTraversalState value) { state_ = value; } 161 static RegisteredExtension* first_extension() { return first_extension_; } 162 private: 163 Extension* extension_; 164 RegisteredExtension* next_; 165 RegisteredExtension* next_auto_; 166 ExtensionTraversalState state_; 167 static RegisteredExtension* first_extension_; 168 static RegisteredExtension* first_auto_extension_; 169 }; 170 171 172 class Utils { 173 public: 174 static bool ReportApiFailure(const char* location, const char* message); 175 176 static Local<FunctionTemplate> ToFunctionTemplate(NeanderObject obj); 177 static Local<ObjectTemplate> ToObjectTemplate(NeanderObject obj); 178 179 static inline Local<Context> ToLocal( 180 v8::internal::Handle<v8::internal::Context> obj); 181 static inline Local<Value> ToLocal( 182 v8::internal::Handle<v8::internal::Object> obj); 183 static inline Local<Function> ToLocal( 184 v8::internal::Handle<v8::internal::JSFunction> obj); 185 static inline Local<String> ToLocal( 186 v8::internal::Handle<v8::internal::String> obj); 187 static inline Local<Object> ToLocal( 188 v8::internal::Handle<v8::internal::JSObject> obj); 189 static inline Local<Array> ToLocal( 190 v8::internal::Handle<v8::internal::JSArray> obj); 191 static inline Local<External> ToLocal( 192 v8::internal::Handle<v8::internal::Proxy> obj); 193 static inline Local<Message> MessageToLocal( 194 v8::internal::Handle<v8::internal::Object> obj); 195 static inline Local<Number> NumberToLocal( 196 v8::internal::Handle<v8::internal::Object> obj); 197 static inline Local<Integer> IntegerToLocal( 198 v8::internal::Handle<v8::internal::Object> obj); 199 static inline Local<Uint32> Uint32ToLocal( 200 v8::internal::Handle<v8::internal::Object> obj); 201 static inline Local<FunctionTemplate> ToLocal( 202 v8::internal::Handle<v8::internal::FunctionTemplateInfo> obj); 203 static inline Local<ObjectTemplate> ToLocal( 204 v8::internal::Handle<v8::internal::ObjectTemplateInfo> obj); 205 static inline Local<Signature> ToLocal( 206 v8::internal::Handle<v8::internal::SignatureInfo> obj); 207 static inline Local<TypeSwitch> ToLocal( 208 v8::internal::Handle<v8::internal::TypeSwitchInfo> obj); 209 210 static inline v8::internal::Handle<v8::internal::TemplateInfo> 211 OpenHandle(const Template* that); 212 static inline v8::internal::Handle<v8::internal::FunctionTemplateInfo> 213 OpenHandle(const FunctionTemplate* that); 214 static inline v8::internal::Handle<v8::internal::ObjectTemplateInfo> 215 OpenHandle(const ObjectTemplate* that); 216 static inline v8::internal::Handle<v8::internal::Object> 217 OpenHandle(const Data* data); 218 static inline v8::internal::Handle<v8::internal::JSObject> 219 OpenHandle(const v8::Object* data); 220 static inline v8::internal::Handle<v8::internal::JSArray> 221 OpenHandle(const v8::Array* data); 222 static inline v8::internal::Handle<v8::internal::String> 223 OpenHandle(const String* data); 224 static inline v8::internal::Handle<v8::internal::JSFunction> 225 OpenHandle(const Script* data); 226 static inline v8::internal::Handle<v8::internal::JSFunction> 227 OpenHandle(const Function* data); 228 static inline v8::internal::Handle<v8::internal::JSObject> 229 OpenHandle(const Message* message); 230 static inline v8::internal::Handle<v8::internal::Context> 231 OpenHandle(const v8::Context* context); 232 static inline v8::internal::Handle<v8::internal::SignatureInfo> 233 OpenHandle(const v8::Signature* sig); 234 static inline v8::internal::Handle<v8::internal::TypeSwitchInfo> 235 OpenHandle(const v8::TypeSwitch* that); 236 static inline v8::internal::Handle<v8::internal::Proxy> 237 OpenHandle(const v8::External* that); 238 }; 239 240 241 template <class T> 242 static inline T* ToApi(v8::internal::Handle<v8::internal::Object> obj) { 243 return reinterpret_cast<T*>(obj.location()); 244 } 245 246 247 template <class T> 248 v8::internal::Handle<T> v8::internal::Handle<T>::EscapeFrom( 249 v8::HandleScope* scope) { 250 return Utils::OpenHandle(*scope->Close(Utils::ToLocal(*this))); 251 } 252 253 254 // Implementations of ToLocal 255 256 #define MAKE_TO_LOCAL(Name, From, To) \ 257 Local<v8::To> Utils::Name(v8::internal::Handle<v8::internal::From> obj) { \ 258 ASSERT(!obj->IsTheHole()); \ 259 return Local<To>(reinterpret_cast<To*>(obj.location())); \ 260 } 261 262 MAKE_TO_LOCAL(ToLocal, Context, Context) 263 MAKE_TO_LOCAL(ToLocal, Object, Value) 264 MAKE_TO_LOCAL(ToLocal, JSFunction, Function) 265 MAKE_TO_LOCAL(ToLocal, String, String) 266 MAKE_TO_LOCAL(ToLocal, JSObject, Object) 267 MAKE_TO_LOCAL(ToLocal, JSArray, Array) 268 MAKE_TO_LOCAL(ToLocal, Proxy, External) 269 MAKE_TO_LOCAL(ToLocal, FunctionTemplateInfo, FunctionTemplate) 270 MAKE_TO_LOCAL(ToLocal, ObjectTemplateInfo, ObjectTemplate) 271 MAKE_TO_LOCAL(ToLocal, SignatureInfo, Signature) 272 MAKE_TO_LOCAL(ToLocal, TypeSwitchInfo, TypeSwitch) 273 MAKE_TO_LOCAL(MessageToLocal, Object, Message) 274 MAKE_TO_LOCAL(NumberToLocal, Object, Number) 275 MAKE_TO_LOCAL(IntegerToLocal, Object, Integer) 276 MAKE_TO_LOCAL(Uint32ToLocal, Object, Uint32) 277 278 #undef MAKE_TO_LOCAL 279 280 281 // Implementations of OpenHandle 282 283 #define MAKE_OPEN_HANDLE(From, To) \ 284 v8::internal::Handle<v8::internal::To> Utils::OpenHandle(\ 285 const v8::From* that) { \ 286 return v8::internal::Handle<v8::internal::To>( \ 287 reinterpret_cast<v8::internal::To**>(const_cast<v8::From*>(that))); \ 288 } 289 290 MAKE_OPEN_HANDLE(Template, TemplateInfo) 291 MAKE_OPEN_HANDLE(FunctionTemplate, FunctionTemplateInfo) 292 MAKE_OPEN_HANDLE(ObjectTemplate, ObjectTemplateInfo) 293 MAKE_OPEN_HANDLE(Signature, SignatureInfo) 294 MAKE_OPEN_HANDLE(TypeSwitch, TypeSwitchInfo) 295 MAKE_OPEN_HANDLE(Data, Object) 296 MAKE_OPEN_HANDLE(Object, JSObject) 297 MAKE_OPEN_HANDLE(Array, JSArray) 298 MAKE_OPEN_HANDLE(String, String) 299 MAKE_OPEN_HANDLE(Script, JSFunction) 300 MAKE_OPEN_HANDLE(Function, JSFunction) 301 MAKE_OPEN_HANDLE(Message, JSObject) 302 MAKE_OPEN_HANDLE(Context, Context) 303 MAKE_OPEN_HANDLE(External, Proxy) 304 305 #undef MAKE_OPEN_HANDLE 306 307 308 namespace internal { 309 310 // This class is here in order to be able to declare it a friend of 311 // HandleScope. Moving these methods to be members of HandleScope would be 312 // neat in some ways, but it would expose external implementation details in 313 // our public header file, which is undesirable. 314 // 315 // There is a singleton instance of this class to hold the per-thread data. 316 // For multithreaded V8 programs this data is copied in and out of storage 317 // so that the currently executing thread always has its own copy of this 318 // data. 319 class HandleScopeImplementer { 320 public: 321 322 HandleScopeImplementer() 323 : blocks_(0), 324 entered_contexts_(0), 325 saved_contexts_(0), 326 spare_(NULL), 327 ignore_out_of_memory_(false), 328 call_depth_(0) { } 329 330 static HandleScopeImplementer* instance(); 331 332 // Threading support for handle data. 333 static int ArchiveSpacePerThread(); 334 static char* RestoreThread(char* from); 335 static char* ArchiveThread(char* to); 336 static void FreeThreadResources(); 337 338 // Garbage collection support. 339 static void Iterate(v8::internal::ObjectVisitor* v); 340 static char* Iterate(v8::internal::ObjectVisitor* v, char* data); 341 342 343 inline internal::Object** GetSpareOrNewBlock(); 344 inline void DeleteExtensions(int extensions); 345 346 inline void IncrementCallDepth() {call_depth_++;} 347 inline void DecrementCallDepth() {call_depth_--;} 348 inline bool CallDepthIsZero() { return call_depth_ == 0; } 349 350 inline void EnterContext(Handle<Object> context); 351 inline bool LeaveLastContext(); 352 353 // Returns the last entered context or an empty handle if no 354 // contexts have been entered. 355 inline Handle<Object> LastEnteredContext(); 356 357 inline void SaveContext(Context* context); 358 inline Context* RestoreContext(); 359 inline bool HasSavedContexts(); 360 361 inline List<internal::Object**>* blocks() { return &blocks_; } 362 inline bool ignore_out_of_memory() { return ignore_out_of_memory_; } 363 inline void set_ignore_out_of_memory(bool value) { 364 ignore_out_of_memory_ = value; 365 } 366 367 private: 368 void ResetAfterArchive() { 369 blocks_.Initialize(0); 370 entered_contexts_.Initialize(0); 371 saved_contexts_.Initialize(0); 372 spare_ = NULL; 373 ignore_out_of_memory_ = false; 374 call_depth_ = 0; 375 } 376 377 void Free() { 378 ASSERT(blocks_.length() == 0); 379 ASSERT(entered_contexts_.length() == 0); 380 ASSERT(saved_contexts_.length() == 0); 381 blocks_.Free(); 382 entered_contexts_.Free(); 383 saved_contexts_.Free(); 384 if (spare_ != NULL) { 385 DeleteArray(spare_); 386 spare_ = NULL; 387 } 388 ASSERT(call_depth_ == 0); 389 } 390 391 List<internal::Object**> blocks_; 392 // Used as a stack to keep track of entered contexts. 393 List<Handle<Object> > entered_contexts_; 394 // Used as a stack to keep track of saved contexts. 395 List<Context*> saved_contexts_; 396 Object** spare_; 397 bool ignore_out_of_memory_; 398 int call_depth_; 399 // This is only used for threading support. 400 v8::ImplementationUtilities::HandleScopeData handle_scope_data_; 401 402 void IterateThis(ObjectVisitor* v); 403 char* RestoreThreadHelper(char* from); 404 char* ArchiveThreadHelper(char* to); 405 406 DISALLOW_COPY_AND_ASSIGN(HandleScopeImplementer); 407 }; 408 409 410 static const int kHandleBlockSize = v8::internal::KB - 2; // fit in one page 411 412 413 void HandleScopeImplementer::SaveContext(Context* context) { 414 saved_contexts_.Add(context); 415 } 416 417 418 Context* HandleScopeImplementer::RestoreContext() { 419 return saved_contexts_.RemoveLast(); 420 } 421 422 423 bool HandleScopeImplementer::HasSavedContexts() { 424 return !saved_contexts_.is_empty(); 425 } 426 427 428 void HandleScopeImplementer::EnterContext(Handle<Object> context) { 429 entered_contexts_.Add(context); 430 } 431 432 433 bool HandleScopeImplementer::LeaveLastContext() { 434 if (entered_contexts_.is_empty()) return false; 435 entered_contexts_.RemoveLast(); 436 return true; 437 } 438 439 440 Handle<Object> HandleScopeImplementer::LastEnteredContext() { 441 if (entered_contexts_.is_empty()) return Handle<Object>::null(); 442 return entered_contexts_.last(); 443 } 444 445 446 // If there's a spare block, use it for growing the current scope. 447 internal::Object** HandleScopeImplementer::GetSpareOrNewBlock() { 448 internal::Object** block = (spare_ != NULL) ? 449 spare_ : 450 NewArray<internal::Object*>(kHandleBlockSize); 451 spare_ = NULL; 452 return block; 453 } 454 455 456 void HandleScopeImplementer::DeleteExtensions(int extensions) { 457 if (spare_ != NULL) { 458 DeleteArray(spare_); 459 spare_ = NULL; 460 } 461 for (int i = extensions; i > 1; --i) { 462 internal::Object** block = blocks_.RemoveLast(); 463 #ifdef DEBUG 464 v8::ImplementationUtilities::ZapHandleRange(block, 465 &block[kHandleBlockSize]); 466 #endif 467 DeleteArray(block); 468 } 469 spare_ = blocks_.RemoveLast(); 470 #ifdef DEBUG 471 v8::ImplementationUtilities::ZapHandleRange( 472 spare_, 473 &spare_[kHandleBlockSize]); 474 #endif 475 } 476 477 } } // namespace v8::internal 478 479 #endif // V8_API_H_ 480