LCOV - code coverage report
Current view: top level - test/cctest - test-api-interceptors.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 2293 2303 99.6 %
Date: 2019-02-19 Functions: 240 243 98.8 %

          Line data    Source code
       1             : // Copyright 2015 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include <stdlib.h>
       6             : 
       7             : #include "test/cctest/test-api.h"
       8             : 
       9             : #include "include/v8-util.h"
      10             : #include "src/api-inl.h"
      11             : #include "src/arguments.h"
      12             : #include "src/base/platform/platform.h"
      13             : #include "src/compilation-cache.h"
      14             : #include "src/execution.h"
      15             : #include "src/objects-inl.h"
      16             : #include "src/objects.h"
      17             : #include "src/runtime/runtime.h"
      18             : #include "src/unicode-inl.h"
      19             : #include "src/utils.h"
      20             : 
      21             : using ::v8::Boolean;
      22             : using ::v8::BooleanObject;
      23             : using ::v8::Context;
      24             : using ::v8::Extension;
      25             : using ::v8::Function;
      26             : using ::v8::FunctionTemplate;
      27             : using ::v8::HandleScope;
      28             : using ::v8::Local;
      29             : using ::v8::Name;
      30             : using ::v8::Message;
      31             : using ::v8::MessageCallback;
      32             : using ::v8::Object;
      33             : using ::v8::ObjectTemplate;
      34             : using ::v8::Persistent;
      35             : using ::v8::Script;
      36             : using ::v8::StackTrace;
      37             : using ::v8::String;
      38             : using ::v8::Symbol;
      39             : using ::v8::TryCatch;
      40             : using ::v8::Undefined;
      41             : using ::v8::V8;
      42             : using ::v8::Value;
      43             : 
      44             : 
      45             : namespace {
      46             : 
      47          30 : void Returns42(const v8::FunctionCallbackInfo<v8::Value>& info) {
      48             :   info.GetReturnValue().Set(42);
      49          30 : }
      50             : 
      51         288 : void Return239Callback(Local<String> name,
      52             :                        const v8::PropertyCallbackInfo<Value>& info) {
      53         288 :   ApiTestFuzzer::Fuzz();
      54         288 :   CheckReturnValue(info, FUNCTION_ADDR(Return239Callback));
      55         288 :   info.GetReturnValue().Set(v8_str("bad value"));
      56         288 :   info.GetReturnValue().Set(v8_num(239));
      57         288 : }
      58             : 
      59             : 
      60        1098 : void EmptyInterceptorGetter(Local<Name> name,
      61        1098 :                             const v8::PropertyCallbackInfo<v8::Value>& info) {}
      62             : 
      63             : 
      64         276 : void EmptyInterceptorSetter(Local<Name> name, Local<Value> value,
      65         276 :                             const v8::PropertyCallbackInfo<v8::Value>& info) {}
      66             : 
      67           6 : void EmptyInterceptorQuery(Local<Name> name,
      68           6 :                            const v8::PropertyCallbackInfo<v8::Integer>& info) {}
      69             : 
      70           0 : void EmptyInterceptorDeleter(
      71           0 :     Local<Name> name, const v8::PropertyCallbackInfo<v8::Boolean>& info) {}
      72             : 
      73           6 : void EmptyInterceptorEnumerator(
      74           6 :     const v8::PropertyCallbackInfo<v8::Array>& info) {}
      75             : 
      76          12 : void SimpleAccessorGetter(Local<String> name,
      77             :                           const v8::PropertyCallbackInfo<v8::Value>& info) {
      78             :   Local<Object> self = Local<Object>::Cast(info.This());
      79             :   info.GetReturnValue().Set(
      80             :       self->Get(info.GetIsolate()->GetCurrentContext(),
      81          48 :                 String::Concat(info.GetIsolate(), v8_str("accessor_"), name))
      82          12 :           .ToLocalChecked());
      83          12 : }
      84             : 
      85      120036 : void SimpleAccessorSetter(Local<String> name, Local<Value> value,
      86             :                           const v8::PropertyCallbackInfo<void>& info) {
      87             :   Local<Object> self = Local<Object>::Cast(info.This());
      88             :   self->Set(info.GetIsolate()->GetCurrentContext(),
      89      480144 :             String::Concat(info.GetIsolate(), v8_str("accessor_"), name), value)
      90      240072 :       .FromJust();
      91      120036 : }
      92             : 
      93             : 
      94           6 : void SymbolAccessorGetter(Local<Name> name,
      95             :                           const v8::PropertyCallbackInfo<v8::Value>& info) {
      96           6 :   CHECK(name->IsSymbol());
      97             :   Local<Symbol> sym = Local<Symbol>::Cast(name);
      98          18 :   if (sym->Name()->IsUndefined()) return;
      99           6 :   SimpleAccessorGetter(Local<String>::Cast(sym->Name()), info);
     100             : }
     101             : 
     102           6 : void SymbolAccessorSetter(Local<Name> name, Local<Value> value,
     103             :                           const v8::PropertyCallbackInfo<void>& info) {
     104           6 :   CHECK(name->IsSymbol());
     105             :   Local<Symbol> sym = Local<Symbol>::Cast(name);
     106          18 :   if (sym->Name()->IsUndefined()) return;
     107           6 :   SimpleAccessorSetter(Local<String>::Cast(sym->Name()), value, info);
     108             : }
     109             : 
     110         276 : void InterceptorGetter(Local<Name> generic_name,
     111             :                        const v8::PropertyCallbackInfo<v8::Value>& info) {
     112         432 :   if (generic_name->IsSymbol()) return;
     113             :   Local<String> name = Local<String>::Cast(generic_name);
     114         276 :   String::Utf8Value utf8(info.GetIsolate(), name);
     115         276 :   char* name_str = *utf8;
     116         276 :   char prefix[] = "interceptor_";
     117             :   int i;
     118        1716 :   for (i = 0; name_str[i] && prefix[i]; ++i) {
     119        1752 :     if (name_str[i] != prefix[i]) return;
     120             :   }
     121             :   Local<Object> self = Local<Object>::Cast(info.This());
     122             :   info.GetReturnValue().Set(
     123             :       self->GetPrivate(
     124             :               info.GetIsolate()->GetCurrentContext(),
     125         360 :               v8::Private::ForApi(info.GetIsolate(), v8_str(name_str + i)))
     126         240 :           .ToLocalChecked());
     127             : }
     128             : 
     129      660218 : void InterceptorSetter(Local<Name> generic_name, Local<Value> value,
     130             :                        const v8::PropertyCallbackInfo<v8::Value>& info) {
     131      840272 :   if (generic_name->IsSymbol()) return;
     132             :   Local<String> name = Local<String>::Cast(generic_name);
     133             :   // Intercept accesses that set certain integer values, for which the name does
     134             :   // not start with 'accessor_'.
     135      660218 :   String::Utf8Value utf8(info.GetIsolate(), name);
     136      660218 :   char* name_str = *utf8;
     137      660218 :   char prefix[] = "accessor_";
     138             :   int i;
     139     2760848 :   for (i = 0; name_str[i] && prefix[i]; ++i) {
     140     2580794 :     if (name_str[i] != prefix[i]) break;
     141             :   }
     142      840272 :   if (!prefix[i]) return;
     143             : 
     144      480164 :   Local<Context> context = info.GetIsolate()->GetCurrentContext();
     145      960328 :   if (value->IsInt32() && value->Int32Value(context).FromJust() < 10000) {
     146             :     Local<Object> self = Local<Object>::Cast(info.This());
     147      240110 :     Local<v8::Private> symbol = v8::Private::ForApi(info.GetIsolate(), name);
     148      480220 :     self->SetPrivate(context, symbol, value).FromJust();
     149             :     info.GetReturnValue().Set(value);
     150      480164 :   }
     151             : }
     152             : 
     153       18066 : void GenericInterceptorGetter(Local<Name> generic_name,
     154             :                               const v8::PropertyCallbackInfo<v8::Value>& info) {
     155             :   Local<String> str;
     156       18066 :   if (generic_name->IsSymbol()) {
     157          12 :     Local<Value> name = Local<Symbol>::Cast(generic_name)->Name();
     158          18 :     if (name->IsUndefined()) return;
     159             :     str = String::Concat(info.GetIsolate(), v8_str("_sym_"),
     160          12 :                          Local<String>::Cast(name));
     161             :   } else {
     162             :     Local<String> name = Local<String>::Cast(generic_name);
     163       18054 :     String::Utf8Value utf8(info.GetIsolate(), name);
     164       18054 :     char* name_str = *utf8;
     165       27078 :     if (*name_str == '_') return;
     166       18060 :     str = String::Concat(info.GetIsolate(), v8_str("_str_"), name);
     167             :   }
     168             : 
     169             :   Local<Object> self = Local<Object>::Cast(info.This());
     170             :   info.GetReturnValue().Set(
     171       18072 :       self->Get(info.GetIsolate()->GetCurrentContext(), str).ToLocalChecked());
     172             : }
     173             : 
     174          30 : void GenericInterceptorSetter(Local<Name> generic_name, Local<Value> value,
     175             :                               const v8::PropertyCallbackInfo<v8::Value>& info) {
     176             :   Local<String> str;
     177          30 :   if (generic_name->IsSymbol()) {
     178          12 :     Local<Value> name = Local<Symbol>::Cast(generic_name)->Name();
     179          18 :     if (name->IsUndefined()) return;
     180             :     str = String::Concat(info.GetIsolate(), v8_str("_sym_"),
     181          12 :                          Local<String>::Cast(name));
     182             :   } else {
     183             :     Local<String> name = Local<String>::Cast(generic_name);
     184          18 :     String::Utf8Value utf8(info.GetIsolate(), name);
     185          18 :     char* name_str = *utf8;
     186          30 :     if (*name_str == '_') return;
     187          12 :     str = String::Concat(info.GetIsolate(), v8_str("_str_"), name);
     188             :   }
     189             : 
     190             :   Local<Object> self = Local<Object>::Cast(info.This());
     191          24 :   self->Set(info.GetIsolate()->GetCurrentContext(), str, value).FromJust();
     192             :   info.GetReturnValue().Set(value);
     193             : }
     194             : 
     195          30 : void AddAccessor(Local<FunctionTemplate> templ, Local<String> name,
     196             :                  v8::AccessorGetterCallback getter,
     197             :                  v8::AccessorSetterCallback setter) {
     198          60 :   templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
     199          30 : }
     200             : 
     201          12 : void AddAccessor(Local<FunctionTemplate> templ, Local<Name> name,
     202             :                  v8::AccessorNameGetterCallback getter,
     203             :                  v8::AccessorNameSetterCallback setter) {
     204          24 :   templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
     205          12 : }
     206             : 
     207           6 : void AddStringOnlyInterceptor(Local<FunctionTemplate> templ,
     208             :                               v8::GenericNamedPropertyGetterCallback getter,
     209             :                               v8::GenericNamedPropertySetterCallback setter) {
     210             :   templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
     211             :       getter, setter, nullptr, nullptr, nullptr, Local<v8::Value>(),
     212          12 :       v8::PropertyHandlerFlags::kOnlyInterceptStrings));
     213           6 : }
     214             : 
     215         131 : void AddInterceptor(Local<FunctionTemplate> templ,
     216             :                     v8::GenericNamedPropertyGetterCallback getter,
     217             :                     v8::GenericNamedPropertySetterCallback setter) {
     218             :   templ->InstanceTemplate()->SetHandler(
     219         262 :       v8::NamedPropertyHandlerConfiguration(getter, setter));
     220         131 : }
     221             : 
     222             : 
     223             : v8::Local<v8::Object> bottom;
     224             : 
     225          48 : void CheckThisIndexedPropertyHandler(
     226             :     uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) {
     227          48 :   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyHandler));
     228          48 :   ApiTestFuzzer::Fuzz();
     229         144 :   CHECK(info.This()
     230             :             ->Equals(info.GetIsolate()->GetCurrentContext(), bottom)
     231             :             .FromJust());
     232          48 : }
     233             : 
     234          48 : void CheckThisNamedPropertyHandler(
     235             :     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
     236          48 :   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyHandler));
     237          48 :   ApiTestFuzzer::Fuzz();
     238         144 :   CHECK(info.This()
     239             :             ->Equals(info.GetIsolate()->GetCurrentContext(), bottom)
     240             :             .FromJust());
     241          48 : }
     242             : 
     243           5 : void CheckThisIndexedPropertyDefiner(
     244             :     uint32_t index, const v8::PropertyDescriptor& desc,
     245             :     const v8::PropertyCallbackInfo<v8::Value>& info) {
     246           5 :   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyDefiner));
     247           5 :   ApiTestFuzzer::Fuzz();
     248          15 :   CHECK(info.This()
     249             :             ->Equals(info.GetIsolate()->GetCurrentContext(), bottom)
     250             :             .FromJust());
     251           5 : }
     252             : 
     253           5 : void CheckThisNamedPropertyDefiner(
     254             :     Local<Name> property, const v8::PropertyDescriptor& desc,
     255             :     const v8::PropertyCallbackInfo<v8::Value>& info) {
     256           5 :   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyDefiner));
     257           5 :   ApiTestFuzzer::Fuzz();
     258          15 :   CHECK(info.This()
     259             :             ->Equals(info.GetIsolate()->GetCurrentContext(), bottom)
     260             :             .FromJust());
     261           5 : }
     262             : 
     263          16 : void CheckThisIndexedPropertySetter(
     264             :     uint32_t index, Local<Value> value,
     265             :     const v8::PropertyCallbackInfo<v8::Value>& info) {
     266          16 :   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertySetter));
     267          16 :   ApiTestFuzzer::Fuzz();
     268          48 :   CHECK(info.This()
     269             :             ->Equals(info.GetIsolate()->GetCurrentContext(), bottom)
     270             :             .FromJust());
     271          16 : }
     272             : 
     273          10 : void CheckThisIndexedPropertyDescriptor(
     274             :     uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) {
     275          10 :   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyDescriptor));
     276          10 :   ApiTestFuzzer::Fuzz();
     277          30 :   CHECK(info.This()
     278             :             ->Equals(info.GetIsolate()->GetCurrentContext(), bottom)
     279             :             .FromJust());
     280          10 : }
     281             : 
     282          10 : void CheckThisNamedPropertyDescriptor(
     283             :     Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {
     284          10 :   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyDescriptor));
     285          10 :   ApiTestFuzzer::Fuzz();
     286          30 :   CHECK(info.This()
     287             :             ->Equals(info.GetIsolate()->GetCurrentContext(), bottom)
     288             :             .FromJust());
     289          10 : }
     290             : 
     291          16 : void CheckThisNamedPropertySetter(
     292             :     Local<Name> property, Local<Value> value,
     293             :     const v8::PropertyCallbackInfo<v8::Value>& info) {
     294          16 :   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertySetter));
     295          16 :   ApiTestFuzzer::Fuzz();
     296          48 :   CHECK(info.This()
     297             :             ->Equals(info.GetIsolate()->GetCurrentContext(), bottom)
     298             :             .FromJust());
     299          16 : }
     300             : 
     301          36 : void CheckThisIndexedPropertyQuery(
     302             :     uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info) {
     303          36 :   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyQuery));
     304          36 :   ApiTestFuzzer::Fuzz();
     305         108 :   CHECK(info.This()
     306             :             ->Equals(info.GetIsolate()->GetCurrentContext(), bottom)
     307             :             .FromJust());
     308          36 : }
     309             : 
     310             : 
     311          36 : void CheckThisNamedPropertyQuery(
     312             :     Local<Name> property, const v8::PropertyCallbackInfo<v8::Integer>& info) {
     313          36 :   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyQuery));
     314          36 :   ApiTestFuzzer::Fuzz();
     315         108 :   CHECK(info.This()
     316             :             ->Equals(info.GetIsolate()->GetCurrentContext(), bottom)
     317             :             .FromJust());
     318          36 : }
     319             : 
     320             : 
     321          11 : void CheckThisIndexedPropertyDeleter(
     322             :     uint32_t index, const v8::PropertyCallbackInfo<v8::Boolean>& info) {
     323          11 :   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyDeleter));
     324          11 :   ApiTestFuzzer::Fuzz();
     325          33 :   CHECK(info.This()
     326             :             ->Equals(info.GetIsolate()->GetCurrentContext(), bottom)
     327             :             .FromJust());
     328          11 : }
     329             : 
     330             : 
     331          11 : void CheckThisNamedPropertyDeleter(
     332             :     Local<Name> property, const v8::PropertyCallbackInfo<v8::Boolean>& info) {
     333          11 :   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyDeleter));
     334          11 :   ApiTestFuzzer::Fuzz();
     335          33 :   CHECK(info.This()
     336             :             ->Equals(info.GetIsolate()->GetCurrentContext(), bottom)
     337             :             .FromJust());
     338          11 : }
     339             : 
     340             : 
     341          33 : void CheckThisIndexedPropertyEnumerator(
     342             :     const v8::PropertyCallbackInfo<v8::Array>& info) {
     343          33 :   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyEnumerator));
     344          33 :   ApiTestFuzzer::Fuzz();
     345          99 :   CHECK(info.This()
     346             :             ->Equals(info.GetIsolate()->GetCurrentContext(), bottom)
     347             :             .FromJust());
     348          33 : }
     349             : 
     350             : 
     351          33 : void CheckThisNamedPropertyEnumerator(
     352             :     const v8::PropertyCallbackInfo<v8::Array>& info) {
     353          33 :   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyEnumerator));
     354          33 :   ApiTestFuzzer::Fuzz();
     355          99 :   CHECK(info.This()
     356             :             ->Equals(info.GetIsolate()->GetCurrentContext(), bottom)
     357             :             .FromJust());
     358          33 : }
     359             : 
     360             : 
     361             : int echo_named_call_count;
     362             : 
     363             : 
     364          24 : void EchoNamedProperty(Local<Name> name,
     365             :                        const v8::PropertyCallbackInfo<v8::Value>& info) {
     366          24 :   ApiTestFuzzer::Fuzz();
     367          72 :   CHECK(v8_str("data")
     368             :             ->Equals(info.GetIsolate()->GetCurrentContext(), info.Data())
     369             :             .FromJust());
     370          24 :   echo_named_call_count++;
     371             :   info.GetReturnValue().Set(name);
     372          24 : }
     373             : 
     374          30 : void InterceptorHasOwnPropertyGetter(
     375             :     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
     376          30 :   ApiTestFuzzer::Fuzz();
     377          30 : }
     378             : 
     379          12 : void InterceptorHasOwnPropertyGetterGC(
     380             :     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
     381          12 :   ApiTestFuzzer::Fuzz();
     382          12 :   CcTest::CollectAllGarbage();
     383          12 : }
     384             : 
     385             : int query_counter_int = 0;
     386             : 
     387          48 : void QueryCallback(Local<Name> property,
     388             :                    const v8::PropertyCallbackInfo<v8::Integer>& info) {
     389          48 :   query_counter_int++;
     390          48 : }
     391             : 
     392             : }  // namespace
     393             : 
     394             : // Examples that show when the query callback is triggered.
     395       25881 : THREADED_TEST(QueryInterceptor) {
     396           6 :   v8::Isolate* isolate = CcTest::isolate();
     397           6 :   v8::HandleScope scope(isolate);
     398           6 :   v8::Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
     399             :   templ->InstanceTemplate()->SetHandler(
     400          12 :       v8::NamedPropertyHandlerConfiguration(nullptr, nullptr, QueryCallback));
     401          12 :   LocalContext env;
     402             :   env->Global()
     403           6 :       ->Set(env.local(), v8_str("obj"), templ->GetFunction(env.local())
     404           6 :                                             .ToLocalChecked()
     405           6 :                                             ->NewInstance(env.local())
     406          24 :                                             .ToLocalChecked())
     407          12 :       .FromJust();
     408           6 :   CHECK_EQ(0, query_counter_int);
     409             :   v8::Local<Value> result =
     410             :       v8_compile("Object.getOwnPropertyDescriptor(obj, 'x');")
     411           6 :           ->Run(env.local())
     412           6 :           .ToLocalChecked();
     413           6 :   CHECK_EQ(1, query_counter_int);
     414          12 :   CHECK_EQ(v8::PropertyAttribute::None,
     415             :            static_cast<v8::PropertyAttribute>(
     416             :                result->Int32Value(env.local()).FromJust()));
     417             : 
     418             :   v8_compile("Object.defineProperty(obj, 'not_enum', {value: 17});")
     419           6 :       ->Run(env.local())
     420           6 :       .ToLocalChecked();
     421           6 :   CHECK_EQ(2, query_counter_int);
     422             : 
     423             :   v8_compile(
     424             :       "Object.defineProperty(obj, 'enum', {value: 17, enumerable: true, "
     425             :       "writable: true});")
     426           6 :       ->Run(env.local())
     427           6 :       .ToLocalChecked();
     428           6 :   CHECK_EQ(3, query_counter_int);
     429             : 
     430          18 :   CHECK(v8_compile("obj.propertyIsEnumerable('enum');")
     431             :             ->Run(env.local())
     432             :             .ToLocalChecked()
     433             :             ->BooleanValue(isolate));
     434           6 :   CHECK_EQ(4, query_counter_int);
     435             : 
     436          18 :   CHECK(!v8_compile("obj.propertyIsEnumerable('not_enum');")
     437             :              ->Run(env.local())
     438             :              .ToLocalChecked()
     439             :              ->BooleanValue(isolate));
     440           6 :   CHECK_EQ(5, query_counter_int);
     441             : 
     442          18 :   CHECK(v8_compile("obj.hasOwnProperty('enum');")
     443             :             ->Run(env.local())
     444             :             .ToLocalChecked()
     445             :             ->BooleanValue(isolate));
     446           6 :   CHECK_EQ(5, query_counter_int);
     447             : 
     448          18 :   CHECK(v8_compile("obj.hasOwnProperty('not_enum');")
     449             :             ->Run(env.local())
     450             :             .ToLocalChecked()
     451             :             ->BooleanValue(isolate));
     452           6 :   CHECK_EQ(5, query_counter_int);
     453             : 
     454          18 :   CHECK(!v8_compile("obj.hasOwnProperty('x');")
     455             :              ->Run(env.local())
     456             :              .ToLocalChecked()
     457             :              ->BooleanValue(isolate));
     458           6 :   CHECK_EQ(6, query_counter_int);
     459             : 
     460          18 :   CHECK(!v8_compile("obj.propertyIsEnumerable('undef');")
     461             :              ->Run(env.local())
     462             :              .ToLocalChecked()
     463             :              ->BooleanValue(isolate));
     464           6 :   CHECK_EQ(7, query_counter_int);
     465             : 
     466             :   v8_compile("Object.defineProperty(obj, 'enum', {value: 42});")
     467           6 :       ->Run(env.local())
     468           6 :       .ToLocalChecked();
     469           6 :   CHECK_EQ(8, query_counter_int);
     470             : 
     471          12 :   v8_compile("Object.isFrozen('obj.x');")->Run(env.local()).ToLocalChecked();
     472          12 :   CHECK_EQ(8, query_counter_int);
     473           6 : }
     474             : 
     475             : namespace {
     476             : 
     477             : bool get_was_called = false;
     478             : bool set_was_called = false;
     479             : 
     480             : int set_was_called_counter = 0;
     481             : 
     482           6 : void GetterCallback(Local<Name> property,
     483             :                     const v8::PropertyCallbackInfo<v8::Value>& info) {
     484           6 :   get_was_called = true;
     485           6 : }
     486             : 
     487          30 : void SetterCallback(Local<Name> property, Local<Value> value,
     488             :                     const v8::PropertyCallbackInfo<v8::Value>& info) {
     489          30 :   set_was_called = true;
     490          30 :   set_was_called_counter++;
     491          30 : }
     492             : 
     493           6 : void InterceptingSetterCallback(
     494             :     Local<Name> property, Local<Value> value,
     495             :     const v8::PropertyCallbackInfo<v8::Value>& info) {
     496             :   info.GetReturnValue().Set(value);
     497           6 : }
     498             : 
     499             : }  // namespace
     500             : 
     501             : // Check that get callback is called in defineProperty with accessor descriptor.
     502       25881 : THREADED_TEST(DefinerCallbackAccessorInterceptor) {
     503           6 :   v8::HandleScope scope(CcTest::isolate());
     504             :   v8::Local<v8::FunctionTemplate> templ =
     505           6 :       v8::FunctionTemplate::New(CcTest::isolate());
     506             :   templ->InstanceTemplate()->SetHandler(
     507          12 :       v8::NamedPropertyHandlerConfiguration(GetterCallback, SetterCallback));
     508          12 :   LocalContext env;
     509             :   env->Global()
     510           6 :       ->Set(env.local(), v8_str("obj"), templ->GetFunction(env.local())
     511           6 :                                             .ToLocalChecked()
     512           6 :                                             ->NewInstance(env.local())
     513          24 :                                             .ToLocalChecked())
     514          12 :       .FromJust();
     515             : 
     516           6 :   get_was_called = false;
     517           6 :   set_was_called = false;
     518             : 
     519             :   v8_compile("Object.defineProperty(obj, 'x', {set: function() {return 17;}});")
     520           6 :       ->Run(env.local())
     521           6 :       .ToLocalChecked();
     522           6 :   CHECK(get_was_called);
     523          12 :   CHECK(!set_was_called);
     524           6 : }
     525             : 
     526             : // Check that set callback is called for function declarations.
     527       25881 : THREADED_TEST(SetterCallbackFunctionDeclarationInterceptor) {
     528           6 :   v8::HandleScope scope(CcTest::isolate());
     529          12 :   LocalContext env;
     530             :   v8::Local<v8::FunctionTemplate> templ =
     531           6 :       v8::FunctionTemplate::New(CcTest::isolate());
     532             : 
     533           6 :   v8::Local<ObjectTemplate> object_template = templ->InstanceTemplate();
     534             :   object_template->SetHandler(
     535           6 :       v8::NamedPropertyHandlerConfiguration(nullptr, SetterCallback));
     536             :   v8::Local<v8::Context> ctx =
     537           6 :       v8::Context::New(CcTest::isolate(), nullptr, object_template);
     538             : 
     539           6 :   set_was_called_counter = 0;
     540             : 
     541             :   // Declare function.
     542           6 :   v8::Local<v8::String> code = v8_str("function x() {return 42;}; x();");
     543          24 :   CHECK_EQ(42, v8::Script::Compile(ctx, code)
     544             :                    .ToLocalChecked()
     545             :                    ->Run(ctx)
     546             :                    .ToLocalChecked()
     547             :                    ->Int32Value(ctx)
     548             :                    .FromJust());
     549           6 :   CHECK_EQ(1, set_was_called_counter);
     550             : 
     551             :   // Redeclare function.
     552           6 :   code = v8_str("function x() {return 43;}; x();");
     553          24 :   CHECK_EQ(43, v8::Script::Compile(ctx, code)
     554             :                    .ToLocalChecked()
     555             :                    ->Run(ctx)
     556             :                    .ToLocalChecked()
     557             :                    ->Int32Value(ctx)
     558             :                    .FromJust());
     559           6 :   CHECK_EQ(2, set_was_called_counter);
     560             : 
     561             :   // Redefine function.
     562           6 :   code = v8_str("x = function() {return 44;}; x();");
     563          24 :   CHECK_EQ(44, v8::Script::Compile(ctx, code)
     564             :                    .ToLocalChecked()
     565             :                    ->Run(ctx)
     566             :                    .ToLocalChecked()
     567             :                    ->Int32Value(ctx)
     568             :                    .FromJust());
     569          12 :   CHECK_EQ(3, set_was_called_counter);
     570           6 : }
     571             : 
     572             : namespace {
     573             : int descriptor_was_called;
     574             : 
     575           6 : void PropertyDescriptorCallback(
     576             :     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
     577             :   // Intercept the callback by setting a different descriptor.
     578           6 :   descriptor_was_called++;
     579             :   const char* code =
     580             :       "var desc = {value: 5};"
     581             :       "desc;";
     582             :   Local<Value> descriptor = v8_compile(code)
     583           6 :                                 ->Run(info.GetIsolate()->GetCurrentContext())
     584           6 :                                 .ToLocalChecked();
     585             :   info.GetReturnValue().Set(descriptor);
     586           6 : }
     587             : }  // namespace
     588             : 
     589             : // Check that the descriptor callback is called on the global object.
     590       25881 : THREADED_TEST(DescriptorCallbackOnGlobalObject) {
     591           6 :   v8::HandleScope scope(CcTest::isolate());
     592          12 :   LocalContext env;
     593             :   v8::Local<v8::FunctionTemplate> templ =
     594           6 :       v8::FunctionTemplate::New(CcTest::isolate());
     595             : 
     596           6 :   v8::Local<ObjectTemplate> object_template = templ->InstanceTemplate();
     597             :   object_template->SetHandler(v8::NamedPropertyHandlerConfiguration(
     598           6 :       nullptr, nullptr, PropertyDescriptorCallback, nullptr, nullptr, nullptr));
     599             :   v8::Local<v8::Context> ctx =
     600           6 :       v8::Context::New(CcTest::isolate(), nullptr, object_template);
     601             : 
     602           6 :   descriptor_was_called = 0;
     603             : 
     604             :   // Declare function.
     605             :   v8::Local<v8::String> code = v8_str(
     606             :       "var x = 42; var desc = Object.getOwnPropertyDescriptor(this, 'x'); "
     607           6 :       "desc.value;");
     608          24 :   CHECK_EQ(5, v8::Script::Compile(ctx, code)
     609             :                   .ToLocalChecked()
     610             :                   ->Run(ctx)
     611             :                   .ToLocalChecked()
     612             :                   ->Int32Value(ctx)
     613             :                   .FromJust());
     614          12 :   CHECK_EQ(1, descriptor_was_called);
     615           6 : }
     616             : 
     617             : namespace {
     618          12 : void QueryCallbackSetDontDelete(
     619             :     Local<Name> property, const v8::PropertyCallbackInfo<v8::Integer>& info) {
     620             :   info.GetReturnValue().Set(v8::PropertyAttribute::DontDelete);
     621          12 : }
     622             : 
     623             : }  // namespace
     624             : 
     625             : // Regression for a Node.js test that fails in debug mode.
     626       25881 : THREADED_TEST(InterceptorFunctionRedeclareWithQueryCallback) {
     627           6 :   v8::HandleScope scope(CcTest::isolate());
     628          12 :   LocalContext env;
     629             :   v8::Local<v8::FunctionTemplate> templ =
     630           6 :       v8::FunctionTemplate::New(CcTest::isolate());
     631             : 
     632           6 :   v8::Local<ObjectTemplate> object_template = templ->InstanceTemplate();
     633             :   object_template->SetHandler(v8::NamedPropertyHandlerConfiguration(
     634           6 :       nullptr, nullptr, QueryCallbackSetDontDelete));
     635             :   v8::Local<v8::Context> ctx =
     636           6 :       v8::Context::New(CcTest::isolate(), nullptr, object_template);
     637             : 
     638             :   // Declare and redeclare function.
     639             :   v8::Local<v8::String> code = v8_str(
     640             :       "function x() {return 42;};"
     641           6 :       "function x() {return 43;};");
     642          18 :   v8::Script::Compile(ctx, code).ToLocalChecked()->Run(ctx).ToLocalChecked();
     643           6 : }
     644             : 
     645             : // Regression test for chromium bug 656648.
     646             : // Do not crash on non-masking, intercepting setter callbacks.
     647       25881 : THREADED_TEST(NonMaskingInterceptor) {
     648           6 :   v8::HandleScope scope(CcTest::isolate());
     649          12 :   LocalContext env;
     650             :   v8::Local<v8::FunctionTemplate> templ =
     651           6 :       v8::FunctionTemplate::New(CcTest::isolate());
     652             : 
     653           6 :   v8::Local<ObjectTemplate> object_template = templ->InstanceTemplate();
     654             :   object_template->SetHandler(v8::NamedPropertyHandlerConfiguration(
     655             :       nullptr, InterceptingSetterCallback, nullptr, nullptr, nullptr,
     656           6 :       Local<Value>(), v8::PropertyHandlerFlags::kNonMasking));
     657             :   v8::Local<v8::Context> ctx =
     658           6 :       v8::Context::New(CcTest::isolate(), nullptr, object_template);
     659             : 
     660           6 :   v8::Local<v8::String> code = v8_str("function x() {return 43;};");
     661          18 :   v8::Script::Compile(ctx, code).ToLocalChecked()->Run(ctx).ToLocalChecked();
     662           6 : }
     663             : 
     664             : // Check that function re-declarations throw if they are read-only.
     665       25881 : THREADED_TEST(SetterCallbackFunctionDeclarationInterceptorThrow) {
     666           6 :   v8::HandleScope scope(CcTest::isolate());
     667          12 :   LocalContext env;
     668             :   v8::Local<v8::FunctionTemplate> templ =
     669           6 :       v8::FunctionTemplate::New(CcTest::isolate());
     670             : 
     671           6 :   v8::Local<ObjectTemplate> object_template = templ->InstanceTemplate();
     672             :   object_template->SetHandler(
     673           6 :       v8::NamedPropertyHandlerConfiguration(nullptr, SetterCallback));
     674             :   v8::Local<v8::Context> ctx =
     675           6 :       v8::Context::New(CcTest::isolate(), nullptr, object_template);
     676             : 
     677           6 :   set_was_called = false;
     678             : 
     679             :   v8::Local<v8::String> code = v8_str(
     680             :       "function x() {return 42;};"
     681             :       "Object.defineProperty(this, 'x', {"
     682             :       "configurable: false, "
     683             :       "writable: false});"
     684           6 :       "x();");
     685          24 :   CHECK_EQ(42, v8::Script::Compile(ctx, code)
     686             :                    .ToLocalChecked()
     687             :                    ->Run(ctx)
     688             :                    .ToLocalChecked()
     689             :                    ->Int32Value(ctx)
     690             :                    .FromJust());
     691             : 
     692           6 :   CHECK(set_was_called);
     693             : 
     694          12 :   v8::TryCatch try_catch(CcTest::isolate());
     695           6 :   set_was_called = false;
     696             : 
     697             :   // Redeclare function that is read-only.
     698           6 :   code = v8_str("function x() {return 43;};");
     699          18 :   CHECK(v8::Script::Compile(ctx, code).ToLocalChecked()->Run(ctx).IsEmpty());
     700           6 :   CHECK(try_catch.HasCaught());
     701             : 
     702          12 :   CHECK(!set_was_called);
     703           6 : }
     704             : 
     705             : 
     706             : namespace {
     707             : 
     708             : bool get_was_called_in_order = false;
     709             : bool define_was_called_in_order = false;
     710             : 
     711          12 : void GetterCallbackOrder(Local<Name> property,
     712             :                          const v8::PropertyCallbackInfo<v8::Value>& info) {
     713          12 :   get_was_called_in_order = true;
     714          12 :   CHECK(!define_was_called_in_order);
     715             :   info.GetReturnValue().Set(property);
     716          12 : }
     717             : 
     718           6 : void DefinerCallbackOrder(Local<Name> property,
     719             :                           const v8::PropertyDescriptor& desc,
     720             :                           const v8::PropertyCallbackInfo<v8::Value>& info) {
     721             :   // Get called before DefineProperty because we query the descriptor first.
     722           6 :   CHECK(get_was_called_in_order);
     723           6 :   define_was_called_in_order = true;
     724           6 : }
     725             : 
     726             : }  // namespace
     727             : 
     728             : // Check that getter callback is called before definer callback.
     729       25881 : THREADED_TEST(DefinerCallbackGetAndDefine) {
     730           6 :   v8::HandleScope scope(CcTest::isolate());
     731             :   v8::Local<v8::FunctionTemplate> templ =
     732           6 :       v8::FunctionTemplate::New(CcTest::isolate());
     733             :   templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
     734             :       GetterCallbackOrder, SetterCallback, nullptr, nullptr, nullptr,
     735          12 :       DefinerCallbackOrder));
     736          12 :   LocalContext env;
     737             :   env->Global()
     738           6 :       ->Set(env.local(), v8_str("obj"), templ->GetFunction(env.local())
     739           6 :                                             .ToLocalChecked()
     740           6 :                                             ->NewInstance(env.local())
     741          24 :                                             .ToLocalChecked())
     742          12 :       .FromJust();
     743             : 
     744           6 :   CHECK(!get_was_called_in_order);
     745           6 :   CHECK(!define_was_called_in_order);
     746             : 
     747             :   v8_compile("Object.defineProperty(obj, 'x', {set: function() {return 17;}});")
     748           6 :       ->Run(env.local())
     749           6 :       .ToLocalChecked();
     750           6 :   CHECK(get_was_called_in_order);
     751          12 :   CHECK(define_was_called_in_order);
     752           6 : }
     753             : 
     754             : namespace {  //  namespace for InObjectLiteralDefinitionWithInterceptor
     755             : 
     756             : // Workaround for no-snapshot builds: only intercept once Context::New() is
     757             : // done, otherwise we'll intercept
     758             : // bootstrapping like defining array on the global object.
     759             : bool context_is_done = false;
     760             : bool getter_callback_was_called = false;
     761             : 
     762           6 : void ReturnUndefinedGetterCallback(
     763             :     Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {
     764           6 :   if (context_is_done) {
     765           6 :     getter_callback_was_called = true;
     766             :     info.GetReturnValue().SetUndefined();
     767             :   }
     768           6 : }
     769             : 
     770             : }  // namespace
     771             : 
     772             : // Check that an interceptor is not invoked during ES6 style definitions inside
     773             : // an object literal.
     774       25881 : THREADED_TEST(InObjectLiteralDefinitionWithInterceptor) {
     775           6 :   v8::HandleScope scope(CcTest::isolate());
     776          12 :   LocalContext env;
     777             : 
     778             :   // Set up a context in which all global object definitions are intercepted.
     779             :   v8::Local<v8::FunctionTemplate> templ =
     780           6 :       v8::FunctionTemplate::New(CcTest::isolate());
     781           6 :   v8::Local<ObjectTemplate> object_template = templ->InstanceTemplate();
     782             :   object_template->SetHandler(
     783           6 :       v8::NamedPropertyHandlerConfiguration(ReturnUndefinedGetterCallback));
     784             :   v8::Local<v8::Context> ctx =
     785           6 :       v8::Context::New(CcTest::isolate(), nullptr, object_template);
     786             : 
     787           6 :   context_is_done = true;
     788             : 
     789             :   // The interceptor returns undefined for any global object,
     790             :   // so setting a property on an object should throw.
     791           6 :   v8::Local<v8::String> code = v8_str("var o = {}; o.x = 5");
     792             :   {
     793           6 :     getter_callback_was_called = false;
     794           6 :     v8::TryCatch try_catch(CcTest::isolate());
     795          18 :     CHECK(v8::Script::Compile(ctx, code).ToLocalChecked()->Run(ctx).IsEmpty());
     796           6 :     CHECK(try_catch.HasCaught());
     797           6 :     CHECK(getter_callback_was_called);
     798             :   }
     799             : 
     800             :   // Defining a property in the object literal should not throw
     801             :   // because the interceptor is not invoked.
     802             :   {
     803           6 :     getter_callback_was_called = false;
     804           6 :     v8::TryCatch try_catch(CcTest::isolate());
     805           6 :     code = v8_str("var l = {x: 5};");
     806          18 :     CHECK(v8::Script::Compile(ctx, code)
     807             :               .ToLocalChecked()
     808             :               ->Run(ctx)
     809             :               .ToLocalChecked()
     810             :               ->IsUndefined());
     811           6 :     CHECK(!try_catch.HasCaught());
     812           6 :     CHECK(!getter_callback_was_called);
     813           6 :   }
     814           6 : }
     815             : 
     816       25881 : THREADED_TEST(InterceptorHasOwnProperty) {
     817           6 :   LocalContext context;
     818           6 :   v8::Isolate* isolate = context->GetIsolate();
     819          12 :   v8::HandleScope scope(isolate);
     820           6 :   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
     821           6 :   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
     822             :   instance_templ->SetHandler(
     823           6 :       v8::NamedPropertyHandlerConfiguration(InterceptorHasOwnPropertyGetter));
     824             :   Local<Function> function =
     825           6 :       fun_templ->GetFunction(context.local()).ToLocalChecked();
     826             :   context->Global()
     827          24 :       ->Set(context.local(), v8_str("constructor"), function)
     828          12 :       .FromJust();
     829             :   v8::Local<Value> value = CompileRun(
     830             :       "var o = new constructor();"
     831             :       "o.hasOwnProperty('ostehaps');");
     832           6 :   CHECK(!value->BooleanValue(isolate));
     833             :   value = CompileRun(
     834             :       "o.ostehaps = 42;"
     835             :       "o.hasOwnProperty('ostehaps');");
     836           6 :   CHECK(value->BooleanValue(isolate));
     837             :   value = CompileRun(
     838             :       "var p = new constructor();"
     839             :       "p.hasOwnProperty('ostehaps');");
     840          12 :   CHECK(!value->BooleanValue(isolate));
     841           6 : }
     842             : 
     843             : 
     844       25881 : THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
     845           6 :   LocalContext context;
     846           6 :   v8::Isolate* isolate = context->GetIsolate();
     847          12 :   v8::HandleScope scope(isolate);
     848           6 :   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
     849           6 :   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
     850             :   instance_templ->SetHandler(
     851           6 :       v8::NamedPropertyHandlerConfiguration(InterceptorHasOwnPropertyGetterGC));
     852             :   Local<Function> function =
     853           6 :       fun_templ->GetFunction(context.local()).ToLocalChecked();
     854             :   context->Global()
     855          24 :       ->Set(context.local(), v8_str("constructor"), function)
     856          12 :       .FromJust();
     857             :   // Let's first make some stuff so we can be sure to get a good GC.
     858             :   CompileRun(
     859             :       "function makestr(size) {"
     860             :       "  switch (size) {"
     861             :       "    case 1: return 'f';"
     862             :       "    case 2: return 'fo';"
     863             :       "    case 3: return 'foo';"
     864             :       "  }"
     865             :       "  return makestr(size >> 1) + makestr((size + 1) >> 1);"
     866             :       "}"
     867             :       "var x = makestr(12345);"
     868             :       "x = makestr(31415);"
     869             :       "x = makestr(23456);");
     870             :   v8::Local<Value> value = CompileRun(
     871             :       "var o = new constructor();"
     872             :       "o.__proto__ = new String(x);"
     873             :       "o.hasOwnProperty('ostehaps');");
     874          12 :   CHECK(!value->BooleanValue(isolate));
     875           6 : }
     876             : 
     877             : 
     878          66 : static void CheckInterceptorLoadIC(
     879             :     v8::GenericNamedPropertyGetterCallback getter, const char* source,
     880             :     int expected) {
     881          66 :   v8::Isolate* isolate = CcTest::isolate();
     882          66 :   v8::HandleScope scope(isolate);
     883          66 :   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
     884             :   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
     885         132 :       getter, nullptr, nullptr, nullptr, nullptr, v8_str("data")));
     886         132 :   LocalContext context;
     887             :   context->Global()
     888             :       ->Set(context.local(), v8_str("o"),
     889         330 :             templ->NewInstance(context.local()).ToLocalChecked())
     890         132 :       .FromJust();
     891             :   v8::Local<Value> value = CompileRun(source);
     892         198 :   CHECK_EQ(expected, value->Int32Value(context.local()).FromJust());
     893          66 : }
     894             : 
     895             : 
     896        6000 : static void InterceptorLoadICGetter(
     897             :     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
     898        6000 :   ApiTestFuzzer::Fuzz();
     899        6000 :   v8::Isolate* isolate = CcTest::isolate();
     900        6000 :   CHECK_EQ(isolate, info.GetIsolate());
     901        6000 :   v8::Local<v8::Context> context = isolate->GetCurrentContext();
     902       18000 :   CHECK(v8_str("data")->Equals(context, info.Data()).FromJust());
     903       18000 :   CHECK(v8_str("x")->Equals(context, name).FromJust());
     904        6000 :   info.GetReturnValue().Set(v8::Integer::New(isolate, 42));
     905        6000 : }
     906             : 
     907             : 
     908             : // This test should hit the load IC for the interceptor case.
     909       25881 : THREADED_TEST(InterceptorLoadIC) {
     910             :   CheckInterceptorLoadIC(InterceptorLoadICGetter,
     911             :                          "var result = 0;"
     912             :                          "for (var i = 0; i < 1000; i++) {"
     913             :                          "  result = o.x;"
     914             :                          "}",
     915           6 :                          42);
     916           6 : }
     917             : 
     918             : 
     919             : // Below go several tests which verify that JITing for various
     920             : // configurations of interceptor and explicit fields works fine
     921             : // (those cases are special cased to get better performance).
     922             : 
     923       66780 : static void InterceptorLoadXICGetter(
     924             :     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
     925       66780 :   ApiTestFuzzer::Fuzz();
     926             :   info.GetReturnValue().Set(
     927             :       v8_str("x")
     928      133560 :               ->Equals(info.GetIsolate()->GetCurrentContext(), name)
     929      133560 :               .FromJust()
     930             :           ? v8::Local<v8::Value>(v8::Integer::New(info.GetIsolate(), 42))
     931       97014 :           : v8::Local<v8::Value>());
     932       66780 : }
     933             : 
     934             : 
     935       25881 : THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
     936             :   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
     937             :                          "var result = 0;"
     938             :                          "o.y = 239;"
     939             :                          "for (var i = 0; i < 1000; i++) {"
     940             :                          "  result = o.y;"
     941             :                          "}",
     942           6 :                          239);
     943           6 : }
     944             : 
     945             : 
     946       25881 : THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
     947             :   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
     948             :                          "var result = 0;"
     949             :                          "o.__proto__ = { 'y': 239 };"
     950             :                          "for (var i = 0; i < 1000; i++) {"
     951             :                          "  result = o.y + o.x;"
     952             :                          "}",
     953           6 :                          239 + 42);
     954           6 : }
     955             : 
     956             : 
     957       25881 : THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
     958             :   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
     959             :                          "var result = 0;"
     960             :                          "o.__proto__.y = 239;"
     961             :                          "for (var i = 0; i < 1000; i++) {"
     962             :                          "  result = o.y + o.x;"
     963             :                          "}",
     964           6 :                          239 + 42);
     965           6 : }
     966             : 
     967             : 
     968       25881 : THREADED_TEST(InterceptorLoadICUndefined) {
     969             :   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
     970             :                          "var result = 0;"
     971             :                          "for (var i = 0; i < 1000; i++) {"
     972             :                          "  result = (o.y == undefined) ? 239 : 42;"
     973             :                          "}",
     974           6 :                          239);
     975           6 : }
     976             : 
     977             : 
     978       25881 : THREADED_TEST(InterceptorLoadICWithOverride) {
     979             :   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
     980             :                          "fst = new Object();  fst.__proto__ = o;"
     981             :                          "snd = new Object();  snd.__proto__ = fst;"
     982             :                          "var result1 = 0;"
     983             :                          "for (var i = 0; i < 1000;  i++) {"
     984             :                          "  result1 = snd.x;"
     985             :                          "}"
     986             :                          "fst.x = 239;"
     987             :                          "var result = 0;"
     988             :                          "for (var i = 0; i < 1000; i++) {"
     989             :                          "  result = snd.x;"
     990             :                          "}"
     991             :                          "result + result1",
     992           6 :                          239 + 42);
     993           6 : }
     994             : 
     995             : 
     996             : // Test the case when we stored field into
     997             : // a stub, but interceptor produced value on its own.
     998       25881 : THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
     999             :   CheckInterceptorLoadIC(
    1000             :       InterceptorLoadXICGetter,
    1001             :       "proto = new Object();"
    1002             :       "o.__proto__ = proto;"
    1003             :       "proto.x = 239;"
    1004             :       "for (var i = 0; i < 1000; i++) {"
    1005             :       "  o.x;"
    1006             :       // Now it should be ICed and keep a reference to x defined on proto
    1007             :       "}"
    1008             :       "var result = 0;"
    1009             :       "for (var i = 0; i < 1000; i++) {"
    1010             :       "  result += o.x;"
    1011             :       "}"
    1012             :       "result;",
    1013           6 :       42 * 1000);
    1014           6 : }
    1015             : 
    1016             : 
    1017             : // Test the case when we stored field into
    1018             : // a stub, but it got invalidated later on.
    1019       25881 : THREADED_TEST(InterceptorLoadICInvalidatedField) {
    1020             :   CheckInterceptorLoadIC(
    1021             :       InterceptorLoadXICGetter,
    1022             :       "proto1 = new Object();"
    1023             :       "proto2 = new Object();"
    1024             :       "o.__proto__ = proto1;"
    1025             :       "proto1.__proto__ = proto2;"
    1026             :       "proto2.y = 239;"
    1027             :       "for (var i = 0; i < 1000; i++) {"
    1028             :       "  o.y;"
    1029             :       // Now it should be ICed and keep a reference to y defined on proto2
    1030             :       "}"
    1031             :       "proto1.y = 42;"
    1032             :       "var result = 0;"
    1033             :       "for (var i = 0; i < 1000; i++) {"
    1034             :       "  result += o.y;"
    1035             :       "}"
    1036             :       "result;",
    1037           6 :       42 * 1000);
    1038           6 : }
    1039             : 
    1040             : 
    1041             : static int interceptor_load_not_handled_calls = 0;
    1042        6000 : static void InterceptorLoadNotHandled(
    1043             :     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
    1044        6000 :   ++interceptor_load_not_handled_calls;
    1045        6000 : }
    1046             : 
    1047             : 
    1048             : // Test how post-interceptor lookups are done in the non-cacheable
    1049             : // case: the interceptor should not be invoked during this lookup.
    1050       25881 : THREADED_TEST(InterceptorLoadICPostInterceptor) {
    1051           6 :   interceptor_load_not_handled_calls = 0;
    1052             :   CheckInterceptorLoadIC(InterceptorLoadNotHandled,
    1053             :                          "receiver = new Object();"
    1054             :                          "receiver.__proto__ = o;"
    1055             :                          "proto = new Object();"
    1056             :                          "/* Make proto a slow-case object. */"
    1057             :                          "for (var i = 0; i < 1000; i++) {"
    1058             :                          "  proto[\"xxxxxxxx\" + i] = [];"
    1059             :                          "}"
    1060             :                          "proto.x = 17;"
    1061             :                          "o.__proto__ = proto;"
    1062             :                          "var result = 0;"
    1063             :                          "for (var i = 0; i < 1000; i++) {"
    1064             :                          "  result += receiver.x;"
    1065             :                          "}"
    1066             :                          "result;",
    1067           6 :                          17 * 1000);
    1068           6 :   CHECK_EQ(1000, interceptor_load_not_handled_calls);
    1069           6 : }
    1070             : 
    1071             : 
    1072             : // Test the case when we stored field into
    1073             : // a stub, but it got invalidated later on due to override on
    1074             : // global object which is between interceptor and fields' holders.
    1075       25881 : THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
    1076             :   CheckInterceptorLoadIC(
    1077             :       InterceptorLoadXICGetter,
    1078             :       "o.__proto__ = this;"  // set a global to be a proto of o.
    1079             :       "this.__proto__.y = 239;"
    1080             :       "for (var i = 0; i < 10; i++) {"
    1081             :       "  if (o.y != 239) throw 'oops: ' + o.y;"
    1082             :       // Now it should be ICed and keep a reference to y defined on
    1083             :       // field_holder.
    1084             :       "}"
    1085             :       "this.y = 42;"  // Assign on a global.
    1086             :       "var result = 0;"
    1087             :       "for (var i = 0; i < 10; i++) {"
    1088             :       "  result += o.y;"
    1089             :       "}"
    1090             :       "result;",
    1091           6 :       42 * 10);
    1092           6 : }
    1093             : 
    1094             : 
    1095          12 : static void SetOnThis(Local<String> name, Local<Value> value,
    1096             :                       const v8::PropertyCallbackInfo<void>& info) {
    1097             :   Local<Object>::Cast(info.This())
    1098          24 :       ->CreateDataProperty(info.GetIsolate()->GetCurrentContext(), name, value)
    1099          24 :       .FromJust();
    1100          12 : }
    1101             : 
    1102             : 
    1103       25881 : THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
    1104           6 :   v8::Isolate* isolate = CcTest::isolate();
    1105           6 :   v8::HandleScope scope(isolate);
    1106           6 :   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
    1107             :   templ->SetHandler(
    1108           6 :       v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
    1109           6 :   templ->SetAccessor(v8_str("y"), Return239Callback);
    1110          12 :   LocalContext context;
    1111             :   context->Global()
    1112             :       ->Set(context.local(), v8_str("o"),
    1113          30 :             templ->NewInstance(context.local()).ToLocalChecked())
    1114          12 :       .FromJust();
    1115             : 
    1116             :   // Check the case when receiver and interceptor's holder
    1117             :   // are the same objects.
    1118             :   v8::Local<Value> value = CompileRun(
    1119             :       "var result = 0;"
    1120             :       "for (var i = 0; i < 7; i++) {"
    1121             :       "  result = o.y;"
    1122             :       "}");
    1123          12 :   CHECK_EQ(239, value->Int32Value(context.local()).FromJust());
    1124             : 
    1125             :   // Check the case when interceptor's holder is in proto chain
    1126             :   // of receiver.
    1127             :   value = CompileRun(
    1128             :       "r = { __proto__: o };"
    1129             :       "var result = 0;"
    1130             :       "for (var i = 0; i < 7; i++) {"
    1131             :       "  result = r.y;"
    1132             :       "}");
    1133          18 :   CHECK_EQ(239, value->Int32Value(context.local()).FromJust());
    1134           6 : }
    1135             : 
    1136             : 
    1137       25881 : THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
    1138           6 :   v8::Isolate* isolate = CcTest::isolate();
    1139           6 :   v8::HandleScope scope(isolate);
    1140           6 :   v8::Local<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
    1141             :   templ_o->SetHandler(
    1142           6 :       v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
    1143           6 :   v8::Local<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
    1144           6 :   templ_p->SetAccessor(v8_str("y"), Return239Callback);
    1145             : 
    1146          12 :   LocalContext context;
    1147             :   context->Global()
    1148             :       ->Set(context.local(), v8_str("o"),
    1149          30 :             templ_o->NewInstance(context.local()).ToLocalChecked())
    1150          12 :       .FromJust();
    1151             :   context->Global()
    1152             :       ->Set(context.local(), v8_str("p"),
    1153          30 :             templ_p->NewInstance(context.local()).ToLocalChecked())
    1154          12 :       .FromJust();
    1155             : 
    1156             :   // Check the case when receiver and interceptor's holder
    1157             :   // are the same objects.
    1158             :   v8::Local<Value> value = CompileRun(
    1159             :       "o.__proto__ = p;"
    1160             :       "var result = 0;"
    1161             :       "for (var i = 0; i < 7; i++) {"
    1162             :       "  result = o.x + o.y;"
    1163             :       "}");
    1164          12 :   CHECK_EQ(239 + 42, value->Int32Value(context.local()).FromJust());
    1165             : 
    1166             :   // Check the case when interceptor's holder is in proto chain
    1167             :   // of receiver.
    1168             :   value = CompileRun(
    1169             :       "r = { __proto__: o };"
    1170             :       "var result = 0;"
    1171             :       "for (var i = 0; i < 7; i++) {"
    1172             :       "  result = r.x + r.y;"
    1173             :       "}");
    1174          18 :   CHECK_EQ(239 + 42, value->Int32Value(context.local()).FromJust());
    1175           6 : }
    1176             : 
    1177             : 
    1178       25881 : THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
    1179           6 :   v8::Isolate* isolate = CcTest::isolate();
    1180           6 :   v8::HandleScope scope(isolate);
    1181           6 :   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
    1182             :   templ->SetHandler(
    1183           6 :       v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
    1184           6 :   templ->SetAccessor(v8_str("y"), Return239Callback);
    1185             : 
    1186          12 :   LocalContext context;
    1187             :   context->Global()
    1188             :       ->Set(context.local(), v8_str("o"),
    1189          30 :             templ->NewInstance(context.local()).ToLocalChecked())
    1190          12 :       .FromJust();
    1191             : 
    1192             :   v8::Local<Value> value = CompileRun(
    1193             :       "fst = new Object();  fst.__proto__ = o;"
    1194             :       "snd = new Object();  snd.__proto__ = fst;"
    1195             :       "var result1 = 0;"
    1196             :       "for (var i = 0; i < 7;  i++) {"
    1197             :       "  result1 = snd.x;"
    1198             :       "}"
    1199             :       "fst.x = 239;"
    1200             :       "var result = 0;"
    1201             :       "for (var i = 0; i < 7; i++) {"
    1202             :       "  result = snd.x;"
    1203             :       "}"
    1204             :       "result + result1");
    1205          18 :   CHECK_EQ(239 + 42, value->Int32Value(context.local()).FromJust());
    1206           6 : }
    1207             : 
    1208             : 
    1209             : // Test the case when we stored callback into
    1210             : // a stub, but interceptor produced value on its own.
    1211       25881 : THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
    1212           6 :   v8::Isolate* isolate = CcTest::isolate();
    1213           6 :   v8::HandleScope scope(isolate);
    1214           6 :   v8::Local<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
    1215             :   templ_o->SetHandler(
    1216           6 :       v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
    1217           6 :   v8::Local<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
    1218           6 :   templ_p->SetAccessor(v8_str("y"), Return239Callback);
    1219             : 
    1220          12 :   LocalContext context;
    1221             :   context->Global()
    1222             :       ->Set(context.local(), v8_str("o"),
    1223          30 :             templ_o->NewInstance(context.local()).ToLocalChecked())
    1224          12 :       .FromJust();
    1225             :   context->Global()
    1226             :       ->Set(context.local(), v8_str("p"),
    1227          30 :             templ_p->NewInstance(context.local()).ToLocalChecked())
    1228          12 :       .FromJust();
    1229             : 
    1230             :   v8::Local<Value> value = CompileRun(
    1231             :       "o.__proto__ = p;"
    1232             :       "for (var i = 0; i < 7; i++) {"
    1233             :       "  o.x;"
    1234             :       // Now it should be ICed and keep a reference to x defined on p
    1235             :       "}"
    1236             :       "var result = 0;"
    1237             :       "for (var i = 0; i < 7; i++) {"
    1238             :       "  result += o.x;"
    1239             :       "}"
    1240             :       "result");
    1241          18 :   CHECK_EQ(42 * 7, value->Int32Value(context.local()).FromJust());
    1242           6 : }
    1243             : 
    1244             : 
    1245             : // Test the case when we stored callback into
    1246             : // a stub, but it got invalidated later on.
    1247       25881 : THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
    1248           6 :   v8::Isolate* isolate = CcTest::isolate();
    1249           6 :   v8::HandleScope scope(isolate);
    1250           6 :   v8::Local<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
    1251             :   templ_o->SetHandler(
    1252           6 :       v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
    1253           6 :   v8::Local<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
    1254           6 :   templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
    1255             : 
    1256          12 :   LocalContext context;
    1257             :   context->Global()
    1258             :       ->Set(context.local(), v8_str("o"),
    1259          30 :             templ_o->NewInstance(context.local()).ToLocalChecked())
    1260          12 :       .FromJust();
    1261             :   context->Global()
    1262             :       ->Set(context.local(), v8_str("p"),
    1263          30 :             templ_p->NewInstance(context.local()).ToLocalChecked())
    1264          12 :       .FromJust();
    1265             : 
    1266             :   v8::Local<Value> value = CompileRun(
    1267             :       "inbetween = new Object();"
    1268             :       "o.__proto__ = inbetween;"
    1269             :       "inbetween.__proto__ = p;"
    1270             :       "for (var i = 0; i < 10; i++) {"
    1271             :       "  o.y;"
    1272             :       // Now it should be ICed and keep a reference to y defined on p
    1273             :       "}"
    1274             :       "inbetween.y = 42;"
    1275             :       "var result = 0;"
    1276             :       "for (var i = 0; i < 10; i++) {"
    1277             :       "  result += o.y;"
    1278             :       "}"
    1279             :       "result");
    1280          18 :   CHECK_EQ(42 * 10, value->Int32Value(context.local()).FromJust());
    1281           6 : }
    1282             : 
    1283             : 
    1284             : // Test the case when we stored callback into
    1285             : // a stub, but it got invalidated later on due to override on
    1286             : // global object which is between interceptor and callbacks' holders.
    1287       25881 : THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
    1288           6 :   v8::Isolate* isolate = CcTest::isolate();
    1289           6 :   v8::HandleScope scope(isolate);
    1290           6 :   v8::Local<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
    1291             :   templ_o->SetHandler(
    1292           6 :       v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
    1293           6 :   v8::Local<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
    1294           6 :   templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
    1295             : 
    1296          12 :   LocalContext context;
    1297             :   context->Global()
    1298             :       ->Set(context.local(), v8_str("o"),
    1299          30 :             templ_o->NewInstance(context.local()).ToLocalChecked())
    1300          12 :       .FromJust();
    1301             :   context->Global()
    1302             :       ->Set(context.local(), v8_str("p"),
    1303          30 :             templ_p->NewInstance(context.local()).ToLocalChecked())
    1304          12 :       .FromJust();
    1305             : 
    1306             :   v8::Local<Value> value = CompileRun(
    1307             :       "o.__proto__ = this;"
    1308             :       "this.__proto__ = p;"
    1309             :       "for (var i = 0; i < 10; i++) {"
    1310             :       "  if (o.y != 239) throw 'oops: ' + o.y;"
    1311             :       // Now it should be ICed and keep a reference to y defined on p
    1312             :       "}"
    1313             :       "this.y = 42;"
    1314             :       "var result = 0;"
    1315             :       "for (var i = 0; i < 10; i++) {"
    1316             :       "  result += o.y;"
    1317             :       "}"
    1318             :       "result");
    1319          18 :   CHECK_EQ(42 * 10, value->Int32Value(context.local()).FromJust());
    1320           6 : }
    1321             : 
    1322             : // Test load of a non-existing global when a global object has an interceptor.
    1323       25881 : THREADED_TEST(InterceptorLoadGlobalICGlobalWithInterceptor) {
    1324           6 :   v8::Isolate* isolate = CcTest::isolate();
    1325           6 :   v8::HandleScope scope(isolate);
    1326           6 :   v8::Local<v8::ObjectTemplate> templ_global = v8::ObjectTemplate::New(isolate);
    1327             :   templ_global->SetHandler(v8::NamedPropertyHandlerConfiguration(
    1328           6 :       EmptyInterceptorGetter, EmptyInterceptorSetter));
    1329             : 
    1330          12 :   LocalContext context(nullptr, templ_global);
    1331             :   i::Handle<i::JSReceiver> global_proxy =
    1332           6 :       v8::Utils::OpenHandle<Object, i::JSReceiver>(context->Global());
    1333          12 :   CHECK(global_proxy->IsJSGlobalProxy());
    1334             :   i::Handle<i::JSGlobalObject> global(
    1335             :       i::JSGlobalObject::cast(global_proxy->map()->prototype()),
    1336             :       global_proxy->GetIsolate());
    1337           6 :   CHECK(global->map()->has_named_interceptor());
    1338             : 
    1339             :   v8::Local<Value> value = CompileRun(
    1340             :       "var f = function() { "
    1341             :       "  try {"
    1342             :       "    x1;"
    1343             :       "  } catch(e) {"
    1344             :       "  }"
    1345             :       "  return typeof x1 === 'undefined';"
    1346             :       "};"
    1347             :       "for (var i = 0; i < 10; i++) {"
    1348             :       "  f();"
    1349             :       "};"
    1350             :       "f();");
    1351           6 :   CHECK(value->BooleanValue(isolate));
    1352             : 
    1353             :   value = CompileRun(
    1354             :       "var f = function() { "
    1355             :       "  try {"
    1356             :       "    x2;"
    1357             :       "    return false;"
    1358             :       "  } catch(e) {"
    1359             :       "    return true;"
    1360             :       "  }"
    1361             :       "};"
    1362             :       "for (var i = 0; i < 10; i++) {"
    1363             :       "  f();"
    1364             :       "};"
    1365             :       "f();");
    1366           6 :   CHECK(value->BooleanValue(isolate));
    1367             : 
    1368             :   value = CompileRun(
    1369             :       "var f = function() { "
    1370             :       "  try {"
    1371             :       "    typeof(x3);"
    1372             :       "    return true;"
    1373             :       "  } catch(e) {"
    1374             :       "    return false;"
    1375             :       "  }"
    1376             :       "};"
    1377             :       "for (var i = 0; i < 10; i++) {"
    1378             :       "  f();"
    1379             :       "};"
    1380             :       "f();");
    1381          12 :   CHECK(value->BooleanValue(isolate));
    1382           6 : }
    1383             : 
    1384             : // Test load of a non-existing global through prototype chain when a global
    1385             : // object has an interceptor.
    1386       25881 : THREADED_TEST(InterceptorLoadICGlobalWithInterceptor) {
    1387           6 :   i::FLAG_allow_natives_syntax = true;
    1388           6 :   v8::Isolate* isolate = CcTest::isolate();
    1389           6 :   v8::HandleScope scope(isolate);
    1390           6 :   v8::Local<v8::ObjectTemplate> templ_global = v8::ObjectTemplate::New(isolate);
    1391             :   templ_global->SetHandler(v8::NamedPropertyHandlerConfiguration(
    1392           6 :       GenericInterceptorGetter, GenericInterceptorSetter));
    1393             : 
    1394          12 :   LocalContext context(nullptr, templ_global);
    1395             :   i::Handle<i::JSReceiver> global_proxy =
    1396           6 :       v8::Utils::OpenHandle<Object, i::JSReceiver>(context->Global());
    1397          12 :   CHECK(global_proxy->IsJSGlobalProxy());
    1398             :   i::Handle<i::JSGlobalObject> global(
    1399             :       i::JSGlobalObject::cast(global_proxy->map()->prototype()),
    1400             :       global_proxy->GetIsolate());
    1401           6 :   CHECK(global->map()->has_named_interceptor());
    1402             : 
    1403             :   ExpectInt32(
    1404             :       "(function() {"
    1405             :       "  var f = function(obj) { "
    1406             :       "    return obj.foo;"
    1407             :       "  };"
    1408             :       "  var obj = { __proto__: this, _str_foo: 42 };"
    1409             :       "  for (var i = 0; i < 1500; i++) obj['p' + i] = 0;"
    1410             :       "  /* Ensure that |obj| is in dictionary mode. */"
    1411             :       "  if (%HasFastProperties(obj)) return -1;"
    1412             :       "  for (var i = 0; i < 3; i++) {"
    1413             :       "    f(obj);"
    1414             :       "  };"
    1415             :       "  return f(obj);"
    1416             :       "})();",
    1417          12 :       42);
    1418           6 : }
    1419             : 
    1420           6 : static void InterceptorLoadICGetter0(
    1421             :     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
    1422           6 :   ApiTestFuzzer::Fuzz();
    1423          18 :   CHECK(v8_str("x")
    1424             :             ->Equals(info.GetIsolate()->GetCurrentContext(), name)
    1425             :             .FromJust());
    1426           6 :   info.GetReturnValue().Set(v8::Integer::New(info.GetIsolate(), 0));
    1427           6 : }
    1428             : 
    1429             : 
    1430       25881 : THREADED_TEST(InterceptorReturningZero) {
    1431             :   CheckInterceptorLoadIC(InterceptorLoadICGetter0, "o.x == undefined ? 1 : 0",
    1432           6 :                          0);
    1433           6 : }
    1434             : 
    1435             : 
    1436        6000 : static void InterceptorStoreICSetter(
    1437             :     Local<Name> key, Local<Value> value,
    1438             :     const v8::PropertyCallbackInfo<v8::Value>& info) {
    1439        6000 :   v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
    1440       18000 :   CHECK(v8_str("x")->Equals(context, key).FromJust());
    1441       12000 :   CHECK_EQ(42, value->Int32Value(context).FromJust());
    1442             :   info.GetReturnValue().Set(value);
    1443        6000 : }
    1444             : 
    1445             : 
    1446             : // This test should hit the store IC for the interceptor case.
    1447       25881 : THREADED_TEST(InterceptorStoreIC) {
    1448           6 :   v8::Isolate* isolate = CcTest::isolate();
    1449           6 :   v8::HandleScope scope(isolate);
    1450           6 :   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
    1451             :   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
    1452             :       InterceptorLoadICGetter, InterceptorStoreICSetter, nullptr, nullptr,
    1453          12 :       nullptr, v8_str("data")));
    1454          12 :   LocalContext context;
    1455             :   context->Global()
    1456             :       ->Set(context.local(), v8_str("o"),
    1457          30 :             templ->NewInstance(context.local()).ToLocalChecked())
    1458          12 :       .FromJust();
    1459             :   CompileRun(
    1460             :       "for (var i = 0; i < 1000; i++) {"
    1461             :       "  o.x = 42;"
    1462           6 :       "}");
    1463           6 : }
    1464             : 
    1465             : 
    1466       25881 : THREADED_TEST(InterceptorStoreICWithNoSetter) {
    1467           6 :   v8::Isolate* isolate = CcTest::isolate();
    1468           6 :   v8::HandleScope scope(isolate);
    1469           6 :   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
    1470             :   templ->SetHandler(
    1471           6 :       v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
    1472          12 :   LocalContext context;
    1473             :   context->Global()
    1474             :       ->Set(context.local(), v8_str("o"),
    1475          30 :             templ->NewInstance(context.local()).ToLocalChecked())
    1476          12 :       .FromJust();
    1477             :   v8::Local<Value> value = CompileRun(
    1478             :       "for (var i = 0; i < 1000; i++) {"
    1479             :       "  o.y = 239;"
    1480             :       "}"
    1481             :       "42 + o.y");
    1482          18 :   CHECK_EQ(239 + 42, value->Int32Value(context.local()).FromJust());
    1483           6 : }
    1484             : 
    1485             : 
    1486       25881 : THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
    1487           6 :   v8::HandleScope scope(CcTest::isolate());
    1488           6 :   Local<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
    1489           6 :   Local<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
    1490           6 :   child->Inherit(parent);
    1491             :   AddAccessor(parent, v8_str("age"), SimpleAccessorGetter,
    1492           6 :               SimpleAccessorSetter);
    1493           6 :   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
    1494          12 :   LocalContext env;
    1495             :   env->Global()
    1496             :       ->Set(env.local(), v8_str("Child"),
    1497          30 :             child->GetFunction(env.local()).ToLocalChecked())
    1498          12 :       .FromJust();
    1499             :   CompileRun(
    1500             :       "var child = new Child;"
    1501             :       "child.age = 10;");
    1502           6 :   ExpectBoolean("child.hasOwnProperty('age')", false);
    1503           6 :   ExpectInt32("child.age", 10);
    1504          12 :   ExpectInt32("child.accessor_age", 10);
    1505           6 : }
    1506             : 
    1507             : 
    1508       25881 : THREADED_TEST(LegacyInterceptorDoesNotSeeSymbols) {
    1509           6 :   LocalContext env;
    1510           6 :   v8::Isolate* isolate = CcTest::isolate();
    1511          12 :   v8::HandleScope scope(isolate);
    1512           6 :   Local<FunctionTemplate> parent = FunctionTemplate::New(isolate);
    1513           6 :   Local<FunctionTemplate> child = FunctionTemplate::New(isolate);
    1514           6 :   v8::Local<v8::Symbol> age = v8::Symbol::New(isolate, v8_str("age"));
    1515             : 
    1516           6 :   child->Inherit(parent);
    1517           6 :   AddAccessor(parent, age, SymbolAccessorGetter, SymbolAccessorSetter);
    1518           6 :   AddStringOnlyInterceptor(child, InterceptorGetter, InterceptorSetter);
    1519             : 
    1520             :   env->Global()
    1521             :       ->Set(env.local(), v8_str("Child"),
    1522          30 :             child->GetFunction(env.local()).ToLocalChecked())
    1523          12 :       .FromJust();
    1524          30 :   env->Global()->Set(env.local(), v8_str("age"), age).FromJust();
    1525             :   CompileRun(
    1526             :       "var child = new Child;"
    1527             :       "child[age] = 10;");
    1528           6 :   ExpectInt32("child[age]", 10);
    1529           6 :   ExpectBoolean("child.hasOwnProperty('age')", false);
    1530          12 :   ExpectBoolean("child.hasOwnProperty('accessor_age')", true);
    1531           6 : }
    1532             : 
    1533             : 
    1534       25881 : THREADED_TEST(GenericInterceptorDoesSeeSymbols) {
    1535           6 :   LocalContext env;
    1536           6 :   v8::Isolate* isolate = CcTest::isolate();
    1537          12 :   v8::HandleScope scope(isolate);
    1538           6 :   Local<FunctionTemplate> parent = FunctionTemplate::New(isolate);
    1539           6 :   Local<FunctionTemplate> child = FunctionTemplate::New(isolate);
    1540           6 :   v8::Local<v8::Symbol> age = v8::Symbol::New(isolate, v8_str("age"));
    1541           6 :   v8::Local<v8::Symbol> anon = v8::Symbol::New(isolate);
    1542             : 
    1543           6 :   child->Inherit(parent);
    1544           6 :   AddAccessor(parent, age, SymbolAccessorGetter, SymbolAccessorSetter);
    1545           6 :   AddInterceptor(child, GenericInterceptorGetter, GenericInterceptorSetter);
    1546             : 
    1547             :   env->Global()
    1548             :       ->Set(env.local(), v8_str("Child"),
    1549          30 :             child->GetFunction(env.local()).ToLocalChecked())
    1550          12 :       .FromJust();
    1551          30 :   env->Global()->Set(env.local(), v8_str("age"), age).FromJust();
    1552          30 :   env->Global()->Set(env.local(), v8_str("anon"), anon).FromJust();
    1553             :   CompileRun(
    1554             :       "var child = new Child;"
    1555             :       "child[age] = 10;");
    1556           6 :   ExpectInt32("child[age]", 10);
    1557           6 :   ExpectInt32("child._sym_age", 10);
    1558             : 
    1559             :   // Check that it also sees strings.
    1560             :   CompileRun("child.foo = 47");
    1561           6 :   ExpectInt32("child.foo", 47);
    1562           6 :   ExpectInt32("child._str_foo", 47);
    1563             : 
    1564             :   // Check that the interceptor can punt (in this case, on anonymous symbols).
    1565             :   CompileRun("child[anon] = 31337");
    1566          12 :   ExpectInt32("child[anon]", 31337);
    1567           6 : }
    1568             : 
    1569             : 
    1570       25881 : THREADED_TEST(NamedPropertyHandlerGetter) {
    1571           6 :   echo_named_call_count = 0;
    1572           6 :   v8::Isolate* isolate = CcTest::isolate();
    1573           6 :   v8::HandleScope scope(isolate);
    1574           6 :   v8::Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
    1575             :   templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
    1576          18 :       EchoNamedProperty, nullptr, nullptr, nullptr, nullptr, v8_str("data")));
    1577          12 :   LocalContext env;
    1578             :   env->Global()
    1579           6 :       ->Set(env.local(), v8_str("obj"), templ->GetFunction(env.local())
    1580           6 :                                             .ToLocalChecked()
    1581           6 :                                             ->NewInstance(env.local())
    1582          24 :                                             .ToLocalChecked())
    1583          12 :       .FromJust();
    1584           6 :   CHECK_EQ(0, echo_named_call_count);
    1585          12 :   v8_compile("obj.x")->Run(env.local()).ToLocalChecked();
    1586           6 :   CHECK_EQ(1, echo_named_call_count);
    1587             :   const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
    1588           6 :   v8::Local<Value> str = CompileRun(code);
    1589          12 :   String::Utf8Value value(isolate, str);
    1590           6 :   CHECK_EQ(0, strcmp(*value, "oddlepoddle"));
    1591             :   // Check default behavior
    1592          24 :   CHECK_EQ(10, v8_compile("obj.flob = 10;")
    1593             :                    ->Run(env.local())
    1594             :                    .ToLocalChecked()
    1595             :                    ->Int32Value(env.local())
    1596             :                    .FromJust());
    1597          18 :   CHECK(v8_compile("'myProperty' in obj")
    1598             :             ->Run(env.local())
    1599             :             .ToLocalChecked()
    1600             :             ->BooleanValue(isolate));
    1601          18 :   CHECK(v8_compile("delete obj.myProperty")
    1602             :             ->Run(env.local())
    1603             :             .ToLocalChecked()
    1604           6 :             ->BooleanValue(isolate));
    1605           6 : }
    1606             : 
    1607             : namespace {
    1608           6 : void NotInterceptingPropertyDefineCallback(
    1609             :     Local<Name> name, const v8::PropertyDescriptor& desc,
    1610             :     const v8::PropertyCallbackInfo<v8::Value>& info) {
    1611             :   // Do not intercept by not calling info.GetReturnValue().Set().
    1612           6 : }
    1613             : 
    1614           6 : void InterceptingPropertyDefineCallback(
    1615             :     Local<Name> name, const v8::PropertyDescriptor& desc,
    1616             :     const v8::PropertyCallbackInfo<v8::Value>& info) {
    1617             :   // Intercept the callback by setting a non-empty handle
    1618             :   info.GetReturnValue().Set(name);
    1619           6 : }
    1620             : 
    1621           6 : void CheckDescriptorInDefineCallback(
    1622             :     Local<Name> name, const v8::PropertyDescriptor& desc,
    1623             :     const v8::PropertyCallbackInfo<v8::Value>& info) {
    1624           6 :   CHECK(!desc.has_writable());
    1625           6 :   CHECK(!desc.has_value());
    1626           6 :   CHECK(!desc.has_enumerable());
    1627           6 :   CHECK(desc.has_configurable());
    1628           6 :   CHECK(!desc.configurable());
    1629           6 :   CHECK(desc.has_get());
    1630          12 :   CHECK(desc.get()->IsFunction());
    1631           6 :   CHECK(desc.has_set());
    1632          12 :   CHECK(desc.set()->IsUndefined());
    1633             :   // intercept the callback by setting a non-empty handle
    1634             :   info.GetReturnValue().Set(name);
    1635           6 : }
    1636             : }  // namespace
    1637             : 
    1638       25881 : THREADED_TEST(PropertyDefinerCallback) {
    1639           6 :   v8::HandleScope scope(CcTest::isolate());
    1640          12 :   LocalContext env;
    1641             : 
    1642             :   {  // Intercept defineProperty()
    1643             :     v8::Local<v8::FunctionTemplate> templ =
    1644           6 :         v8::FunctionTemplate::New(CcTest::isolate());
    1645             :     templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
    1646             :         nullptr, nullptr, nullptr, nullptr, nullptr,
    1647          12 :         NotInterceptingPropertyDefineCallback));
    1648             :     env->Global()
    1649           6 :         ->Set(env.local(), v8_str("obj"), templ->GetFunction(env.local())
    1650           6 :                                               .ToLocalChecked()
    1651           6 :                                               ->NewInstance(env.local())
    1652          24 :                                               .ToLocalChecked())
    1653          12 :         .FromJust();
    1654             :     const char* code =
    1655             :         "obj.x = 17; "
    1656             :         "Object.defineProperty(obj, 'x', {value: 42});"
    1657             :         "obj.x;";
    1658          24 :     CHECK_EQ(42, v8_compile(code)
    1659             :                      ->Run(env.local())
    1660             :                      .ToLocalChecked()
    1661             :                      ->Int32Value(env.local())
    1662             :                      .FromJust());
    1663             :   }
    1664             : 
    1665             :   {  // Intercept defineProperty() for correct accessor descriptor
    1666             :     v8::Local<v8::FunctionTemplate> templ =
    1667           6 :         v8::FunctionTemplate::New(CcTest::isolate());
    1668             :     templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
    1669             :         nullptr, nullptr, nullptr, nullptr, nullptr,
    1670          12 :         CheckDescriptorInDefineCallback));
    1671             :     env->Global()
    1672           6 :         ->Set(env.local(), v8_str("obj"), templ->GetFunction(env.local())
    1673           6 :                                               .ToLocalChecked()
    1674           6 :                                               ->NewInstance(env.local())
    1675          24 :                                               .ToLocalChecked())
    1676          12 :         .FromJust();
    1677             :     const char* code =
    1678             :         "obj.x = 17; "
    1679             :         "Object.defineProperty(obj, 'x', {"
    1680             :         "get: function(){ return 42; }, "
    1681             :         "set: undefined,"
    1682             :         "configurable: 0"
    1683             :         "});"
    1684             :         "obj.x;";
    1685          24 :     CHECK_EQ(17, v8_compile(code)
    1686             :                      ->Run(env.local())
    1687             :                      .ToLocalChecked()
    1688             :                      ->Int32Value(env.local())
    1689             :                      .FromJust());
    1690             :   }
    1691             : 
    1692             :   {  // Do not intercept defineProperty()
    1693             :     v8::Local<v8::FunctionTemplate> templ2 =
    1694           6 :         v8::FunctionTemplate::New(CcTest::isolate());
    1695             :     templ2->InstanceTemplate()->SetHandler(
    1696             :         v8::NamedPropertyHandlerConfiguration(
    1697             :             nullptr, nullptr, nullptr, nullptr, nullptr,
    1698          12 :             InterceptingPropertyDefineCallback));
    1699             :     env->Global()
    1700           6 :         ->Set(env.local(), v8_str("obj"), templ2->GetFunction(env.local())
    1701           6 :                                               .ToLocalChecked()
    1702           6 :                                               ->NewInstance(env.local())
    1703          24 :                                               .ToLocalChecked())
    1704          12 :         .FromJust();
    1705             : 
    1706             :     const char* code =
    1707             :         "obj.x = 17; "
    1708             :         "Object.defineProperty(obj, 'x', {value: 42});"
    1709             :         "obj.x;";
    1710          24 :     CHECK_EQ(17, v8_compile(code)
    1711             :                      ->Run(env.local())
    1712             :                      .ToLocalChecked()
    1713             :                      ->Int32Value(env.local())
    1714             :                      .FromJust());
    1715           6 :   }
    1716           6 : }
    1717             : 
    1718             : namespace {
    1719           6 : void NotInterceptingPropertyDefineCallbackIndexed(
    1720             :     uint32_t index, const v8::PropertyDescriptor& desc,
    1721             :     const v8::PropertyCallbackInfo<v8::Value>& info) {
    1722             :   // Do not intercept by not calling info.GetReturnValue().Set()
    1723           6 : }
    1724             : 
    1725           6 : void InterceptingPropertyDefineCallbackIndexed(
    1726             :     uint32_t index, const v8::PropertyDescriptor& desc,
    1727             :     const v8::PropertyCallbackInfo<v8::Value>& info) {
    1728             :   // intercept the callback by setting a non-empty handle
    1729             :   info.GetReturnValue().Set(index);
    1730           6 : }
    1731             : 
    1732           6 : void CheckDescriptorInDefineCallbackIndexed(
    1733             :     uint32_t index, const v8::PropertyDescriptor& desc,
    1734             :     const v8::PropertyCallbackInfo<v8::Value>& info) {
    1735           6 :   CHECK(!desc.has_writable());
    1736           6 :   CHECK(!desc.has_value());
    1737           6 :   CHECK(desc.has_enumerable());
    1738           6 :   CHECK(desc.enumerable());
    1739           6 :   CHECK(!desc.has_configurable());
    1740           6 :   CHECK(desc.has_get());
    1741          12 :   CHECK(desc.get()->IsFunction());
    1742           6 :   CHECK(desc.has_set());
    1743          12 :   CHECK(desc.set()->IsUndefined());
    1744             :   // intercept the callback by setting a non-empty handle
    1745             :   info.GetReturnValue().Set(index);
    1746           6 : }
    1747             : }  // namespace
    1748             : 
    1749       25881 : THREADED_TEST(PropertyDefinerCallbackIndexed) {
    1750           6 :   v8::HandleScope scope(CcTest::isolate());
    1751          12 :   LocalContext env;
    1752             : 
    1753             :   {  // Intercept defineProperty()
    1754             :     v8::Local<v8::FunctionTemplate> templ =
    1755           6 :         v8::FunctionTemplate::New(CcTest::isolate());
    1756             :     templ->InstanceTemplate()->SetHandler(
    1757             :         v8::IndexedPropertyHandlerConfiguration(
    1758             :             nullptr, nullptr, nullptr, nullptr, nullptr,
    1759          12 :             NotInterceptingPropertyDefineCallbackIndexed));
    1760             :     env->Global()
    1761           6 :         ->Set(env.local(), v8_str("obj"), templ->GetFunction(env.local())
    1762           6 :                                               .ToLocalChecked()
    1763           6 :                                               ->NewInstance(env.local())
    1764          24 :                                               .ToLocalChecked())
    1765          12 :         .FromJust();
    1766             :     const char* code =
    1767             :         "obj[2] = 17; "
    1768             :         "Object.defineProperty(obj, 2, {value: 42});"
    1769             :         "obj[2];";
    1770          24 :     CHECK_EQ(42, v8_compile(code)
    1771             :                      ->Run(env.local())
    1772             :                      .ToLocalChecked()
    1773             :                      ->Int32Value(env.local())
    1774             :                      .FromJust());
    1775             :   }
    1776             : 
    1777             :   {  // Intercept defineProperty() for correct accessor descriptor
    1778             :     v8::Local<v8::FunctionTemplate> templ =
    1779           6 :         v8::FunctionTemplate::New(CcTest::isolate());
    1780             :     templ->InstanceTemplate()->SetHandler(
    1781             :         v8::IndexedPropertyHandlerConfiguration(
    1782             :             nullptr, nullptr, nullptr, nullptr, nullptr,
    1783          12 :             CheckDescriptorInDefineCallbackIndexed));
    1784             :     env->Global()
    1785           6 :         ->Set(env.local(), v8_str("obj"), templ->GetFunction(env.local())
    1786           6 :                                               .ToLocalChecked()
    1787           6 :                                               ->NewInstance(env.local())
    1788          24 :                                               .ToLocalChecked())
    1789          12 :         .FromJust();
    1790             :     const char* code =
    1791             :         "obj[2] = 17; "
    1792             :         "Object.defineProperty(obj, 2, {"
    1793             :         "get: function(){ return 42; }, "
    1794             :         "set: undefined,"
    1795             :         "enumerable: true"
    1796             :         "});"
    1797             :         "obj[2];";
    1798          24 :     CHECK_EQ(17, v8_compile(code)
    1799             :                      ->Run(env.local())
    1800             :                      .ToLocalChecked()
    1801             :                      ->Int32Value(env.local())
    1802             :                      .FromJust());
    1803             :   }
    1804             : 
    1805             :   {  // Do not intercept defineProperty()
    1806             :     v8::Local<v8::FunctionTemplate> templ2 =
    1807           6 :         v8::FunctionTemplate::New(CcTest::isolate());
    1808             :     templ2->InstanceTemplate()->SetHandler(
    1809             :         v8::IndexedPropertyHandlerConfiguration(
    1810             :             nullptr, nullptr, nullptr, nullptr, nullptr,
    1811          12 :             InterceptingPropertyDefineCallbackIndexed));
    1812             :     env->Global()
    1813           6 :         ->Set(env.local(), v8_str("obj"), templ2->GetFunction(env.local())
    1814           6 :                                               .ToLocalChecked()
    1815           6 :                                               ->NewInstance(env.local())
    1816          24 :                                               .ToLocalChecked())
    1817          12 :         .FromJust();
    1818             : 
    1819             :     const char* code =
    1820             :         "obj[2] = 17; "
    1821             :         "Object.defineProperty(obj, 2, {value: 42});"
    1822             :         "obj[2];";
    1823          24 :     CHECK_EQ(17, v8_compile(code)
    1824             :                      ->Run(env.local())
    1825             :                      .ToLocalChecked()
    1826             :                      ->Int32Value(env.local())
    1827             :                      .FromJust());
    1828           6 :   }
    1829           6 : }
    1830             : 
    1831             : // Test that freeze() is intercepted.
    1832       25881 : THREADED_TEST(PropertyDefinerCallbackForFreeze) {
    1833           6 :   v8::Isolate* isolate = CcTest::isolate();
    1834           6 :   v8::HandleScope scope(isolate);
    1835          12 :   LocalContext env;
    1836           6 :   v8::Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
    1837             :   templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
    1838             :       nullptr, nullptr, nullptr, nullptr, nullptr,
    1839          12 :       InterceptingPropertyDefineCallback));
    1840             :   env->Global()
    1841           6 :       ->Set(env.local(), v8_str("obj"), templ->GetFunction(env.local())
    1842           6 :                                             .ToLocalChecked()
    1843           6 :                                             ->NewInstance(env.local())
    1844          24 :                                             .ToLocalChecked())
    1845          12 :       .FromJust();
    1846             :   const char* code =
    1847             :       "obj.x = 17; "
    1848             :       "Object.freeze(obj.x); "
    1849             :       "Object.isFrozen(obj.x);";
    1850             : 
    1851          18 :   CHECK(v8_compile(code)
    1852             :             ->Run(env.local())
    1853             :             .ToLocalChecked()
    1854           6 :             ->BooleanValue(isolate));
    1855           6 : }
    1856             : 
    1857             : // Check that the descriptor passed to the callback is enumerable.
    1858             : namespace {
    1859           6 : void CheckEnumerablePropertyDefineCallback(
    1860             :     Local<Name> name, const v8::PropertyDescriptor& desc,
    1861             :     const v8::PropertyCallbackInfo<v8::Value>& info) {
    1862           6 :   CHECK(desc.has_value());
    1863          18 :   CHECK_EQ(42, desc.value()
    1864             :                    ->Int32Value(info.GetIsolate()->GetCurrentContext())
    1865             :                    .FromJust());
    1866           6 :   CHECK(desc.has_enumerable());
    1867           6 :   CHECK(desc.enumerable());
    1868           6 :   CHECK(!desc.has_writable());
    1869             : 
    1870             :   // intercept the callback by setting a non-empty handle
    1871             :   info.GetReturnValue().Set(name);
    1872           6 : }
    1873             : }  // namespace
    1874       25881 : THREADED_TEST(PropertyDefinerCallbackEnumerable) {
    1875           6 :   v8::HandleScope scope(CcTest::isolate());
    1876          12 :   LocalContext env;
    1877             :   v8::Local<v8::FunctionTemplate> templ =
    1878           6 :       v8::FunctionTemplate::New(CcTest::isolate());
    1879             :   templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
    1880             :       nullptr, nullptr, nullptr, nullptr, nullptr,
    1881          12 :       CheckEnumerablePropertyDefineCallback));
    1882             :   env->Global()
    1883           6 :       ->Set(env.local(), v8_str("obj"), templ->GetFunction(env.local())
    1884           6 :                                             .ToLocalChecked()
    1885           6 :                                             ->NewInstance(env.local())
    1886          24 :                                             .ToLocalChecked())
    1887          12 :       .FromJust();
    1888             :   const char* code =
    1889             :       "obj.x = 17; "
    1890             :       "Object.defineProperty(obj, 'x', {value: 42, enumerable: true});"
    1891             :       "obj.x;";
    1892          24 :   CHECK_EQ(17, v8_compile(code)
    1893             :                    ->Run(env.local())
    1894             :                    .ToLocalChecked()
    1895             :                    ->Int32Value(env.local())
    1896           6 :                    .FromJust());
    1897           6 : }
    1898             : 
    1899             : // Check that the descriptor passed to the callback is configurable.
    1900             : namespace {
    1901           6 : void CheckConfigurablePropertyDefineCallback(
    1902             :     Local<Name> name, const v8::PropertyDescriptor& desc,
    1903             :     const v8::PropertyCallbackInfo<v8::Value>& info) {
    1904           6 :   CHECK(desc.has_value());
    1905          18 :   CHECK_EQ(42, desc.value()
    1906             :                    ->Int32Value(info.GetIsolate()->GetCurrentContext())
    1907             :                    .FromJust());
    1908           6 :   CHECK(desc.has_configurable());
    1909           6 :   CHECK(desc.configurable());
    1910             : 
    1911             :   // intercept the callback by setting a non-empty handle
    1912             :   info.GetReturnValue().Set(name);
    1913           6 : }
    1914             : }  // namespace
    1915       25881 : THREADED_TEST(PropertyDefinerCallbackConfigurable) {
    1916           6 :   v8::HandleScope scope(CcTest::isolate());
    1917          12 :   LocalContext env;
    1918             :   v8::Local<v8::FunctionTemplate> templ =
    1919           6 :       v8::FunctionTemplate::New(CcTest::isolate());
    1920             :   templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
    1921             :       nullptr, nullptr, nullptr, nullptr, nullptr,
    1922          12 :       CheckConfigurablePropertyDefineCallback));
    1923             :   env->Global()
    1924           6 :       ->Set(env.local(), v8_str("obj"), templ->GetFunction(env.local())
    1925           6 :                                             .ToLocalChecked()
    1926           6 :                                             ->NewInstance(env.local())
    1927          24 :                                             .ToLocalChecked())
    1928          12 :       .FromJust();
    1929             :   const char* code =
    1930             :       "obj.x = 17; "
    1931             :       "Object.defineProperty(obj, 'x', {value: 42, configurable: true});"
    1932             :       "obj.x;";
    1933          24 :   CHECK_EQ(17, v8_compile(code)
    1934             :                    ->Run(env.local())
    1935             :                    .ToLocalChecked()
    1936             :                    ->Int32Value(env.local())
    1937           6 :                    .FromJust());
    1938           6 : }
    1939             : 
    1940             : // Check that the descriptor passed to the callback is writable.
    1941             : namespace {
    1942           6 : void CheckWritablePropertyDefineCallback(
    1943             :     Local<Name> name, const v8::PropertyDescriptor& desc,
    1944             :     const v8::PropertyCallbackInfo<v8::Value>& info) {
    1945           6 :   CHECK(desc.has_writable());
    1946           6 :   CHECK(desc.writable());
    1947             : 
    1948             :   // intercept the callback by setting a non-empty handle
    1949             :   info.GetReturnValue().Set(name);
    1950           6 : }
    1951             : }  // namespace
    1952       25881 : THREADED_TEST(PropertyDefinerCallbackWritable) {
    1953           6 :   v8::HandleScope scope(CcTest::isolate());
    1954          12 :   LocalContext env;
    1955             :   v8::Local<v8::FunctionTemplate> templ =
    1956           6 :       v8::FunctionTemplate::New(CcTest::isolate());
    1957             :   templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
    1958             :       nullptr, nullptr, nullptr, nullptr, nullptr,
    1959          12 :       CheckWritablePropertyDefineCallback));
    1960             :   env->Global()
    1961           6 :       ->Set(env.local(), v8_str("obj"), templ->GetFunction(env.local())
    1962           6 :                                             .ToLocalChecked()
    1963           6 :                                             ->NewInstance(env.local())
    1964          24 :                                             .ToLocalChecked())
    1965          12 :       .FromJust();
    1966             :   const char* code =
    1967             :       "obj.x = 17; "
    1968             :       "Object.defineProperty(obj, 'x', {value: 42, writable: true});"
    1969             :       "obj.x;";
    1970          24 :   CHECK_EQ(17, v8_compile(code)
    1971             :                    ->Run(env.local())
    1972             :                    .ToLocalChecked()
    1973             :                    ->Int32Value(env.local())
    1974           6 :                    .FromJust());
    1975           6 : }
    1976             : 
    1977             : // Check that the descriptor passed to the callback has a getter.
    1978             : namespace {
    1979           6 : void CheckGetterPropertyDefineCallback(
    1980             :     Local<Name> name, const v8::PropertyDescriptor& desc,
    1981             :     const v8::PropertyCallbackInfo<v8::Value>& info) {
    1982           6 :   CHECK(desc.has_get());
    1983           6 :   CHECK(!desc.has_set());
    1984             :   // intercept the callback by setting a non-empty handle
    1985             :   info.GetReturnValue().Set(name);
    1986           6 : }
    1987             : }  // namespace
    1988       25881 : THREADED_TEST(PropertyDefinerCallbackWithGetter) {
    1989           6 :   v8::HandleScope scope(CcTest::isolate());
    1990          12 :   LocalContext env;
    1991             :   v8::Local<v8::FunctionTemplate> templ =
    1992           6 :       v8::FunctionTemplate::New(CcTest::isolate());
    1993             :   templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
    1994             :       nullptr, nullptr, nullptr, nullptr, nullptr,
    1995          12 :       CheckGetterPropertyDefineCallback));
    1996             :   env->Global()
    1997           6 :       ->Set(env.local(), v8_str("obj"), templ->GetFunction(env.local())
    1998           6 :                                             .ToLocalChecked()
    1999           6 :                                             ->NewInstance(env.local())
    2000          24 :                                             .ToLocalChecked())
    2001          12 :       .FromJust();
    2002             :   const char* code =
    2003             :       "obj.x = 17;"
    2004             :       "Object.defineProperty(obj, 'x', {get: function() {return 42;}});"
    2005             :       "obj.x;";
    2006          24 :   CHECK_EQ(17, v8_compile(code)
    2007             :                    ->Run(env.local())
    2008             :                    .ToLocalChecked()
    2009             :                    ->Int32Value(env.local())
    2010           6 :                    .FromJust());
    2011           6 : }
    2012             : 
    2013             : // Check that the descriptor passed to the callback has a setter.
    2014             : namespace {
    2015           6 : void CheckSetterPropertyDefineCallback(
    2016             :     Local<Name> name, const v8::PropertyDescriptor& desc,
    2017             :     const v8::PropertyCallbackInfo<v8::Value>& info) {
    2018           6 :   CHECK(desc.has_set());
    2019           6 :   CHECK(!desc.has_get());
    2020             :   // intercept the callback by setting a non-empty handle
    2021             :   info.GetReturnValue().Set(name);
    2022           6 : }
    2023             : }  // namespace
    2024       25881 : THREADED_TEST(PropertyDefinerCallbackWithSetter) {
    2025           6 :   v8::HandleScope scope(CcTest::isolate());
    2026          12 :   LocalContext env;
    2027             :   v8::Local<v8::FunctionTemplate> templ =
    2028           6 :       v8::FunctionTemplate::New(CcTest::isolate());
    2029             :   templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
    2030             :       nullptr, nullptr, nullptr, nullptr, nullptr,
    2031          12 :       CheckSetterPropertyDefineCallback));
    2032             :   env->Global()
    2033           6 :       ->Set(env.local(), v8_str("obj"), templ->GetFunction(env.local())
    2034           6 :                                             .ToLocalChecked()
    2035           6 :                                             ->NewInstance(env.local())
    2036          24 :                                             .ToLocalChecked())
    2037          12 :       .FromJust();
    2038             :   const char* code =
    2039             :       "Object.defineProperty(obj, 'x', {set: function() {return 42;}});"
    2040             :       "obj.x = 17;";
    2041          24 :   CHECK_EQ(17, v8_compile(code)
    2042             :                    ->Run(env.local())
    2043             :                    .ToLocalChecked()
    2044             :                    ->Int32Value(env.local())
    2045           6 :                    .FromJust());
    2046           6 : }
    2047             : 
    2048             : namespace {
    2049           6 : void EmptyPropertyDescriptorCallback(
    2050             :     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
    2051             :   // Do not intercept by not calling info.GetReturnValue().Set().
    2052           6 : }
    2053             : 
    2054           6 : void InterceptingPropertyDescriptorCallback(
    2055             :     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
    2056             :   // Intercept the callback by setting a different descriptor.
    2057             :   const char* code =
    2058             :       "var desc = {value: 42};"
    2059             :       "desc;";
    2060             :   Local<Value> descriptor = v8_compile(code)
    2061           6 :                                 ->Run(info.GetIsolate()->GetCurrentContext())
    2062           6 :                                 .ToLocalChecked();
    2063             :   info.GetReturnValue().Set(descriptor);
    2064           6 : }
    2065             : }  // namespace
    2066             : 
    2067       25881 : THREADED_TEST(PropertyDescriptorCallback) {
    2068           6 :   v8::HandleScope scope(CcTest::isolate());
    2069          12 :   LocalContext env;
    2070             : 
    2071             :   {  // Normal behavior of getOwnPropertyDescriptor() with empty callback.
    2072             :     v8::Local<v8::FunctionTemplate> templ =
    2073           6 :         v8::FunctionTemplate::New(CcTest::isolate());
    2074             :     templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
    2075             :         nullptr, nullptr, EmptyPropertyDescriptorCallback, nullptr, nullptr,
    2076          12 :         nullptr));
    2077             :     env->Global()
    2078           6 :         ->Set(env.local(), v8_str("obj"), templ->GetFunction(env.local())
    2079           6 :                                               .ToLocalChecked()
    2080           6 :                                               ->NewInstance(env.local())
    2081          24 :                                               .ToLocalChecked())
    2082          12 :         .FromJust();
    2083             :     const char* code =
    2084             :         "obj.x = 17; "
    2085             :         "var desc = Object.getOwnPropertyDescriptor(obj, 'x');"
    2086             :         "desc.value;";
    2087          24 :     CHECK_EQ(17, v8_compile(code)
    2088             :                      ->Run(env.local())
    2089             :                      .ToLocalChecked()
    2090             :                      ->Int32Value(env.local())
    2091             :                      .FromJust());
    2092             :   }
    2093             : 
    2094             :   {  // Intercept getOwnPropertyDescriptor().
    2095             :     v8::Local<v8::FunctionTemplate> templ =
    2096           6 :         v8::FunctionTemplate::New(CcTest::isolate());
    2097             :     templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
    2098             :         nullptr, nullptr, InterceptingPropertyDescriptorCallback, nullptr,
    2099          12 :         nullptr, nullptr));
    2100             :     env->Global()
    2101           6 :         ->Set(env.local(), v8_str("obj"), templ->GetFunction(env.local())
    2102           6 :                                               .ToLocalChecked()
    2103           6 :                                               ->NewInstance(env.local())
    2104          24 :                                               .ToLocalChecked())
    2105          12 :         .FromJust();
    2106             :     const char* code =
    2107             :         "obj.x = 17; "
    2108             :         "var desc = Object.getOwnPropertyDescriptor(obj, 'x');"
    2109             :         "desc.value;";
    2110          24 :     CHECK_EQ(42, v8_compile(code)
    2111             :                      ->Run(env.local())
    2112             :                      .ToLocalChecked()
    2113             :                      ->Int32Value(env.local())
    2114             :                      .FromJust());
    2115           6 :   }
    2116           6 : }
    2117             : 
    2118             : namespace {
    2119             : int echo_indexed_call_count = 0;
    2120             : }  // namespace
    2121             : 
    2122           6 : static void EchoIndexedProperty(
    2123             :     uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) {
    2124           6 :   ApiTestFuzzer::Fuzz();
    2125          18 :   CHECK(v8_num(637)
    2126             :             ->Equals(info.GetIsolate()->GetCurrentContext(), info.Data())
    2127             :             .FromJust());
    2128           6 :   echo_indexed_call_count++;
    2129           6 :   info.GetReturnValue().Set(v8_num(index));
    2130           6 : }
    2131             : 
    2132             : 
    2133       25881 : THREADED_TEST(IndexedPropertyHandlerGetter) {
    2134           6 :   v8::Isolate* isolate = CcTest::isolate();
    2135           6 :   v8::HandleScope scope(isolate);
    2136           6 :   v8::Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
    2137             :   templ->InstanceTemplate()->SetHandler(v8::IndexedPropertyHandlerConfiguration(
    2138          18 :       EchoIndexedProperty, nullptr, nullptr, nullptr, nullptr, v8_num(637)));
    2139          12 :   LocalContext env;
    2140             :   env->Global()
    2141           6 :       ->Set(env.local(), v8_str("obj"), templ->GetFunction(env.local())
    2142           6 :                                             .ToLocalChecked()
    2143           6 :                                             ->NewInstance(env.local())
    2144          24 :                                             .ToLocalChecked())
    2145          12 :       .FromJust();
    2146             :   Local<Script> script = v8_compile("obj[900]");
    2147          18 :   CHECK_EQ(900, script->Run(env.local())
    2148             :                     .ToLocalChecked()
    2149             :                     ->Int32Value(env.local())
    2150           6 :                     .FromJust());
    2151           6 : }
    2152             : 
    2153             : 
    2154       25881 : THREADED_TEST(PropertyHandlerInPrototype) {
    2155           6 :   LocalContext env;
    2156           6 :   v8::Isolate* isolate = env->GetIsolate();
    2157          12 :   v8::HandleScope scope(isolate);
    2158             : 
    2159           6 :   v8::Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
    2160             :   templ->InstanceTemplate()->SetHandler(v8::IndexedPropertyHandlerConfiguration(
    2161             :       CheckThisIndexedPropertyHandler, CheckThisIndexedPropertySetter,
    2162             :       CheckThisIndexedPropertyQuery, CheckThisIndexedPropertyDeleter,
    2163          12 :       CheckThisIndexedPropertyEnumerator));
    2164             : 
    2165             :   templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
    2166             :       CheckThisNamedPropertyHandler, CheckThisNamedPropertySetter,
    2167             :       CheckThisNamedPropertyQuery, CheckThisNamedPropertyDeleter,
    2168          12 :       CheckThisNamedPropertyEnumerator));
    2169             : 
    2170           6 :   bottom = templ->GetFunction(env.local())
    2171           6 :                .ToLocalChecked()
    2172           6 :                ->NewInstance(env.local())
    2173           6 :                .ToLocalChecked();
    2174           6 :   Local<v8::Object> top = templ->GetFunction(env.local())
    2175           6 :                               .ToLocalChecked()
    2176           6 :                               ->NewInstance(env.local())
    2177             :                               .ToLocalChecked();
    2178           6 :   Local<v8::Object> middle = templ->GetFunction(env.local())
    2179           6 :                                  .ToLocalChecked()
    2180           6 :                                  ->NewInstance(env.local())
    2181             :                                  .ToLocalChecked();
    2182             : 
    2183          18 :   bottom->SetPrototype(env.local(), middle).FromJust();
    2184          12 :   middle->SetPrototype(env.local(), top).FromJust();
    2185          30 :   env->Global()->Set(env.local(), v8_str("obj"), bottom).FromJust();
    2186             : 
    2187             :   // Indexed and named get.
    2188             :   CompileRun("obj[0]");
    2189             :   CompileRun("obj.x");
    2190             : 
    2191             :   // Indexed and named set.
    2192             :   CompileRun("obj[1] = 42");
    2193             :   CompileRun("obj.y = 42");
    2194             : 
    2195             :   // Indexed and named query.
    2196             :   CompileRun("0 in obj");
    2197             :   CompileRun("'x' in obj");
    2198             : 
    2199             :   // Indexed and named deleter.
    2200             :   CompileRun("delete obj[0]");
    2201             :   CompileRun("delete obj.x");
    2202             : 
    2203             :   // Enumerators.
    2204           6 :   CompileRun("for (var p in obj) ;");
    2205           6 : }
    2206             : 
    2207       25880 : TEST(PropertyHandlerInPrototypeWithDefine) {
    2208           5 :   LocalContext env;
    2209           5 :   v8::Isolate* isolate = env->GetIsolate();
    2210          10 :   v8::HandleScope scope(isolate);
    2211             : 
    2212           5 :   v8::Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
    2213             :   templ->InstanceTemplate()->SetHandler(v8::IndexedPropertyHandlerConfiguration(
    2214             :       CheckThisIndexedPropertyHandler, CheckThisIndexedPropertySetter,
    2215             :       CheckThisIndexedPropertyDescriptor, CheckThisIndexedPropertyDeleter,
    2216          10 :       CheckThisIndexedPropertyEnumerator, CheckThisIndexedPropertyDefiner));
    2217             : 
    2218             :   templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
    2219             :       CheckThisNamedPropertyHandler, CheckThisNamedPropertySetter,
    2220             :       CheckThisNamedPropertyDescriptor, CheckThisNamedPropertyDeleter,
    2221          10 :       CheckThisNamedPropertyEnumerator, CheckThisNamedPropertyDefiner));
    2222             : 
    2223           5 :   bottom = templ->GetFunction(env.local())
    2224           5 :                .ToLocalChecked()
    2225           5 :                ->NewInstance(env.local())
    2226           5 :                .ToLocalChecked();
    2227           5 :   Local<v8::Object> top = templ->GetFunction(env.local())
    2228           5 :                               .ToLocalChecked()
    2229           5 :                               ->NewInstance(env.local())
    2230             :                               .ToLocalChecked();
    2231           5 :   Local<v8::Object> middle = templ->GetFunction(env.local())
    2232           5 :                                  .ToLocalChecked()
    2233           5 :                                  ->NewInstance(env.local())
    2234             :                                  .ToLocalChecked();
    2235             : 
    2236          15 :   bottom->SetPrototype(env.local(), middle).FromJust();
    2237          10 :   middle->SetPrototype(env.local(), top).FromJust();
    2238          25 :   env->Global()->Set(env.local(), v8_str("obj"), bottom).FromJust();
    2239             : 
    2240             :   // Indexed and named get.
    2241             :   CompileRun("obj[0]");
    2242             :   CompileRun("obj.x");
    2243             : 
    2244             :   // Indexed and named set.
    2245             :   CompileRun("obj[1] = 42");
    2246             :   CompileRun("obj.y = 42");
    2247             : 
    2248             :   // Indexed and named deleter.
    2249             :   CompileRun("delete obj[0]");
    2250             :   CompileRun("delete obj.x");
    2251             : 
    2252             :   // Enumerators.
    2253             :   CompileRun("for (var p in obj) ;");
    2254             : 
    2255             :   // Indexed and named definer.
    2256             :   CompileRun("Object.defineProperty(obj, 2, {});");
    2257             :   CompileRun("Object.defineProperty(obj, 'z', {});");
    2258             : 
    2259             :   // Indexed and named propertyDescriptor.
    2260             :   CompileRun("Object.getOwnPropertyDescriptor(obj, 2);");
    2261           5 :   CompileRun("Object.getOwnPropertyDescriptor(obj, 'z');");
    2262           5 : }
    2263             : 
    2264             : 
    2265             : bool is_bootstrapping = false;
    2266          18 : static void PrePropertyHandlerGet(
    2267             :     Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>& info) {
    2268          18 :   ApiTestFuzzer::Fuzz();
    2269          54 :   if (!is_bootstrapping &&
    2270             :       v8_str("pre")
    2271          54 :           ->Equals(info.GetIsolate()->GetCurrentContext(), key)
    2272          36 :           .FromJust()) {
    2273           6 :     info.GetReturnValue().Set(v8_str("PrePropertyHandler: pre"));
    2274             :   }
    2275          18 : }
    2276             : 
    2277             : 
    2278           0 : static void PrePropertyHandlerQuery(
    2279             :     Local<Name> key, const v8::PropertyCallbackInfo<v8::Integer>& info) {
    2280           0 :   if (!is_bootstrapping &&
    2281             :       v8_str("pre")
    2282           0 :           ->Equals(info.GetIsolate()->GetCurrentContext(), key)
    2283           0 :           .FromJust()) {
    2284             :     info.GetReturnValue().Set(static_cast<int32_t>(v8::None));
    2285             :   }
    2286           0 : }
    2287             : 
    2288             : 
    2289       25881 : THREADED_TEST(PrePropertyHandler) {
    2290           6 :   v8::Isolate* isolate = CcTest::isolate();
    2291           6 :   v8::HandleScope scope(isolate);
    2292           6 :   v8::Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
    2293             :   desc->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
    2294          12 :       PrePropertyHandlerGet, nullptr, PrePropertyHandlerQuery));
    2295           6 :   is_bootstrapping = true;
    2296          12 :   LocalContext env(nullptr, desc->InstanceTemplate());
    2297           6 :   is_bootstrapping = false;
    2298             :   CompileRun("var pre = 'Object: pre'; var on = 'Object: on';");
    2299           6 :   v8::Local<Value> result_pre = CompileRun("pre");
    2300          18 :   CHECK(v8_str("PrePropertyHandler: pre")
    2301             :             ->Equals(env.local(), result_pre)
    2302             :             .FromJust());
    2303           6 :   v8::Local<Value> result_on = CompileRun("on");
    2304          18 :   CHECK(v8_str("Object: on")->Equals(env.local(), result_on).FromJust());
    2305             :   v8::Local<Value> result_post = CompileRun("post");
    2306          12 :   CHECK(result_post.IsEmpty());
    2307           6 : }
    2308             : 
    2309             : 
    2310       25881 : THREADED_TEST(EmptyInterceptorBreakTransitions) {
    2311           6 :   v8::HandleScope scope(CcTest::isolate());
    2312           6 :   Local<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
    2313           6 :   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
    2314          12 :   LocalContext env;
    2315             :   env->Global()
    2316             :       ->Set(env.local(), v8_str("Constructor"),
    2317          36 :             templ->GetFunction(env.local()).ToLocalChecked())
    2318          12 :       .FromJust();
    2319             :   CompileRun(
    2320             :       "var o1 = new Constructor;"
    2321             :       "o1.a = 1;"  // Ensure a and x share the descriptor array.
    2322             :       "Object.defineProperty(o1, 'x', {value: 10});");
    2323             :   CompileRun(
    2324             :       "var o2 = new Constructor;"
    2325             :       "o2.a = 1;"
    2326           6 :       "Object.defineProperty(o2, 'x', {value: 10});");
    2327           6 : }
    2328             : 
    2329             : 
    2330       25881 : THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) {
    2331           6 :   v8::Isolate* isolate = CcTest::isolate();
    2332           6 :   v8::HandleScope scope(isolate);
    2333           6 :   Local<FunctionTemplate> parent = FunctionTemplate::New(isolate);
    2334           6 :   Local<FunctionTemplate> child = FunctionTemplate::New(isolate);
    2335           6 :   child->Inherit(parent);
    2336           6 :   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
    2337          12 :   LocalContext env;
    2338             :   env->Global()
    2339             :       ->Set(env.local(), v8_str("Child"),
    2340          30 :             child->GetFunction(env.local()).ToLocalChecked())
    2341          12 :       .FromJust();
    2342             :   CompileRun(
    2343             :       "var child = new Child;"
    2344             :       "var parent = child.__proto__;"
    2345             :       "Object.defineProperty(parent, 'age', "
    2346             :       "  {get: function(){ return this.accessor_age; }, "
    2347             :       "   set: function(v){ this.accessor_age = v; }, "
    2348             :       "   enumerable: true, configurable: true});"
    2349             :       "child.age = 10;");
    2350           6 :   ExpectBoolean("child.hasOwnProperty('age')", false);
    2351           6 :   ExpectInt32("child.age", 10);
    2352          12 :   ExpectInt32("child.accessor_age", 10);
    2353           6 : }
    2354             : 
    2355             : 
    2356       25881 : THREADED_TEST(EmptyInterceptorDoesNotShadowApiAccessors) {
    2357           6 :   v8::Isolate* isolate = CcTest::isolate();
    2358           6 :   v8::HandleScope scope(isolate);
    2359           6 :   Local<FunctionTemplate> parent = FunctionTemplate::New(isolate);
    2360           6 :   auto returns_42 = FunctionTemplate::New(isolate, Returns42);
    2361          18 :   parent->PrototypeTemplate()->SetAccessorProperty(v8_str("age"), returns_42);
    2362           6 :   Local<FunctionTemplate> child = FunctionTemplate::New(isolate);
    2363           6 :   child->Inherit(parent);
    2364           6 :   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
    2365          12 :   LocalContext env;
    2366             :   env->Global()
    2367             :       ->Set(env.local(), v8_str("Child"),
    2368          30 :             child->GetFunction(env.local()).ToLocalChecked())
    2369          12 :       .FromJust();
    2370             :   CompileRun(
    2371             :       "var child = new Child;"
    2372             :       "var parent = child.__proto__;");
    2373           6 :   ExpectBoolean("child.hasOwnProperty('age')", false);
    2374           6 :   ExpectInt32("child.age", 42);
    2375             :   // Check interceptor followup.
    2376             :   ExpectInt32(
    2377             :       "var result;"
    2378             :       "for (var i = 0; i < 4; ++i) {"
    2379             :       "  result = child.age;"
    2380             :       "}"
    2381             :       "result",
    2382          12 :       42);
    2383           6 : }
    2384             : 
    2385             : 
    2386       25881 : THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) {
    2387           6 :   v8::Isolate* isolate = CcTest::isolate();
    2388           6 :   v8::HandleScope scope(isolate);
    2389           6 :   Local<FunctionTemplate> parent = FunctionTemplate::New(isolate);
    2390           6 :   Local<FunctionTemplate> child = FunctionTemplate::New(isolate);
    2391           6 :   child->Inherit(parent);
    2392           6 :   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
    2393          12 :   LocalContext env;
    2394             :   env->Global()
    2395             :       ->Set(env.local(), v8_str("Child"),
    2396          30 :             child->GetFunction(env.local()).ToLocalChecked())
    2397          12 :       .FromJust();
    2398             :   CompileRun(
    2399             :       "var child = new Child;"
    2400             :       "var parent = child.__proto__;"
    2401             :       "parent.name = 'Alice';");
    2402           6 :   ExpectBoolean("child.hasOwnProperty('name')", false);
    2403           6 :   ExpectString("child.name", "Alice");
    2404             :   CompileRun("child.name = 'Bob';");
    2405           6 :   ExpectString("child.name", "Bob");
    2406           6 :   ExpectBoolean("child.hasOwnProperty('name')", true);
    2407          12 :   ExpectString("parent.name", "Alice");
    2408           6 : }
    2409             : 
    2410             : 
    2411       25881 : THREADED_TEST(SwitchFromInterceptorToAccessor) {
    2412           6 :   v8::HandleScope scope(CcTest::isolate());
    2413           6 :   Local<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
    2414           6 :   AddAccessor(templ, v8_str("age"), SimpleAccessorGetter, SimpleAccessorSetter);
    2415           6 :   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
    2416          12 :   LocalContext env;
    2417             :   env->Global()
    2418             :       ->Set(env.local(), v8_str("Obj"),
    2419          36 :             templ->GetFunction(env.local()).ToLocalChecked())
    2420          12 :       .FromJust();
    2421             :   CompileRun(
    2422             :       "var obj = new Obj;"
    2423             :       "function setAge(i){ obj.age = i; };"
    2424             :       "for(var i = 0; i <= 10000; i++) setAge(i);");
    2425             :   // All i < 10000 go to the interceptor.
    2426           6 :   ExpectInt32("obj.interceptor_age", 9999);
    2427             :   // The last i goes to the accessor.
    2428          12 :   ExpectInt32("obj.accessor_age", 10000);
    2429           6 : }
    2430             : 
    2431             : 
    2432       25881 : THREADED_TEST(SwitchFromAccessorToInterceptor) {
    2433           6 :   v8::HandleScope scope(CcTest::isolate());
    2434           6 :   Local<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
    2435           6 :   AddAccessor(templ, v8_str("age"), SimpleAccessorGetter, SimpleAccessorSetter);
    2436           6 :   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
    2437          12 :   LocalContext env;
    2438             :   env->Global()
    2439             :       ->Set(env.local(), v8_str("Obj"),
    2440          36 :             templ->GetFunction(env.local()).ToLocalChecked())
    2441          12 :       .FromJust();
    2442             :   CompileRun(
    2443             :       "var obj = new Obj;"
    2444             :       "function setAge(i){ obj.age = i; };"
    2445             :       "for(var i = 20000; i >= 9999; i--) setAge(i);");
    2446             :   // All i >= 10000 go to the accessor.
    2447           6 :   ExpectInt32("obj.accessor_age", 10000);
    2448             :   // The last i goes to the interceptor.
    2449          12 :   ExpectInt32("obj.interceptor_age", 9999);
    2450           6 : }
    2451             : 
    2452             : 
    2453       25881 : THREADED_TEST(SwitchFromInterceptorToAccessorWithInheritance) {
    2454           6 :   v8::HandleScope scope(CcTest::isolate());
    2455           6 :   Local<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
    2456           6 :   Local<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
    2457           6 :   child->Inherit(parent);
    2458             :   AddAccessor(parent, v8_str("age"), SimpleAccessorGetter,
    2459           6 :               SimpleAccessorSetter);
    2460           6 :   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
    2461          12 :   LocalContext env;
    2462             :   env->Global()
    2463             :       ->Set(env.local(), v8_str("Child"),
    2464          30 :             child->GetFunction(env.local()).ToLocalChecked())
    2465          12 :       .FromJust();
    2466             :   CompileRun(
    2467             :       "var child = new Child;"
    2468             :       "function setAge(i){ child.age = i; };"
    2469             :       "for(var i = 0; i <= 10000; i++) setAge(i);");
    2470             :   // All i < 10000 go to the interceptor.
    2471           6 :   ExpectInt32("child.interceptor_age", 9999);
    2472             :   // The last i goes to the accessor.
    2473          12 :   ExpectInt32("child.accessor_age", 10000);
    2474           6 : }
    2475             : 
    2476             : 
    2477       25881 : THREADED_TEST(SwitchFromAccessorToInterceptorWithInheritance) {
    2478           6 :   v8::HandleScope scope(CcTest::isolate());
    2479           6 :   Local<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
    2480           6 :   Local<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
    2481           6 :   child->Inherit(parent);
    2482             :   AddAccessor(parent, v8_str("age"), SimpleAccessorGetter,
    2483           6 :               SimpleAccessorSetter);
    2484           6 :   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
    2485          12 :   LocalContext env;
    2486             :   env->Global()
    2487             :       ->Set(env.local(), v8_str("Child"),
    2488          30 :             child->GetFunction(env.local()).ToLocalChecked())
    2489          12 :       .FromJust();
    2490             :   CompileRun(
    2491             :       "var child = new Child;"
    2492             :       "function setAge(i){ child.age = i; };"
    2493             :       "for(var i = 20000; i >= 9999; i--) setAge(i);");
    2494             :   // All i >= 10000 go to the accessor.
    2495           6 :   ExpectInt32("child.accessor_age", 10000);
    2496             :   // The last i goes to the interceptor.
    2497          12 :   ExpectInt32("child.interceptor_age", 9999);
    2498           6 : }
    2499             : 
    2500             : 
    2501       25881 : THREADED_TEST(SwitchFromInterceptorToJSAccessor) {
    2502           6 :   v8::HandleScope scope(CcTest::isolate());
    2503           6 :   Local<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
    2504           6 :   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
    2505          12 :   LocalContext env;
    2506             :   env->Global()
    2507             :       ->Set(env.local(), v8_str("Obj"),
    2508          36 :             templ->GetFunction(env.local()).ToLocalChecked())
    2509          12 :       .FromJust();
    2510             :   CompileRun(
    2511             :       "var obj = new Obj;"
    2512             :       "function setter(i) { this.accessor_age = i; };"
    2513             :       "function getter() { return this.accessor_age; };"
    2514             :       "function setAge(i) { obj.age = i; };"
    2515             :       "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
    2516             :       "for(var i = 0; i <= 10000; i++) setAge(i);");
    2517             :   // All i < 10000 go to the interceptor.
    2518           6 :   ExpectInt32("obj.interceptor_age", 9999);
    2519             :   // The last i goes to the JavaScript accessor.
    2520           6 :   ExpectInt32("obj.accessor_age", 10000);
    2521             :   // The installed JavaScript getter is still intact.
    2522             :   // This last part is a regression test for issue 1651 and relies on the fact
    2523             :   // that both interceptor and accessor are being installed on the same object.
    2524           6 :   ExpectInt32("obj.age", 10000);
    2525           6 :   ExpectBoolean("obj.hasOwnProperty('age')", true);
    2526          12 :   ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
    2527           6 : }
    2528             : 
    2529             : 
    2530       25881 : THREADED_TEST(SwitchFromJSAccessorToInterceptor) {
    2531           6 :   v8::HandleScope scope(CcTest::isolate());
    2532           6 :   Local<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
    2533           6 :   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
    2534          12 :   LocalContext env;
    2535             :   env->Global()
    2536             :       ->Set(env.local(), v8_str("Obj"),
    2537          36 :             templ->GetFunction(env.local()).ToLocalChecked())
    2538          12 :       .FromJust();
    2539             :   CompileRun(
    2540             :       "var obj = new Obj;"
    2541             :       "function setter(i) { this.accessor_age = i; };"
    2542             :       "function getter() { return this.accessor_age; };"
    2543             :       "function setAge(i) { obj.age = i; };"
    2544             :       "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
    2545             :       "for(var i = 20000; i >= 9999; i--) setAge(i);");
    2546             :   // All i >= 10000 go to the accessor.
    2547           6 :   ExpectInt32("obj.accessor_age", 10000);
    2548             :   // The last i goes to the interceptor.
    2549           6 :   ExpectInt32("obj.interceptor_age", 9999);
    2550             :   // The installed JavaScript getter is still intact.
    2551             :   // This last part is a regression test for issue 1651 and relies on the fact
    2552             :   // that both interceptor and accessor are being installed on the same object.
    2553           6 :   ExpectInt32("obj.age", 10000);
    2554           6 :   ExpectBoolean("obj.hasOwnProperty('age')", true);
    2555          12 :   ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
    2556           6 : }
    2557             : 
    2558             : 
    2559       25881 : THREADED_TEST(SwitchFromInterceptorToProperty) {
    2560           6 :   v8::HandleScope scope(CcTest::isolate());
    2561           6 :   Local<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
    2562           6 :   Local<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
    2563           6 :   child->Inherit(parent);
    2564           6 :   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
    2565          12 :   LocalContext env;
    2566             :   env->Global()
    2567             :       ->Set(env.local(), v8_str("Child"),
    2568          30 :             child->GetFunction(env.local()).ToLocalChecked())
    2569          12 :       .FromJust();
    2570             :   CompileRun(
    2571             :       "var child = new Child;"
    2572             :       "function setAge(i){ child.age = i; };"
    2573             :       "for(var i = 0; i <= 10000; i++) setAge(i);");
    2574             :   // All i < 10000 go to the interceptor.
    2575           6 :   ExpectInt32("child.interceptor_age", 9999);
    2576             :   // The last i goes to child's own property.
    2577          12 :   ExpectInt32("child.age", 10000);
    2578           6 : }
    2579             : 
    2580             : 
    2581       25881 : THREADED_TEST(SwitchFromPropertyToInterceptor) {
    2582           6 :   v8::HandleScope scope(CcTest::isolate());
    2583           6 :   Local<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
    2584           6 :   Local<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
    2585           6 :   child->Inherit(parent);
    2586           6 :   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
    2587          12 :   LocalContext env;
    2588             :   env->Global()
    2589             :       ->Set(env.local(), v8_str("Child"),
    2590          30 :             child->GetFunction(env.local()).ToLocalChecked())
    2591          12 :       .FromJust();
    2592             :   CompileRun(
    2593             :       "var child = new Child;"
    2594             :       "function setAge(i){ child.age = i; };"
    2595             :       "for(var i = 20000; i >= 9999; i--) setAge(i);");
    2596             :   // All i >= 10000 go to child's own property.
    2597           6 :   ExpectInt32("child.age", 10000);
    2598             :   // The last i goes to the interceptor.
    2599          12 :   ExpectInt32("child.interceptor_age", 9999);
    2600           6 : }
    2601             : 
    2602             : 
    2603             : static bool interceptor_for_hidden_properties_called;
    2604           0 : static void InterceptorForHiddenProperties(
    2605             :     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
    2606           0 :   interceptor_for_hidden_properties_called = true;
    2607           0 : }
    2608             : 
    2609       25881 : THREADED_TEST(NoSideEffectPropertyHandler) {
    2610           6 :   v8::Isolate* isolate = CcTest::isolate();
    2611           6 :   v8::HandleScope scope(isolate);
    2612          12 :   LocalContext context;
    2613             : 
    2614           6 :   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
    2615             :   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
    2616             :       EmptyInterceptorGetter, EmptyInterceptorSetter, EmptyInterceptorQuery,
    2617           6 :       EmptyInterceptorDeleter, EmptyInterceptorEnumerator));
    2618             :   v8::Local<v8::Object> object =
    2619           6 :       templ->NewInstance(context.local()).ToLocalChecked();
    2620          30 :   context->Global()->Set(context.local(), v8_str("obj"), object).FromJust();
    2621             : 
    2622          12 :   CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("obj.x"), true).IsEmpty());
    2623          12 :   CHECK(
    2624             :       v8::debug::EvaluateGlobal(isolate, v8_str("obj.x = 1"), true).IsEmpty());
    2625          12 :   CHECK(
    2626             :       v8::debug::EvaluateGlobal(isolate, v8_str("'x' in obj"), true).IsEmpty());
    2627          12 :   CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("delete obj.x"), true)
    2628             :             .IsEmpty());
    2629             :   // Wrap the variable declaration since declaring globals is a side effect.
    2630          12 :   CHECK(v8::debug::EvaluateGlobal(
    2631             :             isolate, v8_str("(function() { for (var p in obj) ; })()"), true)
    2632             :             .IsEmpty());
    2633             : 
    2634             :   // Side-effect-free version.
    2635           6 :   Local<ObjectTemplate> templ2 = ObjectTemplate::New(isolate);
    2636             :   templ2->SetHandler(v8::NamedPropertyHandlerConfiguration(
    2637             :       EmptyInterceptorGetter, EmptyInterceptorSetter, EmptyInterceptorQuery,
    2638             :       EmptyInterceptorDeleter, EmptyInterceptorEnumerator,
    2639           6 :       v8::Local<v8::Value>(), v8::PropertyHandlerFlags::kHasNoSideEffect));
    2640             :   v8::Local<v8::Object> object2 =
    2641           6 :       templ2->NewInstance(context.local()).ToLocalChecked();
    2642          30 :   context->Global()->Set(context.local(), v8_str("obj2"), object2).FromJust();
    2643             : 
    2644           6 :   v8::debug::EvaluateGlobal(isolate, v8_str("obj2.x"), true).ToLocalChecked();
    2645          12 :   CHECK(
    2646             :       v8::debug::EvaluateGlobal(isolate, v8_str("obj2.x = 1"), true).IsEmpty());
    2647           6 :   v8::debug::EvaluateGlobal(isolate, v8_str("'x' in obj2"), true)
    2648           6 :       .ToLocalChecked();
    2649          12 :   CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("delete obj2.x"), true)
    2650             :             .IsEmpty());
    2651             :   v8::debug::EvaluateGlobal(
    2652           6 :       isolate, v8_str("(function() { for (var p in obj2) ; })()"), true)
    2653          12 :       .ToLocalChecked();
    2654           6 : }
    2655             : 
    2656       25881 : THREADED_TEST(HiddenPropertiesWithInterceptors) {
    2657           6 :   LocalContext context;
    2658           6 :   v8::Isolate* isolate = context->GetIsolate();
    2659          12 :   v8::HandleScope scope(isolate);
    2660             : 
    2661           6 :   interceptor_for_hidden_properties_called = false;
    2662             : 
    2663             :   v8::Local<v8::Private> key =
    2664           6 :       v8::Private::New(isolate, v8_str("api-test::hidden-key"));
    2665             : 
    2666             :   // Associate an interceptor with an object and start setting hidden values.
    2667           6 :   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
    2668           6 :   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
    2669             :   instance_templ->SetHandler(
    2670           6 :       v8::NamedPropertyHandlerConfiguration(InterceptorForHiddenProperties));
    2671             :   Local<v8::Function> function =
    2672           6 :       fun_templ->GetFunction(context.local()).ToLocalChecked();
    2673             :   Local<v8::Object> obj =
    2674           6 :       function->NewInstance(context.local()).ToLocalChecked();
    2675          18 :   CHECK(obj->SetPrivate(context.local(), key, v8::Integer::New(isolate, 2302))
    2676             :             .FromJust());
    2677          18 :   CHECK_EQ(2302, obj->GetPrivate(context.local(), key)
    2678             :                      .ToLocalChecked()
    2679             :                      ->Int32Value(context.local())
    2680             :                      .FromJust());
    2681          12 :   CHECK(!interceptor_for_hidden_properties_called);
    2682           6 : }
    2683             : 
    2684             : 
    2685         192 : static void XPropertyGetter(Local<Name> property,
    2686             :                             const v8::PropertyCallbackInfo<v8::Value>& info) {
    2687         192 :   ApiTestFuzzer::Fuzz();
    2688         192 :   CHECK(info.Data()->IsUndefined());
    2689             :   info.GetReturnValue().Set(property);
    2690         192 : }
    2691             : 
    2692             : 
    2693       25881 : THREADED_TEST(NamedInterceptorPropertyRead) {
    2694           6 :   v8::Isolate* isolate = CcTest::isolate();
    2695           6 :   v8::HandleScope scope(isolate);
    2696           6 :   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
    2697           6 :   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(XPropertyGetter));
    2698          12 :   LocalContext context;
    2699             :   context->Global()
    2700             :       ->Set(context.local(), v8_str("obj"),
    2701          30 :             templ->NewInstance(context.local()).ToLocalChecked())
    2702          12 :       .FromJust();
    2703             :   Local<Script> script = v8_compile("obj.x");
    2704          66 :   for (int i = 0; i < 10; i++) {
    2705          60 :     Local<Value> result = script->Run(context.local()).ToLocalChecked();
    2706         180 :     CHECK(result->Equals(context.local(), v8_str("x")).FromJust());
    2707           6 :   }
    2708           6 : }
    2709             : 
    2710             : 
    2711       25881 : THREADED_TEST(NamedInterceptorDictionaryIC) {
    2712           6 :   v8::Isolate* isolate = CcTest::isolate();
    2713           6 :   v8::HandleScope scope(isolate);
    2714           6 :   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
    2715           6 :   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(XPropertyGetter));
    2716          12 :   LocalContext context;
    2717             :   // Create an object with a named interceptor.
    2718             :   context->Global()
    2719             :       ->Set(context.local(), v8_str("interceptor_obj"),
    2720          30 :             templ->NewInstance(context.local()).ToLocalChecked())
    2721          12 :       .FromJust();
    2722             :   Local<Script> script = v8_compile("interceptor_obj.x");
    2723          66 :   for (int i = 0; i < 10; i++) {
    2724          60 :     Local<Value> result = script->Run(context.local()).ToLocalChecked();
    2725         180 :     CHECK(result->Equals(context.local(), v8_str("x")).FromJust());
    2726             :   }
    2727             :   // Create a slow case object and a function accessing a property in
    2728             :   // that slow case object (with dictionary probing in generated
    2729             :   // code). Then force object with a named interceptor into slow-case,
    2730             :   // pass it to the function, and check that the interceptor is called
    2731             :   // instead of accessing the local property.
    2732             :   Local<Value> result = CompileRun(
    2733             :       "function get_x(o) { return o.x; };"
    2734             :       "var obj = { x : 42, y : 0 };"
    2735             :       "delete obj.y;"
    2736             :       "for (var i = 0; i < 10; i++) get_x(obj);"
    2737             :       "interceptor_obj.x = 42;"
    2738             :       "interceptor_obj.y = 10;"
    2739             :       "delete interceptor_obj.y;"
    2740             :       "get_x(interceptor_obj)");
    2741          24 :   CHECK(result->Equals(context.local(), v8_str("x")).FromJust());
    2742           6 : }
    2743             : 
    2744             : 
    2745       25881 : THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
    2746           6 :   v8::Isolate* isolate = CcTest::isolate();
    2747           6 :   v8::HandleScope scope(isolate);
    2748           6 :   v8::Local<Context> context1 = Context::New(isolate);
    2749             : 
    2750           6 :   context1->Enter();
    2751           6 :   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
    2752           6 :   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(XPropertyGetter));
    2753             :   // Create an object with a named interceptor.
    2754           6 :   v8::Local<v8::Object> object = templ->NewInstance(context1).ToLocalChecked();
    2755             :   context1->Global()
    2756          18 :       ->Set(context1, v8_str("interceptor_obj"), object)
    2757          12 :       .FromJust();
    2758             : 
    2759             :   // Force the object into the slow case.
    2760             :   CompileRun(
    2761             :       "interceptor_obj.y = 0;"
    2762             :       "delete interceptor_obj.y;");
    2763           6 :   context1->Exit();
    2764             : 
    2765             :   {
    2766             :     // Introduce the object into a different context.
    2767             :     // Repeat named loads to exercise ICs.
    2768           6 :     LocalContext context2;
    2769             :     context2->Global()
    2770          24 :         ->Set(context2.local(), v8_str("interceptor_obj"), object)
    2771          12 :         .FromJust();
    2772             :     Local<Value> result = CompileRun(
    2773             :         "function get_x(o) { return o.x; }"
    2774             :         "interceptor_obj.x = 42;"
    2775             :         "for (var i=0; i != 10; i++) {"
    2776             :         "  get_x(interceptor_obj);"
    2777             :         "}"
    2778             :         "get_x(interceptor_obj)");
    2779             :     // Check that the interceptor was actually invoked.
    2780          18 :     CHECK(result->Equals(context2.local(), v8_str("x")).FromJust());
    2781             :   }
    2782             : 
    2783             :   // Return to the original context and force some object to the slow case
    2784             :   // to cause the NormalizedMapCache to verify.
    2785           6 :   context1->Enter();
    2786             :   CompileRun("var obj = { x : 0 }; delete obj.x;");
    2787           6 :   context1->Exit();
    2788           6 : }
    2789             : 
    2790             : 
    2791           6 : static void SetXOnPrototypeGetter(
    2792             :     Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {
    2793             :   // Set x on the prototype object and do not handle the get request.
    2794           6 :   v8::Local<v8::Value> proto = info.Holder()->GetPrototype();
    2795             :   proto.As<v8::Object>()
    2796             :       ->Set(info.GetIsolate()->GetCurrentContext(), v8_str("x"),
    2797          24 :             v8::Integer::New(info.GetIsolate(), 23))
    2798          12 :       .FromJust();
    2799           6 : }
    2800             : 
    2801             : 
    2802             : // This is a regression test for http://crbug.com/20104. Map
    2803             : // transitions should not interfere with post interceptor lookup.
    2804       25881 : THREADED_TEST(NamedInterceptorMapTransitionRead) {
    2805           6 :   v8::Isolate* isolate = CcTest::isolate();
    2806           6 :   v8::HandleScope scope(isolate);
    2807             :   Local<v8::FunctionTemplate> function_template =
    2808           6 :       v8::FunctionTemplate::New(isolate);
    2809             :   Local<v8::ObjectTemplate> instance_template =
    2810           6 :       function_template->InstanceTemplate();
    2811             :   instance_template->SetHandler(
    2812           6 :       v8::NamedPropertyHandlerConfiguration(SetXOnPrototypeGetter));
    2813          12 :   LocalContext context;
    2814             :   context->Global()
    2815             :       ->Set(context.local(), v8_str("F"),
    2816          30 :             function_template->GetFunction(context.local()).ToLocalChecked())
    2817          12 :       .FromJust();
    2818             :   // Create an instance of F and introduce a map transition for x.
    2819             :   CompileRun("var o = new F(); o.x = 23;");
    2820             :   // Create an instance of F and invoke the getter. The result should be 23.
    2821             :   Local<Value> result = CompileRun("o = new F(); o.x");
    2822          18 :   CHECK_EQ(23, result->Int32Value(context.local()).FromJust());
    2823           6 : }
    2824             : 
    2825             : 
    2826          30 : static void IndexedPropertyGetter(
    2827             :     uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) {
    2828          30 :   ApiTestFuzzer::Fuzz();
    2829          30 :   if (index == 37) {
    2830           6 :     info.GetReturnValue().Set(v8_num(625));
    2831             :   }
    2832          30 : }
    2833             : 
    2834             : 
    2835          12 : static void IndexedPropertySetter(
    2836             :     uint32_t index, Local<Value> value,
    2837             :     const v8::PropertyCallbackInfo<v8::Value>& info) {
    2838          12 :   ApiTestFuzzer::Fuzz();
    2839          12 :   if (index == 39) {
    2840             :     info.GetReturnValue().Set(value);
    2841             :   }
    2842          12 : }
    2843             : 
    2844             : 
    2845       25881 : THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
    2846           6 :   v8::Isolate* isolate = CcTest::isolate();
    2847           6 :   v8::HandleScope scope(isolate);
    2848           6 :   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
    2849             :   templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
    2850           6 :       IndexedPropertyGetter, IndexedPropertySetter));
    2851          12 :   LocalContext context;
    2852             :   context->Global()
    2853             :       ->Set(context.local(), v8_str("obj"),
    2854          30 :             templ->NewInstance(context.local()).ToLocalChecked())
    2855          12 :       .FromJust();
    2856             :   Local<Script> getter_script =
    2857             :       v8_compile("obj.__defineGetter__(\"3\", function(){return 5;});obj[3];");
    2858             :   Local<Script> setter_script = v8_compile(
    2859             :       "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
    2860             :       "obj[17] = 23;"
    2861             :       "obj.foo;");
    2862             :   Local<Script> interceptor_setter_script = v8_compile(
    2863             :       "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
    2864             :       "obj[39] = 47;"
    2865             :       "obj.foo;");  // This setter should not run, due to the interceptor.
    2866             :   Local<Script> interceptor_getter_script = v8_compile("obj[37];");
    2867          12 :   Local<Value> result = getter_script->Run(context.local()).ToLocalChecked();
    2868          18 :   CHECK(v8_num(5)->Equals(context.local(), result).FromJust());
    2869          12 :   result = setter_script->Run(context.local()).ToLocalChecked();
    2870          18 :   CHECK(v8_num(23)->Equals(context.local(), result).FromJust());
    2871          12 :   result = interceptor_setter_script->Run(context.local()).ToLocalChecked();
    2872          18 :   CHECK(v8_num(23)->Equals(context.local(), result).FromJust());
    2873          12 :   result = interceptor_getter_script->Run(context.local()).ToLocalChecked();
    2874          24 :   CHECK(v8_num(625)->Equals(context.local(), result).FromJust());
    2875           6 : }
    2876             : 
    2877             : 
    2878      240078 : static void UnboxedDoubleIndexedPropertyGetter(
    2879             :     uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) {
    2880      240078 :   ApiTestFuzzer::Fuzz();
    2881      240078 :   if (index < 25) {
    2882         150 :     info.GetReturnValue().Set(v8_num(index));
    2883             :   }
    2884      240078 : }
    2885             : 
    2886             : 
    2887       65634 : static void UnboxedDoubleIndexedPropertySetter(
    2888             :     uint32_t index, Local<Value> value,
    2889             :     const v8::PropertyCallbackInfo<v8::Value>& info) {
    2890       65634 :   ApiTestFuzzer::Fuzz();
    2891       65634 :   if (index < 25) {
    2892          78 :     info.GetReturnValue().Set(v8_num(index));
    2893             :   }
    2894       65634 : }
    2895             : 
    2896             : 
    2897           6 : void UnboxedDoubleIndexedPropertyEnumerator(
    2898             :     const v8::PropertyCallbackInfo<v8::Array>& info) {
    2899             :   // Force the list of returned keys to be stored in a FastDoubleArray.
    2900             :   Local<Script> indexed_property_names_script = v8_compile(
    2901             :       "keys = new Array(); keys[125000] = 1;"
    2902             :       "for(i = 0; i < 80000; i++) { keys[i] = i; };"
    2903             :       "keys.length = 25; keys;");
    2904             :   Local<Value> result =
    2905           6 :       indexed_property_names_script->Run(info.GetIsolate()->GetCurrentContext())
    2906           6 :           .ToLocalChecked();
    2907             :   info.GetReturnValue().Set(Local<v8::Array>::Cast(result));
    2908           6 : }
    2909             : 
    2910             : 
    2911             : // Make sure that the the interceptor code in the runtime properly handles
    2912             : // merging property name lists for double-array-backed arrays.
    2913       25881 : THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
    2914           6 :   v8::Isolate* isolate = CcTest::isolate();
    2915           6 :   v8::HandleScope scope(isolate);
    2916           6 :   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
    2917             :   templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
    2918             :       UnboxedDoubleIndexedPropertyGetter, UnboxedDoubleIndexedPropertySetter,
    2919           6 :       nullptr, nullptr, UnboxedDoubleIndexedPropertyEnumerator));
    2920          12 :   LocalContext context;
    2921             :   context->Global()
    2922             :       ->Set(context.local(), v8_str("obj"),
    2923          30 :             templ->NewInstance(context.local()).ToLocalChecked())
    2924          12 :       .FromJust();
    2925             :   // When obj is created, force it to be Stored in a FastDoubleArray.
    2926             :   Local<Script> create_unboxed_double_script = v8_compile(
    2927             :       "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
    2928             :       "key_count = 0; "
    2929             :       "for (x in obj) {key_count++;};"
    2930             :       "obj;");
    2931             :   Local<Value> result =
    2932           6 :       create_unboxed_double_script->Run(context.local()).ToLocalChecked();
    2933          18 :   CHECK(result->ToObject(context.local())
    2934             :             .ToLocalChecked()
    2935             :             ->HasRealIndexedProperty(context.local(), 2000)
    2936             :             .FromJust());
    2937             :   Local<Script> key_count_check = v8_compile("key_count;");
    2938           6 :   result = key_count_check->Run(context.local()).ToLocalChecked();
    2939          24 :   CHECK(v8_num(40013)->Equals(context.local(), result).FromJust());
    2940           6 : }
    2941             : 
    2942             : 
    2943          78 : void SloppyArgsIndexedPropertyEnumerator(
    2944             :     const v8::PropertyCallbackInfo<v8::Array>& info) {
    2945             :   // Force the list of returned keys to be stored in a Arguments object.
    2946             :   Local<Script> indexed_property_names_script = v8_compile(
    2947             :       "function f(w,x) {"
    2948             :       " return arguments;"
    2949             :       "}"
    2950             :       "keys = f(0, 1, 2, 3);"
    2951             :       "keys;");
    2952             :   Local<Object> result = Local<Object>::Cast(
    2953          78 :       indexed_property_names_script->Run(info.GetIsolate()->GetCurrentContext())
    2954          78 :           .ToLocalChecked());
    2955             :   // Have to populate the handle manually, as it's not Cast-able.
    2956             :   i::Handle<i::JSReceiver> o =
    2957             :       v8::Utils::OpenHandle<Object, i::JSReceiver>(result);
    2958             :   i::Handle<i::JSArray> array(i::JSArray::unchecked_cast(*o), o->GetIsolate());
    2959             :   info.GetReturnValue().Set(v8::Utils::ToLocal(array));
    2960          78 : }
    2961             : 
    2962             : 
    2963          24 : static void SloppyIndexedPropertyGetter(
    2964             :     uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) {
    2965          24 :   ApiTestFuzzer::Fuzz();
    2966          24 :   if (index < 4) {
    2967          24 :     info.GetReturnValue().Set(v8_num(index));
    2968             :   }
    2969          24 : }
    2970             : 
    2971             : 
    2972             : // Make sure that the the interceptor code in the runtime properly handles
    2973             : // merging property name lists for non-string arguments arrays.
    2974       25881 : THREADED_TEST(IndexedInterceptorSloppyArgsWithIndexedAccessor) {
    2975           6 :   v8::Isolate* isolate = CcTest::isolate();
    2976           6 :   v8::HandleScope scope(isolate);
    2977           6 :   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
    2978             :   templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
    2979             :       SloppyIndexedPropertyGetter, nullptr, nullptr, nullptr,
    2980           6 :       SloppyArgsIndexedPropertyEnumerator));
    2981          12 :   LocalContext context;
    2982             :   context->Global()
    2983             :       ->Set(context.local(), v8_str("obj"),
    2984          30 :             templ->NewInstance(context.local()).ToLocalChecked())
    2985          12 :       .FromJust();
    2986             :   Local<Script> create_args_script = v8_compile(
    2987             :       "var key_count = 0;"
    2988             :       "for (x in obj) {key_count++;} key_count;");
    2989             :   Local<Value> result =
    2990          12 :       create_args_script->Run(context.local()).ToLocalChecked();
    2991          24 :   CHECK(v8_num(4)->Equals(context.local(), result).FromJust());
    2992           6 : }
    2993             : 
    2994             : 
    2995        4188 : static void IdentityIndexedPropertyGetter(
    2996             :     uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) {
    2997             :   info.GetReturnValue().Set(index);
    2998        4188 : }
    2999             : 
    3000             : 
    3001       25881 : THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
    3002           6 :   v8::Isolate* isolate = CcTest::isolate();
    3003           6 :   v8::HandleScope scope(isolate);
    3004           6 :   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
    3005             :   templ->SetHandler(
    3006           6 :       v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
    3007             : 
    3008          12 :   LocalContext context;
    3009             :   context->Global()
    3010             :       ->Set(context.local(), v8_str("obj"),
    3011          30 :             templ->NewInstance(context.local()).ToLocalChecked())
    3012          12 :       .FromJust();
    3013             : 
    3014             :   // Check fast object case.
    3015             :   const char* fast_case_code =
    3016             :       "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
    3017           6 :   ExpectString(fast_case_code, "0");
    3018             : 
    3019             :   // Check slow case.
    3020             :   const char* slow_case_code =
    3021             :       "obj.x = 1; delete obj.x;"
    3022             :       "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
    3023          12 :   ExpectString(slow_case_code, "1");
    3024           6 : }
    3025             : 
    3026             : 
    3027       25881 : THREADED_TEST(IndexedInterceptorWithNoSetter) {
    3028           6 :   v8::Isolate* isolate = CcTest::isolate();
    3029           6 :   v8::HandleScope scope(isolate);
    3030           6 :   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
    3031             :   templ->SetHandler(
    3032           6 :       v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
    3033             : 
    3034          12 :   LocalContext context;
    3035             :   context->Global()
    3036             :       ->Set(context.local(), v8_str("obj"),
    3037          30 :             templ->NewInstance(context.local()).ToLocalChecked())
    3038          12 :       .FromJust();
    3039             : 
    3040             :   const char* code =
    3041             :       "try {"
    3042             :       "  obj[0] = 239;"
    3043             :       "  for (var i = 0; i < 100; i++) {"
    3044             :       "    var v = obj[0];"
    3045             :       "    if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
    3046             :       "  }"
    3047             :       "  'PASSED'"
    3048             :       "} catch(e) {"
    3049             :       "  e"
    3050             :       "}";
    3051          12 :   ExpectString(code, "PASSED");
    3052           6 : }
    3053             : 
    3054         600 : static bool AccessAlwaysBlocked(Local<v8::Context> accessing_context,
    3055             :                                 Local<v8::Object> accessed_object,
    3056             :                                 Local<v8::Value> data) {
    3057         600 :   return false;
    3058             : }
    3059             : 
    3060             : 
    3061       25881 : THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
    3062           6 :   v8::Isolate* isolate = CcTest::isolate();
    3063           6 :   v8::HandleScope scope(isolate);
    3064           6 :   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
    3065             :   templ->SetHandler(
    3066           6 :       v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
    3067             : 
    3068           6 :   templ->SetAccessCheckCallback(AccessAlwaysBlocked);
    3069             : 
    3070          12 :   LocalContext context;
    3071           6 :   Local<v8::Object> obj = templ->NewInstance(context.local()).ToLocalChecked();
    3072          30 :   context->Global()->Set(context.local(), v8_str("obj"), obj).FromJust();
    3073             : 
    3074             :   const char* code =
    3075             :       "var result = 'PASSED';"
    3076             :       "for (var i = 0; i < 100; i++) {"
    3077             :       "  try {"
    3078             :       "    var v = obj[0];"
    3079             :       "    result = 'Wrong value ' + v + ' at iteration ' + i;"
    3080             :       "    break;"
    3081             :       "  } catch (e) {"
    3082             :       "    /* pass */"
    3083             :       "  }"
    3084             :       "}"
    3085             :       "result";
    3086          12 :   ExpectString(code, "PASSED");
    3087           6 : }
    3088             : 
    3089             : 
    3090       25881 : THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
    3091           6 :   v8::Isolate* isolate = CcTest::isolate();
    3092           6 :   v8::HandleScope scope(isolate);
    3093           6 :   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
    3094             :   templ->SetHandler(
    3095           6 :       v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
    3096             : 
    3097          12 :   LocalContext context;
    3098           6 :   Local<v8::Object> obj = templ->NewInstance(context.local()).ToLocalChecked();
    3099          30 :   context->Global()->Set(context.local(), v8_str("obj"), obj).FromJust();
    3100             : 
    3101             :   const char* code =
    3102             :       "try {"
    3103             :       "  for (var i = 0; i < 100; i++) {"
    3104             :       "    var v = obj[i];"
    3105             :       "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
    3106             :       "  }"
    3107             :       "  'PASSED'"
    3108             :       "} catch(e) {"
    3109             :       "  e"
    3110             :       "}";
    3111          12 :   ExpectString(code, "PASSED");
    3112           6 : }
    3113             : 
    3114             : 
    3115       25881 : THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
    3116           6 :   v8::Isolate* isolate = CcTest::isolate();
    3117           6 :   v8::HandleScope scope(isolate);
    3118           6 :   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
    3119             :   templ->SetHandler(
    3120           6 :       v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
    3121             : 
    3122          12 :   LocalContext context;
    3123           6 :   Local<v8::Object> obj = templ->NewInstance(context.local()).ToLocalChecked();
    3124          30 :   context->Global()->Set(context.local(), v8_str("obj"), obj).FromJust();
    3125             : 
    3126             :   const char* code =
    3127             :       "try {"
    3128             :       "  for (var i = 0; i < 100; i++) {"
    3129             :       "    var expected = i;"
    3130             :       "    var key = i;"
    3131             :       "    if (i == 25) {"
    3132             :       "       key = -1;"
    3133             :       "       expected = undefined;"
    3134             :       "    }"
    3135             :       "    if (i == 50) {"
    3136             :       "       /* probe minimal Smi number on 32-bit platforms */"
    3137             :       "       key = -(1 << 30);"
    3138             :       "       expected = undefined;"
    3139             :       "    }"
    3140             :       "    if (i == 75) {"
    3141             :       "       /* probe minimal Smi number on 64-bit platforms */"
    3142             :       "       key = 1 << 31;"
    3143             :       "       expected = undefined;"
    3144             :       "    }"
    3145             :       "    var v = obj[key];"
    3146             :       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
    3147             :       "  }"
    3148             :       "  'PASSED'"
    3149             :       "} catch(e) {"
    3150             :       "  e"
    3151             :       "}";
    3152          12 :   ExpectString(code, "PASSED");
    3153           6 : }
    3154             : 
    3155             : 
    3156       25881 : THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
    3157           6 :   v8::Isolate* isolate = CcTest::isolate();
    3158           6 :   v8::HandleScope scope(isolate);
    3159           6 :   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
    3160             :   templ->SetHandler(
    3161           6 :       v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
    3162             : 
    3163          12 :   LocalContext context;
    3164           6 :   Local<v8::Object> obj = templ->NewInstance(context.local()).ToLocalChecked();
    3165          30 :   context->Global()->Set(context.local(), v8_str("obj"), obj).FromJust();
    3166             : 
    3167             :   const char* code =
    3168             :       "try {"
    3169             :       "  for (var i = 0; i < 100; i++) {"
    3170             :       "    var expected = i;"
    3171             :       "    var key = i;"
    3172             :       "    if (i == 50) {"
    3173             :       "       key = 'foobar';"
    3174             :       "       expected = undefined;"
    3175             :       "    }"
    3176             :       "    var v = obj[key];"
    3177             :       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
    3178             :       "  }"
    3179             :       "  'PASSED'"
    3180             :       "} catch(e) {"
    3181             :       "  e"
    3182             :       "}";
    3183          12 :   ExpectString(code, "PASSED");
    3184           6 : }
    3185             : 
    3186             : 
    3187       25881 : THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
    3188           6 :   v8::Isolate* isolate = CcTest::isolate();
    3189           6 :   v8::HandleScope scope(isolate);
    3190           6 :   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
    3191             :   templ->SetHandler(
    3192           6 :       v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
    3193             : 
    3194          12 :   LocalContext context;
    3195           6 :   Local<v8::Object> obj = templ->NewInstance(context.local()).ToLocalChecked();
    3196          30 :   context->Global()->Set(context.local(), v8_str("obj"), obj).FromJust();
    3197             : 
    3198             :   const char* code =
    3199             :       "var original = obj;"
    3200             :       "try {"
    3201             :       "  for (var i = 0; i < 100; i++) {"
    3202             :       "    var expected = i;"
    3203             :       "    if (i == 50) {"
    3204             :       "       obj = {50: 'foobar'};"
    3205             :       "       expected = 'foobar';"
    3206             :       "    }"
    3207             :       "    var v = obj[i];"
    3208             :       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
    3209             :       "    if (i == 50) obj = original;"
    3210             :       "  }"
    3211             :       "  'PASSED'"
    3212             :       "} catch(e) {"
    3213             :       "  e"
    3214             :       "}";
    3215          12 :   ExpectString(code, "PASSED");
    3216           6 : }
    3217             : 
    3218             : 
    3219       25881 : THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
    3220           6 :   v8::Isolate* isolate = CcTest::isolate();
    3221           6 :   v8::HandleScope scope(isolate);
    3222           6 :   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
    3223             :   templ->SetHandler(
    3224           6 :       v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
    3225             : 
    3226          12 :   LocalContext context;
    3227           6 :   Local<v8::Object> obj = templ->NewInstance(context.local()).ToLocalChecked();
    3228          30 :   context->Global()->Set(context.local(), v8_str("obj"), obj).FromJust();
    3229             : 
    3230             :   const char* code =
    3231             :       "var original = obj;"
    3232             :       "try {"
    3233             :       "  for (var i = 0; i < 100; i++) {"
    3234             :       "    var expected = i;"
    3235             :       "    if (i == 5) {"
    3236             :       "       obj = 239;"
    3237             :       "       expected = undefined;"
    3238             :       "    }"
    3239             :       "    var v = obj[i];"
    3240             :       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
    3241             :       "    if (i == 5) obj = original;"
    3242             :       "  }"
    3243             :       "  'PASSED'"
    3244             :       "} catch(e) {"
    3245             :       "  e"
    3246             :       "}";
    3247          12 :   ExpectString(code, "PASSED");
    3248           6 : }
    3249             : 
    3250             : 
    3251       25881 : THREADED_TEST(IndexedInterceptorOnProto) {
    3252           6 :   v8::Isolate* isolate = CcTest::isolate();
    3253           6 :   v8::HandleScope scope(isolate);
    3254           6 :   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
    3255             :   templ->SetHandler(
    3256           6 :       v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
    3257             : 
    3258          12 :   LocalContext context;
    3259           6 :   Local<v8::Object> obj = templ->NewInstance(context.local()).ToLocalChecked();
    3260          30 :   context->Global()->Set(context.local(), v8_str("obj"), obj).FromJust();
    3261             : 
    3262             :   const char* code =
    3263             :       "var o = {__proto__: obj};"
    3264             :       "try {"
    3265             :       "  for (var i = 0; i < 100; i++) {"
    3266             :       "    var v = o[i];"
    3267             :       "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
    3268             :       "  }"
    3269             :       "  'PASSED'"
    3270             :       "} catch(e) {"
    3271             :       "  e"
    3272             :       "}";
    3273          12 :   ExpectString(code, "PASSED");
    3274           6 : }
    3275             : 
    3276             : 
    3277        6666 : static void NoBlockGetterX(Local<Name> name,
    3278        6666 :                            const v8::PropertyCallbackInfo<v8::Value>&) {}
    3279             : 
    3280             : 
    3281          12 : static void NoBlockGetterI(uint32_t index,
    3282          12 :                            const v8::PropertyCallbackInfo<v8::Value>&) {}
    3283             : 
    3284             : 
    3285          12 : static void PDeleter(Local<Name> name,
    3286             :                      const v8::PropertyCallbackInfo<v8::Boolean>& info) {
    3287          36 :   if (!name->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("foo"))
    3288          24 :            .FromJust()) {
    3289          12 :     return;  // not intercepted
    3290             :   }
    3291             : 
    3292             :   info.GetReturnValue().Set(false);  // intercepted, don't delete the property
    3293             : }
    3294             : 
    3295             : 
    3296          12 : static void IDeleter(uint32_t index,
    3297             :                      const v8::PropertyCallbackInfo<v8::Boolean>& info) {
    3298          12 :   if (index != 2) {
    3299          12 :     return;  // not intercepted
    3300             :   }
    3301             : 
    3302             :   info.GetReturnValue().Set(false);  // intercepted, don't delete the property
    3303             : }
    3304             : 
    3305             : 
    3306       25881 : THREADED_TEST(Deleter) {
    3307           6 :   v8::Isolate* isolate = CcTest::isolate();
    3308           6 :   v8::HandleScope scope(isolate);
    3309           6 :   v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
    3310             :   obj->SetHandler(v8::NamedPropertyHandlerConfiguration(
    3311           6 :       NoBlockGetterX, nullptr, nullptr, PDeleter, nullptr));
    3312             :   obj->SetHandler(v8::IndexedPropertyHandlerConfiguration(
    3313           6 :       NoBlockGetterI, nullptr, nullptr, IDeleter, nullptr));
    3314          12 :   LocalContext context;
    3315             :   context->Global()
    3316             :       ->Set(context.local(), v8_str("k"),
    3317          30 :             obj->NewInstance(context.local()).ToLocalChecked())
    3318          12 :       .FromJust();
    3319             :   CompileRun(
    3320             :       "k.foo = 'foo';"
    3321             :       "k.bar = 'bar';"
    3322             :       "k[2] = 2;"
    3323             :       "k[4] = 4;");
    3324          18 :   CHECK(v8_compile("delete k.foo")
    3325             :             ->Run(context.local())
    3326             :             .ToLocalChecked()
    3327             :             ->IsFalse());
    3328          18 :   CHECK(v8_compile("delete k.bar")
    3329             :             ->Run(context.local())
    3330             :             .ToLocalChecked()
    3331             :             ->IsTrue());
    3332             : 
    3333          30 :   CHECK(v8_compile("k.foo")
    3334             :             ->Run(context.local())
    3335             :             .ToLocalChecked()
    3336             :             ->Equals(context.local(), v8_str("foo"))
    3337             :             .FromJust());
    3338          18 :   CHECK(v8_compile("k.bar")
    3339             :             ->Run(context.local())
    3340             :             .ToLocalChecked()
    3341             :             ->IsUndefined());
    3342             : 
    3343          18 :   CHECK(v8_compile("delete k[2]")
    3344             :             ->Run(context.local())
    3345             :             .ToLocalChecked()
    3346             :             ->IsFalse());
    3347          18 :   CHECK(v8_compile("delete k[4]")
    3348             :             ->Run(context.local())
    3349             :             .ToLocalChecked()
    3350             :             ->IsTrue());
    3351             : 
    3352          24 :   CHECK(v8_compile("k[2]")
    3353             :             ->Run(context.local())
    3354             :             .ToLocalChecked()
    3355             :             ->Equals(context.local(), v8_num(2))
    3356             :             .FromJust());
    3357          18 :   CHECK(
    3358           6 :       v8_compile("k[4]")->Run(context.local()).ToLocalChecked()->IsUndefined());
    3359           6 : }
    3360             : 
    3361             : 
    3362          66 : static void GetK(Local<Name> name,
    3363             :                  const v8::PropertyCallbackInfo<v8::Value>& info) {
    3364          66 :   ApiTestFuzzer::Fuzz();
    3365          66 :   v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
    3366         258 :   if (name->Equals(context, v8_str("foo")).FromJust() ||
    3367         246 :       name->Equals(context, v8_str("bar")).FromJust() ||
    3368         174 :       name->Equals(context, v8_str("baz")).FromJust()) {
    3369             :     info.GetReturnValue().SetUndefined();
    3370             :   }
    3371          66 : }
    3372             : 
    3373             : 
    3374          36 : static void IndexedGetK(uint32_t index,
    3375             :                         const v8::PropertyCallbackInfo<v8::Value>& info) {
    3376          36 :   ApiTestFuzzer::Fuzz();
    3377          36 :   if (index == 0 || index == 1) info.GetReturnValue().SetUndefined();
    3378          36 : }
    3379             : 
    3380             : 
    3381          24 : static void NamedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
    3382          24 :   ApiTestFuzzer::Fuzz();
    3383          24 :   v8::Local<v8::Array> result = v8::Array::New(info.GetIsolate(), 3);
    3384          24 :   v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
    3385          96 :   CHECK(
    3386             :       result
    3387             :           ->Set(context, v8::Integer::New(info.GetIsolate(), 0), v8_str("foo"))
    3388             :           .FromJust());
    3389          96 :   CHECK(
    3390             :       result
    3391             :           ->Set(context, v8::Integer::New(info.GetIsolate(), 1), v8_str("bar"))
    3392             :           .FromJust());
    3393          96 :   CHECK(
    3394             :       result
    3395             :           ->Set(context, v8::Integer::New(info.GetIsolate(), 2), v8_str("baz"))
    3396             :           .FromJust());
    3397             :   info.GetReturnValue().Set(result);
    3398          24 : }
    3399             : 
    3400             : 
    3401           6 : static void IndexedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
    3402           6 :   ApiTestFuzzer::Fuzz();
    3403           6 :   v8::Local<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
    3404           6 :   v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
    3405          24 :   CHECK(
    3406             :       result->Set(context, v8::Integer::New(info.GetIsolate(), 0), v8_str("0"))
    3407             :           .FromJust());
    3408          24 :   CHECK(
    3409             :       result->Set(context, v8::Integer::New(info.GetIsolate(), 1), v8_str("1"))
    3410             :           .FromJust());
    3411             :   info.GetReturnValue().Set(result);
    3412           6 : }
    3413             : 
    3414             : 
    3415       25881 : THREADED_TEST(Enumerators) {
    3416           6 :   v8::Isolate* isolate = CcTest::isolate();
    3417           6 :   v8::HandleScope scope(isolate);
    3418           6 :   v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
    3419             :   obj->SetHandler(v8::NamedPropertyHandlerConfiguration(GetK, nullptr, nullptr,
    3420           6 :                                                         nullptr, NamedEnum));
    3421             :   obj->SetHandler(v8::IndexedPropertyHandlerConfiguration(
    3422           6 :       IndexedGetK, nullptr, nullptr, nullptr, IndexedEnum));
    3423          12 :   LocalContext context;
    3424             :   context->Global()
    3425             :       ->Set(context.local(), v8_str("k"),
    3426          30 :             obj->NewInstance(context.local()).ToLocalChecked())
    3427          12 :       .FromJust();
    3428             :   v8::Local<v8::Array> result =
    3429             :       v8::Local<v8::Array>::Cast(CompileRun("k[10] = 0;"
    3430             :                                             "k.a = 0;"
    3431             :                                             "k[5] = 0;"
    3432             :                                             "k.b = 0;"
    3433             :                                             "k[4294967294] = 0;"
    3434             :                                             "k.c = 0;"
    3435             :                                             "k[4294967295] = 0;"
    3436             :                                             "k.d = 0;"
    3437             :                                             "k[140000] = 0;"
    3438             :                                             "k.e = 0;"
    3439             :                                             "k[30000000000] = 0;"
    3440             :                                             "k.f = 0;"
    3441             :                                             "var result = [];"
    3442             :                                             "for (var prop in k) {"
    3443             :                                             "  result.push(prop);"
    3444             :                                             "}"
    3445             :                                             "result"));
    3446             :   // Check that we get all the property names returned including the
    3447             :   // ones from the enumerators in the right order: indexed properties
    3448             :   // in numerical order, indexed interceptor properties, named
    3449             :   // properties in insertion order, named interceptor properties.
    3450             :   // This order is not mandated by the spec, so this test is just
    3451             :   // documenting our behavior.
    3452           6 :   CHECK_EQ(17u, result->Length());
    3453             :   // Indexed properties.
    3454          30 :   CHECK(v8_str("5")
    3455             :             ->Equals(context.local(),
    3456             :                      result->Get(context.local(), v8::Integer::New(isolate, 0))
    3457             :                          .ToLocalChecked())
    3458             :             .FromJust());
    3459          30 :   CHECK(v8_str("10")
    3460             :             ->Equals(context.local(),
    3461             :                      result->Get(context.local(), v8::Integer::New(isolate, 1))
    3462             :                          .ToLocalChecked())
    3463             :             .FromJust());
    3464          30 :   CHECK(v8_str("140000")
    3465             :             ->Equals(context.local(),
    3466             :                      result->Get(context.local(), v8::Integer::New(isolate, 2))
    3467             :                          .ToLocalChecked())
    3468             :             .FromJust());
    3469          30 :   CHECK(v8_str("4294967294")
    3470             :             ->Equals(context.local(),
    3471             :                      result->Get(context.local(), v8::Integer::New(isolate, 3))
    3472             :                          .ToLocalChecked())
    3473             :             .FromJust());
    3474             :   // Indexed Interceptor properties
    3475          30 :   CHECK(v8_str("0")
    3476             :             ->Equals(context.local(),
    3477             :                      result->Get(context.local(), v8::Integer::New(isolate, 4))
    3478             :                          .ToLocalChecked())
    3479             :             .FromJust());
    3480          30 :   CHECK(v8_str("1")
    3481             :             ->Equals(context.local(),
    3482             :                      result->Get(context.local(), v8::Integer::New(isolate, 5))
    3483             :                          .ToLocalChecked())
    3484             :             .FromJust());
    3485             :   // Named properties in insertion order.
    3486          30 :   CHECK(v8_str("a")
    3487             :             ->Equals(context.local(),
    3488             :                      result->Get(context.local(), v8::Integer::New(isolate, 6))
    3489             :                          .ToLocalChecked())
    3490             :             .FromJust());
    3491          30 :   CHECK(v8_str("b")
    3492             :             ->Equals(context.local(),
    3493             :                      result->Get(context.local(), v8::Integer::New(isolate, 7))
    3494             :                          .ToLocalChecked())
    3495             :             .FromJust());
    3496          30 :   CHECK(v8_str("c")
    3497             :             ->Equals(context.local(),
    3498             :                      result->Get(context.local(), v8::Integer::New(isolate, 8))
    3499             :                          .ToLocalChecked())
    3500             :             .FromJust());
    3501          30 :   CHECK(v8_str("4294967295")
    3502             :             ->Equals(context.local(),
    3503             :                      result->Get(context.local(), v8::Integer::New(isolate, 9))
    3504             :                          .ToLocalChecked())
    3505             :             .FromJust());
    3506          30 :   CHECK(v8_str("d")
    3507             :             ->Equals(context.local(),
    3508             :                      result->Get(context.local(), v8::Integer::New(isolate, 10))
    3509             :                          .ToLocalChecked())
    3510             :             .FromJust());
    3511          30 :   CHECK(v8_str("e")
    3512             :             ->Equals(context.local(),
    3513             :                      result->Get(context.local(), v8::Integer::New(isolate, 11))
    3514             :                          .ToLocalChecked())
    3515             :             .FromJust());
    3516          30 :   CHECK(v8_str("30000000000")
    3517             :             ->Equals(context.local(),
    3518             :                      result->Get(context.local(), v8::Integer::New(isolate, 12))
    3519             :                          .ToLocalChecked())
    3520             :             .FromJust());
    3521          30 :   CHECK(v8_str("f")
    3522             :             ->Equals(context.local(),
    3523             :                      result->Get(context.local(), v8::Integer::New(isolate, 13))
    3524             :                          .ToLocalChecked())
    3525             :             .FromJust());
    3526             :   // Named interceptor properties.
    3527          30 :   CHECK(v8_str("foo")
    3528             :             ->Equals(context.local(),
    3529             :                      result->Get(context.local(), v8::Integer::New(isolate, 14))
    3530             :                          .ToLocalChecked())
    3531             :             .FromJust());
    3532          30 :   CHECK(v8_str("bar")
    3533             :             ->Equals(context.local(),
    3534             :                      result->Get(context.local(), v8::Integer::New(isolate, 15))
    3535             :                          .ToLocalChecked())
    3536             :             .FromJust());
    3537          30 :   CHECK(v8_str("baz")
    3538             :             ->Equals(context.local(),
    3539             :                      result->Get(context.local(), v8::Integer::New(isolate, 16))
    3540             :                          .ToLocalChecked())
    3541           6 :             .FromJust());
    3542           6 : }
    3543             : 
    3544             : 
    3545             : v8::Local<Value> call_ic_function;
    3546             : v8::Local<Value> call_ic_function2;
    3547             : v8::Local<Value> call_ic_function3;
    3548             : 
    3549        6000 : static void InterceptorCallICGetter(
    3550             :     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
    3551        6000 :   ApiTestFuzzer::Fuzz();
    3552       18000 :   CHECK(v8_str("x")
    3553             :             ->Equals(info.GetIsolate()->GetCurrentContext(), name)
    3554             :             .FromJust());
    3555             :   info.GetReturnValue().Set(call_ic_function);
    3556        6000 : }
    3557             : 
    3558             : 
    3559             : // This test should hit the call IC for the interceptor case.
    3560       25881 : THREADED_TEST(InterceptorCallIC) {
    3561           6 :   v8::Isolate* isolate = CcTest::isolate();
    3562           6 :   v8::HandleScope scope(isolate);
    3563           6 :   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
    3564             :   templ->SetHandler(
    3565           6 :       v8::NamedPropertyHandlerConfiguration(InterceptorCallICGetter));
    3566          12 :   LocalContext context;
    3567             :   context->Global()
    3568             :       ->Set(context.local(), v8_str("o"),
    3569          30 :             templ->NewInstance(context.local()).ToLocalChecked())
    3570          12 :       .FromJust();
    3571             :   call_ic_function = v8_compile("function f(x) { return x + 1; }; f")
    3572           6 :                          ->Run(context.local())
    3573          12 :                          .ToLocalChecked();
    3574             :   v8::Local<Value> value = CompileRun(
    3575             :       "var result = 0;"
    3576             :       "for (var i = 0; i < 1000; i++) {"
    3577             :       "  result = o.x(41);"
    3578             :       "}");
    3579          18 :   CHECK_EQ(42, value->Int32Value(context.local()).FromJust());
    3580           6 : }
    3581             : 
    3582             : 
    3583             : // This test checks that if interceptor doesn't provide
    3584             : // a value, we can fetch regular value.
    3585       25881 : THREADED_TEST(InterceptorCallICSeesOthers) {
    3586           6 :   v8::Isolate* isolate = CcTest::isolate();
    3587           6 :   v8::HandleScope scope(isolate);
    3588           6 :   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
    3589           6 :   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
    3590          12 :   LocalContext context;
    3591             :   context->Global()
    3592             :       ->Set(context.local(), v8_str("o"),
    3593          30 :             templ->NewInstance(context.local()).ToLocalChecked())
    3594          12 :       .FromJust();
    3595             :   v8::Local<Value> value = CompileRun(
    3596             :       "o.x = function f(x) { return x + 1; };"
    3597             :       "var result = 0;"
    3598             :       "for (var i = 0; i < 7; i++) {"
    3599             :       "  result = o.x(41);"
    3600             :       "}");
    3601          18 :   CHECK_EQ(42, value->Int32Value(context.local()).FromJust());
    3602           6 : }
    3603             : 
    3604             : 
    3605             : static v8::Local<Value> call_ic_function4;
    3606        6000 : static void InterceptorCallICGetter4(
    3607             :     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
    3608        6000 :   ApiTestFuzzer::Fuzz();
    3609       18000 :   CHECK(v8_str("x")
    3610             :             ->Equals(info.GetIsolate()->GetCurrentContext(), name)
    3611             :             .FromJust());
    3612             :   info.GetReturnValue().Set(call_ic_function4);
    3613        6000 : }
    3614             : 
    3615             : 
    3616             : // This test checks that if interceptor provides a function,
    3617             : // even if we cached shadowed variant, interceptor's function
    3618             : // is invoked
    3619       25881 : THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
    3620           6 :   v8::Isolate* isolate = CcTest::isolate();
    3621           6 :   v8::HandleScope scope(isolate);
    3622           6 :   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
    3623             :   templ->SetHandler(
    3624           6 :       v8::NamedPropertyHandlerConfiguration(InterceptorCallICGetter4));
    3625          12 :   LocalContext context;
    3626             :   context->Global()
    3627             :       ->Set(context.local(), v8_str("o"),
    3628          30 :             templ->NewInstance(context.local()).ToLocalChecked())
    3629          12 :       .FromJust();
    3630             :   call_ic_function4 = v8_compile("function f(x) { return x - 1; }; f")
    3631           6 :                           ->Run(context.local())
    3632          12 :                           .ToLocalChecked();
    3633             :   v8::Local<Value> value = CompileRun(
    3634             :       "Object.getPrototypeOf(o).x = function(x) { return x + 1; };"
    3635             :       "var result = 0;"
    3636             :       "for (var i = 0; i < 1000; i++) {"
    3637             :       "  result = o.x(42);"
    3638             :       "}");
    3639          18 :   CHECK_EQ(41, value->Int32Value(context.local()).FromJust());
    3640           6 : }
    3641             : 
    3642             : 
    3643             : // Test the case when we stored cacheable lookup into
    3644             : // a stub, but it got invalidated later on
    3645       25881 : THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
    3646           6 :   v8::Isolate* isolate = CcTest::isolate();
    3647           6 :   v8::HandleScope scope(isolate);
    3648           6 :   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
    3649           6 :   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
    3650          12 :   LocalContext context;
    3651             :   context->Global()
    3652             :       ->Set(context.local(), v8_str("o"),
    3653          30 :             templ->NewInstance(context.local()).ToLocalChecked())
    3654          12 :       .FromJust();
    3655             :   v8::Local<Value> value = CompileRun(
    3656             :       "proto1 = new Object();"
    3657             :       "proto2 = new Object();"
    3658             :       "o.__proto__ = proto1;"
    3659             :       "proto1.__proto__ = proto2;"
    3660             :       "proto2.y = function(x) { return x + 1; };"
    3661             :       // Invoke it many times to compile a stub
    3662             :       "for (var i = 0; i < 7; i++) {"
    3663             :       "  o.y(42);"
    3664             :       "}"
    3665             :       "proto1.y = function(x) { return x - 1; };"
    3666             :       "var result = 0;"
    3667             :       "for (var i = 0; i < 7; i++) {"
    3668             :       "  result += o.y(42);"
    3669             :       "}");
    3670          18 :   CHECK_EQ(41 * 7, value->Int32Value(context.local()).FromJust());
    3671           6 : }
    3672             : 
    3673             : 
    3674             : // This test checks that if interceptor doesn't provide a function,
    3675             : // cached constant function is used
    3676       25881 : THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
    3677           6 :   v8::Isolate* isolate = CcTest::isolate();
    3678           6 :   v8::HandleScope scope(isolate);
    3679           6 :   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
    3680           6 :   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
    3681          12 :   LocalContext context;
    3682             :   context->Global()
    3683             :       ->Set(context.local(), v8_str("o"),
    3684          30 :             templ->NewInstance(context.local()).ToLocalChecked())
    3685          12 :       .FromJust();
    3686             :   v8::Local<Value> value = CompileRun(
    3687             :       "function inc(x) { return x + 1; };"
    3688             :       "inc(1);"
    3689             :       "o.x = inc;"
    3690             :       "var result = 0;"
    3691             :       "for (var i = 0; i < 1000; i++) {"
    3692             :       "  result = o.x(42);"
    3693             :       "}");
    3694          18 :   CHECK_EQ(43, value->Int32Value(context.local()).FromJust());
    3695           6 : }
    3696             : 
    3697             : 
    3698             : static v8::Local<Value> call_ic_function5;
    3699        6000 : static void InterceptorCallICGetter5(
    3700             :     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
    3701        6000 :   ApiTestFuzzer::Fuzz();
    3702        6000 :   if (v8_str("x")
    3703       12000 :           ->Equals(info.GetIsolate()->GetCurrentContext(), name)
    3704       12000 :           .FromJust())
    3705             :     info.GetReturnValue().Set(call_ic_function5);
    3706        6000 : }
    3707             : 
    3708             : 
    3709             : // This test checks that if interceptor provides a function,
    3710             : // even if we cached constant function, interceptor's function
    3711             : // is invoked
    3712       25881 : THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
    3713           6 :   v8::Isolate* isolate = CcTest::isolate();
    3714           6 :   v8::HandleScope scope(isolate);
    3715           6 :   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
    3716             :   templ->SetHandler(
    3717           6 :       v8::NamedPropertyHandlerConfiguration(InterceptorCallICGetter5));
    3718          12 :   LocalContext context;
    3719             :   context->Global()
    3720             :       ->Set(context.local(), v8_str("o"),
    3721          30 :             templ->NewInstance(context.local()).ToLocalChecked())
    3722          12 :       .FromJust();
    3723             :   call_ic_function5 = v8_compile("function f(x) { return x - 1; }; f")
    3724           6 :                           ->Run(context.local())
    3725          12 :                           .ToLocalChecked();
    3726             :   v8::Local<Value> value = CompileRun(
    3727             :       "function inc(x) { return x + 1; };"
    3728             :       "inc(1);"
    3729             :       "o.x = inc;"
    3730             :       "var result = 0;"
    3731             :       "for (var i = 0; i < 1000; i++) {"
    3732             :       "  result = o.x(42);"
    3733             :       "}");
    3734          18 :   CHECK_EQ(41, value->Int32Value(context.local()).FromJust());
    3735           6 : }
    3736             : 
    3737             : 
    3738             : static v8::Local<Value> call_ic_function6;
    3739       24000 : static void InterceptorCallICGetter6(
    3740             :     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
    3741       24000 :   ApiTestFuzzer::Fuzz();
    3742       24000 :   if (v8_str("x")
    3743       48000 :           ->Equals(info.GetIsolate()->GetCurrentContext(), name)
    3744       48000 :           .FromJust())
    3745             :     info.GetReturnValue().Set(call_ic_function6);
    3746       24000 : }
    3747             : 
    3748             : 
    3749             : // Same test as above, except the code is wrapped in a function
    3750             : // to test the optimized compiler.
    3751       25881 : THREADED_TEST(InterceptorCallICConstantFunctionNotNeededWrapped) {
    3752           6 :   i::FLAG_allow_natives_syntax = true;
    3753           6 :   v8::Isolate* isolate = CcTest::isolate();
    3754           6 :   v8::HandleScope scope(isolate);
    3755           6 :   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
    3756             :   templ->SetHandler(
    3757           6 :       v8::NamedPropertyHandlerConfiguration(InterceptorCallICGetter6));
    3758          12 :   LocalContext context;
    3759             :   context->Global()
    3760             :       ->Set(context.local(), v8_str("o"),
    3761          30 :             templ->NewInstance(context.local()).ToLocalChecked())
    3762          12 :       .FromJust();
    3763             :   call_ic_function6 = v8_compile("function f(x) { return x - 1; }; f")
    3764           6 :                           ->Run(context.local())
    3765          12 :                           .ToLocalChecked();
    3766             :   v8::Local<Value> value = CompileRun(
    3767             :       "function inc(x) { return x + 1; };"
    3768             :       "inc(1);"
    3769             :       "o.x = inc;"
    3770             :       "function test() {"
    3771             :       "  var result = 0;"
    3772             :       "  for (var i = 0; i < 1000; i++) {"
    3773             :       "    result = o.x(42);"
    3774             :       "  }"
    3775             :       "  return result;"
    3776             :       "};"
    3777             :       "test();"
    3778             :       "test();"
    3779             :       "test();"
    3780             :       "%OptimizeFunctionOnNextCall(test);"
    3781             :       "test()");
    3782          18 :   CHECK_EQ(41, value->Int32Value(context.local()).FromJust());
    3783           6 : }
    3784             : 
    3785             : 
    3786             : // Test the case when we stored constant function into
    3787             : // a stub, but it got invalidated later on
    3788       25881 : THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
    3789           6 :   v8::Isolate* isolate = CcTest::isolate();
    3790           6 :   v8::HandleScope scope(isolate);
    3791           6 :   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
    3792           6 :   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
    3793          12 :   LocalContext context;
    3794             :   context->Global()
    3795             :       ->Set(context.local(), v8_str("o"),
    3796          30 :             templ->NewInstance(context.local()).ToLocalChecked())
    3797          12 :       .FromJust();
    3798             :   v8::Local<Value> value = CompileRun(
    3799             :       "function inc(x) { return x + 1; };"
    3800             :       "inc(1);"
    3801             :       "proto1 = new Object();"
    3802             :       "proto2 = new Object();"
    3803             :       "o.__proto__ = proto1;"
    3804             :       "proto1.__proto__ = proto2;"
    3805             :       "proto2.y = inc;"
    3806             :       // Invoke it many times to compile a stub
    3807             :       "for (var i = 0; i < 7; i++) {"
    3808             :       "  o.y(42);"
    3809             :       "}"
    3810             :       "proto1.y = function(x) { return x - 1; };"
    3811             :       "var result = 0;"
    3812             :       "for (var i = 0; i < 7; i++) {"
    3813             :       "  result += o.y(42);"
    3814             :       "}");
    3815          18 :   CHECK_EQ(41 * 7, value->Int32Value(context.local()).FromJust());
    3816           6 : }
    3817             : 
    3818             : 
    3819             : // Test the case when we stored constant function into
    3820             : // a stub, but it got invalidated later on due to override on
    3821             : // global object which is between interceptor and constant function' holders.
    3822       25881 : THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
    3823           6 :   v8::Isolate* isolate = CcTest::isolate();
    3824           6 :   v8::HandleScope scope(isolate);
    3825           6 :   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
    3826           6 :   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
    3827          12 :   LocalContext context;
    3828             :   context->Global()
    3829             :       ->Set(context.local(), v8_str("o"),
    3830          30 :             templ->NewInstance(context.local()).ToLocalChecked())
    3831          12 :       .FromJust();
    3832             :   v8::Local<Value> value = CompileRun(
    3833             :       "function inc(x) { return x + 1; };"
    3834             :       "inc(1);"
    3835             :       "o.__proto__ = this;"
    3836             :       "this.__proto__.y = inc;"
    3837             :       // Invoke it many times to compile a stub
    3838             :       "for (var i = 0; i < 7; i++) {"
    3839             :       "  if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
    3840             :       "}"
    3841             :       "this.y = function(x) { return x - 1; };"
    3842             :       "var result = 0;"
    3843             :       "for (var i = 0; i < 7; i++) {"
    3844             :       "  result += o.y(42);"
    3845             :       "}");
    3846          18 :   CHECK_EQ(41 * 7, value->Int32Value(context.local()).FromJust());
    3847           6 : }
    3848             : 
    3849             : 
    3850             : // Test the case when actual function to call sits on global object.
    3851       25881 : THREADED_TEST(InterceptorCallICCachedFromGlobal) {
    3852           6 :   v8::Isolate* isolate = CcTest::isolate();
    3853           6 :   v8::HandleScope scope(isolate);
    3854           6 :   v8::Local<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
    3855           6 :   templ_o->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
    3856             : 
    3857          12 :   LocalContext context;
    3858             :   context->Global()
    3859             :       ->Set(context.local(), v8_str("o"),
    3860          30 :             templ_o->NewInstance(context.local()).ToLocalChecked())
    3861          12 :       .FromJust();
    3862             : 
    3863             :   v8::Local<Value> value = CompileRun(
    3864             :       "try {"
    3865             :       "  o.__proto__ = this;"
    3866             :       "  for (var i = 0; i < 10; i++) {"
    3867             :       "    var v = o.parseFloat('239');"
    3868             :       "    if (v != 239) throw v;"
    3869             :       // Now it should be ICed and keep a reference to parseFloat.
    3870             :       "  }"
    3871             :       "  var result = 0;"
    3872             :       "  for (var i = 0; i < 10; i++) {"
    3873             :       "    result += o.parseFloat('239');"
    3874             :       "  }"
    3875             :       "  result"
    3876             :       "} catch(e) {"
    3877             :       "  e"
    3878             :       "};");
    3879          18 :   CHECK_EQ(239 * 10, value->Int32Value(context.local()).FromJust());
    3880           6 : }
    3881             : 
    3882             : 
    3883             : v8::Local<Value> keyed_call_ic_function;
    3884             : 
    3885          30 : static void InterceptorKeyedCallICGetter(
    3886             :     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
    3887          30 :   ApiTestFuzzer::Fuzz();
    3888          30 :   if (v8_str("x")
    3889          60 :           ->Equals(info.GetIsolate()->GetCurrentContext(), name)
    3890          60 :           .FromJust()) {
    3891             :     info.GetReturnValue().Set(keyed_call_ic_function);
    3892             :   }
    3893          30 : }
    3894             : 
    3895             : 
    3896             : // Test the case when we stored cacheable lookup into
    3897             : // a stub, but the function name changed (to another cacheable function).
    3898       25881 : THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
    3899           6 :   v8::Isolate* isolate = CcTest::isolate();
    3900           6 :   v8::HandleScope scope(isolate);
    3901           6 :   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
    3902           6 :   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
    3903          12 :   LocalContext context;
    3904             :   context->Global()
    3905             :       ->Set(context.local(), v8_str("o"),
    3906          30 :             templ->NewInstance(context.local()).ToLocalChecked())
    3907          12 :       .FromJust();
    3908             :   CompileRun(
    3909             :       "proto = new Object();"
    3910             :       "proto.y = function(x) { return x + 1; };"
    3911             :       "proto.z = function(x) { return x - 1; };"
    3912             :       "o.__proto__ = proto;"
    3913             :       "var result = 0;"
    3914             :       "var method = 'y';"
    3915             :       "for (var i = 0; i < 10; i++) {"
    3916             :       "  if (i == 5) { method = 'z'; };"
    3917             :       "  result += o[method](41);"
    3918             :       "}");
    3919          36 :   CHECK_EQ(42 * 5 + 40 * 5, context->Global()
    3920             :                                 ->Get(context.local(), v8_str("result"))
    3921             :                                 .ToLocalChecked()
    3922             :                                 ->Int32Value(context.local())
    3923           6 :                                 .FromJust());
    3924           6 : }
    3925             : 
    3926             : 
    3927             : // Test the case when we stored cacheable lookup into
    3928             : // a stub, but the function name changed (and the new function is present
    3929             : // both before and after the interceptor in the prototype chain).
    3930       25881 : THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
    3931           6 :   v8::Isolate* isolate = CcTest::isolate();
    3932           6 :   v8::HandleScope scope(isolate);
    3933           6 :   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
    3934             :   templ->SetHandler(
    3935           6 :       v8::NamedPropertyHandlerConfiguration(InterceptorKeyedCallICGetter));
    3936          12 :   LocalContext context;
    3937             :   context->Global()
    3938             :       ->Set(context.local(), v8_str("proto1"),
    3939          30 :             templ->NewInstance(context.local()).ToLocalChecked())
    3940          12 :       .FromJust();
    3941             :   keyed_call_ic_function = v8_compile("function f(x) { return x - 1; }; f")
    3942           6 :                                ->Run(context.local())
    3943          12 :                                .ToLocalChecked();
    3944             :   CompileRun(
    3945             :       "o = new Object();"
    3946             :       "proto2 = new Object();"
    3947             :       "o.y = function(x) { return x + 1; };"
    3948             :       "proto2.y = function(x) { return x + 2; };"
    3949             :       "o.__proto__ = proto1;"
    3950             :       "proto1.__proto__ = proto2;"
    3951             :       "var result = 0;"
    3952             :       "var method = 'x';"
    3953             :       "for (var i = 0; i < 10; i++) {"
    3954             :       "  if (i == 5) { method = 'y'; };"
    3955             :       "  result += o[method](41);"
    3956             :       "}");
    3957          36 :   CHECK_EQ(42 * 5 + 40 * 5, context->Global()
    3958             :                                 ->Get(context.local(), v8_str("result"))
    3959             :                                 .ToLocalChecked()
    3960             :                                 ->Int32Value(context.local())
    3961           6 :                                 .FromJust());
    3962           6 : }
    3963             : 
    3964             : 
    3965             : // Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
    3966             : // on the global object.
    3967       25881 : THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
    3968           6 :   v8::Isolate* isolate = CcTest::isolate();
    3969           6 :   v8::HandleScope scope(isolate);
    3970           6 :   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
    3971           6 :   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
    3972          12 :   LocalContext context;
    3973             :   context->Global()
    3974             :       ->Set(context.local(), v8_str("o"),
    3975          30 :             templ->NewInstance(context.local()).ToLocalChecked())
    3976          12 :       .FromJust();
    3977             :   CompileRun(
    3978             :       "function inc(x) { return x + 1; };"
    3979             :       "inc(1);"
    3980             :       "function dec(x) { return x - 1; };"
    3981             :       "dec(1);"
    3982             :       "o.__proto__ = this;"
    3983             :       "this.__proto__.x = inc;"
    3984             :       "this.__proto__.y = dec;"
    3985             :       "var result = 0;"
    3986             :       "var method = 'x';"
    3987             :       "for (var i = 0; i < 10; i++) {"
    3988             :       "  if (i == 5) { method = 'y'; };"
    3989             :       "  result += o[method](41);"
    3990             :       "}");
    3991          36 :   CHECK_EQ(42 * 5 + 40 * 5, context->Global()
    3992             :                                 ->Get(context.local(), v8_str("result"))
    3993             :                                 .ToLocalChecked()
    3994             :                                 ->Int32Value(context.local())
    3995           6 :                                 .FromJust());
    3996           6 : }
    3997             : 
    3998             : 
    3999             : // Test the case when actual function to call sits on global object.
    4000       25881 : THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
    4001           6 :   v8::Isolate* isolate = CcTest::isolate();
    4002           6 :   v8::HandleScope scope(isolate);
    4003           6 :   v8::Local<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
    4004           6 :   templ_o->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
    4005          12 :   LocalContext context;
    4006             :   context->Global()
    4007             :       ->Set(context.local(), v8_str("o"),
    4008          30 :             templ_o->NewInstance(context.local()).ToLocalChecked())
    4009          12 :       .FromJust();
    4010             : 
    4011             :   CompileRun(
    4012             :       "function len(x) { return x.length; };"
    4013             :       "o.__proto__ = this;"
    4014             :       "var m = 'parseFloat';"
    4015             :       "var result = 0;"
    4016             :       "for (var i = 0; i < 10; i++) {"
    4017             :       "  if (i == 5) {"
    4018             :       "    m = 'len';"
    4019             :       "    saved_result = result;"
    4020             :       "  };"
    4021             :       "  result = o[m]('239');"
    4022             :       "}");
    4023          36 :   CHECK_EQ(3, context->Global()
    4024             :                   ->Get(context.local(), v8_str("result"))
    4025             :                   .ToLocalChecked()
    4026             :                   ->Int32Value(context.local())
    4027             :                   .FromJust());
    4028          36 :   CHECK_EQ(239, context->Global()
    4029             :                     ->Get(context.local(), v8_str("saved_result"))
    4030             :                     .ToLocalChecked()
    4031             :                     ->Int32Value(context.local())
    4032           6 :                     .FromJust());
    4033           6 : }
    4034             : 
    4035             : 
    4036             : // Test the map transition before the interceptor.
    4037       25881 : THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
    4038           6 :   v8::Isolate* isolate = CcTest::isolate();
    4039           6 :   v8::HandleScope scope(isolate);
    4040           6 :   v8::Local<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
    4041           6 :   templ_o->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
    4042          12 :   LocalContext context;
    4043             :   context->Global()
    4044             :       ->Set(context.local(), v8_str("proto"),
    4045          30 :             templ_o->NewInstance(context.local()).ToLocalChecked())
    4046          12 :       .FromJust();
    4047             : 
    4048             :   CompileRun(
    4049             :       "var o = new Object();"
    4050             :       "o.__proto__ = proto;"
    4051             :       "o.method = function(x) { return x + 1; };"
    4052             :       "var m = 'method';"
    4053             :       "var result = 0;"
    4054             :       "for (var i = 0; i < 10; i++) {"
    4055             :       "  if (i == 5) { o.method = function(x) { return x - 1; }; };"
    4056             :       "  result += o[m](41);"
    4057             :       "}");
    4058          36 :   CHECK_EQ(42 * 5 + 40 * 5, context->Global()
    4059             :                                 ->Get(context.local(), v8_str("result"))
    4060             :                                 .ToLocalChecked()
    4061             :                                 ->Int32Value(context.local())
    4062           6 :                                 .FromJust());
    4063           6 : }
    4064             : 
    4065             : 
    4066             : // Test the map transition after the interceptor.
    4067       25881 : THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
    4068           6 :   v8::Isolate* isolate = CcTest::isolate();
    4069           6 :   v8::HandleScope scope(isolate);
    4070           6 :   v8::Local<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
    4071           6 :   templ_o->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
    4072          12 :   LocalContext context;
    4073             :   context->Global()
    4074             :       ->Set(context.local(), v8_str("o"),
    4075          30 :             templ_o->NewInstance(context.local()).ToLocalChecked())
    4076          12 :       .FromJust();
    4077             : 
    4078             :   CompileRun(
    4079             :       "var proto = new Object();"
    4080             :       "o.__proto__ = proto;"
    4081             :       "proto.method = function(x) { return x + 1; };"
    4082             :       "var m = 'method';"
    4083             :       "var result = 0;"
    4084             :       "for (var i = 0; i < 10; i++) {"
    4085             :       "  if (i == 5) { proto.method = function(x) { return x - 1; }; };"
    4086             :       "  result += o[m](41);"
    4087             :       "}");
    4088          36 :   CHECK_EQ(42 * 5 + 40 * 5, context->Global()
    4089             :                                 ->Get(context.local(), v8_str("result"))
    4090             :                                 .ToLocalChecked()
    4091             :                                 ->Int32Value(context.local())
    4092           6 :                                 .FromJust());
    4093           6 : }
    4094             : 
    4095             : 
    4096             : static int interceptor_call_count = 0;
    4097             : 
    4098         288 : static void InterceptorICRefErrorGetter(
    4099             :     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
    4100         288 :   ApiTestFuzzer::Fuzz();
    4101         864 :   if (!is_bootstrapping &&
    4102             :       v8_str("x")
    4103         864 :           ->Equals(info.GetIsolate()->GetCurrentContext(), name)
    4104         828 :           .FromJust() &&
    4105         252 :       interceptor_call_count++ < 20) {
    4106             :     info.GetReturnValue().Set(call_ic_function2);
    4107             :   }
    4108         288 : }
    4109             : 
    4110             : 
    4111             : // This test should hit load and call ICs for the interceptor case.
    4112             : // Once in a while, the interceptor will reply that a property was not
    4113             : // found in which case we should get a reference error.
    4114       25881 : THREADED_TEST(InterceptorICReferenceErrors) {
    4115           6 :   v8::Isolate* isolate = CcTest::isolate();
    4116           6 :   v8::HandleScope scope(isolate);
    4117           6 :   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
    4118             :   templ->SetHandler(
    4119           6 :       v8::NamedPropertyHandlerConfiguration(InterceptorICRefErrorGetter));
    4120           6 :   is_bootstrapping = true;
    4121          12 :   LocalContext context(nullptr, templ, v8::Local<Value>());
    4122           6 :   is_bootstrapping = false;
    4123             :   call_ic_function2 = v8_compile("function h(x) { return x; }; h")
    4124           6 :                           ->Run(context.local())
    4125          12 :                           .ToLocalChecked();
    4126             :   v8::Local<Value> value = CompileRun(
    4127             :       "function f() {"
    4128             :       "  for (var i = 0; i < 1000; i++) {"
    4129             :       "    try { x; } catch(e) { return true; }"
    4130             :       "  }"
    4131             :       "  return false;"
    4132             :       "};"
    4133             :       "f();");
    4134           6 :   CHECK(value->BooleanValue(isolate));
    4135           6 :   interceptor_call_count = 0;
    4136             :   value = CompileRun(
    4137             :       "function g() {"
    4138             :       "  for (var i = 0; i < 1000; i++) {"
    4139             :       "    try { x(42); } catch(e) { return true; }"
    4140             :       "  }"
    4141             :       "  return false;"
    4142             :       "};"
    4143             :       "g();");
    4144          12 :   CHECK(value->BooleanValue(isolate));
    4145           6 : }
    4146             : 
    4147             : 
    4148             : static int interceptor_ic_exception_get_count = 0;
    4149             : 
    4150         276 : static void InterceptorICExceptionGetter(
    4151             :     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
    4152         276 :   ApiTestFuzzer::Fuzz();
    4153         276 :   if (is_bootstrapping) return;
    4154         276 :   if (v8_str("x")
    4155         552 :           ->Equals(info.GetIsolate()->GetCurrentContext(), name)
    4156         792 :           .FromJust() &&
    4157         240 :       ++interceptor_ic_exception_get_count < 20) {
    4158             :     info.GetReturnValue().Set(call_ic_function3);
    4159             :   }
    4160         276 :   if (interceptor_ic_exception_get_count == 20) {
    4161          24 :     info.GetIsolate()->ThrowException(v8_num(42));
    4162          12 :     return;
    4163             :   }
    4164             : }
    4165             : 
    4166             : 
    4167             : // Test interceptor load/call IC where the interceptor throws an
    4168             : // exception once in a while.
    4169       25881 : THREADED_TEST(InterceptorICGetterExceptions) {
    4170           6 :   interceptor_ic_exception_get_count = 0;
    4171           6 :   v8::Isolate* isolate = CcTest::isolate();
    4172           6 :   v8::HandleScope scope(isolate);
    4173           6 :   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
    4174             :   templ->SetHandler(
    4175           6 :       v8::NamedPropertyHandlerConfiguration(InterceptorICExceptionGetter));
    4176           6 :   is_bootstrapping = true;
    4177          12 :   LocalContext context(nullptr, templ, v8::Local<Value>());
    4178           6 :   is_bootstrapping = false;
    4179             :   call_ic_function3 = v8_compile("function h(x) { return x; }; h")
    4180           6 :                           ->Run(context.local())
    4181          12 :                           .ToLocalChecked();
    4182             :   v8::Local<Value> value = CompileRun(
    4183             :       "function f() {"
    4184             :       "  for (var i = 0; i < 100; i++) {"
    4185             :       "    try { x; } catch(e) { return true; }"
    4186             :       "  }"
    4187             :       "  return false;"
    4188             :       "};"
    4189             :       "f();");
    4190           6 :   CHECK(value->BooleanValue(isolate));
    4191           6 :   interceptor_ic_exception_get_count = 0;
    4192             :   value = CompileRun(
    4193             :       "function f() {"
    4194             :       "  for (var i = 0; i < 100; i++) {"
    4195             :       "    try { x(42); } catch(e) { return true; }"
    4196             :       "  }"
    4197             :       "  return false;"
    4198             :       "};"
    4199             :       "f();");
    4200          12 :   CHECK(value->BooleanValue(isolate));
    4201           6 : }
    4202             : 
    4203             : 
    4204             : static int interceptor_ic_exception_set_count = 0;
    4205             : 
    4206         126 : static void InterceptorICExceptionSetter(
    4207             :     Local<Name> key, Local<Value> value,
    4208             :     const v8::PropertyCallbackInfo<v8::Value>& info) {
    4209         126 :   ApiTestFuzzer::Fuzz();
    4210         126 :   if (++interceptor_ic_exception_set_count > 20) {
    4211          12 :     info.GetIsolate()->ThrowException(v8_num(42));
    4212             :   }
    4213         126 : }
    4214             : 
    4215             : 
    4216             : // Test interceptor store IC where the interceptor throws an exception
    4217             : // once in a while.
    4218       25881 : THREADED_TEST(InterceptorICSetterExceptions) {
    4219           6 :   interceptor_ic_exception_set_count = 0;
    4220           6 :   v8::Isolate* isolate = CcTest::isolate();
    4221           6 :   v8::HandleScope scope(isolate);
    4222           6 :   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
    4223             :   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
    4224           6 :       nullptr, InterceptorICExceptionSetter));
    4225          12 :   LocalContext context(nullptr, templ, v8::Local<Value>());
    4226             :   v8::Local<Value> value = CompileRun(
    4227             :       "function f() {"
    4228             :       "  for (var i = 0; i < 100; i++) {"
    4229             :       "    try { x = 42; } catch(e) { return true; }"
    4230             :       "  }"
    4231             :       "  return false;"
    4232             :       "};"
    4233             :       "f();");
    4234          12 :   CHECK(value->BooleanValue(isolate));
    4235           6 : }
    4236             : 
    4237             : 
    4238             : // Test that we ignore null interceptors.
    4239       25881 : THREADED_TEST(NullNamedInterceptor) {
    4240           6 :   v8::Isolate* isolate = CcTest::isolate();
    4241           6 :   v8::HandleScope scope(isolate);
    4242           6 :   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
    4243             :   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
    4244           6 :       static_cast<v8::GenericNamedPropertyGetterCallback>(nullptr)));
    4245          12 :   LocalContext context;
    4246           6 :   templ->Set(CcTest::isolate(), "x", v8_num(42));
    4247             :   v8::Local<v8::Object> obj =
    4248           6 :       templ->NewInstance(context.local()).ToLocalChecked();
    4249          30 :   context->Global()->Set(context.local(), v8_str("obj"), obj).FromJust();
    4250             :   v8::Local<Value> value = CompileRun("obj.x");
    4251           6 :   CHECK(value->IsInt32());
    4252          18 :   CHECK_EQ(42, value->Int32Value(context.local()).FromJust());
    4253           6 : }
    4254             : 
    4255             : 
    4256             : // Test that we ignore null interceptors.
    4257       25881 : THREADED_TEST(NullIndexedInterceptor) {
    4258           6 :   v8::Isolate* isolate = CcTest::isolate();
    4259           6 :   v8::HandleScope scope(isolate);
    4260           6 :   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
    4261             :   templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
    4262           6 :       static_cast<v8::IndexedPropertyGetterCallback>(nullptr)));
    4263          12 :   LocalContext context;
    4264           6 :   templ->Set(CcTest::isolate(), "42", v8_num(42));
    4265             :   v8::Local<v8::Object> obj =
    4266           6 :       templ->NewInstance(context.local()).ToLocalChecked();
    4267          30 :   context->Global()->Set(context.local(), v8_str("obj"), obj).FromJust();
    4268             :   v8::Local<Value> value = CompileRun("obj[42]");
    4269           6 :   CHECK(value->IsInt32());
    4270          18 :   CHECK_EQ(42, value->Int32Value(context.local()).FromJust());
    4271           6 : }
    4272             : 
    4273             : 
    4274       25881 : THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
    4275           6 :   v8::Isolate* isolate = CcTest::isolate();
    4276           6 :   v8::HandleScope scope(isolate);
    4277           6 :   v8::Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
    4278             :   templ->InstanceTemplate()->SetHandler(
    4279          12 :       v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
    4280          12 :   LocalContext env;
    4281             :   env->Global()
    4282           6 :       ->Set(env.local(), v8_str("obj"), templ->GetFunction(env.local())
    4283           6 :                                             .ToLocalChecked()
    4284           6 :                                             ->NewInstance(env.local())
    4285          24 :                                             .ToLocalChecked())
    4286          12 :       .FromJust();
    4287             :   ExpectTrue("obj.x === 42");
    4288           6 :   ExpectTrue("!obj.propertyIsEnumerable('x')");
    4289           6 : }
    4290             : 
    4291             : 
    4292       25881 : THREADED_TEST(Regress256330) {
    4293           7 :   if (!i::FLAG_opt) return;
    4294           5 :   i::FLAG_allow_natives_syntax = true;
    4295           5 :   LocalContext context;
    4296          10 :   v8::HandleScope scope(context->GetIsolate());
    4297           5 :   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
    4298           5 :   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
    4299             :   context->Global()
    4300             :       ->Set(context.local(), v8_str("Bug"),
    4301          30 :             templ->GetFunction(context.local()).ToLocalChecked())
    4302          10 :       .FromJust();
    4303             :   CompileRun(
    4304             :       "\"use strict\"; var o = new Bug;"
    4305             :       "function f(o) { o.x = 10; };"
    4306             :       "f(o); f(o); f(o);"
    4307             :       "%OptimizeFunctionOnNextCall(f);"
    4308             :       "f(o);");
    4309           5 :   int status = v8_run_int32value(v8_compile("%GetOptimizationStatus(f)"));
    4310             :   int mask = static_cast<int>(i::OptimizationStatus::kIsFunction) |
    4311             :              static_cast<int>(i::OptimizationStatus::kOptimized);
    4312          10 :   CHECK_EQ(mask, status & mask);
    4313             : }
    4314             : 
    4315       25881 : THREADED_TEST(OptimizedInterceptorSetter) {
    4316           6 :   i::FLAG_allow_natives_syntax = true;
    4317           6 :   v8::HandleScope scope(CcTest::isolate());
    4318           6 :   Local<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
    4319           6 :   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
    4320          12 :   LocalContext env;
    4321             :   env->Global()
    4322             :       ->Set(env.local(), v8_str("Obj"),
    4323          36 :             templ->GetFunction(env.local()).ToLocalChecked())
    4324          12 :       .FromJust();
    4325             :   CompileRun(
    4326             :       "var obj = new Obj;"
    4327             :       // Initialize fields to avoid transitions later.
    4328             :       "obj.age = 0;"
    4329             :       "obj.accessor_age = 42;"
    4330             :       "function setter(i) { this.accessor_age = i; };"
    4331             :       "function getter() { return this.accessor_age; };"
    4332             :       "function setAge(i) { obj.age = i; };"
    4333             :       "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
    4334             :       "setAge(1);"
    4335             :       "setAge(2);"
    4336             :       "setAge(3);"
    4337             :       "%OptimizeFunctionOnNextCall(setAge);"
    4338             :       "setAge(4);");
    4339             :   // All stores went through the interceptor.
    4340           6 :   ExpectInt32("obj.interceptor_age", 4);
    4341          12 :   ExpectInt32("obj.accessor_age", 42);
    4342           6 : }
    4343             : 
    4344       25881 : THREADED_TEST(OptimizedInterceptorGetter) {
    4345           6 :   i::FLAG_allow_natives_syntax = true;
    4346           6 :   v8::HandleScope scope(CcTest::isolate());
    4347           6 :   Local<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
    4348           6 :   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
    4349          12 :   LocalContext env;
    4350             :   env->Global()
    4351             :       ->Set(env.local(), v8_str("Obj"),
    4352          36 :             templ->GetFunction(env.local()).ToLocalChecked())
    4353          12 :       .FromJust();
    4354             :   CompileRun(
    4355             :       "var obj = new Obj;"
    4356             :       // Initialize fields to avoid transitions later.
    4357             :       "obj.age = 1;"
    4358             :       "obj.accessor_age = 42;"
    4359             :       "function getter() { return this.accessor_age; };"
    4360             :       "function getAge() { return obj.interceptor_age; };"
    4361             :       "Object.defineProperty(obj, 'interceptor_age', { get:getter });"
    4362             :       "getAge();"
    4363             :       "getAge();"
    4364             :       "getAge();"
    4365             :       "%OptimizeFunctionOnNextCall(getAge);");
    4366             :   // Access through interceptor.
    4367          12 :   ExpectInt32("getAge()", 1);
    4368           6 : }
    4369             : 
    4370       25881 : THREADED_TEST(OptimizedInterceptorFieldRead) {
    4371           6 :   i::FLAG_allow_natives_syntax = true;
    4372           6 :   v8::HandleScope scope(CcTest::isolate());
    4373           6 :   Local<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
    4374           6 :   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
    4375          12 :   LocalContext env;
    4376             :   env->Global()
    4377             :       ->Set(env.local(), v8_str("Obj"),
    4378          36 :             templ->GetFunction(env.local()).ToLocalChecked())
    4379          12 :       .FromJust();
    4380             :   CompileRun(
    4381             :       "var obj = new Obj;"
    4382             :       "obj.__proto__.interceptor_age = 42;"
    4383             :       "obj.age = 100;"
    4384             :       "function getAge() { return obj.interceptor_age; };");
    4385           6 :   ExpectInt32("getAge();", 100);
    4386           6 :   ExpectInt32("getAge();", 100);
    4387           6 :   ExpectInt32("getAge();", 100);
    4388             :   CompileRun("%OptimizeFunctionOnNextCall(getAge);");
    4389             :   // Access through interceptor.
    4390          12 :   ExpectInt32("getAge();", 100);
    4391           6 : }
    4392             : 
    4393       25881 : THREADED_TEST(OptimizedInterceptorFieldWrite) {
    4394           6 :   i::FLAG_allow_natives_syntax = true;
    4395           6 :   v8::HandleScope scope(CcTest::isolate());
    4396           6 :   Local<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
    4397           6 :   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
    4398          12 :   LocalContext env;
    4399             :   env->Global()
    4400             :       ->Set(env.local(), v8_str("Obj"),
    4401          36 :             templ->GetFunction(env.local()).ToLocalChecked())
    4402          12 :       .FromJust();
    4403             :   CompileRun(
    4404             :       "var obj = new Obj;"
    4405             :       "obj.age = 100000;"
    4406             :       "function setAge(i) { obj.age = i };"
    4407             :       "setAge(100);"
    4408             :       "setAge(101);"
    4409             :       "setAge(102);"
    4410             :       "%OptimizeFunctionOnNextCall(setAge);"
    4411             :       "setAge(103);");
    4412           6 :   ExpectInt32("obj.age", 100000);
    4413          12 :   ExpectInt32("obj.interceptor_age", 103);
    4414           6 : }
    4415             : 
    4416             : 
    4417       25881 : THREADED_TEST(Regress149912) {
    4418           6 :   LocalContext context;
    4419          12 :   v8::HandleScope scope(context->GetIsolate());
    4420           6 :   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
    4421           6 :   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
    4422             :   context->Global()
    4423             :       ->Set(context.local(), v8_str("Bug"),
    4424          36 :             templ->GetFunction(context.local()).ToLocalChecked())
    4425          12 :       .FromJust();
    4426           6 :   CompileRun("Number.prototype.__proto__ = new Bug; var x = 0; x.foo();");
    4427           6 : }
    4428             : 
    4429       25881 : THREADED_TEST(Regress625155) {
    4430           6 :   LocalContext context;
    4431          12 :   v8::HandleScope scope(context->GetIsolate());
    4432           6 :   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
    4433           6 :   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
    4434             :   context->Global()
    4435             :       ->Set(context.local(), v8_str("Bug"),
    4436          36 :             templ->GetFunction(context.local()).ToLocalChecked())
    4437          12 :       .FromJust();
    4438             :   CompileRun(
    4439             :       "Number.prototype.__proto__ = new Bug;"
    4440             :       "var x;"
    4441             :       "x = 0xDEAD;"
    4442             :       "x.boom = 0;"
    4443             :       "x = 's';"
    4444             :       "x.boom = 0;"
    4445             :       "x = 1.5;"
    4446           6 :       "x.boom = 0;");
    4447           6 : }
    4448             : 
    4449       25881 : THREADED_TEST(Regress125988) {
    4450           6 :   v8::HandleScope scope(CcTest::isolate());
    4451           6 :   Local<FunctionTemplate> intercept = FunctionTemplate::New(CcTest::isolate());
    4452           6 :   AddInterceptor(intercept, EmptyInterceptorGetter, EmptyInterceptorSetter);
    4453          12 :   LocalContext env;
    4454             :   env->Global()
    4455             :       ->Set(env.local(), v8_str("Intercept"),
    4456          36 :             intercept->GetFunction(env.local()).ToLocalChecked())
    4457          12 :       .FromJust();
    4458             :   CompileRun(
    4459             :       "var a = new Object();"
    4460             :       "var b = new Intercept();"
    4461             :       "var c = new Object();"
    4462             :       "c.__proto__ = b;"
    4463             :       "b.__proto__ = a;"
    4464             :       "a.x = 23;"
    4465             :       "for (var i = 0; i < 3; i++) c.x;");
    4466           6 :   ExpectBoolean("c.hasOwnProperty('x')", false);
    4467           6 :   ExpectInt32("c.x", 23);
    4468             :   CompileRun(
    4469             :       "a.y = 42;"
    4470             :       "for (var i = 0; i < 3; i++) c.x;");
    4471           6 :   ExpectBoolean("c.hasOwnProperty('x')", false);
    4472           6 :   ExpectInt32("c.x", 23);
    4473           6 :   ExpectBoolean("c.hasOwnProperty('y')", false);
    4474          12 :   ExpectInt32("c.y", 42);
    4475           6 : }
    4476             : 
    4477             : 
    4478          12 : static void IndexedPropertyEnumerator(
    4479             :     const v8::PropertyCallbackInfo<v8::Array>& info) {
    4480          12 :   v8::Local<v8::Array> result = v8::Array::New(info.GetIsolate(), 1);
    4481             :   result->Set(info.GetIsolate()->GetCurrentContext(), 0,
    4482          36 :               v8::Integer::New(info.GetIsolate(), 7))
    4483          24 :       .FromJust();
    4484             :   info.GetReturnValue().Set(result);
    4485          12 : }
    4486             : 
    4487             : 
    4488          18 : static void NamedPropertyEnumerator(
    4489             :     const v8::PropertyCallbackInfo<v8::Array>& info) {
    4490          18 :   v8::Local<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
    4491          18 :   v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
    4492          54 :   result->Set(context, 0, v8_str("x")).FromJust();
    4493          36 :   result->Set(context, 1, v8::Symbol::GetIterator(info.GetIsolate()))
    4494          36 :       .FromJust();
    4495             :   info.GetReturnValue().Set(result);
    4496          18 : }
    4497             : 
    4498             : 
    4499       25881 : THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
    4500           6 :   v8::Isolate* isolate = CcTest::isolate();
    4501           6 :   v8::HandleScope handle_scope(isolate);
    4502           6 :   v8::Local<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New(isolate);
    4503             : 
    4504          18 :   obj_template->Set(v8_str("7"), v8::Integer::New(CcTest::isolate(), 7));
    4505          18 :   obj_template->Set(v8_str("x"), v8::Integer::New(CcTest::isolate(), 42));
    4506             :   obj_template->SetHandler(v8::IndexedPropertyHandlerConfiguration(
    4507           6 :       nullptr, nullptr, nullptr, nullptr, IndexedPropertyEnumerator));
    4508             :   obj_template->SetHandler(v8::NamedPropertyHandlerConfiguration(
    4509           6 :       nullptr, nullptr, nullptr, nullptr, NamedPropertyEnumerator));
    4510             : 
    4511          12 :   LocalContext context;
    4512           6 :   v8::Local<v8::Object> global = context->Global();
    4513             :   global->Set(context.local(), v8_str("object"),
    4514          24 :               obj_template->NewInstance(context.local()).ToLocalChecked())
    4515          12 :       .FromJust();
    4516             : 
    4517             :   v8::Local<v8::Value> result =
    4518             :       CompileRun("Object.getOwnPropertyNames(object)");
    4519           6 :   CHECK(result->IsArray());
    4520             :   v8::Local<v8::Array> result_array = v8::Local<v8::Array>::Cast(result);
    4521           6 :   CHECK_EQ(2u, result_array->Length());
    4522          12 :   CHECK(result_array->Get(context.local(), 0).ToLocalChecked()->IsString());
    4523          12 :   CHECK(result_array->Get(context.local(), 1).ToLocalChecked()->IsString());
    4524          24 :   CHECK(v8_str("7")
    4525             :             ->Equals(context.local(),
    4526             :                      result_array->Get(context.local(), 0).ToLocalChecked())
    4527             :             .FromJust());
    4528          24 :   CHECK(v8_str("x")
    4529             :             ->Equals(context.local(),
    4530             :                      result_array->Get(context.local(), 1).ToLocalChecked())
    4531             :             .FromJust());
    4532             : 
    4533             :   result = CompileRun("var ret = []; for (var k in object) ret.push(k); ret");
    4534           6 :   CHECK(result->IsArray());
    4535             :   result_array = v8::Local<v8::Array>::Cast(result);
    4536           6 :   CHECK_EQ(2u, result_array->Length());
    4537          12 :   CHECK(result_array->Get(context.local(), 0).ToLocalChecked()->IsString());
    4538          12 :   CHECK(result_array->Get(context.local(), 1).ToLocalChecked()->IsString());
    4539          24 :   CHECK(v8_str("7")
    4540             :             ->Equals(context.local(),
    4541             :                      result_array->Get(context.local(), 0).ToLocalChecked())
    4542             :             .FromJust());
    4543          24 :   CHECK(v8_str("x")
    4544             :             ->Equals(context.local(),
    4545             :                      result_array->Get(context.local(), 1).ToLocalChecked())
    4546             :             .FromJust());
    4547             : 
    4548             :   result = CompileRun("Object.getOwnPropertySymbols(object)");
    4549           6 :   CHECK(result->IsArray());
    4550             :   result_array = v8::Local<v8::Array>::Cast(result);
    4551           6 :   CHECK_EQ(1u, result_array->Length());
    4552          24 :   CHECK(result_array->Get(context.local(), 0)
    4553             :             .ToLocalChecked()
    4554             :             ->Equals(context.local(), v8::Symbol::GetIterator(isolate))
    4555           6 :             .FromJust());
    4556           6 : }
    4557             : 
    4558             : 
    4559          12 : static void IndexedPropertyEnumeratorException(
    4560             :     const v8::PropertyCallbackInfo<v8::Array>& info) {
    4561          24 :   info.GetIsolate()->ThrowException(v8_num(42));
    4562          12 : }
    4563             : 
    4564             : 
    4565       25881 : THREADED_TEST(GetOwnPropertyNamesWithIndexedInterceptorExceptions_regress4026) {
    4566           6 :   v8::Isolate* isolate = CcTest::isolate();
    4567           6 :   v8::HandleScope handle_scope(isolate);
    4568           6 :   v8::Local<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New(isolate);
    4569             : 
    4570          18 :   obj_template->Set(v8_str("7"), v8::Integer::New(CcTest::isolate(), 7));
    4571          18 :   obj_template->Set(v8_str("x"), v8::Integer::New(CcTest::isolate(), 42));
    4572             :   // First just try a failing indexed interceptor.
    4573             :   obj_template->SetHandler(v8::IndexedPropertyHandlerConfiguration(
    4574           6 :       nullptr, nullptr, nullptr, nullptr, IndexedPropertyEnumeratorException));
    4575             : 
    4576          12 :   LocalContext context;
    4577           6 :   v8::Local<v8::Object> global = context->Global();
    4578             :   global->Set(context.local(), v8_str("object"),
    4579          24 :               obj_template->NewInstance(context.local()).ToLocalChecked())
    4580          12 :       .FromJust();
    4581             :   v8::Local<v8::Value> result = CompileRun(
    4582             :       "var result  = []; "
    4583             :       "try { "
    4584             :       "  for (var k in object) result .push(k);"
    4585             :       "} catch (e) {"
    4586             :       "  result  = e"
    4587             :       "}"
    4588             :       "result ");
    4589           6 :   CHECK(!result->IsArray());
    4590          18 :   CHECK(v8_num(42)->Equals(context.local(), result).FromJust());
    4591             : 
    4592             :   result = CompileRun(
    4593             :       "var result = [];"
    4594             :       "try { "
    4595             :       "  result = Object.keys(object);"
    4596             :       "} catch (e) {"
    4597             :       "  result = e;"
    4598             :       "}"
    4599             :       "result");
    4600           6 :   CHECK(!result->IsArray());
    4601          24 :   CHECK(v8_num(42)->Equals(context.local(), result).FromJust());
    4602           6 : }
    4603             : 
    4604             : 
    4605          12 : static void NamedPropertyEnumeratorException(
    4606             :     const v8::PropertyCallbackInfo<v8::Array>& info) {
    4607          24 :   info.GetIsolate()->ThrowException(v8_num(43));
    4608          12 : }
    4609             : 
    4610             : 
    4611       25881 : THREADED_TEST(GetOwnPropertyNamesWithNamedInterceptorExceptions_regress4026) {
    4612           6 :   v8::Isolate* isolate = CcTest::isolate();
    4613           6 :   v8::HandleScope handle_scope(isolate);
    4614           6 :   v8::Local<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New(isolate);
    4615             : 
    4616          18 :   obj_template->Set(v8_str("7"), v8::Integer::New(CcTest::isolate(), 7));
    4617          18 :   obj_template->Set(v8_str("x"), v8::Integer::New(CcTest::isolate(), 42));
    4618             :   // First just try a failing indexed interceptor.
    4619             :   obj_template->SetHandler(v8::NamedPropertyHandlerConfiguration(
    4620           6 :       nullptr, nullptr, nullptr, nullptr, NamedPropertyEnumeratorException));
    4621             : 
    4622          12 :   LocalContext context;
    4623           6 :   v8::Local<v8::Object> global = context->Global();
    4624             :   global->Set(context.local(), v8_str("object"),
    4625          24 :               obj_template->NewInstance(context.local()).ToLocalChecked())
    4626          12 :       .FromJust();
    4627             : 
    4628             :   v8::Local<v8::Value> result = CompileRun(
    4629             :       "var result = []; "
    4630             :       "try { "
    4631             :       "  for (var k in object) result.push(k);"
    4632             :       "} catch (e) {"
    4633             :       "  result = e"
    4634             :       "}"
    4635             :       "result");
    4636           6 :   CHECK(!result->IsArray());
    4637          18 :   CHECK(v8_num(43)->Equals(context.local(), result).FromJust());
    4638             : 
    4639             :   result = CompileRun(
    4640             :       "var result = [];"
    4641             :       "try { "
    4642             :       "  result = Object.keys(object);"
    4643             :       "} catch (e) {"
    4644             :       "  result = e;"
    4645             :       "}"
    4646             :       "result");
    4647           6 :   CHECK(!result->IsArray());
    4648          24 :   CHECK(v8_num(43)->Equals(context.local(), result).FromJust());
    4649           6 : }
    4650             : 
    4651             : namespace {
    4652             : 
    4653             : template <typename T>
    4654          38 : Local<Object> BuildWrappedObject(v8::Isolate* isolate, T* data) {
    4655          38 :   auto templ = v8::ObjectTemplate::New(isolate);
    4656          38 :   templ->SetInternalFieldCount(1);
    4657             :   auto instance =
    4658          38 :       templ->NewInstance(isolate->GetCurrentContext()).ToLocalChecked();
    4659          38 :   instance->SetAlignedPointerInInternalField(0, data);
    4660          38 :   return instance;
    4661             : }
    4662             : 
    4663             : 
    4664             : template <typename T>
    4665         276 : T* GetWrappedObject(Local<Value> data) {
    4666             :   return reinterpret_cast<T*>(
    4667         276 :       Object::Cast(*data)->GetAlignedPointerFromInternalField(0));
    4668             : }
    4669             : 
    4670             : 
    4671             : struct AccessCheckData {
    4672             :   int count;
    4673             :   bool result;
    4674             : };
    4675             : 
    4676             : AccessCheckData* g_access_check_data = nullptr;
    4677             : 
    4678         110 : bool SimpleAccessChecker(Local<v8::Context> accessing_context,
    4679             :                          Local<v8::Object> access_object,
    4680             :                          Local<v8::Value> data) {
    4681         110 :   g_access_check_data->count++;
    4682         110 :   return g_access_check_data->result;
    4683             : }
    4684             : 
    4685             : 
    4686             : struct ShouldInterceptData {
    4687             :   int value;
    4688             :   bool should_intercept;
    4689             : };
    4690             : 
    4691             : 
    4692         261 : void ShouldNamedInterceptor(Local<Name> name,
    4693             :                             const v8::PropertyCallbackInfo<Value>& info) {
    4694         261 :   ApiTestFuzzer::Fuzz();
    4695         261 :   CheckReturnValue(info, FUNCTION_ADDR(ShouldNamedInterceptor));
    4696         261 :   auto data = GetWrappedObject<ShouldInterceptData>(info.Data());
    4697         522 :   if (!data->should_intercept) return;
    4698         256 :   info.GetReturnValue().Set(v8_num(data->value));
    4699             : }
    4700             : 
    4701             : 
    4702          15 : void ShouldIndexedInterceptor(uint32_t,
    4703             :                               const v8::PropertyCallbackInfo<Value>& info) {
    4704          15 :   ApiTestFuzzer::Fuzz();
    4705          15 :   CheckReturnValue(info, FUNCTION_ADDR(ShouldIndexedInterceptor));
    4706          15 :   auto data = GetWrappedObject<ShouldInterceptData>(info.Data());
    4707          30 :   if (!data->should_intercept) return;
    4708          10 :   info.GetReturnValue().Set(v8_num(data->value));
    4709             : }
    4710             : 
    4711             : }  // namespace
    4712             : 
    4713             : 
    4714       25880 : TEST(NamedAllCanReadInterceptor) {
    4715           5 :   auto isolate = CcTest::isolate();
    4716           5 :   v8::HandleScope handle_scope(isolate);
    4717          10 :   LocalContext context;
    4718             : 
    4719             :   AccessCheckData access_check_data;
    4720           5 :   access_check_data.result = true;
    4721           5 :   access_check_data.count = 0;
    4722             : 
    4723           5 :   g_access_check_data = &access_check_data;
    4724             : 
    4725             :   ShouldInterceptData intercept_data_0;
    4726           5 :   intercept_data_0.value = 239;
    4727           5 :   intercept_data_0.should_intercept = true;
    4728             : 
    4729             :   ShouldInterceptData intercept_data_1;
    4730           5 :   intercept_data_1.value = 165;
    4731           5 :   intercept_data_1.should_intercept = false;
    4732             : 
    4733           5 :   auto intercepted_0 = v8::ObjectTemplate::New(isolate);
    4734             :   {
    4735             :     v8::NamedPropertyHandlerConfiguration conf(ShouldNamedInterceptor);
    4736           5 :     conf.flags = v8::PropertyHandlerFlags::kAllCanRead;
    4737             :     conf.data =
    4738           5 :         BuildWrappedObject<ShouldInterceptData>(isolate, &intercept_data_0);
    4739           5 :     intercepted_0->SetHandler(conf);
    4740             :   }
    4741             : 
    4742           5 :   auto intercepted_1 = v8::ObjectTemplate::New(isolate);
    4743             :   {
    4744             :     v8::NamedPropertyHandlerConfiguration conf(ShouldNamedInterceptor);
    4745           5 :     conf.flags = v8::PropertyHandlerFlags::kAllCanRead;
    4746             :     conf.data =
    4747           5 :         BuildWrappedObject<ShouldInterceptData>(isolate, &intercept_data_1);
    4748           5 :     intercepted_1->SetHandler(conf);
    4749             :   }
    4750             : 
    4751           5 :   auto checked = v8::ObjectTemplate::New(isolate);
    4752           5 :   checked->SetAccessCheckCallback(SimpleAccessChecker);
    4753             : 
    4754             :   context->Global()
    4755             :       ->Set(context.local(), v8_str("intercepted_0"),
    4756          25 :             intercepted_0->NewInstance(context.local()).ToLocalChecked())
    4757          10 :       .FromJust();
    4758             :   context->Global()
    4759             :       ->Set(context.local(), v8_str("intercepted_1"),
    4760          25 :             intercepted_1->NewInstance(context.local()).ToLocalChecked())
    4761          10 :       .FromJust();
    4762             :   auto checked_instance =
    4763           5 :       checked->NewInstance(context.local()).ToLocalChecked();
    4764          15 :   checked_instance->Set(context.local(), v8_str("whatever"), v8_num(17))
    4765          10 :       .FromJust();
    4766             :   context->Global()
    4767          20 :       ->Set(context.local(), v8_str("checked"), checked_instance)
    4768          10 :       .FromJust();
    4769             :   CompileRun(
    4770             :       "checked.__proto__ = intercepted_1;"
    4771             :       "intercepted_1.__proto__ = intercepted_0;");
    4772             : 
    4773           5 :   CHECK_EQ(3, access_check_data.count);
    4774             : 
    4775           5 :   ExpectInt32("checked.whatever", 17);
    4776           5 :   CHECK(!CompileRun("Object.getOwnPropertyDescriptor(checked, 'whatever')")
    4777             :              ->IsUndefined());
    4778           5 :   CHECK_EQ(5, access_check_data.count);
    4779             : 
    4780           5 :   access_check_data.result = false;
    4781           5 :   ExpectInt32("checked.whatever", intercept_data_0.value);
    4782             :   {
    4783           5 :     v8::TryCatch try_catch(isolate);
    4784             :     CompileRun("Object.getOwnPropertyDescriptor(checked, 'whatever')");
    4785           5 :     CHECK(try_catch.HasCaught());
    4786             :   }
    4787           5 :   CHECK_EQ(8, access_check_data.count);
    4788             : 
    4789           5 :   intercept_data_1.should_intercept = true;
    4790           5 :   ExpectInt32("checked.whatever", intercept_data_1.value);
    4791             :   {
    4792           5 :     v8::TryCatch try_catch(isolate);
    4793             :     CompileRun("Object.getOwnPropertyDescriptor(checked, 'whatever')");
    4794           5 :     CHECK(try_catch.HasCaught());
    4795             :   }
    4796           5 :   CHECK_EQ(11, access_check_data.count);
    4797          10 :   g_access_check_data = nullptr;
    4798           5 : }
    4799             : 
    4800             : 
    4801       25880 : TEST(IndexedAllCanReadInterceptor) {
    4802           5 :   auto isolate = CcTest::isolate();
    4803           5 :   v8::HandleScope handle_scope(isolate);
    4804          10 :   LocalContext context;
    4805             : 
    4806             :   AccessCheckData access_check_data;
    4807           5 :   access_check_data.result = true;
    4808           5 :   access_check_data.count = 0;
    4809             : 
    4810           5 :   g_access_check_data = &access_check_data;
    4811             : 
    4812             :   ShouldInterceptData intercept_data_0;
    4813           5 :   intercept_data_0.value = 239;
    4814           5 :   intercept_data_0.should_intercept = true;
    4815             : 
    4816             :   ShouldInterceptData intercept_data_1;
    4817           5 :   intercept_data_1.value = 165;
    4818           5 :   intercept_data_1.should_intercept = false;
    4819             : 
    4820           5 :   auto intercepted_0 = v8::ObjectTemplate::New(isolate);
    4821             :   {
    4822             :     v8::IndexedPropertyHandlerConfiguration conf(ShouldIndexedInterceptor);
    4823           5 :     conf.flags = v8::PropertyHandlerFlags::kAllCanRead;
    4824             :     conf.data =
    4825           5 :         BuildWrappedObject<ShouldInterceptData>(isolate, &intercept_data_0);
    4826           5 :     intercepted_0->SetHandler(conf);
    4827             :   }
    4828             : 
    4829           5 :   auto intercepted_1 = v8::ObjectTemplate::New(isolate);
    4830             :   {
    4831             :     v8::IndexedPropertyHandlerConfiguration conf(ShouldIndexedInterceptor);
    4832           5 :     conf.flags = v8::PropertyHandlerFlags::kAllCanRead;
    4833             :     conf.data =
    4834           5 :         BuildWrappedObject<ShouldInterceptData>(isolate, &intercept_data_1);
    4835           5 :     intercepted_1->SetHandler(conf);
    4836             :   }
    4837             : 
    4838           5 :   auto checked = v8::ObjectTemplate::New(isolate);
    4839           5 :   checked->SetAccessCheckCallback(SimpleAccessChecker);
    4840             : 
    4841             :   context->Global()
    4842             :       ->Set(context.local(), v8_str("intercepted_0"),
    4843          25 :             intercepted_0->NewInstance(context.local()).ToLocalChecked())
    4844          10 :       .FromJust();
    4845             :   context->Global()
    4846             :       ->Set(context.local(), v8_str("intercepted_1"),
    4847          25 :             intercepted_1->NewInstance(context.local()).ToLocalChecked())
    4848          10 :       .FromJust();
    4849             :   auto checked_instance =
    4850           5 :       checked->NewInstance(context.local()).ToLocalChecked();
    4851             :   context->Global()
    4852          20 :       ->Set(context.local(), v8_str("checked"), checked_instance)
    4853          10 :       .FromJust();
    4854          10 :   checked_instance->Set(context.local(), 15, v8_num(17)).FromJust();
    4855             :   CompileRun(
    4856             :       "checked.__proto__ = intercepted_1;"
    4857             :       "intercepted_1.__proto__ = intercepted_0;");
    4858             : 
    4859           5 :   CHECK_EQ(3, access_check_data.count);
    4860             : 
    4861           5 :   access_check_data.result = true;
    4862           5 :   ExpectInt32("checked[15]", 17);
    4863           5 :   CHECK(!CompileRun("Object.getOwnPropertyDescriptor(checked, '15')")
    4864             :              ->IsUndefined());
    4865           5 :   CHECK_EQ(5, access_check_data.count);
    4866             : 
    4867           5 :   access_check_data.result = false;
    4868           5 :   ExpectInt32("checked[15]", intercept_data_0.value);
    4869             :   {
    4870           5 :     v8::TryCatch try_catch(isolate);
    4871             :     CompileRun("Object.getOwnPropertyDescriptor(checked, '15')");
    4872           5 :     CHECK(try_catch.HasCaught());
    4873             :   }
    4874           5 :   CHECK_EQ(8, access_check_data.count);
    4875             : 
    4876           5 :   intercept_data_1.should_intercept = true;
    4877           5 :   ExpectInt32("checked[15]", intercept_data_1.value);
    4878             :   {
    4879           5 :     v8::TryCatch try_catch(isolate);
    4880             :     CompileRun("Object.getOwnPropertyDescriptor(checked, '15')");
    4881           5 :     CHECK(try_catch.HasCaught());
    4882             :   }
    4883           5 :   CHECK_EQ(11, access_check_data.count);
    4884             : 
    4885          10 :   g_access_check_data = nullptr;
    4886           5 : }
    4887             : 
    4888             : 
    4889       25881 : THREADED_TEST(NonMaskingInterceptorOwnProperty) {
    4890           6 :   auto isolate = CcTest::isolate();
    4891           6 :   v8::HandleScope handle_scope(isolate);
    4892          12 :   LocalContext context;
    4893             : 
    4894             :   ShouldInterceptData intercept_data;
    4895           6 :   intercept_data.value = 239;
    4896           6 :   intercept_data.should_intercept = true;
    4897             : 
    4898           6 :   auto interceptor_templ = v8::ObjectTemplate::New(isolate);
    4899             :   v8::NamedPropertyHandlerConfiguration conf(ShouldNamedInterceptor);
    4900           6 :   conf.flags = v8::PropertyHandlerFlags::kNonMasking;
    4901           6 :   conf.data = BuildWrappedObject<ShouldInterceptData>(isolate, &intercept_data);
    4902           6 :   interceptor_templ->SetHandler(conf);
    4903             : 
    4904             :   auto interceptor =
    4905           6 :       interceptor_templ->NewInstance(context.local()).ToLocalChecked();
    4906             :   context->Global()
    4907          24 :       ->Set(context.local(), v8_str("obj"), interceptor)
    4908          12 :       .FromJust();
    4909             : 
    4910           6 :   ExpectInt32("obj.whatever", 239);
    4911             : 
    4912             :   CompileRun("obj.whatever = 4;");
    4913             : 
    4914             :   // obj.whatever exists, thus it is not affected by the non-masking
    4915             :   // interceptor.
    4916           6 :   ExpectInt32("obj.whatever", 4);
    4917             : 
    4918             :   CompileRun("delete obj.whatever;");
    4919          12 :   ExpectInt32("obj.whatever", 239);
    4920           6 : }
    4921             : 
    4922             : 
    4923       25881 : THREADED_TEST(NonMaskingInterceptorPrototypeProperty) {
    4924           6 :   auto isolate = CcTest::isolate();
    4925           6 :   v8::HandleScope handle_scope(isolate);
    4926          12 :   LocalContext context;
    4927             : 
    4928             :   ShouldInterceptData intercept_data;
    4929           6 :   intercept_data.value = 239;
    4930           6 :   intercept_data.should_intercept = true;
    4931             : 
    4932           6 :   auto interceptor_templ = v8::ObjectTemplate::New(isolate);
    4933             :   v8::NamedPropertyHandlerConfiguration conf(ShouldNamedInterceptor);
    4934           6 :   conf.flags = v8::PropertyHandlerFlags::kNonMasking;
    4935           6 :   conf.data = BuildWrappedObject<ShouldInterceptData>(isolate, &intercept_data);
    4936           6 :   interceptor_templ->SetHandler(conf);
    4937             : 
    4938             :   auto interceptor =
    4939           6 :       interceptor_templ->NewInstance(context.local()).ToLocalChecked();
    4940             :   context->Global()
    4941          24 :       ->Set(context.local(), v8_str("obj"), interceptor)
    4942          12 :       .FromJust();
    4943             : 
    4944           6 :   ExpectInt32("obj.whatever", 239);
    4945             : 
    4946             :   CompileRun("obj.__proto__ = {'whatever': 4};");
    4947           6 :   ExpectInt32("obj.whatever", 4);
    4948             : 
    4949             :   CompileRun("delete obj.__proto__.whatever;");
    4950          12 :   ExpectInt32("obj.whatever", 239);
    4951           6 : }
    4952             : 
    4953             : 
    4954       25881 : THREADED_TEST(NonMaskingInterceptorPrototypePropertyIC) {
    4955           6 :   auto isolate = CcTest::isolate();
    4956           6 :   v8::HandleScope handle_scope(isolate);
    4957          12 :   LocalContext context;
    4958             : 
    4959             :   ShouldInterceptData intercept_data;
    4960           6 :   intercept_data.value = 239;
    4961           6 :   intercept_data.should_intercept = true;
    4962             : 
    4963           6 :   auto interceptor_templ = v8::ObjectTemplate::New(isolate);
    4964             :   v8::NamedPropertyHandlerConfiguration conf(ShouldNamedInterceptor);
    4965           6 :   conf.flags = v8::PropertyHandlerFlags::kNonMasking;
    4966           6 :   conf.data = BuildWrappedObject<ShouldInterceptData>(isolate, &intercept_data);
    4967           6 :   interceptor_templ->SetHandler(conf);
    4968             : 
    4969             :   auto interceptor =
    4970           6 :       interceptor_templ->NewInstance(context.local()).ToLocalChecked();
    4971             :   context->Global()
    4972          24 :       ->Set(context.local(), v8_str("obj"), interceptor)
    4973          12 :       .FromJust();
    4974             : 
    4975             :   CompileRun(
    4976             :       "outer = {};"
    4977             :       "outer.__proto__ = obj;"
    4978             :       "function f(obj) {"
    4979             :       "  var x;"
    4980             :       "  for (var i = 0; i < 4; i++) {"
    4981             :       "    x = obj.whatever;"
    4982             :       "  }"
    4983             :       "  return x;"
    4984             :       "}");
    4985             : 
    4986             :   // Receiver == holder.
    4987             :   CompileRun("obj.__proto__ = null;");
    4988           6 :   ExpectInt32("f(obj)", 239);
    4989           6 :   ExpectInt32("f(outer)", 239);
    4990             : 
    4991             :   // Receiver != holder.
    4992             :   CompileRun("Object.setPrototypeOf(obj, {});");
    4993           6 :   ExpectInt32("f(obj)", 239);
    4994           6 :   ExpectInt32("f(outer)", 239);
    4995             : 
    4996             :   // Masked value on prototype.
    4997             :   CompileRun("obj.__proto__.whatever = 4;");
    4998             :   CompileRun("obj.__proto__.__proto__ = { 'whatever' : 5 };");
    4999           6 :   ExpectInt32("f(obj)", 4);
    5000           6 :   ExpectInt32("f(outer)", 4);
    5001             : 
    5002             :   // Masked value on prototype prototype.
    5003             :   CompileRun("delete obj.__proto__.whatever;");
    5004           6 :   ExpectInt32("f(obj)", 5);
    5005           6 :   ExpectInt32("f(outer)", 5);
    5006             : 
    5007             :   // Reset.
    5008             :   CompileRun("delete obj.__proto__.__proto__.whatever;");
    5009           6 :   ExpectInt32("f(obj)", 239);
    5010           6 :   ExpectInt32("f(outer)", 239);
    5011             : 
    5012             :   // Masked value on self.
    5013             :   CompileRun("obj.whatever = 4;");
    5014           6 :   ExpectInt32("f(obj)", 4);
    5015           6 :   ExpectInt32("f(outer)", 4);
    5016             : 
    5017             :   // Reset.
    5018             :   CompileRun("delete obj.whatever;");
    5019           6 :   ExpectInt32("f(obj)", 239);
    5020           6 :   ExpectInt32("f(outer)", 239);
    5021             : 
    5022             :   CompileRun("outer.whatever = 4;");
    5023           6 :   ExpectInt32("f(obj)", 239);
    5024          12 :   ExpectInt32("f(outer)", 4);
    5025           6 : }
    5026             : 
    5027             : namespace {
    5028             : 
    5029         120 : void ConcatNamedPropertyGetter(
    5030             :     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
    5031             :   info.GetReturnValue().Set(
    5032             :       // Return the property name concatenated with itself.
    5033         120 :       String::Concat(info.GetIsolate(), name.As<String>(), name.As<String>()));
    5034         120 : }
    5035             : 
    5036         288 : void ConcatIndexedPropertyGetter(
    5037             :     uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) {
    5038             :   info.GetReturnValue().Set(
    5039             :       // Return the double value of the index.
    5040         288 :       v8_num(index + index));
    5041         288 : }
    5042             : 
    5043          96 : void EnumCallbackWithNames(const v8::PropertyCallbackInfo<v8::Array>& info) {
    5044          96 :   ApiTestFuzzer::Fuzz();
    5045          96 :   v8::Local<v8::Array> result = v8::Array::New(info.GetIsolate(), 4);
    5046          96 :   v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
    5047         384 :   CHECK(
    5048             :       result
    5049             :           ->Set(context, v8::Integer::New(info.GetIsolate(), 0), v8_str("foo"))
    5050             :           .FromJust());
    5051         384 :   CHECK(
    5052             :       result
    5053             :           ->Set(context, v8::Integer::New(info.GetIsolate(), 1), v8_str("bar"))
    5054             :           .FromJust());
    5055         384 :   CHECK(
    5056             :       result
    5057             :           ->Set(context, v8::Integer::New(info.GetIsolate(), 2), v8_str("baz"))
    5058             :           .FromJust());
    5059         384 :   CHECK(
    5060             :       result->Set(context, v8::Integer::New(info.GetIsolate(), 3), v8_str("10"))
    5061             :           .FromJust());
    5062             : 
    5063             :   //  Create a holey array.
    5064         288 :   CHECK(result->Delete(context, v8::Integer::New(info.GetIsolate(), 1))
    5065             :             .FromJust());
    5066             :   info.GetReturnValue().Set(result);
    5067          96 : }
    5068             : 
    5069          66 : void EnumCallbackWithIndices(const v8::PropertyCallbackInfo<v8::Array>& info) {
    5070          66 :   ApiTestFuzzer::Fuzz();
    5071          66 :   v8::Local<v8::Array> result = v8::Array::New(info.GetIsolate(), 4);
    5072          66 :   v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
    5073             : 
    5074         264 :   CHECK(result->Set(context, v8::Integer::New(info.GetIsolate(), 0), v8_num(10))
    5075             :             .FromJust());
    5076         264 :   CHECK(result->Set(context, v8::Integer::New(info.GetIsolate(), 1), v8_num(11))
    5077             :             .FromJust());
    5078         264 :   CHECK(result->Set(context, v8::Integer::New(info.GetIsolate(), 2), v8_num(12))
    5079             :             .FromJust());
    5080         264 :   CHECK(result->Set(context, v8::Integer::New(info.GetIsolate(), 3), v8_num(14))
    5081             :             .FromJust());
    5082             : 
    5083             :   //  Create a holey array.
    5084         198 :   CHECK(result->Delete(context, v8::Integer::New(info.GetIsolate(), 1))
    5085             :             .FromJust());
    5086             :   info.GetReturnValue().Set(result);
    5087          66 : }
    5088             : 
    5089         138 : void RestrictiveNamedQuery(Local<Name> property,
    5090             :                            const v8::PropertyCallbackInfo<v8::Integer>& info) {
    5091             :   // Only "foo" is enumerable.
    5092         138 :   if (v8_str("foo")
    5093         276 :           ->Equals(info.GetIsolate()->GetCurrentContext(), property)
    5094         276 :           .FromJust()) {
    5095             :     info.GetReturnValue().Set(v8::PropertyAttribute::None);
    5096         204 :     return;
    5097             :   }
    5098             :   info.GetReturnValue().Set(v8::PropertyAttribute::DontEnum);
    5099             : }
    5100             : 
    5101         312 : void RestrictiveIndexedQuery(
    5102             :     uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info) {
    5103             :   // Only index 2 and 12 are enumerable.
    5104         312 :   if (index == 2 || index == 12) {
    5105             :     info.GetReturnValue().Set(v8::PropertyAttribute::None);
    5106         408 :     return;
    5107             :   }
    5108             :   info.GetReturnValue().Set(v8::PropertyAttribute::DontEnum);
    5109             : }
    5110             : }  // namespace
    5111             : 
    5112             : // Regression test for V8 bug 6627.
    5113             : // Object.keys() must return enumerable keys only.
    5114       25881 : THREADED_TEST(EnumeratorsAndUnenumerableNamedProperties) {
    5115             :   // The enumerator interceptor returns a list
    5116             :   // of items which are filtered according to the
    5117             :   // properties defined in the query interceptor.
    5118           6 :   v8::Isolate* isolate = CcTest::isolate();
    5119           6 :   v8::HandleScope scope(isolate);
    5120           6 :   v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
    5121             :   obj->SetHandler(v8::NamedPropertyHandlerConfiguration(
    5122             :       ConcatNamedPropertyGetter, nullptr, RestrictiveNamedQuery, nullptr,
    5123           6 :       EnumCallbackWithNames));
    5124          12 :   LocalContext context;
    5125             :   context->Global()
    5126             :       ->Set(context.local(), v8_str("obj"),
    5127          30 :             obj->NewInstance(context.local()).ToLocalChecked())
    5128          12 :       .FromJust();
    5129             : 
    5130           6 :   ExpectInt32("Object.getOwnPropertyNames(obj).length", 3);
    5131           6 :   ExpectString("Object.getOwnPropertyNames(obj)[0]", "foo");
    5132           6 :   ExpectString("Object.getOwnPropertyNames(obj)[1]", "baz");
    5133           6 :   ExpectString("Object.getOwnPropertyNames(obj)[2]", "10");
    5134             : 
    5135             :   ExpectTrue("Object.getOwnPropertyDescriptor(obj, 'foo').enumerable");
    5136             :   ExpectFalse("Object.getOwnPropertyDescriptor(obj, 'baz').enumerable");
    5137             : 
    5138           6 :   ExpectInt32("Object.entries(obj).length", 1);
    5139           6 :   ExpectString("Object.entries(obj)[0][0]", "foo");
    5140           6 :   ExpectString("Object.entries(obj)[0][1]", "foofoo");
    5141             : 
    5142           6 :   ExpectInt32("Object.keys(obj).length", 1);
    5143           6 :   ExpectString("Object.keys(obj)[0]", "foo");
    5144             : 
    5145           6 :   ExpectInt32("Object.values(obj).length", 1);
    5146          12 :   ExpectString("Object.values(obj)[0]", "foofoo");
    5147           6 : }
    5148             : 
    5149             : namespace {
    5150          24 : void QueryInterceptorForFoo(Local<Name> property,
    5151             :                             const v8::PropertyCallbackInfo<v8::Integer>& info) {
    5152             :   // Don't intercept anything except "foo."
    5153          24 :   if (!v8_str("foo")
    5154          48 :            ->Equals(info.GetIsolate()->GetCurrentContext(), property)
    5155          48 :            .FromJust()) {
    5156          24 :     return;
    5157             :   }
    5158             :   // "foo" is enumerable.
    5159             :   info.GetReturnValue().Set(v8::PropertyAttribute::None);
    5160             : }
    5161             : }  // namespace
    5162             : 
    5163             : // Test that calls to the query interceptor are independent of each
    5164             : // other.
    5165       25881 : THREADED_TEST(EnumeratorsAndUnenumerableNamedPropertiesWithoutSet) {
    5166             :   // The enumerator interceptor returns a list
    5167             :   // of items which are filtered according to the
    5168             :   // properties defined in the query interceptor.
    5169           6 :   v8::Isolate* isolate = CcTest::isolate();
    5170           6 :   v8::HandleScope scope(isolate);
    5171           6 :   v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
    5172             :   obj->SetHandler(v8::NamedPropertyHandlerConfiguration(
    5173             :       ConcatNamedPropertyGetter, nullptr, QueryInterceptorForFoo, nullptr,
    5174           6 :       EnumCallbackWithNames));
    5175          12 :   LocalContext context;
    5176             :   context->Global()
    5177             :       ->Set(context.local(), v8_str("obj"),
    5178          30 :             obj->NewInstance(context.local()).ToLocalChecked())
    5179          12 :       .FromJust();
    5180             : 
    5181           6 :   ExpectInt32("Object.getOwnPropertyNames(obj).length", 3);
    5182           6 :   ExpectString("Object.getOwnPropertyNames(obj)[0]", "foo");
    5183           6 :   ExpectString("Object.getOwnPropertyNames(obj)[1]", "baz");
    5184           6 :   ExpectString("Object.getOwnPropertyNames(obj)[2]", "10");
    5185             : 
    5186             :   ExpectTrue("Object.getOwnPropertyDescriptor(obj, 'foo').enumerable");
    5187          12 :   ExpectInt32("Object.keys(obj).length", 1);
    5188           6 : }
    5189             : 
    5190       25881 : THREADED_TEST(EnumeratorsAndUnenumerableIndexedPropertiesArgumentsElements) {
    5191           6 :   v8::Isolate* isolate = CcTest::isolate();
    5192           6 :   v8::HandleScope scope(isolate);
    5193           6 :   v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
    5194             :   obj->SetHandler(v8::IndexedPropertyHandlerConfiguration(
    5195             :       ConcatIndexedPropertyGetter, nullptr, RestrictiveIndexedQuery, nullptr,
    5196           6 :       SloppyArgsIndexedPropertyEnumerator));
    5197          12 :   LocalContext context;
    5198             :   context->Global()
    5199             :       ->Set(context.local(), v8_str("obj"),
    5200          30 :             obj->NewInstance(context.local()).ToLocalChecked())
    5201          12 :       .FromJust();
    5202             : 
    5203           6 :   ExpectInt32("Object.getOwnPropertyNames(obj).length", 4);
    5204           6 :   ExpectString("Object.getOwnPropertyNames(obj)[0]", "0");
    5205           6 :   ExpectString("Object.getOwnPropertyNames(obj)[1]", "1");
    5206           6 :   ExpectString("Object.getOwnPropertyNames(obj)[2]", "2");
    5207           6 :   ExpectString("Object.getOwnPropertyNames(obj)[3]", "3");
    5208             : 
    5209             :   ExpectTrue("Object.getOwnPropertyDescriptor(obj, '2').enumerable");
    5210             : 
    5211           6 :   ExpectInt32("Object.entries(obj).length", 1);
    5212           6 :   ExpectString("Object.entries(obj)[0][0]", "2");
    5213           6 :   ExpectInt32("Object.entries(obj)[0][1]", 4);
    5214             : 
    5215           6 :   ExpectInt32("Object.keys(obj).length", 1);
    5216           6 :   ExpectString("Object.keys(obj)[0]", "2");
    5217             : 
    5218           6 :   ExpectInt32("Object.values(obj).length", 1);
    5219          12 :   ExpectInt32("Object.values(obj)[0]", 4);
    5220           6 : }
    5221             : 
    5222       25881 : THREADED_TEST(EnumeratorsAndUnenumerableIndexedProperties) {
    5223             :   // The enumerator interceptor returns a list
    5224             :   // of items which are filtered according to the
    5225             :   // properties defined in the query interceptor.
    5226           6 :   v8::Isolate* isolate = CcTest::isolate();
    5227           6 :   v8::HandleScope scope(isolate);
    5228           6 :   v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
    5229             :   obj->SetHandler(v8::IndexedPropertyHandlerConfiguration(
    5230             :       ConcatIndexedPropertyGetter, nullptr, RestrictiveIndexedQuery, nullptr,
    5231           6 :       EnumCallbackWithIndices));
    5232          12 :   LocalContext context;
    5233             :   context->Global()
    5234             :       ->Set(context.local(), v8_str("obj"),
    5235          30 :             obj->NewInstance(context.local()).ToLocalChecked())
    5236          12 :       .FromJust();
    5237             : 
    5238           6 :   ExpectInt32("Object.getOwnPropertyNames(obj).length", 3);
    5239           6 :   ExpectString("Object.getOwnPropertyNames(obj)[0]", "10");
    5240           6 :   ExpectString("Object.getOwnPropertyNames(obj)[1]", "12");
    5241           6 :   ExpectString("Object.getOwnPropertyNames(obj)[2]", "14");
    5242             : 
    5243             :   ExpectFalse("Object.getOwnPropertyDescriptor(obj, '10').enumerable");
    5244             :   ExpectTrue("Object.getOwnPropertyDescriptor(obj, '12').enumerable");
    5245             : 
    5246           6 :   ExpectInt32("Object.entries(obj).length", 1);
    5247           6 :   ExpectString("Object.entries(obj)[0][0]", "12");
    5248           6 :   ExpectInt32("Object.entries(obj)[0][1]", 24);
    5249             : 
    5250           6 :   ExpectInt32("Object.keys(obj).length", 1);
    5251           6 :   ExpectString("Object.keys(obj)[0]", "12");
    5252             : 
    5253           6 :   ExpectInt32("Object.values(obj).length", 1);
    5254          12 :   ExpectInt32("Object.values(obj)[0]", 24);
    5255           6 : }
    5256             : 
    5257       25881 : THREADED_TEST(EnumeratorsAndForIn) {
    5258           6 :   v8::Isolate* isolate = CcTest::isolate();
    5259           6 :   v8::HandleScope scope(isolate);
    5260           6 :   v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
    5261             :   obj->SetHandler(v8::NamedPropertyHandlerConfiguration(
    5262             :       ConcatNamedPropertyGetter, nullptr, RestrictiveNamedQuery, nullptr,
    5263           6 :       NamedEnum));
    5264          12 :   LocalContext context;
    5265             :   context->Global()
    5266             :       ->Set(context.local(), v8_str("obj"),
    5267          30 :             obj->NewInstance(context.local()).ToLocalChecked())
    5268          12 :       .FromJust();
    5269             : 
    5270           6 :   ExpectInt32("Object.getOwnPropertyNames(obj).length", 3);
    5271           6 :   ExpectString("Object.getOwnPropertyNames(obj)[0]", "foo");
    5272             : 
    5273             :   ExpectTrue("Object.getOwnPropertyDescriptor(obj, 'foo').enumerable");
    5274             : 
    5275             :   CompileRun(
    5276             :       "let concat = '';"
    5277             :       "for(var prop in obj) {"
    5278             :       "  concat += `key:${prop}:value:${obj[prop]}`;"
    5279             :       "}");
    5280             : 
    5281             :   // Check that for...in only iterates over enumerable properties.
    5282          12 :   ExpectString("concat", "key:foo:value:foofoo");
    5283           6 : }
    5284             : 
    5285             : namespace {
    5286             : 
    5287          24 : void DatabaseGetter(Local<Name> name,
    5288             :                     const v8::PropertyCallbackInfo<Value>& info) {
    5289          24 :   ApiTestFuzzer::Fuzz();
    5290          24 :   auto context = info.GetIsolate()->GetCurrentContext();
    5291             :   Local<v8::Object> db = info.Holder()
    5292          48 :                              ->GetRealNamedProperty(context, v8_str("db"))
    5293          24 :                              .ToLocalChecked()
    5294             :                              .As<v8::Object>();
    5295          48 :   if (!db->Has(context, name).FromJust()) return;
    5296          48 :   info.GetReturnValue().Set(db->Get(context, name).ToLocalChecked());
    5297             : }
    5298             : 
    5299             : 
    5300          24 : void DatabaseSetter(Local<Name> name, Local<Value> value,
    5301             :                     const v8::PropertyCallbackInfo<Value>& info) {
    5302          24 :   ApiTestFuzzer::Fuzz();
    5303          24 :   auto context = info.GetIsolate()->GetCurrentContext();
    5304          84 :   if (name->Equals(context, v8_str("db")).FromJust()) return;
    5305             :   Local<v8::Object> db = info.Holder()
    5306          24 :                              ->GetRealNamedProperty(context, v8_str("db"))
    5307          12 :                              .ToLocalChecked()
    5308             :                              .As<v8::Object>();
    5309          24 :   db->Set(context, name, value).FromJust();
    5310             :   info.GetReturnValue().Set(value);
    5311             : }
    5312             : 
    5313             : }  // namespace
    5314             : 
    5315             : 
    5316       25881 : THREADED_TEST(NonMaskingInterceptorGlobalEvalRegression) {
    5317           6 :   auto isolate = CcTest::isolate();
    5318           6 :   v8::HandleScope handle_scope(isolate);
    5319          12 :   LocalContext context;
    5320             : 
    5321           6 :   auto interceptor_templ = v8::ObjectTemplate::New(isolate);
    5322             :   v8::NamedPropertyHandlerConfiguration conf(DatabaseGetter, DatabaseSetter);
    5323           6 :   conf.flags = v8::PropertyHandlerFlags::kNonMasking;
    5324           6 :   interceptor_templ->SetHandler(conf);
    5325             : 
    5326             :   context->Global()
    5327             :       ->Set(context.local(), v8_str("intercepted_1"),
    5328          30 :             interceptor_templ->NewInstance(context.local()).ToLocalChecked())
    5329          12 :       .FromJust();
    5330             :   context->Global()
    5331             :       ->Set(context.local(), v8_str("intercepted_2"),
    5332          30 :             interceptor_templ->NewInstance(context.local()).ToLocalChecked())
    5333          12 :       .FromJust();
    5334             : 
    5335             :   // Init dbs.
    5336             :   CompileRun(
    5337             :       "intercepted_1.db = {};"
    5338             :       "intercepted_2.db = {};");
    5339             : 
    5340             :   ExpectInt32(
    5341             :       "var obj = intercepted_1;"
    5342             :       "obj.x = 4;"
    5343             :       "eval('obj.x');"
    5344             :       "eval('obj.x');"
    5345             :       "eval('obj.x');"
    5346             :       "obj = intercepted_2;"
    5347             :       "obj.x = 9;"
    5348             :       "eval('obj.x');",
    5349          12 :       9);
    5350           6 : }
    5351             : 
    5352          15 : static void CheckReceiver(Local<Name> name,
    5353             :                           const v8::PropertyCallbackInfo<v8::Value>& info) {
    5354          15 :   CHECK(info.This()->IsObject());
    5355          15 : }
    5356             : 
    5357       25880 : TEST(Regress609134Interceptor) {
    5358           5 :   LocalContext env;
    5359           5 :   v8::Isolate* isolate = env->GetIsolate();
    5360          10 :   v8::HandleScope scope(isolate);
    5361           5 :   auto fun_templ = v8::FunctionTemplate::New(isolate);
    5362             :   fun_templ->InstanceTemplate()->SetHandler(
    5363          10 :       v8::NamedPropertyHandlerConfiguration(CheckReceiver));
    5364             : 
    5365          30 :   CHECK(env->Global()
    5366             :             ->Set(env.local(), v8_str("Fun"),
    5367             :                   fun_templ->GetFunction(env.local()).ToLocalChecked())
    5368             :             .FromJust());
    5369             : 
    5370             :   CompileRun(
    5371             :       "var f = new Fun();"
    5372             :       "Number.prototype.__proto__ = f;"
    5373             :       "var a = 42;"
    5374           5 :       "for (var i = 0; i<3; i++) { a.foo; }");
    5375       77630 : }

Generated by: LCOV version 1.10