| Index: src/arguments.h
|
| diff --git a/src/arguments.h b/src/arguments.h
|
| index f8fb00c57538aeb32b7a0adcfdc40d0796a91332..7d00d17138ddc0a7737f5ef1046dee8df462bf0f 100644
|
| --- a/src/arguments.h
|
| +++ b/src/arguments.h
|
| @@ -82,35 +82,216 @@ class Arguments BASE_EMBEDDED {
|
| };
|
|
|
|
|
| +#define FOR_EACH_CALLBACK_TABLE_MAPPING(F) \
|
| + F(AccessorGetter, AccessorGetterCallback) \
|
| + F(AccessorSetter, AccessorSetterCallback) \
|
| + F(InvocationCallback, FunctionCallback) \
|
| + F(NamedPropertySetter, NamedPropertySetterCallback) \
|
| + F(NamedPropertyQuery, NamedPropertyQueryCallback) \
|
| + F(NamedPropertyDeleter, NamedPropertyDeleterCallback) \
|
| + F(IndexedPropertyGetter, IndexedPropertyGetterCallback) \
|
| + F(IndexedPropertySetter, IndexedPropertySetterCallback) \
|
| + F(IndexedPropertyQuery, IndexedPropertyQueryCallback) \
|
| + F(IndexedPropertyDeleter, IndexedPropertyDeleterCallback) \
|
| + F(IndexedPropertyEnumerator, IndexedPropertyEnumeratorCallback) \
|
| +
|
| +// These aren't included in the list as they have duplicate signatures
|
| +// F(NamedPropertyEnumerator, NamedPropertyEnumeratorCallback) \
|
| +// F(NamedPropertyGetter, NamedPropertyGetterCallback) \
|
| +
|
| +// 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;
|
| + }
|
| +
|
| +#define WRITE_REGISTER(OldFunction, NewFunction) \
|
| + static OldFunction Register(Isolate* isolate, NewFunction f) { \
|
| + InsertCallback(isolate, reinterpret_cast<void*>(f), true); \
|
| + return reinterpret_cast<OldFunction>(f); \
|
| + } \
|
| + \
|
| + static OldFunction Register(Isolate* isolate, OldFunction f) { \
|
| + InsertCallback(isolate, reinterpret_cast<void*>(f), false); \
|
| + return f; \
|
| + }
|
| + FOR_EACH_CALLBACK_TABLE_MAPPING(WRITE_REGISTER)
|
| +#undef WRITE_REGISTER
|
| +
|
| + private:
|
| + CallbackTable(): map_(Match, 64) {}
|
| + typedef HashMap::Entry Entry;
|
| + static bool Match(void* a, void* b) {
|
| + return a == b;
|
| + }
|
| + static uint32_t Hash(void* function) {
|
| + uintptr_t as_int = reinterpret_cast<uintptr_t>(function);
|
| + if (sizeof(function) == 4) return static_cast<uint32_t>(as_int);
|
| + uint64_t as_64 = static_cast<uint64_t>(as_int);
|
| + return
|
| + static_cast<uint32_t>(as_64 >> 32) ^
|
| + static_cast<uint32_t>(as_64);
|
| + }
|
| + bool Contains(void* function) {
|
| + ASSERT(function != NULL);
|
| + return map_.Lookup(function, Hash(function), false) != NULL;
|
| + }
|
| + static void InsertCallback(Isolate* isolate,
|
| + void* function,
|
| + bool returns_void) {
|
| + if (function == NULL) return;
|
| + // Don't store for performance.
|
| + if (kStoreVoidFunctions != returns_void) return;
|
| + CallbackTable* table = isolate->callback_table();
|
| + if (table == NULL) {
|
| + table = new CallbackTable();
|
| + isolate->set_callback_table(table);
|
| + }
|
| + table->Insert(function);
|
| + }
|
| + void Insert(void* function) {
|
| + ASSERT(function != NULL);
|
| + Entry* entry = map_.Lookup(function, Hash(function), true);
|
| + ASSERT(entry != NULL);
|
| + ASSERT(entry->value == NULL || entry->value == function);
|
| + entry->value = function;
|
| + }
|
| + 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);
|
| - }
|
| -
|
| - 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);
|
| + 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);
|
| + }
|
| +
|
| +#define WRITE_CALLBACK_RESULT(OldFunction, NewFunction) \
|
| + template<typename V> \
|
| + inline v8::Handle<V> GetCallbackResult(Isolate* isolate, \
|
| + OldFunction function, \
|
| + v8::Handle<V> call_result) { \
|
| + return GetCallbackResult(isolate, \
|
| + reinterpret_cast<void*>(function), \
|
| + call_result); \
|
| + }
|
| + FOR_EACH_CALLBACK_TABLE_MAPPING(WRITE_CALLBACK_RESULT)
|
| +#undef WRITE_CALLBACK_RESULT
|
| +
|
| + protected:
|
| + template<typename V>
|
| + inline v8::Handle<V> GetCallbackResult(Isolate* isolate,
|
| + void* function,
|
| + v8::Handle<V> call_result) {
|
| + // For non-void calls, return the result only if call_result is set.
|
| + if (!CallbackTable::ReturnsVoid(isolate, function) &&
|
| + !call_result.IsEmpty()) {
|
| + return call_result;
|
| }
|
| -#endif
|
| + // Check the ReturnValue.
|
| + Object* object = this->end()[kReturnValueOffset];
|
| + // Nothing was set, return empty handle as per previous behaviour.
|
| + if (object->IsTheHole()) return v8::Handle<V>();
|
| + // We shouldn't need this, but play it safe for now.
|
| + // TODO(dcarney) Remove once all calls to this are verified as safe??
|
| + return v8::Local<V>::New(reinterpret_cast<v8::Isolate*>(isolate),
|
| + v8::Handle<V>(reinterpret_cast<V*>(&object)));
|
| }
|
|
|
| - void IterateInstance(ObjectVisitor* v);
|
| - Object** end() { return values_ + ARRAY_SIZE(values_) - 1; }
|
| + explicit inline CustomArguments(Isolate* isolate) : Super(isolate) {}
|
| +};
|
|
|
| - private:
|
| - Object* values_[4];
|
| +
|
| +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());
|
| + }
|
| +
|
| + inline v8::AccessorInfo NewInfo() {
|
| + return v8::AccessorInfo(end());
|
| + }
|
| +};
|
| +
|
| +
|
| +class FunctionCallbackArguments
|
| + : public CustomArguments<FunctionCallbackInfo<Value> > {
|
| + public:
|
| + typedef FunctionCallbackInfo<Value> T;
|
| + typedef CustomArguments<T> Super;
|
| + static const int kArgsLength = T::kArgsLength;
|
| +
|
| + FunctionCallbackArguments(internal::Isolate* isolate,
|
| + internal::Object* data,
|
| + internal::JSFunction* callee,
|
| + internal::Object* holder)
|
| + : Super(isolate) {
|
| + 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());
|
| + }
|
| +
|
| + inline v8::Arguments NewArguments(internal::Object** argv,
|
| + int argc,
|
| + bool is_construct_call) {
|
| + return v8::Arguments(this->end(), argv, argc, is_construct_call);
|
| + }
|
| };
|
|
|
|
|
|
|