• 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 
InterceptorLoadICGetter0(Local<Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)858 static void InterceptorLoadICGetter0(
859     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
860   ApiTestFuzzer::Fuzz();
861   CHECK(v8_str("x")
862             ->Equals(info.GetIsolate()->GetCurrentContext(), name)
863             .FromJust());
864   info.GetReturnValue().Set(v8::Integer::New(info.GetIsolate(), 0));
865 }
866 
867 
THREADED_TEST(InterceptorReturningZero)868 THREADED_TEST(InterceptorReturningZero) {
869   CheckInterceptorLoadIC(InterceptorLoadICGetter0, "o.x == undefined ? 1 : 0",
870                          0);
871 }
872 
873 
InterceptorStoreICSetter(Local<Name> key,Local<Value> value,const v8::PropertyCallbackInfo<v8::Value> & info)874 static void InterceptorStoreICSetter(
875     Local<Name> key, Local<Value> value,
876     const v8::PropertyCallbackInfo<v8::Value>& info) {
877   v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
878   CHECK(v8_str("x")->Equals(context, key).FromJust());
879   CHECK_EQ(42, value->Int32Value(context).FromJust());
880   info.GetReturnValue().Set(value);
881 }
882 
883 
884 // This test should hit the store IC for the interceptor case.
THREADED_TEST(InterceptorStoreIC)885 THREADED_TEST(InterceptorStoreIC) {
886   v8::Isolate* isolate = CcTest::isolate();
887   v8::HandleScope scope(isolate);
888   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
889   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
890       InterceptorLoadICGetter, InterceptorStoreICSetter, 0, 0, 0,
891       v8_str("data")));
892   LocalContext context;
893   context->Global()
894       ->Set(context.local(), v8_str("o"),
895             templ->NewInstance(context.local()).ToLocalChecked())
896       .FromJust();
897   CompileRun(
898       "for (var i = 0; i < 1000; i++) {"
899       "  o.x = 42;"
900       "}");
901 }
902 
903 
THREADED_TEST(InterceptorStoreICWithNoSetter)904 THREADED_TEST(InterceptorStoreICWithNoSetter) {
905   v8::Isolate* isolate = CcTest::isolate();
906   v8::HandleScope scope(isolate);
907   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
908   templ->SetHandler(
909       v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
910   LocalContext context;
911   context->Global()
912       ->Set(context.local(), v8_str("o"),
913             templ->NewInstance(context.local()).ToLocalChecked())
914       .FromJust();
915   v8::Local<Value> value = CompileRun(
916       "for (var i = 0; i < 1000; i++) {"
917       "  o.y = 239;"
918       "}"
919       "42 + o.y");
920   CHECK_EQ(239 + 42, value->Int32Value(context.local()).FromJust());
921 }
922 
923 
THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors)924 THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
925   v8::HandleScope scope(CcTest::isolate());
926   Local<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
927   Local<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
928   child->Inherit(parent);
929   AddAccessor(parent, v8_str("age"), SimpleAccessorGetter,
930               SimpleAccessorSetter);
931   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
932   LocalContext env;
933   env->Global()
934       ->Set(env.local(), v8_str("Child"),
935             child->GetFunction(env.local()).ToLocalChecked())
936       .FromJust();
937   CompileRun(
938       "var child = new Child;"
939       "child.age = 10;");
940   ExpectBoolean("child.hasOwnProperty('age')", false);
941   ExpectInt32("child.age", 10);
942   ExpectInt32("child.accessor_age", 10);
943 }
944 
945 
THREADED_TEST(LegacyInterceptorDoesNotSeeSymbols)946 THREADED_TEST(LegacyInterceptorDoesNotSeeSymbols) {
947   LocalContext env;
948   v8::Isolate* isolate = CcTest::isolate();
949   v8::HandleScope scope(isolate);
950   Local<FunctionTemplate> parent = FunctionTemplate::New(isolate);
951   Local<FunctionTemplate> child = FunctionTemplate::New(isolate);
952   v8::Local<v8::Symbol> age = v8::Symbol::New(isolate, v8_str("age"));
953 
954   child->Inherit(parent);
955   AddAccessor(parent, age, SymbolAccessorGetter, SymbolAccessorSetter);
956   AddInterceptor(child, StringInterceptorGetter, StringInterceptorSetter);
957 
958   env->Global()
959       ->Set(env.local(), v8_str("Child"),
960             child->GetFunction(env.local()).ToLocalChecked())
961       .FromJust();
962   env->Global()->Set(env.local(), v8_str("age"), age).FromJust();
963   CompileRun(
964       "var child = new Child;"
965       "child[age] = 10;");
966   ExpectInt32("child[age]", 10);
967   ExpectBoolean("child.hasOwnProperty('age')", false);
968   ExpectBoolean("child.hasOwnProperty('accessor_age')", true);
969 }
970 
971 
THREADED_TEST(GenericInterceptorDoesSeeSymbols)972 THREADED_TEST(GenericInterceptorDoesSeeSymbols) {
973   LocalContext env;
974   v8::Isolate* isolate = CcTest::isolate();
975   v8::HandleScope scope(isolate);
976   Local<FunctionTemplate> parent = FunctionTemplate::New(isolate);
977   Local<FunctionTemplate> child = FunctionTemplate::New(isolate);
978   v8::Local<v8::Symbol> age = v8::Symbol::New(isolate, v8_str("age"));
979   v8::Local<v8::Symbol> anon = v8::Symbol::New(isolate);
980 
981   child->Inherit(parent);
982   AddAccessor(parent, age, SymbolAccessorGetter, SymbolAccessorSetter);
983   AddInterceptor(child, GenericInterceptorGetter, GenericInterceptorSetter);
984 
985   env->Global()
986       ->Set(env.local(), v8_str("Child"),
987             child->GetFunction(env.local()).ToLocalChecked())
988       .FromJust();
989   env->Global()->Set(env.local(), v8_str("age"), age).FromJust();
990   env->Global()->Set(env.local(), v8_str("anon"), anon).FromJust();
991   CompileRun(
992       "var child = new Child;"
993       "child[age] = 10;");
994   ExpectInt32("child[age]", 10);
995   ExpectInt32("child._sym_age", 10);
996 
997   // Check that it also sees strings.
998   CompileRun("child.foo = 47");
999   ExpectInt32("child.foo", 47);
1000   ExpectInt32("child._str_foo", 47);
1001 
1002   // Check that the interceptor can punt (in this case, on anonymous symbols).
1003   CompileRun("child[anon] = 31337");
1004   ExpectInt32("child[anon]", 31337);
1005 }
1006 
1007 
THREADED_TEST(NamedPropertyHandlerGetter)1008 THREADED_TEST(NamedPropertyHandlerGetter) {
1009   echo_named_call_count = 0;
1010   v8::HandleScope scope(CcTest::isolate());
1011   v8::Local<v8::FunctionTemplate> templ =
1012       v8::FunctionTemplate::New(CcTest::isolate());
1013   templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
1014       EchoNamedProperty, 0, 0, 0, 0, v8_str("data")));
1015   LocalContext env;
1016   env->Global()
1017       ->Set(env.local(), v8_str("obj"), templ->GetFunction(env.local())
1018                                             .ToLocalChecked()
1019                                             ->NewInstance(env.local())
1020                                             .ToLocalChecked())
1021       .FromJust();
1022   CHECK_EQ(echo_named_call_count, 0);
1023   v8_compile("obj.x")->Run(env.local()).ToLocalChecked();
1024   CHECK_EQ(echo_named_call_count, 1);
1025   const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
1026   v8::Local<Value> str = CompileRun(code);
1027   String::Utf8Value value(str);
1028   CHECK_EQ(0, strcmp(*value, "oddlepoddle"));
1029   // Check default behavior
1030   CHECK_EQ(10, v8_compile("obj.flob = 10;")
1031                    ->Run(env.local())
1032                    .ToLocalChecked()
1033                    ->Int32Value(env.local())
1034                    .FromJust());
1035   CHECK(v8_compile("'myProperty' in obj")
1036             ->Run(env.local())
1037             .ToLocalChecked()
1038             ->BooleanValue(env.local())
1039             .FromJust());
1040   CHECK(v8_compile("delete obj.myProperty")
1041             ->Run(env.local())
1042             .ToLocalChecked()
1043             ->BooleanValue(env.local())
1044             .FromJust());
1045 }
1046 
1047 
1048 int echo_indexed_call_count = 0;
1049 
1050 
EchoIndexedProperty(uint32_t index,const v8::PropertyCallbackInfo<v8::Value> & info)1051 static void EchoIndexedProperty(
1052     uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) {
1053   ApiTestFuzzer::Fuzz();
1054   CHECK(v8_num(637)
1055             ->Equals(info.GetIsolate()->GetCurrentContext(), info.Data())
1056             .FromJust());
1057   echo_indexed_call_count++;
1058   info.GetReturnValue().Set(v8_num(index));
1059 }
1060 
1061 
THREADED_TEST(IndexedPropertyHandlerGetter)1062 THREADED_TEST(IndexedPropertyHandlerGetter) {
1063   v8::Isolate* isolate = CcTest::isolate();
1064   v8::HandleScope scope(isolate);
1065   v8::Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
1066   templ->InstanceTemplate()->SetHandler(v8::IndexedPropertyHandlerConfiguration(
1067       EchoIndexedProperty, 0, 0, 0, 0, v8_num(637)));
1068   LocalContext env;
1069   env->Global()
1070       ->Set(env.local(), v8_str("obj"), templ->GetFunction(env.local())
1071                                             .ToLocalChecked()
1072                                             ->NewInstance(env.local())
1073                                             .ToLocalChecked())
1074       .FromJust();
1075   Local<Script> script = v8_compile("obj[900]");
1076   CHECK_EQ(script->Run(env.local())
1077                .ToLocalChecked()
1078                ->Int32Value(env.local())
1079                .FromJust(),
1080            900);
1081 }
1082 
1083 
THREADED_TEST(PropertyHandlerInPrototype)1084 THREADED_TEST(PropertyHandlerInPrototype) {
1085   LocalContext env;
1086   v8::Isolate* isolate = env->GetIsolate();
1087   v8::HandleScope scope(isolate);
1088 
1089   // Set up a prototype chain with three interceptors.
1090   v8::Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
1091   templ->InstanceTemplate()->SetHandler(v8::IndexedPropertyHandlerConfiguration(
1092       CheckThisIndexedPropertyHandler, CheckThisIndexedPropertySetter,
1093       CheckThisIndexedPropertyQuery, CheckThisIndexedPropertyDeleter,
1094       CheckThisIndexedPropertyEnumerator));
1095 
1096   templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
1097       CheckThisNamedPropertyHandler, CheckThisNamedPropertySetter,
1098       CheckThisNamedPropertyQuery, CheckThisNamedPropertyDeleter,
1099       CheckThisNamedPropertyEnumerator));
1100 
1101   bottom = templ->GetFunction(env.local())
1102                .ToLocalChecked()
1103                ->NewInstance(env.local())
1104                .ToLocalChecked();
1105   Local<v8::Object> top = templ->GetFunction(env.local())
1106                               .ToLocalChecked()
1107                               ->NewInstance(env.local())
1108                               .ToLocalChecked();
1109   Local<v8::Object> middle = templ->GetFunction(env.local())
1110                                  .ToLocalChecked()
1111                                  ->NewInstance(env.local())
1112                                  .ToLocalChecked();
1113 
1114   bottom->SetPrototype(env.local(), middle).FromJust();
1115   middle->SetPrototype(env.local(), top).FromJust();
1116   env->Global()->Set(env.local(), v8_str("obj"), bottom).FromJust();
1117 
1118   // Indexed and named get.
1119   CompileRun("obj[0]");
1120   CompileRun("obj.x");
1121 
1122   // Indexed and named set.
1123   CompileRun("obj[1] = 42");
1124   CompileRun("obj.y = 42");
1125 
1126   // Indexed and named query.
1127   CompileRun("0 in obj");
1128   CompileRun("'x' in obj");
1129 
1130   // Indexed and named deleter.
1131   CompileRun("delete obj[0]");
1132   CompileRun("delete obj.x");
1133 
1134   // Enumerators.
1135   CompileRun("for (var p in obj) ;");
1136 }
1137 
1138 
1139 bool is_bootstrapping = false;
PrePropertyHandlerGet(Local<Name> key,const v8::PropertyCallbackInfo<v8::Value> & info)1140 static void PrePropertyHandlerGet(
1141     Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>& info) {
1142   ApiTestFuzzer::Fuzz();
1143   if (!is_bootstrapping &&
1144       v8_str("pre")
1145           ->Equals(info.GetIsolate()->GetCurrentContext(), key)
1146           .FromJust()) {
1147     info.GetReturnValue().Set(v8_str("PrePropertyHandler: pre"));
1148   }
1149 }
1150 
1151 
PrePropertyHandlerQuery(Local<Name> key,const v8::PropertyCallbackInfo<v8::Integer> & info)1152 static void PrePropertyHandlerQuery(
1153     Local<Name> key, const v8::PropertyCallbackInfo<v8::Integer>& info) {
1154   if (!is_bootstrapping &&
1155       v8_str("pre")
1156           ->Equals(info.GetIsolate()->GetCurrentContext(), key)
1157           .FromJust()) {
1158     info.GetReturnValue().Set(static_cast<int32_t>(v8::None));
1159   }
1160 }
1161 
1162 
THREADED_TEST(PrePropertyHandler)1163 THREADED_TEST(PrePropertyHandler) {
1164   v8::Isolate* isolate = CcTest::isolate();
1165   v8::HandleScope scope(isolate);
1166   v8::Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
1167   desc->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
1168       PrePropertyHandlerGet, 0, PrePropertyHandlerQuery));
1169   is_bootstrapping = true;
1170   LocalContext env(NULL, desc->InstanceTemplate());
1171   is_bootstrapping = false;
1172   CompileRun("var pre = 'Object: pre'; var on = 'Object: on';");
1173   v8::Local<Value> result_pre = CompileRun("pre");
1174   CHECK(v8_str("PrePropertyHandler: pre")
1175             ->Equals(env.local(), result_pre)
1176             .FromJust());
1177   v8::Local<Value> result_on = CompileRun("on");
1178   CHECK(v8_str("Object: on")->Equals(env.local(), result_on).FromJust());
1179   v8::Local<Value> result_post = CompileRun("post");
1180   CHECK(result_post.IsEmpty());
1181 }
1182 
1183 
THREADED_TEST(EmptyInterceptorBreakTransitions)1184 THREADED_TEST(EmptyInterceptorBreakTransitions) {
1185   v8::HandleScope scope(CcTest::isolate());
1186   Local<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
1187   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
1188   LocalContext env;
1189   env->Global()
1190       ->Set(env.local(), v8_str("Constructor"),
1191             templ->GetFunction(env.local()).ToLocalChecked())
1192       .FromJust();
1193   CompileRun(
1194       "var o1 = new Constructor;"
1195       "o1.a = 1;"  // Ensure a and x share the descriptor array.
1196       "Object.defineProperty(o1, 'x', {value: 10});");
1197   CompileRun(
1198       "var o2 = new Constructor;"
1199       "o2.a = 1;"
1200       "Object.defineProperty(o2, 'x', {value: 10});");
1201 }
1202 
1203 
THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors)1204 THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) {
1205   v8::Isolate* isolate = CcTest::isolate();
1206   v8::HandleScope scope(isolate);
1207   Local<FunctionTemplate> parent = FunctionTemplate::New(isolate);
1208   Local<FunctionTemplate> child = FunctionTemplate::New(isolate);
1209   child->Inherit(parent);
1210   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1211   LocalContext env;
1212   env->Global()
1213       ->Set(env.local(), v8_str("Child"),
1214             child->GetFunction(env.local()).ToLocalChecked())
1215       .FromJust();
1216   CompileRun(
1217       "var child = new Child;"
1218       "var parent = child.__proto__;"
1219       "Object.defineProperty(parent, 'age', "
1220       "  {get: function(){ return this.accessor_age; }, "
1221       "   set: function(v){ this.accessor_age = v; }, "
1222       "   enumerable: true, configurable: true});"
1223       "child.age = 10;");
1224   ExpectBoolean("child.hasOwnProperty('age')", false);
1225   ExpectInt32("child.age", 10);
1226   ExpectInt32("child.accessor_age", 10);
1227 }
1228 
1229 
THREADED_TEST(EmptyInterceptorDoesNotShadowApiAccessors)1230 THREADED_TEST(EmptyInterceptorDoesNotShadowApiAccessors) {
1231   v8::Isolate* isolate = CcTest::isolate();
1232   v8::HandleScope scope(isolate);
1233   Local<FunctionTemplate> parent = FunctionTemplate::New(isolate);
1234   auto returns_42 = FunctionTemplate::New(isolate, Returns42);
1235   parent->PrototypeTemplate()->SetAccessorProperty(v8_str("age"), returns_42);
1236   Local<FunctionTemplate> child = FunctionTemplate::New(isolate);
1237   child->Inherit(parent);
1238   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1239   LocalContext env;
1240   env->Global()
1241       ->Set(env.local(), v8_str("Child"),
1242             child->GetFunction(env.local()).ToLocalChecked())
1243       .FromJust();
1244   CompileRun(
1245       "var child = new Child;"
1246       "var parent = child.__proto__;");
1247   ExpectBoolean("child.hasOwnProperty('age')", false);
1248   ExpectInt32("child.age", 42);
1249   // Check interceptor followup.
1250   ExpectInt32(
1251       "var result;"
1252       "for (var i = 0; i < 4; ++i) {"
1253       "  result = child.age;"
1254       "}"
1255       "result",
1256       42);
1257 }
1258 
1259 
THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties)1260 THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) {
1261   v8::Isolate* isolate = CcTest::isolate();
1262   v8::HandleScope scope(isolate);
1263   Local<FunctionTemplate> parent = FunctionTemplate::New(isolate);
1264   Local<FunctionTemplate> child = FunctionTemplate::New(isolate);
1265   child->Inherit(parent);
1266   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1267   LocalContext env;
1268   env->Global()
1269       ->Set(env.local(), v8_str("Child"),
1270             child->GetFunction(env.local()).ToLocalChecked())
1271       .FromJust();
1272   CompileRun(
1273       "var child = new Child;"
1274       "var parent = child.__proto__;"
1275       "parent.name = 'Alice';");
1276   ExpectBoolean("child.hasOwnProperty('name')", false);
1277   ExpectString("child.name", "Alice");
1278   CompileRun("child.name = 'Bob';");
1279   ExpectString("child.name", "Bob");
1280   ExpectBoolean("child.hasOwnProperty('name')", true);
1281   ExpectString("parent.name", "Alice");
1282 }
1283 
1284 
THREADED_TEST(SwitchFromInterceptorToAccessor)1285 THREADED_TEST(SwitchFromInterceptorToAccessor) {
1286   v8::HandleScope scope(CcTest::isolate());
1287   Local<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
1288   AddAccessor(templ, v8_str("age"), SimpleAccessorGetter, SimpleAccessorSetter);
1289   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1290   LocalContext env;
1291   env->Global()
1292       ->Set(env.local(), v8_str("Obj"),
1293             templ->GetFunction(env.local()).ToLocalChecked())
1294       .FromJust();
1295   CompileRun(
1296       "var obj = new Obj;"
1297       "function setAge(i){ obj.age = i; };"
1298       "for(var i = 0; i <= 10000; i++) setAge(i);");
1299   // All i < 10000 go to the interceptor.
1300   ExpectInt32("obj.interceptor_age", 9999);
1301   // The last i goes to the accessor.
1302   ExpectInt32("obj.accessor_age", 10000);
1303 }
1304 
1305 
THREADED_TEST(SwitchFromAccessorToInterceptor)1306 THREADED_TEST(SwitchFromAccessorToInterceptor) {
1307   v8::HandleScope scope(CcTest::isolate());
1308   Local<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
1309   AddAccessor(templ, v8_str("age"), SimpleAccessorGetter, SimpleAccessorSetter);
1310   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1311   LocalContext env;
1312   env->Global()
1313       ->Set(env.local(), v8_str("Obj"),
1314             templ->GetFunction(env.local()).ToLocalChecked())
1315       .FromJust();
1316   CompileRun(
1317       "var obj = new Obj;"
1318       "function setAge(i){ obj.age = i; };"
1319       "for(var i = 20000; i >= 9999; i--) setAge(i);");
1320   // All i >= 10000 go to the accessor.
1321   ExpectInt32("obj.accessor_age", 10000);
1322   // The last i goes to the interceptor.
1323   ExpectInt32("obj.interceptor_age", 9999);
1324 }
1325 
1326 
THREADED_TEST(SwitchFromInterceptorToAccessorWithInheritance)1327 THREADED_TEST(SwitchFromInterceptorToAccessorWithInheritance) {
1328   v8::HandleScope scope(CcTest::isolate());
1329   Local<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
1330   Local<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
1331   child->Inherit(parent);
1332   AddAccessor(parent, v8_str("age"), SimpleAccessorGetter,
1333               SimpleAccessorSetter);
1334   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1335   LocalContext env;
1336   env->Global()
1337       ->Set(env.local(), v8_str("Child"),
1338             child->GetFunction(env.local()).ToLocalChecked())
1339       .FromJust();
1340   CompileRun(
1341       "var child = new Child;"
1342       "function setAge(i){ child.age = i; };"
1343       "for(var i = 0; i <= 10000; i++) setAge(i);");
1344   // All i < 10000 go to the interceptor.
1345   ExpectInt32("child.interceptor_age", 9999);
1346   // The last i goes to the accessor.
1347   ExpectInt32("child.accessor_age", 10000);
1348 }
1349 
1350 
THREADED_TEST(SwitchFromAccessorToInterceptorWithInheritance)1351 THREADED_TEST(SwitchFromAccessorToInterceptorWithInheritance) {
1352   v8::HandleScope scope(CcTest::isolate());
1353   Local<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
1354   Local<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
1355   child->Inherit(parent);
1356   AddAccessor(parent, v8_str("age"), SimpleAccessorGetter,
1357               SimpleAccessorSetter);
1358   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1359   LocalContext env;
1360   env->Global()
1361       ->Set(env.local(), v8_str("Child"),
1362             child->GetFunction(env.local()).ToLocalChecked())
1363       .FromJust();
1364   CompileRun(
1365       "var child = new Child;"
1366       "function setAge(i){ child.age = i; };"
1367       "for(var i = 20000; i >= 9999; i--) setAge(i);");
1368   // All i >= 10000 go to the accessor.
1369   ExpectInt32("child.accessor_age", 10000);
1370   // The last i goes to the interceptor.
1371   ExpectInt32("child.interceptor_age", 9999);
1372 }
1373 
1374 
THREADED_TEST(SwitchFromInterceptorToJSAccessor)1375 THREADED_TEST(SwitchFromInterceptorToJSAccessor) {
1376   v8::HandleScope scope(CcTest::isolate());
1377   Local<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
1378   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1379   LocalContext env;
1380   env->Global()
1381       ->Set(env.local(), v8_str("Obj"),
1382             templ->GetFunction(env.local()).ToLocalChecked())
1383       .FromJust();
1384   CompileRun(
1385       "var obj = new Obj;"
1386       "function setter(i) { this.accessor_age = i; };"
1387       "function getter() { return this.accessor_age; };"
1388       "function setAge(i) { obj.age = i; };"
1389       "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
1390       "for(var i = 0; i <= 10000; i++) setAge(i);");
1391   // All i < 10000 go to the interceptor.
1392   ExpectInt32("obj.interceptor_age", 9999);
1393   // The last i goes to the JavaScript accessor.
1394   ExpectInt32("obj.accessor_age", 10000);
1395   // The installed JavaScript getter is still intact.
1396   // This last part is a regression test for issue 1651 and relies on the fact
1397   // that both interceptor and accessor are being installed on the same object.
1398   ExpectInt32("obj.age", 10000);
1399   ExpectBoolean("obj.hasOwnProperty('age')", true);
1400   ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
1401 }
1402 
1403 
THREADED_TEST(SwitchFromJSAccessorToInterceptor)1404 THREADED_TEST(SwitchFromJSAccessorToInterceptor) {
1405   v8::HandleScope scope(CcTest::isolate());
1406   Local<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
1407   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1408   LocalContext env;
1409   env->Global()
1410       ->Set(env.local(), v8_str("Obj"),
1411             templ->GetFunction(env.local()).ToLocalChecked())
1412       .FromJust();
1413   CompileRun(
1414       "var obj = new Obj;"
1415       "function setter(i) { this.accessor_age = i; };"
1416       "function getter() { return this.accessor_age; };"
1417       "function setAge(i) { obj.age = i; };"
1418       "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
1419       "for(var i = 20000; i >= 9999; i--) setAge(i);");
1420   // All i >= 10000 go to the accessor.
1421   ExpectInt32("obj.accessor_age", 10000);
1422   // The last i goes to the interceptor.
1423   ExpectInt32("obj.interceptor_age", 9999);
1424   // The installed JavaScript getter is still intact.
1425   // This last part is a regression test for issue 1651 and relies on the fact
1426   // that both interceptor and accessor are being installed on the same object.
1427   ExpectInt32("obj.age", 10000);
1428   ExpectBoolean("obj.hasOwnProperty('age')", true);
1429   ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
1430 }
1431 
1432 
THREADED_TEST(SwitchFromInterceptorToProperty)1433 THREADED_TEST(SwitchFromInterceptorToProperty) {
1434   v8::HandleScope scope(CcTest::isolate());
1435   Local<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
1436   Local<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
1437   child->Inherit(parent);
1438   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1439   LocalContext env;
1440   env->Global()
1441       ->Set(env.local(), v8_str("Child"),
1442             child->GetFunction(env.local()).ToLocalChecked())
1443       .FromJust();
1444   CompileRun(
1445       "var child = new Child;"
1446       "function setAge(i){ child.age = i; };"
1447       "for(var i = 0; i <= 10000; i++) setAge(i);");
1448   // All i < 10000 go to the interceptor.
1449   ExpectInt32("child.interceptor_age", 9999);
1450   // The last i goes to child's own property.
1451   ExpectInt32("child.age", 10000);
1452 }
1453 
1454 
THREADED_TEST(SwitchFromPropertyToInterceptor)1455 THREADED_TEST(SwitchFromPropertyToInterceptor) {
1456   v8::HandleScope scope(CcTest::isolate());
1457   Local<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
1458   Local<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
1459   child->Inherit(parent);
1460   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1461   LocalContext env;
1462   env->Global()
1463       ->Set(env.local(), v8_str("Child"),
1464             child->GetFunction(env.local()).ToLocalChecked())
1465       .FromJust();
1466   CompileRun(
1467       "var child = new Child;"
1468       "function setAge(i){ child.age = i; };"
1469       "for(var i = 20000; i >= 9999; i--) setAge(i);");
1470   // All i >= 10000 go to child's own property.
1471   ExpectInt32("child.age", 10000);
1472   // The last i goes to the interceptor.
1473   ExpectInt32("child.interceptor_age", 9999);
1474 }
1475 
1476 
1477 static bool interceptor_for_hidden_properties_called;
InterceptorForHiddenProperties(Local<Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)1478 static void InterceptorForHiddenProperties(
1479     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
1480   interceptor_for_hidden_properties_called = true;
1481 }
1482 
1483 
THREADED_TEST(HiddenPropertiesWithInterceptors)1484 THREADED_TEST(HiddenPropertiesWithInterceptors) {
1485   LocalContext context;
1486   v8::Isolate* isolate = context->GetIsolate();
1487   v8::HandleScope scope(isolate);
1488 
1489   interceptor_for_hidden_properties_called = false;
1490 
1491   v8::Local<v8::Private> key =
1492       v8::Private::New(isolate, v8_str("api-test::hidden-key"));
1493 
1494   // Associate an interceptor with an object and start setting hidden values.
1495   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
1496   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
1497   instance_templ->SetHandler(
1498       v8::NamedPropertyHandlerConfiguration(InterceptorForHiddenProperties));
1499   Local<v8::Function> function =
1500       fun_templ->GetFunction(context.local()).ToLocalChecked();
1501   Local<v8::Object> obj =
1502       function->NewInstance(context.local()).ToLocalChecked();
1503   CHECK(obj->SetPrivate(context.local(), key, v8::Integer::New(isolate, 2302))
1504             .FromJust());
1505   CHECK_EQ(2302, obj->GetPrivate(context.local(), key)
1506                      .ToLocalChecked()
1507                      ->Int32Value(context.local())
1508                      .FromJust());
1509   CHECK(!interceptor_for_hidden_properties_called);
1510 }
1511 
1512 
XPropertyGetter(Local<Name> property,const v8::PropertyCallbackInfo<v8::Value> & info)1513 static void XPropertyGetter(Local<Name> property,
1514                             const v8::PropertyCallbackInfo<v8::Value>& info) {
1515   ApiTestFuzzer::Fuzz();
1516   CHECK(info.Data()->IsUndefined());
1517   info.GetReturnValue().Set(property);
1518 }
1519 
1520 
THREADED_TEST(NamedInterceptorPropertyRead)1521 THREADED_TEST(NamedInterceptorPropertyRead) {
1522   v8::Isolate* isolate = CcTest::isolate();
1523   v8::HandleScope scope(isolate);
1524   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1525   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(XPropertyGetter));
1526   LocalContext context;
1527   context->Global()
1528       ->Set(context.local(), v8_str("obj"),
1529             templ->NewInstance(context.local()).ToLocalChecked())
1530       .FromJust();
1531   Local<Script> script = v8_compile("obj.x");
1532   for (int i = 0; i < 10; i++) {
1533     Local<Value> result = script->Run(context.local()).ToLocalChecked();
1534     CHECK(result->Equals(context.local(), v8_str("x")).FromJust());
1535   }
1536 }
1537 
1538 
THREADED_TEST(NamedInterceptorDictionaryIC)1539 THREADED_TEST(NamedInterceptorDictionaryIC) {
1540   v8::Isolate* isolate = CcTest::isolate();
1541   v8::HandleScope scope(isolate);
1542   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1543   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(XPropertyGetter));
1544   LocalContext context;
1545   // Create an object with a named interceptor.
1546   context->Global()
1547       ->Set(context.local(), v8_str("interceptor_obj"),
1548             templ->NewInstance(context.local()).ToLocalChecked())
1549       .FromJust();
1550   Local<Script> script = v8_compile("interceptor_obj.x");
1551   for (int i = 0; i < 10; i++) {
1552     Local<Value> result = script->Run(context.local()).ToLocalChecked();
1553     CHECK(result->Equals(context.local(), v8_str("x")).FromJust());
1554   }
1555   // Create a slow case object and a function accessing a property in
1556   // that slow case object (with dictionary probing in generated
1557   // code). Then force object with a named interceptor into slow-case,
1558   // pass it to the function, and check that the interceptor is called
1559   // instead of accessing the local property.
1560   Local<Value> result = CompileRun(
1561       "function get_x(o) { return o.x; };"
1562       "var obj = { x : 42, y : 0 };"
1563       "delete obj.y;"
1564       "for (var i = 0; i < 10; i++) get_x(obj);"
1565       "interceptor_obj.x = 42;"
1566       "interceptor_obj.y = 10;"
1567       "delete interceptor_obj.y;"
1568       "get_x(interceptor_obj)");
1569   CHECK(result->Equals(context.local(), v8_str("x")).FromJust());
1570 }
1571 
1572 
THREADED_TEST(NamedInterceptorDictionaryICMultipleContext)1573 THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
1574   v8::Isolate* isolate = CcTest::isolate();
1575   v8::HandleScope scope(isolate);
1576   v8::Local<Context> context1 = Context::New(isolate);
1577 
1578   context1->Enter();
1579   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1580   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(XPropertyGetter));
1581   // Create an object with a named interceptor.
1582   v8::Local<v8::Object> object = templ->NewInstance(context1).ToLocalChecked();
1583   context1->Global()
1584       ->Set(context1, v8_str("interceptor_obj"), object)
1585       .FromJust();
1586 
1587   // Force the object into the slow case.
1588   CompileRun(
1589       "interceptor_obj.y = 0;"
1590       "delete interceptor_obj.y;");
1591   context1->Exit();
1592 
1593   {
1594     // Introduce the object into a different context.
1595     // Repeat named loads to exercise ICs.
1596     LocalContext context2;
1597     context2->Global()
1598         ->Set(context2.local(), v8_str("interceptor_obj"), object)
1599         .FromJust();
1600     Local<Value> result = CompileRun(
1601         "function get_x(o) { return o.x; }"
1602         "interceptor_obj.x = 42;"
1603         "for (var i=0; i != 10; i++) {"
1604         "  get_x(interceptor_obj);"
1605         "}"
1606         "get_x(interceptor_obj)");
1607     // Check that the interceptor was actually invoked.
1608     CHECK(result->Equals(context2.local(), v8_str("x")).FromJust());
1609   }
1610 
1611   // Return to the original context and force some object to the slow case
1612   // to cause the NormalizedMapCache to verify.
1613   context1->Enter();
1614   CompileRun("var obj = { x : 0 }; delete obj.x;");
1615   context1->Exit();
1616 }
1617 
1618 
SetXOnPrototypeGetter(Local<Name> property,const v8::PropertyCallbackInfo<v8::Value> & info)1619 static void SetXOnPrototypeGetter(
1620     Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {
1621   // Set x on the prototype object and do not handle the get request.
1622   v8::Local<v8::Value> proto = info.Holder()->GetPrototype();
1623   proto.As<v8::Object>()
1624       ->Set(info.GetIsolate()->GetCurrentContext(), v8_str("x"),
1625             v8::Integer::New(info.GetIsolate(), 23))
1626       .FromJust();
1627 }
1628 
1629 
1630 // This is a regression test for http://crbug.com/20104. Map
1631 // transitions should not interfere with post interceptor lookup.
THREADED_TEST(NamedInterceptorMapTransitionRead)1632 THREADED_TEST(NamedInterceptorMapTransitionRead) {
1633   v8::Isolate* isolate = CcTest::isolate();
1634   v8::HandleScope scope(isolate);
1635   Local<v8::FunctionTemplate> function_template =
1636       v8::FunctionTemplate::New(isolate);
1637   Local<v8::ObjectTemplate> instance_template =
1638       function_template->InstanceTemplate();
1639   instance_template->SetHandler(
1640       v8::NamedPropertyHandlerConfiguration(SetXOnPrototypeGetter));
1641   LocalContext context;
1642   context->Global()
1643       ->Set(context.local(), v8_str("F"),
1644             function_template->GetFunction(context.local()).ToLocalChecked())
1645       .FromJust();
1646   // Create an instance of F and introduce a map transition for x.
1647   CompileRun("var o = new F(); o.x = 23;");
1648   // Create an instance of F and invoke the getter. The result should be 23.
1649   Local<Value> result = CompileRun("o = new F(); o.x");
1650   CHECK_EQ(result->Int32Value(context.local()).FromJust(), 23);
1651 }
1652 
1653 
IndexedPropertyGetter(uint32_t index,const v8::PropertyCallbackInfo<v8::Value> & info)1654 static void IndexedPropertyGetter(
1655     uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) {
1656   ApiTestFuzzer::Fuzz();
1657   if (index == 37) {
1658     info.GetReturnValue().Set(v8_num(625));
1659   }
1660 }
1661 
1662 
IndexedPropertySetter(uint32_t index,Local<Value> value,const v8::PropertyCallbackInfo<v8::Value> & info)1663 static void IndexedPropertySetter(
1664     uint32_t index, Local<Value> value,
1665     const v8::PropertyCallbackInfo<v8::Value>& info) {
1666   ApiTestFuzzer::Fuzz();
1667   if (index == 39) {
1668     info.GetReturnValue().Set(value);
1669   }
1670 }
1671 
1672 
THREADED_TEST(IndexedInterceptorWithIndexedAccessor)1673 THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
1674   v8::Isolate* isolate = CcTest::isolate();
1675   v8::HandleScope scope(isolate);
1676   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1677   templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
1678       IndexedPropertyGetter, IndexedPropertySetter));
1679   LocalContext context;
1680   context->Global()
1681       ->Set(context.local(), v8_str("obj"),
1682             templ->NewInstance(context.local()).ToLocalChecked())
1683       .FromJust();
1684   Local<Script> getter_script =
1685       v8_compile("obj.__defineGetter__(\"3\", function(){return 5;});obj[3];");
1686   Local<Script> setter_script = v8_compile(
1687       "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
1688       "obj[17] = 23;"
1689       "obj.foo;");
1690   Local<Script> interceptor_setter_script = v8_compile(
1691       "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
1692       "obj[39] = 47;"
1693       "obj.foo;");  // This setter should not run, due to the interceptor.
1694   Local<Script> interceptor_getter_script = v8_compile("obj[37];");
1695   Local<Value> result = getter_script->Run(context.local()).ToLocalChecked();
1696   CHECK(v8_num(5)->Equals(context.local(), result).FromJust());
1697   result = setter_script->Run(context.local()).ToLocalChecked();
1698   CHECK(v8_num(23)->Equals(context.local(), result).FromJust());
1699   result = interceptor_setter_script->Run(context.local()).ToLocalChecked();
1700   CHECK(v8_num(23)->Equals(context.local(), result).FromJust());
1701   result = interceptor_getter_script->Run(context.local()).ToLocalChecked();
1702   CHECK(v8_num(625)->Equals(context.local(), result).FromJust());
1703 }
1704 
1705 
UnboxedDoubleIndexedPropertyGetter(uint32_t index,const v8::PropertyCallbackInfo<v8::Value> & info)1706 static void UnboxedDoubleIndexedPropertyGetter(
1707     uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) {
1708   ApiTestFuzzer::Fuzz();
1709   if (index < 25) {
1710     info.GetReturnValue().Set(v8_num(index));
1711   }
1712 }
1713 
1714 
UnboxedDoubleIndexedPropertySetter(uint32_t index,Local<Value> value,const v8::PropertyCallbackInfo<v8::Value> & info)1715 static void UnboxedDoubleIndexedPropertySetter(
1716     uint32_t index, Local<Value> value,
1717     const v8::PropertyCallbackInfo<v8::Value>& info) {
1718   ApiTestFuzzer::Fuzz();
1719   if (index < 25) {
1720     info.GetReturnValue().Set(v8_num(index));
1721   }
1722 }
1723 
1724 
UnboxedDoubleIndexedPropertyEnumerator(const v8::PropertyCallbackInfo<v8::Array> & info)1725 void UnboxedDoubleIndexedPropertyEnumerator(
1726     const v8::PropertyCallbackInfo<v8::Array>& info) {
1727   // Force the list of returned keys to be stored in a FastDoubleArray.
1728   Local<Script> indexed_property_names_script = v8_compile(
1729       "keys = new Array(); keys[125000] = 1;"
1730       "for(i = 0; i < 80000; i++) { keys[i] = i; };"
1731       "keys.length = 25; keys;");
1732   Local<Value> result =
1733       indexed_property_names_script->Run(info.GetIsolate()->GetCurrentContext())
1734           .ToLocalChecked();
1735   info.GetReturnValue().Set(Local<v8::Array>::Cast(result));
1736 }
1737 
1738 
1739 // Make sure that the the interceptor code in the runtime properly handles
1740 // merging property name lists for double-array-backed arrays.
THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor)1741 THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
1742   v8::Isolate* isolate = CcTest::isolate();
1743   v8::HandleScope scope(isolate);
1744   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1745   templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
1746       UnboxedDoubleIndexedPropertyGetter, UnboxedDoubleIndexedPropertySetter, 0,
1747       0, UnboxedDoubleIndexedPropertyEnumerator));
1748   LocalContext context;
1749   context->Global()
1750       ->Set(context.local(), v8_str("obj"),
1751             templ->NewInstance(context.local()).ToLocalChecked())
1752       .FromJust();
1753   // When obj is created, force it to be Stored in a FastDoubleArray.
1754   Local<Script> create_unboxed_double_script = v8_compile(
1755       "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
1756       "key_count = 0; "
1757       "for (x in obj) {key_count++;};"
1758       "obj;");
1759   Local<Value> result =
1760       create_unboxed_double_script->Run(context.local()).ToLocalChecked();
1761   CHECK(result->ToObject(context.local())
1762             .ToLocalChecked()
1763             ->HasRealIndexedProperty(context.local(), 2000)
1764             .FromJust());
1765   Local<Script> key_count_check = v8_compile("key_count;");
1766   result = key_count_check->Run(context.local()).ToLocalChecked();
1767   CHECK(v8_num(40013)->Equals(context.local(), result).FromJust());
1768 }
1769 
1770 
SloppyArgsIndexedPropertyEnumerator(const v8::PropertyCallbackInfo<v8::Array> & info)1771 void SloppyArgsIndexedPropertyEnumerator(
1772     const v8::PropertyCallbackInfo<v8::Array>& info) {
1773   // Force the list of returned keys to be stored in a Arguments object.
1774   Local<Script> indexed_property_names_script = v8_compile(
1775       "function f(w,x) {"
1776       " return arguments;"
1777       "}"
1778       "keys = f(0, 1, 2, 3);"
1779       "keys;");
1780   Local<Object> result = Local<Object>::Cast(
1781       indexed_property_names_script->Run(info.GetIsolate()->GetCurrentContext())
1782           .ToLocalChecked());
1783   // Have to populate the handle manually, as it's not Cast-able.
1784   i::Handle<i::JSReceiver> o =
1785       v8::Utils::OpenHandle<Object, i::JSReceiver>(result);
1786   i::Handle<i::JSArray> array(reinterpret_cast<i::JSArray*>(*o));
1787   info.GetReturnValue().Set(v8::Utils::ToLocal(array));
1788 }
1789 
1790 
SloppyIndexedPropertyGetter(uint32_t index,const v8::PropertyCallbackInfo<v8::Value> & info)1791 static void SloppyIndexedPropertyGetter(
1792     uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) {
1793   ApiTestFuzzer::Fuzz();
1794   if (index < 4) {
1795     info.GetReturnValue().Set(v8_num(index));
1796   }
1797 }
1798 
1799 
1800 // Make sure that the the interceptor code in the runtime properly handles
1801 // merging property name lists for non-string arguments arrays.
THREADED_TEST(IndexedInterceptorSloppyArgsWithIndexedAccessor)1802 THREADED_TEST(IndexedInterceptorSloppyArgsWithIndexedAccessor) {
1803   v8::Isolate* isolate = CcTest::isolate();
1804   v8::HandleScope scope(isolate);
1805   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1806   templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
1807       SloppyIndexedPropertyGetter, 0, 0, 0,
1808       SloppyArgsIndexedPropertyEnumerator));
1809   LocalContext context;
1810   context->Global()
1811       ->Set(context.local(), v8_str("obj"),
1812             templ->NewInstance(context.local()).ToLocalChecked())
1813       .FromJust();
1814   Local<Script> create_args_script = v8_compile(
1815       "var key_count = 0;"
1816       "for (x in obj) {key_count++;} key_count;");
1817   Local<Value> result =
1818       create_args_script->Run(context.local()).ToLocalChecked();
1819   CHECK(v8_num(4)->Equals(context.local(), result).FromJust());
1820 }
1821 
1822 
IdentityIndexedPropertyGetter(uint32_t index,const v8::PropertyCallbackInfo<v8::Value> & info)1823 static void IdentityIndexedPropertyGetter(
1824     uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) {
1825   info.GetReturnValue().Set(index);
1826 }
1827 
1828 
THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor)1829 THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
1830   v8::Isolate* isolate = CcTest::isolate();
1831   v8::HandleScope scope(isolate);
1832   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1833   templ->SetHandler(
1834       v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
1835 
1836   LocalContext context;
1837   context->Global()
1838       ->Set(context.local(), v8_str("obj"),
1839             templ->NewInstance(context.local()).ToLocalChecked())
1840       .FromJust();
1841 
1842   // Check fast object case.
1843   const char* fast_case_code =
1844       "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
1845   ExpectString(fast_case_code, "0");
1846 
1847   // Check slow case.
1848   const char* slow_case_code =
1849       "obj.x = 1; delete obj.x;"
1850       "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
1851   ExpectString(slow_case_code, "1");
1852 }
1853 
1854 
THREADED_TEST(IndexedInterceptorWithNoSetter)1855 THREADED_TEST(IndexedInterceptorWithNoSetter) {
1856   v8::Isolate* isolate = CcTest::isolate();
1857   v8::HandleScope scope(isolate);
1858   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1859   templ->SetHandler(
1860       v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
1861 
1862   LocalContext context;
1863   context->Global()
1864       ->Set(context.local(), v8_str("obj"),
1865             templ->NewInstance(context.local()).ToLocalChecked())
1866       .FromJust();
1867 
1868   const char* code =
1869       "try {"
1870       "  obj[0] = 239;"
1871       "  for (var i = 0; i < 100; i++) {"
1872       "    var v = obj[0];"
1873       "    if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
1874       "  }"
1875       "  'PASSED'"
1876       "} catch(e) {"
1877       "  e"
1878       "}";
1879   ExpectString(code, "PASSED");
1880 }
1881 
1882 
AccessAlwaysBlocked(Local<v8::Context> accessing_context,Local<v8::Object> accessed_object)1883 static bool AccessAlwaysBlocked(Local<v8::Context> accessing_context,
1884                                 Local<v8::Object> accessed_object) {
1885   return false;
1886 }
1887 
1888 
THREADED_TEST(IndexedInterceptorWithAccessorCheck)1889 THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
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   templ->SetAccessCheckCallback(AccessAlwaysBlocked);
1897 
1898   LocalContext context;
1899   Local<v8::Object> obj = templ->NewInstance(context.local()).ToLocalChecked();
1900   context->Global()->Set(context.local(), v8_str("obj"), obj).FromJust();
1901 
1902   const char* code =
1903       "var result = 'PASSED';"
1904       "for (var i = 0; i < 100; i++) {"
1905       "  try {"
1906       "    var v = obj[0];"
1907       "    result = 'Wrong value ' + v + ' at iteration ' + i;"
1908       "    break;"
1909       "  } catch (e) {"
1910       "    /* pass */"
1911       "  }"
1912       "}"
1913       "result";
1914   ExpectString(code, "PASSED");
1915 }
1916 
1917 
THREADED_TEST(IndexedInterceptorWithDifferentIndices)1918 THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
1919   v8::Isolate* isolate = CcTest::isolate();
1920   v8::HandleScope scope(isolate);
1921   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1922   templ->SetHandler(
1923       v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
1924 
1925   LocalContext context;
1926   Local<v8::Object> obj = templ->NewInstance(context.local()).ToLocalChecked();
1927   context->Global()->Set(context.local(), v8_str("obj"), obj).FromJust();
1928 
1929   const char* code =
1930       "try {"
1931       "  for (var i = 0; i < 100; i++) {"
1932       "    var v = obj[i];"
1933       "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
1934       "  }"
1935       "  'PASSED'"
1936       "} catch(e) {"
1937       "  e"
1938       "}";
1939   ExpectString(code, "PASSED");
1940 }
1941 
1942 
THREADED_TEST(IndexedInterceptorWithNegativeIndices)1943 THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
1944   v8::Isolate* isolate = CcTest::isolate();
1945   v8::HandleScope scope(isolate);
1946   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1947   templ->SetHandler(
1948       v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
1949 
1950   LocalContext context;
1951   Local<v8::Object> obj = templ->NewInstance(context.local()).ToLocalChecked();
1952   context->Global()->Set(context.local(), v8_str("obj"), obj).FromJust();
1953 
1954   const char* code =
1955       "try {"
1956       "  for (var i = 0; i < 100; i++) {"
1957       "    var expected = i;"
1958       "    var key = i;"
1959       "    if (i == 25) {"
1960       "       key = -1;"
1961       "       expected = undefined;"
1962       "    }"
1963       "    if (i == 50) {"
1964       "       /* probe minimal Smi number on 32-bit platforms */"
1965       "       key = -(1 << 30);"
1966       "       expected = undefined;"
1967       "    }"
1968       "    if (i == 75) {"
1969       "       /* probe minimal Smi number on 64-bit platforms */"
1970       "       key = 1 << 31;"
1971       "       expected = undefined;"
1972       "    }"
1973       "    var v = obj[key];"
1974       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
1975       "  }"
1976       "  'PASSED'"
1977       "} catch(e) {"
1978       "  e"
1979       "}";
1980   ExpectString(code, "PASSED");
1981 }
1982 
1983 
THREADED_TEST(IndexedInterceptorWithNotSmiLookup)1984 THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
1985   v8::Isolate* isolate = CcTest::isolate();
1986   v8::HandleScope scope(isolate);
1987   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1988   templ->SetHandler(
1989       v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
1990 
1991   LocalContext context;
1992   Local<v8::Object> obj = templ->NewInstance(context.local()).ToLocalChecked();
1993   context->Global()->Set(context.local(), v8_str("obj"), obj).FromJust();
1994 
1995   const char* code =
1996       "try {"
1997       "  for (var i = 0; i < 100; i++) {"
1998       "    var expected = i;"
1999       "    var key = i;"
2000       "    if (i == 50) {"
2001       "       key = 'foobar';"
2002       "       expected = undefined;"
2003       "    }"
2004       "    var v = obj[key];"
2005       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
2006       "  }"
2007       "  'PASSED'"
2008       "} catch(e) {"
2009       "  e"
2010       "}";
2011   ExpectString(code, "PASSED");
2012 }
2013 
2014 
THREADED_TEST(IndexedInterceptorGoingMegamorphic)2015 THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
2016   v8::Isolate* isolate = CcTest::isolate();
2017   v8::HandleScope scope(isolate);
2018   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
2019   templ->SetHandler(
2020       v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
2021 
2022   LocalContext context;
2023   Local<v8::Object> obj = templ->NewInstance(context.local()).ToLocalChecked();
2024   context->Global()->Set(context.local(), v8_str("obj"), obj).FromJust();
2025 
2026   const char* code =
2027       "var original = obj;"
2028       "try {"
2029       "  for (var i = 0; i < 100; i++) {"
2030       "    var expected = i;"
2031       "    if (i == 50) {"
2032       "       obj = {50: 'foobar'};"
2033       "       expected = 'foobar';"
2034       "    }"
2035       "    var v = obj[i];"
2036       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
2037       "    if (i == 50) obj = original;"
2038       "  }"
2039       "  'PASSED'"
2040       "} catch(e) {"
2041       "  e"
2042       "}";
2043   ExpectString(code, "PASSED");
2044 }
2045 
2046 
THREADED_TEST(IndexedInterceptorReceiverTurningSmi)2047 THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
2048   v8::Isolate* isolate = CcTest::isolate();
2049   v8::HandleScope scope(isolate);
2050   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
2051   templ->SetHandler(
2052       v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
2053 
2054   LocalContext context;
2055   Local<v8::Object> obj = templ->NewInstance(context.local()).ToLocalChecked();
2056   context->Global()->Set(context.local(), v8_str("obj"), obj).FromJust();
2057 
2058   const char* code =
2059       "var original = obj;"
2060       "try {"
2061       "  for (var i = 0; i < 100; i++) {"
2062       "    var expected = i;"
2063       "    if (i == 5) {"
2064       "       obj = 239;"
2065       "       expected = undefined;"
2066       "    }"
2067       "    var v = obj[i];"
2068       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
2069       "    if (i == 5) obj = original;"
2070       "  }"
2071       "  'PASSED'"
2072       "} catch(e) {"
2073       "  e"
2074       "}";
2075   ExpectString(code, "PASSED");
2076 }
2077 
2078 
THREADED_TEST(IndexedInterceptorOnProto)2079 THREADED_TEST(IndexedInterceptorOnProto) {
2080   v8::Isolate* isolate = CcTest::isolate();
2081   v8::HandleScope scope(isolate);
2082   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
2083   templ->SetHandler(
2084       v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
2085 
2086   LocalContext context;
2087   Local<v8::Object> obj = templ->NewInstance(context.local()).ToLocalChecked();
2088   context->Global()->Set(context.local(), v8_str("obj"), obj).FromJust();
2089 
2090   const char* code =
2091       "var o = {__proto__: obj};"
2092       "try {"
2093       "  for (var i = 0; i < 100; i++) {"
2094       "    var v = o[i];"
2095       "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
2096       "  }"
2097       "  'PASSED'"
2098       "} catch(e) {"
2099       "  e"
2100       "}";
2101   ExpectString(code, "PASSED");
2102 }
2103 
2104 
NoBlockGetterX(Local<Name> name,const v8::PropertyCallbackInfo<v8::Value> &)2105 static void NoBlockGetterX(Local<Name> name,
2106                            const v8::PropertyCallbackInfo<v8::Value>&) {}
2107 
2108 
NoBlockGetterI(uint32_t index,const v8::PropertyCallbackInfo<v8::Value> &)2109 static void NoBlockGetterI(uint32_t index,
2110                            const v8::PropertyCallbackInfo<v8::Value>&) {}
2111 
2112 
PDeleter(Local<Name> name,const v8::PropertyCallbackInfo<v8::Boolean> & info)2113 static void PDeleter(Local<Name> name,
2114                      const v8::PropertyCallbackInfo<v8::Boolean>& info) {
2115   if (!name->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("foo"))
2116            .FromJust()) {
2117     return;  // not intercepted
2118   }
2119 
2120   info.GetReturnValue().Set(false);  // intercepted, don't delete the property
2121 }
2122 
2123 
IDeleter(uint32_t index,const v8::PropertyCallbackInfo<v8::Boolean> & info)2124 static void IDeleter(uint32_t index,
2125                      const v8::PropertyCallbackInfo<v8::Boolean>& info) {
2126   if (index != 2) {
2127     return;  // not intercepted
2128   }
2129 
2130   info.GetReturnValue().Set(false);  // intercepted, don't delete the property
2131 }
2132 
2133 
THREADED_TEST(Deleter)2134 THREADED_TEST(Deleter) {
2135   v8::Isolate* isolate = CcTest::isolate();
2136   v8::HandleScope scope(isolate);
2137   v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
2138   obj->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX, NULL,
2139                                                         NULL, PDeleter, NULL));
2140   obj->SetHandler(v8::IndexedPropertyHandlerConfiguration(
2141       NoBlockGetterI, NULL, NULL, IDeleter, NULL));
2142   LocalContext context;
2143   context->Global()
2144       ->Set(context.local(), v8_str("k"),
2145             obj->NewInstance(context.local()).ToLocalChecked())
2146       .FromJust();
2147   CompileRun(
2148       "k.foo = 'foo';"
2149       "k.bar = 'bar';"
2150       "k[2] = 2;"
2151       "k[4] = 4;");
2152   CHECK(v8_compile("delete k.foo")
2153             ->Run(context.local())
2154             .ToLocalChecked()
2155             ->IsFalse());
2156   CHECK(v8_compile("delete k.bar")
2157             ->Run(context.local())
2158             .ToLocalChecked()
2159             ->IsTrue());
2160 
2161   CHECK(v8_compile("k.foo")
2162             ->Run(context.local())
2163             .ToLocalChecked()
2164             ->Equals(context.local(), v8_str("foo"))
2165             .FromJust());
2166   CHECK(v8_compile("k.bar")
2167             ->Run(context.local())
2168             .ToLocalChecked()
2169             ->IsUndefined());
2170 
2171   CHECK(v8_compile("delete k[2]")
2172             ->Run(context.local())
2173             .ToLocalChecked()
2174             ->IsFalse());
2175   CHECK(v8_compile("delete k[4]")
2176             ->Run(context.local())
2177             .ToLocalChecked()
2178             ->IsTrue());
2179 
2180   CHECK(v8_compile("k[2]")
2181             ->Run(context.local())
2182             .ToLocalChecked()
2183             ->Equals(context.local(), v8_num(2))
2184             .FromJust());
2185   CHECK(
2186       v8_compile("k[4]")->Run(context.local()).ToLocalChecked()->IsUndefined());
2187 }
2188 
2189 
GetK(Local<Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)2190 static void GetK(Local<Name> name,
2191                  const v8::PropertyCallbackInfo<v8::Value>& info) {
2192   ApiTestFuzzer::Fuzz();
2193   v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
2194   if (name->Equals(context, v8_str("foo")).FromJust() ||
2195       name->Equals(context, v8_str("bar")).FromJust() ||
2196       name->Equals(context, v8_str("baz")).FromJust()) {
2197     info.GetReturnValue().SetUndefined();
2198   }
2199 }
2200 
2201 
IndexedGetK(uint32_t index,const v8::PropertyCallbackInfo<v8::Value> & info)2202 static void IndexedGetK(uint32_t index,
2203                         const v8::PropertyCallbackInfo<v8::Value>& info) {
2204   ApiTestFuzzer::Fuzz();
2205   if (index == 0 || index == 1) info.GetReturnValue().SetUndefined();
2206 }
2207 
2208 
NamedEnum(const v8::PropertyCallbackInfo<v8::Array> & info)2209 static void NamedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
2210   ApiTestFuzzer::Fuzz();
2211   v8::Local<v8::Array> result = v8::Array::New(info.GetIsolate(), 3);
2212   v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
2213   result->Set(context, v8::Integer::New(info.GetIsolate(), 0), v8_str("foo"))
2214       .FromJust();
2215   result->Set(context, v8::Integer::New(info.GetIsolate(), 1), v8_str("bar"))
2216       .FromJust();
2217   result->Set(context, v8::Integer::New(info.GetIsolate(), 2), v8_str("baz"))
2218       .FromJust();
2219   info.GetReturnValue().Set(result);
2220 }
2221 
2222 
IndexedEnum(const v8::PropertyCallbackInfo<v8::Array> & info)2223 static void IndexedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
2224   ApiTestFuzzer::Fuzz();
2225   v8::Local<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
2226   v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
2227   result->Set(context, v8::Integer::New(info.GetIsolate(), 0), v8_str("0"))
2228       .FromJust();
2229   result->Set(context, v8::Integer::New(info.GetIsolate(), 1), v8_str("1"))
2230       .FromJust();
2231   info.GetReturnValue().Set(result);
2232 }
2233 
2234 
THREADED_TEST(Enumerators)2235 THREADED_TEST(Enumerators) {
2236   v8::Isolate* isolate = CcTest::isolate();
2237   v8::HandleScope scope(isolate);
2238   v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
2239   obj->SetHandler(
2240       v8::NamedPropertyHandlerConfiguration(GetK, NULL, NULL, NULL, NamedEnum));
2241   obj->SetHandler(v8::IndexedPropertyHandlerConfiguration(
2242       IndexedGetK, NULL, NULL, NULL, IndexedEnum));
2243   LocalContext context;
2244   context->Global()
2245       ->Set(context.local(), v8_str("k"),
2246             obj->NewInstance(context.local()).ToLocalChecked())
2247       .FromJust();
2248   v8::Local<v8::Array> result =
2249       v8::Local<v8::Array>::Cast(CompileRun("k[10] = 0;"
2250                                             "k.a = 0;"
2251                                             "k[5] = 0;"
2252                                             "k.b = 0;"
2253                                             "k[4294967294] = 0;"
2254                                             "k.c = 0;"
2255                                             "k[4294967295] = 0;"
2256                                             "k.d = 0;"
2257                                             "k[140000] = 0;"
2258                                             "k.e = 0;"
2259                                             "k[30000000000] = 0;"
2260                                             "k.f = 0;"
2261                                             "var result = [];"
2262                                             "for (var prop in k) {"
2263                                             "  result.push(prop);"
2264                                             "}"
2265                                             "result"));
2266   // Check that we get all the property names returned including the
2267   // ones from the enumerators in the right order: indexed properties
2268   // in numerical order, indexed interceptor properties, named
2269   // properties in insertion order, named interceptor properties.
2270   // This order is not mandated by the spec, so this test is just
2271   // documenting our behavior.
2272   CHECK_EQ(17u, result->Length());
2273   // Indexed properties + indexed interceptor properties in numerical order.
2274   CHECK(v8_str("0")
2275             ->Equals(context.local(),
2276                      result->Get(context.local(), v8::Integer::New(isolate, 0))
2277                          .ToLocalChecked())
2278             .FromJust());
2279   CHECK(v8_str("1")
2280             ->Equals(context.local(),
2281                      result->Get(context.local(), v8::Integer::New(isolate, 1))
2282                          .ToLocalChecked())
2283             .FromJust());
2284   CHECK(v8_str("5")
2285             ->Equals(context.local(),
2286                      result->Get(context.local(), v8::Integer::New(isolate, 2))
2287                          .ToLocalChecked())
2288             .FromJust());
2289   CHECK(v8_str("10")
2290             ->Equals(context.local(),
2291                      result->Get(context.local(), v8::Integer::New(isolate, 3))
2292                          .ToLocalChecked())
2293             .FromJust());
2294   CHECK(v8_str("140000")
2295             ->Equals(context.local(),
2296                      result->Get(context.local(), v8::Integer::New(isolate, 4))
2297                          .ToLocalChecked())
2298             .FromJust());
2299   CHECK(v8_str("4294967294")
2300             ->Equals(context.local(),
2301                      result->Get(context.local(), v8::Integer::New(isolate, 5))
2302                          .ToLocalChecked())
2303             .FromJust());
2304   // Named properties in insertion order.
2305   CHECK(v8_str("a")
2306             ->Equals(context.local(),
2307                      result->Get(context.local(), v8::Integer::New(isolate, 6))
2308                          .ToLocalChecked())
2309             .FromJust());
2310   CHECK(v8_str("b")
2311             ->Equals(context.local(),
2312                      result->Get(context.local(), v8::Integer::New(isolate, 7))
2313                          .ToLocalChecked())
2314             .FromJust());
2315   CHECK(v8_str("c")
2316             ->Equals(context.local(),
2317                      result->Get(context.local(), v8::Integer::New(isolate, 8))
2318                          .ToLocalChecked())
2319             .FromJust());
2320   CHECK(v8_str("4294967295")
2321             ->Equals(context.local(),
2322                      result->Get(context.local(), v8::Integer::New(isolate, 9))
2323                          .ToLocalChecked())
2324             .FromJust());
2325   CHECK(v8_str("d")
2326             ->Equals(context.local(),
2327                      result->Get(context.local(), v8::Integer::New(isolate, 10))
2328                          .ToLocalChecked())
2329             .FromJust());
2330   CHECK(v8_str("e")
2331             ->Equals(context.local(),
2332                      result->Get(context.local(), v8::Integer::New(isolate, 11))
2333                          .ToLocalChecked())
2334             .FromJust());
2335   CHECK(v8_str("30000000000")
2336             ->Equals(context.local(),
2337                      result->Get(context.local(), v8::Integer::New(isolate, 12))
2338                          .ToLocalChecked())
2339             .FromJust());
2340   CHECK(v8_str("f")
2341             ->Equals(context.local(),
2342                      result->Get(context.local(), v8::Integer::New(isolate, 13))
2343                          .ToLocalChecked())
2344             .FromJust());
2345   // Named interceptor properties.
2346   CHECK(v8_str("foo")
2347             ->Equals(context.local(),
2348                      result->Get(context.local(), v8::Integer::New(isolate, 14))
2349                          .ToLocalChecked())
2350             .FromJust());
2351   CHECK(v8_str("bar")
2352             ->Equals(context.local(),
2353                      result->Get(context.local(), v8::Integer::New(isolate, 15))
2354                          .ToLocalChecked())
2355             .FromJust());
2356   CHECK(v8_str("baz")
2357             ->Equals(context.local(),
2358                      result->Get(context.local(), v8::Integer::New(isolate, 16))
2359                          .ToLocalChecked())
2360             .FromJust());
2361 }
2362 
2363 
2364 v8::Local<Value> call_ic_function;
2365 v8::Local<Value> call_ic_function2;
2366 v8::Local<Value> call_ic_function3;
2367 
InterceptorCallICGetter(Local<Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)2368 static void InterceptorCallICGetter(
2369     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2370   ApiTestFuzzer::Fuzz();
2371   CHECK(v8_str("x")
2372             ->Equals(info.GetIsolate()->GetCurrentContext(), name)
2373             .FromJust());
2374   info.GetReturnValue().Set(call_ic_function);
2375 }
2376 
2377 
2378 // This test should hit the call IC for the interceptor case.
THREADED_TEST(InterceptorCallIC)2379 THREADED_TEST(InterceptorCallIC) {
2380   v8::Isolate* isolate = CcTest::isolate();
2381   v8::HandleScope scope(isolate);
2382   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2383   templ->SetHandler(
2384       v8::NamedPropertyHandlerConfiguration(InterceptorCallICGetter));
2385   LocalContext context;
2386   context->Global()
2387       ->Set(context.local(), v8_str("o"),
2388             templ->NewInstance(context.local()).ToLocalChecked())
2389       .FromJust();
2390   call_ic_function = v8_compile("function f(x) { return x + 1; }; f")
2391                          ->Run(context.local())
2392                          .ToLocalChecked();
2393   v8::Local<Value> value = CompileRun(
2394       "var result = 0;"
2395       "for (var i = 0; i < 1000; i++) {"
2396       "  result = o.x(41);"
2397       "}");
2398   CHECK_EQ(42, value->Int32Value(context.local()).FromJust());
2399 }
2400 
2401 
2402 // This test checks that if interceptor doesn't provide
2403 // a value, we can fetch regular value.
THREADED_TEST(InterceptorCallICSeesOthers)2404 THREADED_TEST(InterceptorCallICSeesOthers) {
2405   v8::Isolate* isolate = CcTest::isolate();
2406   v8::HandleScope scope(isolate);
2407   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2408   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
2409   LocalContext context;
2410   context->Global()
2411       ->Set(context.local(), v8_str("o"),
2412             templ->NewInstance(context.local()).ToLocalChecked())
2413       .FromJust();
2414   v8::Local<Value> value = CompileRun(
2415       "o.x = function f(x) { return x + 1; };"
2416       "var result = 0;"
2417       "for (var i = 0; i < 7; i++) {"
2418       "  result = o.x(41);"
2419       "}");
2420   CHECK_EQ(42, value->Int32Value(context.local()).FromJust());
2421 }
2422 
2423 
2424 static v8::Local<Value> call_ic_function4;
InterceptorCallICGetter4(Local<Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)2425 static void InterceptorCallICGetter4(
2426     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2427   ApiTestFuzzer::Fuzz();
2428   CHECK(v8_str("x")
2429             ->Equals(info.GetIsolate()->GetCurrentContext(), name)
2430             .FromJust());
2431   info.GetReturnValue().Set(call_ic_function4);
2432 }
2433 
2434 
2435 // This test checks that if interceptor provides a function,
2436 // even if we cached shadowed variant, interceptor's function
2437 // is invoked
THREADED_TEST(InterceptorCallICCacheableNotNeeded)2438 THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
2439   v8::Isolate* isolate = CcTest::isolate();
2440   v8::HandleScope scope(isolate);
2441   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2442   templ->SetHandler(
2443       v8::NamedPropertyHandlerConfiguration(InterceptorCallICGetter4));
2444   LocalContext context;
2445   context->Global()
2446       ->Set(context.local(), v8_str("o"),
2447             templ->NewInstance(context.local()).ToLocalChecked())
2448       .FromJust();
2449   call_ic_function4 = v8_compile("function f(x) { return x - 1; }; f")
2450                           ->Run(context.local())
2451                           .ToLocalChecked();
2452   v8::Local<Value> value = CompileRun(
2453       "Object.getPrototypeOf(o).x = function(x) { return x + 1; };"
2454       "var result = 0;"
2455       "for (var i = 0; i < 1000; i++) {"
2456       "  result = o.x(42);"
2457       "}");
2458   CHECK_EQ(41, value->Int32Value(context.local()).FromJust());
2459 }
2460 
2461 
2462 // Test the case when we stored cacheable lookup into
2463 // a stub, but it got invalidated later on
THREADED_TEST(InterceptorCallICInvalidatedCacheable)2464 THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
2465   v8::Isolate* isolate = CcTest::isolate();
2466   v8::HandleScope scope(isolate);
2467   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2468   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
2469   LocalContext context;
2470   context->Global()
2471       ->Set(context.local(), v8_str("o"),
2472             templ->NewInstance(context.local()).ToLocalChecked())
2473       .FromJust();
2474   v8::Local<Value> value = CompileRun(
2475       "proto1 = new Object();"
2476       "proto2 = new Object();"
2477       "o.__proto__ = proto1;"
2478       "proto1.__proto__ = proto2;"
2479       "proto2.y = function(x) { return x + 1; };"
2480       // Invoke it many times to compile a stub
2481       "for (var i = 0; i < 7; i++) {"
2482       "  o.y(42);"
2483       "}"
2484       "proto1.y = function(x) { return x - 1; };"
2485       "var result = 0;"
2486       "for (var i = 0; i < 7; i++) {"
2487       "  result += o.y(42);"
2488       "}");
2489   CHECK_EQ(41 * 7, value->Int32Value(context.local()).FromJust());
2490 }
2491 
2492 
2493 // This test checks that if interceptor doesn't provide a function,
2494 // cached constant function is used
THREADED_TEST(InterceptorCallICConstantFunctionUsed)2495 THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
2496   v8::Isolate* isolate = CcTest::isolate();
2497   v8::HandleScope scope(isolate);
2498   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2499   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
2500   LocalContext context;
2501   context->Global()
2502       ->Set(context.local(), v8_str("o"),
2503             templ->NewInstance(context.local()).ToLocalChecked())
2504       .FromJust();
2505   v8::Local<Value> value = CompileRun(
2506       "function inc(x) { return x + 1; };"
2507       "inc(1);"
2508       "o.x = inc;"
2509       "var result = 0;"
2510       "for (var i = 0; i < 1000; i++) {"
2511       "  result = o.x(42);"
2512       "}");
2513   CHECK_EQ(43, value->Int32Value(context.local()).FromJust());
2514 }
2515 
2516 
2517 static v8::Local<Value> call_ic_function5;
InterceptorCallICGetter5(Local<Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)2518 static void InterceptorCallICGetter5(
2519     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2520   ApiTestFuzzer::Fuzz();
2521   if (v8_str("x")
2522           ->Equals(info.GetIsolate()->GetCurrentContext(), name)
2523           .FromJust())
2524     info.GetReturnValue().Set(call_ic_function5);
2525 }
2526 
2527 
2528 // This test checks that if interceptor provides a function,
2529 // even if we cached constant function, interceptor's function
2530 // is invoked
THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded)2531 THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
2532   v8::Isolate* isolate = CcTest::isolate();
2533   v8::HandleScope scope(isolate);
2534   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2535   templ->SetHandler(
2536       v8::NamedPropertyHandlerConfiguration(InterceptorCallICGetter5));
2537   LocalContext context;
2538   context->Global()
2539       ->Set(context.local(), v8_str("o"),
2540             templ->NewInstance(context.local()).ToLocalChecked())
2541       .FromJust();
2542   call_ic_function5 = v8_compile("function f(x) { return x - 1; }; f")
2543                           ->Run(context.local())
2544                           .ToLocalChecked();
2545   v8::Local<Value> value = CompileRun(
2546       "function inc(x) { return x + 1; };"
2547       "inc(1);"
2548       "o.x = inc;"
2549       "var result = 0;"
2550       "for (var i = 0; i < 1000; i++) {"
2551       "  result = o.x(42);"
2552       "}");
2553   CHECK_EQ(41, value->Int32Value(context.local()).FromJust());
2554 }
2555 
2556 
2557 static v8::Local<Value> call_ic_function6;
InterceptorCallICGetter6(Local<Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)2558 static void InterceptorCallICGetter6(
2559     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2560   ApiTestFuzzer::Fuzz();
2561   if (v8_str("x")
2562           ->Equals(info.GetIsolate()->GetCurrentContext(), name)
2563           .FromJust())
2564     info.GetReturnValue().Set(call_ic_function6);
2565 }
2566 
2567 
2568 // Same test as above, except the code is wrapped in a function
2569 // to test the optimized compiler.
THREADED_TEST(InterceptorCallICConstantFunctionNotNeededWrapped)2570 THREADED_TEST(InterceptorCallICConstantFunctionNotNeededWrapped) {
2571   i::FLAG_allow_natives_syntax = true;
2572   v8::Isolate* isolate = CcTest::isolate();
2573   v8::HandleScope scope(isolate);
2574   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2575   templ->SetHandler(
2576       v8::NamedPropertyHandlerConfiguration(InterceptorCallICGetter6));
2577   LocalContext context;
2578   context->Global()
2579       ->Set(context.local(), v8_str("o"),
2580             templ->NewInstance(context.local()).ToLocalChecked())
2581       .FromJust();
2582   call_ic_function6 = v8_compile("function f(x) { return x - 1; }; f")
2583                           ->Run(context.local())
2584                           .ToLocalChecked();
2585   v8::Local<Value> value = CompileRun(
2586       "function inc(x) { return x + 1; };"
2587       "inc(1);"
2588       "o.x = inc;"
2589       "function test() {"
2590       "  var result = 0;"
2591       "  for (var i = 0; i < 1000; i++) {"
2592       "    result = o.x(42);"
2593       "  }"
2594       "  return result;"
2595       "};"
2596       "test();"
2597       "test();"
2598       "test();"
2599       "%OptimizeFunctionOnNextCall(test);"
2600       "test()");
2601   CHECK_EQ(41, value->Int32Value(context.local()).FromJust());
2602 }
2603 
2604 
2605 // Test the case when we stored constant function into
2606 // a stub, but it got invalidated later on
THREADED_TEST(InterceptorCallICInvalidatedConstantFunction)2607 THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
2608   v8::Isolate* isolate = CcTest::isolate();
2609   v8::HandleScope scope(isolate);
2610   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2611   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
2612   LocalContext context;
2613   context->Global()
2614       ->Set(context.local(), v8_str("o"),
2615             templ->NewInstance(context.local()).ToLocalChecked())
2616       .FromJust();
2617   v8::Local<Value> value = CompileRun(
2618       "function inc(x) { return x + 1; };"
2619       "inc(1);"
2620       "proto1 = new Object();"
2621       "proto2 = new Object();"
2622       "o.__proto__ = proto1;"
2623       "proto1.__proto__ = proto2;"
2624       "proto2.y = inc;"
2625       // Invoke it many times to compile a stub
2626       "for (var i = 0; i < 7; i++) {"
2627       "  o.y(42);"
2628       "}"
2629       "proto1.y = function(x) { return x - 1; };"
2630       "var result = 0;"
2631       "for (var i = 0; i < 7; i++) {"
2632       "  result += o.y(42);"
2633       "}");
2634   CHECK_EQ(41 * 7, value->Int32Value(context.local()).FromJust());
2635 }
2636 
2637 
2638 // Test the case when we stored constant function into
2639 // a stub, but it got invalidated later on due to override on
2640 // global object which is between interceptor and constant function' holders.
THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal)2641 THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
2642   v8::Isolate* isolate = CcTest::isolate();
2643   v8::HandleScope scope(isolate);
2644   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2645   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
2646   LocalContext context;
2647   context->Global()
2648       ->Set(context.local(), v8_str("o"),
2649             templ->NewInstance(context.local()).ToLocalChecked())
2650       .FromJust();
2651   v8::Local<Value> value = CompileRun(
2652       "function inc(x) { return x + 1; };"
2653       "inc(1);"
2654       "o.__proto__ = this;"
2655       "this.__proto__.y = inc;"
2656       // Invoke it many times to compile a stub
2657       "for (var i = 0; i < 7; i++) {"
2658       "  if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
2659       "}"
2660       "this.y = function(x) { return x - 1; };"
2661       "var result = 0;"
2662       "for (var i = 0; i < 7; i++) {"
2663       "  result += o.y(42);"
2664       "}");
2665   CHECK_EQ(41 * 7, value->Int32Value(context.local()).FromJust());
2666 }
2667 
2668 
2669 // Test the case when actual function to call sits on global object.
THREADED_TEST(InterceptorCallICCachedFromGlobal)2670 THREADED_TEST(InterceptorCallICCachedFromGlobal) {
2671   v8::Isolate* isolate = CcTest::isolate();
2672   v8::HandleScope scope(isolate);
2673   v8::Local<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
2674   templ_o->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
2675 
2676   LocalContext context;
2677   context->Global()
2678       ->Set(context.local(), v8_str("o"),
2679             templ_o->NewInstance(context.local()).ToLocalChecked())
2680       .FromJust();
2681 
2682   v8::Local<Value> value = CompileRun(
2683       "try {"
2684       "  o.__proto__ = this;"
2685       "  for (var i = 0; i < 10; i++) {"
2686       "    var v = o.parseFloat('239');"
2687       "    if (v != 239) throw v;"
2688       // Now it should be ICed and keep a reference to parseFloat.
2689       "  }"
2690       "  var result = 0;"
2691       "  for (var i = 0; i < 10; i++) {"
2692       "    result += o.parseFloat('239');"
2693       "  }"
2694       "  result"
2695       "} catch(e) {"
2696       "  e"
2697       "};");
2698   CHECK_EQ(239 * 10, value->Int32Value(context.local()).FromJust());
2699 }
2700 
2701 
2702 v8::Local<Value> keyed_call_ic_function;
2703 
InterceptorKeyedCallICGetter(Local<Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)2704 static void InterceptorKeyedCallICGetter(
2705     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2706   ApiTestFuzzer::Fuzz();
2707   if (v8_str("x")
2708           ->Equals(info.GetIsolate()->GetCurrentContext(), name)
2709           .FromJust()) {
2710     info.GetReturnValue().Set(keyed_call_ic_function);
2711   }
2712 }
2713 
2714 
2715 // Test the case when we stored cacheable lookup into
2716 // a stub, but the function name changed (to another cacheable function).
THREADED_TEST(InterceptorKeyedCallICKeyChange1)2717 THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
2718   v8::Isolate* isolate = CcTest::isolate();
2719   v8::HandleScope scope(isolate);
2720   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2721   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
2722   LocalContext context;
2723   context->Global()
2724       ->Set(context.local(), v8_str("o"),
2725             templ->NewInstance(context.local()).ToLocalChecked())
2726       .FromJust();
2727   CompileRun(
2728       "proto = new Object();"
2729       "proto.y = function(x) { return x + 1; };"
2730       "proto.z = function(x) { return x - 1; };"
2731       "o.__proto__ = proto;"
2732       "var result = 0;"
2733       "var method = 'y';"
2734       "for (var i = 0; i < 10; i++) {"
2735       "  if (i == 5) { method = 'z'; };"
2736       "  result += o[method](41);"
2737       "}");
2738   CHECK_EQ(42 * 5 + 40 * 5, context->Global()
2739                                 ->Get(context.local(), v8_str("result"))
2740                                 .ToLocalChecked()
2741                                 ->Int32Value(context.local())
2742                                 .FromJust());
2743 }
2744 
2745 
2746 // Test the case when we stored cacheable lookup into
2747 // a stub, but the function name changed (and the new function is present
2748 // both before and after the interceptor in the prototype chain).
THREADED_TEST(InterceptorKeyedCallICKeyChange2)2749 THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
2750   v8::Isolate* isolate = CcTest::isolate();
2751   v8::HandleScope scope(isolate);
2752   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2753   templ->SetHandler(
2754       v8::NamedPropertyHandlerConfiguration(InterceptorKeyedCallICGetter));
2755   LocalContext context;
2756   context->Global()
2757       ->Set(context.local(), v8_str("proto1"),
2758             templ->NewInstance(context.local()).ToLocalChecked())
2759       .FromJust();
2760   keyed_call_ic_function = v8_compile("function f(x) { return x - 1; }; f")
2761                                ->Run(context.local())
2762                                .ToLocalChecked();
2763   CompileRun(
2764       "o = new Object();"
2765       "proto2 = new Object();"
2766       "o.y = function(x) { return x + 1; };"
2767       "proto2.y = function(x) { return x + 2; };"
2768       "o.__proto__ = proto1;"
2769       "proto1.__proto__ = proto2;"
2770       "var result = 0;"
2771       "var method = 'x';"
2772       "for (var i = 0; i < 10; i++) {"
2773       "  if (i == 5) { method = 'y'; };"
2774       "  result += o[method](41);"
2775       "}");
2776   CHECK_EQ(42 * 5 + 40 * 5, context->Global()
2777                                 ->Get(context.local(), v8_str("result"))
2778                                 .ToLocalChecked()
2779                                 ->Int32Value(context.local())
2780                                 .FromJust());
2781 }
2782 
2783 
2784 // Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
2785 // on the global object.
THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal)2786 THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
2787   v8::Isolate* isolate = CcTest::isolate();
2788   v8::HandleScope scope(isolate);
2789   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2790   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
2791   LocalContext context;
2792   context->Global()
2793       ->Set(context.local(), v8_str("o"),
2794             templ->NewInstance(context.local()).ToLocalChecked())
2795       .FromJust();
2796   CompileRun(
2797       "function inc(x) { return x + 1; };"
2798       "inc(1);"
2799       "function dec(x) { return x - 1; };"
2800       "dec(1);"
2801       "o.__proto__ = this;"
2802       "this.__proto__.x = inc;"
2803       "this.__proto__.y = dec;"
2804       "var result = 0;"
2805       "var method = 'x';"
2806       "for (var i = 0; i < 10; i++) {"
2807       "  if (i == 5) { method = 'y'; };"
2808       "  result += o[method](41);"
2809       "}");
2810   CHECK_EQ(42 * 5 + 40 * 5, context->Global()
2811                                 ->Get(context.local(), v8_str("result"))
2812                                 .ToLocalChecked()
2813                                 ->Int32Value(context.local())
2814                                 .FromJust());
2815 }
2816 
2817 
2818 // Test the case when actual function to call sits on global object.
THREADED_TEST(InterceptorKeyedCallICFromGlobal)2819 THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
2820   v8::Isolate* isolate = CcTest::isolate();
2821   v8::HandleScope scope(isolate);
2822   v8::Local<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
2823   templ_o->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
2824   LocalContext context;
2825   context->Global()
2826       ->Set(context.local(), v8_str("o"),
2827             templ_o->NewInstance(context.local()).ToLocalChecked())
2828       .FromJust();
2829 
2830   CompileRun(
2831       "function len(x) { return x.length; };"
2832       "o.__proto__ = this;"
2833       "var m = 'parseFloat';"
2834       "var result = 0;"
2835       "for (var i = 0; i < 10; i++) {"
2836       "  if (i == 5) {"
2837       "    m = 'len';"
2838       "    saved_result = result;"
2839       "  };"
2840       "  result = o[m]('239');"
2841       "}");
2842   CHECK_EQ(3, context->Global()
2843                   ->Get(context.local(), v8_str("result"))
2844                   .ToLocalChecked()
2845                   ->Int32Value(context.local())
2846                   .FromJust());
2847   CHECK_EQ(239, context->Global()
2848                     ->Get(context.local(), v8_str("saved_result"))
2849                     .ToLocalChecked()
2850                     ->Int32Value(context.local())
2851                     .FromJust());
2852 }
2853 
2854 
2855 // Test the map transition before the interceptor.
THREADED_TEST(InterceptorKeyedCallICMapChangeBefore)2856 THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
2857   v8::Isolate* isolate = CcTest::isolate();
2858   v8::HandleScope scope(isolate);
2859   v8::Local<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
2860   templ_o->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
2861   LocalContext context;
2862   context->Global()
2863       ->Set(context.local(), v8_str("proto"),
2864             templ_o->NewInstance(context.local()).ToLocalChecked())
2865       .FromJust();
2866 
2867   CompileRun(
2868       "var o = new Object();"
2869       "o.__proto__ = proto;"
2870       "o.method = function(x) { return x + 1; };"
2871       "var m = 'method';"
2872       "var result = 0;"
2873       "for (var i = 0; i < 10; i++) {"
2874       "  if (i == 5) { o.method = function(x) { return x - 1; }; };"
2875       "  result += o[m](41);"
2876       "}");
2877   CHECK_EQ(42 * 5 + 40 * 5, context->Global()
2878                                 ->Get(context.local(), v8_str("result"))
2879                                 .ToLocalChecked()
2880                                 ->Int32Value(context.local())
2881                                 .FromJust());
2882 }
2883 
2884 
2885 // Test the map transition after the interceptor.
THREADED_TEST(InterceptorKeyedCallICMapChangeAfter)2886 THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
2887   v8::Isolate* isolate = CcTest::isolate();
2888   v8::HandleScope scope(isolate);
2889   v8::Local<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
2890   templ_o->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
2891   LocalContext context;
2892   context->Global()
2893       ->Set(context.local(), v8_str("o"),
2894             templ_o->NewInstance(context.local()).ToLocalChecked())
2895       .FromJust();
2896 
2897   CompileRun(
2898       "var proto = new Object();"
2899       "o.__proto__ = proto;"
2900       "proto.method = function(x) { return x + 1; };"
2901       "var m = 'method';"
2902       "var result = 0;"
2903       "for (var i = 0; i < 10; i++) {"
2904       "  if (i == 5) { proto.method = function(x) { return x - 1; }; };"
2905       "  result += o[m](41);"
2906       "}");
2907   CHECK_EQ(42 * 5 + 40 * 5, context->Global()
2908                                 ->Get(context.local(), v8_str("result"))
2909                                 .ToLocalChecked()
2910                                 ->Int32Value(context.local())
2911                                 .FromJust());
2912 }
2913 
2914 
2915 static int interceptor_call_count = 0;
2916 
InterceptorICRefErrorGetter(Local<Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)2917 static void InterceptorICRefErrorGetter(
2918     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2919   ApiTestFuzzer::Fuzz();
2920   if (!is_bootstrapping &&
2921       v8_str("x")
2922           ->Equals(info.GetIsolate()->GetCurrentContext(), name)
2923           .FromJust() &&
2924       interceptor_call_count++ < 20) {
2925     info.GetReturnValue().Set(call_ic_function2);
2926   }
2927 }
2928 
2929 
2930 // This test should hit load and call ICs for the interceptor case.
2931 // Once in a while, the interceptor will reply that a property was not
2932 // found in which case we should get a reference error.
THREADED_TEST(InterceptorICReferenceErrors)2933 THREADED_TEST(InterceptorICReferenceErrors) {
2934   v8::Isolate* isolate = CcTest::isolate();
2935   v8::HandleScope scope(isolate);
2936   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2937   templ->SetHandler(
2938       v8::NamedPropertyHandlerConfiguration(InterceptorICRefErrorGetter));
2939   is_bootstrapping = true;
2940   LocalContext context(0, templ, v8::Local<Value>());
2941   is_bootstrapping = false;
2942   call_ic_function2 = v8_compile("function h(x) { return x; }; h")
2943                           ->Run(context.local())
2944                           .ToLocalChecked();
2945   v8::Local<Value> value = CompileRun(
2946       "function f() {"
2947       "  for (var i = 0; i < 1000; i++) {"
2948       "    try { x; } catch(e) { return true; }"
2949       "  }"
2950       "  return false;"
2951       "};"
2952       "f();");
2953   CHECK_EQ(true, value->BooleanValue(context.local()).FromJust());
2954   interceptor_call_count = 0;
2955   value = CompileRun(
2956       "function g() {"
2957       "  for (var i = 0; i < 1000; i++) {"
2958       "    try { x(42); } catch(e) { return true; }"
2959       "  }"
2960       "  return false;"
2961       "};"
2962       "g();");
2963   CHECK_EQ(true, value->BooleanValue(context.local()).FromJust());
2964 }
2965 
2966 
2967 static int interceptor_ic_exception_get_count = 0;
2968 
InterceptorICExceptionGetter(Local<Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)2969 static void InterceptorICExceptionGetter(
2970     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2971   ApiTestFuzzer::Fuzz();
2972   if (is_bootstrapping) return;
2973   if (v8_str("x")
2974           ->Equals(info.GetIsolate()->GetCurrentContext(), name)
2975           .FromJust() &&
2976       ++interceptor_ic_exception_get_count < 20) {
2977     info.GetReturnValue().Set(call_ic_function3);
2978   }
2979   if (interceptor_ic_exception_get_count == 20) {
2980     info.GetIsolate()->ThrowException(v8_num(42));
2981     return;
2982   }
2983 }
2984 
2985 
2986 // Test interceptor load/call IC where the interceptor throws an
2987 // exception once in a while.
THREADED_TEST(InterceptorICGetterExceptions)2988 THREADED_TEST(InterceptorICGetterExceptions) {
2989   interceptor_ic_exception_get_count = 0;
2990   v8::Isolate* isolate = CcTest::isolate();
2991   v8::HandleScope scope(isolate);
2992   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2993   templ->SetHandler(
2994       v8::NamedPropertyHandlerConfiguration(InterceptorICExceptionGetter));
2995   is_bootstrapping = true;
2996   LocalContext context(0, templ, v8::Local<Value>());
2997   is_bootstrapping = false;
2998   call_ic_function3 = v8_compile("function h(x) { return x; }; h")
2999                           ->Run(context.local())
3000                           .ToLocalChecked();
3001   v8::Local<Value> value = CompileRun(
3002       "function f() {"
3003       "  for (var i = 0; i < 100; i++) {"
3004       "    try { x; } catch(e) { return true; }"
3005       "  }"
3006       "  return false;"
3007       "};"
3008       "f();");
3009   CHECK_EQ(true, value->BooleanValue(context.local()).FromJust());
3010   interceptor_ic_exception_get_count = 0;
3011   value = CompileRun(
3012       "function f() {"
3013       "  for (var i = 0; i < 100; i++) {"
3014       "    try { x(42); } catch(e) { return true; }"
3015       "  }"
3016       "  return false;"
3017       "};"
3018       "f();");
3019   CHECK_EQ(true, value->BooleanValue(context.local()).FromJust());
3020 }
3021 
3022 
3023 static int interceptor_ic_exception_set_count = 0;
3024 
InterceptorICExceptionSetter(Local<Name> key,Local<Value> value,const v8::PropertyCallbackInfo<v8::Value> & info)3025 static void InterceptorICExceptionSetter(
3026     Local<Name> key, Local<Value> value,
3027     const v8::PropertyCallbackInfo<v8::Value>& info) {
3028   ApiTestFuzzer::Fuzz();
3029   if (++interceptor_ic_exception_set_count > 20) {
3030     info.GetIsolate()->ThrowException(v8_num(42));
3031   }
3032 }
3033 
3034 
3035 // Test interceptor store IC where the interceptor throws an exception
3036 // once in a while.
THREADED_TEST(InterceptorICSetterExceptions)3037 THREADED_TEST(InterceptorICSetterExceptions) {
3038   interceptor_ic_exception_set_count = 0;
3039   v8::Isolate* isolate = CcTest::isolate();
3040   v8::HandleScope scope(isolate);
3041   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
3042   templ->SetHandler(
3043       v8::NamedPropertyHandlerConfiguration(0, InterceptorICExceptionSetter));
3044   LocalContext context(0, templ, v8::Local<Value>());
3045   v8::Local<Value> value = CompileRun(
3046       "function f() {"
3047       "  for (var i = 0; i < 100; i++) {"
3048       "    try { x = 42; } catch(e) { return true; }"
3049       "  }"
3050       "  return false;"
3051       "};"
3052       "f();");
3053   CHECK_EQ(true, value->BooleanValue(context.local()).FromJust());
3054 }
3055 
3056 
3057 // Test that we ignore null interceptors.
THREADED_TEST(NullNamedInterceptor)3058 THREADED_TEST(NullNamedInterceptor) {
3059   v8::Isolate* isolate = CcTest::isolate();
3060   v8::HandleScope scope(isolate);
3061   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
3062   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
3063       static_cast<v8::GenericNamedPropertyGetterCallback>(0)));
3064   LocalContext context;
3065   templ->Set(CcTest::isolate(), "x", v8_num(42));
3066   v8::Local<v8::Object> obj =
3067       templ->NewInstance(context.local()).ToLocalChecked();
3068   context->Global()->Set(context.local(), v8_str("obj"), obj).FromJust();
3069   v8::Local<Value> value = CompileRun("obj.x");
3070   CHECK(value->IsInt32());
3071   CHECK_EQ(42, value->Int32Value(context.local()).FromJust());
3072 }
3073 
3074 
3075 // Test that we ignore null interceptors.
THREADED_TEST(NullIndexedInterceptor)3076 THREADED_TEST(NullIndexedInterceptor) {
3077   v8::Isolate* isolate = CcTest::isolate();
3078   v8::HandleScope scope(isolate);
3079   v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
3080   templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
3081       static_cast<v8::IndexedPropertyGetterCallback>(0)));
3082   LocalContext context;
3083   templ->Set(CcTest::isolate(), "42", v8_num(42));
3084   v8::Local<v8::Object> obj =
3085       templ->NewInstance(context.local()).ToLocalChecked();
3086   context->Global()->Set(context.local(), v8_str("obj"), obj).FromJust();
3087   v8::Local<Value> value = CompileRun("obj[42]");
3088   CHECK(value->IsInt32());
3089   CHECK_EQ(42, value->Int32Value(context.local()).FromJust());
3090 }
3091 
3092 
THREADED_TEST(NamedPropertyHandlerGetterAttributes)3093 THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
3094   v8::Isolate* isolate = CcTest::isolate();
3095   v8::HandleScope scope(isolate);
3096   v8::Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
3097   templ->InstanceTemplate()->SetHandler(
3098       v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
3099   LocalContext env;
3100   env->Global()
3101       ->Set(env.local(), v8_str("obj"), templ->GetFunction(env.local())
3102                                             .ToLocalChecked()
3103                                             ->NewInstance(env.local())
3104                                             .ToLocalChecked())
3105       .FromJust();
3106   ExpectTrue("obj.x === 42");
3107   ExpectTrue("!obj.propertyIsEnumerable('x')");
3108 }
3109 
3110 
THREADED_TEST(Regress256330)3111 THREADED_TEST(Regress256330) {
3112   i::FLAG_allow_natives_syntax = true;
3113   LocalContext context;
3114   v8::HandleScope scope(context->GetIsolate());
3115   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
3116   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
3117   context->Global()
3118       ->Set(context.local(), v8_str("Bug"),
3119             templ->GetFunction(context.local()).ToLocalChecked())
3120       .FromJust();
3121   CompileRun(
3122       "\"use strict\"; var o = new Bug;"
3123       "function f(o) { o.x = 10; };"
3124       "f(o); f(o); f(o);"
3125       "%OptimizeFunctionOnNextCall(f);"
3126       "f(o);");
3127   ExpectBoolean("%GetOptimizationStatus(f) != 2", true);
3128 }
3129 
3130 
THREADED_TEST(CrankshaftInterceptorSetter)3131 THREADED_TEST(CrankshaftInterceptorSetter) {
3132   i::FLAG_allow_natives_syntax = true;
3133   v8::HandleScope scope(CcTest::isolate());
3134   Local<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
3135   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
3136   LocalContext env;
3137   env->Global()
3138       ->Set(env.local(), v8_str("Obj"),
3139             templ->GetFunction(env.local()).ToLocalChecked())
3140       .FromJust();
3141   CompileRun(
3142       "var obj = new Obj;"
3143       // Initialize fields to avoid transitions later.
3144       "obj.age = 0;"
3145       "obj.accessor_age = 42;"
3146       "function setter(i) { this.accessor_age = i; };"
3147       "function getter() { return this.accessor_age; };"
3148       "function setAge(i) { obj.age = i; };"
3149       "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
3150       "setAge(1);"
3151       "setAge(2);"
3152       "setAge(3);"
3153       "%OptimizeFunctionOnNextCall(setAge);"
3154       "setAge(4);");
3155   // All stores went through the interceptor.
3156   ExpectInt32("obj.interceptor_age", 4);
3157   ExpectInt32("obj.accessor_age", 42);
3158 }
3159 
3160 
THREADED_TEST(CrankshaftInterceptorGetter)3161 THREADED_TEST(CrankshaftInterceptorGetter) {
3162   i::FLAG_allow_natives_syntax = true;
3163   v8::HandleScope scope(CcTest::isolate());
3164   Local<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
3165   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
3166   LocalContext env;
3167   env->Global()
3168       ->Set(env.local(), v8_str("Obj"),
3169             templ->GetFunction(env.local()).ToLocalChecked())
3170       .FromJust();
3171   CompileRun(
3172       "var obj = new Obj;"
3173       // Initialize fields to avoid transitions later.
3174       "obj.age = 1;"
3175       "obj.accessor_age = 42;"
3176       "function getter() { return this.accessor_age; };"
3177       "function getAge() { return obj.interceptor_age; };"
3178       "Object.defineProperty(obj, 'interceptor_age', { get:getter });"
3179       "getAge();"
3180       "getAge();"
3181       "getAge();"
3182       "%OptimizeFunctionOnNextCall(getAge);");
3183   // Access through interceptor.
3184   ExpectInt32("getAge()", 1);
3185 }
3186 
3187 
THREADED_TEST(CrankshaftInterceptorFieldRead)3188 THREADED_TEST(CrankshaftInterceptorFieldRead) {
3189   i::FLAG_allow_natives_syntax = true;
3190   v8::HandleScope scope(CcTest::isolate());
3191   Local<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
3192   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
3193   LocalContext env;
3194   env->Global()
3195       ->Set(env.local(), v8_str("Obj"),
3196             templ->GetFunction(env.local()).ToLocalChecked())
3197       .FromJust();
3198   CompileRun(
3199       "var obj = new Obj;"
3200       "obj.__proto__.interceptor_age = 42;"
3201       "obj.age = 100;"
3202       "function getAge() { return obj.interceptor_age; };");
3203   ExpectInt32("getAge();", 100);
3204   ExpectInt32("getAge();", 100);
3205   ExpectInt32("getAge();", 100);
3206   CompileRun("%OptimizeFunctionOnNextCall(getAge);");
3207   // Access through interceptor.
3208   ExpectInt32("getAge();", 100);
3209 }
3210 
3211 
THREADED_TEST(CrankshaftInterceptorFieldWrite)3212 THREADED_TEST(CrankshaftInterceptorFieldWrite) {
3213   i::FLAG_allow_natives_syntax = true;
3214   v8::HandleScope scope(CcTest::isolate());
3215   Local<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
3216   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
3217   LocalContext env;
3218   env->Global()
3219       ->Set(env.local(), v8_str("Obj"),
3220             templ->GetFunction(env.local()).ToLocalChecked())
3221       .FromJust();
3222   CompileRun(
3223       "var obj = new Obj;"
3224       "obj.age = 100000;"
3225       "function setAge(i) { obj.age = i };"
3226       "setAge(100);"
3227       "setAge(101);"
3228       "setAge(102);"
3229       "%OptimizeFunctionOnNextCall(setAge);"
3230       "setAge(103);");
3231   ExpectInt32("obj.age", 100000);
3232   ExpectInt32("obj.interceptor_age", 103);
3233 }
3234 
3235 
THREADED_TEST(Regress149912)3236 THREADED_TEST(Regress149912) {
3237   LocalContext context;
3238   v8::HandleScope scope(context->GetIsolate());
3239   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
3240   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
3241   context->Global()
3242       ->Set(context.local(), v8_str("Bug"),
3243             templ->GetFunction(context.local()).ToLocalChecked())
3244       .FromJust();
3245   CompileRun("Number.prototype.__proto__ = new Bug; var x = 0; x.foo();");
3246 }
3247 
3248 
THREADED_TEST(Regress125988)3249 THREADED_TEST(Regress125988) {
3250   v8::HandleScope scope(CcTest::isolate());
3251   Local<FunctionTemplate> intercept = FunctionTemplate::New(CcTest::isolate());
3252   AddInterceptor(intercept, EmptyInterceptorGetter, EmptyInterceptorSetter);
3253   LocalContext env;
3254   env->Global()
3255       ->Set(env.local(), v8_str("Intercept"),
3256             intercept->GetFunction(env.local()).ToLocalChecked())
3257       .FromJust();
3258   CompileRun(
3259       "var a = new Object();"
3260       "var b = new Intercept();"
3261       "var c = new Object();"
3262       "c.__proto__ = b;"
3263       "b.__proto__ = a;"
3264       "a.x = 23;"
3265       "for (var i = 0; i < 3; i++) c.x;");
3266   ExpectBoolean("c.hasOwnProperty('x')", false);
3267   ExpectInt32("c.x", 23);
3268   CompileRun(
3269       "a.y = 42;"
3270       "for (var i = 0; i < 3; i++) c.x;");
3271   ExpectBoolean("c.hasOwnProperty('x')", false);
3272   ExpectInt32("c.x", 23);
3273   ExpectBoolean("c.hasOwnProperty('y')", false);
3274   ExpectInt32("c.y", 42);
3275 }
3276 
3277 
IndexedPropertyEnumerator(const v8::PropertyCallbackInfo<v8::Array> & info)3278 static void IndexedPropertyEnumerator(
3279     const v8::PropertyCallbackInfo<v8::Array>& info) {
3280   v8::Local<v8::Array> result = v8::Array::New(info.GetIsolate(), 1);
3281   result->Set(info.GetIsolate()->GetCurrentContext(), 0,
3282               v8::Integer::New(info.GetIsolate(), 7))
3283       .FromJust();
3284   info.GetReturnValue().Set(result);
3285 }
3286 
3287 
NamedPropertyEnumerator(const v8::PropertyCallbackInfo<v8::Array> & info)3288 static void NamedPropertyEnumerator(
3289     const v8::PropertyCallbackInfo<v8::Array>& info) {
3290   v8::Local<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
3291   v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
3292   result->Set(context, 0, v8_str("x")).FromJust();
3293   result->Set(context, 1, v8::Symbol::GetIterator(info.GetIsolate()))
3294       .FromJust();
3295   info.GetReturnValue().Set(result);
3296 }
3297 
3298 
THREADED_TEST(GetOwnPropertyNamesWithInterceptor)3299 THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
3300   v8::Isolate* isolate = CcTest::isolate();
3301   v8::HandleScope handle_scope(isolate);
3302   v8::Local<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New(isolate);
3303 
3304   obj_template->Set(v8_str("7"), v8::Integer::New(CcTest::isolate(), 7));
3305   obj_template->Set(v8_str("x"), v8::Integer::New(CcTest::isolate(), 42));
3306   obj_template->SetHandler(v8::IndexedPropertyHandlerConfiguration(
3307       NULL, NULL, NULL, NULL, IndexedPropertyEnumerator));
3308   obj_template->SetHandler(v8::NamedPropertyHandlerConfiguration(
3309       NULL, NULL, NULL, NULL, NamedPropertyEnumerator));
3310 
3311   LocalContext context;
3312   v8::Local<v8::Object> global = context->Global();
3313   global->Set(context.local(), v8_str("object"),
3314               obj_template->NewInstance(context.local()).ToLocalChecked())
3315       .FromJust();
3316 
3317   v8::Local<v8::Value> result =
3318       CompileRun("Object.getOwnPropertyNames(object)");
3319   CHECK(result->IsArray());
3320   v8::Local<v8::Array> result_array = v8::Local<v8::Array>::Cast(result);
3321   CHECK_EQ(2u, result_array->Length());
3322   CHECK(result_array->Get(context.local(), 0).ToLocalChecked()->IsString());
3323   CHECK(result_array->Get(context.local(), 1).ToLocalChecked()->IsString());
3324   CHECK(v8_str("7")
3325             ->Equals(context.local(),
3326                      result_array->Get(context.local(), 0).ToLocalChecked())
3327             .FromJust());
3328   CHECK(v8_str("x")
3329             ->Equals(context.local(),
3330                      result_array->Get(context.local(), 1).ToLocalChecked())
3331             .FromJust());
3332 
3333   result = CompileRun("var ret = []; for (var k in object) ret.push(k); ret");
3334   CHECK(result->IsArray());
3335   result_array = v8::Local<v8::Array>::Cast(result);
3336   CHECK_EQ(2u, result_array->Length());
3337   CHECK(result_array->Get(context.local(), 0).ToLocalChecked()->IsString());
3338   CHECK(result_array->Get(context.local(), 1).ToLocalChecked()->IsString());
3339   CHECK(v8_str("7")
3340             ->Equals(context.local(),
3341                      result_array->Get(context.local(), 0).ToLocalChecked())
3342             .FromJust());
3343   CHECK(v8_str("x")
3344             ->Equals(context.local(),
3345                      result_array->Get(context.local(), 1).ToLocalChecked())
3346             .FromJust());
3347 
3348   result = CompileRun("Object.getOwnPropertySymbols(object)");
3349   CHECK(result->IsArray());
3350   result_array = v8::Local<v8::Array>::Cast(result);
3351   CHECK_EQ(1u, result_array->Length());
3352   CHECK(result_array->Get(context.local(), 0)
3353             .ToLocalChecked()
3354             ->Equals(context.local(), v8::Symbol::GetIterator(isolate))
3355             .FromJust());
3356 }
3357 
3358 
IndexedPropertyEnumeratorException(const v8::PropertyCallbackInfo<v8::Array> & info)3359 static void IndexedPropertyEnumeratorException(
3360     const v8::PropertyCallbackInfo<v8::Array>& info) {
3361   info.GetIsolate()->ThrowException(v8_num(42));
3362 }
3363 
3364 
THREADED_TEST(GetOwnPropertyNamesWithIndexedInterceptorExceptions_regress4026)3365 THREADED_TEST(GetOwnPropertyNamesWithIndexedInterceptorExceptions_regress4026) {
3366   v8::Isolate* isolate = CcTest::isolate();
3367   v8::HandleScope handle_scope(isolate);
3368   v8::Local<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New(isolate);
3369 
3370   obj_template->Set(v8_str("7"), v8::Integer::New(CcTest::isolate(), 7));
3371   obj_template->Set(v8_str("x"), v8::Integer::New(CcTest::isolate(), 42));
3372   // First just try a failing indexed interceptor.
3373   obj_template->SetHandler(v8::IndexedPropertyHandlerConfiguration(
3374       NULL, NULL, NULL, NULL, IndexedPropertyEnumeratorException));
3375 
3376   LocalContext context;
3377   v8::Local<v8::Object> global = context->Global();
3378   global->Set(context.local(), v8_str("object"),
3379               obj_template->NewInstance(context.local()).ToLocalChecked())
3380       .FromJust();
3381   v8::Local<v8::Value> result = CompileRun(
3382       "var result  = []; "
3383       "try { "
3384       "  for (var k in object) result .push(k);"
3385       "} catch (e) {"
3386       "  result  = e"
3387       "}"
3388       "result ");
3389   CHECK(!result->IsArray());
3390   CHECK(v8_num(42)->Equals(context.local(), result).FromJust());
3391 
3392   result = CompileRun(
3393       "var result = [];"
3394       "try { "
3395       "  result = Object.keys(object);"
3396       "} catch (e) {"
3397       "  result = e;"
3398       "}"
3399       "result");
3400   CHECK(!result->IsArray());
3401   CHECK(v8_num(42)->Equals(context.local(), result).FromJust());
3402 }
3403 
3404 
NamedPropertyEnumeratorException(const v8::PropertyCallbackInfo<v8::Array> & info)3405 static void NamedPropertyEnumeratorException(
3406     const v8::PropertyCallbackInfo<v8::Array>& info) {
3407   info.GetIsolate()->ThrowException(v8_num(43));
3408 }
3409 
3410 
THREADED_TEST(GetOwnPropertyNamesWithNamedInterceptorExceptions_regress4026)3411 THREADED_TEST(GetOwnPropertyNamesWithNamedInterceptorExceptions_regress4026) {
3412   v8::Isolate* isolate = CcTest::isolate();
3413   v8::HandleScope handle_scope(isolate);
3414   v8::Local<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New(isolate);
3415 
3416   obj_template->Set(v8_str("7"), v8::Integer::New(CcTest::isolate(), 7));
3417   obj_template->Set(v8_str("x"), v8::Integer::New(CcTest::isolate(), 42));
3418   // First just try a failing indexed interceptor.
3419   obj_template->SetHandler(v8::NamedPropertyHandlerConfiguration(
3420       NULL, NULL, NULL, NULL, NamedPropertyEnumeratorException));
3421 
3422   LocalContext context;
3423   v8::Local<v8::Object> global = context->Global();
3424   global->Set(context.local(), v8_str("object"),
3425               obj_template->NewInstance(context.local()).ToLocalChecked())
3426       .FromJust();
3427 
3428   v8::Local<v8::Value> result = CompileRun(
3429       "var result = []; "
3430       "try { "
3431       "  for (var k in object) result.push(k);"
3432       "} catch (e) {"
3433       "  result = e"
3434       "}"
3435       "result");
3436   CHECK(!result->IsArray());
3437   CHECK(v8_num(43)->Equals(context.local(), result).FromJust());
3438 
3439   result = CompileRun(
3440       "var result = [];"
3441       "try { "
3442       "  result = Object.keys(object);"
3443       "} catch (e) {"
3444       "  result = e;"
3445       "}"
3446       "result");
3447   CHECK(!result->IsArray());
3448   CHECK(v8_num(43)->Equals(context.local(), result).FromJust());
3449 }
3450 
3451 namespace {
3452 
3453 template <typename T>
BuildWrappedObject(v8::Isolate * isolate,T * data)3454 Local<Object> BuildWrappedObject(v8::Isolate* isolate, T* data) {
3455   auto templ = v8::ObjectTemplate::New(isolate);
3456   templ->SetInternalFieldCount(1);
3457   auto instance =
3458       templ->NewInstance(isolate->GetCurrentContext()).ToLocalChecked();
3459   instance->SetAlignedPointerInInternalField(0, data);
3460   return instance;
3461 }
3462 
3463 
3464 template <typename T>
GetWrappedObject(Local<Value> data)3465 T* GetWrappedObject(Local<Value> data) {
3466   return reinterpret_cast<T*>(
3467       Object::Cast(*data)->GetAlignedPointerFromInternalField(0));
3468 }
3469 
3470 
3471 struct AccessCheckData {
3472   int count;
3473   bool result;
3474 };
3475 
3476 AccessCheckData* g_access_check_data = nullptr;
3477 
3478 
SimpleAccessChecker(Local<v8::Context> accessing_context,Local<v8::Object> access_object)3479 bool SimpleAccessChecker(Local<v8::Context> accessing_context,
3480                          Local<v8::Object> access_object) {
3481   g_access_check_data->count++;
3482   return g_access_check_data->result;
3483 }
3484 
3485 
3486 struct ShouldInterceptData {
3487   int value;
3488   bool should_intercept;
3489 };
3490 
3491 
ShouldNamedInterceptor(Local<Name> name,const v8::PropertyCallbackInfo<Value> & info)3492 void ShouldNamedInterceptor(Local<Name> name,
3493                             const v8::PropertyCallbackInfo<Value>& info) {
3494   ApiTestFuzzer::Fuzz();
3495   CheckReturnValue(info, FUNCTION_ADDR(ShouldNamedInterceptor));
3496   auto data = GetWrappedObject<ShouldInterceptData>(info.Data());
3497   if (!data->should_intercept) return;
3498   info.GetReturnValue().Set(v8_num(data->value));
3499 }
3500 
3501 
ShouldIndexedInterceptor(uint32_t,const v8::PropertyCallbackInfo<Value> & info)3502 void ShouldIndexedInterceptor(uint32_t,
3503                               const v8::PropertyCallbackInfo<Value>& info) {
3504   ApiTestFuzzer::Fuzz();
3505   CheckReturnValue(info, FUNCTION_ADDR(ShouldIndexedInterceptor));
3506   auto data = GetWrappedObject<ShouldInterceptData>(info.Data());
3507   if (!data->should_intercept) return;
3508   info.GetReturnValue().Set(v8_num(data->value));
3509 }
3510 
3511 }  // namespace
3512 
3513 
TEST(NamedAllCanReadInterceptor)3514 TEST(NamedAllCanReadInterceptor) {
3515   auto isolate = CcTest::isolate();
3516   v8::HandleScope handle_scope(isolate);
3517   LocalContext context;
3518 
3519   AccessCheckData access_check_data;
3520   access_check_data.result = true;
3521   access_check_data.count = 0;
3522 
3523   g_access_check_data = &access_check_data;
3524 
3525   ShouldInterceptData intercept_data_0;
3526   intercept_data_0.value = 239;
3527   intercept_data_0.should_intercept = true;
3528 
3529   ShouldInterceptData intercept_data_1;
3530   intercept_data_1.value = 165;
3531   intercept_data_1.should_intercept = false;
3532 
3533   auto intercepted_0 = v8::ObjectTemplate::New(isolate);
3534   {
3535     v8::NamedPropertyHandlerConfiguration conf(ShouldNamedInterceptor);
3536     conf.flags = v8::PropertyHandlerFlags::kAllCanRead;
3537     conf.data =
3538         BuildWrappedObject<ShouldInterceptData>(isolate, &intercept_data_0);
3539     intercepted_0->SetHandler(conf);
3540   }
3541 
3542   auto intercepted_1 = v8::ObjectTemplate::New(isolate);
3543   {
3544     v8::NamedPropertyHandlerConfiguration conf(ShouldNamedInterceptor);
3545     conf.flags = v8::PropertyHandlerFlags::kAllCanRead;
3546     conf.data =
3547         BuildWrappedObject<ShouldInterceptData>(isolate, &intercept_data_1);
3548     intercepted_1->SetHandler(conf);
3549   }
3550 
3551   auto checked = v8::ObjectTemplate::New(isolate);
3552   checked->SetAccessCheckCallback(SimpleAccessChecker);
3553 
3554   context->Global()
3555       ->Set(context.local(), v8_str("intercepted_0"),
3556             intercepted_0->NewInstance(context.local()).ToLocalChecked())
3557       .FromJust();
3558   context->Global()
3559       ->Set(context.local(), v8_str("intercepted_1"),
3560             intercepted_1->NewInstance(context.local()).ToLocalChecked())
3561       .FromJust();
3562   auto checked_instance =
3563       checked->NewInstance(context.local()).ToLocalChecked();
3564   checked_instance->Set(context.local(), v8_str("whatever"), v8_num(17))
3565       .FromJust();
3566   context->Global()
3567       ->Set(context.local(), v8_str("checked"), checked_instance)
3568       .FromJust();
3569   CompileRun(
3570       "checked.__proto__ = intercepted_1;"
3571       "intercepted_1.__proto__ = intercepted_0;");
3572 
3573   CHECK_EQ(3, access_check_data.count);
3574 
3575   ExpectInt32("checked.whatever", 17);
3576   CHECK(!CompileRun("Object.getOwnPropertyDescriptor(checked, 'whatever')")
3577              ->IsUndefined());
3578   CHECK_EQ(5, access_check_data.count);
3579 
3580   access_check_data.result = false;
3581   ExpectInt32("checked.whatever", intercept_data_0.value);
3582   {
3583     v8::TryCatch try_catch(isolate);
3584     CompileRun("Object.getOwnPropertyDescriptor(checked, 'whatever')");
3585     CHECK(try_catch.HasCaught());
3586   }
3587   CHECK_EQ(7, access_check_data.count);
3588 
3589   intercept_data_1.should_intercept = true;
3590   ExpectInt32("checked.whatever", intercept_data_1.value);
3591   {
3592     v8::TryCatch try_catch(isolate);
3593     CompileRun("Object.getOwnPropertyDescriptor(checked, 'whatever')");
3594     CHECK(try_catch.HasCaught());
3595   }
3596   CHECK_EQ(9, access_check_data.count);
3597   g_access_check_data = nullptr;
3598 }
3599 
3600 
TEST(IndexedAllCanReadInterceptor)3601 TEST(IndexedAllCanReadInterceptor) {
3602   auto isolate = CcTest::isolate();
3603   v8::HandleScope handle_scope(isolate);
3604   LocalContext context;
3605 
3606   AccessCheckData access_check_data;
3607   access_check_data.result = true;
3608   access_check_data.count = 0;
3609 
3610   g_access_check_data = &access_check_data;
3611 
3612   ShouldInterceptData intercept_data_0;
3613   intercept_data_0.value = 239;
3614   intercept_data_0.should_intercept = true;
3615 
3616   ShouldInterceptData intercept_data_1;
3617   intercept_data_1.value = 165;
3618   intercept_data_1.should_intercept = false;
3619 
3620   auto intercepted_0 = v8::ObjectTemplate::New(isolate);
3621   {
3622     v8::IndexedPropertyHandlerConfiguration conf(ShouldIndexedInterceptor);
3623     conf.flags = v8::PropertyHandlerFlags::kAllCanRead;
3624     conf.data =
3625         BuildWrappedObject<ShouldInterceptData>(isolate, &intercept_data_0);
3626     intercepted_0->SetHandler(conf);
3627   }
3628 
3629   auto intercepted_1 = v8::ObjectTemplate::New(isolate);
3630   {
3631     v8::IndexedPropertyHandlerConfiguration conf(ShouldIndexedInterceptor);
3632     conf.flags = v8::PropertyHandlerFlags::kAllCanRead;
3633     conf.data =
3634         BuildWrappedObject<ShouldInterceptData>(isolate, &intercept_data_1);
3635     intercepted_1->SetHandler(conf);
3636   }
3637 
3638   auto checked = v8::ObjectTemplate::New(isolate);
3639   checked->SetAccessCheckCallback(SimpleAccessChecker);
3640 
3641   context->Global()
3642       ->Set(context.local(), v8_str("intercepted_0"),
3643             intercepted_0->NewInstance(context.local()).ToLocalChecked())
3644       .FromJust();
3645   context->Global()
3646       ->Set(context.local(), v8_str("intercepted_1"),
3647             intercepted_1->NewInstance(context.local()).ToLocalChecked())
3648       .FromJust();
3649   auto checked_instance =
3650       checked->NewInstance(context.local()).ToLocalChecked();
3651   context->Global()
3652       ->Set(context.local(), v8_str("checked"), checked_instance)
3653       .FromJust();
3654   checked_instance->Set(context.local(), 15, v8_num(17)).FromJust();
3655   CompileRun(
3656       "checked.__proto__ = intercepted_1;"
3657       "intercepted_1.__proto__ = intercepted_0;");
3658 
3659   CHECK_EQ(3, access_check_data.count);
3660 
3661   access_check_data.result = true;
3662   ExpectInt32("checked[15]", 17);
3663   CHECK(!CompileRun("Object.getOwnPropertyDescriptor(checked, '15')")
3664              ->IsUndefined());
3665   CHECK_EQ(5, access_check_data.count);
3666 
3667   access_check_data.result = false;
3668   ExpectInt32("checked[15]", intercept_data_0.value);
3669   {
3670     v8::TryCatch try_catch(isolate);
3671     CompileRun("Object.getOwnPropertyDescriptor(checked, '15')");
3672     CHECK(try_catch.HasCaught());
3673   }
3674   CHECK_EQ(7, access_check_data.count);
3675 
3676   intercept_data_1.should_intercept = true;
3677   ExpectInt32("checked[15]", intercept_data_1.value);
3678   {
3679     v8::TryCatch try_catch(isolate);
3680     CompileRun("Object.getOwnPropertyDescriptor(checked, '15')");
3681     CHECK(try_catch.HasCaught());
3682   }
3683   CHECK_EQ(9, access_check_data.count);
3684 
3685   g_access_check_data = nullptr;
3686 }
3687 
3688 
THREADED_TEST(NonMaskingInterceptorOwnProperty)3689 THREADED_TEST(NonMaskingInterceptorOwnProperty) {
3690   auto isolate = CcTest::isolate();
3691   v8::HandleScope handle_scope(isolate);
3692   LocalContext context;
3693 
3694   ShouldInterceptData intercept_data;
3695   intercept_data.value = 239;
3696   intercept_data.should_intercept = true;
3697 
3698   auto interceptor_templ = v8::ObjectTemplate::New(isolate);
3699   v8::NamedPropertyHandlerConfiguration conf(ShouldNamedInterceptor);
3700   conf.flags = v8::PropertyHandlerFlags::kNonMasking;
3701   conf.data = BuildWrappedObject<ShouldInterceptData>(isolate, &intercept_data);
3702   interceptor_templ->SetHandler(conf);
3703 
3704   auto interceptor =
3705       interceptor_templ->NewInstance(context.local()).ToLocalChecked();
3706   context->Global()
3707       ->Set(context.local(), v8_str("obj"), interceptor)
3708       .FromJust();
3709 
3710   ExpectInt32("obj.whatever", 239);
3711 
3712   CompileRun("obj.whatever = 4;");
3713   ExpectInt32("obj.whatever", 4);
3714 
3715   CompileRun("delete obj.whatever;");
3716   ExpectInt32("obj.whatever", 239);
3717 }
3718 
3719 
THREADED_TEST(NonMaskingInterceptorPrototypeProperty)3720 THREADED_TEST(NonMaskingInterceptorPrototypeProperty) {
3721   auto isolate = CcTest::isolate();
3722   v8::HandleScope handle_scope(isolate);
3723   LocalContext context;
3724 
3725   ShouldInterceptData intercept_data;
3726   intercept_data.value = 239;
3727   intercept_data.should_intercept = true;
3728 
3729   auto interceptor_templ = v8::ObjectTemplate::New(isolate);
3730   v8::NamedPropertyHandlerConfiguration conf(ShouldNamedInterceptor);
3731   conf.flags = v8::PropertyHandlerFlags::kNonMasking;
3732   conf.data = BuildWrappedObject<ShouldInterceptData>(isolate, &intercept_data);
3733   interceptor_templ->SetHandler(conf);
3734 
3735   auto interceptor =
3736       interceptor_templ->NewInstance(context.local()).ToLocalChecked();
3737   context->Global()
3738       ->Set(context.local(), v8_str("obj"), interceptor)
3739       .FromJust();
3740 
3741   ExpectInt32("obj.whatever", 239);
3742 
3743   CompileRun("obj.__proto__ = {'whatever': 4};");
3744   ExpectInt32("obj.whatever", 4);
3745 
3746   CompileRun("delete obj.__proto__.whatever;");
3747   ExpectInt32("obj.whatever", 239);
3748 }
3749 
3750 
THREADED_TEST(NonMaskingInterceptorPrototypePropertyIC)3751 THREADED_TEST(NonMaskingInterceptorPrototypePropertyIC) {
3752   auto isolate = CcTest::isolate();
3753   v8::HandleScope handle_scope(isolate);
3754   LocalContext context;
3755 
3756   ShouldInterceptData intercept_data;
3757   intercept_data.value = 239;
3758   intercept_data.should_intercept = true;
3759 
3760   auto interceptor_templ = v8::ObjectTemplate::New(isolate);
3761   v8::NamedPropertyHandlerConfiguration conf(ShouldNamedInterceptor);
3762   conf.flags = v8::PropertyHandlerFlags::kNonMasking;
3763   conf.data = BuildWrappedObject<ShouldInterceptData>(isolate, &intercept_data);
3764   interceptor_templ->SetHandler(conf);
3765 
3766   auto interceptor =
3767       interceptor_templ->NewInstance(context.local()).ToLocalChecked();
3768   context->Global()
3769       ->Set(context.local(), v8_str("obj"), interceptor)
3770       .FromJust();
3771 
3772   CompileRun(
3773       "outer = {};"
3774       "outer.__proto__ = obj;"
3775       "function f(obj) {"
3776       "  var x;"
3777       "  for (var i = 0; i < 4; i++) {"
3778       "    x = obj.whatever;"
3779       "  }"
3780       "  return x;"
3781       "}");
3782 
3783   // Receiver == holder.
3784   CompileRun("obj.__proto__ = null;");
3785   ExpectInt32("f(obj)", 239);
3786   ExpectInt32("f(outer)", 239);
3787 
3788   // Receiver != holder.
3789   CompileRun("Object.setPrototypeOf(obj, {});");
3790   ExpectInt32("f(obj)", 239);
3791   ExpectInt32("f(outer)", 239);
3792 
3793   // Masked value on prototype.
3794   CompileRun("obj.__proto__.whatever = 4;");
3795   CompileRun("obj.__proto__.__proto__ = { 'whatever' : 5 };");
3796   ExpectInt32("f(obj)", 4);
3797   ExpectInt32("f(outer)", 4);
3798 
3799   // Masked value on prototype prototype.
3800   CompileRun("delete obj.__proto__.whatever;");
3801   ExpectInt32("f(obj)", 5);
3802   ExpectInt32("f(outer)", 5);
3803 
3804   // Reset.
3805   CompileRun("delete obj.__proto__.__proto__.whatever;");
3806   ExpectInt32("f(obj)", 239);
3807   ExpectInt32("f(outer)", 239);
3808 
3809   // Masked value on self.
3810   CompileRun("obj.whatever = 4;");
3811   ExpectInt32("f(obj)", 4);
3812   ExpectInt32("f(outer)", 4);
3813 
3814   // Reset.
3815   CompileRun("delete obj.whatever;");
3816   ExpectInt32("f(obj)", 239);
3817   ExpectInt32("f(outer)", 239);
3818 
3819   CompileRun("outer.whatever = 4;");
3820   ExpectInt32("f(obj)", 239);
3821   ExpectInt32("f(outer)", 4);
3822 }
3823 
3824 
3825 namespace {
3826 
DatabaseGetter(Local<Name> name,const v8::PropertyCallbackInfo<Value> & info)3827 void DatabaseGetter(Local<Name> name,
3828                     const v8::PropertyCallbackInfo<Value>& info) {
3829   ApiTestFuzzer::Fuzz();
3830   auto context = info.GetIsolate()->GetCurrentContext();
3831   Local<v8::Object> db = info.Holder()
3832                              ->GetRealNamedProperty(context, v8_str("db"))
3833                              .ToLocalChecked()
3834                              .As<v8::Object>();
3835   if (!db->Has(context, name).FromJust()) return;
3836   info.GetReturnValue().Set(db->Get(context, name).ToLocalChecked());
3837 }
3838 
3839 
DatabaseSetter(Local<Name> name,Local<Value> value,const v8::PropertyCallbackInfo<Value> & info)3840 void DatabaseSetter(Local<Name> name, Local<Value> value,
3841                     const v8::PropertyCallbackInfo<Value>& info) {
3842   ApiTestFuzzer::Fuzz();
3843   auto context = info.GetIsolate()->GetCurrentContext();
3844   if (name->Equals(context, v8_str("db")).FromJust()) return;
3845   Local<v8::Object> db = info.Holder()
3846                              ->GetRealNamedProperty(context, v8_str("db"))
3847                              .ToLocalChecked()
3848                              .As<v8::Object>();
3849   db->Set(context, name, value).FromJust();
3850   info.GetReturnValue().Set(value);
3851 }
3852 
3853 }  // namespace
3854 
3855 
THREADED_TEST(NonMaskingInterceptorGlobalEvalRegression)3856 THREADED_TEST(NonMaskingInterceptorGlobalEvalRegression) {
3857   auto isolate = CcTest::isolate();
3858   v8::HandleScope handle_scope(isolate);
3859   LocalContext context;
3860 
3861   auto interceptor_templ = v8::ObjectTemplate::New(isolate);
3862   v8::NamedPropertyHandlerConfiguration conf(DatabaseGetter, DatabaseSetter);
3863   conf.flags = v8::PropertyHandlerFlags::kNonMasking;
3864   interceptor_templ->SetHandler(conf);
3865 
3866   context->Global()
3867       ->Set(context.local(), v8_str("intercepted_1"),
3868             interceptor_templ->NewInstance(context.local()).ToLocalChecked())
3869       .FromJust();
3870   context->Global()
3871       ->Set(context.local(), v8_str("intercepted_2"),
3872             interceptor_templ->NewInstance(context.local()).ToLocalChecked())
3873       .FromJust();
3874 
3875   // Init dbs.
3876   CompileRun(
3877       "intercepted_1.db = {};"
3878       "intercepted_2.db = {};");
3879 
3880   ExpectInt32(
3881       "var obj = intercepted_1;"
3882       "obj.x = 4;"
3883       "eval('obj.x');"
3884       "eval('obj.x');"
3885       "eval('obj.x');"
3886       "obj = intercepted_2;"
3887       "obj.x = 9;"
3888       "eval('obj.x');",
3889       9);
3890 }
3891