a2acb24d76472796542fd424b0d20b0b3cec17fa
[platform/upstream/nodejs.git] / deps / v8 / test / cctest / test-api-interceptors.cc
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/parser.h"
17 #include "src/smart-pointers.h"
18 #include "src/snapshot.h"
19 #include "src/unicode-inl.h"
20 #include "src/utils.h"
21 #include "src/vm-state.h"
22
23 using ::v8::Boolean;
24 using ::v8::BooleanObject;
25 using ::v8::Context;
26 using ::v8::Extension;
27 using ::v8::Function;
28 using ::v8::FunctionTemplate;
29 using ::v8::Handle;
30 using ::v8::HandleScope;
31 using ::v8::Local;
32 using ::v8::Name;
33 using ::v8::Message;
34 using ::v8::MessageCallback;
35 using ::v8::Object;
36 using ::v8::ObjectTemplate;
37 using ::v8::Persistent;
38 using ::v8::Script;
39 using ::v8::StackTrace;
40 using ::v8::String;
41 using ::v8::Symbol;
42 using ::v8::TryCatch;
43 using ::v8::Undefined;
44 using ::v8::UniqueId;
45 using ::v8::V8;
46 using ::v8::Value;
47
48
49 namespace {
50
51 void Returns42(const v8::FunctionCallbackInfo<v8::Value>& info) {
52   info.GetReturnValue().Set(42);
53 }
54
55 void Return239Callback(Local<String> name,
56                        const v8::PropertyCallbackInfo<Value>& info) {
57   ApiTestFuzzer::Fuzz();
58   CheckReturnValue(info, FUNCTION_ADDR(Return239Callback));
59   info.GetReturnValue().Set(v8_str("bad value"));
60   info.GetReturnValue().Set(v8_num(239));
61 }
62
63
64 void EmptyInterceptorGetter(Local<Name> name,
65                             const v8::PropertyCallbackInfo<v8::Value>& info) {}
66
67
68 void EmptyInterceptorSetter(Local<Name> name, Local<Value> value,
69                             const v8::PropertyCallbackInfo<v8::Value>& info) {}
70
71
72 void SimpleAccessorGetter(Local<String> name,
73                           const v8::PropertyCallbackInfo<v8::Value>& info) {
74   Handle<Object> self = Handle<Object>::Cast(info.This());
75   info.GetReturnValue().Set(
76       self->Get(String::Concat(v8_str("accessor_"), name)));
77 }
78
79 void SimpleAccessorSetter(Local<String> name, Local<Value> value,
80                           const v8::PropertyCallbackInfo<void>& info) {
81   Handle<Object> self = Handle<Object>::Cast(info.This());
82   self->Set(String::Concat(v8_str("accessor_"), name), value);
83 }
84
85
86 void SymbolAccessorGetter(Local<Name> name,
87                           const v8::PropertyCallbackInfo<v8::Value>& info) {
88   CHECK(name->IsSymbol());
89   Local<Symbol> sym = Local<Symbol>::Cast(name);
90   if (sym->Name()->IsUndefined()) return;
91   SimpleAccessorGetter(Local<String>::Cast(sym->Name()), info);
92 }
93
94 void SymbolAccessorSetter(Local<Name> name, Local<Value> value,
95                           const v8::PropertyCallbackInfo<void>& info) {
96   CHECK(name->IsSymbol());
97   Local<Symbol> sym = Local<Symbol>::Cast(name);
98   if (sym->Name()->IsUndefined()) return;
99   SimpleAccessorSetter(Local<String>::Cast(sym->Name()), value, info);
100 }
101
102 void StringInterceptorGetter(
103     Local<String> name,
104     const v8::PropertyCallbackInfo<v8::Value>&
105         info) {  // Intercept names that start with 'interceptor_'.
106   String::Utf8Value utf8(name);
107   char* name_str = *utf8;
108   char prefix[] = "interceptor_";
109   int i;
110   for (i = 0; name_str[i] && prefix[i]; ++i) {
111     if (name_str[i] != prefix[i]) return;
112   }
113   Handle<Object> self = Handle<Object>::Cast(info.This());
114   info.GetReturnValue().Set(self->GetHiddenValue(v8_str(name_str + i)));
115 }
116
117
118 void StringInterceptorSetter(Local<String> name, Local<Value> value,
119                              const v8::PropertyCallbackInfo<v8::Value>& info) {
120   // Intercept accesses that set certain integer values, for which the name does
121   // not start with 'accessor_'.
122   String::Utf8Value utf8(name);
123   char* name_str = *utf8;
124   char prefix[] = "accessor_";
125   int i;
126   for (i = 0; name_str[i] && prefix[i]; ++i) {
127     if (name_str[i] != prefix[i]) break;
128   }
129   if (!prefix[i]) return;
130
131   if (value->IsInt32() && value->Int32Value() < 10000) {
132     Handle<Object> self = Handle<Object>::Cast(info.This());
133     self->SetHiddenValue(name, value);
134     info.GetReturnValue().Set(value);
135   }
136 }
137
138 void InterceptorGetter(Local<Name> generic_name,
139                        const v8::PropertyCallbackInfo<v8::Value>& info) {
140   if (generic_name->IsSymbol()) return;
141   StringInterceptorGetter(Local<String>::Cast(generic_name), info);
142 }
143
144 void InterceptorSetter(Local<Name> generic_name, Local<Value> value,
145                        const v8::PropertyCallbackInfo<v8::Value>& info) {
146   if (generic_name->IsSymbol()) return;
147   StringInterceptorSetter(Local<String>::Cast(generic_name), value, info);
148 }
149
150 void GenericInterceptorGetter(Local<Name> generic_name,
151                               const v8::PropertyCallbackInfo<v8::Value>& info) {
152   Local<String> str;
153   if (generic_name->IsSymbol()) {
154     Local<Value> name = Local<Symbol>::Cast(generic_name)->Name();
155     if (name->IsUndefined()) return;
156     str = String::Concat(v8_str("_sym_"), Local<String>::Cast(name));
157   } else {
158     Local<String> name = Local<String>::Cast(generic_name);
159     String::Utf8Value utf8(name);
160     char* name_str = *utf8;
161     if (*name_str == '_') return;
162     str = String::Concat(v8_str("_str_"), name);
163   }
164
165   Handle<Object> self = Handle<Object>::Cast(info.This());
166   info.GetReturnValue().Set(self->Get(str));
167 }
168
169 void GenericInterceptorSetter(Local<Name> generic_name, Local<Value> value,
170                               const v8::PropertyCallbackInfo<v8::Value>& info) {
171   Local<String> str;
172   if (generic_name->IsSymbol()) {
173     Local<Value> name = Local<Symbol>::Cast(generic_name)->Name();
174     if (name->IsUndefined()) return;
175     str = String::Concat(v8_str("_sym_"), Local<String>::Cast(name));
176   } else {
177     Local<String> name = Local<String>::Cast(generic_name);
178     String::Utf8Value utf8(name);
179     char* name_str = *utf8;
180     if (*name_str == '_') return;
181     str = String::Concat(v8_str("_str_"), name);
182   }
183
184   Handle<Object> self = Handle<Object>::Cast(info.This());
185   self->Set(str, value);
186   info.GetReturnValue().Set(value);
187 }
188
189 void AddAccessor(Handle<FunctionTemplate> templ, Handle<String> name,
190                  v8::AccessorGetterCallback getter,
191                  v8::AccessorSetterCallback setter) {
192   templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
193 }
194
195 void AddInterceptor(Handle<FunctionTemplate> templ,
196                     v8::NamedPropertyGetterCallback getter,
197                     v8::NamedPropertySetterCallback setter) {
198   templ->InstanceTemplate()->SetNamedPropertyHandler(getter, setter);
199 }
200
201
202 void AddAccessor(Handle<FunctionTemplate> templ, Handle<Name> name,
203                  v8::AccessorNameGetterCallback getter,
204                  v8::AccessorNameSetterCallback setter) {
205   templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
206 }
207
208 void AddInterceptor(Handle<FunctionTemplate> templ,
209                     v8::GenericNamedPropertyGetterCallback getter,
210                     v8::GenericNamedPropertySetterCallback setter) {
211   templ->InstanceTemplate()->SetHandler(
212       v8::NamedPropertyHandlerConfiguration(getter, setter));
213 }
214
215
216 v8::Handle<v8::Object> bottom;
217
218 void CheckThisIndexedPropertyHandler(
219     uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) {
220   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyHandler));
221   ApiTestFuzzer::Fuzz();
222   CHECK(info.This()->Equals(bottom));
223 }
224
225 void CheckThisNamedPropertyHandler(
226     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
227   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyHandler));
228   ApiTestFuzzer::Fuzz();
229   CHECK(info.This()->Equals(bottom));
230 }
231
232 void CheckThisIndexedPropertySetter(
233     uint32_t index, Local<Value> value,
234     const v8::PropertyCallbackInfo<v8::Value>& info) {
235   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertySetter));
236   ApiTestFuzzer::Fuzz();
237   CHECK(info.This()->Equals(bottom));
238 }
239
240
241 void CheckThisNamedPropertySetter(
242     Local<Name> property, Local<Value> value,
243     const v8::PropertyCallbackInfo<v8::Value>& info) {
244   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertySetter));
245   ApiTestFuzzer::Fuzz();
246   CHECK(info.This()->Equals(bottom));
247 }
248
249 void CheckThisIndexedPropertyQuery(
250     uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info) {
251   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyQuery));
252   ApiTestFuzzer::Fuzz();
253   CHECK(info.This()->Equals(bottom));
254 }
255
256
257 void CheckThisNamedPropertyQuery(
258     Local<Name> property, const v8::PropertyCallbackInfo<v8::Integer>& info) {
259   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyQuery));
260   ApiTestFuzzer::Fuzz();
261   CHECK(info.This()->Equals(bottom));
262 }
263
264
265 void CheckThisIndexedPropertyDeleter(
266     uint32_t index, const v8::PropertyCallbackInfo<v8::Boolean>& info) {
267   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyDeleter));
268   ApiTestFuzzer::Fuzz();
269   CHECK(info.This()->Equals(bottom));
270 }
271
272
273 void CheckThisNamedPropertyDeleter(
274     Local<Name> property, const v8::PropertyCallbackInfo<v8::Boolean>& info) {
275   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyDeleter));
276   ApiTestFuzzer::Fuzz();
277   CHECK(info.This()->Equals(bottom));
278 }
279
280
281 void CheckThisIndexedPropertyEnumerator(
282     const v8::PropertyCallbackInfo<v8::Array>& info) {
283   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyEnumerator));
284   ApiTestFuzzer::Fuzz();
285   CHECK(info.This()->Equals(bottom));
286 }
287
288
289 void CheckThisNamedPropertyEnumerator(
290     const v8::PropertyCallbackInfo<v8::Array>& info) {
291   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyEnumerator));
292   ApiTestFuzzer::Fuzz();
293   CHECK(info.This()->Equals(bottom));
294 }
295
296
297 int echo_named_call_count;
298
299
300 void EchoNamedProperty(Local<Name> name,
301                        const v8::PropertyCallbackInfo<v8::Value>& info) {
302   ApiTestFuzzer::Fuzz();
303   CHECK(v8_str("data")->Equals(info.Data()));
304   echo_named_call_count++;
305   info.GetReturnValue().Set(name);
306 }
307
308 void InterceptorHasOwnPropertyGetter(
309     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
310   ApiTestFuzzer::Fuzz();
311 }
312
313 void InterceptorHasOwnPropertyGetterGC(
314     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
315   ApiTestFuzzer::Fuzz();
316   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
317 }
318
319 }  // namespace
320
321
322 THREADED_TEST(InterceptorHasOwnProperty) {
323   LocalContext context;
324   v8::Isolate* isolate = context->GetIsolate();
325   v8::HandleScope scope(isolate);
326   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
327   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
328   instance_templ->SetHandler(
329       v8::NamedPropertyHandlerConfiguration(InterceptorHasOwnPropertyGetter));
330   Local<Function> function = fun_templ->GetFunction();
331   context->Global()->Set(v8_str("constructor"), function);
332   v8::Handle<Value> value = CompileRun(
333       "var o = new constructor();"
334       "o.hasOwnProperty('ostehaps');");
335   CHECK_EQ(false, value->BooleanValue());
336   value = CompileRun(
337       "o.ostehaps = 42;"
338       "o.hasOwnProperty('ostehaps');");
339   CHECK_EQ(true, value->BooleanValue());
340   value = CompileRun(
341       "var p = new constructor();"
342       "p.hasOwnProperty('ostehaps');");
343   CHECK_EQ(false, value->BooleanValue());
344 }
345
346
347 THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
348   LocalContext context;
349   v8::Isolate* isolate = context->GetIsolate();
350   v8::HandleScope scope(isolate);
351   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
352   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
353   instance_templ->SetHandler(
354       v8::NamedPropertyHandlerConfiguration(InterceptorHasOwnPropertyGetterGC));
355   Local<Function> function = fun_templ->GetFunction();
356   context->Global()->Set(v8_str("constructor"), function);
357   // Let's first make some stuff so we can be sure to get a good GC.
358   CompileRun(
359       "function makestr(size) {"
360       "  switch (size) {"
361       "    case 1: return 'f';"
362       "    case 2: return 'fo';"
363       "    case 3: return 'foo';"
364       "  }"
365       "  return makestr(size >> 1) + makestr((size + 1) >> 1);"
366       "}"
367       "var x = makestr(12345);"
368       "x = makestr(31415);"
369       "x = makestr(23456);");
370   v8::Handle<Value> value = CompileRun(
371       "var o = new constructor();"
372       "o.__proto__ = new String(x);"
373       "o.hasOwnProperty('ostehaps');");
374   CHECK_EQ(false, value->BooleanValue());
375 }
376
377
378 static void CheckInterceptorLoadIC(
379     v8::GenericNamedPropertyGetterCallback getter, const char* source,
380     int expected) {
381   v8::Isolate* isolate = CcTest::isolate();
382   v8::HandleScope scope(isolate);
383   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
384   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(getter, 0, 0, 0, 0,
385                                                           v8_str("data")));
386   LocalContext context;
387   context->Global()->Set(v8_str("o"), templ->NewInstance());
388   v8::Handle<Value> value = CompileRun(source);
389   CHECK_EQ(expected, value->Int32Value());
390 }
391
392
393 static void InterceptorLoadICGetter(
394     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
395   ApiTestFuzzer::Fuzz();
396   v8::Isolate* isolate = CcTest::isolate();
397   CHECK_EQ(isolate, info.GetIsolate());
398   CHECK(v8_str("data")->Equals(info.Data()));
399   CHECK(v8_str("x")->Equals(name));
400   info.GetReturnValue().Set(v8::Integer::New(isolate, 42));
401 }
402
403
404 // This test should hit the load IC for the interceptor case.
405 THREADED_TEST(InterceptorLoadIC) {
406   CheckInterceptorLoadIC(InterceptorLoadICGetter,
407                          "var result = 0;"
408                          "for (var i = 0; i < 1000; i++) {"
409                          "  result = o.x;"
410                          "}",
411                          42);
412 }
413
414
415 // Below go several tests which verify that JITing for various
416 // configurations of interceptor and explicit fields works fine
417 // (those cases are special cased to get better performance).
418
419 static void InterceptorLoadXICGetter(
420     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
421   ApiTestFuzzer::Fuzz();
422   info.GetReturnValue().Set(
423       v8_str("x")->Equals(name)
424           ? v8::Handle<v8::Value>(v8::Integer::New(info.GetIsolate(), 42))
425           : v8::Handle<v8::Value>());
426 }
427
428
429 THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
430   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
431                          "var result = 0;"
432                          "o.y = 239;"
433                          "for (var i = 0; i < 1000; i++) {"
434                          "  result = o.y;"
435                          "}",
436                          239);
437 }
438
439
440 THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
441   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
442                          "var result = 0;"
443                          "o.__proto__ = { 'y': 239 };"
444                          "for (var i = 0; i < 1000; i++) {"
445                          "  result = o.y + o.x;"
446                          "}",
447                          239 + 42);
448 }
449
450
451 THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
452   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
453                          "var result = 0;"
454                          "o.__proto__.y = 239;"
455                          "for (var i = 0; i < 1000; i++) {"
456                          "  result = o.y + o.x;"
457                          "}",
458                          239 + 42);
459 }
460
461
462 THREADED_TEST(InterceptorLoadICUndefined) {
463   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
464                          "var result = 0;"
465                          "for (var i = 0; i < 1000; i++) {"
466                          "  result = (o.y == undefined) ? 239 : 42;"
467                          "}",
468                          239);
469 }
470
471
472 THREADED_TEST(InterceptorLoadICWithOverride) {
473   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
474                          "fst = new Object();  fst.__proto__ = o;"
475                          "snd = new Object();  snd.__proto__ = fst;"
476                          "var result1 = 0;"
477                          "for (var i = 0; i < 1000;  i++) {"
478                          "  result1 = snd.x;"
479                          "}"
480                          "fst.x = 239;"
481                          "var result = 0;"
482                          "for (var i = 0; i < 1000; i++) {"
483                          "  result = snd.x;"
484                          "}"
485                          "result + result1",
486                          239 + 42);
487 }
488
489
490 // Test the case when we stored field into
491 // a stub, but interceptor produced value on its own.
492 THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
493   CheckInterceptorLoadIC(
494       InterceptorLoadXICGetter,
495       "proto = new Object();"
496       "o.__proto__ = proto;"
497       "proto.x = 239;"
498       "for (var i = 0; i < 1000; i++) {"
499       "  o.x;"
500       // Now it should be ICed and keep a reference to x defined on proto
501       "}"
502       "var result = 0;"
503       "for (var i = 0; i < 1000; i++) {"
504       "  result += o.x;"
505       "}"
506       "result;",
507       42 * 1000);
508 }
509
510
511 // Test the case when we stored field into
512 // a stub, but it got invalidated later on.
513 THREADED_TEST(InterceptorLoadICInvalidatedField) {
514   CheckInterceptorLoadIC(
515       InterceptorLoadXICGetter,
516       "proto1 = new Object();"
517       "proto2 = new Object();"
518       "o.__proto__ = proto1;"
519       "proto1.__proto__ = proto2;"
520       "proto2.y = 239;"
521       "for (var i = 0; i < 1000; i++) {"
522       "  o.y;"
523       // Now it should be ICed and keep a reference to y defined on proto2
524       "}"
525       "proto1.y = 42;"
526       "var result = 0;"
527       "for (var i = 0; i < 1000; i++) {"
528       "  result += o.y;"
529       "}"
530       "result;",
531       42 * 1000);
532 }
533
534
535 static int interceptor_load_not_handled_calls = 0;
536 static void InterceptorLoadNotHandled(
537     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
538   ++interceptor_load_not_handled_calls;
539 }
540
541
542 // Test how post-interceptor lookups are done in the non-cacheable
543 // case: the interceptor should not be invoked during this lookup.
544 THREADED_TEST(InterceptorLoadICPostInterceptor) {
545   interceptor_load_not_handled_calls = 0;
546   CheckInterceptorLoadIC(InterceptorLoadNotHandled,
547                          "receiver = new Object();"
548                          "receiver.__proto__ = o;"
549                          "proto = new Object();"
550                          "/* Make proto a slow-case object. */"
551                          "for (var i = 0; i < 1000; i++) {"
552                          "  proto[\"xxxxxxxx\" + i] = [];"
553                          "}"
554                          "proto.x = 17;"
555                          "o.__proto__ = proto;"
556                          "var result = 0;"
557                          "for (var i = 0; i < 1000; i++) {"
558                          "  result += receiver.x;"
559                          "}"
560                          "result;",
561                          17 * 1000);
562   CHECK_EQ(1000, interceptor_load_not_handled_calls);
563 }
564
565
566 // Test the case when we stored field into
567 // a stub, but it got invalidated later on due to override on
568 // global object which is between interceptor and fields' holders.
569 THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
570   CheckInterceptorLoadIC(
571       InterceptorLoadXICGetter,
572       "o.__proto__ = this;"  // set a global to be a proto of o.
573       "this.__proto__.y = 239;"
574       "for (var i = 0; i < 10; i++) {"
575       "  if (o.y != 239) throw 'oops: ' + o.y;"
576       // Now it should be ICed and keep a reference to y defined on
577       // field_holder.
578       "}"
579       "this.y = 42;"  // Assign on a global.
580       "var result = 0;"
581       "for (var i = 0; i < 10; i++) {"
582       "  result += o.y;"
583       "}"
584       "result;",
585       42 * 10);
586 }
587
588
589 static void SetOnThis(Local<String> name, Local<Value> value,
590                       const v8::PropertyCallbackInfo<void>& info) {
591   Local<Object>::Cast(info.This())->ForceSet(name, value);
592 }
593
594
595 THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
596   v8::Isolate* isolate = CcTest::isolate();
597   v8::HandleScope scope(isolate);
598   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
599   templ->SetHandler(
600       v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
601   templ->SetAccessor(v8_str("y"), Return239Callback);
602   LocalContext context;
603   context->Global()->Set(v8_str("o"), templ->NewInstance());
604
605   // Check the case when receiver and interceptor's holder
606   // are the same objects.
607   v8::Handle<Value> value = CompileRun(
608       "var result = 0;"
609       "for (var i = 0; i < 7; i++) {"
610       "  result = o.y;"
611       "}");
612   CHECK_EQ(239, value->Int32Value());
613
614   // Check the case when interceptor's holder is in proto chain
615   // of receiver.
616   value = CompileRun(
617       "r = { __proto__: o };"
618       "var result = 0;"
619       "for (var i = 0; i < 7; i++) {"
620       "  result = r.y;"
621       "}");
622   CHECK_EQ(239, value->Int32Value());
623 }
624
625
626 THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
627   v8::Isolate* isolate = CcTest::isolate();
628   v8::HandleScope scope(isolate);
629   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
630   templ_o->SetHandler(
631       v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
632   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
633   templ_p->SetAccessor(v8_str("y"), Return239Callback);
634
635   LocalContext context;
636   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
637   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
638
639   // Check the case when receiver and interceptor's holder
640   // are the same objects.
641   v8::Handle<Value> value = CompileRun(
642       "o.__proto__ = p;"
643       "var result = 0;"
644       "for (var i = 0; i < 7; i++) {"
645       "  result = o.x + o.y;"
646       "}");
647   CHECK_EQ(239 + 42, value->Int32Value());
648
649   // Check the case when interceptor's holder is in proto chain
650   // of receiver.
651   value = CompileRun(
652       "r = { __proto__: o };"
653       "var result = 0;"
654       "for (var i = 0; i < 7; i++) {"
655       "  result = r.x + r.y;"
656       "}");
657   CHECK_EQ(239 + 42, value->Int32Value());
658 }
659
660
661 THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
662   v8::Isolate* isolate = CcTest::isolate();
663   v8::HandleScope scope(isolate);
664   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
665   templ->SetHandler(
666       v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
667   templ->SetAccessor(v8_str("y"), Return239Callback);
668
669   LocalContext context;
670   context->Global()->Set(v8_str("o"), templ->NewInstance());
671
672   v8::Handle<Value> value = CompileRun(
673       "fst = new Object();  fst.__proto__ = o;"
674       "snd = new Object();  snd.__proto__ = fst;"
675       "var result1 = 0;"
676       "for (var i = 0; i < 7;  i++) {"
677       "  result1 = snd.x;"
678       "}"
679       "fst.x = 239;"
680       "var result = 0;"
681       "for (var i = 0; i < 7; i++) {"
682       "  result = snd.x;"
683       "}"
684       "result + result1");
685   CHECK_EQ(239 + 42, value->Int32Value());
686 }
687
688
689 // Test the case when we stored callback into
690 // a stub, but interceptor produced value on its own.
691 THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
692   v8::Isolate* isolate = CcTest::isolate();
693   v8::HandleScope scope(isolate);
694   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
695   templ_o->SetHandler(
696       v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
697   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
698   templ_p->SetAccessor(v8_str("y"), Return239Callback);
699
700   LocalContext context;
701   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
702   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
703
704   v8::Handle<Value> value = CompileRun(
705       "o.__proto__ = p;"
706       "for (var i = 0; i < 7; i++) {"
707       "  o.x;"
708       // Now it should be ICed and keep a reference to x defined on p
709       "}"
710       "var result = 0;"
711       "for (var i = 0; i < 7; i++) {"
712       "  result += o.x;"
713       "}"
714       "result");
715   CHECK_EQ(42 * 7, value->Int32Value());
716 }
717
718
719 // Test the case when we stored callback into
720 // a stub, but it got invalidated later on.
721 THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
722   v8::Isolate* isolate = CcTest::isolate();
723   v8::HandleScope scope(isolate);
724   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
725   templ_o->SetHandler(
726       v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
727   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
728   templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
729
730   LocalContext context;
731   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
732   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
733
734   v8::Handle<Value> value = CompileRun(
735       "inbetween = new Object();"
736       "o.__proto__ = inbetween;"
737       "inbetween.__proto__ = p;"
738       "for (var i = 0; i < 10; i++) {"
739       "  o.y;"
740       // Now it should be ICed and keep a reference to y defined on p
741       "}"
742       "inbetween.y = 42;"
743       "var result = 0;"
744       "for (var i = 0; i < 10; i++) {"
745       "  result += o.y;"
746       "}"
747       "result");
748   CHECK_EQ(42 * 10, value->Int32Value());
749 }
750
751
752 // Test the case when we stored callback into
753 // a stub, but it got invalidated later on due to override on
754 // global object which is between interceptor and callbacks' holders.
755 THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
756   v8::Isolate* isolate = CcTest::isolate();
757   v8::HandleScope scope(isolate);
758   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
759   templ_o->SetHandler(
760       v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
761   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
762   templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
763
764   LocalContext context;
765   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
766   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
767
768   v8::Handle<Value> value = CompileRun(
769       "o.__proto__ = this;"
770       "this.__proto__ = p;"
771       "for (var i = 0; i < 10; i++) {"
772       "  if (o.y != 239) throw 'oops: ' + o.y;"
773       // Now it should be ICed and keep a reference to y defined on p
774       "}"
775       "this.y = 42;"
776       "var result = 0;"
777       "for (var i = 0; i < 10; i++) {"
778       "  result += o.y;"
779       "}"
780       "result");
781   CHECK_EQ(42 * 10, value->Int32Value());
782 }
783
784
785 static void InterceptorLoadICGetter0(
786     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
787   ApiTestFuzzer::Fuzz();
788   CHECK(v8_str("x")->Equals(name));
789   info.GetReturnValue().Set(v8::Integer::New(info.GetIsolate(), 0));
790 }
791
792
793 THREADED_TEST(InterceptorReturningZero) {
794   CheckInterceptorLoadIC(InterceptorLoadICGetter0, "o.x == undefined ? 1 : 0",
795                          0);
796 }
797
798
799 static void InterceptorStoreICSetter(
800     Local<Name> key, Local<Value> value,
801     const v8::PropertyCallbackInfo<v8::Value>& info) {
802   CHECK(v8_str("x")->Equals(key));
803   CHECK_EQ(42, value->Int32Value());
804   info.GetReturnValue().Set(value);
805 }
806
807
808 // This test should hit the store IC for the interceptor case.
809 THREADED_TEST(InterceptorStoreIC) {
810   v8::Isolate* isolate = CcTest::isolate();
811   v8::HandleScope scope(isolate);
812   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
813   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
814       InterceptorLoadICGetter, InterceptorStoreICSetter, 0, 0, 0,
815       v8_str("data")));
816   LocalContext context;
817   context->Global()->Set(v8_str("o"), templ->NewInstance());
818   CompileRun(
819       "for (var i = 0; i < 1000; i++) {"
820       "  o.x = 42;"
821       "}");
822 }
823
824
825 THREADED_TEST(InterceptorStoreICWithNoSetter) {
826   v8::Isolate* isolate = CcTest::isolate();
827   v8::HandleScope scope(isolate);
828   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
829   templ->SetHandler(
830       v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
831   LocalContext context;
832   context->Global()->Set(v8_str("o"), templ->NewInstance());
833   v8::Handle<Value> value = CompileRun(
834       "for (var i = 0; i < 1000; i++) {"
835       "  o.y = 239;"
836       "}"
837       "42 + o.y");
838   CHECK_EQ(239 + 42, value->Int32Value());
839 }
840
841
842 THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
843   v8::HandleScope scope(CcTest::isolate());
844   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
845   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
846   child->Inherit(parent);
847   AddAccessor(parent, v8_str("age"), SimpleAccessorGetter,
848               SimpleAccessorSetter);
849   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
850   LocalContext env;
851   env->Global()->Set(v8_str("Child"), child->GetFunction());
852   CompileRun(
853       "var child = new Child;"
854       "child.age = 10;");
855   ExpectBoolean("child.hasOwnProperty('age')", false);
856   ExpectInt32("child.age", 10);
857   ExpectInt32("child.accessor_age", 10);
858 }
859
860
861 THREADED_TEST(LegacyInterceptorDoesNotSeeSymbols) {
862   LocalContext env;
863   v8::Isolate* isolate = CcTest::isolate();
864   v8::HandleScope scope(isolate);
865   Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
866   Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
867   v8::Local<v8::Symbol> age = v8::Symbol::New(isolate, v8_str("age"));
868
869   child->Inherit(parent);
870   AddAccessor(parent, age, SymbolAccessorGetter, SymbolAccessorSetter);
871   AddInterceptor(child, StringInterceptorGetter, StringInterceptorSetter);
872
873   env->Global()->Set(v8_str("Child"), child->GetFunction());
874   env->Global()->Set(v8_str("age"), age);
875   CompileRun(
876       "var child = new Child;"
877       "child[age] = 10;");
878   ExpectInt32("child[age]", 10);
879   ExpectBoolean("child.hasOwnProperty('age')", false);
880   ExpectBoolean("child.hasOwnProperty('accessor_age')", true);
881 }
882
883
884 THREADED_TEST(GenericInterceptorDoesSeeSymbols) {
885   LocalContext env;
886   v8::Isolate* isolate = CcTest::isolate();
887   v8::HandleScope scope(isolate);
888   Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
889   Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
890   v8::Local<v8::Symbol> age = v8::Symbol::New(isolate, v8_str("age"));
891   v8::Local<v8::Symbol> anon = v8::Symbol::New(isolate);
892
893   child->Inherit(parent);
894   AddAccessor(parent, age, SymbolAccessorGetter, SymbolAccessorSetter);
895   AddInterceptor(child, GenericInterceptorGetter, GenericInterceptorSetter);
896
897   env->Global()->Set(v8_str("Child"), child->GetFunction());
898   env->Global()->Set(v8_str("age"), age);
899   env->Global()->Set(v8_str("anon"), anon);
900   CompileRun(
901       "var child = new Child;"
902       "child[age] = 10;");
903   ExpectInt32("child[age]", 10);
904   ExpectInt32("child._sym_age", 10);
905
906   // Check that it also sees strings.
907   CompileRun("child.foo = 47");
908   ExpectInt32("child.foo", 47);
909   ExpectInt32("child._str_foo", 47);
910
911   // Check that the interceptor can punt (in this case, on anonymous symbols).
912   CompileRun("child[anon] = 31337");
913   ExpectInt32("child[anon]", 31337);
914 }
915
916
917 THREADED_TEST(NamedPropertyHandlerGetter) {
918   echo_named_call_count = 0;
919   v8::HandleScope scope(CcTest::isolate());
920   v8::Handle<v8::FunctionTemplate> templ =
921       v8::FunctionTemplate::New(CcTest::isolate());
922   templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
923       EchoNamedProperty, 0, 0, 0, 0, v8_str("data")));
924   LocalContext env;
925   env->Global()->Set(v8_str("obj"), templ->GetFunction()->NewInstance());
926   CHECK_EQ(echo_named_call_count, 0);
927   v8_compile("obj.x")->Run();
928   CHECK_EQ(echo_named_call_count, 1);
929   const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
930   v8::Handle<Value> str = CompileRun(code);
931   String::Utf8Value value(str);
932   CHECK_EQ(0, strcmp(*value, "oddlepoddle"));
933   // Check default behavior
934   CHECK_EQ(10, v8_compile("obj.flob = 10;")->Run()->Int32Value());
935   CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
936   CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
937 }
938
939
940 int echo_indexed_call_count = 0;
941
942
943 static void EchoIndexedProperty(
944     uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) {
945   ApiTestFuzzer::Fuzz();
946   CHECK(v8_num(637)->Equals(info.Data()));
947   echo_indexed_call_count++;
948   info.GetReturnValue().Set(v8_num(index));
949 }
950
951
952 THREADED_TEST(IndexedPropertyHandlerGetter) {
953   v8::Isolate* isolate = CcTest::isolate();
954   v8::HandleScope scope(isolate);
955   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
956   templ->InstanceTemplate()->SetHandler(v8::IndexedPropertyHandlerConfiguration(
957       EchoIndexedProperty, 0, 0, 0, 0, v8_num(637)));
958   LocalContext env;
959   env->Global()->Set(v8_str("obj"), templ->GetFunction()->NewInstance());
960   Local<Script> script = v8_compile("obj[900]");
961   CHECK_EQ(script->Run()->Int32Value(), 900);
962 }
963
964
965 THREADED_TEST(PropertyHandlerInPrototype) {
966   LocalContext env;
967   v8::Isolate* isolate = env->GetIsolate();
968   v8::HandleScope scope(isolate);
969
970   // Set up a prototype chain with three interceptors.
971   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
972   templ->InstanceTemplate()->SetHandler(v8::IndexedPropertyHandlerConfiguration(
973       CheckThisIndexedPropertyHandler, CheckThisIndexedPropertySetter,
974       CheckThisIndexedPropertyQuery, CheckThisIndexedPropertyDeleter,
975       CheckThisIndexedPropertyEnumerator));
976
977   templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
978       CheckThisNamedPropertyHandler, CheckThisNamedPropertySetter,
979       CheckThisNamedPropertyQuery, CheckThisNamedPropertyDeleter,
980       CheckThisNamedPropertyEnumerator));
981
982   bottom = templ->GetFunction()->NewInstance();
983   Local<v8::Object> top = templ->GetFunction()->NewInstance();
984   Local<v8::Object> middle = templ->GetFunction()->NewInstance();
985
986   bottom->SetPrototype(middle);
987   middle->SetPrototype(top);
988   env->Global()->Set(v8_str("obj"), bottom);
989
990   // Indexed and named get.
991   CompileRun("obj[0]");
992   CompileRun("obj.x");
993
994   // Indexed and named set.
995   CompileRun("obj[1] = 42");
996   CompileRun("obj.y = 42");
997
998   // Indexed and named query.
999   CompileRun("0 in obj");
1000   CompileRun("'x' in obj");
1001
1002   // Indexed and named deleter.
1003   CompileRun("delete obj[0]");
1004   CompileRun("delete obj.x");
1005
1006   // Enumerators.
1007   CompileRun("for (var p in obj) ;");
1008 }
1009
1010
1011 static void PrePropertyHandlerGet(
1012     Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>& info) {
1013   ApiTestFuzzer::Fuzz();
1014   if (v8_str("pre")->Equals(key)) {
1015     info.GetReturnValue().Set(v8_str("PrePropertyHandler: pre"));
1016   }
1017 }
1018
1019
1020 static void PrePropertyHandlerQuery(
1021     Local<Name> key, const v8::PropertyCallbackInfo<v8::Integer>& info) {
1022   if (v8_str("pre")->Equals(key)) {
1023     info.GetReturnValue().Set(static_cast<int32_t>(v8::None));
1024   }
1025 }
1026
1027
1028 THREADED_TEST(PrePropertyHandler) {
1029   v8::Isolate* isolate = CcTest::isolate();
1030   v8::HandleScope scope(isolate);
1031   v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
1032   desc->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
1033       PrePropertyHandlerGet, 0, PrePropertyHandlerQuery));
1034   LocalContext env(NULL, desc->InstanceTemplate());
1035   CompileRun("var pre = 'Object: pre'; var on = 'Object: on';");
1036   v8::Handle<Value> result_pre = CompileRun("pre");
1037   CHECK(v8_str("PrePropertyHandler: pre")->Equals(result_pre));
1038   v8::Handle<Value> result_on = CompileRun("on");
1039   CHECK(v8_str("Object: on")->Equals(result_on));
1040   v8::Handle<Value> result_post = CompileRun("post");
1041   CHECK(result_post.IsEmpty());
1042 }
1043
1044
1045 THREADED_TEST(EmptyInterceptorBreakTransitions) {
1046   v8::HandleScope scope(CcTest::isolate());
1047   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
1048   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
1049   LocalContext env;
1050   env->Global()->Set(v8_str("Constructor"), templ->GetFunction());
1051   CompileRun(
1052       "var o1 = new Constructor;"
1053       "o1.a = 1;"  // Ensure a and x share the descriptor array.
1054       "Object.defineProperty(o1, 'x', {value: 10});");
1055   CompileRun(
1056       "var o2 = new Constructor;"
1057       "o2.a = 1;"
1058       "Object.defineProperty(o2, 'x', {value: 10});");
1059 }
1060
1061
1062 THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) {
1063   v8::Isolate* isolate = CcTest::isolate();
1064   v8::HandleScope scope(isolate);
1065   Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
1066   Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
1067   child->Inherit(parent);
1068   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1069   LocalContext env;
1070   env->Global()->Set(v8_str("Child"), child->GetFunction());
1071   CompileRun(
1072       "var child = new Child;"
1073       "var parent = child.__proto__;"
1074       "Object.defineProperty(parent, 'age', "
1075       "  {get: function(){ return this.accessor_age; }, "
1076       "   set: function(v){ this.accessor_age = v; }, "
1077       "   enumerable: true, configurable: true});"
1078       "child.age = 10;");
1079   ExpectBoolean("child.hasOwnProperty('age')", false);
1080   ExpectInt32("child.age", 10);
1081   ExpectInt32("child.accessor_age", 10);
1082 }
1083
1084
1085 THREADED_TEST(EmptyInterceptorDoesNotShadowApiAccessors) {
1086   v8::Isolate* isolate = CcTest::isolate();
1087   v8::HandleScope scope(isolate);
1088   Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
1089   auto returns_42 = FunctionTemplate::New(isolate, Returns42);
1090   parent->PrototypeTemplate()->SetAccessorProperty(v8_str("age"), returns_42);
1091   Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
1092   child->Inherit(parent);
1093   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1094   LocalContext env;
1095   env->Global()->Set(v8_str("Child"), child->GetFunction());
1096   CompileRun(
1097       "var child = new Child;"
1098       "var parent = child.__proto__;");
1099   ExpectBoolean("child.hasOwnProperty('age')", false);
1100   ExpectInt32("child.age", 42);
1101   // Check interceptor followup.
1102   ExpectInt32(
1103       "var result;"
1104       "for (var i = 0; i < 4; ++i) {"
1105       "  result = child.age;"
1106       "}"
1107       "result",
1108       42);
1109 }
1110
1111
1112 THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) {
1113   v8::Isolate* isolate = CcTest::isolate();
1114   v8::HandleScope scope(isolate);
1115   Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
1116   Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
1117   child->Inherit(parent);
1118   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1119   LocalContext env;
1120   env->Global()->Set(v8_str("Child"), child->GetFunction());
1121   CompileRun(
1122       "var child = new Child;"
1123       "var parent = child.__proto__;"
1124       "parent.name = 'Alice';");
1125   ExpectBoolean("child.hasOwnProperty('name')", false);
1126   ExpectString("child.name", "Alice");
1127   CompileRun("child.name = 'Bob';");
1128   ExpectString("child.name", "Bob");
1129   ExpectBoolean("child.hasOwnProperty('name')", true);
1130   ExpectString("parent.name", "Alice");
1131 }
1132
1133
1134 THREADED_TEST(SwitchFromInterceptorToAccessor) {
1135   v8::HandleScope scope(CcTest::isolate());
1136   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
1137   AddAccessor(templ, v8_str("age"), SimpleAccessorGetter, SimpleAccessorSetter);
1138   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1139   LocalContext env;
1140   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
1141   CompileRun(
1142       "var obj = new Obj;"
1143       "function setAge(i){ obj.age = i; };"
1144       "for(var i = 0; i <= 10000; i++) setAge(i);");
1145   // All i < 10000 go to the interceptor.
1146   ExpectInt32("obj.interceptor_age", 9999);
1147   // The last i goes to the accessor.
1148   ExpectInt32("obj.accessor_age", 10000);
1149 }
1150
1151
1152 THREADED_TEST(SwitchFromAccessorToInterceptor) {
1153   v8::HandleScope scope(CcTest::isolate());
1154   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
1155   AddAccessor(templ, v8_str("age"), SimpleAccessorGetter, SimpleAccessorSetter);
1156   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1157   LocalContext env;
1158   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
1159   CompileRun(
1160       "var obj = new Obj;"
1161       "function setAge(i){ obj.age = i; };"
1162       "for(var i = 20000; i >= 9999; i--) setAge(i);");
1163   // All i >= 10000 go to the accessor.
1164   ExpectInt32("obj.accessor_age", 10000);
1165   // The last i goes to the interceptor.
1166   ExpectInt32("obj.interceptor_age", 9999);
1167 }
1168
1169
1170 THREADED_TEST(SwitchFromInterceptorToAccessorWithInheritance) {
1171   v8::HandleScope scope(CcTest::isolate());
1172   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
1173   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
1174   child->Inherit(parent);
1175   AddAccessor(parent, v8_str("age"), SimpleAccessorGetter,
1176               SimpleAccessorSetter);
1177   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1178   LocalContext env;
1179   env->Global()->Set(v8_str("Child"), child->GetFunction());
1180   CompileRun(
1181       "var child = new Child;"
1182       "function setAge(i){ child.age = i; };"
1183       "for(var i = 0; i <= 10000; i++) setAge(i);");
1184   // All i < 10000 go to the interceptor.
1185   ExpectInt32("child.interceptor_age", 9999);
1186   // The last i goes to the accessor.
1187   ExpectInt32("child.accessor_age", 10000);
1188 }
1189
1190
1191 THREADED_TEST(SwitchFromAccessorToInterceptorWithInheritance) {
1192   v8::HandleScope scope(CcTest::isolate());
1193   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
1194   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
1195   child->Inherit(parent);
1196   AddAccessor(parent, v8_str("age"), SimpleAccessorGetter,
1197               SimpleAccessorSetter);
1198   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1199   LocalContext env;
1200   env->Global()->Set(v8_str("Child"), child->GetFunction());
1201   CompileRun(
1202       "var child = new Child;"
1203       "function setAge(i){ child.age = i; };"
1204       "for(var i = 20000; i >= 9999; i--) setAge(i);");
1205   // All i >= 10000 go to the accessor.
1206   ExpectInt32("child.accessor_age", 10000);
1207   // The last i goes to the interceptor.
1208   ExpectInt32("child.interceptor_age", 9999);
1209 }
1210
1211
1212 THREADED_TEST(SwitchFromInterceptorToJSAccessor) {
1213   v8::HandleScope scope(CcTest::isolate());
1214   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
1215   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1216   LocalContext env;
1217   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
1218   CompileRun(
1219       "var obj = new Obj;"
1220       "function setter(i) { this.accessor_age = i; };"
1221       "function getter() { return this.accessor_age; };"
1222       "function setAge(i) { obj.age = i; };"
1223       "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
1224       "for(var i = 0; i <= 10000; i++) setAge(i);");
1225   // All i < 10000 go to the interceptor.
1226   ExpectInt32("obj.interceptor_age", 9999);
1227   // The last i goes to the JavaScript accessor.
1228   ExpectInt32("obj.accessor_age", 10000);
1229   // The installed JavaScript getter is still intact.
1230   // This last part is a regression test for issue 1651 and relies on the fact
1231   // that both interceptor and accessor are being installed on the same object.
1232   ExpectInt32("obj.age", 10000);
1233   ExpectBoolean("obj.hasOwnProperty('age')", true);
1234   ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
1235 }
1236
1237
1238 THREADED_TEST(SwitchFromJSAccessorToInterceptor) {
1239   v8::HandleScope scope(CcTest::isolate());
1240   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
1241   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1242   LocalContext env;
1243   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
1244   CompileRun(
1245       "var obj = new Obj;"
1246       "function setter(i) { this.accessor_age = i; };"
1247       "function getter() { return this.accessor_age; };"
1248       "function setAge(i) { obj.age = i; };"
1249       "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
1250       "for(var i = 20000; i >= 9999; i--) setAge(i);");
1251   // All i >= 10000 go to the accessor.
1252   ExpectInt32("obj.accessor_age", 10000);
1253   // The last i goes to the interceptor.
1254   ExpectInt32("obj.interceptor_age", 9999);
1255   // The installed JavaScript getter is still intact.
1256   // This last part is a regression test for issue 1651 and relies on the fact
1257   // that both interceptor and accessor are being installed on the same object.
1258   ExpectInt32("obj.age", 10000);
1259   ExpectBoolean("obj.hasOwnProperty('age')", true);
1260   ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
1261 }
1262
1263
1264 THREADED_TEST(SwitchFromInterceptorToProperty) {
1265   v8::HandleScope scope(CcTest::isolate());
1266   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
1267   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
1268   child->Inherit(parent);
1269   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1270   LocalContext env;
1271   env->Global()->Set(v8_str("Child"), child->GetFunction());
1272   CompileRun(
1273       "var child = new Child;"
1274       "function setAge(i){ child.age = i; };"
1275       "for(var i = 0; i <= 10000; i++) setAge(i);");
1276   // All i < 10000 go to the interceptor.
1277   ExpectInt32("child.interceptor_age", 9999);
1278   // The last i goes to child's own property.
1279   ExpectInt32("child.age", 10000);
1280 }
1281
1282
1283 THREADED_TEST(SwitchFromPropertyToInterceptor) {
1284   v8::HandleScope scope(CcTest::isolate());
1285   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
1286   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
1287   child->Inherit(parent);
1288   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1289   LocalContext env;
1290   env->Global()->Set(v8_str("Child"), child->GetFunction());
1291   CompileRun(
1292       "var child = new Child;"
1293       "function setAge(i){ child.age = i; };"
1294       "for(var i = 20000; i >= 9999; i--) setAge(i);");
1295   // All i >= 10000 go to child's own property.
1296   ExpectInt32("child.age", 10000);
1297   // The last i goes to the interceptor.
1298   ExpectInt32("child.interceptor_age", 9999);
1299 }
1300
1301
1302 static bool interceptor_for_hidden_properties_called;
1303 static void InterceptorForHiddenProperties(
1304     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
1305   interceptor_for_hidden_properties_called = true;
1306 }
1307
1308
1309 THREADED_TEST(HiddenPropertiesWithInterceptors) {
1310   LocalContext context;
1311   v8::Isolate* isolate = context->GetIsolate();
1312   v8::HandleScope scope(isolate);
1313
1314   interceptor_for_hidden_properties_called = false;
1315
1316   v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1317
1318   // Associate an interceptor with an object and start setting hidden values.
1319   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
1320   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
1321   instance_templ->SetHandler(
1322       v8::NamedPropertyHandlerConfiguration(InterceptorForHiddenProperties));
1323   Local<v8::Function> function = fun_templ->GetFunction();
1324   Local<v8::Object> obj = function->NewInstance();
1325   CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2302)));
1326   CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
1327   CHECK(!interceptor_for_hidden_properties_called);
1328 }
1329
1330
1331 static void XPropertyGetter(Local<Name> property,
1332                             const v8::PropertyCallbackInfo<v8::Value>& info) {
1333   ApiTestFuzzer::Fuzz();
1334   CHECK(info.Data()->IsUndefined());
1335   info.GetReturnValue().Set(property);
1336 }
1337
1338
1339 THREADED_TEST(NamedInterceptorPropertyRead) {
1340   v8::Isolate* isolate = CcTest::isolate();
1341   v8::HandleScope scope(isolate);
1342   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1343   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(XPropertyGetter));
1344   LocalContext context;
1345   context->Global()->Set(v8_str("obj"), templ->NewInstance());
1346   Local<Script> script = v8_compile("obj.x");
1347   for (int i = 0; i < 10; i++) {
1348     Local<Value> result = script->Run();
1349     CHECK(result->Equals(v8_str("x")));
1350   }
1351 }
1352
1353
1354 THREADED_TEST(NamedInterceptorDictionaryIC) {
1355   v8::Isolate* isolate = CcTest::isolate();
1356   v8::HandleScope scope(isolate);
1357   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1358   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(XPropertyGetter));
1359   LocalContext context;
1360   // Create an object with a named interceptor.
1361   context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
1362   Local<Script> script = v8_compile("interceptor_obj.x");
1363   for (int i = 0; i < 10; i++) {
1364     Local<Value> result = script->Run();
1365     CHECK(result->Equals(v8_str("x")));
1366   }
1367   // Create a slow case object and a function accessing a property in
1368   // that slow case object (with dictionary probing in generated
1369   // code). Then force object with a named interceptor into slow-case,
1370   // pass it to the function, and check that the interceptor is called
1371   // instead of accessing the local property.
1372   Local<Value> result = CompileRun(
1373       "function get_x(o) { return o.x; };"
1374       "var obj = { x : 42, y : 0 };"
1375       "delete obj.y;"
1376       "for (var i = 0; i < 10; i++) get_x(obj);"
1377       "interceptor_obj.x = 42;"
1378       "interceptor_obj.y = 10;"
1379       "delete interceptor_obj.y;"
1380       "get_x(interceptor_obj)");
1381   CHECK(result->Equals(v8_str("x")));
1382 }
1383
1384
1385 THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
1386   v8::Isolate* isolate = CcTest::isolate();
1387   v8::HandleScope scope(isolate);
1388   v8::Local<Context> context1 = Context::New(isolate);
1389
1390   context1->Enter();
1391   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1392   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(XPropertyGetter));
1393   // Create an object with a named interceptor.
1394   v8::Local<v8::Object> object = templ->NewInstance();
1395   context1->Global()->Set(v8_str("interceptor_obj"), object);
1396
1397   // Force the object into the slow case.
1398   CompileRun(
1399       "interceptor_obj.y = 0;"
1400       "delete interceptor_obj.y;");
1401   context1->Exit();
1402
1403   {
1404     // Introduce the object into a different context.
1405     // Repeat named loads to exercise ICs.
1406     LocalContext context2;
1407     context2->Global()->Set(v8_str("interceptor_obj"), object);
1408     Local<Value> result = CompileRun(
1409         "function get_x(o) { return o.x; }"
1410         "interceptor_obj.x = 42;"
1411         "for (var i=0; i != 10; i++) {"
1412         "  get_x(interceptor_obj);"
1413         "}"
1414         "get_x(interceptor_obj)");
1415     // Check that the interceptor was actually invoked.
1416     CHECK(result->Equals(v8_str("x")));
1417   }
1418
1419   // Return to the original context and force some object to the slow case
1420   // to cause the NormalizedMapCache to verify.
1421   context1->Enter();
1422   CompileRun("var obj = { x : 0 }; delete obj.x;");
1423   context1->Exit();
1424 }
1425
1426
1427 static void SetXOnPrototypeGetter(
1428     Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {
1429   // Set x on the prototype object and do not handle the get request.
1430   v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
1431   proto.As<v8::Object>()->Set(v8_str("x"),
1432                               v8::Integer::New(info.GetIsolate(), 23));
1433 }
1434
1435
1436 // This is a regression test for http://crbug.com/20104. Map
1437 // transitions should not interfere with post interceptor lookup.
1438 THREADED_TEST(NamedInterceptorMapTransitionRead) {
1439   v8::Isolate* isolate = CcTest::isolate();
1440   v8::HandleScope scope(isolate);
1441   Local<v8::FunctionTemplate> function_template =
1442       v8::FunctionTemplate::New(isolate);
1443   Local<v8::ObjectTemplate> instance_template =
1444       function_template->InstanceTemplate();
1445   instance_template->SetHandler(
1446       v8::NamedPropertyHandlerConfiguration(SetXOnPrototypeGetter));
1447   LocalContext context;
1448   context->Global()->Set(v8_str("F"), function_template->GetFunction());
1449   // Create an instance of F and introduce a map transition for x.
1450   CompileRun("var o = new F(); o.x = 23;");
1451   // Create an instance of F and invoke the getter. The result should be 23.
1452   Local<Value> result = CompileRun("o = new F(); o.x");
1453   CHECK_EQ(result->Int32Value(), 23);
1454 }
1455
1456
1457 static void IndexedPropertyGetter(
1458     uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) {
1459   ApiTestFuzzer::Fuzz();
1460   if (index == 37) {
1461     info.GetReturnValue().Set(v8_num(625));
1462   }
1463 }
1464
1465
1466 static void IndexedPropertySetter(
1467     uint32_t index, Local<Value> value,
1468     const v8::PropertyCallbackInfo<v8::Value>& info) {
1469   ApiTestFuzzer::Fuzz();
1470   if (index == 39) {
1471     info.GetReturnValue().Set(value);
1472   }
1473 }
1474
1475
1476 THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
1477   v8::Isolate* isolate = CcTest::isolate();
1478   v8::HandleScope scope(isolate);
1479   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1480   templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
1481       IndexedPropertyGetter, IndexedPropertySetter));
1482   LocalContext context;
1483   context->Global()->Set(v8_str("obj"), templ->NewInstance());
1484   Local<Script> getter_script =
1485       v8_compile("obj.__defineGetter__(\"3\", function(){return 5;});obj[3];");
1486   Local<Script> setter_script = v8_compile(
1487       "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
1488       "obj[17] = 23;"
1489       "obj.foo;");
1490   Local<Script> interceptor_setter_script = v8_compile(
1491       "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
1492       "obj[39] = 47;"
1493       "obj.foo;");  // This setter should not run, due to the interceptor.
1494   Local<Script> interceptor_getter_script = v8_compile("obj[37];");
1495   Local<Value> result = getter_script->Run();
1496   CHECK(v8_num(5)->Equals(result));
1497   result = setter_script->Run();
1498   CHECK(v8_num(23)->Equals(result));
1499   result = interceptor_setter_script->Run();
1500   CHECK(v8_num(23)->Equals(result));
1501   result = interceptor_getter_script->Run();
1502   CHECK(v8_num(625)->Equals(result));
1503 }
1504
1505
1506 static void UnboxedDoubleIndexedPropertyGetter(
1507     uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) {
1508   ApiTestFuzzer::Fuzz();
1509   if (index < 25) {
1510     info.GetReturnValue().Set(v8_num(index));
1511   }
1512 }
1513
1514
1515 static void UnboxedDoubleIndexedPropertySetter(
1516     uint32_t index, Local<Value> value,
1517     const v8::PropertyCallbackInfo<v8::Value>& info) {
1518   ApiTestFuzzer::Fuzz();
1519   if (index < 25) {
1520     info.GetReturnValue().Set(v8_num(index));
1521   }
1522 }
1523
1524
1525 void UnboxedDoubleIndexedPropertyEnumerator(
1526     const v8::PropertyCallbackInfo<v8::Array>& info) {
1527   // Force the list of returned keys to be stored in a FastDoubleArray.
1528   Local<Script> indexed_property_names_script = v8_compile(
1529       "keys = new Array(); keys[125000] = 1;"
1530       "for(i = 0; i < 80000; i++) { keys[i] = i; };"
1531       "keys.length = 25; keys;");
1532   Local<Value> result = indexed_property_names_script->Run();
1533   info.GetReturnValue().Set(Local<v8::Array>::Cast(result));
1534 }
1535
1536
1537 // Make sure that the the interceptor code in the runtime properly handles
1538 // merging property name lists for double-array-backed arrays.
1539 THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
1540   v8::Isolate* isolate = CcTest::isolate();
1541   v8::HandleScope scope(isolate);
1542   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1543   templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
1544       UnboxedDoubleIndexedPropertyGetter, UnboxedDoubleIndexedPropertySetter, 0,
1545       0, UnboxedDoubleIndexedPropertyEnumerator));
1546   LocalContext context;
1547   context->Global()->Set(v8_str("obj"), templ->NewInstance());
1548   // When obj is created, force it to be Stored in a FastDoubleArray.
1549   Local<Script> create_unboxed_double_script = v8_compile(
1550       "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
1551       "key_count = 0; "
1552       "for (x in obj) {key_count++;};"
1553       "obj;");
1554   Local<Value> result = create_unboxed_double_script->Run();
1555   CHECK(result->ToObject(isolate)->HasRealIndexedProperty(2000));
1556   Local<Script> key_count_check = v8_compile("key_count;");
1557   result = key_count_check->Run();
1558   CHECK(v8_num(40013)->Equals(result));
1559 }
1560
1561
1562 void SloppyArgsIndexedPropertyEnumerator(
1563     const v8::PropertyCallbackInfo<v8::Array>& info) {
1564   // Force the list of returned keys to be stored in a Arguments object.
1565   Local<Script> indexed_property_names_script = v8_compile(
1566       "function f(w,x) {"
1567       " return arguments;"
1568       "}"
1569       "keys = f(0, 1, 2, 3);"
1570       "keys;");
1571   Local<Object> result =
1572       Local<Object>::Cast(indexed_property_names_script->Run());
1573   // Have to populate the handle manually, as it's not Cast-able.
1574   i::Handle<i::JSObject> o = v8::Utils::OpenHandle<Object, i::JSObject>(result);
1575   i::Handle<i::JSArray> array(reinterpret_cast<i::JSArray*>(*o));
1576   info.GetReturnValue().Set(v8::Utils::ToLocal(array));
1577 }
1578
1579
1580 static void SloppyIndexedPropertyGetter(
1581     uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) {
1582   ApiTestFuzzer::Fuzz();
1583   if (index < 4) {
1584     info.GetReturnValue().Set(v8_num(index));
1585   }
1586 }
1587
1588
1589 // Make sure that the the interceptor code in the runtime properly handles
1590 // merging property name lists for non-string arguments arrays.
1591 THREADED_TEST(IndexedInterceptorSloppyArgsWithIndexedAccessor) {
1592   v8::Isolate* isolate = CcTest::isolate();
1593   v8::HandleScope scope(isolate);
1594   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1595   templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
1596       SloppyIndexedPropertyGetter, 0, 0, 0,
1597       SloppyArgsIndexedPropertyEnumerator));
1598   LocalContext context;
1599   context->Global()->Set(v8_str("obj"), templ->NewInstance());
1600   Local<Script> create_args_script = v8_compile(
1601       "var key_count = 0;"
1602       "for (x in obj) {key_count++;} key_count;");
1603   Local<Value> result = create_args_script->Run();
1604   CHECK(v8_num(4)->Equals(result));
1605 }
1606
1607
1608 static void IdentityIndexedPropertyGetter(
1609     uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) {
1610   info.GetReturnValue().Set(index);
1611 }
1612
1613
1614 THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
1615   v8::Isolate* isolate = CcTest::isolate();
1616   v8::HandleScope scope(isolate);
1617   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1618   templ->SetHandler(
1619       v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
1620
1621   LocalContext context;
1622   context->Global()->Set(v8_str("obj"), templ->NewInstance());
1623
1624   // Check fast object case.
1625   const char* fast_case_code =
1626       "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
1627   ExpectString(fast_case_code, "0");
1628
1629   // Check slow case.
1630   const char* slow_case_code =
1631       "obj.x = 1; delete obj.x;"
1632       "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
1633   ExpectString(slow_case_code, "1");
1634 }
1635
1636
1637 THREADED_TEST(IndexedInterceptorWithNoSetter) {
1638   v8::Isolate* isolate = CcTest::isolate();
1639   v8::HandleScope scope(isolate);
1640   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1641   templ->SetHandler(
1642       v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
1643
1644   LocalContext context;
1645   context->Global()->Set(v8_str("obj"), templ->NewInstance());
1646
1647   const char* code =
1648       "try {"
1649       "  obj[0] = 239;"
1650       "  for (var i = 0; i < 100; i++) {"
1651       "    var v = obj[0];"
1652       "    if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
1653       "  }"
1654       "  'PASSED'"
1655       "} catch(e) {"
1656       "  e"
1657       "}";
1658   ExpectString(code, "PASSED");
1659 }
1660
1661
1662 THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
1663   v8::Isolate* isolate = CcTest::isolate();
1664   v8::HandleScope scope(isolate);
1665   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1666   templ->SetHandler(
1667       v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
1668
1669   LocalContext context;
1670   Local<v8::Object> obj = templ->NewInstance();
1671   obj->TurnOnAccessCheck();
1672   context->Global()->Set(v8_str("obj"), obj);
1673
1674   const char* code =
1675       "var result = 'PASSED';"
1676       "for (var i = 0; i < 100; i++) {"
1677       "  try {"
1678       "    var v = obj[0];"
1679       "    result = 'Wrong value ' + v + ' at iteration ' + i;"
1680       "    break;"
1681       "  } catch (e) {"
1682       "    /* pass */"
1683       "  }"
1684       "}"
1685       "result";
1686   ExpectString(code, "PASSED");
1687 }
1688
1689
1690 THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
1691   i::FLAG_allow_natives_syntax = true;
1692   v8::Isolate* isolate = CcTest::isolate();
1693   v8::HandleScope scope(isolate);
1694   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1695   templ->SetHandler(
1696       v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
1697
1698   LocalContext context;
1699   Local<v8::Object> obj = templ->NewInstance();
1700   context->Global()->Set(v8_str("obj"), obj);
1701
1702   const char* code =
1703       "var result = 'PASSED';"
1704       "for (var i = 0; i < 100; i++) {"
1705       "  var expected = i;"
1706       "  if (i == 5) {"
1707       "    %EnableAccessChecks(obj);"
1708       "  }"
1709       "  try {"
1710       "    var v = obj[i];"
1711       "    if (i == 5) {"
1712       "      result = 'Should not have reached this!';"
1713       "      break;"
1714       "    } else if (v != expected) {"
1715       "      result = 'Wrong value ' + v + ' at iteration ' + i;"
1716       "      break;"
1717       "    }"
1718       "  } catch (e) {"
1719       "    if (i != 5) {"
1720       "      result = e;"
1721       "    }"
1722       "  }"
1723       "  if (i == 5) %DisableAccessChecks(obj);"
1724       "}"
1725       "result";
1726   ExpectString(code, "PASSED");
1727 }
1728
1729
1730 THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
1731   v8::Isolate* isolate = CcTest::isolate();
1732   v8::HandleScope scope(isolate);
1733   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1734   templ->SetHandler(
1735       v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
1736
1737   LocalContext context;
1738   Local<v8::Object> obj = templ->NewInstance();
1739   context->Global()->Set(v8_str("obj"), obj);
1740
1741   const char* code =
1742       "try {"
1743       "  for (var i = 0; i < 100; i++) {"
1744       "    var v = obj[i];"
1745       "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
1746       "  }"
1747       "  'PASSED'"
1748       "} catch(e) {"
1749       "  e"
1750       "}";
1751   ExpectString(code, "PASSED");
1752 }
1753
1754
1755 THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
1756   v8::Isolate* isolate = CcTest::isolate();
1757   v8::HandleScope scope(isolate);
1758   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1759   templ->SetHandler(
1760       v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
1761
1762   LocalContext context;
1763   Local<v8::Object> obj = templ->NewInstance();
1764   context->Global()->Set(v8_str("obj"), obj);
1765
1766   const char* code =
1767       "try {"
1768       "  for (var i = 0; i < 100; i++) {"
1769       "    var expected = i;"
1770       "    var key = i;"
1771       "    if (i == 25) {"
1772       "       key = -1;"
1773       "       expected = undefined;"
1774       "    }"
1775       "    if (i == 50) {"
1776       "       /* probe minimal Smi number on 32-bit platforms */"
1777       "       key = -(1 << 30);"
1778       "       expected = undefined;"
1779       "    }"
1780       "    if (i == 75) {"
1781       "       /* probe minimal Smi number on 64-bit platforms */"
1782       "       key = 1 << 31;"
1783       "       expected = undefined;"
1784       "    }"
1785       "    var v = obj[key];"
1786       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
1787       "  }"
1788       "  'PASSED'"
1789       "} catch(e) {"
1790       "  e"
1791       "}";
1792   ExpectString(code, "PASSED");
1793 }
1794
1795
1796 THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
1797   v8::Isolate* isolate = CcTest::isolate();
1798   v8::HandleScope scope(isolate);
1799   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1800   templ->SetHandler(
1801       v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
1802
1803   LocalContext context;
1804   Local<v8::Object> obj = templ->NewInstance();
1805   context->Global()->Set(v8_str("obj"), obj);
1806
1807   const char* code =
1808       "try {"
1809       "  for (var i = 0; i < 100; i++) {"
1810       "    var expected = i;"
1811       "    var key = i;"
1812       "    if (i == 50) {"
1813       "       key = 'foobar';"
1814       "       expected = undefined;"
1815       "    }"
1816       "    var v = obj[key];"
1817       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
1818       "  }"
1819       "  'PASSED'"
1820       "} catch(e) {"
1821       "  e"
1822       "}";
1823   ExpectString(code, "PASSED");
1824 }
1825
1826
1827 THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
1828   v8::Isolate* isolate = CcTest::isolate();
1829   v8::HandleScope scope(isolate);
1830   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1831   templ->SetHandler(
1832       v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
1833
1834   LocalContext context;
1835   Local<v8::Object> obj = templ->NewInstance();
1836   context->Global()->Set(v8_str("obj"), obj);
1837
1838   const char* code =
1839       "var original = obj;"
1840       "try {"
1841       "  for (var i = 0; i < 100; i++) {"
1842       "    var expected = i;"
1843       "    if (i == 50) {"
1844       "       obj = {50: 'foobar'};"
1845       "       expected = 'foobar';"
1846       "    }"
1847       "    var v = obj[i];"
1848       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
1849       "    if (i == 50) obj = original;"
1850       "  }"
1851       "  'PASSED'"
1852       "} catch(e) {"
1853       "  e"
1854       "}";
1855   ExpectString(code, "PASSED");
1856 }
1857
1858
1859 THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
1860   v8::Isolate* isolate = CcTest::isolate();
1861   v8::HandleScope scope(isolate);
1862   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1863   templ->SetHandler(
1864       v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
1865
1866   LocalContext context;
1867   Local<v8::Object> obj = templ->NewInstance();
1868   context->Global()->Set(v8_str("obj"), obj);
1869
1870   const char* code =
1871       "var original = obj;"
1872       "try {"
1873       "  for (var i = 0; i < 100; i++) {"
1874       "    var expected = i;"
1875       "    if (i == 5) {"
1876       "       obj = 239;"
1877       "       expected = undefined;"
1878       "    }"
1879       "    var v = obj[i];"
1880       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
1881       "    if (i == 5) obj = original;"
1882       "  }"
1883       "  'PASSED'"
1884       "} catch(e) {"
1885       "  e"
1886       "}";
1887   ExpectString(code, "PASSED");
1888 }
1889
1890
1891 THREADED_TEST(IndexedInterceptorOnProto) {
1892   v8::Isolate* isolate = CcTest::isolate();
1893   v8::HandleScope scope(isolate);
1894   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1895   templ->SetHandler(
1896       v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
1897
1898   LocalContext context;
1899   Local<v8::Object> obj = templ->NewInstance();
1900   context->Global()->Set(v8_str("obj"), obj);
1901
1902   const char* code =
1903       "var o = {__proto__: obj};"
1904       "try {"
1905       "  for (var i = 0; i < 100; i++) {"
1906       "    var v = o[i];"
1907       "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
1908       "  }"
1909       "  'PASSED'"
1910       "} catch(e) {"
1911       "  e"
1912       "}";
1913   ExpectString(code, "PASSED");
1914 }
1915
1916
1917 static void NoBlockGetterX(Local<Name> name,
1918                            const v8::PropertyCallbackInfo<v8::Value>&) {}
1919
1920
1921 static void NoBlockGetterI(uint32_t index,
1922                            const v8::PropertyCallbackInfo<v8::Value>&) {}
1923
1924
1925 static void PDeleter(Local<Name> name,
1926                      const v8::PropertyCallbackInfo<v8::Boolean>& info) {
1927   if (!name->Equals(v8_str("foo"))) {
1928     return;  // not intercepted
1929   }
1930
1931   info.GetReturnValue().Set(false);  // intercepted, don't delete the property
1932 }
1933
1934
1935 static void IDeleter(uint32_t index,
1936                      const v8::PropertyCallbackInfo<v8::Boolean>& info) {
1937   if (index != 2) {
1938     return;  // not intercepted
1939   }
1940
1941   info.GetReturnValue().Set(false);  // intercepted, don't delete the property
1942 }
1943
1944
1945 THREADED_TEST(Deleter) {
1946   v8::Isolate* isolate = CcTest::isolate();
1947   v8::HandleScope scope(isolate);
1948   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
1949   obj->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX, NULL,
1950                                                         NULL, PDeleter, NULL));
1951   obj->SetHandler(v8::IndexedPropertyHandlerConfiguration(
1952       NoBlockGetterI, NULL, NULL, IDeleter, NULL));
1953   LocalContext context;
1954   context->Global()->Set(v8_str("k"), obj->NewInstance());
1955   CompileRun(
1956       "k.foo = 'foo';"
1957       "k.bar = 'bar';"
1958       "k[2] = 2;"
1959       "k[4] = 4;");
1960   CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
1961   CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
1962
1963   CHECK(v8_compile("k.foo")->Run()->Equals(v8_str("foo")));
1964   CHECK(v8_compile("k.bar")->Run()->IsUndefined());
1965
1966   CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
1967   CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
1968
1969   CHECK(v8_compile("k[2]")->Run()->Equals(v8_num(2)));
1970   CHECK(v8_compile("k[4]")->Run()->IsUndefined());
1971 }
1972
1973
1974 static void GetK(Local<Name> name,
1975                  const v8::PropertyCallbackInfo<v8::Value>& info) {
1976   ApiTestFuzzer::Fuzz();
1977   if (name->Equals(v8_str("foo")) || name->Equals(v8_str("bar")) ||
1978       name->Equals(v8_str("baz"))) {
1979     info.GetReturnValue().SetUndefined();
1980   }
1981 }
1982
1983
1984 static void IndexedGetK(uint32_t index,
1985                         const v8::PropertyCallbackInfo<v8::Value>& info) {
1986   ApiTestFuzzer::Fuzz();
1987   if (index == 0 || index == 1) info.GetReturnValue().SetUndefined();
1988 }
1989
1990
1991 static void NamedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
1992   ApiTestFuzzer::Fuzz();
1993   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 3);
1994   result->Set(v8::Integer::New(info.GetIsolate(), 0), v8_str("foo"));
1995   result->Set(v8::Integer::New(info.GetIsolate(), 1), v8_str("bar"));
1996   result->Set(v8::Integer::New(info.GetIsolate(), 2), v8_str("baz"));
1997   info.GetReturnValue().Set(result);
1998 }
1999
2000
2001 static void IndexedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
2002   ApiTestFuzzer::Fuzz();
2003   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
2004   result->Set(v8::Integer::New(info.GetIsolate(), 0), v8_str("0"));
2005   result->Set(v8::Integer::New(info.GetIsolate(), 1), v8_str("1"));
2006   info.GetReturnValue().Set(result);
2007 }
2008
2009
2010 THREADED_TEST(Enumerators) {
2011   v8::Isolate* isolate = CcTest::isolate();
2012   v8::HandleScope scope(isolate);
2013   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
2014   obj->SetHandler(
2015       v8::NamedPropertyHandlerConfiguration(GetK, NULL, NULL, NULL, NamedEnum));
2016   obj->SetHandler(v8::IndexedPropertyHandlerConfiguration(
2017       IndexedGetK, NULL, NULL, NULL, IndexedEnum));
2018   LocalContext context;
2019   context->Global()->Set(v8_str("k"), obj->NewInstance());
2020   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
2021       "k[10] = 0;"
2022       "k.a = 0;"
2023       "k[5] = 0;"
2024       "k.b = 0;"
2025       "k[4294967295] = 0;"
2026       "k.c = 0;"
2027       "k[4294967296] = 0;"
2028       "k.d = 0;"
2029       "k[140000] = 0;"
2030       "k.e = 0;"
2031       "k[30000000000] = 0;"
2032       "k.f = 0;"
2033       "var result = [];"
2034       "for (var prop in k) {"
2035       "  result.push(prop);"
2036       "}"
2037       "result"));
2038   // Check that we get all the property names returned including the
2039   // ones from the enumerators in the right order: indexed properties
2040   // in numerical order, indexed interceptor properties, named
2041   // properties in insertion order, named interceptor properties.
2042   // This order is not mandated by the spec, so this test is just
2043   // documenting our behavior.
2044   CHECK_EQ(17u, result->Length());
2045   // Indexed properties in numerical order.
2046   CHECK(v8_str("5")->Equals(result->Get(v8::Integer::New(isolate, 0))));
2047   CHECK(v8_str("10")->Equals(result->Get(v8::Integer::New(isolate, 1))));
2048   CHECK(v8_str("140000")->Equals(result->Get(v8::Integer::New(isolate, 2))));
2049   CHECK(
2050       v8_str("4294967295")->Equals(result->Get(v8::Integer::New(isolate, 3))));
2051   // Indexed interceptor properties in the order they are returned
2052   // from the enumerator interceptor.
2053   CHECK(v8_str("0")->Equals(result->Get(v8::Integer::New(isolate, 4))));
2054   CHECK(v8_str("1")->Equals(result->Get(v8::Integer::New(isolate, 5))));
2055   // Named properties in insertion order.
2056   CHECK(v8_str("a")->Equals(result->Get(v8::Integer::New(isolate, 6))));
2057   CHECK(v8_str("b")->Equals(result->Get(v8::Integer::New(isolate, 7))));
2058   CHECK(v8_str("c")->Equals(result->Get(v8::Integer::New(isolate, 8))));
2059   CHECK(
2060       v8_str("4294967296")->Equals(result->Get(v8::Integer::New(isolate, 9))));
2061   CHECK(v8_str("d")->Equals(result->Get(v8::Integer::New(isolate, 10))));
2062   CHECK(v8_str("e")->Equals(result->Get(v8::Integer::New(isolate, 11))));
2063   CHECK(v8_str("30000000000")
2064             ->Equals(result->Get(v8::Integer::New(isolate, 12))));
2065   CHECK(v8_str("f")->Equals(result->Get(v8::Integer::New(isolate, 13))));
2066   // Named interceptor properties.
2067   CHECK(v8_str("foo")->Equals(result->Get(v8::Integer::New(isolate, 14))));
2068   CHECK(v8_str("bar")->Equals(result->Get(v8::Integer::New(isolate, 15))));
2069   CHECK(v8_str("baz")->Equals(result->Get(v8::Integer::New(isolate, 16))));
2070 }
2071
2072
2073 v8::Handle<Value> call_ic_function;
2074 v8::Handle<Value> call_ic_function2;
2075 v8::Handle<Value> call_ic_function3;
2076
2077 static void InterceptorCallICGetter(
2078     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2079   ApiTestFuzzer::Fuzz();
2080   CHECK(v8_str("x")->Equals(name));
2081   info.GetReturnValue().Set(call_ic_function);
2082 }
2083
2084
2085 // This test should hit the call IC for the interceptor case.
2086 THREADED_TEST(InterceptorCallIC) {
2087   v8::Isolate* isolate = CcTest::isolate();
2088   v8::HandleScope scope(isolate);
2089   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2090   templ->SetHandler(
2091       v8::NamedPropertyHandlerConfiguration(InterceptorCallICGetter));
2092   LocalContext context;
2093   context->Global()->Set(v8_str("o"), templ->NewInstance());
2094   call_ic_function = v8_compile("function f(x) { return x + 1; }; f")->Run();
2095   v8::Handle<Value> value = CompileRun(
2096       "var result = 0;"
2097       "for (var i = 0; i < 1000; i++) {"
2098       "  result = o.x(41);"
2099       "}");
2100   CHECK_EQ(42, value->Int32Value());
2101 }
2102
2103
2104 // This test checks that if interceptor doesn't provide
2105 // a value, we can fetch regular value.
2106 THREADED_TEST(InterceptorCallICSeesOthers) {
2107   v8::Isolate* isolate = CcTest::isolate();
2108   v8::HandleScope scope(isolate);
2109   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2110   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
2111   LocalContext context;
2112   context->Global()->Set(v8_str("o"), templ->NewInstance());
2113   v8::Handle<Value> value = CompileRun(
2114       "o.x = function f(x) { return x + 1; };"
2115       "var result = 0;"
2116       "for (var i = 0; i < 7; i++) {"
2117       "  result = o.x(41);"
2118       "}");
2119   CHECK_EQ(42, value->Int32Value());
2120 }
2121
2122
2123 static v8::Handle<Value> call_ic_function4;
2124 static void InterceptorCallICGetter4(
2125     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2126   ApiTestFuzzer::Fuzz();
2127   CHECK(v8_str("x")->Equals(name));
2128   info.GetReturnValue().Set(call_ic_function4);
2129 }
2130
2131
2132 // This test checks that if interceptor provides a function,
2133 // even if we cached shadowed variant, interceptor's function
2134 // is invoked
2135 THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
2136   v8::Isolate* isolate = CcTest::isolate();
2137   v8::HandleScope scope(isolate);
2138   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2139   templ->SetHandler(
2140       v8::NamedPropertyHandlerConfiguration(InterceptorCallICGetter4));
2141   LocalContext context;
2142   context->Global()->Set(v8_str("o"), templ->NewInstance());
2143   call_ic_function4 = v8_compile("function f(x) { return x - 1; }; f")->Run();
2144   v8::Handle<Value> value = CompileRun(
2145       "Object.getPrototypeOf(o).x = function(x) { return x + 1; };"
2146       "var result = 0;"
2147       "for (var i = 0; i < 1000; i++) {"
2148       "  result = o.x(42);"
2149       "}");
2150   CHECK_EQ(41, value->Int32Value());
2151 }
2152
2153
2154 // Test the case when we stored cacheable lookup into
2155 // a stub, but it got invalidated later on
2156 THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
2157   v8::Isolate* isolate = CcTest::isolate();
2158   v8::HandleScope scope(isolate);
2159   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2160   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
2161   LocalContext context;
2162   context->Global()->Set(v8_str("o"), templ->NewInstance());
2163   v8::Handle<Value> value = CompileRun(
2164       "proto1 = new Object();"
2165       "proto2 = new Object();"
2166       "o.__proto__ = proto1;"
2167       "proto1.__proto__ = proto2;"
2168       "proto2.y = function(x) { return x + 1; };"
2169       // Invoke it many times to compile a stub
2170       "for (var i = 0; i < 7; i++) {"
2171       "  o.y(42);"
2172       "}"
2173       "proto1.y = function(x) { return x - 1; };"
2174       "var result = 0;"
2175       "for (var i = 0; i < 7; i++) {"
2176       "  result += o.y(42);"
2177       "}");
2178   CHECK_EQ(41 * 7, value->Int32Value());
2179 }
2180
2181
2182 // This test checks that if interceptor doesn't provide a function,
2183 // cached constant function is used
2184 THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
2185   v8::Isolate* isolate = CcTest::isolate();
2186   v8::HandleScope scope(isolate);
2187   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2188   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
2189   LocalContext context;
2190   context->Global()->Set(v8_str("o"), templ->NewInstance());
2191   v8::Handle<Value> value = CompileRun(
2192       "function inc(x) { return x + 1; };"
2193       "inc(1);"
2194       "o.x = inc;"
2195       "var result = 0;"
2196       "for (var i = 0; i < 1000; i++) {"
2197       "  result = o.x(42);"
2198       "}");
2199   CHECK_EQ(43, value->Int32Value());
2200 }
2201
2202
2203 static v8::Handle<Value> call_ic_function5;
2204 static void InterceptorCallICGetter5(
2205     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2206   ApiTestFuzzer::Fuzz();
2207   if (v8_str("x")->Equals(name)) info.GetReturnValue().Set(call_ic_function5);
2208 }
2209
2210
2211 // This test checks that if interceptor provides a function,
2212 // even if we cached constant function, interceptor's function
2213 // is invoked
2214 THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
2215   v8::Isolate* isolate = CcTest::isolate();
2216   v8::HandleScope scope(isolate);
2217   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2218   templ->SetHandler(
2219       v8::NamedPropertyHandlerConfiguration(InterceptorCallICGetter5));
2220   LocalContext context;
2221   context->Global()->Set(v8_str("o"), templ->NewInstance());
2222   call_ic_function5 = v8_compile("function f(x) { return x - 1; }; f")->Run();
2223   v8::Handle<Value> value = CompileRun(
2224       "function inc(x) { return x + 1; };"
2225       "inc(1);"
2226       "o.x = inc;"
2227       "var result = 0;"
2228       "for (var i = 0; i < 1000; i++) {"
2229       "  result = o.x(42);"
2230       "}");
2231   CHECK_EQ(41, value->Int32Value());
2232 }
2233
2234
2235 static v8::Handle<Value> call_ic_function6;
2236 static void InterceptorCallICGetter6(
2237     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2238   ApiTestFuzzer::Fuzz();
2239   if (v8_str("x")->Equals(name)) info.GetReturnValue().Set(call_ic_function6);
2240 }
2241
2242
2243 // Same test as above, except the code is wrapped in a function
2244 // to test the optimized compiler.
2245 THREADED_TEST(InterceptorCallICConstantFunctionNotNeededWrapped) {
2246   i::FLAG_allow_natives_syntax = true;
2247   v8::Isolate* isolate = CcTest::isolate();
2248   v8::HandleScope scope(isolate);
2249   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2250   templ->SetHandler(
2251       v8::NamedPropertyHandlerConfiguration(InterceptorCallICGetter6));
2252   LocalContext context;
2253   context->Global()->Set(v8_str("o"), templ->NewInstance());
2254   call_ic_function6 = v8_compile("function f(x) { return x - 1; }; f")->Run();
2255   v8::Handle<Value> value = CompileRun(
2256       "function inc(x) { return x + 1; };"
2257       "inc(1);"
2258       "o.x = inc;"
2259       "function test() {"
2260       "  var result = 0;"
2261       "  for (var i = 0; i < 1000; i++) {"
2262       "    result = o.x(42);"
2263       "  }"
2264       "  return result;"
2265       "};"
2266       "test();"
2267       "test();"
2268       "test();"
2269       "%OptimizeFunctionOnNextCall(test);"
2270       "test()");
2271   CHECK_EQ(41, value->Int32Value());
2272 }
2273
2274
2275 // Test the case when we stored constant function into
2276 // a stub, but it got invalidated later on
2277 THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
2278   v8::Isolate* isolate = CcTest::isolate();
2279   v8::HandleScope scope(isolate);
2280   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2281   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
2282   LocalContext context;
2283   context->Global()->Set(v8_str("o"), templ->NewInstance());
2284   v8::Handle<Value> value = CompileRun(
2285       "function inc(x) { return x + 1; };"
2286       "inc(1);"
2287       "proto1 = new Object();"
2288       "proto2 = new Object();"
2289       "o.__proto__ = proto1;"
2290       "proto1.__proto__ = proto2;"
2291       "proto2.y = inc;"
2292       // Invoke it many times to compile a stub
2293       "for (var i = 0; i < 7; i++) {"
2294       "  o.y(42);"
2295       "}"
2296       "proto1.y = function(x) { return x - 1; };"
2297       "var result = 0;"
2298       "for (var i = 0; i < 7; i++) {"
2299       "  result += o.y(42);"
2300       "}");
2301   CHECK_EQ(41 * 7, value->Int32Value());
2302 }
2303
2304
2305 // Test the case when we stored constant function into
2306 // a stub, but it got invalidated later on due to override on
2307 // global object which is between interceptor and constant function' holders.
2308 THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
2309   v8::Isolate* isolate = CcTest::isolate();
2310   v8::HandleScope scope(isolate);
2311   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2312   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
2313   LocalContext context;
2314   context->Global()->Set(v8_str("o"), templ->NewInstance());
2315   v8::Handle<Value> value = CompileRun(
2316       "function inc(x) { return x + 1; };"
2317       "inc(1);"
2318       "o.__proto__ = this;"
2319       "this.__proto__.y = inc;"
2320       // Invoke it many times to compile a stub
2321       "for (var i = 0; i < 7; i++) {"
2322       "  if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
2323       "}"
2324       "this.y = function(x) { return x - 1; };"
2325       "var result = 0;"
2326       "for (var i = 0; i < 7; i++) {"
2327       "  result += o.y(42);"
2328       "}");
2329   CHECK_EQ(41 * 7, value->Int32Value());
2330 }
2331
2332
2333 // Test the case when actual function to call sits on global object.
2334 THREADED_TEST(InterceptorCallICCachedFromGlobal) {
2335   v8::Isolate* isolate = CcTest::isolate();
2336   v8::HandleScope scope(isolate);
2337   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
2338   templ_o->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
2339
2340   LocalContext context;
2341   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
2342
2343   v8::Handle<Value> value = CompileRun(
2344       "try {"
2345       "  o.__proto__ = this;"
2346       "  for (var i = 0; i < 10; i++) {"
2347       "    var v = o.parseFloat('239');"
2348       "    if (v != 239) throw v;"
2349       // Now it should be ICed and keep a reference to parseFloat.
2350       "  }"
2351       "  var result = 0;"
2352       "  for (var i = 0; i < 10; i++) {"
2353       "    result += o.parseFloat('239');"
2354       "  }"
2355       "  result"
2356       "} catch(e) {"
2357       "  e"
2358       "};");
2359   CHECK_EQ(239 * 10, value->Int32Value());
2360 }
2361
2362
2363 v8::Handle<Value> keyed_call_ic_function;
2364
2365 static void InterceptorKeyedCallICGetter(
2366     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2367   ApiTestFuzzer::Fuzz();
2368   if (v8_str("x")->Equals(name)) {
2369     info.GetReturnValue().Set(keyed_call_ic_function);
2370   }
2371 }
2372
2373
2374 // Test the case when we stored cacheable lookup into
2375 // a stub, but the function name changed (to another cacheable function).
2376 THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
2377   v8::Isolate* isolate = CcTest::isolate();
2378   v8::HandleScope scope(isolate);
2379   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2380   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
2381   LocalContext context;
2382   context->Global()->Set(v8_str("o"), templ->NewInstance());
2383   CompileRun(
2384       "proto = new Object();"
2385       "proto.y = function(x) { return x + 1; };"
2386       "proto.z = function(x) { return x - 1; };"
2387       "o.__proto__ = proto;"
2388       "var result = 0;"
2389       "var method = 'y';"
2390       "for (var i = 0; i < 10; i++) {"
2391       "  if (i == 5) { method = 'z'; };"
2392       "  result += o[method](41);"
2393       "}");
2394   CHECK_EQ(42 * 5 + 40 * 5,
2395            context->Global()->Get(v8_str("result"))->Int32Value());
2396 }
2397
2398
2399 // Test the case when we stored cacheable lookup into
2400 // a stub, but the function name changed (and the new function is present
2401 // both before and after the interceptor in the prototype chain).
2402 THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
2403   v8::Isolate* isolate = CcTest::isolate();
2404   v8::HandleScope scope(isolate);
2405   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2406   templ->SetHandler(
2407       v8::NamedPropertyHandlerConfiguration(InterceptorKeyedCallICGetter));
2408   LocalContext context;
2409   context->Global()->Set(v8_str("proto1"), templ->NewInstance());
2410   keyed_call_ic_function =
2411       v8_compile("function f(x) { return x - 1; }; f")->Run();
2412   CompileRun(
2413       "o = new Object();"
2414       "proto2 = new Object();"
2415       "o.y = function(x) { return x + 1; };"
2416       "proto2.y = function(x) { return x + 2; };"
2417       "o.__proto__ = proto1;"
2418       "proto1.__proto__ = proto2;"
2419       "var result = 0;"
2420       "var method = 'x';"
2421       "for (var i = 0; i < 10; i++) {"
2422       "  if (i == 5) { method = 'y'; };"
2423       "  result += o[method](41);"
2424       "}");
2425   CHECK_EQ(42 * 5 + 40 * 5,
2426            context->Global()->Get(v8_str("result"))->Int32Value());
2427 }
2428
2429
2430 // Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
2431 // on the global object.
2432 THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
2433   v8::Isolate* isolate = CcTest::isolate();
2434   v8::HandleScope scope(isolate);
2435   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2436   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
2437   LocalContext context;
2438   context->Global()->Set(v8_str("o"), templ->NewInstance());
2439   CompileRun(
2440       "function inc(x) { return x + 1; };"
2441       "inc(1);"
2442       "function dec(x) { return x - 1; };"
2443       "dec(1);"
2444       "o.__proto__ = this;"
2445       "this.__proto__.x = inc;"
2446       "this.__proto__.y = dec;"
2447       "var result = 0;"
2448       "var method = 'x';"
2449       "for (var i = 0; i < 10; i++) {"
2450       "  if (i == 5) { method = 'y'; };"
2451       "  result += o[method](41);"
2452       "}");
2453   CHECK_EQ(42 * 5 + 40 * 5,
2454            context->Global()->Get(v8_str("result"))->Int32Value());
2455 }
2456
2457
2458 // Test the case when actual function to call sits on global object.
2459 THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
2460   v8::Isolate* isolate = CcTest::isolate();
2461   v8::HandleScope scope(isolate);
2462   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
2463   templ_o->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
2464   LocalContext context;
2465   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
2466
2467   CompileRun(
2468       "function len(x) { return x.length; };"
2469       "o.__proto__ = this;"
2470       "var m = 'parseFloat';"
2471       "var result = 0;"
2472       "for (var i = 0; i < 10; i++) {"
2473       "  if (i == 5) {"
2474       "    m = 'len';"
2475       "    saved_result = result;"
2476       "  };"
2477       "  result = o[m]('239');"
2478       "}");
2479   CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
2480   CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
2481 }
2482
2483
2484 // Test the map transition before the interceptor.
2485 THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
2486   v8::Isolate* isolate = CcTest::isolate();
2487   v8::HandleScope scope(isolate);
2488   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
2489   templ_o->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
2490   LocalContext context;
2491   context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
2492
2493   CompileRun(
2494       "var o = new Object();"
2495       "o.__proto__ = proto;"
2496       "o.method = function(x) { return x + 1; };"
2497       "var m = 'method';"
2498       "var result = 0;"
2499       "for (var i = 0; i < 10; i++) {"
2500       "  if (i == 5) { o.method = function(x) { return x - 1; }; };"
2501       "  result += o[m](41);"
2502       "}");
2503   CHECK_EQ(42 * 5 + 40 * 5,
2504            context->Global()->Get(v8_str("result"))->Int32Value());
2505 }
2506
2507
2508 // Test the map transition after the interceptor.
2509 THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
2510   v8::Isolate* isolate = CcTest::isolate();
2511   v8::HandleScope scope(isolate);
2512   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
2513   templ_o->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
2514   LocalContext context;
2515   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
2516
2517   CompileRun(
2518       "var proto = new Object();"
2519       "o.__proto__ = proto;"
2520       "proto.method = function(x) { return x + 1; };"
2521       "var m = 'method';"
2522       "var result = 0;"
2523       "for (var i = 0; i < 10; i++) {"
2524       "  if (i == 5) { proto.method = function(x) { return x - 1; }; };"
2525       "  result += o[m](41);"
2526       "}");
2527   CHECK_EQ(42 * 5 + 40 * 5,
2528            context->Global()->Get(v8_str("result"))->Int32Value());
2529 }
2530
2531
2532 static int interceptor_call_count = 0;
2533
2534 static void InterceptorICRefErrorGetter(
2535     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2536   ApiTestFuzzer::Fuzz();
2537   if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
2538     info.GetReturnValue().Set(call_ic_function2);
2539   }
2540 }
2541
2542
2543 // This test should hit load and call ICs for the interceptor case.
2544 // Once in a while, the interceptor will reply that a property was not
2545 // found in which case we should get a reference error.
2546 THREADED_TEST(InterceptorICReferenceErrors) {
2547   v8::Isolate* isolate = CcTest::isolate();
2548   v8::HandleScope scope(isolate);
2549   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2550   templ->SetHandler(
2551       v8::NamedPropertyHandlerConfiguration(InterceptorICRefErrorGetter));
2552   LocalContext context(0, templ, v8::Handle<Value>());
2553   call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
2554   v8::Handle<Value> value = CompileRun(
2555       "function f() {"
2556       "  for (var i = 0; i < 1000; i++) {"
2557       "    try { x; } catch(e) { return true; }"
2558       "  }"
2559       "  return false;"
2560       "};"
2561       "f();");
2562   CHECK_EQ(true, value->BooleanValue());
2563   interceptor_call_count = 0;
2564   value = CompileRun(
2565       "function g() {"
2566       "  for (var i = 0; i < 1000; i++) {"
2567       "    try { x(42); } catch(e) { return true; }"
2568       "  }"
2569       "  return false;"
2570       "};"
2571       "g();");
2572   CHECK_EQ(true, value->BooleanValue());
2573 }
2574
2575
2576 static int interceptor_ic_exception_get_count = 0;
2577
2578 static void InterceptorICExceptionGetter(
2579     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2580   ApiTestFuzzer::Fuzz();
2581   if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
2582     info.GetReturnValue().Set(call_ic_function3);
2583   }
2584   if (interceptor_ic_exception_get_count == 20) {
2585     info.GetIsolate()->ThrowException(v8_num(42));
2586     return;
2587   }
2588 }
2589
2590
2591 // Test interceptor load/call IC where the interceptor throws an
2592 // exception once in a while.
2593 THREADED_TEST(InterceptorICGetterExceptions) {
2594   interceptor_ic_exception_get_count = 0;
2595   v8::Isolate* isolate = CcTest::isolate();
2596   v8::HandleScope scope(isolate);
2597   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2598   templ->SetHandler(
2599       v8::NamedPropertyHandlerConfiguration(InterceptorICExceptionGetter));
2600   LocalContext context(0, templ, v8::Handle<Value>());
2601   call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
2602   v8::Handle<Value> value = CompileRun(
2603       "function f() {"
2604       "  for (var i = 0; i < 100; i++) {"
2605       "    try { x; } catch(e) { return true; }"
2606       "  }"
2607       "  return false;"
2608       "};"
2609       "f();");
2610   CHECK_EQ(true, value->BooleanValue());
2611   interceptor_ic_exception_get_count = 0;
2612   value = CompileRun(
2613       "function f() {"
2614       "  for (var i = 0; i < 100; i++) {"
2615       "    try { x(42); } catch(e) { return true; }"
2616       "  }"
2617       "  return false;"
2618       "};"
2619       "f();");
2620   CHECK_EQ(true, value->BooleanValue());
2621 }
2622
2623
2624 static int interceptor_ic_exception_set_count = 0;
2625
2626 static void InterceptorICExceptionSetter(
2627     Local<Name> key, Local<Value> value,
2628     const v8::PropertyCallbackInfo<v8::Value>& info) {
2629   ApiTestFuzzer::Fuzz();
2630   if (++interceptor_ic_exception_set_count > 20) {
2631     info.GetIsolate()->ThrowException(v8_num(42));
2632   }
2633 }
2634
2635
2636 // Test interceptor store IC where the interceptor throws an exception
2637 // once in a while.
2638 THREADED_TEST(InterceptorICSetterExceptions) {
2639   interceptor_ic_exception_set_count = 0;
2640   v8::Isolate* isolate = CcTest::isolate();
2641   v8::HandleScope scope(isolate);
2642   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2643   templ->SetHandler(
2644       v8::NamedPropertyHandlerConfiguration(0, InterceptorICExceptionSetter));
2645   LocalContext context(0, templ, v8::Handle<Value>());
2646   v8::Handle<Value> value = CompileRun(
2647       "function f() {"
2648       "  for (var i = 0; i < 100; i++) {"
2649       "    try { x = 42; } catch(e) { return true; }"
2650       "  }"
2651       "  return false;"
2652       "};"
2653       "f();");
2654   CHECK_EQ(true, value->BooleanValue());
2655 }
2656
2657
2658 // Test that we ignore null interceptors.
2659 THREADED_TEST(NullNamedInterceptor) {
2660   v8::Isolate* isolate = CcTest::isolate();
2661   v8::HandleScope scope(isolate);
2662   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2663   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
2664       static_cast<v8::GenericNamedPropertyGetterCallback>(0)));
2665   LocalContext context;
2666   templ->Set(CcTest::isolate(), "x", v8_num(42));
2667   v8::Handle<v8::Object> obj = templ->NewInstance();
2668   context->Global()->Set(v8_str("obj"), obj);
2669   v8::Handle<Value> value = CompileRun("obj.x");
2670   CHECK(value->IsInt32());
2671   CHECK_EQ(42, value->Int32Value());
2672 }
2673
2674
2675 // Test that we ignore null interceptors.
2676 THREADED_TEST(NullIndexedInterceptor) {
2677   v8::Isolate* isolate = CcTest::isolate();
2678   v8::HandleScope scope(isolate);
2679   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2680   templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
2681       static_cast<v8::IndexedPropertyGetterCallback>(0)));
2682   LocalContext context;
2683   templ->Set(CcTest::isolate(), "42", v8_num(42));
2684   v8::Handle<v8::Object> obj = templ->NewInstance();
2685   context->Global()->Set(v8_str("obj"), obj);
2686   v8::Handle<Value> value = CompileRun("obj[42]");
2687   CHECK(value->IsInt32());
2688   CHECK_EQ(42, value->Int32Value());
2689 }
2690
2691
2692 THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
2693   v8::Isolate* isolate = CcTest::isolate();
2694   v8::HandleScope scope(isolate);
2695   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2696   templ->InstanceTemplate()->SetHandler(
2697       v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
2698   LocalContext env;
2699   env->Global()->Set(v8_str("obj"), templ->GetFunction()->NewInstance());
2700   ExpectTrue("obj.x === 42");
2701   ExpectTrue("!obj.propertyIsEnumerable('x')");
2702 }
2703
2704
2705 THREADED_TEST(Regress256330) {
2706   i::FLAG_allow_natives_syntax = true;
2707   LocalContext context;
2708   v8::HandleScope scope(context->GetIsolate());
2709   Handle<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
2710   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2711   context->Global()->Set(v8_str("Bug"), templ->GetFunction());
2712   CompileRun(
2713       "\"use strict\"; var o = new Bug;"
2714       "function f(o) { o.x = 10; };"
2715       "f(o); f(o); f(o);"
2716       "%OptimizeFunctionOnNextCall(f);"
2717       "f(o);");
2718   ExpectBoolean("%GetOptimizationStatus(f) != 2", true);
2719 }
2720
2721
2722 THREADED_TEST(CrankshaftInterceptorSetter) {
2723   i::FLAG_allow_natives_syntax = true;
2724   v8::HandleScope scope(CcTest::isolate());
2725   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2726   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2727   LocalContext env;
2728   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2729   CompileRun(
2730       "var obj = new Obj;"
2731       // Initialize fields to avoid transitions later.
2732       "obj.age = 0;"
2733       "obj.accessor_age = 42;"
2734       "function setter(i) { this.accessor_age = i; };"
2735       "function getter() { return this.accessor_age; };"
2736       "function setAge(i) { obj.age = i; };"
2737       "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
2738       "setAge(1);"
2739       "setAge(2);"
2740       "setAge(3);"
2741       "%OptimizeFunctionOnNextCall(setAge);"
2742       "setAge(4);");
2743   // All stores went through the interceptor.
2744   ExpectInt32("obj.interceptor_age", 4);
2745   ExpectInt32("obj.accessor_age", 42);
2746 }
2747
2748
2749 THREADED_TEST(CrankshaftInterceptorGetter) {
2750   i::FLAG_allow_natives_syntax = true;
2751   v8::HandleScope scope(CcTest::isolate());
2752   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2753   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2754   LocalContext env;
2755   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2756   CompileRun(
2757       "var obj = new Obj;"
2758       // Initialize fields to avoid transitions later.
2759       "obj.age = 1;"
2760       "obj.accessor_age = 42;"
2761       "function getter() { return this.accessor_age; };"
2762       "function getAge() { return obj.interceptor_age; };"
2763       "Object.defineProperty(obj, 'interceptor_age', { get:getter });"
2764       "getAge();"
2765       "getAge();"
2766       "getAge();"
2767       "%OptimizeFunctionOnNextCall(getAge);");
2768   // Access through interceptor.
2769   ExpectInt32("getAge()", 1);
2770 }
2771
2772
2773 THREADED_TEST(CrankshaftInterceptorFieldRead) {
2774   i::FLAG_allow_natives_syntax = true;
2775   v8::HandleScope scope(CcTest::isolate());
2776   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2777   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2778   LocalContext env;
2779   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2780   CompileRun(
2781       "var obj = new Obj;"
2782       "obj.__proto__.interceptor_age = 42;"
2783       "obj.age = 100;"
2784       "function getAge() { return obj.interceptor_age; };");
2785   ExpectInt32("getAge();", 100);
2786   ExpectInt32("getAge();", 100);
2787   ExpectInt32("getAge();", 100);
2788   CompileRun("%OptimizeFunctionOnNextCall(getAge);");
2789   // Access through interceptor.
2790   ExpectInt32("getAge();", 100);
2791 }
2792
2793
2794 THREADED_TEST(CrankshaftInterceptorFieldWrite) {
2795   i::FLAG_allow_natives_syntax = true;
2796   v8::HandleScope scope(CcTest::isolate());
2797   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2798   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2799   LocalContext env;
2800   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2801   CompileRun(
2802       "var obj = new Obj;"
2803       "obj.age = 100000;"
2804       "function setAge(i) { obj.age = i };"
2805       "setAge(100);"
2806       "setAge(101);"
2807       "setAge(102);"
2808       "%OptimizeFunctionOnNextCall(setAge);"
2809       "setAge(103);");
2810   ExpectInt32("obj.age", 100000);
2811   ExpectInt32("obj.interceptor_age", 103);
2812 }
2813
2814
2815 THREADED_TEST(Regress149912) {
2816   LocalContext context;
2817   v8::HandleScope scope(context->GetIsolate());
2818   Handle<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
2819   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
2820   context->Global()->Set(v8_str("Bug"), templ->GetFunction());
2821   CompileRun("Number.prototype.__proto__ = new Bug; var x = 0; x.foo();");
2822 }
2823
2824
2825 THREADED_TEST(Regress125988) {
2826   v8::HandleScope scope(CcTest::isolate());
2827   Handle<FunctionTemplate> intercept = FunctionTemplate::New(CcTest::isolate());
2828   AddInterceptor(intercept, EmptyInterceptorGetter, EmptyInterceptorSetter);
2829   LocalContext env;
2830   env->Global()->Set(v8_str("Intercept"), intercept->GetFunction());
2831   CompileRun(
2832       "var a = new Object();"
2833       "var b = new Intercept();"
2834       "var c = new Object();"
2835       "c.__proto__ = b;"
2836       "b.__proto__ = a;"
2837       "a.x = 23;"
2838       "for (var i = 0; i < 3; i++) c.x;");
2839   ExpectBoolean("c.hasOwnProperty('x')", false);
2840   ExpectInt32("c.x", 23);
2841   CompileRun(
2842       "a.y = 42;"
2843       "for (var i = 0; i < 3; i++) c.x;");
2844   ExpectBoolean("c.hasOwnProperty('x')", false);
2845   ExpectInt32("c.x", 23);
2846   ExpectBoolean("c.hasOwnProperty('y')", false);
2847   ExpectInt32("c.y", 42);
2848 }
2849
2850
2851 static void IndexedPropertyEnumerator(
2852     const v8::PropertyCallbackInfo<v8::Array>& info) {
2853   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 1);
2854   result->Set(0, v8::Integer::New(info.GetIsolate(), 7));
2855   info.GetReturnValue().Set(result);
2856 }
2857
2858
2859 static void NamedPropertyEnumerator(
2860     const v8::PropertyCallbackInfo<v8::Array>& info) {
2861   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
2862   result->Set(0, v8_str("x"));
2863   result->Set(1, v8::Symbol::GetIterator(info.GetIsolate()));
2864   info.GetReturnValue().Set(result);
2865 }
2866
2867
2868 THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
2869   v8::Isolate* isolate = CcTest::isolate();
2870   v8::HandleScope handle_scope(isolate);
2871   v8::Handle<v8::ObjectTemplate> obj_template =
2872       v8::ObjectTemplate::New(isolate);
2873
2874   obj_template->Set(v8_str("7"), v8::Integer::New(CcTest::isolate(), 7));
2875   obj_template->Set(v8_str("x"), v8::Integer::New(CcTest::isolate(), 42));
2876   obj_template->SetHandler(v8::IndexedPropertyHandlerConfiguration(
2877       NULL, NULL, NULL, NULL, IndexedPropertyEnumerator));
2878   obj_template->SetHandler(v8::NamedPropertyHandlerConfiguration(
2879       NULL, NULL, NULL, NULL, NamedPropertyEnumerator));
2880
2881   LocalContext context;
2882   v8::Handle<v8::Object> global = context->Global();
2883   global->Set(v8_str("object"), obj_template->NewInstance());
2884
2885   v8::Handle<v8::Value> result =
2886       CompileRun("Object.getOwnPropertyNames(object)");
2887   CHECK(result->IsArray());
2888   v8::Handle<v8::Array> result_array = v8::Handle<v8::Array>::Cast(result);
2889   CHECK_EQ(2u, result_array->Length());
2890   CHECK(result_array->Get(0)->IsString());
2891   CHECK(result_array->Get(1)->IsString());
2892   CHECK(v8_str("7")->Equals(result_array->Get(0)));
2893   CHECK(v8_str("x")->Equals(result_array->Get(1)));
2894
2895   result = CompileRun("var ret = []; for (var k in object) ret.push(k); ret");
2896   CHECK(result->IsArray());
2897   result_array = v8::Handle<v8::Array>::Cast(result);
2898   CHECK_EQ(2u, result_array->Length());
2899   CHECK(result_array->Get(0)->IsString());
2900   CHECK(result_array->Get(1)->IsString());
2901   CHECK(v8_str("7")->Equals(result_array->Get(0)));
2902   CHECK(v8_str("x")->Equals(result_array->Get(1)));
2903
2904   result = CompileRun("Object.getOwnPropertySymbols(object)");
2905   CHECK(result->IsArray());
2906   result_array = v8::Handle<v8::Array>::Cast(result);
2907   CHECK_EQ(1u, result_array->Length());
2908   CHECK(result_array->Get(0)->Equals(v8::Symbol::GetIterator(isolate)));
2909 }
2910
2911
2912 namespace {
2913
2914 template <typename T>
2915 Local<Object> BuildWrappedObject(v8::Isolate* isolate, T* data) {
2916   auto templ = v8::ObjectTemplate::New(isolate);
2917   templ->SetInternalFieldCount(1);
2918   auto instance = templ->NewInstance();
2919   instance->SetAlignedPointerInInternalField(0, data);
2920   return instance;
2921 }
2922
2923
2924 template <typename T>
2925 T* GetWrappedObject(Local<Value> data) {
2926   return reinterpret_cast<T*>(
2927       Object::Cast(*data)->GetAlignedPointerFromInternalField(0));
2928 }
2929
2930
2931 struct AccessCheckData {
2932   int count;
2933   bool result;
2934 };
2935
2936
2937 bool SimpleNamedAccessChecker(Local<v8::Object> global, Local<Value> name,
2938                               v8::AccessType type, Local<Value> data) {
2939   auto access_check_data = GetWrappedObject<AccessCheckData>(data);
2940   access_check_data->count++;
2941   return access_check_data->result;
2942 }
2943
2944
2945 bool SimpleIndexedAccessChecker(Local<v8::Object> global, uint32_t index,
2946                                 v8::AccessType type, Local<Value> data) {
2947   auto access_check_data = GetWrappedObject<AccessCheckData>(data);
2948   access_check_data->count++;
2949   return access_check_data->result;
2950 }
2951
2952
2953 struct ShouldInterceptData {
2954   int value;
2955   bool should_intercept;
2956 };
2957
2958
2959 void ShouldNamedInterceptor(Local<Name> name,
2960                             const v8::PropertyCallbackInfo<Value>& info) {
2961   ApiTestFuzzer::Fuzz();
2962   CheckReturnValue(info, FUNCTION_ADDR(ShouldNamedInterceptor));
2963   auto data = GetWrappedObject<ShouldInterceptData>(info.Data());
2964   if (!data->should_intercept) return;
2965   info.GetReturnValue().Set(v8_num(data->value));
2966 }
2967
2968
2969 void ShouldIndexedInterceptor(uint32_t,
2970                               const v8::PropertyCallbackInfo<Value>& info) {
2971   ApiTestFuzzer::Fuzz();
2972   CheckReturnValue(info, FUNCTION_ADDR(ShouldIndexedInterceptor));
2973   auto data = GetWrappedObject<ShouldInterceptData>(info.Data());
2974   if (!data->should_intercept) return;
2975   info.GetReturnValue().Set(v8_num(data->value));
2976 }
2977
2978 }  // namespace
2979
2980
2981 THREADED_TEST(NamedAllCanReadInterceptor) {
2982   auto isolate = CcTest::isolate();
2983   v8::HandleScope handle_scope(isolate);
2984   LocalContext context;
2985
2986   AccessCheckData access_check_data;
2987   access_check_data.result = false;
2988   access_check_data.count = 0;
2989
2990   ShouldInterceptData intercept_data_0;
2991   intercept_data_0.value = 239;
2992   intercept_data_0.should_intercept = true;
2993
2994   ShouldInterceptData intercept_data_1;
2995   intercept_data_1.value = 165;
2996   intercept_data_1.should_intercept = false;
2997
2998   auto intercepted_0 = v8::ObjectTemplate::New(isolate);
2999   {
3000     v8::NamedPropertyHandlerConfiguration conf(ShouldNamedInterceptor);
3001     conf.flags = v8::PropertyHandlerFlags::kAllCanRead;
3002     conf.data =
3003         BuildWrappedObject<ShouldInterceptData>(isolate, &intercept_data_0);
3004     intercepted_0->SetHandler(conf);
3005   }
3006
3007   auto intercepted_1 = v8::ObjectTemplate::New(isolate);
3008   {
3009     v8::NamedPropertyHandlerConfiguration conf(ShouldNamedInterceptor);
3010     conf.flags = v8::PropertyHandlerFlags::kAllCanRead;
3011     conf.data =
3012         BuildWrappedObject<ShouldInterceptData>(isolate, &intercept_data_1);
3013     intercepted_1->SetHandler(conf);
3014   }
3015
3016   auto checked = v8::ObjectTemplate::New(isolate);
3017   checked->SetAccessCheckCallbacks(
3018       SimpleNamedAccessChecker, nullptr,
3019       BuildWrappedObject<AccessCheckData>(isolate, &access_check_data), false);
3020
3021   context->Global()->Set(v8_str("intercepted_0"), intercepted_0->NewInstance());
3022   context->Global()->Set(v8_str("intercepted_1"), intercepted_1->NewInstance());
3023   auto checked_instance = checked->NewInstance();
3024   checked_instance->Set(v8_str("whatever"), v8_num(17));
3025   context->Global()->Set(v8_str("checked"), checked_instance);
3026   CompileRun(
3027       "checked.__proto__ = intercepted_1;"
3028       "intercepted_1.__proto__ = intercepted_0;");
3029
3030   checked_instance->TurnOnAccessCheck();
3031   CHECK_EQ(0, access_check_data.count);
3032
3033   access_check_data.result = true;
3034   ExpectInt32("checked.whatever", 17);
3035   CHECK_EQ(1, access_check_data.count);
3036
3037   access_check_data.result = false;
3038   ExpectInt32("checked.whatever", intercept_data_0.value);
3039   CHECK_EQ(2, access_check_data.count);
3040
3041   intercept_data_1.should_intercept = true;
3042   ExpectInt32("checked.whatever", intercept_data_1.value);
3043   CHECK_EQ(3, access_check_data.count);
3044 }
3045
3046
3047 THREADED_TEST(IndexedAllCanReadInterceptor) {
3048   auto isolate = CcTest::isolate();
3049   v8::HandleScope handle_scope(isolate);
3050   LocalContext context;
3051
3052   AccessCheckData access_check_data;
3053   access_check_data.result = false;
3054   access_check_data.count = 0;
3055
3056   ShouldInterceptData intercept_data_0;
3057   intercept_data_0.value = 239;
3058   intercept_data_0.should_intercept = true;
3059
3060   ShouldInterceptData intercept_data_1;
3061   intercept_data_1.value = 165;
3062   intercept_data_1.should_intercept = false;
3063
3064   auto intercepted_0 = v8::ObjectTemplate::New(isolate);
3065   {
3066     v8::IndexedPropertyHandlerConfiguration conf(ShouldIndexedInterceptor);
3067     conf.flags = v8::PropertyHandlerFlags::kAllCanRead;
3068     conf.data =
3069         BuildWrappedObject<ShouldInterceptData>(isolate, &intercept_data_0);
3070     intercepted_0->SetHandler(conf);
3071   }
3072
3073   auto intercepted_1 = v8::ObjectTemplate::New(isolate);
3074   {
3075     v8::IndexedPropertyHandlerConfiguration conf(ShouldIndexedInterceptor);
3076     conf.flags = v8::PropertyHandlerFlags::kAllCanRead;
3077     conf.data =
3078         BuildWrappedObject<ShouldInterceptData>(isolate, &intercept_data_1);
3079     intercepted_1->SetHandler(conf);
3080   }
3081
3082   auto checked = v8::ObjectTemplate::New(isolate);
3083   checked->SetAccessCheckCallbacks(
3084       nullptr, SimpleIndexedAccessChecker,
3085       BuildWrappedObject<AccessCheckData>(isolate, &access_check_data), false);
3086
3087   context->Global()->Set(v8_str("intercepted_0"), intercepted_0->NewInstance());
3088   context->Global()->Set(v8_str("intercepted_1"), intercepted_1->NewInstance());
3089   auto checked_instance = checked->NewInstance();
3090   context->Global()->Set(v8_str("checked"), checked_instance);
3091   checked_instance->Set(15, v8_num(17));
3092   CompileRun(
3093       "checked.__proto__ = intercepted_1;"
3094       "intercepted_1.__proto__ = intercepted_0;");
3095
3096   checked_instance->TurnOnAccessCheck();
3097   CHECK_EQ(0, access_check_data.count);
3098
3099   access_check_data.result = true;
3100   ExpectInt32("checked[15]", 17);
3101   CHECK_EQ(1, access_check_data.count);
3102
3103   access_check_data.result = false;
3104   ExpectInt32("checked[15]", intercept_data_0.value);
3105   CHECK_EQ(2, access_check_data.count);
3106
3107   intercept_data_1.should_intercept = true;
3108   ExpectInt32("checked[15]", intercept_data_1.value);
3109   CHECK_EQ(3, access_check_data.count);
3110 }