NamedPropertyQuery query,
NamedPropertyDeleter remover,
NamedPropertyEnumerator enumerator,
+ bool is_fallback,
Handle<Value> data);
void SetIndexedInstancePropertyHandler(IndexedPropertyGetter getter,
IndexedPropertySetter setter,
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.
NamedPropertyQuery query,
NamedPropertyDeleter remover,
NamedPropertyEnumerator enumerator,
+ bool is_fallback,
Handle<Value> data) {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
if (IsDeadCheck(isolate,
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));
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::SetNamedPropertyHandler()")) {
+ 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);
}
// 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();
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,
+ skip_fallback_interceptor),
Object);
}
Handle<String> key,
Handle<Object> value,
PropertyAttributes attributes,
- StrictModeFlag strict_mode);
+ StrictModeFlag strict_mode,
+ bool skip_fallback_interceptor = false);
Handle<Object> SetProperty(Handle<Object> object,
Handle<Object> key,
bool Map::is_shared() {
return ((1 << kIsShared) & bit_field3()) != 0;
}
+
+void Map::set_named_interceptor_is_fallback(bool value)
+{
+ if (value) {
+ set_bit_field3(bit_field3() | (1 << kNamedInterceptorIsFallback));
+ } else {
+ set_bit_field3(bit_field3() & ~(1 << kNamedInterceptorIsFallback));
+ }
+}
+
+bool Map::named_interceptor_is_fallback()
+{
+ return ((1 << kNamedInterceptorIsFallback) & bit_field3()) != 0;
+}
JSFunction* Map::unchecked_constructor() {
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)
MaybeObject* JSReceiver::SetProperty(String* name,
Object* value,
PropertyAttributes attributes,
- StrictModeFlag strict_mode) {
+ StrictModeFlag strict_mode,
+ bool skip_fallback_interceptor) {
LookupResult result(GetIsolate());
- LocalLookup(name, &result);
+ LocalLookup(name, &result, skip_fallback_interceptor);
return SetProperty(&result, name, value, attributes, strict_mode);
}
}
-void JSReceiver::LocalLookup(String* name, LookupResult* result) {
+void JSReceiver::LocalLookup(String* name, LookupResult* result,
+ bool skip_fallback_interceptor) {
ASSERT(name->IsString());
Heap* heap = GetHeap();
}
// 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 (wouldIntercept && !skip_fallback_interceptor && !result->IsProperty() &&
+ map()->named_interceptor_is_fallback()) {
+ result->InterceptorResult(js_object);
+ return;
+ }
}
-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);
+ JSReceiver::cast(current)->LocalLookup(name, result, skip_fallback_interceptor);
if (result->IsProperty()) return;
}
result->NotFound();
MUST_USE_RESULT MaybeObject* SetProperty(String* key,
Object* value,
PropertyAttributes attributes,
- StrictModeFlag strict_mode);
+ StrictModeFlag strict_mode,
+ bool skip_fallback_interceptor = false);
MUST_USE_RESULT MaybeObject* SetProperty(LookupResult* result,
String* key,
Object* value,
// Lookup a property. If found, the result is valid and has
// detailed information.
- void LocalLookup(String* name, LookupResult* result);
- void Lookup(String* name, LookupResult* result);
+ void LocalLookup(String* name, LookupResult* result, bool skip_fallback_interceptor = false);
+ void Lookup(String* name, LookupResult* result, bool skip_fallback_interceptor = false);
protected:
Smi* GenerateIdentityHash();
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)
// Bit positions for bit field 3
static const int kIsShared = 0;
+ static const int kNamedInterceptorIsFallback = 1;
// Layout of the default cache. It holds alternating name and code objects.
static const int kCodeCacheEntrySize = 2;
DECL_ACCESSORS(deleter, Object)
DECL_ACCESSORS(enumerator, Object)
DECL_ACCESSORS(data, Object)
+ DECL_ACCESSORS(is_fallback, Smi)
static inline InterceptorInfo* cast(Object* obj);
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);
// Lookup the property in the global object, and don't set the
// value of the variable if the property is already there.
LookupResult lookup(isolate);
- global->Lookup(*name, &lookup);
+ global->Lookup(*name, &lookup, true);
if (lookup.IsProperty()) {
// We found an existing property. Unless it was an interceptor
// that claims the property is absent, skip this declaration.
}
LookupResult lookup(isolate);
- global->LocalLookup(*name, &lookup);
+ global->LocalLookup(*name, &lookup, true);
// Compute the property attributes. According to ECMA-262, section
// 13, page 71, the property must be read-only and
name,
value,
static_cast<PropertyAttributes>(attr),
- strict_mode));
+ strict_mode,
+ true));
}
}
while (object->IsJSObject() &&
JSObject::cast(object)->map()->is_hidden_prototype()) {
JSObject* raw_holder = JSObject::cast(object);
- raw_holder->LocalLookup(*name, &lookup);
+ raw_holder->LocalLookup(*name, &lookup, true);
if (lookup.IsProperty() && lookup.type() == INTERCEPTOR) {
HandleScope handle_scope(isolate);
Handle<JSObject> holder(raw_holder);
// Reload global in case the loop above performed a GC.
global = isolate->context()->global();
if (assign) {
- return global->SetProperty(*name, args[2], attributes, strict_mode);
+ return global->SetProperty(*name, args[2], attributes, strict_mode, true);
}
return isolate->heap()->undefined_value();
}