Index: include/v8.h |
=================================================================== |
--- include/v8.h (revision 2749) |
+++ include/v8.h (working copy) |
@@ -127,7 +127,13 @@ |
class ObjectTemplate; |
class Data; |
+namespace internal { |
+class Object; |
+ |
+} |
+ |
+ |
// --- W e a k H a n d l e s |
@@ -227,8 +233,8 @@ |
* The handles' references are not checked. |
*/ |
template <class S> bool operator==(Handle<S> that) const { |
- void** a = reinterpret_cast<void**>(**this); |
- void** b = reinterpret_cast<void**>(*that); |
+ internal::Object** a = reinterpret_cast<internal::Object**>(**this); |
+ internal::Object** b = reinterpret_cast<internal::Object**>(*that); |
if (a == 0) return b == 0; |
if (b == 0) return false; |
return *a == *b; |
@@ -245,7 +251,11 @@ |
} |
template <class S> static inline Handle<T> Cast(Handle<S> that) { |
+#ifdef V8_ENABLE_CHECKS |
+ // If we're going to perform the type check then we have to check |
+ // that the handle isn't empty before doing the checked cast. |
if (that.IsEmpty()) return Handle<T>(); |
+#endif |
return Handle<T>(T::Cast(*that)); |
} |
@@ -275,7 +285,11 @@ |
} |
template <class S> inline Local(S* that) : Handle<T>(that) { } |
template <class S> static inline Local<T> Cast(Local<S> that) { |
+#ifdef V8_ENABLE_CHECKS |
+ // If we're going to perform the type check then we have to check |
+ // that the handle isn't empty before doing the checked cast. |
if (that.IsEmpty()) return Local<T>(); |
+#endif |
return Local<T>(T::Cast(*that)); |
} |
@@ -344,7 +358,11 @@ |
: Handle<T>(*that) { } |
template <class S> static inline Persistent<T> Cast(Persistent<S> that) { |
+#ifdef V8_ENABLE_CHECKS |
+ // If we're going to perform the type check then we have to check |
+ // that the handle isn't empty before doing the checked cast. |
if (that.IsEmpty()) return Persistent<T>(); |
+#endif |
return Persistent<T>(T::Cast(*that)); |
} |
@@ -423,7 +441,7 @@ |
/** |
* Creates a new handle with the given value. |
*/ |
- static void** CreateHandle(void* value); |
+ static internal::Object** CreateHandle(internal::Object* value); |
private: |
// Make it impossible to create heap-allocated or illegal handle |
@@ -438,8 +456,8 @@ |
class V8EXPORT Data { |
public: |
int extensions; |
- void** next; |
- void** limit; |
+ internal::Object** next; |
+ internal::Object** limit; |
inline void Initialize() { |
extensions = -1; |
next = limit = NULL; |
@@ -451,7 +469,7 @@ |
// Allow for the active closing of HandleScopes which allows to pass a handle |
// from the HandleScope being closed to the next top most HandleScope. |
bool is_closed_; |
- void** RawClose(void** value); |
+ internal::Object** RawClose(internal::Object** value); |
friend class ImplementationUtilities; |
}; |
@@ -671,7 +689,7 @@ |
* Returns true if this value is an instance of the String type. |
* See ECMA-262 8.4. |
*/ |
- bool IsString() const; |
+ inline bool IsString() const; |
/** |
* Returns true if this value is a function. |
@@ -737,6 +755,10 @@ |
/** JS == */ |
bool Equals(Handle<Value> that) const; |
bool StrictEquals(Handle<Value> that) const; |
+ |
+ private: |
+ inline bool QuickIsString() const; |
+ bool FullIsString() const; |
}; |
@@ -868,7 +890,7 @@ |
* Get the ExternalStringResource for an external string. Returns |
* NULL if IsExternal() doesn't return true. |
*/ |
- ExternalStringResource* GetExternalStringResource() const; |
+ inline ExternalStringResource* GetExternalStringResource() const; |
/** |
* Get the ExternalAsciiStringResource for an external ascii string. |
@@ -876,7 +898,7 @@ |
*/ |
ExternalAsciiStringResource* GetExternalAsciiStringResource() const; |
- static String* Cast(v8::Value* obj); |
+ static inline String* Cast(v8::Value* obj); |
/** |
* Allocates a new string from either utf-8 encoded or ascii data. |
@@ -1010,6 +1032,10 @@ |
Value(const Value&); |
void operator=(const Value&); |
}; |
+ |
+ private: |
+ void VerifyExternalStringResource(ExternalStringResource* val) const; |
+ static void CheckCast(v8::Value* obj); |
}; |
@@ -1020,9 +1046,10 @@ |
public: |
double Value() const; |
static Local<Number> New(double value); |
- static Number* Cast(v8::Value* obj); |
+ static inline Number* Cast(v8::Value* obj); |
private: |
Number(); |
+ static void CheckCast(v8::Value* obj); |
}; |
@@ -1033,9 +1060,10 @@ |
public: |
static Local<Integer> New(int32_t value); |
int64_t Value() const; |
- static Integer* Cast(v8::Value* obj); |
+ static inline Integer* Cast(v8::Value* obj); |
private: |
Integer(); |
+ static void CheckCast(v8::Value* obj); |
}; |
@@ -1074,7 +1102,9 @@ |
*/ |
double NumberValue() const; |
- static Date* Cast(v8::Value* obj); |
+ static inline Date* Cast(v8::Value* obj); |
+ private: |
+ static void CheckCast(v8::Value* obj); |
}; |
@@ -1153,14 +1183,13 @@ |
/** Gets the number of internal fields for this Object. */ |
int InternalFieldCount(); |
/** Gets the value in an internal field. */ |
- Local<Value> GetInternalField(int index); |
+ inline Local<Value> GetInternalField(int index); |
/** Sets the value in an internal field. */ |
void SetInternalField(int index, Handle<Value> value); |
- // The two functions below do not perform index bounds checks and |
- // they do not check that the VM is still running. Use with caution. |
/** Gets a native pointer from an internal field. */ |
- void* GetPointerFromInternalField(int index); |
+ inline void* GetPointerFromInternalField(int index); |
+ |
/** Sets a native pointer in an internal field. */ |
void SetPointerInInternalField(int index, void* value); |
@@ -1223,9 +1252,17 @@ |
void SetIndexedPropertiesToPixelData(uint8_t* data, int length); |
static Local<Object> New(); |
- static Object* Cast(Value* obj); |
+ static inline Object* Cast(Value* obj); |
private: |
Object(); |
+ static void CheckCast(Value* obj); |
+ Local<Value> CheckedGetInternalField(int index); |
+ |
+ /** |
+ * If quick access to the internal field is possible this method |
+ * returns the value. Otherwise an empty handle is returned. |
+ */ |
+ inline Local<Value> UncheckedGetInternalField(int index); |
}; |
@@ -1243,9 +1280,10 @@ |
Local<Object> CloneElementAt(uint32_t index); |
static Local<Array> New(int length = 0); |
- static Array* Cast(Value* obj); |
+ static inline Array* Cast(Value* obj); |
private: |
Array(); |
+ static void CheckCast(Value* obj); |
}; |
@@ -1259,9 +1297,10 @@ |
Local<Value> Call(Handle<Object> recv, int argc, Handle<Value> argv[]); |
void SetName(Handle<String> name); |
Handle<Value> GetName() const; |
- static Function* Cast(Value* obj); |
+ static inline Function* Cast(Value* obj); |
private: |
Function(); |
+ static void CheckCast(Value* obj); |
}; |
@@ -1279,13 +1318,16 @@ |
class V8EXPORT External : public Value { |
public: |
static Local<Value> Wrap(void* data); |
- static void* Unwrap(Handle<Value> obj); |
+ static inline void* Unwrap(Handle<Value> obj); |
static Local<External> New(void* value); |
- static External* Cast(Value* obj); |
+ static inline External* Cast(Value* obj); |
void* Value() const; |
private: |
External(); |
+ static void CheckCast(v8::Value* obj); |
+ static inline void* QuickUnwrap(Handle<v8::Value> obj); |
+ static void* FullUnwrap(Handle<v8::Value> obj); |
}; |
@@ -2297,12 +2339,14 @@ |
private: |
V8(); |
- static void** GlobalizeReference(void** handle); |
- static void DisposeGlobal(void** global_handle); |
- static void MakeWeak(void** global_handle, void* data, WeakReferenceCallback); |
- static void ClearWeak(void** global_handle); |
- static bool IsGlobalNearDeath(void** global_handle); |
- static bool IsGlobalWeak(void** global_handle); |
+ static internal::Object** GlobalizeReference(internal::Object** handle); |
+ static void DisposeGlobal(internal::Object** global_handle); |
+ static void MakeWeak(internal::Object** global_handle, |
+ void* data, |
+ WeakReferenceCallback); |
+ static void ClearWeak(internal::Object** global_handle); |
+ static bool IsGlobalNearDeath(internal::Object** global_handle); |
+ static bool IsGlobalWeak(internal::Object** global_handle); |
template <class T> friend class Handle; |
template <class T> friend class Local; |
@@ -2641,6 +2685,77 @@ |
// --- I m p l e m e n t a t i o n --- |
+ |
+namespace internal { |
+ |
+ |
+// Tag information for HeapObject. |
+const int kHeapObjectTag = 1; |
+const int kHeapObjectTagSize = 2; |
+const intptr_t kHeapObjectTagMask = (1 << kHeapObjectTagSize) - 1; |
+ |
+ |
+// Tag information for Smi. |
+const int kSmiTag = 0; |
+const int kSmiTagSize = 1; |
+const intptr_t kSmiTagMask = (1 << kSmiTagSize) - 1; |
+ |
+ |
+/** |
+ * This class exports constants and functionality from within v8 that |
+ * is necessary to implement inline functions in the v8 api. Don't |
+ * depend on functions and constants defined here. |
+ */ |
+class Internals { |
+ public: |
+ |
+ // These values match non-compiler-dependent values defined within |
+ // the implementation of v8. |
+ static const int kHeapObjectMapOffset = 0; |
+ static const int kMapInstanceTypeOffset = sizeof(void*) + sizeof(int); |
+ static const int kStringResourceOffset = 2 * sizeof(void*); |
+ static const int kProxyProxyOffset = sizeof(void*); |
+ static const int kJSObjectHeaderSize = 3 * sizeof(void*); |
+ static const int kFullStringRepresentationMask = 0x07; |
+ static const int kExternalTwoByteRepresentationTag = 0x03; |
+ static const int kAlignedPointerShift = 2; |
+ |
+ // These constants are compiler dependent so their values must be |
+ // defined within the implementation. |
+ static int kJSObjectType; |
+ static int kFirstNonstringType; |
+ static int kProxyType; |
+ |
+ static inline bool HasHeapObjectTag(internal::Object* value) { |
+ return ((reinterpret_cast<intptr_t>(value) & kHeapObjectTagMask) == |
+ kHeapObjectTag); |
Mads Ager (chromium)
2009/08/26 06:22:20
I would align this with '(reinterpret_cast...' on
|
+ } |
+ |
+ static inline bool HasSmiTag(internal::Object* value) { |
+ return ((reinterpret_cast<intptr_t>(value) & kSmiTagMask) == |
Mads Ager (chromium)
2009/08/26 06:22:20
This should fit on one line?
|
+ kSmiTag); |
+ } |
+ |
+ static inline int SmiValue(internal::Object* value) { |
+ return static_cast<int>(reinterpret_cast<intptr_t>(value)) >> kSmiTagSize; |
+ } |
+ |
+ static inline bool IsExternalTwoByteString(int instance_type) { |
+ int representation = (instance_type & kFullStringRepresentationMask); |
+ return representation == kExternalTwoByteRepresentationTag; |
+ } |
+ |
+ template <typename T> |
+ static inline T ReadField(Object* ptr, int offset) { |
+ uint8_t* addr = reinterpret_cast<uint8_t*>(ptr) + offset - kHeapObjectTag; |
+ return *reinterpret_cast<T*>(addr); |
+ } |
+ |
+}; |
+ |
+} |
+ |
+ |
template <class T> |
Handle<T>::Handle() : val_(0) { } |
@@ -2652,7 +2767,7 @@ |
template <class T> |
Local<T> Local<T>::New(Handle<T> that) { |
if (that.IsEmpty()) return Local<T>(); |
- void** p = reinterpret_cast<void**>(*that); |
+ internal::Object** p = reinterpret_cast<internal::Object**>(*that); |
return Local<T>(reinterpret_cast<T*>(HandleScope::CreateHandle(*p))); |
} |
@@ -2660,7 +2775,7 @@ |
template <class T> |
Persistent<T> Persistent<T>::New(Handle<T> that) { |
if (that.IsEmpty()) return Persistent<T>(); |
- void** p = reinterpret_cast<void**>(*that); |
+ internal::Object** p = reinterpret_cast<internal::Object**>(*that); |
return Persistent<T>(reinterpret_cast<T*>(V8::GlobalizeReference(p))); |
} |
@@ -2668,21 +2783,21 @@ |
template <class T> |
bool Persistent<T>::IsNearDeath() const { |
if (this->IsEmpty()) return false; |
- return V8::IsGlobalNearDeath(reinterpret_cast<void**>(**this)); |
+ return V8::IsGlobalNearDeath(reinterpret_cast<internal::Object**>(**this)); |
} |
template <class T> |
bool Persistent<T>::IsWeak() const { |
if (this->IsEmpty()) return false; |
- return V8::IsGlobalWeak(reinterpret_cast<void**>(**this)); |
+ return V8::IsGlobalWeak(reinterpret_cast<internal::Object**>(**this)); |
} |
template <class T> |
void Persistent<T>::Dispose() { |
if (this->IsEmpty()) return; |
- V8::DisposeGlobal(reinterpret_cast<void**>(**this)); |
+ V8::DisposeGlobal(reinterpret_cast<internal::Object**>(**this)); |
} |
@@ -2691,12 +2806,14 @@ |
template <class T> |
void Persistent<T>::MakeWeak(void* parameters, WeakReferenceCallback callback) { |
- V8::MakeWeak(reinterpret_cast<void**>(**this), parameters, callback); |
+ V8::MakeWeak(reinterpret_cast<internal::Object**>(**this), |
+ parameters, |
+ callback); |
} |
template <class T> |
void Persistent<T>::ClearWeak() { |
- V8::ClearWeak(reinterpret_cast<void**>(**this)); |
+ V8::ClearWeak(reinterpret_cast<internal::Object**>(**this)); |
} |
Local<Value> Arguments::operator[](int i) const { |
@@ -2752,7 +2869,8 @@ |
template <class T> |
Local<T> HandleScope::Close(Handle<T> value) { |
- void** after = RawClose(reinterpret_cast<void**>(*value)); |
+ internal::Object** before = reinterpret_cast<internal::Object**>(*value); |
+ internal::Object** after = RawClose(before); |
return Local<T>(reinterpret_cast<T*>(after)); |
} |
@@ -2781,6 +2899,171 @@ |
} |
+Local<Value> Object::GetInternalField(int index) { |
+#ifndef V8_ENABLE_CHECKS |
+ Local<Value> quick_result = UncheckedGetInternalField(index); |
+ if (!quick_result.IsEmpty()) return quick_result; |
+#endif |
+ return CheckedGetInternalField(index); |
+} |
+ |
+ |
+Local<Value> Object::UncheckedGetInternalField(int index) { |
+ typedef internal::Object O; |
+ typedef internal::Internals I; |
+ O* obj = *reinterpret_cast<O**>(this); |
+ O* map = I::ReadField<O*>(obj, I::kHeapObjectMapOffset); |
+ int instance_type = I::ReadField<uint8_t>(map, I::kMapInstanceTypeOffset); |
+ if (instance_type == I::kJSObjectType) { |
+ // If the object is a plain JSObject, which is the common case, |
+ // we know where to find the internal fields and can return the |
+ // value directly. |
+ int offset = I::kJSObjectHeaderSize + (sizeof(void*) * index); |
+ O* value = I::ReadField<O*>(obj, offset); |
+ O** result = HandleScope::CreateHandle(value); |
+ return Local<Value>(reinterpret_cast<Value*>(result)); |
+ } else { |
+ return Local<Value>(); |
+ } |
+} |
+ |
+ |
+void* External::Unwrap(Handle<v8::Value> obj) { |
+#ifdef V8_ENABLE_CHECKS |
+ return FullUnwrap(obj); |
+#else |
+ return QuickUnwrap(obj); |
+#endif |
+} |
+ |
+ |
+void* External::QuickUnwrap(Handle<v8::Value> wrapper) { |
+ typedef internal::Object O; |
+ typedef internal::Internals I; |
+ O* obj = *reinterpret_cast<O**>(const_cast<v8::Value*>(*wrapper)); |
+ if (I::HasSmiTag(obj)) { |
+ int value = I::SmiValue(obj) << I::kAlignedPointerShift; |
+ return reinterpret_cast<void*>(value); |
+ } else { |
+ O* map = I::ReadField<O*>(obj, I::kHeapObjectMapOffset); |
+ int instance_type = I::ReadField<uint8_t>(map, I::kMapInstanceTypeOffset); |
+ if (instance_type == I::kProxyType) { |
+ return I::ReadField<void*>(obj, I::kProxyProxyOffset); |
+ } else { |
+ return NULL; |
+ } |
+ } |
+} |
+ |
+ |
+void* Object::GetPointerFromInternalField(int index) { |
+ return External::Unwrap(GetInternalField(index)); |
+} |
+ |
+ |
+String* String::Cast(v8::Value* value) { |
+#ifdef V8_ENABLE_CHECKS |
+ CheckCast(value); |
+#endif |
+ return static_cast<String*>(value); |
+} |
+ |
+ |
+String::ExternalStringResource* String::GetExternalStringResource() const { |
+ typedef internal::Object O; |
+ typedef internal::Internals I; |
+ O* obj = *reinterpret_cast<O**>(const_cast<String*>(this)); |
+ O* map = I::ReadField<O*>(obj, I::kHeapObjectMapOffset); |
+ int instance_type = I::ReadField<uint8_t>(map, I::kMapInstanceTypeOffset); |
+ String::ExternalStringResource* result; |
+ if (I::IsExternalTwoByteString(instance_type)) { |
+ void* value = I::ReadField<void*>(obj, I::kStringResourceOffset); |
+ result = reinterpret_cast<String::ExternalStringResource*>(value); |
+ } else { |
+ result = NULL; |
+ } |
+#ifdef V8_ENABLE_CHECKS |
+ VerifyExternalStringResource(result); |
+#endif |
+ return result; |
+} |
+ |
+ |
+bool Value::IsString() const { |
+#ifdef V8_ENABLE_CHECKS |
+ return FullIsString(); |
+#else |
+ return QuickIsString(); |
+#endif |
+} |
+ |
+bool Value::QuickIsString() const { |
+ typedef internal::Object O; |
+ typedef internal::Internals I; |
+ O* obj = *reinterpret_cast<O**>(const_cast<Value*>(this)); |
+ if (!I::HasHeapObjectTag(obj)) return false; |
+ O* map = I::ReadField<O*>(obj, I::kHeapObjectMapOffset); |
+ int instance_type = I::ReadField<uint8_t>(map, I::kMapInstanceTypeOffset); |
+ return (instance_type < I::kFirstNonstringType); |
+} |
+ |
+ |
+Number* Number::Cast(v8::Value* value) { |
+#ifdef V8_ENABLE_CHECKS |
+ CheckCast(value); |
+#endif |
+ return static_cast<Number*>(value); |
+} |
+ |
+ |
+Integer* Integer::Cast(v8::Value* value) { |
+#ifdef V8_ENABLE_CHECKS |
+ CheckCast(value); |
+#endif |
+ return static_cast<Integer*>(value); |
+} |
+ |
+ |
+Date* Date::Cast(v8::Value* value) { |
+#ifdef V8_ENABLE_CHECKS |
+ CheckCast(value); |
+#endif |
+ return static_cast<Date*>(value); |
+} |
+ |
+ |
+Object* Object::Cast(v8::Value* value) { |
+#ifdef V8_ENABLE_CHECKS |
+ CheckCast(value); |
+#endif |
+ return static_cast<Object*>(value); |
+} |
+ |
+ |
+Array* Array::Cast(v8::Value* value) { |
+#ifdef V8_ENABLE_CHECKS |
+ CheckCast(value); |
+#endif |
+ return static_cast<Array*>(value); |
+} |
+ |
+ |
+Function* Function::Cast(v8::Value* value) { |
+#ifdef V8_ENABLE_CHECKS |
+ CheckCast(value); |
+#endif |
+ return static_cast<Function*>(value); |
+} |
+ |
+ |
+External* External::Cast(v8::Value* value) { |
+#ifdef V8_ENABLE_CHECKS |
+ CheckCast(value); |
+#endif |
+ return static_cast<External*>(value); |
+} |
+ |
+ |
/** |
* \example shell.cc |
* A simple shell that takes a list of expressions on the |