• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.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.h"
16 #include "src/parsing/parser.h"
17 #include "src/unicode-inl.h"
18 #include "src/utils.h"
19 #include "src/vm-state.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::UniqueId;
42 using ::v8::V8;
43 using ::v8::Value;
44 
45 
46 namespace {
47 
Returns42(const v8::FunctionCallbackInfo<v8::Value> & info)48 void Returns42(const v8::FunctionCallbackInfo<v8::Value>& info) {
49   info.GetReturnValue().Set(42);
50 }
51 
Return239Callback(Local<String> name,const v8::PropertyCallbackInfo<Value> & info)52 void Return239Callback(Local<String> name,
53                        const v8::PropertyCallbackInfo<Value>& info) {
54   ApiTestFuzzer::Fuzz();
55   CheckReturnValue(info, FUNCTION_ADDR(Return239Callback));
56   info.GetReturnValue().Set(v8_str("bad value"));
57   info.GetReturnValue().Set(v8_num(239));
58 }
59 
60 
EmptyInterceptorGetter(Local<Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)61 void EmptyInterceptorGetter(Local<Name> name,
62                             const v8::PropertyCallbackInfo<v8::Value>& info) {}
63 
64 
EmptyInterceptorSetter(Local<Name> name,Local<Value> value,const v8::PropertyCallbackInfo<v8::Value> & info)65 void EmptyInterceptorSetter(Local<Name> name, Local<Value> value,
66                             const v8::PropertyCallbackInfo<v8::Value>& info) {}
67 
68 
SimpleAccessorGetter(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)69 void SimpleAccessorGetter(Local<String> name,
70                           const v8::PropertyCallbackInfo<v8::Value>& info) {
71   Local<Object> self = Local<Object>::Cast(info.This());
72   info.GetReturnValue().Set(self->Get(info.GetIsolate()->GetCurrentContext(),
73                                       String::Concat(v8_str("accessor_"), name))
74                                 .ToLocalChecked());
75 }
76 
SimpleAccessorSetter(Local<String> name,Local<Value> value,const v8::PropertyCallbackInfo<void> & info)77 void SimpleAccessorSetter(Local<String> name, Local<Value> value,
78                           const v8::PropertyCallbackInfo<void>& info) {
79   Local<Object> self = Local<Object>::Cast(info.This());
80   self->Set(info.GetIsolate()->GetCurrentContext(),
81             String::Concat(v8_str("accessor_"), name), value)
82       .FromJust();
83 }
84 
85 
SymbolAccessorGetter(Local<Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)86 void SymbolAccessorGetter(Local<Name> name,
87                           const v8::PropertyCallbackInfo<v8::Value>& info) {
88   CHECK(name->IsSymbol());
89   Local<Symbol> sym = Local<Symbol>::Cast(name);
90   if (sym->Name()->IsUndefined()) return;
91   SimpleAccessorGetter(Local<String>::Cast(sym->Name()), info);
92 }
93 
SymbolAccessorSetter(Local<Name> name,Local<Value> value,const v8::PropertyCallbackInfo<void> & info)94 void SymbolAccessorSetter(Local<Name> name, Local<Value> value,
95                           const v8::PropertyCallbackInfo<void>& info) {
96   CHECK(name->IsSymbol());
97   Local<Symbol> sym = Local<Symbol>::Cast(name);
98   if (sym->Name()->IsUndefined()) return;
99   SimpleAccessorSetter(Local<String>::Cast(sym->Name()), value, info);
100 }
101 
StringInterceptorGetter(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)102 void StringInterceptorGetter(
103     Local<String> name,
104     const v8::PropertyCallbackInfo<v8::Value>&
105         info) {  // Intercept names that start with 'interceptor_'.
106   String::Utf8Value utf8(name);
107   char* name_str = *utf8;
108   char prefix[] = "interceptor_";
109   int i;
110   for (i = 0; name_str[i] && prefix[i]; ++i) {
111     if (name_str[i] != prefix[i]) return;
112   }
113   Local<Object> self = Local<Object>::Cast(info.This());
114   info.GetReturnValue().Set(
115       self->GetPrivate(
116               info.GetIsolate()->GetCurrentContext(),
117               v8::Private::ForApi(info.GetIsolate(), v8_str(name_str + i)))
118           .ToLocalChecked());
119 }
120 
121 
StringInterceptorSetter(Local<String> name,Local<Value> value,const v8::PropertyCallbackInfo<v8::Value> & info)122 void StringInterceptorSetter(Local<String> name, Local<Value> value,
123                              const v8::PropertyCallbackInfo<v8::Value>& info) {
124   // Intercept accesses that set certain integer values, for which the name does
125   // not start with 'accessor_'.
126   String::Utf8Value utf8(name);
127   char* name_str = *utf8;
128   char prefix[] = "accessor_";
129   int i;
130   for (i = 0; name_str[i] && prefix[i]; ++i) {
131     if (name_str[i] != prefix[i]) break;
132   }
133   if (!prefix[i]) return;
134 
135   Local<Context> context = info.GetIsolate()->GetCurrentContext();
136   if (value->IsInt32() && value->Int32Value(context).FromJust() < 10000) {
137     Local<Object> self = Local<Object>::Cast(info.This());
138     Local<v8::Private> symbol = v8::Private::ForApi(info.GetIsolate(), name);
139     self->SetPrivate(context, symbol, value).FromJust();
140     info.GetReturnValue().Set(value);
141   }
142 }
143 
InterceptorGetter(Local<Name> generic_name,const v8::PropertyCallbackInfo<v8::Value> & info)144 void InterceptorGetter(Local<Name> generic_name,
145                        const v8::PropertyCallbackInfo<v8::Value>& info) {
146   if (generic_name->IsSymbol()) return;
147   StringInterceptorGetter(Local<String>::Cast(generic_name), info);
148 }
149 
InterceptorSetter(Local<Name> generic_name,Local<Value> value,const v8::PropertyCallbackInfo<v8::Value> & info)150 void InterceptorSetter(Local<Name> generic_name, Local<Value> value,
151                        const v8::PropertyCallbackInfo<v8::Value>& info) {
152   if (generic_name->IsSymbol()) return;
153   StringInterceptorSetter(Local<String>::Cast(generic_name), value, info);
154 }
155 
GenericInterceptorGetter(Local<Name> generic_name,const v8::PropertyCallbackInfo<v8::Value> & info)156 void GenericInterceptorGetter(Local<Name> generic_name,
157                               const v8::PropertyCallbackInfo<v8::Value>& info) {
158   Local<String> str;
159   if (generic_name->IsSymbol()) {
160     Local<Value> name = Local<Symbol>::Cast(generic_name)->Name();
161     if (name->IsUndefined()) return;
162     str = String::Concat(v8_str("_sym_"), Local<String>::Cast(name));
163   } else {
164     Local<String> name = Local<String>::Cast(generic_name);
165     String::Utf8Value utf8(name);
166     char* name_str = *utf8;
167     if (*name_str == '_') return;
168     str = String::Concat(v8_str("_str_"), name);
169   }
170 
171   Local<Object> self = Local<Object>::Cast(info.This());
172   info.GetReturnValue().Set(
173       self->Get(info.GetIsolate()->GetCurrentContext(), str).ToLocalChecked());
174 }
175 
GenericInterceptorSetter(Local<Name> generic_name,Local<Value> value,const v8::PropertyCallbackInfo<v8::Value> & info)176 void GenericInterceptorSetter(Local<Name> generic_name, Local<Value> value,
177                               const v8::PropertyCallbackInfo<v8::Value>& info) {
178   Local<String> str;
179   if (generic_name->IsSymbol()) {
180     Local<Value> name = Local<Symbol>::Cast(generic_name)->Name();
181     if (name->IsUndefined()) return;
182     str = String::Concat(v8_str("_sym_"), Local<String>::Cast(name));
183   } else {
184     Local<String> name = Local<String>::Cast(generic_name);
185     String::Utf8Value utf8(name);
186     char* name_str = *utf8;
187     if (*name_str == '_') return;
188     str = String::Concat(v8_str("_str_"), name);
189   }
190 
191   Local<Object> self = Local<Object>::Cast(info.This());
192   self->Set(info.GetIsolate()->GetCurrentContext(), str, value).FromJust();
193   info.GetReturnValue().Set(value);
194 }
195 
AddAccessor(Local<FunctionTemplate> templ,Local<String> name,v8::AccessorGetterCallback getter,v8::AccessorSetterCallback setter)196 void AddAccessor(Local<FunctionTemplate> templ, Local<String> name,
197                  v8::AccessorGetterCallback getter,
198                  v8::AccessorSetterCallback setter) {
199   templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
200 }
201 
AddInterceptor(Local<FunctionTemplate> templ,v8::NamedPropertyGetterCallback getter,v8::NamedPropertySetterCallback setter)202 void AddInterceptor(Local<FunctionTemplate> templ,
203                     v8::NamedPropertyGetterCallback getter,
204                     v8::NamedPropertySetterCallback setter) {
205   templ->InstanceTemplate()->SetNamedPropertyHandler(getter, setter);
206 }
207 
208 
AddAccessor(Local<FunctionTemplate> templ,Local<Name> name,v8::AccessorNameGetterCallback getter,v8::AccessorNameSetterCallback setter)209 void AddAccessor(Local<FunctionTemplate> templ, Local<Name> name,
210                  v8::AccessorNameGetterCallback getter,
211                  v8::AccessorNameSetterCallback setter) {
212   templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
213 }
214 
AddInterceptor(Local<FunctionTemplate> templ,v8::GenericNamedPropertyGetterCallback getter,v8::GenericNamedPropertySetterCallback setter)215 void AddInterceptor(Local<FunctionTemplate> templ,
216                     v8::GenericNamedPropertyGetterCallback getter,
217                     v8::GenericNamedPropertySetterCallback setter) {
218   templ->InstanceTemplate()->SetHandler(
219       v8::NamedPropertyHandlerConfiguration(getter, setter));
220 }
221 
222 
223 v8::Local<v8::Object> bottom;
224 
CheckThisIndexedPropertyHandler(uint32_t index,const v8::PropertyCallbackInfo<v8::Value> & info)225 void CheckThisIndexedPropertyHandler(
226     uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) {
227   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyHandler));
228   ApiTestFuzzer::Fuzz();
229   CHECK(info.This()
230             ->Equals(info.GetIsolate()->GetCurrentContext(), bottom)
231             .FromJust());
232 }
233 
CheckThisNamedPropertyHandler(Local<Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)234 void CheckThisNamedPropertyHandler(
235     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
236   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyHandler));
237   ApiTestFuzzer::Fuzz();
238   CHECK(info.This()
239             ->Equals(info.GetIsolate()->GetCurrentContext(), bottom)
240             .FromJust());
241 }
242 
CheckThisIndexedPropertySetter(uint32_t index,Local<Value> value,const v8::PropertyCallbackInfo<v8::Value> & info)243 void CheckThisIndexedPropertySetter(
244     uint32_t index, Local<Value> value,
245     const v8::PropertyCallbackInfo<v8::Value>& info) {
246   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertySetter));
247   ApiTestFuzzer::Fuzz();
248   CHECK(info.This()
249             ->Equals(info.GetIsolate()->GetCurrentContext(), bottom)
250             .FromJust());
251 }
252 
253 
CheckThisNamedPropertySetter(Local<Name> property,Local<Value> value,const v8::PropertyCallbackInfo<v8::Value> & info)254 void CheckThisNamedPropertySetter(
255     Local<Name> property, Local<Value> value,
256     const v8::PropertyCallbackInfo<v8::Value>& info) {
257   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertySetter));
258   ApiTestFuzzer::Fuzz();
259   CHECK(info.This()
260             ->Equals(info.GetIsolate()->GetCurrentContext(), bottom)
261             .FromJust());
262 }
263 
CheckThisIndexedPropertyQuery(uint32_t index,const v8::PropertyCallbackInfo<v8::Integer> & info)264 void CheckThisIndexedPropertyQuery(
265     uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info) {
266   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyQuery));
267   ApiTestFuzzer::Fuzz();
268   CHECK(info.This()
269             ->Equals(info.GetIsolate()->GetCurrentContext(), bottom)
270             .FromJust());
271 }
272 
273 
CheckThisNamedPropertyQuery(Local<Name> property,const v8::PropertyCallbackInfo<v8::Integer> & info)274 void CheckThisNamedPropertyQuery(
275     Local<Name> property, const v8::PropertyCallbackInfo<v8::Integer>& info) {
276   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyQuery));
277   ApiTestFuzzer::Fuzz();
278   CHECK(info.This()
279             ->Equals(info.GetIsolate()->GetCurrentContext(), bottom)
280             .FromJust());
281 }
282 
283 
CheckThisIndexedPropertyDeleter(uint32_t index,const v8::PropertyCallbackInfo<v8::Boolean> & info)284 void CheckThisIndexedPropertyDeleter(
285     uint32_t index, const v8::PropertyCallbackInfo<v8::Boolean>& info) {
286   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyDeleter));
287   ApiTestFuzzer::Fuzz();
288   CHECK(info.This()
289             ->Equals(info.GetIsolate()->GetCurrentContext(), bottom)
290             .FromJust());
291 }
292 
293 
CheckThisNamedPropertyDeleter(Local<Name> property,const v8::PropertyCallbackInfo<v8::Boolean> & info)294 void CheckThisNamedPropertyDeleter(
295     Local<Name> property, const v8::PropertyCallbackInfo<v8::Boolean>& info) {
296   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyDeleter));
297   ApiTestFuzzer::Fuzz();
298   CHECK(info.This()
299             ->Equals(info.GetIsolate()->GetCurrentContext(), bottom)
300             .FromJust());
301 }
302 
303 
CheckThisIndexedPropertyEnumerator(const v8::PropertyCallbackInfo<v8::Array> & info)304 void CheckThisIndexedPropertyEnumerator(
305     const v8::PropertyCallbackInfo<v8::Array>& info) {
306   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyEnumerator));
307   ApiTestFuzzer::Fuzz();
308   CHECK(info.This()
309             ->Equals(info.GetIsolate()->GetCurrentContext(), bottom)
310             .FromJust());
311 }
312 
313 
CheckThisNamedPropertyEnumerator(const v8::PropertyCallbackInfo<v8::Array> & info)314 void CheckThisNamedPropertyEnumerator(
315     const v8::PropertyCallbackInfo<v8::Array>& info) {
316   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyEnumerator));
317   ApiTestFuzzer::Fuzz();
318   CHECK(info.This()
319             ->Equals(info.GetIsolate()->GetCurrentContext(), bottom)
320             .FromJust());
321 }
322 
323 
324 int echo_named_call_count;
325 
326 
EchoNamedProperty(Local<Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)327 void EchoNamedProperty(Local<Name> name,
328                        const v8::PropertyCallbackInfo<v8::Value>& info) {
329   ApiTestFuzzer::Fuzz();
330   CHECK(v8_str("data")
331             ->Equals(info.GetIsolate()->GetCurrentContext(), info.Data())
332             .FromJust());
333   echo_named_call_count++;
334   info.GetReturnValue().Set(name);
335 }
336 
InterceptorHasOwnPropertyGetter(Local<Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)337 void InterceptorHasOwnPropertyGetter(
338     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
339   ApiTestFuzzer::Fuzz();
340 }
341 
InterceptorHasOwnPropertyGetterGC(Local<Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)342 void InterceptorHasOwnPropertyGetterGC(
343     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
344   ApiTestFuzzer::Fuzz();
345   CcTest::heap()->CollectAllGarbage();
346 }
347 
348 }  // namespace
349 
350 
THREADED_TEST(InterceptorHasOwnProperty)351 THREADED_TEST(InterceptorHasOwnProperty) {
352   LocalContext context;
353   v8::Isolate* isolate = context->GetIsolate();
354   v8::HandleScope scope(isolate);
355   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
356   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
357   instance_templ->SetHandler(
358       v8::NamedPropertyHandlerConfiguration(InterceptorHasOwnPropertyGetter));
359   Local<Function> function =
360       fun_templ->GetFunction(context.local()).ToLocalChecked();
361   context->Global()
362       ->Set(context.local(), v8_str("constructor"), function)
363       .FromJust();
364   v8::Local<Value> value = CompileRun(
365       "var o = new constructor();"
366       "o.hasOwnProperty('ostehaps');");
367   CHECK_EQ(false, value->BooleanValue(context.local()).FromJust());
368   value = CompileRun(
369       "o.ostehaps = 42;"
370       "o.hasOwnProperty('ostehaps');");
371   CHECK_EQ(true, value->BooleanValue(context.local()).FromJust());
372   value = CompileRun(
373       "var p = new constructor();"
374       "p.hasOwnProperty('ostehaps');");
375   CHECK_EQ(false, value->BooleanValue(context.local()).FromJust());
376 }
377 
378 
THREADED_TEST(InterceptorHasOwnPropertyCausingGC)379 THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
380   LocalContext context;
381   v8::Isolate* isolate = context->GetIsolate();
382   v8::HandleScope scope(isolate);
383   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
384   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
385   instance_templ->SetHandler(
386       v8::NamedPropertyHandlerConfiguration(InterceptorHasOwnPropertyGetterGC));
387   Local<Function> function =
388       fun_templ->GetFunction(context.local()).ToLocalChecked();
389   context->Global()
390       ->Set(context.local(), v8_str("constructor"), function)
391       .FromJust();
392   // Let's first make some stuff so we can be sure to get a good GC.
393   CompileRun(
394       "function makestr(size) {"
395       "  switch (size) {"
396       "    case 1: return 'f';"
397       "    case 2: return 'fo';"
398       "    case 3: return 'foo';"
399       "  }"
400       "  return makestr(size >> 1) + makestr((size + 1) >> 1);"
401       "}"
402       "var x = makestr(12345);"
403       "x = makestr(31415);"
404       "x = makestr(23456);");
405   v8::Local<Value> value = CompileRun(
406       "var o = new constructor();"
407       "o.__proto__ = new String(x);"
408       "o.hasOwnProperty('ostehaps');");
409   CHECK_EQ(false, value->BooleanValue(context.local()).FromJust());
410 }
411 
412 
CheckInterceptorLoadIC(v8::GenericNamedPropertyGetterCallback getter,const char * source,int expected)413 static void CheckInterceptorLoadIC(
414     v8::GenericNamedPropertyGetterCallback getter, const char* source,
415     int expected) {
416   v8::Isolate* isolate = CcTest::isolate();
417   v8::HandleScope scope(isolate);
418   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
419   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(getter, 0, 0, 0, 0,
420                                                           v8_str("data")));
421   LocalContext context;
422   context->Global()
423       ->Set(context.local(), v8_str("o"),
424             templ->NewInstance(context.local()).ToLocalChecked())
425       .FromJust();
426   v8::Local<Value> value = CompileRun(source);
427   CHECK_EQ(expected, value->Int32Value(context.local()).FromJust());
428 }
429 
430 
InterceptorLoadICGetter(Local<Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)431 static void InterceptorLoadICGetter(
432     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
433   ApiTestFuzzer::Fuzz();
434   v8::Isolate* isolate = CcTest::isolate();
435   CHECK_EQ(isolate, info.GetIsolate());
436   v8::Local<v8::Context> context = isolate->GetCurrentContext();
437   CHECK(v8_str("data")->Equals(context, info.Data()).FromJust());
438   CHECK(v8_str("x")->Equals(context, name).FromJust());
439   info.GetReturnValue().Set(v8::Integer::New(isolate, 42));
440 }
441 
442 
443 // This test should hit the load IC for the interceptor case.
THREADED_TEST(InterceptorLoadIC)444 THREADED_TEST(InterceptorLoadIC) {
445   CheckInterceptorLoadIC(InterceptorLoadICGetter,
446                          "var result = 0;"
447                          "for (var i = 0; i < 1000; i++) {"
448                          "  result = o.x;"
449                          "}",
450                          42);
451 }
452 
453 
454 // Below go several tests which verify that JITing for various
455 // configurations of interceptor and explicit fields works fine
456 // (those cases are special cased to get better performance).
457 
InterceptorLoadXICGetter(Local<Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)458 static void InterceptorLoadXICGetter(
459     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
460   ApiTestFuzzer::Fuzz();
461   info.GetReturnValue().Set(
462       v8_str("x")
463               ->Equals(info.GetIsolate()->GetCurrentContext(), name)
464               .FromJust()
465           ? v8::Local<v8::Value>(v8::Integer::New(info.GetIsolate(), 42))
466           : v8::Local<v8::Value>());
467 }
468 
469 
THREADED_TEST(InterceptorLoadICWithFieldOnHolder)470 THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
471   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
472                          "var result = 0;"
473                          "o.y = 239;"
474                          "for (var i = 0; i < 1000; i++) {"
475                          "  result = o.y;"
476                          "}",
477                          239);
478 }
479 
480 
THREADED_TEST(InterceptorLoadICWithSubstitutedProto)481 THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
482   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
483                          "var result = 0;"
484                          "o.__proto__ = { 'y': 239 };"
485                          "for (var i = 0; i < 1000; i++) {"
486                          "  result = o.y + o.x;"
487                          "}",
488                          239 + 42);
489 }
490 
491 
THREADED_TEST(InterceptorLoadICWithPropertyOnProto)492 THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
493   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
494                          "var result = 0;"
495                          "o.__proto__.y = 239;"
496                          "for (var i = 0; i < 1000; i++) {"
497                          "  result = o.y + o.x;"
498                          "}",
499                          239 + 42);
500 }
501 
502 
THREADED_TEST(InterceptorLoadICUndefined)503 THREADED_TEST(InterceptorLoadICUndefined) {
504   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
505                          "var result = 0;"
506                          "for (var i = 0; i < 1000; i++) {"
507                          "  result = (o.y == undefined) ? 239 : 42;"
508                          "}",
509                          239);
510 }
511 
512 
THREADED_TEST(InterceptorLoadICWithOverride)513 THREADED_TEST(InterceptorLoadICWithOverride) {
514   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
515                          "fst = new Object();  fst.__proto__ = o;"
516                          "snd = new Object();  snd.__proto__ = fst;"
517                          "var result1 = 0;"
518                          "for (var i = 0; i < 1000;  i++) {"
519                          "  result1 = snd.x;"
520                          "}"
521                          "fst.x = 239;"
522                          "var result = 0;"
523                          "for (var i = 0; i < 1000; i++) {"
524                          "  result = snd.x;"
525                          "}"
526                          "result + result1",
527                          239 + 42);
528 }
529 
530 
531 // Test the case when we stored field into
532 // a stub, but interceptor produced value on its own.
THREADED_TEST(InterceptorLoadICFieldNotNeeded)533 THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
534   CheckInterceptorLoadIC(
535       InterceptorLoadXICGetter,
536       "proto = new Object();"
537       "o.__proto__ = proto;"
538       "proto.x = 239;"
539       "for (var i = 0; i < 1000; i++) {"
540       "  o.x;"
541       // Now it should be ICed and keep a reference to x defined on proto
542       "}"
543       "var result = 0;"
544       "for (var i = 0; i < 1000; i++) {"
545       "  result += o.x;"
546       "}"
547       "result;",
548       42 * 1000);
549 }
550 
551 
552 // Test the case when we stored field into
553 // a stub, but it got invalidated later on.
THREADED_TEST(InterceptorLoadICInvalidatedField)554 THREADED_TEST(InterceptorLoadICInvalidatedField) {
555   CheckInterceptorLoadIC(
556       InterceptorLoadXICGetter,
557       "proto1 = new Object();"
558       "proto2 = new Object();"
559       "o.__proto__ = proto1;"
560       "proto1.__proto__ = proto2;"
561       "proto2.y = 239;"
562       "for (var i = 0; i < 1000; i++) {"
563       "  o.y;"
564       // Now it should be ICed and keep a reference to y defined on proto2
565       "}"
566       "proto1.y = 42;"
567       "var result = 0;"
568       "for (var i = 0; i < 1000; i++) {"
569       "  result += o.y;"
570       "}"
571       "result;",
572       42 * 1000);
573 }
574 
575 
576 static int interceptor_load_not_handled_calls = 0;
InterceptorLoadNotHandled(Local<Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)577 static void InterceptorLoadNotHandled(
578     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
579   ++interceptor_load_not_handled_calls;
580 }
581 
582 
583 // Test how post-interceptor lookups are done in the non-cacheable
584 // case: the interceptor should not be invoked during this lookup.
THREADED_TEST(InterceptorLoadICPostInterceptor)585 THREADED_TEST(InterceptorLoadICPostInterceptor) {
586   interceptor_load_not_handled_calls = 0;
587   CheckInterceptorLoadIC(InterceptorLoadNotHandled,
588                          "receiver = new Object();"
589                          "receiver.__proto__ = o;"
590                          "proto = new Object();"
591                          "/* Make proto a slow-case object. */"
592                          "for (var i = 0; i < 1000; i++) {"
593                          "  proto[\"xxxxxxxx\" + i] = [];"
594                          "}"
595                          "proto.x = 17;"
596                          "o.__proto__ = proto;"
597                          "var result = 0;"
598                          "for (var i = 0; i < 1000; i++) {"
599                          "  result += receiver.x;"
600                          "}"
601                          "result;",
602                          17 * 1000);
603   CHECK_EQ(1000, interceptor_load_not_handled_calls);
604 }
605 
606 
607 // Test the case when we stored field into
608 // a stub, but it got invalidated later on due to override on
609 // global object which is between interceptor and fields' holders.
THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal)610 THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
611   CheckInterceptorLoadIC(
612       InterceptorLoadXICGetter,
613       "o.__proto__ = this;"  // set a global to be a proto of o.
614       "this.__proto__.y = 239;"
615       "for (var i = 0; i < 10; i++) {"
616       "  if (o.y != 239) throw 'oops: ' + o.y;"
617       // Now it should be ICed and keep a reference to y defined on
618       // field_holder.
619       "}"
620       "this.y = 42;"  // Assign on a global.
621       "var result = 0;"
622       "for (var i = 0; i < 10; i++) {"
623       "  result += o.y;"
624       "}"
625       "result;",
626       42 * 10);
627 }
628 
629 
SetOnThis(Local<String> name,Local<Value> value,const v8::PropertyCallbackInfo<void> & info)630 static void SetOnThis(Local<String> name, Local<Value> value,
631                       const v8::PropertyCallbackInfo<void>& info) {
632   Local<Object>::Cast(info.This())
633       ->CreateDataProperty(info.GetIsolate()->GetCurrentContext(), name, value)
634       .FromJust();
635 }
636 
637 
THREADED_TEST(InterceptorLoadICWithCallbackOnHolder)638 THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
639   v8::Isolate* isolate = CcTest::isolate();
640   v8::HandleScope scope(isolate);
641   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
642   templ->SetHandler(
643       v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
644   templ->SetAccessor(v8_str("y"), Return239Callback);
645   LocalContext context;
646   context->Global()
647       ->Set(context.local(), v8_str("o"),
648             templ->NewInstance(context.local()).ToLocalChecked())
649       .FromJust();
650 
651   // Check the case when receiver and interceptor's holder
652   // are the same objects.
653   v8::Local<Value> value = CompileRun(
654       "var result = 0;"
655       "for (var i = 0; i < 7; i++) {"
656       "  result = o.y;"
657       "}");
658   CHECK_EQ(239, value->Int32Value(context.local()).FromJust());
659 
660   // Check the case when interceptor's holder is in proto chain
661   // of receiver.
662   value = CompileRun(
663       "r = { __proto__: o };"
664       "var result = 0;"
665       "for (var i = 0; i < 7; i++) {"
666       "  result = r.y;"
667       "}");
668   CHECK_EQ(239, value->Int32Value(context.local()).FromJust());
669 }
670 
671 
THREADED_TEST(InterceptorLoadICWithCallbackOnProto)672 THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
673   v8::Isolate* isolate = CcTest::isolate();
674   v8::HandleScope scope(isolate);
675   v8::Local<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
676   templ_o->SetHandler(
677       v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
678   v8::Local<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
679   templ_p->SetAccessor(v8_str("y"), Return239Callback);
680 
681   LocalContext context;
682   context->Global()
683       ->Set(context.local(), v8_str("o"),
684             templ_o->NewInstance(context.local()).ToLocalChecked())
685       .FromJust();
686   context->Global()
687       ->Set(context.local(), v8_str("p"),
688             templ_p->NewInstance(context.local()).ToLocalChecked())
689       .FromJust();
690 
691   // Check the case when receiver and interceptor's holder
692   // are the same objects.
693   v8::Local<Value> value = CompileRun(
694       "o.__proto__ = p;"
695       "var result = 0;"
696       "for (var i = 0; i < 7; i++) {"
697       "  result = o.x + o.y;"
698       "}");
699   CHECK_EQ(239 + 42, value->Int32Value(context.local()).FromJust());
700 
701   // Check the case when interceptor's holder is in proto chain
702   // of receiver.
703   value = CompileRun(
704       "r = { __proto__: o };"
705       "var result = 0;"
706       "for (var i = 0; i < 7; i++) {"
707       "  result = r.x + r.y;"
708       "}");
709   CHECK_EQ(239 + 42, value->Int32Value(context.local()).FromJust());
710 }
711 
712 
THREADED_TEST(InterceptorLoadICForCallbackWithOverride)713 THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
714   v8::Isolate* isolate = CcTest::isolate();
715   v8::HandleScope scope(isolate);
716   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
717   templ->SetHandler(
718       v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
719   templ->SetAccessor(v8_str("y"), Return239Callback);
720 
721   LocalContext context;
722   context->Global()
723       ->Set(context.local(), v8_str("o"),
724             templ->NewInstance(context.local()).ToLocalChecked())
725       .FromJust();
726 
727   v8::Local<Value> value = CompileRun(
728       "fst = new Object();  fst.__proto__ = o;"
729       "snd = new Object();  snd.__proto__ = fst;"
730       "var result1 = 0;"
731       "for (var i = 0; i < 7;  i++) {"
732       "  result1 = snd.x;"
733       "}"
734       "fst.x = 239;"
735       "var result = 0;"
736       "for (var i = 0; i < 7; i++) {"
737       "  result = snd.x;"
738       "}"
739       "result + result1");
740   CHECK_EQ(239 + 42, value->Int32Value(context.local()).FromJust());
741 }
742 
743 
744 // Test the case when we stored callback into
745 // a stub, but interceptor produced value on its own.
THREADED_TEST(InterceptorLoadICCallbackNotNeeded)746 THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
747   v8::Isolate* isolate = CcTest::isolate();
748   v8::HandleScope scope(isolate);
749   v8::Local<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
750   templ_o->SetHandler(
751       v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
752   v8::Local<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
753   templ_p->SetAccessor(v8_str("y"), Return239Callback);
754 
755   LocalContext context;
756   context->Global()
757       ->Set(context.local(), v8_str("o"),
758             templ_o->NewInstance(context.local()).ToLocalChecked())
759       .FromJust();
760   context->Global()
761       ->Set(context.local(), v8_str("p"),
762             templ_p->NewInstance(context.local()).ToLocalChecked())
763       .FromJust();
764 
765   v8::Local<Value> value = CompileRun(
766       "o.__proto__ = p;"
767       "for (var i = 0; i < 7; i++) {"
768       "  o.x;"
769       // Now it should be ICed and keep a reference to x defined on p
770       "}"
771       "var result = 0;"
772       "for (var i = 0; i < 7; i++) {"
773       "  result += o.x;"
774       "}"
775       "result");
776   CHECK_EQ(42 * 7, value->Int32Value(context.local()).FromJust());
777 }
778 
779 
780 // Test the case when we stored callback into
781 // a stub, but it got invalidated later on.
THREADED_TEST(InterceptorLoadICInvalidatedCallback)782 THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
783   v8::Isolate* isolate = CcTest::isolate();
784   v8::HandleScope scope(isolate);
785   v8::Local<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
786   templ_o->SetHandler(
787       v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
788   v8::Local<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
789   templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
790 
791   LocalContext context;
792   context->Global()
793       ->Set(context.local(), v8_str("o"),
794             templ_o->NewInstance(context.local()).ToLocalChecked())
795       .FromJust();
796   context->Global()
797       ->Set(context.local(), v8_str("p"),
798             templ_p->NewInstance(context.local()).ToLocalChecked())
799       .FromJust();
800 
801   v8::Local<Value> value = CompileRun(
802       "inbetween = new Object();"
803       "o.__proto__ = inbetween;"
804       "inbetween.__proto__ = p;"
805       "for (var i = 0; i < 10; i++) {"
806       "  o.y;"
807       // Now it should be ICed and keep a reference to y defined on p
808       "}"
809       "inbetween.y = 42;"
810       "var result = 0;"
811       "for (var i = 0; i < 10; i++) {"
812       "  result += o.y;"
813       "}"
814       "result");
815   CHECK_EQ(42 * 10, value->Int32Value(context.local()).FromJust());
816 }
817 
818 
819 // Test the case when we stored callback into
820 // a stub, but it got invalidated later on due to override on
821 // global object which is between interceptor and callbacks' holders.
THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal)822 THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
823   v8::Isolate* isolate = CcTest::isolate();
824   v8::HandleScope scope(isolate);
825   v8::Local<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
826   templ_o->SetHandler(
827       v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
828   v8::Local<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
829   templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
830 
831   LocalContext context;
832   context->Global()
833       ->Set(context.local(), v8_str("o"),
834             templ_o->NewInstance(context.local()).ToLocalChecked())
835       .FromJust();
836   context->Global()
837       ->Set(context.local(), v8_str("p"),
838             templ_p->NewInstance(context.local()).ToLocalChecked())
839       .FromJust();
840 
841   v8::Local<Value> value = CompileRun(
842       "o.__proto__ = this;"
843       "this.__proto__ = p;"
844       "for (var i = 0; i < 10; i++) {"
845       "  if (o.y != 239) throw 'oops: ' + o.y;"
846       // Now it should be ICed and keep a reference to y defined on p
847       "}"
848       "this.y = 42;"
849       "var result = 0;"
850       "for (var i = 0; i < 10; i++) {"
851       "  result += o.y;"
852       "}"
853       "result");
854   CHECK_EQ(42 * 10, value->Int32Value(context.local()).FromJust());
855 }
856 
857 // Test load of a non-existing global when a global object has an interceptor.
THREADED_TEST(InterceptorLoadGlobalICGlobalWithInterceptor)858 THREADED_TEST(InterceptorLoadGlobalICGlobalWithInterceptor) {
859   v8::Isolate* isolate = CcTest::isolate();
860   v8::HandleScope scope(isolate);
861   v8::Local<v8::ObjectTemplate> templ_global = v8::ObjectTemplate::New(isolate);
862   templ_global->SetHandler(v8::NamedPropertyHandlerConfiguration(
863       EmptyInterceptorGetter, EmptyInterceptorSetter));
864 
865   LocalContext context(nullptr, templ_global);
866   i::Handle<i::JSReceiver> global_proxy =
867       v8::Utils::OpenHandle<Object, i::JSReceiver>(context->Global());
868   CHECK(global_proxy->IsJSGlobalProxy());
869   i::Handle<i::JSGlobalObject> global(
870       i::JSGlobalObject::cast(global_proxy->map()->prototype()));
871   CHECK(global->map()->has_named_interceptor());
872 
873   v8::Local<Value> value = CompileRun(
874       "var f = function() { "
875       "  try {"
876       "    x1;"
877       "  } catch(e) {"
878       "  }"
879       "  return typeof x1 === 'undefined';"
880       "};"
881       "for (var i = 0; i < 10; i++) {"
882       "  f();"
883       "};"
884       "f();");
885   CHECK_EQ(true, value->BooleanValue(context.local()).FromJust());
886 
887   value = CompileRun(
888       "var f = function() { "
889       "  try {"
890       "    x2;"
891       "    return false;"
892       "  } catch(e) {"
893       "    return true;"
894       "  }"
895       "};"
896       "for (var i = 0; i < 10; i++) {"
897       "  f();"
898       "};"
899       "f();");
900   CHECK_EQ(true, value->BooleanValue(context.local()).FromJust());
901 
902   value = CompileRun(
903       "var f = function() { "
904       "  try {"
905       "    typeof(x3);"
906       "    return true;"
907       "  } catch(e) {"
908       "    return false;"
909       "  }"
910       "};"
911       "for (var i = 0; i < 10; i++) {"
912       "  f();"
913       "};"
914       "f();");
915   CHECK_EQ(true, value->BooleanValue(context.local()).FromJust());
916 }
917 
InterceptorLoadICGetter0(Local<Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)918 static void InterceptorLoadICGetter0(
919     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
920   ApiTestFuzzer::Fuzz();
921   CHECK(v8_str("x")
922             ->Equals(info.GetIsolate()->GetCurrentContext(), name)
923             .FromJust());
924   info.GetReturnValue().Set(v8::Integer::New(info.GetIsolate(), 0));
925 }
926 
927 
THREADED_TEST(InterceptorReturningZero)928 THREADED_TEST(InterceptorReturningZero) {
929   CheckInterceptorLoadIC(InterceptorLoadICGetter0, "o.x == undefined ? 1 : 0",
930                          0);
931 }
932 
933 
InterceptorStoreICSetter(Local<Name> key,Local<Value> value,const v8::PropertyCallbackInfo<v8::Value> & info)934 static void InterceptorStoreICSetter(
935     Local<Name> key, Local<Value> value,
936     const v8::PropertyCallbackInfo<v8::Value>& info) {
937   v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
938   CHECK(v8_str("x")->Equals(context, key).FromJust());
939   CHECK_EQ(42, value->Int32Value(context).FromJust());
940   info.GetReturnValue().Set(value);
941 }
942 
943 
944 // This test should hit the store IC for the interceptor case.
THREADED_TEST(InterceptorStoreIC)945 THREADED_TEST(InterceptorStoreIC) {
946   v8::Isolate* isolate = CcTest::isolate();
947   v8::HandleScope scope(isolate);
948   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
949   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
950       InterceptorLoadICGetter, InterceptorStoreICSetter, 0, 0, 0,
951       v8_str("data")));
952   LocalContext context;
953   context->Global()
954       ->Set(context.local(), v8_str("o"),
955             templ->NewInstance(context.local()).ToLocalChecked())
956       .FromJust();
957   CompileRun(
958       "for (var i = 0; i < 1000; i++) {"
959       "  o.x = 42;"
960       "}");
961 }
962 
963 
THREADED_TEST(InterceptorStoreICWithNoSetter)964 THREADED_TEST(InterceptorStoreICWithNoSetter) {
965   v8::Isolate* isolate = CcTest::isolate();
966   v8::HandleScope scope(isolate);
967   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
968   templ->SetHandler(
969       v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
970   LocalContext context;
971   context->Global()
972       ->Set(context.local(), v8_str("o"),
973             templ->NewInstance(context.local()).ToLocalChecked())
974       .FromJust();
975   v8::Local<Value> value = CompileRun(
976       "for (var i = 0; i < 1000; i++) {"
977       "  o.y = 239;"
978       "}"
979       "42 + o.y");
980   CHECK_EQ(239 + 42, value->Int32Value(context.local()).FromJust());
981 }
982 
983 
THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors)984 THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
985   v8::HandleScope scope(CcTest::isolate());
986   Local<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
987   Local<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
988   child->Inherit(parent);
989   AddAccessor(parent, v8_str("age"), SimpleAccessorGetter,
990               SimpleAccessorSetter);
991   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
992   LocalContext env;
993   env->Global()
994       ->Set(env.local(), v8_str("Child"),
995             child->GetFunction(env.local()).ToLocalChecked())
996       .FromJust();
997   CompileRun(
998       "var child = new Child;"
999       "child.age = 10;");
1000   ExpectBoolean("child.hasOwnProperty('age')", false);
1001   ExpectInt32("child.age", 10);
1002   ExpectInt32("child.accessor_age", 10);
1003 }
1004 
1005 
THREADED_TEST(LegacyInterceptorDoesNotSeeSymbols)1006 THREADED_TEST(LegacyInterceptorDoesNotSeeSymbols) {
1007   LocalContext env;
1008   v8::Isolate* isolate = CcTest::isolate();
1009   v8::HandleScope scope(isolate);
1010   Local<FunctionTemplate> parent = FunctionTemplate::New(isolate);
1011   Local<FunctionTemplate> child = FunctionTemplate::New(isolate);
1012   v8::Local<v8::Symbol> age = v8::Symbol::New(isolate, v8_str("age"));
1013 
1014   child->Inherit(parent);
1015   AddAccessor(parent, age, SymbolAccessorGetter, SymbolAccessorSetter);
1016   AddInterceptor(child, StringInterceptorGetter, StringInterceptorSetter);
1017 
1018   env->Global()
1019       ->Set(env.local(), v8_str("Child"),
1020             child->GetFunction(env.local()).ToLocalChecked())
1021       .FromJust();
1022   env->Global()->Set(env.local(), v8_str("age"), age).FromJust();
1023   CompileRun(
1024       "var child = new Child;"
1025       "child[age] = 10;");
1026   ExpectInt32("child[age]", 10);
1027   ExpectBoolean("child.hasOwnProperty('age')", false);
1028   ExpectBoolean("child.hasOwnProperty('accessor_age')", true);
1029 }
1030 
1031 
THREADED_TEST(GenericInterceptorDoesSeeSymbols)1032 THREADED_TEST(GenericInterceptorDoesSeeSymbols) {
1033   LocalContext env;
1034   v8::Isolate* isolate = CcTest::isolate();
1035   v8::HandleScope scope(isolate);
1036   Local<FunctionTemplate> parent = FunctionTemplate::New(isolate);
1037   Local<FunctionTemplate> child = FunctionTemplate::New(isolate);
1038   v8::Local<v8::Symbol> age = v8::Symbol::New(isolate, v8_str("age"));
1039   v8::Local<v8::Symbol> anon = v8::Symbol::New(isolate);
1040 
1041   child->Inherit(parent);
1042   AddAccessor(parent, age, SymbolAccessorGetter, SymbolAccessorSetter);
1043   AddInterceptor(child, GenericInterceptorGetter, GenericInterceptorSetter);
1044 
1045   env->Global()
1046       ->Set(env.local(), v8_str("Child"),
1047             child->GetFunction(env.local()).ToLocalChecked())
1048       .FromJust();
1049   env->Global()->Set(env.local(), v8_str("age"), age).FromJust();
1050   env->Global()->Set(env.local(), v8_str("anon"), anon).FromJust();
1051   CompileRun(
1052       "var child = new Child;"
1053       "child[age] = 10;");
1054   ExpectInt32("child[age]", 10);
1055   ExpectInt32("child._sym_age", 10);
1056 
1057   // Check that it also sees strings.
1058   CompileRun("child.foo = 47");
1059   ExpectInt32("child.foo", 47);
1060   ExpectInt32("child._str_foo", 47);
1061 
1062   // Check that the interceptor can punt (in this case, on anonymous symbols).
1063   CompileRun("child[anon] = 31337");
1064   ExpectInt32("child[anon]", 31337);
1065 }
1066 
1067 
THREADED_TEST(NamedPropertyHandlerGetter)1068 THREADED_TEST(NamedPropertyHandlerGetter) {
1069   echo_named_call_count = 0;
1070   v8::HandleScope scope(CcTest::isolate());
1071   v8::Local<v8::FunctionTemplate> templ =
1072       v8::FunctionTemplate::New(CcTest::isolate());
1073   templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
1074       EchoNamedProperty, 0, 0, 0, 0, v8_str("data")));
1075   LocalContext env;
1076   env->Global()
1077       ->Set(env.local(), v8_str("obj"), templ->GetFunction(env.local())
1078                                             .ToLocalChecked()
1079                                             ->NewInstance(env.local())
1080                                             .ToLocalChecked())
1081       .FromJust();
1082   CHECK_EQ(echo_named_call_count, 0);
1083   v8_compile("obj.x")->Run(env.local()).ToLocalChecked();
1084   CHECK_EQ(echo_named_call_count, 1);
1085   const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
1086   v8::Local<Value> str = CompileRun(code);
1087   String::Utf8Value value(str);
1088   CHECK_EQ(0, strcmp(*value, "oddlepoddle"));
1089   // Check default behavior
1090   CHECK_EQ(10, v8_compile("obj.flob = 10;")
1091                    ->Run(env.local())
1092                    .ToLocalChecked()
1093                    ->Int32Value(env.local())
1094                    .FromJust());
1095   CHECK(v8_compile("'myProperty' in obj")
1096             ->Run(env.local())
1097             .ToLocalChecked()
1098             ->BooleanValue(env.local())
1099             .FromJust());
1100   CHECK(v8_compile("delete obj.myProperty")
1101             ->Run(env.local())
1102             .ToLocalChecked()
1103             ->BooleanValue(env.local())
1104             .FromJust());
1105 }
1106 
1107 
1108 int echo_indexed_call_count = 0;
1109 
1110 
EchoIndexedProperty(uint32_t index,const v8::PropertyCallbackInfo<v8::Value> & info)1111 static void EchoIndexedProperty(
1112     uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) {
1113   ApiTestFuzzer::Fuzz();
1114   CHECK(v8_num(637)
1115             ->Equals(info.GetIsolate()->GetCurrentContext(), info.Data())
1116             .FromJust());
1117   echo_indexed_call_count++;
1118   info.GetReturnValue().Set(v8_num(index));
1119 }
1120 
1121 
THREADED_TEST(IndexedPropertyHandlerGetter)1122 THREADED_TEST(IndexedPropertyHandlerGetter) {
1123   v8::Isolate* isolate = CcTest::isolate();
1124   v8::HandleScope scope(isolate);
1125   v8::Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
1126   templ->InstanceTemplate()->SetHandler(v8::IndexedPropertyHandlerConfiguration(
1127       EchoIndexedProperty, 0, 0, 0, 0, v8_num(637)));
1128   LocalContext env;
1129   env->Global()
1130       ->Set(env.local(), v8_str("obj"), templ->GetFunction(env.local())
1131                                             .ToLocalChecked()
1132                                             ->NewInstance(env.local())
1133                                             .ToLocalChecked())
1134       .FromJust();
1135   Local<Script> script = v8_compile("obj[900]");
1136   CHECK_EQ(script->Run(env.local())
1137                .ToLocalChecked()
1138                ->Int32Value(env.local())
1139                .FromJust(),
1140            900);
1141 }
1142 
1143 
THREADED_TEST(PropertyHandlerInPrototype)1144 THREADED_TEST(PropertyHandlerInPrototype) {
1145   LocalContext env;
1146   v8::Isolate* isolate = env->GetIsolate();
1147   v8::HandleScope scope(isolate);
1148 
1149   // Set up a prototype chain with three interceptors.
1150   v8::Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
1151   templ->InstanceTemplate()->SetHandler(v8::IndexedPropertyHandlerConfiguration(
1152       CheckThisIndexedPropertyHandler, CheckThisIndexedPropertySetter,
1153       CheckThisIndexedPropertyQuery, CheckThisIndexedPropertyDeleter,
1154       CheckThisIndexedPropertyEnumerator));
1155 
1156   templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
1157       CheckThisNamedPropertyHandler, CheckThisNamedPropertySetter,
1158       CheckThisNamedPropertyQuery, CheckThisNamedPropertyDeleter,
1159       CheckThisNamedPropertyEnumerator));
1160 
1161   bottom = templ->GetFunction(env.local())
1162                .ToLocalChecked()
1163                ->NewInstance(env.local())
1164                .ToLocalChecked();
1165   Local<v8::Object> top = templ->GetFunction(env.local())
1166                               .ToLocalChecked()
1167                               ->NewInstance(env.local())
1168                               .ToLocalChecked();
1169   Local<v8::Object> middle = templ->GetFunction(env.local())
1170                                  .ToLocalChecked()
1171                                  ->NewInstance(env.local())
1172                                  .ToLocalChecked();
1173 
1174   bottom->SetPrototype(env.local(), middle).FromJust();
1175   middle->SetPrototype(env.local(), top).FromJust();
1176   env->Global()->Set(env.local(), v8_str("obj"), bottom).FromJust();
1177 
1178   // Indexed and named get.
1179   CompileRun("obj[0]");
1180   CompileRun("obj.x");
1181 
1182   // Indexed and named set.
1183   CompileRun("obj[1] = 42");
1184   CompileRun("obj.y = 42");
1185 
1186   // Indexed and named query.
1187   CompileRun("0 in obj");
1188   CompileRun("'x' in obj");
1189 
1190   // Indexed and named deleter.
1191   CompileRun("delete obj[0]");
1192   CompileRun("delete obj.x");
1193 
1194   // Enumerators.
1195   CompileRun("for (var p in obj) ;");
1196 }
1197 
1198 
1199 bool is_bootstrapping = false;
PrePropertyHandlerGet(Local<Name> key,const v8::PropertyCallbackInfo<v8::Value> & info)1200 static void PrePropertyHandlerGet(
1201     Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>& info) {
1202   ApiTestFuzzer::Fuzz();
1203   if (!is_bootstrapping &&
1204       v8_str("pre")
1205           ->Equals(info.GetIsolate()->GetCurrentContext(), key)
1206           .FromJust()) {
1207     info.GetReturnValue().Set(v8_str("PrePropertyHandler: pre"));
1208   }
1209 }
1210 
1211 
PrePropertyHandlerQuery(Local<Name> key,const v8::PropertyCallbackInfo<v8::Integer> & info)1212 static void PrePropertyHandlerQuery(
1213     Local<Name> key, const v8::PropertyCallbackInfo<v8::Integer>& info) {
1214   if (!is_bootstrapping &&
1215       v8_str("pre")
1216           ->Equals(info.GetIsolate()->GetCurrentContext(), key)
1217           .FromJust()) {
1218     info.GetReturnValue().Set(static_cast<int32_t>(v8::None));
1219   }
1220 }
1221 
1222 
THREADED_TEST(PrePropertyHandler)1223 THREADED_TEST(PrePropertyHandler) {
1224   v8::Isolate* isolate = CcTest::isolate();
1225   v8::HandleScope scope(isolate);
1226   v8::Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
1227   desc->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
1228       PrePropertyHandlerGet, 0, PrePropertyHandlerQuery));
1229   is_bootstrapping = true;
1230   LocalContext env(NULL, desc->InstanceTemplate());
1231   is_bootstrapping = false;
1232   CompileRun("var pre = 'Object: pre'; var on = 'Object: on';");
1233   v8::Local<Value> result_pre = CompileRun("pre");
1234   CHECK(v8_str("PrePropertyHandler: pre")
1235             ->Equals(env.local(), result_pre)
1236             .FromJust());
1237   v8::Local<Value> result_on = CompileRun("on");
1238   CHECK(v8_str("Object: on")->Equals(env.local(), result_on).FromJust());
1239   v8::Local<Value> result_post = CompileRun("post");
1240   CHECK(result_post.IsEmpty());
1241 }
1242 
1243 
THREADED_TEST(EmptyInterceptorBreakTransitions)1244 THREADED_TEST(EmptyInterceptorBreakTransitions) {
1245   v8::HandleScope scope(CcTest::isolate());
1246   Local<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
1247   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
1248   LocalContext env;
1249   env->Global()
1250       ->Set(env.local(), v8_str("Constructor"),
1251             templ->GetFunction(env.local()).ToLocalChecked())
1252       .FromJust();
1253   CompileRun(
1254       "var o1 = new Constructor;"
1255       "o1.a = 1;"  // Ensure a and x share the descriptor array.
1256       "Object.defineProperty(o1, 'x', {value: 10});");
1257   CompileRun(
1258       "var o2 = new Constructor;"
1259       "o2.a = 1;"
1260       "Object.defineProperty(o2, 'x', {value: 10});");
1261 }
1262 
1263 
THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors)1264 THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) {
1265   v8::Isolate* isolate = CcTest::isolate();
1266   v8::HandleScope scope(isolate);
1267   Local<FunctionTemplate> parent = FunctionTemplate::New(isolate);
1268   Local<FunctionTemplate> child = FunctionTemplate::New(isolate);
1269   child->Inherit(parent);
1270   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1271   LocalContext env;
1272   env->Global()
1273       ->Set(env.local(), v8_str("Child"),
1274             child->GetFunction(env.local()).ToLocalChecked())
1275       .FromJust();
1276   CompileRun(
1277       "var child = new Child;"
1278       "var parent = child.__proto__;"
1279       "Object.defineProperty(parent, 'age', "
1280       "  {get: function(){ return this.accessor_age; }, "
1281       "   set: function(v){ this.accessor_age = v; }, "
1282       "   enumerable: true, configurable: true});"
1283       "child.age = 10;");
1284   ExpectBoolean("child.hasOwnProperty('age')", false);
1285   ExpectInt32("child.age", 10);
1286   ExpectInt32("child.accessor_age", 10);
1287 }
1288 
1289 
THREADED_TEST(EmptyInterceptorDoesNotShadowApiAccessors)1290 THREADED_TEST(EmptyInterceptorDoesNotShadowApiAccessors) {
1291   v8::Isolate* isolate = CcTest::isolate();
1292   v8::HandleScope scope(isolate);
1293   Local<FunctionTemplate> parent = FunctionTemplate::New(isolate);
1294   auto returns_42 = FunctionTemplate::New(isolate, Returns42);
1295   parent->PrototypeTemplate()->SetAccessorProperty(v8_str("age"), returns_42);
1296   Local<FunctionTemplate> child = FunctionTemplate::New(isolate);
1297   child->Inherit(parent);
1298   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1299   LocalContext env;
1300   env->Global()
1301       ->Set(env.local(), v8_str("Child"),
1302             child->GetFunction(env.local()).ToLocalChecked())
1303       .FromJust();
1304   CompileRun(
1305       "var child = new Child;"
1306       "var parent = child.__proto__;");
1307   ExpectBoolean("child.hasOwnProperty('age')", false);
1308   ExpectInt32("child.age", 42);
1309   // Check interceptor followup.
1310   ExpectInt32(
1311       "var result;"
1312       "for (var i = 0; i < 4; ++i) {"
1313       "  result = child.age;"
1314       "}"
1315       "result",
1316       42);
1317 }
1318 
1319 
THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties)1320 THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) {
1321   v8::Isolate* isolate = CcTest::isolate();
1322   v8::HandleScope scope(isolate);
1323   Local<FunctionTemplate> parent = FunctionTemplate::New(isolate);
1324   Local<FunctionTemplate> child = FunctionTemplate::New(isolate);
1325   child->Inherit(parent);
1326   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1327   LocalContext env;
1328   env->Global()
1329       ->Set(env.local(), v8_str("Child"),
1330             child->GetFunction(env.local()).ToLocalChecked())
1331       .FromJust();
1332   CompileRun(
1333       "var child = new Child;"
1334       "var parent = child.__proto__;"
1335       "parent.name = 'Alice';");
1336   ExpectBoolean("child.hasOwnProperty('name')", false);
1337   ExpectString("child.name", "Alice");
1338   CompileRun("child.name = 'Bob';");
1339   ExpectString("child.name", "Bob");
1340   ExpectBoolean("child.hasOwnProperty('name')", true);
1341   ExpectString("parent.name", "Alice");
1342 }
1343 
1344 
THREADED_TEST(SwitchFromInterceptorToAccessor)1345 THREADED_TEST(SwitchFromInterceptorToAccessor) {
1346   v8::HandleScope scope(CcTest::isolate());
1347   Local<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
1348   AddAccessor(templ, v8_str("age"), SimpleAccessorGetter, SimpleAccessorSetter);
1349   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1350   LocalContext env;
1351   env->Global()
1352       ->Set(env.local(), v8_str("Obj"),
1353             templ->GetFunction(env.local()).ToLocalChecked())
1354       .FromJust();
1355   CompileRun(
1356       "var obj = new Obj;"
1357       "function setAge(i){ obj.age = i; };"
1358       "for(var i = 0; i <= 10000; i++) setAge(i);");
1359   // All i < 10000 go to the interceptor.
1360   ExpectInt32("obj.interceptor_age", 9999);
1361   // The last i goes to the accessor.
1362   ExpectInt32("obj.accessor_age", 10000);
1363 }
1364 
1365 
THREADED_TEST(SwitchFromAccessorToInterceptor)1366 THREADED_TEST(SwitchFromAccessorToInterceptor) {
1367   v8::HandleScope scope(CcTest::isolate());
1368   Local<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
1369   AddAccessor(templ, v8_str("age"), SimpleAccessorGetter, SimpleAccessorSetter);
1370   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1371   LocalContext env;
1372   env->Global()
1373       ->Set(env.local(), v8_str("Obj"),
1374             templ->GetFunction(env.local()).ToLocalChecked())
1375       .FromJust();
1376   CompileRun(
1377       "var obj = new Obj;"
1378       "function setAge(i){ obj.age = i; };"
1379       "for(var i = 20000; i >= 9999; i--) setAge(i);");
1380   // All i >= 10000 go to the accessor.
1381   ExpectInt32("obj.accessor_age", 10000);
1382   // The last i goes to the interceptor.
1383   ExpectInt32("obj.interceptor_age", 9999);
1384 }
1385 
1386 
THREADED_TEST(SwitchFromInterceptorToAccessorWithInheritance)1387 THREADED_TEST(SwitchFromInterceptorToAccessorWithInheritance) {
1388   v8::HandleScope scope(CcTest::isolate());
1389   Local<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
1390   Local<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
1391   child->Inherit(parent);
1392   AddAccessor(parent, v8_str("age"), SimpleAccessorGetter,
1393               SimpleAccessorSetter);
1394   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1395   LocalContext env;
1396   env->Global()
1397       ->Set(env.local(), v8_str("Child"),
1398             child->GetFunction(env.local()).ToLocalChecked())
1399       .FromJust();
1400   CompileRun(
1401       "var child = new Child;"
1402       "function setAge(i){ child.age = i; };"
1403       "for(var i = 0; i <= 10000; i++) setAge(i);");
1404   // All i < 10000 go to the interceptor.
1405   ExpectInt32("child.interceptor_age", 9999);
1406   // The last i goes to the accessor.
1407   ExpectInt32("child.accessor_age", 10000);
1408 }
1409 
1410 
THREADED_TEST(SwitchFromAccessorToInterceptorWithInheritance)1411 THREADED_TEST(SwitchFromAccessorToInterceptorWithInheritance) {
1412   v8::HandleScope scope(CcTest::isolate());
1413   Local<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
1414   Local<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
1415   child->Inherit(parent);
1416   AddAccessor(parent, v8_str("age"), SimpleAccessorGetter,
1417               SimpleAccessorSetter);
1418   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1419   LocalContext env;
1420   env->Global()
1421       ->Set(env.local(), v8_str("Child"),
1422             child->GetFunction(env.local()).ToLocalChecked())
1423       .FromJust();
1424   CompileRun(
1425       "var child = new Child;"
1426       "function setAge(i){ child.age = i; };"
1427       "for(var i = 20000; i >= 9999; i--) setAge(i);");
1428   // All i >= 10000 go to the accessor.
1429   ExpectInt32("child.accessor_age", 10000);
1430   // The last i goes to the interceptor.
1431   ExpectInt32("child.interceptor_age", 9999);
1432 }
1433 
1434 
THREADED_TEST(SwitchFromInterceptorToJSAccessor)1435 THREADED_TEST(SwitchFromInterceptorToJSAccessor) {
1436   v8::HandleScope scope(CcTest::isolate());
1437   Local<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
1438   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1439   LocalContext env;
1440   env->Global()
1441       ->Set(env.local(), v8_str("Obj"),
1442             templ->GetFunction(env.local()).ToLocalChecked())
1443       .FromJust();
1444   CompileRun(
1445       "var obj = new Obj;"
1446       "function setter(i) { this.accessor_age = i; };"
1447       "function getter() { return this.accessor_age; };"
1448       "function setAge(i) { obj.age = i; };"
1449       "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
1450       "for(var i = 0; i <= 10000; i++) setAge(i);");
1451   // All i < 10000 go to the interceptor.
1452   ExpectInt32("obj.interceptor_age", 9999);
1453   // The last i goes to the JavaScript accessor.
1454   ExpectInt32("obj.accessor_age", 10000);
1455   // The installed JavaScript getter is still intact.
1456   // This last part is a regression test for issue 1651 and relies on the fact
1457   // that both interceptor and accessor are being installed on the same object.
1458   ExpectInt32("obj.age", 10000);
1459   ExpectBoolean("obj.hasOwnProperty('age')", true);
1460   ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
1461 }
1462 
1463 
THREADED_TEST(SwitchFromJSAccessorToInterceptor)1464 THREADED_TEST(SwitchFromJSAccessorToInterceptor) {
1465   v8::HandleScope scope(CcTest::isolate());
1466   Local<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
1467   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1468   LocalContext env;
1469   env->Global()
1470       ->Set(env.local(), v8_str("Obj"),
1471             templ->GetFunction(env.local()).ToLocalChecked())
1472       .FromJust();
1473   CompileRun(
1474       "var obj = new Obj;"
1475       "function setter(i) { this.accessor_age = i; };"
1476       "function getter() { return this.accessor_age; };"
1477       "function setAge(i) { obj.age = i; };"
1478       "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
1479       "for(var i = 20000; i >= 9999; i--) setAge(i);");
1480   // All i >= 10000 go to the accessor.
1481   ExpectInt32("obj.accessor_age", 10000);
1482   // The last i goes to the interceptor.
1483   ExpectInt32("obj.interceptor_age", 9999);
1484   // The installed JavaScript getter is still intact.
1485   // This last part is a regression test for issue 1651 and relies on the fact
1486   // that both interceptor and accessor are being installed on the same object.
1487   ExpectInt32("obj.age", 10000);
1488   ExpectBoolean("obj.hasOwnProperty('age')", true);
1489   ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
1490 }
1491 
1492 
THREADED_TEST(SwitchFromInterceptorToProperty)1493 THREADED_TEST(SwitchFromInterceptorToProperty) {
1494   v8::HandleScope scope(CcTest::isolate());
1495   Local<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
1496   Local<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
1497   child->Inherit(parent);
1498   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1499   LocalContext env;
1500   env->Global()
1501       ->Set(env.local(), v8_str("Child"),
1502             child->GetFunction(env.local()).ToLocalChecked())
1503       .FromJust();
1504   CompileRun(
1505       "var child = new Child;"
1506       "function setAge(i){ child.age = i; };"
1507       "for(var i = 0; i <= 10000; i++) setAge(i);");
1508   // All i < 10000 go to the interceptor.
1509   ExpectInt32("child.interceptor_age", 9999);
1510   // The last i goes to child's own property.
1511   ExpectInt32("child.age", 10000);
1512 }
1513 
1514 
THREADED_TEST(SwitchFromPropertyToInterceptor)1515 THREADED_TEST(SwitchFromPropertyToInterceptor) {
1516   v8::HandleScope scope(CcTest::isolate());
1517   Local<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
1518   Local<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
1519   child->Inherit(parent);
1520   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1521   LocalContext env;
1522   env->Global()
1523       ->Set(env.local(), v8_str("Child"),
1524             child->GetFunction(env.local()).ToLocalChecked())
1525       .FromJust();
1526   CompileRun(
1527       "var child = new Child;"
1528       "function setAge(i){ child.age = i; };"
1529       "for(var i = 20000; i >= 9999; i--) setAge(i);");
1530   // All i >= 10000 go to child's own property.
1531   ExpectInt32("child.age", 10000);
1532   // The last i goes to the interceptor.
1533   ExpectInt32("child.interceptor_age", 9999);
1534 }
1535 
1536 
1537 static bool interceptor_for_hidden_properties_called;
InterceptorForHiddenProperties(Local<Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)1538 static void InterceptorForHiddenProperties(
1539     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
1540   interceptor_for_hidden_properties_called = true;
1541 }
1542 
1543 
THREADED_TEST(HiddenPropertiesWithInterceptors)1544 THREADED_TEST(HiddenPropertiesWithInterceptors) {
1545   LocalContext context;
1546   v8::Isolate* isolate = context->GetIsolate();
1547   v8::HandleScope scope(isolate);
1548 
1549   interceptor_for_hidden_properties_called = false;
1550 
1551   v8::Local<v8::Private> key =
1552       v8::Private::New(isolate, v8_str("api-test::hidden-key"));
1553 
1554   // Associate an interceptor with an object and start setting hidden values.
1555   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
1556   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
1557   instance_templ->SetHandler(
1558       v8::NamedPropertyHandlerConfiguration(InterceptorForHiddenProperties));
1559   Local<v8::Function> function =
1560       fun_templ->GetFunction(context.local()).ToLocalChecked();
1561   Local<v8::Object> obj =
1562       function->NewInstance(context.local()).ToLocalChecked();
1563   CHECK(obj->SetPrivate(context.local(), key, v8::Integer::New(isolate, 2302))
1564             .FromJust());
1565   CHECK_EQ(2302, obj->GetPrivate(context.local(), key)
1566                      .ToLocalChecked()
1567                      ->Int32Value(context.local())
1568                      .FromJust());
1569   CHECK(!interceptor_for_hidden_properties_called);
1570 }
1571 
1572 
XPropertyGetter(Local<Name> property,const v8::PropertyCallbackInfo<v8::Value> & info)1573 static void XPropertyGetter(Local<Name> property,
1574                             const v8::PropertyCallbackInfo<v8::Value>& info) {
1575   ApiTestFuzzer::Fuzz();
1576   CHECK(info.Data()->IsUndefined());
1577   info.GetReturnValue().Set(property);
1578 }
1579 
1580 
THREADED_TEST(NamedInterceptorPropertyRead)1581 THREADED_TEST(NamedInterceptorPropertyRead) {
1582   v8::Isolate* isolate = CcTest::isolate();
1583   v8::HandleScope scope(isolate);
1584   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1585   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(XPropertyGetter));
1586   LocalContext context;
1587   context->Global()
1588       ->Set(context.local(), v8_str("obj"),
1589             templ->NewInstance(context.local()).ToLocalChecked())
1590       .FromJust();
1591   Local<Script> script = v8_compile("obj.x");
1592   for (int i = 0; i < 10; i++) {
1593     Local<Value> result = script->Run(context.local()).ToLocalChecked();
1594     CHECK(result->Equals(context.local(), v8_str("x")).FromJust());
1595   }
1596 }
1597 
1598 
THREADED_TEST(NamedInterceptorDictionaryIC)1599 THREADED_TEST(NamedInterceptorDictionaryIC) {
1600   v8::Isolate* isolate = CcTest::isolate();
1601   v8::HandleScope scope(isolate);
1602   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1603   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(XPropertyGetter));
1604   LocalContext context;
1605   // Create an object with a named interceptor.
1606   context->Global()
1607       ->Set(context.local(), v8_str("interceptor_obj"),
1608             templ->NewInstance(context.local()).ToLocalChecked())
1609       .FromJust();
1610   Local<Script> script = v8_compile("interceptor_obj.x");
1611   for (int i = 0; i < 10; i++) {
1612     Local<Value> result = script->Run(context.local()).ToLocalChecked();
1613     CHECK(result->Equals(context.local(), v8_str("x")).FromJust());
1614   }
1615   // Create a slow case object and a function accessing a property in
1616   // that slow case object (with dictionary probing in generated
1617   // code). Then force object with a named interceptor into slow-case,
1618   // pass it to the function, and check that the interceptor is called
1619   // instead of accessing the local property.
1620   Local<Value> result = CompileRun(
1621       "function get_x(o) { return o.x; };"
1622       "var obj = { x : 42, y : 0 };"
1623       "delete obj.y;"
1624       "for (var i = 0; i < 10; i++) get_x(obj);"
1625       "interceptor_obj.x = 42;"
1626       "interceptor_obj.y = 10;"
1627       "delete interceptor_obj.y;"
1628       "get_x(interceptor_obj)");
1629   CHECK(result->Equals(context.local(), v8_str("x")).FromJust());
1630 }
1631 
1632 
THREADED_TEST(NamedInterceptorDictionaryICMultipleContext)1633 THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
1634   v8::Isolate* isolate = CcTest::isolate();
1635   v8::HandleScope scope(isolate);
1636   v8::Local<Context> context1 = Context::New(isolate);
1637 
1638   context1->Enter();
1639   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1640   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(XPropertyGetter));
1641   // Create an object with a named interceptor.
1642   v8::Local<v8::Object> object = templ->NewInstance(context1).ToLocalChecked();
1643   context1->Global()
1644       ->Set(context1, v8_str("interceptor_obj"), object)
1645       .FromJust();
1646 
1647   // Force the object into the slow case.
1648   CompileRun(
1649       "interceptor_obj.y = 0;"
1650       "delete interceptor_obj.y;");
1651   context1->Exit();
1652 
1653   {
1654     // Introduce the object into a different context.
1655     // Repeat named loads to exercise ICs.
1656     LocalContext context2;
1657     context2->Global()
1658         ->Set(context2.local(), v8_str("interceptor_obj"), object)
1659         .FromJust();
1660     Local<Value> result = CompileRun(
1661         "function get_x(o) { return o.x; }"
1662         "interceptor_obj.x = 42;"
1663         "for (var i=0; i != 10; i++) {"
1664         "  get_x(interceptor_obj);"
1665         "}"
1666         "get_x(interceptor_obj)");
1667     // Check that the interceptor was actually invoked.
1668     CHECK(result->Equals(context2.local(), v8_str("x")).FromJust());
1669   }
1670 
1671   // Return to the original context and force some object to the slow case
1672   // to cause the NormalizedMapCache to verify.
1673   context1->Enter();
1674   CompileRun("var obj = { x : 0 }; delete obj.x;");
1675   context1->Exit();
1676 }
1677 
1678 
SetXOnPrototypeGetter(Local<Name> property,const v8::PropertyCallbackInfo<v8::Value> & info)1679 static void SetXOnPrototypeGetter(
1680     Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {
1681   // Set x on the prototype object and do not handle the get request.
1682   v8::Local<v8::Value> proto = info.Holder()->GetPrototype();
1683   proto.As<v8::Object>()
1684       ->Set(info.GetIsolate()->GetCurrentContext(), v8_str("x"),
1685             v8::Integer::New(info.GetIsolate(), 23))
1686       .FromJust();
1687 }
1688 
1689 
1690 // This is a regression test for http://crbug.com/20104. Map
1691 // transitions should not interfere with post interceptor lookup.
THREADED_TEST(NamedInterceptorMapTransitionRead)1692 THREADED_TEST(NamedInterceptorMapTransitionRead) {
1693   v8::Isolate* isolate = CcTest::isolate();
1694   v8::HandleScope scope(isolate);
1695   Local<v8::FunctionTemplate> function_template =
1696       v8::FunctionTemplate::New(isolate);
1697   Local<v8::ObjectTemplate> instance_template =
1698       function_template->InstanceTemplate();
1699   instance_template->SetHandler(
1700       v8::NamedPropertyHandlerConfiguration(SetXOnPrototypeGetter));
1701   LocalContext context;
1702   context->Global()
1703       ->Set(context.local(), v8_str("F"),
1704             function_template->GetFunction(context.local()).ToLocalChecked())
1705       .FromJust();
1706   // Create an instance of F and introduce a map transition for x.
1707   CompileRun("var o = new F(); o.x = 23;");
1708   // Create an instance of F and invoke the getter. The result should be 23.
1709   Local<Value> result = CompileRun("o = new F(); o.x");
1710   CHECK_EQ(result->Int32Value(context.local()).FromJust(), 23);
1711 }
1712 
1713 
IndexedPropertyGetter(uint32_t index,const v8::PropertyCallbackInfo<v8::Value> & info)1714 static void IndexedPropertyGetter(
1715     uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) {
1716   ApiTestFuzzer::Fuzz();
1717   if (index == 37) {
1718     info.GetReturnValue().Set(v8_num(625));
1719   }
1720 }
1721 
1722 
IndexedPropertySetter(uint32_t index,Local<Value> value,const v8::PropertyCallbackInfo<v8::Value> & info)1723 static void IndexedPropertySetter(
1724     uint32_t index, Local<Value> value,
1725     const v8::PropertyCallbackInfo<v8::Value>& info) {
1726   ApiTestFuzzer::Fuzz();
1727   if (index == 39) {
1728     info.GetReturnValue().Set(value);
1729   }
1730 }
1731 
1732 
THREADED_TEST(IndexedInterceptorWithIndexedAccessor)1733 THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
1734   v8::Isolate* isolate = CcTest::isolate();
1735   v8::HandleScope scope(isolate);
1736   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1737   templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
1738       IndexedPropertyGetter, IndexedPropertySetter));
1739   LocalContext context;
1740   context->Global()
1741       ->Set(context.local(), v8_str("obj"),
1742             templ->NewInstance(context.local()).ToLocalChecked())
1743       .FromJust();
1744   Local<Script> getter_script =
1745       v8_compile("obj.__defineGetter__(\"3\", function(){return 5;});obj[3];");
1746   Local<Script> setter_script = v8_compile(
1747       "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
1748       "obj[17] = 23;"
1749       "obj.foo;");
1750   Local<Script> interceptor_setter_script = v8_compile(
1751       "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
1752       "obj[39] = 47;"
1753       "obj.foo;");  // This setter should not run, due to the interceptor.
1754   Local<Script> interceptor_getter_script = v8_compile("obj[37];");
1755   Local<Value> result = getter_script->Run(context.local()).ToLocalChecked();
1756   CHECK(v8_num(5)->Equals(context.local(), result).FromJust());
1757   result = setter_script->Run(context.local()).ToLocalChecked();
1758   CHECK(v8_num(23)->Equals(context.local(), result).FromJust());
1759   result = interceptor_setter_script->Run(context.local()).ToLocalChecked();
1760   CHECK(v8_num(23)->Equals(context.local(), result).FromJust());
1761   result = interceptor_getter_script->Run(context.local()).ToLocalChecked();
1762   CHECK(v8_num(625)->Equals(context.local(), result).FromJust());
1763 }
1764 
1765 
UnboxedDoubleIndexedPropertyGetter(uint32_t index,const v8::PropertyCallbackInfo<v8::Value> & info)1766 static void UnboxedDoubleIndexedPropertyGetter(
1767     uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) {
1768   ApiTestFuzzer::Fuzz();
1769   if (index < 25) {
1770     info.GetReturnValue().Set(v8_num(index));
1771   }
1772 }
1773 
1774 
UnboxedDoubleIndexedPropertySetter(uint32_t index,Local<Value> value,const v8::PropertyCallbackInfo<v8::Value> & info)1775 static void UnboxedDoubleIndexedPropertySetter(
1776     uint32_t index, Local<Value> value,
1777     const v8::PropertyCallbackInfo<v8::Value>& info) {
1778   ApiTestFuzzer::Fuzz();
1779   if (index < 25) {
1780     info.GetReturnValue().Set(v8_num(index));
1781   }
1782 }
1783 
1784 
UnboxedDoubleIndexedPropertyEnumerator(const v8::PropertyCallbackInfo<v8::Array> & info)1785 void UnboxedDoubleIndexedPropertyEnumerator(
1786     const v8::PropertyCallbackInfo<v8::Array>& info) {
1787   // Force the list of returned keys to be stored in a FastDoubleArray.
1788   Local<Script> indexed_property_names_script = v8_compile(
1789       "keys = new Array(); keys[125000] = 1;"
1790       "for(i = 0; i < 80000; i++) { keys[i] = i; };"
1791       "keys.length = 25; keys;");
1792   Local<Value> result =
1793       indexed_property_names_script->Run(info.GetIsolate()->GetCurrentContext())
1794           .ToLocalChecked();
1795   info.GetReturnValue().Set(Local<v8::Array>::Cast(result));
1796 }
1797 
1798 
1799 // Make sure that the the interceptor code in the runtime properly handles
1800 // merging property name lists for double-array-backed arrays.
THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor)1801 THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
1802   v8::Isolate* isolate = CcTest::isolate();
1803   v8::HandleScope scope(isolate);
1804   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1805   templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
1806       UnboxedDoubleIndexedPropertyGetter, UnboxedDoubleIndexedPropertySetter, 0,
1807       0, UnboxedDoubleIndexedPropertyEnumerator));
1808   LocalContext context;
1809   context->Global()
1810       ->Set(context.local(), v8_str("obj"),
1811             templ->NewInstance(context.local()).ToLocalChecked())
1812       .FromJust();
1813   // When obj is created, force it to be Stored in a FastDoubleArray.
1814   Local<Script> create_unboxed_double_script = v8_compile(
1815       "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
1816       "key_count = 0; "
1817       "for (x in obj) {key_count++;};"
1818       "obj;");
1819   Local<Value> result =
1820       create_unboxed_double_script->Run(context.local()).ToLocalChecked();
1821   CHECK(result->ToObject(context.local())
1822             .ToLocalChecked()
1823             ->HasRealIndexedProperty(context.local(), 2000)
1824             .FromJust());
1825   Local<Script> key_count_check = v8_compile("key_count;");
1826   result = key_count_check->Run(context.local()).ToLocalChecked();
1827   CHECK(v8_num(40013)->Equals(context.local(), result).FromJust());
1828 }
1829 
1830 
SloppyArgsIndexedPropertyEnumerator(const v8::PropertyCallbackInfo<v8::Array> & info)1831 void SloppyArgsIndexedPropertyEnumerator(
1832     const v8::PropertyCallbackInfo<v8::Array>& info) {
1833   // Force the list of returned keys to be stored in a Arguments object.
1834   Local<Script> indexed_property_names_script = v8_compile(
1835       "function f(w,x) {"
1836       " return arguments;"
1837       "}"
1838       "keys = f(0, 1, 2, 3);"
1839       "keys;");
1840   Local<Object> result = Local<Object>::Cast(
1841       indexed_property_names_script->Run(info.GetIsolate()->GetCurrentContext())
1842           .ToLocalChecked());
1843   // Have to populate the handle manually, as it's not Cast-able.
1844   i::Handle<i::JSReceiver> o =
1845       v8::Utils::OpenHandle<Object, i::JSReceiver>(result);
1846   i::Handle<i::JSArray> array(reinterpret_cast<i::JSArray*>(*o));
1847   info.GetReturnValue().Set(v8::Utils::ToLocal(array));
1848 }
1849 
1850 
SloppyIndexedPropertyGetter(uint32_t index,const v8::PropertyCallbackInfo<v8::Value> & info)1851 static void SloppyIndexedPropertyGetter(
1852     uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) {
1853   ApiTestFuzzer::Fuzz();
1854   if (index < 4) {
1855     info.GetReturnValue().Set(v8_num(index));
1856   }
1857 }
1858 
1859 
1860 // Make sure that the the interceptor code in the runtime properly handles
1861 // merging property name lists for non-string arguments arrays.
THREADED_TEST(IndexedInterceptorSloppyArgsWithIndexedAccessor)1862 THREADED_TEST(IndexedInterceptorSloppyArgsWithIndexedAccessor) {
1863   v8::Isolate* isolate = CcTest::isolate();
1864   v8::HandleScope scope(isolate);
1865   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1866   templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
1867       SloppyIndexedPropertyGetter, 0, 0, 0,
1868       SloppyArgsIndexedPropertyEnumerator));
1869   LocalContext context;
1870   context->Global()
1871       ->Set(context.local(), v8_str("obj"),
1872             templ->NewInstance(context.local()).ToLocalChecked())
1873       .FromJust();
1874   Local<Script> create_args_script = v8_compile(
1875       "var key_count = 0;"
1876       "for (x in obj) {key_count++;} key_count;");
1877   Local<Value> result =
1878       create_args_script->Run(context.local()).ToLocalChecked();
1879   CHECK(v8_num(4)->Equals(context.local(), result).FromJust());
1880 }
1881 
1882 
IdentityIndexedPropertyGetter(uint32_t index,const v8::PropertyCallbackInfo<v8::Value> & info)1883 static void IdentityIndexedPropertyGetter(
1884     uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) {
1885   info.GetReturnValue().Set(index);
1886 }
1887 
1888 
THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor)1889 THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
1890   v8::Isolate* isolate = CcTest::isolate();
1891   v8::HandleScope scope(isolate);
1892   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1893   templ->SetHandler(
1894       v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
1895 
1896   LocalContext context;
1897   context->Global()
1898       ->Set(context.local(), v8_str("obj"),
1899             templ->NewInstance(context.local()).ToLocalChecked())
1900       .FromJust();
1901 
1902   // Check fast object case.
1903   const char* fast_case_code =
1904       "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
1905   ExpectString(fast_case_code, "0");
1906 
1907   // Check slow case.
1908   const char* slow_case_code =
1909       "obj.x = 1; delete obj.x;"
1910       "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
1911   ExpectString(slow_case_code, "1");
1912 }
1913 
1914 
THREADED_TEST(IndexedInterceptorWithNoSetter)1915 THREADED_TEST(IndexedInterceptorWithNoSetter) {
1916   v8::Isolate* isolate = CcTest::isolate();
1917   v8::HandleScope scope(isolate);
1918   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1919   templ->SetHandler(
1920       v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
1921 
1922   LocalContext context;
1923   context->Global()
1924       ->Set(context.local(), v8_str("obj"),
1925             templ->NewInstance(context.local()).ToLocalChecked())
1926       .FromJust();
1927 
1928   const char* code =
1929       "try {"
1930       "  obj[0] = 239;"
1931       "  for (var i = 0; i < 100; i++) {"
1932       "    var v = obj[0];"
1933       "    if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
1934       "  }"
1935       "  'PASSED'"
1936       "} catch(e) {"
1937       "  e"
1938       "}";
1939   ExpectString(code, "PASSED");
1940 }
1941 
AccessAlwaysBlocked(Local<v8::Context> accessing_context,Local<v8::Object> accessed_object,Local<v8::Value> data)1942 static bool AccessAlwaysBlocked(Local<v8::Context> accessing_context,
1943                                 Local<v8::Object> accessed_object,
1944                                 Local<v8::Value> data) {
1945   return false;
1946 }
1947 
1948 
THREADED_TEST(IndexedInterceptorWithAccessorCheck)1949 THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
1950   v8::Isolate* isolate = CcTest::isolate();
1951   v8::HandleScope scope(isolate);
1952   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1953   templ->SetHandler(
1954       v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
1955 
1956   templ->SetAccessCheckCallback(AccessAlwaysBlocked);
1957 
1958   LocalContext context;
1959   Local<v8::Object> obj = templ->NewInstance(context.local()).ToLocalChecked();
1960   context->Global()->Set(context.local(), v8_str("obj"), obj).FromJust();
1961 
1962   const char* code =
1963       "var result = 'PASSED';"
1964       "for (var i = 0; i < 100; i++) {"
1965       "  try {"
1966       "    var v = obj[0];"
1967       "    result = 'Wrong value ' + v + ' at iteration ' + i;"
1968       "    break;"
1969       "  } catch (e) {"
1970       "    /* pass */"
1971       "  }"
1972       "}"
1973       "result";
1974   ExpectString(code, "PASSED");
1975 }
1976 
1977 
THREADED_TEST(IndexedInterceptorWithDifferentIndices)1978 THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
1979   v8::Isolate* isolate = CcTest::isolate();
1980   v8::HandleScope scope(isolate);
1981   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1982   templ->SetHandler(
1983       v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
1984 
1985   LocalContext context;
1986   Local<v8::Object> obj = templ->NewInstance(context.local()).ToLocalChecked();
1987   context->Global()->Set(context.local(), v8_str("obj"), obj).FromJust();
1988 
1989   const char* code =
1990       "try {"
1991       "  for (var i = 0; i < 100; i++) {"
1992       "    var v = obj[i];"
1993       "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
1994       "  }"
1995       "  'PASSED'"
1996       "} catch(e) {"
1997       "  e"
1998       "}";
1999   ExpectString(code, "PASSED");
2000 }
2001 
2002 
THREADED_TEST(IndexedInterceptorWithNegativeIndices)2003 THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
2004   v8::Isolate* isolate = CcTest::isolate();
2005   v8::HandleScope scope(isolate);
2006   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
2007   templ->SetHandler(
2008       v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
2009 
2010   LocalContext context;
2011   Local<v8::Object> obj = templ->NewInstance(context.local()).ToLocalChecked();
2012   context->Global()->Set(context.local(), v8_str("obj"), obj).FromJust();
2013 
2014   const char* code =
2015       "try {"
2016       "  for (var i = 0; i < 100; i++) {"
2017       "    var expected = i;"
2018       "    var key = i;"
2019       "    if (i == 25) {"
2020       "       key = -1;"
2021       "       expected = undefined;"
2022       "    }"
2023       "    if (i == 50) {"
2024       "       /* probe minimal Smi number on 32-bit platforms */"
2025       "       key = -(1 << 30);"
2026       "       expected = undefined;"
2027       "    }"
2028       "    if (i == 75) {"
2029       "       /* probe minimal Smi number on 64-bit platforms */"
2030       "       key = 1 << 31;"
2031       "       expected = undefined;"
2032       "    }"
2033       "    var v = obj[key];"
2034       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
2035       "  }"
2036       "  'PASSED'"
2037       "} catch(e) {"
2038       "  e"
2039       "}";
2040   ExpectString(code, "PASSED");
2041 }
2042 
2043 
THREADED_TEST(IndexedInterceptorWithNotSmiLookup)2044 THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
2045   v8::Isolate* isolate = CcTest::isolate();
2046   v8::HandleScope scope(isolate);
2047   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
2048   templ->SetHandler(
2049       v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
2050 
2051   LocalContext context;
2052   Local<v8::Object> obj = templ->NewInstance(context.local()).ToLocalChecked();
2053   context->Global()->Set(context.local(), v8_str("obj"), obj).FromJust();
2054 
2055   const char* code =
2056       "try {"
2057       "  for (var i = 0; i < 100; i++) {"
2058       "    var expected = i;"
2059       "    var key = i;"
2060       "    if (i == 50) {"
2061       "       key = 'foobar';"
2062       "       expected = undefined;"
2063       "    }"
2064       "    var v = obj[key];"
2065       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
2066       "  }"
2067       "  'PASSED'"
2068       "} catch(e) {"
2069       "  e"
2070       "}";
2071   ExpectString(code, "PASSED");
2072 }
2073 
2074 
THREADED_TEST(IndexedInterceptorGoingMegamorphic)2075 THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
2076   v8::Isolate* isolate = CcTest::isolate();
2077   v8::HandleScope scope(isolate);
2078   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
2079   templ->SetHandler(
2080       v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
2081 
2082   LocalContext context;
2083   Local<v8::Object> obj = templ->NewInstance(context.local()).ToLocalChecked();
2084   context->Global()->Set(context.local(), v8_str("obj"), obj).FromJust();
2085 
2086   const char* code =
2087       "var original = obj;"
2088       "try {"
2089       "  for (var i = 0; i < 100; i++) {"
2090       "    var expected = i;"
2091       "    if (i == 50) {"
2092       "       obj = {50: 'foobar'};"
2093       "       expected = 'foobar';"
2094       "    }"
2095       "    var v = obj[i];"
2096       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
2097       "    if (i == 50) obj = original;"
2098       "  }"
2099       "  'PASSED'"
2100       "} catch(e) {"
2101       "  e"
2102       "}";
2103   ExpectString(code, "PASSED");
2104 }
2105 
2106 
THREADED_TEST(IndexedInterceptorReceiverTurningSmi)2107 THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
2108   v8::Isolate* isolate = CcTest::isolate();
2109   v8::HandleScope scope(isolate);
2110   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
2111   templ->SetHandler(
2112       v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
2113 
2114   LocalContext context;
2115   Local<v8::Object> obj = templ->NewInstance(context.local()).ToLocalChecked();
2116   context->Global()->Set(context.local(), v8_str("obj"), obj).FromJust();
2117 
2118   const char* code =
2119       "var original = obj;"
2120       "try {"
2121       "  for (var i = 0; i < 100; i++) {"
2122       "    var expected = i;"
2123       "    if (i == 5) {"
2124       "       obj = 239;"
2125       "       expected = undefined;"
2126       "    }"
2127       "    var v = obj[i];"
2128       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
2129       "    if (i == 5) obj = original;"
2130       "  }"
2131       "  'PASSED'"
2132       "} catch(e) {"
2133       "  e"
2134       "}";
2135   ExpectString(code, "PASSED");
2136 }
2137 
2138 
THREADED_TEST(IndexedInterceptorOnProto)2139 THREADED_TEST(IndexedInterceptorOnProto) {
2140   v8::Isolate* isolate = CcTest::isolate();
2141   v8::HandleScope scope(isolate);
2142   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
2143   templ->SetHandler(
2144       v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
2145 
2146   LocalContext context;
2147   Local<v8::Object> obj = templ->NewInstance(context.local()).ToLocalChecked();
2148   context->Global()->Set(context.local(), v8_str("obj"), obj).FromJust();
2149 
2150   const char* code =
2151       "var o = {__proto__: obj};"
2152       "try {"
2153       "  for (var i = 0; i < 100; i++) {"
2154       "    var v = o[i];"
2155       "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
2156       "  }"
2157       "  'PASSED'"
2158       "} catch(e) {"
2159       "  e"
2160       "}";
2161   ExpectString(code, "PASSED");
2162 }
2163 
2164 
NoBlockGetterX(Local<Name> name,const v8::PropertyCallbackInfo<v8::Value> &)2165 static void NoBlockGetterX(Local<Name> name,
2166                            const v8::PropertyCallbackInfo<v8::Value>&) {}
2167 
2168 
NoBlockGetterI(uint32_t index,const v8::PropertyCallbackInfo<v8::Value> &)2169 static void NoBlockGetterI(uint32_t index,
2170                            const v8::PropertyCallbackInfo<v8::Value>&) {}
2171 
2172 
PDeleter(Local<Name> name,const v8::PropertyCallbackInfo<v8::Boolean> & info)2173 static void PDeleter(Local<Name> name,
2174                      const v8::PropertyCallbackInfo<v8::Boolean>& info) {
2175   if (!name->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("foo"))
2176            .FromJust()) {
2177     return;  // not intercepted
2178   }
2179 
2180   info.GetReturnValue().Set(false);  // intercepted, don't delete the property
2181 }
2182 
2183 
IDeleter(uint32_t index,const v8::PropertyCallbackInfo<v8::Boolean> & info)2184 static void IDeleter(uint32_t index,
2185                      const v8::PropertyCallbackInfo<v8::Boolean>& info) {
2186   if (index != 2) {
2187     return;  // not intercepted
2188   }
2189 
2190   info.GetReturnValue().Set(false);  // intercepted, don't delete the property
2191 }
2192 
2193 
THREADED_TEST(Deleter)2194 THREADED_TEST(Deleter) {
2195   v8::Isolate* isolate = CcTest::isolate();
2196   v8::HandleScope scope(isolate);
2197   v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
2198   obj->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX, NULL,
2199                                                         NULL, PDeleter, NULL));
2200   obj->SetHandler(v8::IndexedPropertyHandlerConfiguration(
2201       NoBlockGetterI, NULL, NULL, IDeleter, NULL));
2202   LocalContext context;
2203   context->Global()
2204       ->Set(context.local(), v8_str("k"),
2205             obj->NewInstance(context.local()).ToLocalChecked())
2206       .FromJust();
2207   CompileRun(
2208       "k.foo = 'foo';"
2209       "k.bar = 'bar';"
2210       "k[2] = 2;"
2211       "k[4] = 4;");
2212   CHECK(v8_compile("delete k.foo")
2213             ->Run(context.local())
2214             .ToLocalChecked()
2215             ->IsFalse());
2216   CHECK(v8_compile("delete k.bar")
2217             ->Run(context.local())
2218             .ToLocalChecked()
2219             ->IsTrue());
2220 
2221   CHECK(v8_compile("k.foo")
2222             ->Run(context.local())
2223             .ToLocalChecked()
2224             ->Equals(context.local(), v8_str("foo"))
2225             .FromJust());
2226   CHECK(v8_compile("k.bar")
2227             ->Run(context.local())
2228             .ToLocalChecked()
2229             ->IsUndefined());
2230 
2231   CHECK(v8_compile("delete k[2]")
2232             ->Run(context.local())
2233             .ToLocalChecked()
2234             ->IsFalse());
2235   CHECK(v8_compile("delete k[4]")
2236             ->Run(context.local())
2237             .ToLocalChecked()
2238             ->IsTrue());
2239 
2240   CHECK(v8_compile("k[2]")
2241             ->Run(context.local())
2242             .ToLocalChecked()
2243             ->Equals(context.local(), v8_num(2))
2244             .FromJust());
2245   CHECK(
2246       v8_compile("k[4]")->Run(context.local()).ToLocalChecked()->IsUndefined());
2247 }
2248 
2249 
GetK(Local<Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)2250 static void GetK(Local<Name> name,
2251                  const v8::PropertyCallbackInfo<v8::Value>& info) {
2252   ApiTestFuzzer::Fuzz();
2253   v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
2254   if (name->Equals(context, v8_str("foo")).FromJust() ||
2255       name->Equals(context, v8_str("bar")).FromJust() ||
2256       name->Equals(context, v8_str("baz")).FromJust()) {
2257     info.GetReturnValue().SetUndefined();
2258   }
2259 }
2260 
2261 
IndexedGetK(uint32_t index,const v8::PropertyCallbackInfo<v8::Value> & info)2262 static void IndexedGetK(uint32_t index,
2263                         const v8::PropertyCallbackInfo<v8::Value>& info) {
2264   ApiTestFuzzer::Fuzz();
2265   if (index == 0 || index == 1) info.GetReturnValue().SetUndefined();
2266 }
2267 
2268 
NamedEnum(const v8::PropertyCallbackInfo<v8::Array> & info)2269 static void NamedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
2270   ApiTestFuzzer::Fuzz();
2271   v8::Local<v8::Array> result = v8::Array::New(info.GetIsolate(), 3);
2272   v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
2273   result->Set(context, v8::Integer::New(info.GetIsolate(), 0), v8_str("foo"))
2274       .FromJust();
2275   result->Set(context, v8::Integer::New(info.GetIsolate(), 1), v8_str("bar"))
2276       .FromJust();
2277   result->Set(context, v8::Integer::New(info.GetIsolate(), 2), v8_str("baz"))
2278       .FromJust();
2279   info.GetReturnValue().Set(result);
2280 }
2281 
2282 
IndexedEnum(const v8::PropertyCallbackInfo<v8::Array> & info)2283 static void IndexedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
2284   ApiTestFuzzer::Fuzz();
2285   v8::Local<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
2286   v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
2287   result->Set(context, v8::Integer::New(info.GetIsolate(), 0), v8_str("0"))
2288       .FromJust();
2289   result->Set(context, v8::Integer::New(info.GetIsolate(), 1), v8_str("1"))
2290       .FromJust();
2291   info.GetReturnValue().Set(result);
2292 }
2293 
2294 
THREADED_TEST(Enumerators)2295 THREADED_TEST(Enumerators) {
2296   v8::Isolate* isolate = CcTest::isolate();
2297   v8::HandleScope scope(isolate);
2298   v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
2299   obj->SetHandler(
2300       v8::NamedPropertyHandlerConfiguration(GetK, NULL, NULL, NULL, NamedEnum));
2301   obj->SetHandler(v8::IndexedPropertyHandlerConfiguration(
2302       IndexedGetK, NULL, NULL, NULL, IndexedEnum));
2303   LocalContext context;
2304   context->Global()
2305       ->Set(context.local(), v8_str("k"),
2306             obj->NewInstance(context.local()).ToLocalChecked())
2307       .FromJust();
2308   v8::Local<v8::Array> result =
2309       v8::Local<v8::Array>::Cast(CompileRun("k[10] = 0;"
2310                                             "k.a = 0;"
2311                                             "k[5] = 0;"
2312                                             "k.b = 0;"
2313                                             "k[4294967294] = 0;"
2314                                             "k.c = 0;"
2315                                             "k[4294967295] = 0;"
2316                                             "k.d = 0;"
2317                                             "k[140000] = 0;"
2318                                             "k.e = 0;"
2319                                             "k[30000000000] = 0;"
2320                                             "k.f = 0;"
2321                                             "var result = [];"
2322                                             "for (var prop in k) {"
2323                                             "  result.push(prop);"
2324                                             "}"
2325                                             "result"));
2326   // Check that we get all the property names returned including the
2327   // ones from the enumerators in the right order: indexed properties
2328   // in numerical order, indexed interceptor properties, named
2329   // properties in insertion order, named interceptor properties.
2330   // This order is not mandated by the spec, so this test is just
2331   // documenting our behavior.
2332   CHECK_EQ(17u, result->Length());
2333   // Indexed properties.
2334   CHECK(v8_str("5")
2335             ->Equals(context.local(),
2336                      result->Get(context.local(), v8::Integer::New(isolate, 0))
2337                          .ToLocalChecked())
2338             .FromJust());
2339   CHECK(v8_str("10")
2340             ->Equals(context.local(),
2341                      result->Get(context.local(), v8::Integer::New(isolate, 1))
2342                          .ToLocalChecked())
2343             .FromJust());
2344   CHECK(v8_str("140000")
2345             ->Equals(context.local(),
2346                      result->Get(context.local(), v8::Integer::New(isolate, 2))
2347                          .ToLocalChecked())
2348             .FromJust());
2349   CHECK(v8_str("4294967294")
2350             ->Equals(context.local(),
2351                      result->Get(context.local(), v8::Integer::New(isolate, 3))
2352                          .ToLocalChecked())
2353             .FromJust());
2354   // Indexed Interceptor properties
2355   CHECK(v8_str("0")
2356             ->Equals(context.local(),
2357                      result->Get(context.local(), v8::Integer::New(isolate, 4))
2358                          .ToLocalChecked())
2359             .FromJust());
2360   CHECK(v8_str("1")
2361             ->Equals(context.local(),
2362                      result->Get(context.local(), v8::Integer::New(isolate, 5))
2363                          .ToLocalChecked())
2364             .FromJust());
2365   // Named properties in insertion order.
2366   CHECK(v8_str("a")
2367             ->Equals(context.local(),
2368                      result->Get(context.local(), v8::Integer::New(isolate, 6))
2369                          .ToLocalChecked())
2370             .FromJust());
2371   CHECK(v8_str("b")
2372             ->Equals(context.local(),
2373                      result->Get(context.local(), v8::Integer::New(isolate, 7))
2374                          .ToLocalChecked())
2375             .FromJust());
2376   CHECK(v8_str("c")
2377             ->Equals(context.local(),
2378                      result->Get(context.local(), v8::Integer::New(isolate, 8))
2379                          .ToLocalChecked())
2380             .FromJust());
2381   CHECK(v8_str("4294967295")
2382             ->Equals(context.local(),
2383                      result->Get(context.local(), v8::Integer::New(isolate, 9))
2384                          .ToLocalChecked())
2385             .FromJust());
2386   CHECK(v8_str("d")
2387             ->Equals(context.local(),
2388                      result->Get(context.local(), v8::Integer::New(isolate, 10))
2389                          .ToLocalChecked())
2390             .FromJust());
2391   CHECK(v8_str("e")
2392             ->Equals(context.local(),
2393                      result->Get(context.local(), v8::Integer::New(isolate, 11))
2394                          .ToLocalChecked())
2395             .FromJust());
2396   CHECK(v8_str("30000000000")
2397             ->Equals(context.local(),
2398                      result->Get(context.local(), v8::Integer::New(isolate, 12))
2399                          .ToLocalChecked())
2400             .FromJust());
2401   CHECK(v8_str("f")
2402             ->Equals(context.local(),
2403                      result->Get(context.local(), v8::Integer::New(isolate, 13))
2404                          .ToLocalChecked())
2405             .FromJust());
2406   // Named interceptor properties.
2407   CHECK(v8_str("foo")
2408             ->Equals(context.local(),
2409                      result->Get(context.local(), v8::Integer::New(isolate, 14))
2410                          .ToLocalChecked())
2411             .FromJust());
2412   CHECK(v8_str("bar")
2413             ->Equals(context.local(),
2414                      result->Get(context.local(), v8::Integer::New(isolate, 15))
2415                          .ToLocalChecked())
2416             .FromJust());
2417   CHECK(v8_str("baz")
2418             ->Equals(context.local(),
2419                      result->Get(context.local(), v8::Integer::New(isolate, 16))
2420                          .ToLocalChecked())
2421             .FromJust());
2422 }
2423 
2424 
2425 v8::Local<Value> call_ic_function;
2426 v8::Local<Value> call_ic_function2;
2427 v8::Local<Value> call_ic_function3;
2428 
InterceptorCallICGetter(Local<Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)2429 static void InterceptorCallICGetter(
2430     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2431   ApiTestFuzzer::Fuzz();
2432   CHECK(v8_str("x")
2433             ->Equals(info.GetIsolate()->GetCurrentContext(), name)
2434             .FromJust());
2435   info.GetReturnValue().Set(call_ic_function);
2436 }
2437 
2438 
2439 // This test should hit the call IC for the interceptor case.
THREADED_TEST(InterceptorCallIC)2440 THREADED_TEST(InterceptorCallIC) {
2441   v8::Isolate* isolate = CcTest::isolate();
2442   v8::HandleScope scope(isolate);
2443   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2444   templ->SetHandler(
2445       v8::NamedPropertyHandlerConfiguration(InterceptorCallICGetter));
2446   LocalContext context;
2447   context->Global()
2448       ->Set(context.local(), v8_str("o"),
2449             templ->NewInstance(context.local()).ToLocalChecked())
2450       .FromJust();
2451   call_ic_function = v8_compile("function f(x) { return x + 1; }; f")
2452                          ->Run(context.local())
2453                          .ToLocalChecked();
2454   v8::Local<Value> value = CompileRun(
2455       "var result = 0;"
2456       "for (var i = 0; i < 1000; i++) {"
2457       "  result = o.x(41);"
2458       "}");
2459   CHECK_EQ(42, value->Int32Value(context.local()).FromJust());
2460 }
2461 
2462 
2463 // This test checks that if interceptor doesn't provide
2464 // a value, we can fetch regular value.
THREADED_TEST(InterceptorCallICSeesOthers)2465 THREADED_TEST(InterceptorCallICSeesOthers) {
2466   v8::Isolate* isolate = CcTest::isolate();
2467   v8::HandleScope scope(isolate);
2468   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2469   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
2470   LocalContext context;
2471   context->Global()
2472       ->Set(context.local(), v8_str("o"),
2473             templ->NewInstance(context.local()).ToLocalChecked())
2474       .FromJust();
2475   v8::Local<Value> value = CompileRun(
2476       "o.x = function f(x) { return x + 1; };"
2477       "var result = 0;"
2478       "for (var i = 0; i < 7; i++) {"
2479       "  result = o.x(41);"
2480       "}");
2481   CHECK_EQ(42, value->Int32Value(context.local()).FromJust());
2482 }
2483 
2484 
2485 static v8::Local<Value> call_ic_function4;
InterceptorCallICGetter4(Local<Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)2486 static void InterceptorCallICGetter4(
2487     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2488   ApiTestFuzzer::Fuzz();
2489   CHECK(v8_str("x")
2490             ->Equals(info.GetIsolate()->GetCurrentContext(), name)
2491             .FromJust());
2492   info.GetReturnValue().Set(call_ic_function4);
2493 }
2494 
2495 
2496 // This test checks that if interceptor provides a function,
2497 // even if we cached shadowed variant, interceptor's function
2498 // is invoked
THREADED_TEST(InterceptorCallICCacheableNotNeeded)2499 THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
2500   v8::Isolate* isolate = CcTest::isolate();
2501   v8::HandleScope scope(isolate);
2502   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2503   templ->SetHandler(
2504       v8::NamedPropertyHandlerConfiguration(InterceptorCallICGetter4));
2505   LocalContext context;
2506   context->Global()
2507       ->Set(context.local(), v8_str("o"),
2508             templ->NewInstance(context.local()).ToLocalChecked())
2509       .FromJust();
2510   call_ic_function4 = v8_compile("function f(x) { return x - 1; }; f")
2511                           ->Run(context.local())
2512                           .ToLocalChecked();
2513   v8::Local<Value> value = CompileRun(
2514       "Object.getPrototypeOf(o).x = function(x) { return x + 1; };"
2515       "var result = 0;"
2516       "for (var i = 0; i < 1000; i++) {"
2517       "  result = o.x(42);"
2518       "}");
2519   CHECK_EQ(41, value->Int32Value(context.local()).FromJust());
2520 }
2521 
2522 
2523 // Test the case when we stored cacheable lookup into
2524 // a stub, but it got invalidated later on
THREADED_TEST(InterceptorCallICInvalidatedCacheable)2525 THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
2526   v8::Isolate* isolate = CcTest::isolate();
2527   v8::HandleScope scope(isolate);
2528   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2529   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
2530   LocalContext context;
2531   context->Global()
2532       ->Set(context.local(), v8_str("o"),
2533             templ->NewInstance(context.local()).ToLocalChecked())
2534       .FromJust();
2535   v8::Local<Value> value = CompileRun(
2536       "proto1 = new Object();"
2537       "proto2 = new Object();"
2538       "o.__proto__ = proto1;"
2539       "proto1.__proto__ = proto2;"
2540       "proto2.y = function(x) { return x + 1; };"
2541       // Invoke it many times to compile a stub
2542       "for (var i = 0; i < 7; i++) {"
2543       "  o.y(42);"
2544       "}"
2545       "proto1.y = function(x) { return x - 1; };"
2546       "var result = 0;"
2547       "for (var i = 0; i < 7; i++) {"
2548       "  result += o.y(42);"
2549       "}");
2550   CHECK_EQ(41 * 7, value->Int32Value(context.local()).FromJust());
2551 }
2552 
2553 
2554 // This test checks that if interceptor doesn't provide a function,
2555 // cached constant function is used
THREADED_TEST(InterceptorCallICConstantFunctionUsed)2556 THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
2557   v8::Isolate* isolate = CcTest::isolate();
2558   v8::HandleScope scope(isolate);
2559   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2560   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
2561   LocalContext context;
2562   context->Global()
2563       ->Set(context.local(), v8_str("o"),
2564             templ->NewInstance(context.local()).ToLocalChecked())
2565       .FromJust();
2566   v8::Local<Value> value = CompileRun(
2567       "function inc(x) { return x + 1; };"
2568       "inc(1);"
2569       "o.x = inc;"
2570       "var result = 0;"
2571       "for (var i = 0; i < 1000; i++) {"
2572       "  result = o.x(42);"
2573       "}");
2574   CHECK_EQ(43, value->Int32Value(context.local()).FromJust());
2575 }
2576 
2577 
2578 static v8::Local<Value> call_ic_function5;
InterceptorCallICGetter5(Local<Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)2579 static void InterceptorCallICGetter5(
2580     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2581   ApiTestFuzzer::Fuzz();
2582   if (v8_str("x")
2583           ->Equals(info.GetIsolate()->GetCurrentContext(), name)
2584           .FromJust())
2585     info.GetReturnValue().Set(call_ic_function5);
2586 }
2587 
2588 
2589 // This test checks that if interceptor provides a function,
2590 // even if we cached constant function, interceptor's function
2591 // is invoked
THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded)2592 THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
2593   v8::Isolate* isolate = CcTest::isolate();
2594   v8::HandleScope scope(isolate);
2595   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2596   templ->SetHandler(
2597       v8::NamedPropertyHandlerConfiguration(InterceptorCallICGetter5));
2598   LocalContext context;
2599   context->Global()
2600       ->Set(context.local(), v8_str("o"),
2601             templ->NewInstance(context.local()).ToLocalChecked())
2602       .FromJust();
2603   call_ic_function5 = v8_compile("function f(x) { return x - 1; }; f")
2604                           ->Run(context.local())
2605                           .ToLocalChecked();
2606   v8::Local<Value> value = CompileRun(
2607       "function inc(x) { return x + 1; };"
2608       "inc(1);"
2609       "o.x = inc;"
2610       "var result = 0;"
2611       "for (var i = 0; i < 1000; i++) {"
2612       "  result = o.x(42);"
2613       "}");
2614   CHECK_EQ(41, value->Int32Value(context.local()).FromJust());
2615 }
2616 
2617 
2618 static v8::Local<Value> call_ic_function6;
InterceptorCallICGetter6(Local<Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)2619 static void InterceptorCallICGetter6(
2620     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2621   ApiTestFuzzer::Fuzz();
2622   if (v8_str("x")
2623           ->Equals(info.GetIsolate()->GetCurrentContext(), name)
2624           .FromJust())
2625     info.GetReturnValue().Set(call_ic_function6);
2626 }
2627 
2628 
2629 // Same test as above, except the code is wrapped in a function
2630 // to test the optimized compiler.
THREADED_TEST(InterceptorCallICConstantFunctionNotNeededWrapped)2631 THREADED_TEST(InterceptorCallICConstantFunctionNotNeededWrapped) {
2632   i::FLAG_allow_natives_syntax = true;
2633   v8::Isolate* isolate = CcTest::isolate();
2634   v8::HandleScope scope(isolate);
2635   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2636   templ->SetHandler(
2637       v8::NamedPropertyHandlerConfiguration(InterceptorCallICGetter6));
2638   LocalContext context;
2639   context->Global()
2640       ->Set(context.local(), v8_str("o"),
2641             templ->NewInstance(context.local()).ToLocalChecked())
2642       .FromJust();
2643   call_ic_function6 = v8_compile("function f(x) { return x - 1; }; f")
2644                           ->Run(context.local())
2645                           .ToLocalChecked();
2646   v8::Local<Value> value = CompileRun(
2647       "function inc(x) { return x + 1; };"
2648       "inc(1);"
2649       "o.x = inc;"
2650       "function test() {"
2651       "  var result = 0;"
2652       "  for (var i = 0; i < 1000; i++) {"
2653       "    result = o.x(42);"
2654       "  }"
2655       "  return result;"
2656       "};"
2657       "test();"
2658       "test();"
2659       "test();"
2660       "%OptimizeFunctionOnNextCall(test);"
2661       "test()");
2662   CHECK_EQ(41, value->Int32Value(context.local()).FromJust());
2663 }
2664 
2665 
2666 // Test the case when we stored constant function into
2667 // a stub, but it got invalidated later on
THREADED_TEST(InterceptorCallICInvalidatedConstantFunction)2668 THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
2669   v8::Isolate* isolate = CcTest::isolate();
2670   v8::HandleScope scope(isolate);
2671   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2672   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
2673   LocalContext context;
2674   context->Global()
2675       ->Set(context.local(), v8_str("o"),
2676             templ->NewInstance(context.local()).ToLocalChecked())
2677       .FromJust();
2678   v8::Local<Value> value = CompileRun(
2679       "function inc(x) { return x + 1; };"
2680       "inc(1);"
2681       "proto1 = new Object();"
2682       "proto2 = new Object();"
2683       "o.__proto__ = proto1;"
2684       "proto1.__proto__ = proto2;"
2685       "proto2.y = inc;"
2686       // Invoke it many times to compile a stub
2687       "for (var i = 0; i < 7; i++) {"
2688       "  o.y(42);"
2689       "}"
2690       "proto1.y = function(x) { return x - 1; };"
2691       "var result = 0;"
2692       "for (var i = 0; i < 7; i++) {"
2693       "  result += o.y(42);"
2694       "}");
2695   CHECK_EQ(41 * 7, value->Int32Value(context.local()).FromJust());
2696 }
2697 
2698 
2699 // Test the case when we stored constant function into
2700 // a stub, but it got invalidated later on due to override on
2701 // global object which is between interceptor and constant function' holders.
THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal)2702 THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
2703   v8::Isolate* isolate = CcTest::isolate();
2704   v8::HandleScope scope(isolate);
2705   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2706   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
2707   LocalContext context;
2708   context->Global()
2709       ->Set(context.local(), v8_str("o"),
2710             templ->NewInstance(context.local()).ToLocalChecked())
2711       .FromJust();
2712   v8::Local<Value> value = CompileRun(
2713       "function inc(x) { return x + 1; };"
2714       "inc(1);"
2715       "o.__proto__ = this;"
2716       "this.__proto__.y = inc;"
2717       // Invoke it many times to compile a stub
2718       "for (var i = 0; i < 7; i++) {"
2719       "  if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
2720       "}"
2721       "this.y = function(x) { return x - 1; };"
2722       "var result = 0;"
2723       "for (var i = 0; i < 7; i++) {"
2724       "  result += o.y(42);"
2725       "}");
2726   CHECK_EQ(41 * 7, value->Int32Value(context.local()).FromJust());
2727 }
2728 
2729 
2730 // Test the case when actual function to call sits on global object.
THREADED_TEST(InterceptorCallICCachedFromGlobal)2731 THREADED_TEST(InterceptorCallICCachedFromGlobal) {
2732   v8::Isolate* isolate = CcTest::isolate();
2733   v8::HandleScope scope(isolate);
2734   v8::Local<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
2735   templ_o->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
2736 
2737   LocalContext context;
2738   context->Global()
2739       ->Set(context.local(), v8_str("o"),
2740             templ_o->NewInstance(context.local()).ToLocalChecked())
2741       .FromJust();
2742 
2743   v8::Local<Value> value = CompileRun(
2744       "try {"
2745       "  o.__proto__ = this;"
2746       "  for (var i = 0; i < 10; i++) {"
2747       "    var v = o.parseFloat('239');"
2748       "    if (v != 239) throw v;"
2749       // Now it should be ICed and keep a reference to parseFloat.
2750       "  }"
2751       "  var result = 0;"
2752       "  for (var i = 0; i < 10; i++) {"
2753       "    result += o.parseFloat('239');"
2754       "  }"
2755       "  result"
2756       "} catch(e) {"
2757       "  e"
2758       "};");
2759   CHECK_EQ(239 * 10, value->Int32Value(context.local()).FromJust());
2760 }
2761 
2762 
2763 v8::Local<Value> keyed_call_ic_function;
2764 
InterceptorKeyedCallICGetter(Local<Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)2765 static void InterceptorKeyedCallICGetter(
2766     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2767   ApiTestFuzzer::Fuzz();
2768   if (v8_str("x")
2769           ->Equals(info.GetIsolate()->GetCurrentContext(), name)
2770           .FromJust()) {
2771     info.GetReturnValue().Set(keyed_call_ic_function);
2772   }
2773 }
2774 
2775 
2776 // Test the case when we stored cacheable lookup into
2777 // a stub, but the function name changed (to another cacheable function).
THREADED_TEST(InterceptorKeyedCallICKeyChange1)2778 THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
2779   v8::Isolate* isolate = CcTest::isolate();
2780   v8::HandleScope scope(isolate);
2781   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2782   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
2783   LocalContext context;
2784   context->Global()
2785       ->Set(context.local(), v8_str("o"),
2786             templ->NewInstance(context.local()).ToLocalChecked())
2787       .FromJust();
2788   CompileRun(
2789       "proto = new Object();"
2790       "proto.y = function(x) { return x + 1; };"
2791       "proto.z = function(x) { return x - 1; };"
2792       "o.__proto__ = proto;"
2793       "var result = 0;"
2794       "var method = 'y';"
2795       "for (var i = 0; i < 10; i++) {"
2796       "  if (i == 5) { method = 'z'; };"
2797       "  result += o[method](41);"
2798       "}");
2799   CHECK_EQ(42 * 5 + 40 * 5, context->Global()
2800                                 ->Get(context.local(), v8_str("result"))
2801                                 .ToLocalChecked()
2802                                 ->Int32Value(context.local())
2803                                 .FromJust());
2804 }
2805 
2806 
2807 // Test the case when we stored cacheable lookup into
2808 // a stub, but the function name changed (and the new function is present
2809 // both before and after the interceptor in the prototype chain).
THREADED_TEST(InterceptorKeyedCallICKeyChange2)2810 THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
2811   v8::Isolate* isolate = CcTest::isolate();
2812   v8::HandleScope scope(isolate);
2813   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2814   templ->SetHandler(
2815       v8::NamedPropertyHandlerConfiguration(InterceptorKeyedCallICGetter));
2816   LocalContext context;
2817   context->Global()
2818       ->Set(context.local(), v8_str("proto1"),
2819             templ->NewInstance(context.local()).ToLocalChecked())
2820       .FromJust();
2821   keyed_call_ic_function = v8_compile("function f(x) { return x - 1; }; f")
2822                                ->Run(context.local())
2823                                .ToLocalChecked();
2824   CompileRun(
2825       "o = new Object();"
2826       "proto2 = new Object();"
2827       "o.y = function(x) { return x + 1; };"
2828       "proto2.y = function(x) { return x + 2; };"
2829       "o.__proto__ = proto1;"
2830       "proto1.__proto__ = proto2;"
2831       "var result = 0;"
2832       "var method = 'x';"
2833       "for (var i = 0; i < 10; i++) {"
2834       "  if (i == 5) { method = 'y'; };"
2835       "  result += o[method](41);"
2836       "}");
2837   CHECK_EQ(42 * 5 + 40 * 5, context->Global()
2838                                 ->Get(context.local(), v8_str("result"))
2839                                 .ToLocalChecked()
2840                                 ->Int32Value(context.local())
2841                                 .FromJust());
2842 }
2843 
2844 
2845 // Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
2846 // on the global object.
THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal)2847 THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
2848   v8::Isolate* isolate = CcTest::isolate();
2849   v8::HandleScope scope(isolate);
2850   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2851   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
2852   LocalContext context;
2853   context->Global()
2854       ->Set(context.local(), v8_str("o"),
2855             templ->NewInstance(context.local()).ToLocalChecked())
2856       .FromJust();
2857   CompileRun(
2858       "function inc(x) { return x + 1; };"
2859       "inc(1);"
2860       "function dec(x) { return x - 1; };"
2861       "dec(1);"
2862       "o.__proto__ = this;"
2863       "this.__proto__.x = inc;"
2864       "this.__proto__.y = dec;"
2865       "var result = 0;"
2866       "var method = 'x';"
2867       "for (var i = 0; i < 10; i++) {"
2868       "  if (i == 5) { method = 'y'; };"
2869       "  result += o[method](41);"
2870       "}");
2871   CHECK_EQ(42 * 5 + 40 * 5, context->Global()
2872                                 ->Get(context.local(), v8_str("result"))
2873                                 .ToLocalChecked()
2874                                 ->Int32Value(context.local())
2875                                 .FromJust());
2876 }
2877 
2878 
2879 // Test the case when actual function to call sits on global object.
THREADED_TEST(InterceptorKeyedCallICFromGlobal)2880 THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
2881   v8::Isolate* isolate = CcTest::isolate();
2882   v8::HandleScope scope(isolate);
2883   v8::Local<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
2884   templ_o->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
2885   LocalContext context;
2886   context->Global()
2887       ->Set(context.local(), v8_str("o"),
2888             templ_o->NewInstance(context.local()).ToLocalChecked())
2889       .FromJust();
2890 
2891   CompileRun(
2892       "function len(x) { return x.length; };"
2893       "o.__proto__ = this;"
2894       "var m = 'parseFloat';"
2895       "var result = 0;"
2896       "for (var i = 0; i < 10; i++) {"
2897       "  if (i == 5) {"
2898       "    m = 'len';"
2899       "    saved_result = result;"
2900       "  };"
2901       "  result = o[m]('239');"
2902       "}");
2903   CHECK_EQ(3, context->Global()
2904                   ->Get(context.local(), v8_str("result"))
2905                   .ToLocalChecked()
2906                   ->Int32Value(context.local())
2907                   .FromJust());
2908   CHECK_EQ(239, context->Global()
2909                     ->Get(context.local(), v8_str("saved_result"))
2910                     .ToLocalChecked()
2911                     ->Int32Value(context.local())
2912                     .FromJust());
2913 }
2914 
2915 
2916 // Test the map transition before the interceptor.
THREADED_TEST(InterceptorKeyedCallICMapChangeBefore)2917 THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
2918   v8::Isolate* isolate = CcTest::isolate();
2919   v8::HandleScope scope(isolate);
2920   v8::Local<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
2921   templ_o->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
2922   LocalContext context;
2923   context->Global()
2924       ->Set(context.local(), v8_str("proto"),
2925             templ_o->NewInstance(context.local()).ToLocalChecked())
2926       .FromJust();
2927 
2928   CompileRun(
2929       "var o = new Object();"
2930       "o.__proto__ = proto;"
2931       "o.method = function(x) { return x + 1; };"
2932       "var m = 'method';"
2933       "var result = 0;"
2934       "for (var i = 0; i < 10; i++) {"
2935       "  if (i == 5) { o.method = function(x) { return x - 1; }; };"
2936       "  result += o[m](41);"
2937       "}");
2938   CHECK_EQ(42 * 5 + 40 * 5, context->Global()
2939                                 ->Get(context.local(), v8_str("result"))
2940                                 .ToLocalChecked()
2941                                 ->Int32Value(context.local())
2942                                 .FromJust());
2943 }
2944 
2945 
2946 // Test the map transition after the interceptor.
THREADED_TEST(InterceptorKeyedCallICMapChangeAfter)2947 THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
2948   v8::Isolate* isolate = CcTest::isolate();
2949   v8::HandleScope scope(isolate);
2950   v8::Local<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
2951   templ_o->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
2952   LocalContext context;
2953   context->Global()
2954       ->Set(context.local(), v8_str("o"),
2955             templ_o->NewInstance(context.local()).ToLocalChecked())
2956       .FromJust();
2957 
2958   CompileRun(
2959       "var proto = new Object();"
2960       "o.__proto__ = proto;"
2961       "proto.method = function(x) { return x + 1; };"
2962       "var m = 'method';"
2963       "var result = 0;"
2964       "for (var i = 0; i < 10; i++) {"
2965       "  if (i == 5) { proto.method = function(x) { return x - 1; }; };"
2966       "  result += o[m](41);"
2967       "}");
2968   CHECK_EQ(42 * 5 + 40 * 5, context->Global()
2969                                 ->Get(context.local(), v8_str("result"))
2970                                 .ToLocalChecked()
2971                                 ->Int32Value(context.local())
2972                                 .FromJust());
2973 }
2974 
2975 
2976 static int interceptor_call_count = 0;
2977 
InterceptorICRefErrorGetter(Local<Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)2978 static void InterceptorICRefErrorGetter(
2979     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2980   ApiTestFuzzer::Fuzz();
2981   if (!is_bootstrapping &&
2982       v8_str("x")
2983           ->Equals(info.GetIsolate()->GetCurrentContext(), name)
2984           .FromJust() &&
2985       interceptor_call_count++ < 20) {
2986     info.GetReturnValue().Set(call_ic_function2);
2987   }
2988 }
2989 
2990 
2991 // This test should hit load and call ICs for the interceptor case.
2992 // Once in a while, the interceptor will reply that a property was not
2993 // found in which case we should get a reference error.
THREADED_TEST(InterceptorICReferenceErrors)2994 THREADED_TEST(InterceptorICReferenceErrors) {
2995   v8::Isolate* isolate = CcTest::isolate();
2996   v8::HandleScope scope(isolate);
2997   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2998   templ->SetHandler(
2999       v8::NamedPropertyHandlerConfiguration(InterceptorICRefErrorGetter));
3000   is_bootstrapping = true;
3001   LocalContext context(0, templ, v8::Local<Value>());
3002   is_bootstrapping = false;
3003   call_ic_function2 = v8_compile("function h(x) { return x; }; h")
3004                           ->Run(context.local())
3005                           .ToLocalChecked();
3006   v8::Local<Value> value = CompileRun(
3007       "function f() {"
3008       "  for (var i = 0; i < 1000; i++) {"
3009       "    try { x; } catch(e) { return true; }"
3010       "  }"
3011       "  return false;"
3012       "};"
3013       "f();");
3014   CHECK_EQ(true, value->BooleanValue(context.local()).FromJust());
3015   interceptor_call_count = 0;
3016   value = CompileRun(
3017       "function g() {"
3018       "  for (var i = 0; i < 1000; i++) {"
3019       "    try { x(42); } catch(e) { return true; }"
3020       "  }"
3021       "  return false;"
3022       "};"
3023       "g();");
3024   CHECK_EQ(true, value->BooleanValue(context.local()).FromJust());
3025 }
3026 
3027 
3028 static int interceptor_ic_exception_get_count = 0;
3029 
InterceptorICExceptionGetter(Local<Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)3030 static void InterceptorICExceptionGetter(
3031     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
3032   ApiTestFuzzer::Fuzz();
3033   if (is_bootstrapping) return;
3034   if (v8_str("x")
3035           ->Equals(info.GetIsolate()->GetCurrentContext(), name)
3036           .FromJust() &&
3037       ++interceptor_ic_exception_get_count < 20) {
3038     info.GetReturnValue().Set(call_ic_function3);
3039   }
3040   if (interceptor_ic_exception_get_count == 20) {
3041     info.GetIsolate()->ThrowException(v8_num(42));
3042     return;
3043   }
3044 }
3045 
3046 
3047 // Test interceptor load/call IC where the interceptor throws an
3048 // exception once in a while.
THREADED_TEST(InterceptorICGetterExceptions)3049 THREADED_TEST(InterceptorICGetterExceptions) {
3050   interceptor_ic_exception_get_count = 0;
3051   v8::Isolate* isolate = CcTest::isolate();
3052   v8::HandleScope scope(isolate);
3053   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
3054   templ->SetHandler(
3055       v8::NamedPropertyHandlerConfiguration(InterceptorICExceptionGetter));
3056   is_bootstrapping = true;
3057   LocalContext context(0, templ, v8::Local<Value>());
3058   is_bootstrapping = false;
3059   call_ic_function3 = v8_compile("function h(x) { return x; }; h")
3060                           ->Run(context.local())
3061                           .ToLocalChecked();
3062   v8::Local<Value> value = CompileRun(
3063       "function f() {"
3064       "  for (var i = 0; i < 100; i++) {"
3065       "    try { x; } catch(e) { return true; }"
3066       "  }"
3067       "  return false;"
3068       "};"
3069       "f();");
3070   CHECK_EQ(true, value->BooleanValue(context.local()).FromJust());
3071   interceptor_ic_exception_get_count = 0;
3072   value = CompileRun(
3073       "function f() {"
3074       "  for (var i = 0; i < 100; i++) {"
3075       "    try { x(42); } catch(e) { return true; }"
3076       "  }"
3077       "  return false;"
3078       "};"
3079       "f();");
3080   CHECK_EQ(true, value->BooleanValue(context.local()).FromJust());
3081 }
3082 
3083 
3084 static int interceptor_ic_exception_set_count = 0;
3085 
InterceptorICExceptionSetter(Local<Name> key,Local<Value> value,const v8::PropertyCallbackInfo<v8::Value> & info)3086 static void InterceptorICExceptionSetter(
3087     Local<Name> key, Local<Value> value,
3088     const v8::PropertyCallbackInfo<v8::Value>& info) {
3089   ApiTestFuzzer::Fuzz();
3090   if (++interceptor_ic_exception_set_count > 20) {
3091     info.GetIsolate()->ThrowException(v8_num(42));
3092   }
3093 }
3094 
3095 
3096 // Test interceptor store IC where the interceptor throws an exception
3097 // once in a while.
THREADED_TEST(InterceptorICSetterExceptions)3098 THREADED_TEST(InterceptorICSetterExceptions) {
3099   interceptor_ic_exception_set_count = 0;
3100   v8::Isolate* isolate = CcTest::isolate();
3101   v8::HandleScope scope(isolate);
3102   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
3103   templ->SetHandler(
3104       v8::NamedPropertyHandlerConfiguration(0, InterceptorICExceptionSetter));
3105   LocalContext context(0, templ, v8::Local<Value>());
3106   v8::Local<Value> value = CompileRun(
3107       "function f() {"
3108       "  for (var i = 0; i < 100; i++) {"
3109       "    try { x = 42; } catch(e) { return true; }"
3110       "  }"
3111       "  return false;"
3112       "};"
3113       "f();");
3114   CHECK_EQ(true, value->BooleanValue(context.local()).FromJust());
3115 }
3116 
3117 
3118 // Test that we ignore null interceptors.
THREADED_TEST(NullNamedInterceptor)3119 THREADED_TEST(NullNamedInterceptor) {
3120   v8::Isolate* isolate = CcTest::isolate();
3121   v8::HandleScope scope(isolate);
3122   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
3123   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
3124       static_cast<v8::GenericNamedPropertyGetterCallback>(0)));
3125   LocalContext context;
3126   templ->Set(CcTest::isolate(), "x", v8_num(42));
3127   v8::Local<v8::Object> obj =
3128       templ->NewInstance(context.local()).ToLocalChecked();
3129   context->Global()->Set(context.local(), v8_str("obj"), obj).FromJust();
3130   v8::Local<Value> value = CompileRun("obj.x");
3131   CHECK(value->IsInt32());
3132   CHECK_EQ(42, value->Int32Value(context.local()).FromJust());
3133 }
3134 
3135 
3136 // Test that we ignore null interceptors.
THREADED_TEST(NullIndexedInterceptor)3137 THREADED_TEST(NullIndexedInterceptor) {
3138   v8::Isolate* isolate = CcTest::isolate();
3139   v8::HandleScope scope(isolate);
3140   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
3141   templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
3142       static_cast<v8::IndexedPropertyGetterCallback>(0)));
3143   LocalContext context;
3144   templ->Set(CcTest::isolate(), "42", v8_num(42));
3145   v8::Local<v8::Object> obj =
3146       templ->NewInstance(context.local()).ToLocalChecked();
3147   context->Global()->Set(context.local(), v8_str("obj"), obj).FromJust();
3148   v8::Local<Value> value = CompileRun("obj[42]");
3149   CHECK(value->IsInt32());
3150   CHECK_EQ(42, value->Int32Value(context.local()).FromJust());
3151 }
3152 
3153 
THREADED_TEST(NamedPropertyHandlerGetterAttributes)3154 THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
3155   v8::Isolate* isolate = CcTest::isolate();
3156   v8::HandleScope scope(isolate);
3157   v8::Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
3158   templ->InstanceTemplate()->SetHandler(
3159       v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
3160   LocalContext env;
3161   env->Global()
3162       ->Set(env.local(), v8_str("obj"), templ->GetFunction(env.local())
3163                                             .ToLocalChecked()
3164                                             ->NewInstance(env.local())
3165                                             .ToLocalChecked())
3166       .FromJust();
3167   ExpectTrue("obj.x === 42");
3168   ExpectTrue("!obj.propertyIsEnumerable('x')");
3169 }
3170 
3171 
THREADED_TEST(Regress256330)3172 THREADED_TEST(Regress256330) {
3173   i::FLAG_allow_natives_syntax = true;
3174   LocalContext context;
3175   v8::HandleScope scope(context->GetIsolate());
3176   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
3177   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
3178   context->Global()
3179       ->Set(context.local(), v8_str("Bug"),
3180             templ->GetFunction(context.local()).ToLocalChecked())
3181       .FromJust();
3182   CompileRun(
3183       "\"use strict\"; var o = new Bug;"
3184       "function f(o) { o.x = 10; };"
3185       "f(o); f(o); f(o);"
3186       "%OptimizeFunctionOnNextCall(f);"
3187       "f(o);");
3188   ExpectBoolean("%GetOptimizationStatus(f) != 2", true);
3189 }
3190 
3191 
THREADED_TEST(CrankshaftInterceptorSetter)3192 THREADED_TEST(CrankshaftInterceptorSetter) {
3193   i::FLAG_allow_natives_syntax = true;
3194   v8::HandleScope scope(CcTest::isolate());
3195   Local<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
3196   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
3197   LocalContext env;
3198   env->Global()
3199       ->Set(env.local(), v8_str("Obj"),
3200             templ->GetFunction(env.local()).ToLocalChecked())
3201       .FromJust();
3202   CompileRun(
3203       "var obj = new Obj;"
3204       // Initialize fields to avoid transitions later.
3205       "obj.age = 0;"
3206       "obj.accessor_age = 42;"
3207       "function setter(i) { this.accessor_age = i; };"
3208       "function getter() { return this.accessor_age; };"
3209       "function setAge(i) { obj.age = i; };"
3210       "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
3211       "setAge(1);"
3212       "setAge(2);"
3213       "setAge(3);"
3214       "%OptimizeFunctionOnNextCall(setAge);"
3215       "setAge(4);");
3216   // All stores went through the interceptor.
3217   ExpectInt32("obj.interceptor_age", 4);
3218   ExpectInt32("obj.accessor_age", 42);
3219 }
3220 
3221 
THREADED_TEST(CrankshaftInterceptorGetter)3222 THREADED_TEST(CrankshaftInterceptorGetter) {
3223   i::FLAG_allow_natives_syntax = true;
3224   v8::HandleScope scope(CcTest::isolate());
3225   Local<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
3226   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
3227   LocalContext env;
3228   env->Global()
3229       ->Set(env.local(), v8_str("Obj"),
3230             templ->GetFunction(env.local()).ToLocalChecked())
3231       .FromJust();
3232   CompileRun(
3233       "var obj = new Obj;"
3234       // Initialize fields to avoid transitions later.
3235       "obj.age = 1;"
3236       "obj.accessor_age = 42;"
3237       "function getter() { return this.accessor_age; };"
3238       "function getAge() { return obj.interceptor_age; };"
3239       "Object.defineProperty(obj, 'interceptor_age', { get:getter });"
3240       "getAge();"
3241       "getAge();"
3242       "getAge();"
3243       "%OptimizeFunctionOnNextCall(getAge);");
3244   // Access through interceptor.
3245   ExpectInt32("getAge()", 1);
3246 }
3247 
3248 
THREADED_TEST(CrankshaftInterceptorFieldRead)3249 THREADED_TEST(CrankshaftInterceptorFieldRead) {
3250   i::FLAG_allow_natives_syntax = true;
3251   v8::HandleScope scope(CcTest::isolate());
3252   Local<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
3253   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
3254   LocalContext env;
3255   env->Global()
3256       ->Set(env.local(), v8_str("Obj"),
3257             templ->GetFunction(env.local()).ToLocalChecked())
3258       .FromJust();
3259   CompileRun(
3260       "var obj = new Obj;"
3261       "obj.__proto__.interceptor_age = 42;"
3262       "obj.age = 100;"
3263       "function getAge() { return obj.interceptor_age; };");
3264   ExpectInt32("getAge();", 100);
3265   ExpectInt32("getAge();", 100);
3266   ExpectInt32("getAge();", 100);
3267   CompileRun("%OptimizeFunctionOnNextCall(getAge);");
3268   // Access through interceptor.
3269   ExpectInt32("getAge();", 100);
3270 }
3271 
3272 
THREADED_TEST(CrankshaftInterceptorFieldWrite)3273 THREADED_TEST(CrankshaftInterceptorFieldWrite) {
3274   i::FLAG_allow_natives_syntax = true;
3275   v8::HandleScope scope(CcTest::isolate());
3276   Local<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
3277   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
3278   LocalContext env;
3279   env->Global()
3280       ->Set(env.local(), v8_str("Obj"),
3281             templ->GetFunction(env.local()).ToLocalChecked())
3282       .FromJust();
3283   CompileRun(
3284       "var obj = new Obj;"
3285       "obj.age = 100000;"
3286       "function setAge(i) { obj.age = i };"
3287       "setAge(100);"
3288       "setAge(101);"
3289       "setAge(102);"
3290       "%OptimizeFunctionOnNextCall(setAge);"
3291       "setAge(103);");
3292   ExpectInt32("obj.age", 100000);
3293   ExpectInt32("obj.interceptor_age", 103);
3294 }
3295 
3296 
THREADED_TEST(Regress149912)3297 THREADED_TEST(Regress149912) {
3298   LocalContext context;
3299   v8::HandleScope scope(context->GetIsolate());
3300   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
3301   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
3302   context->Global()
3303       ->Set(context.local(), v8_str("Bug"),
3304             templ->GetFunction(context.local()).ToLocalChecked())
3305       .FromJust();
3306   CompileRun("Number.prototype.__proto__ = new Bug; var x = 0; x.foo();");
3307 }
3308 
THREADED_TEST(Regress625155)3309 THREADED_TEST(Regress625155) {
3310   LocalContext context;
3311   v8::HandleScope scope(context->GetIsolate());
3312   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
3313   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
3314   context->Global()
3315       ->Set(context.local(), v8_str("Bug"),
3316             templ->GetFunction(context.local()).ToLocalChecked())
3317       .FromJust();
3318   CompileRun(
3319       "Number.prototype.__proto__ = new Bug;"
3320       "var x;"
3321       "x = 0xdead;"
3322       "x.boom = 0;"
3323       "x = 's';"
3324       "x.boom = 0;"
3325       "x = 1.5;"
3326       "x.boom = 0;");
3327 }
3328 
THREADED_TEST(Regress125988)3329 THREADED_TEST(Regress125988) {
3330   v8::HandleScope scope(CcTest::isolate());
3331   Local<FunctionTemplate> intercept = FunctionTemplate::New(CcTest::isolate());
3332   AddInterceptor(intercept, EmptyInterceptorGetter, EmptyInterceptorSetter);
3333   LocalContext env;
3334   env->Global()
3335       ->Set(env.local(), v8_str("Intercept"),
3336             intercept->GetFunction(env.local()).ToLocalChecked())
3337       .FromJust();
3338   CompileRun(
3339       "var a = new Object();"
3340       "var b = new Intercept();"
3341       "var c = new Object();"
3342       "c.__proto__ = b;"
3343       "b.__proto__ = a;"
3344       "a.x = 23;"
3345       "for (var i = 0; i < 3; i++) c.x;");
3346   ExpectBoolean("c.hasOwnProperty('x')", false);
3347   ExpectInt32("c.x", 23);
3348   CompileRun(
3349       "a.y = 42;"
3350       "for (var i = 0; i < 3; i++) c.x;");
3351   ExpectBoolean("c.hasOwnProperty('x')", false);
3352   ExpectInt32("c.x", 23);
3353   ExpectBoolean("c.hasOwnProperty('y')", false);
3354   ExpectInt32("c.y", 42);
3355 }
3356 
3357 
IndexedPropertyEnumerator(const v8::PropertyCallbackInfo<v8::Array> & info)3358 static void IndexedPropertyEnumerator(
3359     const v8::PropertyCallbackInfo<v8::Array>& info) {
3360   v8::Local<v8::Array> result = v8::Array::New(info.GetIsolate(), 1);
3361   result->Set(info.GetIsolate()->GetCurrentContext(), 0,
3362               v8::Integer::New(info.GetIsolate(), 7))
3363       .FromJust();
3364   info.GetReturnValue().Set(result);
3365 }
3366 
3367 
NamedPropertyEnumerator(const v8::PropertyCallbackInfo<v8::Array> & info)3368 static void NamedPropertyEnumerator(
3369     const v8::PropertyCallbackInfo<v8::Array>& info) {
3370   v8::Local<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
3371   v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
3372   result->Set(context, 0, v8_str("x")).FromJust();
3373   result->Set(context, 1, v8::Symbol::GetIterator(info.GetIsolate()))
3374       .FromJust();
3375   info.GetReturnValue().Set(result);
3376 }
3377 
3378 
THREADED_TEST(GetOwnPropertyNamesWithInterceptor)3379 THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
3380   v8::Isolate* isolate = CcTest::isolate();
3381   v8::HandleScope handle_scope(isolate);
3382   v8::Local<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New(isolate);
3383 
3384   obj_template->Set(v8_str("7"), v8::Integer::New(CcTest::isolate(), 7));
3385   obj_template->Set(v8_str("x"), v8::Integer::New(CcTest::isolate(), 42));
3386   obj_template->SetHandler(v8::IndexedPropertyHandlerConfiguration(
3387       NULL, NULL, NULL, NULL, IndexedPropertyEnumerator));
3388   obj_template->SetHandler(v8::NamedPropertyHandlerConfiguration(
3389       NULL, NULL, NULL, NULL, NamedPropertyEnumerator));
3390 
3391   LocalContext context;
3392   v8::Local<v8::Object> global = context->Global();
3393   global->Set(context.local(), v8_str("object"),
3394               obj_template->NewInstance(context.local()).ToLocalChecked())
3395       .FromJust();
3396 
3397   v8::Local<v8::Value> result =
3398       CompileRun("Object.getOwnPropertyNames(object)");
3399   CHECK(result->IsArray());
3400   v8::Local<v8::Array> result_array = v8::Local<v8::Array>::Cast(result);
3401   CHECK_EQ(2u, result_array->Length());
3402   CHECK(result_array->Get(context.local(), 0).ToLocalChecked()->IsString());
3403   CHECK(result_array->Get(context.local(), 1).ToLocalChecked()->IsString());
3404   CHECK(v8_str("7")
3405             ->Equals(context.local(),
3406                      result_array->Get(context.local(), 0).ToLocalChecked())
3407             .FromJust());
3408   CHECK(v8_str("x")
3409             ->Equals(context.local(),
3410                      result_array->Get(context.local(), 1).ToLocalChecked())
3411             .FromJust());
3412 
3413   result = CompileRun("var ret = []; for (var k in object) ret.push(k); ret");
3414   CHECK(result->IsArray());
3415   result_array = v8::Local<v8::Array>::Cast(result);
3416   CHECK_EQ(2u, result_array->Length());
3417   CHECK(result_array->Get(context.local(), 0).ToLocalChecked()->IsString());
3418   CHECK(result_array->Get(context.local(), 1).ToLocalChecked()->IsString());
3419   CHECK(v8_str("7")
3420             ->Equals(context.local(),
3421                      result_array->Get(context.local(), 0).ToLocalChecked())
3422             .FromJust());
3423   CHECK(v8_str("x")
3424             ->Equals(context.local(),
3425                      result_array->Get(context.local(), 1).ToLocalChecked())
3426             .FromJust());
3427 
3428   result = CompileRun("Object.getOwnPropertySymbols(object)");
3429   CHECK(result->IsArray());
3430   result_array = v8::Local<v8::Array>::Cast(result);
3431   CHECK_EQ(1u, result_array->Length());
3432   CHECK(result_array->Get(context.local(), 0)
3433             .ToLocalChecked()
3434             ->Equals(context.local(), v8::Symbol::GetIterator(isolate))
3435             .FromJust());
3436 }
3437 
3438 
IndexedPropertyEnumeratorException(const v8::PropertyCallbackInfo<v8::Array> & info)3439 static void IndexedPropertyEnumeratorException(
3440     const v8::PropertyCallbackInfo<v8::Array>& info) {
3441   info.GetIsolate()->ThrowException(v8_num(42));
3442 }
3443 
3444 
THREADED_TEST(GetOwnPropertyNamesWithIndexedInterceptorExceptions_regress4026)3445 THREADED_TEST(GetOwnPropertyNamesWithIndexedInterceptorExceptions_regress4026) {
3446   v8::Isolate* isolate = CcTest::isolate();
3447   v8::HandleScope handle_scope(isolate);
3448   v8::Local<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New(isolate);
3449 
3450   obj_template->Set(v8_str("7"), v8::Integer::New(CcTest::isolate(), 7));
3451   obj_template->Set(v8_str("x"), v8::Integer::New(CcTest::isolate(), 42));
3452   // First just try a failing indexed interceptor.
3453   obj_template->SetHandler(v8::IndexedPropertyHandlerConfiguration(
3454       NULL, NULL, NULL, NULL, IndexedPropertyEnumeratorException));
3455 
3456   LocalContext context;
3457   v8::Local<v8::Object> global = context->Global();
3458   global->Set(context.local(), v8_str("object"),
3459               obj_template->NewInstance(context.local()).ToLocalChecked())
3460       .FromJust();
3461   v8::Local<v8::Value> result = CompileRun(
3462       "var result  = []; "
3463       "try { "
3464       "  for (var k in object) result .push(k);"
3465       "} catch (e) {"
3466       "  result  = e"
3467       "}"
3468       "result ");
3469   CHECK(!result->IsArray());
3470   CHECK(v8_num(42)->Equals(context.local(), result).FromJust());
3471 
3472   result = CompileRun(
3473       "var result = [];"
3474       "try { "
3475       "  result = Object.keys(object);"
3476       "} catch (e) {"
3477       "  result = e;"
3478       "}"
3479       "result");
3480   CHECK(!result->IsArray());
3481   CHECK(v8_num(42)->Equals(context.local(), result).FromJust());
3482 }
3483 
3484 
NamedPropertyEnumeratorException(const v8::PropertyCallbackInfo<v8::Array> & info)3485 static void NamedPropertyEnumeratorException(
3486     const v8::PropertyCallbackInfo<v8::Array>& info) {
3487   info.GetIsolate()->ThrowException(v8_num(43));
3488 }
3489 
3490 
THREADED_TEST(GetOwnPropertyNamesWithNamedInterceptorExceptions_regress4026)3491 THREADED_TEST(GetOwnPropertyNamesWithNamedInterceptorExceptions_regress4026) {
3492   v8::Isolate* isolate = CcTest::isolate();
3493   v8::HandleScope handle_scope(isolate);
3494   v8::Local<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New(isolate);
3495 
3496   obj_template->Set(v8_str("7"), v8::Integer::New(CcTest::isolate(), 7));
3497   obj_template->Set(v8_str("x"), v8::Integer::New(CcTest::isolate(), 42));
3498   // First just try a failing indexed interceptor.
3499   obj_template->SetHandler(v8::NamedPropertyHandlerConfiguration(
3500       NULL, NULL, NULL, NULL, NamedPropertyEnumeratorException));
3501 
3502   LocalContext context;
3503   v8::Local<v8::Object> global = context->Global();
3504   global->Set(context.local(), v8_str("object"),
3505               obj_template->NewInstance(context.local()).ToLocalChecked())
3506       .FromJust();
3507 
3508   v8::Local<v8::Value> result = CompileRun(
3509       "var result = []; "
3510       "try { "
3511       "  for (var k in object) result.push(k);"
3512       "} catch (e) {"
3513       "  result = e"
3514       "}"
3515       "result");
3516   CHECK(!result->IsArray());
3517   CHECK(v8_num(43)->Equals(context.local(), result).FromJust());
3518 
3519   result = CompileRun(
3520       "var result = [];"
3521       "try { "
3522       "  result = Object.keys(object);"
3523       "} catch (e) {"
3524       "  result = e;"
3525       "}"
3526       "result");
3527   CHECK(!result->IsArray());
3528   CHECK(v8_num(43)->Equals(context.local(), result).FromJust());
3529 }
3530 
3531 namespace {
3532 
3533 template <typename T>
BuildWrappedObject(v8::Isolate * isolate,T * data)3534 Local<Object> BuildWrappedObject(v8::Isolate* isolate, T* data) {
3535   auto templ = v8::ObjectTemplate::New(isolate);
3536   templ->SetInternalFieldCount(1);
3537   auto instance =
3538       templ->NewInstance(isolate->GetCurrentContext()).ToLocalChecked();
3539   instance->SetAlignedPointerInInternalField(0, data);
3540   return instance;
3541 }
3542 
3543 
3544 template <typename T>
GetWrappedObject(Local<Value> data)3545 T* GetWrappedObject(Local<Value> data) {
3546   return reinterpret_cast<T*>(
3547       Object::Cast(*data)->GetAlignedPointerFromInternalField(0));
3548 }
3549 
3550 
3551 struct AccessCheckData {
3552   int count;
3553   bool result;
3554 };
3555 
3556 AccessCheckData* g_access_check_data = nullptr;
3557 
SimpleAccessChecker(Local<v8::Context> accessing_context,Local<v8::Object> access_object,Local<v8::Value> data)3558 bool SimpleAccessChecker(Local<v8::Context> accessing_context,
3559                          Local<v8::Object> access_object,
3560                          Local<v8::Value> data) {
3561   g_access_check_data->count++;
3562   return g_access_check_data->result;
3563 }
3564 
3565 
3566 struct ShouldInterceptData {
3567   int value;
3568   bool should_intercept;
3569 };
3570 
3571 
ShouldNamedInterceptor(Local<Name> name,const v8::PropertyCallbackInfo<Value> & info)3572 void ShouldNamedInterceptor(Local<Name> name,
3573                             const v8::PropertyCallbackInfo<Value>& info) {
3574   ApiTestFuzzer::Fuzz();
3575   CheckReturnValue(info, FUNCTION_ADDR(ShouldNamedInterceptor));
3576   auto data = GetWrappedObject<ShouldInterceptData>(info.Data());
3577   if (!data->should_intercept) return;
3578   info.GetReturnValue().Set(v8_num(data->value));
3579 }
3580 
3581 
ShouldIndexedInterceptor(uint32_t,const v8::PropertyCallbackInfo<Value> & info)3582 void ShouldIndexedInterceptor(uint32_t,
3583                               const v8::PropertyCallbackInfo<Value>& info) {
3584   ApiTestFuzzer::Fuzz();
3585   CheckReturnValue(info, FUNCTION_ADDR(ShouldIndexedInterceptor));
3586   auto data = GetWrappedObject<ShouldInterceptData>(info.Data());
3587   if (!data->should_intercept) return;
3588   info.GetReturnValue().Set(v8_num(data->value));
3589 }
3590 
3591 }  // namespace
3592 
3593 
TEST(NamedAllCanReadInterceptor)3594 TEST(NamedAllCanReadInterceptor) {
3595   auto isolate = CcTest::isolate();
3596   v8::HandleScope handle_scope(isolate);
3597   LocalContext context;
3598 
3599   AccessCheckData access_check_data;
3600   access_check_data.result = true;
3601   access_check_data.count = 0;
3602 
3603   g_access_check_data = &access_check_data;
3604 
3605   ShouldInterceptData intercept_data_0;
3606   intercept_data_0.value = 239;
3607   intercept_data_0.should_intercept = true;
3608 
3609   ShouldInterceptData intercept_data_1;
3610   intercept_data_1.value = 165;
3611   intercept_data_1.should_intercept = false;
3612 
3613   auto intercepted_0 = v8::ObjectTemplate::New(isolate);
3614   {
3615     v8::NamedPropertyHandlerConfiguration conf(ShouldNamedInterceptor);
3616     conf.flags = v8::PropertyHandlerFlags::kAllCanRead;
3617     conf.data =
3618         BuildWrappedObject<ShouldInterceptData>(isolate, &intercept_data_0);
3619     intercepted_0->SetHandler(conf);
3620   }
3621 
3622   auto intercepted_1 = v8::ObjectTemplate::New(isolate);
3623   {
3624     v8::NamedPropertyHandlerConfiguration conf(ShouldNamedInterceptor);
3625     conf.flags = v8::PropertyHandlerFlags::kAllCanRead;
3626     conf.data =
3627         BuildWrappedObject<ShouldInterceptData>(isolate, &intercept_data_1);
3628     intercepted_1->SetHandler(conf);
3629   }
3630 
3631   auto checked = v8::ObjectTemplate::New(isolate);
3632   checked->SetAccessCheckCallback(SimpleAccessChecker);
3633 
3634   context->Global()
3635       ->Set(context.local(), v8_str("intercepted_0"),
3636             intercepted_0->NewInstance(context.local()).ToLocalChecked())
3637       .FromJust();
3638   context->Global()
3639       ->Set(context.local(), v8_str("intercepted_1"),
3640             intercepted_1->NewInstance(context.local()).ToLocalChecked())
3641       .FromJust();
3642   auto checked_instance =
3643       checked->NewInstance(context.local()).ToLocalChecked();
3644   checked_instance->Set(context.local(), v8_str("whatever"), v8_num(17))
3645       .FromJust();
3646   context->Global()
3647       ->Set(context.local(), v8_str("checked"), checked_instance)
3648       .FromJust();
3649   CompileRun(
3650       "checked.__proto__ = intercepted_1;"
3651       "intercepted_1.__proto__ = intercepted_0;");
3652 
3653   CHECK_EQ(3, access_check_data.count);
3654 
3655   ExpectInt32("checked.whatever", 17);
3656   CHECK(!CompileRun("Object.getOwnPropertyDescriptor(checked, 'whatever')")
3657              ->IsUndefined());
3658   CHECK_EQ(5, access_check_data.count);
3659 
3660   access_check_data.result = false;
3661   ExpectInt32("checked.whatever", intercept_data_0.value);
3662   {
3663     v8::TryCatch try_catch(isolate);
3664     CompileRun("Object.getOwnPropertyDescriptor(checked, 'whatever')");
3665     CHECK(try_catch.HasCaught());
3666   }
3667   CHECK_EQ(7, access_check_data.count);
3668 
3669   intercept_data_1.should_intercept = true;
3670   ExpectInt32("checked.whatever", intercept_data_1.value);
3671   {
3672     v8::TryCatch try_catch(isolate);
3673     CompileRun("Object.getOwnPropertyDescriptor(checked, 'whatever')");
3674     CHECK(try_catch.HasCaught());
3675   }
3676   CHECK_EQ(9, access_check_data.count);
3677   g_access_check_data = nullptr;
3678 }
3679 
3680 
TEST(IndexedAllCanReadInterceptor)3681 TEST(IndexedAllCanReadInterceptor) {
3682   auto isolate = CcTest::isolate();
3683   v8::HandleScope handle_scope(isolate);
3684   LocalContext context;
3685 
3686   AccessCheckData access_check_data;
3687   access_check_data.result = true;
3688   access_check_data.count = 0;
3689 
3690   g_access_check_data = &access_check_data;
3691 
3692   ShouldInterceptData intercept_data_0;
3693   intercept_data_0.value = 239;
3694   intercept_data_0.should_intercept = true;
3695 
3696   ShouldInterceptData intercept_data_1;
3697   intercept_data_1.value = 165;
3698   intercept_data_1.should_intercept = false;
3699 
3700   auto intercepted_0 = v8::ObjectTemplate::New(isolate);
3701   {
3702     v8::IndexedPropertyHandlerConfiguration conf(ShouldIndexedInterceptor);
3703     conf.flags = v8::PropertyHandlerFlags::kAllCanRead;
3704     conf.data =
3705         BuildWrappedObject<ShouldInterceptData>(isolate, &intercept_data_0);
3706     intercepted_0->SetHandler(conf);
3707   }
3708 
3709   auto intercepted_1 = v8::ObjectTemplate::New(isolate);
3710   {
3711     v8::IndexedPropertyHandlerConfiguration conf(ShouldIndexedInterceptor);
3712     conf.flags = v8::PropertyHandlerFlags::kAllCanRead;
3713     conf.data =
3714         BuildWrappedObject<ShouldInterceptData>(isolate, &intercept_data_1);
3715     intercepted_1->SetHandler(conf);
3716   }
3717 
3718   auto checked = v8::ObjectTemplate::New(isolate);
3719   checked->SetAccessCheckCallback(SimpleAccessChecker);
3720 
3721   context->Global()
3722       ->Set(context.local(), v8_str("intercepted_0"),
3723             intercepted_0->NewInstance(context.local()).ToLocalChecked())
3724       .FromJust();
3725   context->Global()
3726       ->Set(context.local(), v8_str("intercepted_1"),
3727             intercepted_1->NewInstance(context.local()).ToLocalChecked())
3728       .FromJust();
3729   auto checked_instance =
3730       checked->NewInstance(context.local()).ToLocalChecked();
3731   context->Global()
3732       ->Set(context.local(), v8_str("checked"), checked_instance)
3733       .FromJust();
3734   checked_instance->Set(context.local(), 15, v8_num(17)).FromJust();
3735   CompileRun(
3736       "checked.__proto__ = intercepted_1;"
3737       "intercepted_1.__proto__ = intercepted_0;");
3738 
3739   CHECK_EQ(3, access_check_data.count);
3740 
3741   access_check_data.result = true;
3742   ExpectInt32("checked[15]", 17);
3743   CHECK(!CompileRun("Object.getOwnPropertyDescriptor(checked, '15')")
3744              ->IsUndefined());
3745   CHECK_EQ(5, access_check_data.count);
3746 
3747   access_check_data.result = false;
3748   ExpectInt32("checked[15]", intercept_data_0.value);
3749   {
3750     v8::TryCatch try_catch(isolate);
3751     CompileRun("Object.getOwnPropertyDescriptor(checked, '15')");
3752     CHECK(try_catch.HasCaught());
3753   }
3754   CHECK_EQ(7, access_check_data.count);
3755 
3756   intercept_data_1.should_intercept = true;
3757   ExpectInt32("checked[15]", intercept_data_1.value);
3758   {
3759     v8::TryCatch try_catch(isolate);
3760     CompileRun("Object.getOwnPropertyDescriptor(checked, '15')");
3761     CHECK(try_catch.HasCaught());
3762   }
3763   CHECK_EQ(9, access_check_data.count);
3764 
3765   g_access_check_data = nullptr;
3766 }
3767 
3768 
THREADED_TEST(NonMaskingInterceptorOwnProperty)3769 THREADED_TEST(NonMaskingInterceptorOwnProperty) {
3770   auto isolate = CcTest::isolate();
3771   v8::HandleScope handle_scope(isolate);
3772   LocalContext context;
3773 
3774   ShouldInterceptData intercept_data;
3775   intercept_data.value = 239;
3776   intercept_data.should_intercept = true;
3777 
3778   auto interceptor_templ = v8::ObjectTemplate::New(isolate);
3779   v8::NamedPropertyHandlerConfiguration conf(ShouldNamedInterceptor);
3780   conf.flags = v8::PropertyHandlerFlags::kNonMasking;
3781   conf.data = BuildWrappedObject<ShouldInterceptData>(isolate, &intercept_data);
3782   interceptor_templ->SetHandler(conf);
3783 
3784   auto interceptor =
3785       interceptor_templ->NewInstance(context.local()).ToLocalChecked();
3786   context->Global()
3787       ->Set(context.local(), v8_str("obj"), interceptor)
3788       .FromJust();
3789 
3790   ExpectInt32("obj.whatever", 239);
3791 
3792   CompileRun("obj.whatever = 4;");
3793   ExpectInt32("obj.whatever", 4);
3794 
3795   CompileRun("delete obj.whatever;");
3796   ExpectInt32("obj.whatever", 239);
3797 }
3798 
3799 
THREADED_TEST(NonMaskingInterceptorPrototypeProperty)3800 THREADED_TEST(NonMaskingInterceptorPrototypeProperty) {
3801   auto isolate = CcTest::isolate();
3802   v8::HandleScope handle_scope(isolate);
3803   LocalContext context;
3804 
3805   ShouldInterceptData intercept_data;
3806   intercept_data.value = 239;
3807   intercept_data.should_intercept = true;
3808 
3809   auto interceptor_templ = v8::ObjectTemplate::New(isolate);
3810   v8::NamedPropertyHandlerConfiguration conf(ShouldNamedInterceptor);
3811   conf.flags = v8::PropertyHandlerFlags::kNonMasking;
3812   conf.data = BuildWrappedObject<ShouldInterceptData>(isolate, &intercept_data);
3813   interceptor_templ->SetHandler(conf);
3814 
3815   auto interceptor =
3816       interceptor_templ->NewInstance(context.local()).ToLocalChecked();
3817   context->Global()
3818       ->Set(context.local(), v8_str("obj"), interceptor)
3819       .FromJust();
3820 
3821   ExpectInt32("obj.whatever", 239);
3822 
3823   CompileRun("obj.__proto__ = {'whatever': 4};");
3824   ExpectInt32("obj.whatever", 4);
3825 
3826   CompileRun("delete obj.__proto__.whatever;");
3827   ExpectInt32("obj.whatever", 239);
3828 }
3829 
3830 
THREADED_TEST(NonMaskingInterceptorPrototypePropertyIC)3831 THREADED_TEST(NonMaskingInterceptorPrototypePropertyIC) {
3832   auto isolate = CcTest::isolate();
3833   v8::HandleScope handle_scope(isolate);
3834   LocalContext context;
3835 
3836   ShouldInterceptData intercept_data;
3837   intercept_data.value = 239;
3838   intercept_data.should_intercept = true;
3839 
3840   auto interceptor_templ = v8::ObjectTemplate::New(isolate);
3841   v8::NamedPropertyHandlerConfiguration conf(ShouldNamedInterceptor);
3842   conf.flags = v8::PropertyHandlerFlags::kNonMasking;
3843   conf.data = BuildWrappedObject<ShouldInterceptData>(isolate, &intercept_data);
3844   interceptor_templ->SetHandler(conf);
3845 
3846   auto interceptor =
3847       interceptor_templ->NewInstance(context.local()).ToLocalChecked();
3848   context->Global()
3849       ->Set(context.local(), v8_str("obj"), interceptor)
3850       .FromJust();
3851 
3852   CompileRun(
3853       "outer = {};"
3854       "outer.__proto__ = obj;"
3855       "function f(obj) {"
3856       "  var x;"
3857       "  for (var i = 0; i < 4; i++) {"
3858       "    x = obj.whatever;"
3859       "  }"
3860       "  return x;"
3861       "}");
3862 
3863   // Receiver == holder.
3864   CompileRun("obj.__proto__ = null;");
3865   ExpectInt32("f(obj)", 239);
3866   ExpectInt32("f(outer)", 239);
3867 
3868   // Receiver != holder.
3869   CompileRun("Object.setPrototypeOf(obj, {});");
3870   ExpectInt32("f(obj)", 239);
3871   ExpectInt32("f(outer)", 239);
3872 
3873   // Masked value on prototype.
3874   CompileRun("obj.__proto__.whatever = 4;");
3875   CompileRun("obj.__proto__.__proto__ = { 'whatever' : 5 };");
3876   ExpectInt32("f(obj)", 4);
3877   ExpectInt32("f(outer)", 4);
3878 
3879   // Masked value on prototype prototype.
3880   CompileRun("delete obj.__proto__.whatever;");
3881   ExpectInt32("f(obj)", 5);
3882   ExpectInt32("f(outer)", 5);
3883 
3884   // Reset.
3885   CompileRun("delete obj.__proto__.__proto__.whatever;");
3886   ExpectInt32("f(obj)", 239);
3887   ExpectInt32("f(outer)", 239);
3888 
3889   // Masked value on self.
3890   CompileRun("obj.whatever = 4;");
3891   ExpectInt32("f(obj)", 4);
3892   ExpectInt32("f(outer)", 4);
3893 
3894   // Reset.
3895   CompileRun("delete obj.whatever;");
3896   ExpectInt32("f(obj)", 239);
3897   ExpectInt32("f(outer)", 239);
3898 
3899   CompileRun("outer.whatever = 4;");
3900   ExpectInt32("f(obj)", 239);
3901   ExpectInt32("f(outer)", 4);
3902 }
3903 
3904 
3905 namespace {
3906 
DatabaseGetter(Local<Name> name,const v8::PropertyCallbackInfo<Value> & info)3907 void DatabaseGetter(Local<Name> name,
3908                     const v8::PropertyCallbackInfo<Value>& info) {
3909   ApiTestFuzzer::Fuzz();
3910   auto context = info.GetIsolate()->GetCurrentContext();
3911   Local<v8::Object> db = info.Holder()
3912                              ->GetRealNamedProperty(context, v8_str("db"))
3913                              .ToLocalChecked()
3914                              .As<v8::Object>();
3915   if (!db->Has(context, name).FromJust()) return;
3916   info.GetReturnValue().Set(db->Get(context, name).ToLocalChecked());
3917 }
3918 
3919 
DatabaseSetter(Local<Name> name,Local<Value> value,const v8::PropertyCallbackInfo<Value> & info)3920 void DatabaseSetter(Local<Name> name, Local<Value> value,
3921                     const v8::PropertyCallbackInfo<Value>& info) {
3922   ApiTestFuzzer::Fuzz();
3923   auto context = info.GetIsolate()->GetCurrentContext();
3924   if (name->Equals(context, v8_str("db")).FromJust()) return;
3925   Local<v8::Object> db = info.Holder()
3926                              ->GetRealNamedProperty(context, v8_str("db"))
3927                              .ToLocalChecked()
3928                              .As<v8::Object>();
3929   db->Set(context, name, value).FromJust();
3930   info.GetReturnValue().Set(value);
3931 }
3932 
3933 }  // namespace
3934 
3935 
THREADED_TEST(NonMaskingInterceptorGlobalEvalRegression)3936 THREADED_TEST(NonMaskingInterceptorGlobalEvalRegression) {
3937   auto isolate = CcTest::isolate();
3938   v8::HandleScope handle_scope(isolate);
3939   LocalContext context;
3940 
3941   auto interceptor_templ = v8::ObjectTemplate::New(isolate);
3942   v8::NamedPropertyHandlerConfiguration conf(DatabaseGetter, DatabaseSetter);
3943   conf.flags = v8::PropertyHandlerFlags::kNonMasking;
3944   interceptor_templ->SetHandler(conf);
3945 
3946   context->Global()
3947       ->Set(context.local(), v8_str("intercepted_1"),
3948             interceptor_templ->NewInstance(context.local()).ToLocalChecked())
3949       .FromJust();
3950   context->Global()
3951       ->Set(context.local(), v8_str("intercepted_2"),
3952             interceptor_templ->NewInstance(context.local()).ToLocalChecked())
3953       .FromJust();
3954 
3955   // Init dbs.
3956   CompileRun(
3957       "intercepted_1.db = {};"
3958       "intercepted_2.db = {};");
3959 
3960   ExpectInt32(
3961       "var obj = intercepted_1;"
3962       "obj.x = 4;"
3963       "eval('obj.x');"
3964       "eval('obj.x');"
3965       "eval('obj.x');"
3966       "obj = intercepted_2;"
3967       "obj.x = 9;"
3968       "eval('obj.x');",
3969       9);
3970 }
3971 
CheckReceiver(Local<Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)3972 static void CheckReceiver(Local<Name> name,
3973                           const v8::PropertyCallbackInfo<v8::Value>& info) {
3974   CHECK(info.This()->IsObject());
3975 }
3976 
TEST(Regress609134Interceptor)3977 TEST(Regress609134Interceptor) {
3978   LocalContext env;
3979   v8::Isolate* isolate = env->GetIsolate();
3980   v8::HandleScope scope(isolate);
3981   auto fun_templ = v8::FunctionTemplate::New(isolate);
3982   fun_templ->InstanceTemplate()->SetHandler(
3983       v8::NamedPropertyHandlerConfiguration(CheckReceiver));
3984 
3985   CHECK(env->Global()
3986             ->Set(env.local(), v8_str("Fun"),
3987                   fun_templ->GetFunction(env.local()).ToLocalChecked())
3988             .FromJust());
3989 
3990   CompileRun(
3991       "var f = new Fun();"
3992       "Number.prototype.__proto__ = f;"
3993       "var a = 42;"
3994       "for (var i = 0; i<3; i++) { a.foo; }");
3995 }
3996