LCOV - code coverage report
Current view: top level - test/cctest - test-api-interceptors.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 2413 2423 99.6 %
Date: 2019-04-17 Functions: 262 265 98.9 %

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

Generated by: LCOV version 1.10