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