Index: src/arguments.h |
diff --git a/src/arguments.h b/src/arguments.h |
index 1423d5642b3912e896d7060bef3e67da24a337c6..a80b6136151716fdccc398657e7ea79c5e395ca6 100644 |
--- a/src/arguments.h |
+++ b/src/arguments.h |
@@ -82,35 +82,258 @@ class Arguments BASE_EMBEDDED { |
}; |
+// mappings from old property callbacks to new ones |
+// F(old name, new name, return value, parameters...) |
+// |
+// These aren't included in the list as they have duplicate signatures |
+// F(NamedPropertyEnumerator, NamedPropertyEnumeratorCallback, ...) |
+// F(NamedPropertyGetter, NamedPropertyGetterCallback, ...) |
+ |
+#define FOR_EACH_CALLBACK_TABLE_MAPPING_0(F) \ |
+ F(IndexedPropertyEnumerator, IndexedPropertyEnumeratorCallback, v8::Array) \ |
+ |
+#define FOR_EACH_CALLBACK_TABLE_MAPPING_1(F) \ |
+ F(AccessorGetter, AccessorGetterCallback, v8::Value, v8::Local<v8::String>) \ |
+ F(NamedPropertyQuery, \ |
+ NamedPropertyQueryCallback, \ |
+ v8::Integer, \ |
+ v8::Local<v8::String>) \ |
+ F(NamedPropertyDeleter, \ |
+ NamedPropertyDeleterCallback, \ |
+ v8::Boolean, \ |
+ v8::Local<v8::String>) \ |
+ F(IndexedPropertyGetter, \ |
+ IndexedPropertyGetterCallback, \ |
+ v8::Value, \ |
+ uint32_t) \ |
+ F(IndexedPropertyQuery, \ |
+ IndexedPropertyQueryCallback, \ |
+ v8::Integer, \ |
+ uint32_t) \ |
+ F(IndexedPropertyDeleter, \ |
+ IndexedPropertyDeleterCallback, \ |
+ v8::Boolean, \ |
+ uint32_t) \ |
+ |
+#define FOR_EACH_CALLBACK_TABLE_MAPPING_2(F) \ |
+ F(NamedPropertySetter, \ |
+ NamedPropertySetterCallback, \ |
+ v8::Value, \ |
+ v8::Local<v8::String>, \ |
+ v8::Local<v8::Value>) \ |
+ F(IndexedPropertySetter, \ |
+ IndexedPropertySetterCallback, \ |
+ v8::Value, \ |
+ uint32_t, \ |
+ v8::Local<v8::Value>) \ |
+ |
+#define FOR_EACH_CALLBACK_TABLE_MAPPING_2_VOID_RETURN(F) \ |
+ F(AccessorSetter, \ |
+ AccessorSetterCallback, \ |
+ void, \ |
+ v8::Local<v8::String>, \ |
+ v8::Local<v8::Value>) \ |
+ |
+// All property callbacks as well as invocation callbacks |
+#define FOR_EACH_CALLBACK_TABLE_MAPPING(F) \ |
+ F(InvocationCallback, FunctionCallback) \ |
+ F(AccessorGetter, AccessorGetterCallback) \ |
+ F(AccessorSetter, AccessorSetterCallback) \ |
+ F(NamedPropertySetter, NamedPropertySetterCallback) \ |
+ F(NamedPropertyQuery, NamedPropertyQueryCallback) \ |
+ F(NamedPropertyDeleter, NamedPropertyDeleterCallback) \ |
+ F(IndexedPropertyGetter, IndexedPropertyGetterCallback) \ |
+ F(IndexedPropertySetter, IndexedPropertySetterCallback) \ |
+ F(IndexedPropertyQuery, IndexedPropertyQueryCallback) \ |
+ F(IndexedPropertyDeleter, IndexedPropertyDeleterCallback) \ |
+ F(IndexedPropertyEnumerator, IndexedPropertyEnumeratorCallback) \ |
+ |
+ |
+// TODO(dcarney): Remove this class when old callbacks are gone. |
+class CallbackTable { |
+ public: |
+ // TODO(dcarney): Flip this when it makes sense for performance. |
+ static const bool kStoreVoidFunctions = true; |
+ static inline bool ReturnsVoid(Isolate* isolate, void* function) { |
+ CallbackTable* table = isolate->callback_table(); |
+ bool contains = |
+ table != NULL && |
+ table->map_.occupancy() != 0 && |
+ table->Contains(function); |
+ return contains == kStoreVoidFunctions; |
+ } |
+ |
+ STATIC_ASSERT(sizeof(intptr_t) == sizeof(AccessorGetterCallback)); |
+ |
+ template<typename F> |
+ static inline void* FunctionToVoidPtr(F function) { |
+ return reinterpret_cast<void*>(reinterpret_cast<intptr_t>(function)); |
+ } |
+ |
+#define WRITE_REGISTER(OldFunction, NewFunction) \ |
+ static OldFunction Register(Isolate* isolate, NewFunction f) { \ |
+ InsertCallback(isolate, FunctionToVoidPtr(f), true); \ |
+ return reinterpret_cast<OldFunction>(f); \ |
+ } \ |
+ \ |
+ static OldFunction Register(Isolate* isolate, OldFunction f) { \ |
+ InsertCallback(isolate, FunctionToVoidPtr(f), false); \ |
+ return f; \ |
+ } |
+ FOR_EACH_CALLBACK_TABLE_MAPPING(WRITE_REGISTER) |
+#undef WRITE_REGISTER |
+ |
+ private: |
+ CallbackTable(); |
+ bool Contains(void* function); |
+ static void InsertCallback(Isolate* isolate, |
+ void* function, |
+ bool returns_void); |
+ HashMap map_; |
+ DISALLOW_COPY_AND_ASSIGN(CallbackTable); |
+}; |
+ |
+ |
// Custom arguments replicate a small segment of stack that can be |
// accessed through an Arguments object the same way the actual stack |
// can. |
-class CustomArguments : public Relocatable { |
+template<int kArrayLength> |
+class CustomArgumentsBase : public Relocatable { |
+ public: |
+ virtual inline void IterateInstance(ObjectVisitor* v) { |
+ v->VisitPointers(values_, values_ + kArrayLength); |
+ } |
+ protected: |
+ inline Object** end() { return values_ + kArrayLength - 1; } |
+ explicit inline CustomArgumentsBase(Isolate* isolate) |
+ : Relocatable(isolate) {} |
+ Object* values_[kArrayLength]; |
+}; |
+ |
+ |
+template<typename T> |
+class CustomArguments : public CustomArgumentsBase<T::kArgsLength> { |
public: |
- inline CustomArguments(Isolate* isolate, |
- Object* data, |
- Object* self, |
- JSObject* holder) : Relocatable(isolate) { |
- ASSERT(reinterpret_cast<Object*>(isolate)->IsSmi()); |
- values_[3] = self; |
- values_[2] = holder; |
- values_[1] = data; |
- values_[0] = reinterpret_cast<Object*>(isolate); |
+ static const int kReturnValueOffset = T::kReturnValueIndex; |
+ |
+ typedef CustomArgumentsBase<T::kArgsLength> Super; |
+ ~CustomArguments() { |
+ // TODO(dcarney): create a new zap value for this. |
+ this->end()[kReturnValueOffset] = |
+ reinterpret_cast<Object*>(kHandleZapValue); |
+ } |
+ |
+ protected: |
+ explicit inline CustomArguments(Isolate* isolate) : Super(isolate) {} |
+ |
+ template<typename V> |
+ v8::Handle<V> GetReturnValue(Isolate* isolate); |
+ |
+ inline Isolate* isolate() { |
+ return reinterpret_cast<Isolate*>(this->end()[T::kIsolateIndex]); |
} |
+}; |
+ |
+ |
+class PropertyCallbackArguments |
+ : public CustomArguments<PropertyCallbackInfo<Value> > { |
+ public: |
+ typedef PropertyCallbackInfo<Value> T; |
+ typedef CustomArguments<T> Super; |
+ static const int kArgsLength = T::kArgsLength; |
+ static const int kThisIndex = T::kThisIndex; |
+ static const int kHolderIndex = T::kHolderIndex; |
+ |
+ PropertyCallbackArguments(Isolate* isolate, |
+ Object* data, |
+ Object* self, |
+ JSObject* holder) |
+ : Super(isolate) { |
+ Object** values = this->end(); |
+ values[T::kThisIndex] = self; |
+ values[T::kHolderIndex] = holder; |
+ values[T::kDataIndex] = data; |
+ values[T::kIsolateIndex] = reinterpret_cast<Object*>(isolate); |
+ values[T::kReturnValueIndex] = isolate->heap()->the_hole_value(); |
+ ASSERT(values[T::kHolderIndex]->IsHeapObject()); |
+ ASSERT(values[T::kIsolateIndex]->IsSmi()); |
+ } |
+ |
+ /* |
+ * The following Call functions wrap the calling of all callbacks to handle |
+ * calling either the old or the new style callbacks depending on which one |
+ * has been registered. |
+ * For old callbacks which return an empty handle, the ReturnValue is checked |
+ * and used if it's been set to anything inside the callback. |
+ * New style callbacks always use the return value. |
+ */ |
+#define WRITE_CALL_0(OldFunction, NewFunction, ReturnValue) \ |
+ v8::Handle<ReturnValue> Call(OldFunction f); \ |
+ |
+#define WRITE_CALL_1(OldFunction, NewFunction, ReturnValue, Arg1) \ |
+ v8::Handle<ReturnValue> Call(OldFunction f, Arg1 arg1); \ |
+ |
+#define WRITE_CALL_2(OldFunction, NewFunction, ReturnValue, Arg1, Arg2) \ |
+ v8::Handle<ReturnValue> Call(OldFunction f, Arg1 arg1, Arg2 arg2); \ |
+ |
+#define WRITE_CALL_2_VOID(OldFunction, NewFunction, ReturnValue, Arg1, Arg2) \ |
+ void Call(OldFunction f, Arg1 arg1, Arg2 arg2); \ |
+ |
+FOR_EACH_CALLBACK_TABLE_MAPPING_0(WRITE_CALL_0) |
+FOR_EACH_CALLBACK_TABLE_MAPPING_1(WRITE_CALL_1) |
+FOR_EACH_CALLBACK_TABLE_MAPPING_2(WRITE_CALL_2) |
+FOR_EACH_CALLBACK_TABLE_MAPPING_2_VOID_RETURN(WRITE_CALL_2_VOID) |
+ |
+#undef WRITE_CALL_0 |
+#undef WRITE_CALL_1 |
+#undef WRITE_CALL_2 |
+#undef WRITE_CALL_2_VOID |
+}; |
+ |
+ |
+class FunctionCallbackArguments |
+ : public CustomArguments<FunctionCallbackInfo<Value> > { |
+ public: |
+ typedef FunctionCallbackInfo<Value> T; |
+ typedef CustomArguments<T> Super; |
+ static const int kArgsLength = T::kArgsLength; |
- inline explicit CustomArguments(Isolate* isolate) : Relocatable(isolate) { |
-#ifdef DEBUG |
- for (size_t i = 0; i < ARRAY_SIZE(values_); i++) { |
- values_[i] = reinterpret_cast<Object*>(kZapValue); |
- } |
-#endif |
+ FunctionCallbackArguments(internal::Isolate* isolate, |
+ internal::Object* data, |
+ internal::JSFunction* callee, |
+ internal::Object* holder, |
+ internal::Object** argv, |
+ int argc, |
+ bool is_construct_call) |
+ : Super(isolate), |
+ argv_(argv), |
+ argc_(argc), |
+ is_construct_call_(is_construct_call) { |
+ Object** values = end(); |
+ values[T::kDataIndex] = data; |
+ values[T::kCalleeIndex] = callee; |
+ values[T::kHolderIndex] = holder; |
+ values[T::kIsolateIndex] = reinterpret_cast<internal::Object*>(isolate); |
+ values[T::kReturnValueIndex] = isolate->heap()->the_hole_value(); |
+ ASSERT(values[T::kCalleeIndex]->IsJSFunction()); |
+ ASSERT(values[T::kHolderIndex]->IsHeapObject()); |
+ ASSERT(values[T::kIsolateIndex]->IsSmi()); |
} |
- void IterateInstance(ObjectVisitor* v); |
- Object** end() { return values_ + ARRAY_SIZE(values_) - 1; } |
+ /* |
+ * The following Call function wraps the calling of all callbacks to handle |
+ * calling either the old or the new style callbacks depending on which one |
+ * has been registered. |
+ * For old callbacks which return an empty handle, the ReturnValue is checked |
+ * and used if it's been set to anything inside the callback. |
+ * New style callbacks always use the return value. |
+ */ |
+ v8::Handle<v8::Value> Call(InvocationCallback f); |
private: |
- Object* values_[4]; |
+ internal::Object** argv_; |
+ int argc_; |
+ bool is_construct_call_; |
}; |