diff options
author | Aaron Kennedy <aaron.kennedy@nokia.com> | 2011-10-27 11:31:56 +0100 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-04-12 16:56:49 +0200 |
commit | a24ac26a9213742564eac93201355215b9fe4d07 (patch) | |
tree | c299d2e8789a926030af35756a028e0c6a13569c | |
parent | 47589e5926cedddd824addc2473a76c3dc0d1ca3 (diff) |
[V8] Add a "fallback" mode for named property interceptors
By default interceptors are called before the normal property
resolution on objects. When an interceptor is installed as a
"fallback" interceptor, it is only called if the object doesn't
already have the property.
In the case of a global object having an fallback interceptor,
the interceptor is not invoked at all for var or function
declarations.
Change-Id: Id5c41db690f2b9df21ac1bcab442cbb76dc302f7
Reviewed-by: Simon Hausmann <simon.hausmann@nokia.com>
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
-rw-r--r-- | src/3rdparty/v8/include/v8.h | 7 | ||||
-rw-r--r-- | src/3rdparty/v8/src/api.cc | 44 | ||||
-rw-r--r-- | src/3rdparty/v8/src/factory.cc | 4 | ||||
-rw-r--r-- | src/3rdparty/v8/src/objects-inl.h | 9 | ||||
-rw-r--r-- | src/3rdparty/v8/src/objects.cc | 52 | ||||
-rw-r--r-- | src/3rdparty/v8/src/objects.h | 21 | ||||
-rw-r--r-- | src/3rdparty/v8/src/runtime.cc | 13 |
7 files changed, 118 insertions, 32 deletions
diff --git a/src/3rdparty/v8/include/v8.h b/src/3rdparty/v8/include/v8.h index 3f02221..b3fe64e 100644 --- a/src/3rdparty/v8/include/v8.h +++ b/src/3rdparty/v8/include/v8.h @@ -2426,6 +2426,7 @@ class V8EXPORT FunctionTemplate : public Template { NamedPropertyQuery query, NamedPropertyDeleter remover, NamedPropertyEnumerator enumerator, + bool is_fallback, Handle<Value> data); void SetIndexedInstancePropertyHandler(IndexedPropertyGetter getter, IndexedPropertySetter setter, @@ -2516,6 +2517,12 @@ class V8EXPORT ObjectTemplate : public Template { NamedPropertyDeleter deleter = 0, NamedPropertyEnumerator enumerator = 0, Handle<Value> data = Handle<Value>()); + void SetFallbackPropertyHandler(NamedPropertyGetter getter, + NamedPropertySetter setter = 0, + NamedPropertyQuery query = 0, + NamedPropertyDeleter deleter = 0, + NamedPropertyEnumerator enumerator = 0, + Handle<Value> data = Handle<Value>()); /** * Sets an indexed property handler on the object template. diff --git a/src/3rdparty/v8/src/api.cc b/src/3rdparty/v8/src/api.cc index f6e7b28..e7c6fa7 100644 --- a/src/3rdparty/v8/src/api.cc +++ b/src/3rdparty/v8/src/api.cc @@ -1217,6 +1217,7 @@ void FunctionTemplate::SetNamedInstancePropertyHandler( NamedPropertyQuery query, NamedPropertyDeleter remover, NamedPropertyEnumerator enumerator, + bool is_fallback, Handle<Value> data) { i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); if (IsDeadCheck(isolate, @@ -1235,6 +1236,7 @@ void FunctionTemplate::SetNamedInstancePropertyHandler( if (query != 0) SET_FIELD_WRAPPED(obj, set_query, query); if (remover != 0) SET_FIELD_WRAPPED(obj, set_deleter, remover); if (enumerator != 0) SET_FIELD_WRAPPED(obj, set_enumerator, enumerator); + obj->set_is_fallback(i::Smi::FromInt(is_fallback)); if (data.IsEmpty()) data = v8::Undefined(); obj->set_data(*Utils::OpenHandle(*data)); @@ -1360,12 +1362,13 @@ void ObjectTemplate::SetAccessor(v8::Handle<String> name, } -void ObjectTemplate::SetNamedPropertyHandler(NamedPropertyGetter getter, - NamedPropertySetter setter, - NamedPropertyQuery query, - NamedPropertyDeleter remover, - NamedPropertyEnumerator enumerator, - Handle<Value> data) { +void ObjectTemplate::SetNamedPropertyHandler( + NamedPropertyGetter getter, + NamedPropertySetter setter, + NamedPropertyQuery query, + NamedPropertyDeleter remover, + NamedPropertyEnumerator enumerator, + Handle<Value> data) { i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); if (IsDeadCheck(isolate, "v8::ObjectTemplate::SetNamedPropertyHandler()")) { return; @@ -1381,6 +1384,35 @@ void ObjectTemplate::SetNamedPropertyHandler(NamedPropertyGetter getter, query, remover, enumerator, + false, + data); +} + + +void ObjectTemplate::SetFallbackPropertyHandler( + NamedPropertyGetter getter, + NamedPropertySetter setter, + NamedPropertyQuery query, + NamedPropertyDeleter remover, + NamedPropertyEnumerator enumerator, + Handle<Value> data) { + i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); + if (IsDeadCheck(isolate, + "v8::ObjectTemplate::SetFallbackPropertyHandler()")) { + return; + } + ENTER_V8(isolate); + i::HandleScope scope(isolate); + EnsureConstructor(this); + i::FunctionTemplateInfo* constructor = + i::FunctionTemplateInfo::cast(Utils::OpenHandle(this)->constructor()); + i::Handle<i::FunctionTemplateInfo> cons(constructor); + Utils::ToLocal(cons)->SetNamedInstancePropertyHandler(getter, + setter, + query, + remover, + enumerator, + true, data); } diff --git a/src/3rdparty/v8/src/factory.cc b/src/3rdparty/v8/src/factory.cc index bb0e85f..296fc96 100644 --- a/src/3rdparty/v8/src/factory.cc +++ b/src/3rdparty/v8/src/factory.cc @@ -1309,6 +1309,10 @@ Handle<JSFunction> Factory::CreateApiFunction( // Set interceptor information in the map. if (!obj->named_property_handler()->IsUndefined()) { map->set_has_named_interceptor(); + InterceptorInfo *nph = InterceptorInfo::cast(obj->named_property_handler()); + bool is_fallback = + nph->is_fallback()->IsUndefined()?false:nph->is_fallback()->value(); + map->set_named_interceptor_is_fallback(is_fallback); } if (!obj->indexed_property_handler()->IsUndefined()) { map->set_has_indexed_interceptor(); diff --git a/src/3rdparty/v8/src/objects-inl.h b/src/3rdparty/v8/src/objects-inl.h index 4b9d3ab..41d0c98 100644 --- a/src/3rdparty/v8/src/objects-inl.h +++ b/src/3rdparty/v8/src/objects-inl.h @@ -3398,6 +3398,14 @@ bool Map::is_shared() { return IsShared::decode(bit_field3()); } +void Map::set_named_interceptor_is_fallback(bool value) { + set_bit_field3(NamedInterceptorIsFallback::update(bit_field3(), value)); +} + +bool Map::named_interceptor_is_fallback() { + return NamedInterceptorIsFallback::decode(bit_field3()); +} + void Map::set_dictionary_map(bool value) { set_bit_field3(DictionaryMap::update(bit_field3(), value)); @@ -4169,6 +4177,7 @@ ACCESSORS(InterceptorInfo, query, Object, kQueryOffset) ACCESSORS(InterceptorInfo, deleter, Object, kDeleterOffset) ACCESSORS(InterceptorInfo, enumerator, Object, kEnumeratorOffset) ACCESSORS(InterceptorInfo, data, Object, kDataOffset) +ACCESSORS(InterceptorInfo, is_fallback, Smi, kFallbackOffset) ACCESSORS(CallHandlerInfo, callback, Object, kCallbackOffset) ACCESSORS(CallHandlerInfo, data, Object, kDataOffset) diff --git a/src/3rdparty/v8/src/objects.cc b/src/3rdparty/v8/src/objects.cc index 6448c83..6f166cb 100644 --- a/src/3rdparty/v8/src/objects.cc +++ b/src/3rdparty/v8/src/objects.cc @@ -1986,9 +1986,12 @@ Handle<Object> JSReceiver::SetProperty(Handle<JSReceiver> object, Handle<String> key, Handle<Object> value, PropertyAttributes attributes, - StrictModeFlag strict_mode) { + StrictModeFlag strict_mode, + bool skip_fallback_interceptor) { CALL_HEAP_FUNCTION(object->GetIsolate(), - object->SetProperty(*key, *value, attributes, strict_mode), + object->SetProperty(*key, *value, attributes, strict_mode, + MAY_BE_STORE_FROM_KEYED, + skip_fallback_interceptor), Object); } @@ -1997,9 +2000,10 @@ MaybeObject* JSReceiver::SetProperty(String* name, Object* value, PropertyAttributes attributes, StrictModeFlag strict_mode, - JSReceiver::StoreFromKeyed store_mode) { + JSReceiver::StoreFromKeyed store_mode, + bool skip_fallback_interceptor) { LookupResult result(GetIsolate()); - LocalLookup(name, &result, true); + LocalLookup(name, &result, true, skip_fallback_interceptor); if (!result.IsFound()) { map()->LookupTransition(JSObject::cast(this), name, &result); } @@ -4593,8 +4597,9 @@ AccessorDescriptor* Map::FindAccessor(String* name) { } -void JSReceiver::LocalLookup( - String* name, LookupResult* result, bool search_hidden_prototypes) { +void JSReceiver::LocalLookup(String* name, LookupResult* result, + bool search_hidden_prototypes, + bool skip_fallback_interceptor) { ASSERT(name->IsString()); Heap* heap = GetHeap(); @@ -4621,31 +4626,46 @@ void JSReceiver::LocalLookup( JSObject* js_object = JSObject::cast(this); // Check for lookup interceptor except when bootstrapping. - if (js_object->HasNamedInterceptor() && - !heap->isolate()->bootstrapper()->IsActive()) { + bool wouldIntercept = js_object->HasNamedInterceptor() && + !heap->isolate()->bootstrapper()->IsActive(); + if (wouldIntercept && !map()->named_interceptor_is_fallback()) { result->InterceptorResult(js_object); return; } js_object->LocalLookupRealNamedProperty(name, result); - if (result->IsFound() || !search_hidden_prototypes) return; - Object* proto = js_object->GetPrototype(); - if (!proto->IsJSReceiver()) return; - JSReceiver* receiver = JSReceiver::cast(proto); - if (receiver->map()->is_hidden_prototype()) { - receiver->LocalLookup(name, result, search_hidden_prototypes); + if (result->IsFound()) return; + + if (search_hidden_prototypes) { + Object* proto = js_object->GetPrototype(); + + if (proto->IsJSReceiver()) { + JSReceiver* receiver = JSReceiver::cast(proto); + if (receiver->map()->is_hidden_prototype()) { + receiver->LocalLookup(name, result, search_hidden_prototypes); + return; + } + } + } + + if (wouldIntercept && !skip_fallback_interceptor && !result->IsProperty() && + map()->named_interceptor_is_fallback()) { + result->InterceptorResult(js_object); } } -void JSReceiver::Lookup(String* name, LookupResult* result) { +void JSReceiver::Lookup(String* name, + LookupResult* result, + bool skip_fallback_interceptor) { // Ecma-262 3rd 8.6.2.4 Heap* heap = GetHeap(); for (Object* current = this; current != heap->null_value(); current = JSObject::cast(current)->GetPrototype()) { - JSReceiver::cast(current)->LocalLookup(name, result, false); + JSReceiver::cast(current)->LocalLookup(name, result, false, + skip_fallback_interceptor); if (result->IsFound()) return; } result->NotFound(); diff --git a/src/3rdparty/v8/src/objects.h b/src/3rdparty/v8/src/objects.h index d7b0088..b32f106 100644 --- a/src/3rdparty/v8/src/objects.h +++ b/src/3rdparty/v8/src/objects.h @@ -1494,14 +1494,16 @@ class JSReceiver: public HeapObject { Handle<String> key, Handle<Object> value, PropertyAttributes attributes, - StrictModeFlag strict_mode); + StrictModeFlag strict_mode, + bool skip_fallback_interceptor = false); // Can cause GC. MUST_USE_RESULT MaybeObject* SetProperty( String* key, Object* value, PropertyAttributes attributes, StrictModeFlag strict_mode, - StoreFromKeyed store_from_keyed = MAY_BE_STORE_FROM_KEYED); + StoreFromKeyed store_from_keyed = MAY_BE_STORE_FROM_KEYED, + bool skip_fallback_interceptor = false); MUST_USE_RESULT MaybeObject* SetProperty( LookupResult* result, String* key, @@ -1564,8 +1566,10 @@ class JSReceiver: public HeapObject { // Lookup a property. If found, the result is valid and has // detailed information. void LocalLookup(String* name, LookupResult* result, - bool search_hidden_prototypes = false); - void Lookup(String* name, LookupResult* result); + bool search_hidden_prototypes = false, + bool skip_fallback_interceptor = false); + void Lookup(String* name, LookupResult* result, + bool skip_fallback_interceptor = false); protected: Smi* GenerateIdentityHash(); @@ -4858,6 +4862,7 @@ class Map: public HeapObject { class DictionaryMap: public BitField<bool, 24, 1> {}; class OwnsDescriptors: public BitField<bool, 25, 1> {}; class IsObserved: public BitField<bool, 26, 1> {}; + class NamedInterceptorIsFallback: public BitField<bool, 27, 1> {}; // Tells whether the object in the prototype property will be used // for instances created from this function. If the prototype @@ -5024,6 +5029,10 @@ class Map: public HeapObject { inline void set_is_access_check_needed(bool access_check_needed); inline bool is_access_check_needed(); + // Whether the named interceptor is a fallback interceptor or not + inline void set_named_interceptor_is_fallback(bool value); + inline bool named_interceptor_is_fallback(); + // [prototype]: implicit prototype object. DECL_ACCESSORS(prototype, Object) @@ -8687,6 +8696,7 @@ class InterceptorInfo: public Struct { DECL_ACCESSORS(deleter, Object) DECL_ACCESSORS(enumerator, Object) DECL_ACCESSORS(data, Object) + DECL_ACCESSORS(is_fallback, Smi) static inline InterceptorInfo* cast(Object* obj); @@ -8700,7 +8710,8 @@ class InterceptorInfo: public Struct { static const int kDeleterOffset = kQueryOffset + kPointerSize; static const int kEnumeratorOffset = kDeleterOffset + kPointerSize; static const int kDataOffset = kEnumeratorOffset + kPointerSize; - static const int kSize = kDataOffset + kPointerSize; + static const int kFallbackOffset = kDataOffset + kPointerSize; + static const int kSize = kFallbackOffset + kPointerSize; private: DISALLOW_IMPLICIT_CONSTRUCTORS(InterceptorInfo); diff --git a/src/3rdparty/v8/src/runtime.cc b/src/3rdparty/v8/src/runtime.cc index 2215ead..a2ff43c 100644 --- a/src/3rdparty/v8/src/runtime.cc +++ b/src/3rdparty/v8/src/runtime.cc @@ -1314,9 +1314,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) { // Do the lookup locally only, see ES5 erratum. LookupResult lookup(isolate); if (FLAG_es52_globals) { - global->LocalLookup(*name, &lookup, true); + global->LocalLookup(*name, &lookup, true, true); } else { - global->Lookup(*name, &lookup); + global->Lookup(*name, &lookup, true); } if (lookup.IsFound()) { // We found an existing property. Unless it was an interceptor @@ -1374,7 +1374,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) { RETURN_IF_EMPTY_HANDLE(isolate, JSObject::SetProperty( global, name, value, static_cast<PropertyAttributes>(attr), - language_mode == CLASSIC_MODE ? kNonStrictMode : kStrictMode)); + language_mode == CLASSIC_MODE ? kNonStrictMode : kStrictMode, + true)); } } @@ -1516,7 +1517,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) { // the whole chain of hidden prototypes to do a 'local' lookup. Object* object = global; LookupResult lookup(isolate); - JSObject::cast(object)->LocalLookup(*name, &lookup, true); + JSObject::cast(object)->LocalLookup(*name, &lookup, true, true); if (lookup.IsInterceptor()) { HandleScope handle_scope(isolate); PropertyAttributes intercepted = @@ -1535,7 +1536,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) { // Reload global in case the loop above performed a GC. global = isolate->context()->global_object(); if (assign) { - return global->SetProperty(*name, args[2], attributes, strict_mode_flag); + return global->SetProperty( + *name, args[2], attributes, strict_mode_flag, + JSReceiver::MAY_BE_STORE_FROM_KEYED, true); } return isolate->heap()->undefined_value(); } |