summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAaron Kennedy <aaron.kennedy@nokia.com>2011-10-27 11:31:56 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-04-12 16:56:49 +0200
commita24ac26a9213742564eac93201355215b9fe4d07 (patch)
treec299d2e8789a926030af35756a028e0c6a13569c
parent47589e5926cedddd824addc2473a76c3dc0d1ca3 (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.h7
-rw-r--r--src/3rdparty/v8/src/api.cc44
-rw-r--r--src/3rdparty/v8/src/factory.cc4
-rw-r--r--src/3rdparty/v8/src/objects-inl.h9
-rw-r--r--src/3rdparty/v8/src/objects.cc52
-rw-r--r--src/3rdparty/v8/src/objects.h21
-rw-r--r--src/3rdparty/v8/src/runtime.cc13
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();
}