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