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.
7 #include "test/cctest/test-api.h"
9 #include "include/v8-util.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"
23 using ::v8::BooleanObject;
25 using ::v8::Extension;
27 using ::v8::FunctionTemplate;
29 using ::v8::HandleScope;
33 using ::v8::MessageCallback;
35 using ::v8::ObjectTemplate;
36 using ::v8::Persistent;
38 using ::v8::StackTrace;
42 using ::v8::Undefined;
50 void Returns42(const v8::FunctionCallbackInfo<v8::Value>& info) {
51 info.GetReturnValue().Set(42);
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));
63 void EmptyInterceptorGetter(Local<Name> name,
64 const v8::PropertyCallbackInfo<v8::Value>& info) {}
67 void EmptyInterceptorSetter(Local<Name> name, Local<Value> value,
68 const v8::PropertyCallbackInfo<v8::Value>& info) {}
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)));
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);
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);
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);
101 void StringInterceptorGetter(
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_";
109 for (i = 0; name_str[i] && prefix[i]; ++i) {
110 if (name_str[i] != prefix[i]) return;
112 Handle<Object> self = Handle<Object>::Cast(info.This());
113 info.GetReturnValue().Set(self->GetHiddenValue(v8_str(name_str + i)));
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_";
125 for (i = 0; name_str[i] && prefix[i]; ++i) {
126 if (name_str[i] != prefix[i]) break;
128 if (!prefix[i]) return;
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);
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);
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);
149 void GenericInterceptorGetter(Local<Name> generic_name,
150 const v8::PropertyCallbackInfo<v8::Value>& info) {
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));
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);
164 Handle<Object> self = Handle<Object>::Cast(info.This());
165 info.GetReturnValue().Set(self->Get(str));
168 void GenericInterceptorSetter(Local<Name> generic_name, Local<Value> value,
169 const v8::PropertyCallbackInfo<v8::Value>& info) {
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));
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);
183 Handle<Object> self = Handle<Object>::Cast(info.This());
184 self->Set(str, value);
185 info.GetReturnValue().Set(value);
188 void AddAccessor(Handle<FunctionTemplate> templ, Handle<String> name,
189 v8::AccessorGetterCallback getter,
190 v8::AccessorSetterCallback setter) {
191 templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
194 void AddInterceptor(Handle<FunctionTemplate> templ,
195 v8::NamedPropertyGetterCallback getter,
196 v8::NamedPropertySetterCallback setter) {
197 templ->InstanceTemplate()->SetNamedPropertyHandler(getter, setter);
201 void AddAccessor(Handle<FunctionTemplate> templ, Handle<Name> name,
202 v8::AccessorNameGetterCallback getter,
203 v8::AccessorNameSetterCallback setter) {
204 templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
207 void AddInterceptor(Handle<FunctionTemplate> templ,
208 v8::GenericNamedPropertyGetterCallback getter,
209 v8::GenericNamedPropertySetterCallback setter) {
210 templ->InstanceTemplate()->SetHandler(
211 v8::NamedPropertyHandlerConfiguration(getter, setter));
215 v8::Handle<v8::Object> bottom;
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));
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));
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));
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));
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));
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));
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));
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));
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));
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));
296 int echo_named_call_count;
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);
307 void InterceptorHasOwnPropertyGetter(
308 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
309 ApiTestFuzzer::Fuzz();
312 void InterceptorHasOwnPropertyGetterGC(
313 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
314 ApiTestFuzzer::Fuzz();
315 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
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());
337 "o.hasOwnProperty('ostehaps');");
338 CHECK_EQ(true, value->BooleanValue());
340 "var p = new constructor();"
341 "p.hasOwnProperty('ostehaps');");
342 CHECK_EQ(false, value->BooleanValue());
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.
358 "function makestr(size) {"
360 " case 1: return 'f';"
361 " case 2: return 'fo';"
362 " case 3: return 'foo';"
364 " return makestr(size >> 1) + makestr((size + 1) >> 1);"
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());
377 static void CheckInterceptorLoadIC(
378 v8::GenericNamedPropertyGetterCallback getter, const char* source,
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,
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());
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));
403 // This test should hit the load IC for the interceptor case.
404 THREADED_TEST(InterceptorLoadIC) {
405 CheckInterceptorLoadIC(InterceptorLoadICGetter,
407 "for (var i = 0; i < 1000; i++) {"
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).
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>());
428 THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
429 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
432 "for (var i = 0; i < 1000; i++) {"
439 THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
440 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
442 "o.__proto__ = { 'y': 239 };"
443 "for (var i = 0; i < 1000; i++) {"
444 " result = o.y + o.x;"
450 THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
451 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
453 "o.__proto__.y = 239;"
454 "for (var i = 0; i < 1000; i++) {"
455 " result = o.y + o.x;"
461 THREADED_TEST(InterceptorLoadICUndefined) {
462 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
464 "for (var i = 0; i < 1000; i++) {"
465 " result = (o.y == undefined) ? 239 : 42;"
471 THREADED_TEST(InterceptorLoadICWithOverride) {
472 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
473 "fst = new Object(); fst.__proto__ = o;"
474 "snd = new Object(); snd.__proto__ = fst;"
476 "for (var i = 0; i < 1000; i++) {"
481 "for (var i = 0; i < 1000; i++) {"
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;"
497 "for (var i = 0; i < 1000; i++) {"
499 // Now it should be ICed and keep a reference to x defined on proto
502 "for (var i = 0; i < 1000; i++) {"
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;"
520 "for (var i = 0; i < 1000; i++) {"
522 // Now it should be ICed and keep a reference to y defined on proto2
526 "for (var i = 0; i < 1000; i++) {"
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;
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] = [];"
554 "o.__proto__ = proto;"
556 "for (var i = 0; i < 1000; i++) {"
557 " result += receiver.x;"
561 CHECK_EQ(1000, interceptor_load_not_handled_calls);
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
578 "this.y = 42;" // Assign on a global.
580 "for (var i = 0; i < 10; i++) {"
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);
594 THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
595 v8::Isolate* isolate = CcTest::isolate();
596 v8::HandleScope scope(isolate);
597 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
599 v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
600 templ->SetAccessor(v8_str("y"), Return239Callback);
601 LocalContext context;
602 context->Global()->Set(v8_str("o"), templ->NewInstance());
604 // Check the case when receiver and interceptor's holder
605 // are the same objects.
606 v8::Handle<Value> value = CompileRun(
608 "for (var i = 0; i < 7; i++) {"
611 CHECK_EQ(239, value->Int32Value());
613 // Check the case when interceptor's holder is in proto chain
616 "r = { __proto__: o };"
618 "for (var i = 0; i < 7; i++) {"
621 CHECK_EQ(239, value->Int32Value());
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);
630 v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
631 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
632 templ_p->SetAccessor(v8_str("y"), Return239Callback);
634 LocalContext context;
635 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
636 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
638 // Check the case when receiver and interceptor's holder
639 // are the same objects.
640 v8::Handle<Value> value = CompileRun(
643 "for (var i = 0; i < 7; i++) {"
644 " result = o.x + o.y;"
646 CHECK_EQ(239 + 42, value->Int32Value());
648 // Check the case when interceptor's holder is in proto chain
651 "r = { __proto__: o };"
653 "for (var i = 0; i < 7; i++) {"
654 " result = r.x + r.y;"
656 CHECK_EQ(239 + 42, value->Int32Value());
660 THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
661 v8::Isolate* isolate = CcTest::isolate();
662 v8::HandleScope scope(isolate);
663 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
665 v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
666 templ->SetAccessor(v8_str("y"), Return239Callback);
668 LocalContext context;
669 context->Global()->Set(v8_str("o"), templ->NewInstance());
671 v8::Handle<Value> value = CompileRun(
672 "fst = new Object(); fst.__proto__ = o;"
673 "snd = new Object(); snd.__proto__ = fst;"
675 "for (var i = 0; i < 7; i++) {"
680 "for (var i = 0; i < 7; i++) {"
684 CHECK_EQ(239 + 42, value->Int32Value());
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);
695 v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
696 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
697 templ_p->SetAccessor(v8_str("y"), Return239Callback);
699 LocalContext context;
700 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
701 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
703 v8::Handle<Value> value = CompileRun(
705 "for (var i = 0; i < 7; i++) {"
707 // Now it should be ICed and keep a reference to x defined on p
710 "for (var i = 0; i < 7; i++) {"
714 CHECK_EQ(42 * 7, value->Int32Value());
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);
725 v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
726 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
727 templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
729 LocalContext context;
730 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
731 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
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++) {"
739 // Now it should be ICed and keep a reference to y defined on p
743 "for (var i = 0; i < 10; i++) {"
747 CHECK_EQ(42 * 10, value->Int32Value());
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);
759 v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
760 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
761 templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
763 LocalContext context;
764 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
765 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
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
776 "for (var i = 0; i < 10; i++) {"
780 CHECK_EQ(42 * 10, value->Int32Value());
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));
792 THREADED_TEST(InterceptorReturningZero) {
793 CheckInterceptorLoadIC(InterceptorLoadICGetter0, "o.x == undefined ? 1 : 0",
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);
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,
815 LocalContext context;
816 context->Global()->Set(v8_str("o"), templ->NewInstance());
818 "for (var i = 0; i < 1000; i++) {"
824 THREADED_TEST(InterceptorStoreICWithNoSetter) {
825 v8::Isolate* isolate = CcTest::isolate();
826 v8::HandleScope scope(isolate);
827 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
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++) {"
837 CHECK_EQ(239 + 42, value->Int32Value());
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);
850 env->Global()->Set(v8_str("Child"), child->GetFunction());
852 "var child = new Child;"
854 ExpectBoolean("child.hasOwnProperty('age')", false);
855 ExpectInt32("child.age", 10);
856 ExpectInt32("child.accessor_age", 10);
860 THREADED_TEST(LegacyInterceptorDoesNotSeeSymbols) {
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"));
868 child->Inherit(parent);
869 AddAccessor(parent, age, SymbolAccessorGetter, SymbolAccessorSetter);
870 AddInterceptor(child, StringInterceptorGetter, StringInterceptorSetter);
872 env->Global()->Set(v8_str("Child"), child->GetFunction());
873 env->Global()->Set(v8_str("age"), age);
875 "var child = new Child;"
877 ExpectInt32("child[age]", 10);
878 ExpectBoolean("child.hasOwnProperty('age')", false);
879 ExpectBoolean("child.hasOwnProperty('accessor_age')", true);
883 THREADED_TEST(GenericInterceptorDoesSeeSymbols) {
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);
892 child->Inherit(parent);
893 AddAccessor(parent, age, SymbolAccessorGetter, SymbolAccessorSetter);
894 AddInterceptor(child, GenericInterceptorGetter, GenericInterceptorSetter);
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);
900 "var child = new Child;"
902 ExpectInt32("child[age]", 10);
903 ExpectInt32("child._sym_age", 10);
905 // Check that it also sees strings.
906 CompileRun("child.foo = 47");
907 ExpectInt32("child.foo", 47);
908 ExpectInt32("child._str_foo", 47);
910 // Check that the interceptor can punt (in this case, on anonymous symbols).
911 CompileRun("child[anon] = 31337");
912 ExpectInt32("child[anon]", 31337);
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")));
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());
939 int echo_indexed_call_count = 0;
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));
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)));
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);
964 THREADED_TEST(PropertyHandlerInPrototype) {
966 v8::Isolate* isolate = env->GetIsolate();
967 v8::HandleScope scope(isolate);
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));
976 templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
977 CheckThisNamedPropertyHandler, CheckThisNamedPropertySetter,
978 CheckThisNamedPropertyQuery, CheckThisNamedPropertyDeleter,
979 CheckThisNamedPropertyEnumerator));
981 bottom = templ->GetFunction()->NewInstance();
982 Local<v8::Object> top = templ->GetFunction()->NewInstance();
983 Local<v8::Object> middle = templ->GetFunction()->NewInstance();
985 bottom->SetPrototype(middle);
986 middle->SetPrototype(top);
987 env->Global()->Set(v8_str("obj"), bottom);
989 // Indexed and named get.
990 CompileRun("obj[0]");
993 // Indexed and named set.
994 CompileRun("obj[1] = 42");
995 CompileRun("obj.y = 42");
997 // Indexed and named query.
998 CompileRun("0 in obj");
999 CompileRun("'x' in obj");
1001 // Indexed and named deleter.
1002 CompileRun("delete obj[0]");
1003 CompileRun("delete obj.x");
1006 CompileRun("for (var p in obj) ;");
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"));
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));
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());
1044 THREADED_TEST(EmptyInterceptorBreakTransitions) {
1045 v8::HandleScope scope(CcTest::isolate());
1046 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
1047 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
1049 env->Global()->Set(v8_str("Constructor"), templ->GetFunction());
1051 "var o1 = new Constructor;"
1052 "o1.a = 1;" // Ensure a and x share the descriptor array.
1053 "Object.defineProperty(o1, 'x', {value: 10});");
1055 "var o2 = new Constructor;"
1057 "Object.defineProperty(o2, 'x', {value: 10});");
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);
1069 env->Global()->Set(v8_str("Child"), child->GetFunction());
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});"
1078 ExpectBoolean("child.hasOwnProperty('age')", false);
1079 ExpectInt32("child.age", 10);
1080 ExpectInt32("child.accessor_age", 10);
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);
1094 env->Global()->Set(v8_str("Child"), child->GetFunction());
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.
1103 "for (var i = 0; i < 4; ++i) {"
1104 " result = child.age;"
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);
1119 env->Global()->Set(v8_str("Child"), child->GetFunction());
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");
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);
1139 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
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);
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);
1157 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
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);
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);
1178 env->Global()->Set(v8_str("Child"), child->GetFunction());
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);
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);
1199 env->Global()->Set(v8_str("Child"), child->GetFunction());
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);
1211 THREADED_TEST(SwitchFromInterceptorToJSAccessor) {
1212 v8::HandleScope scope(CcTest::isolate());
1213 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
1214 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1216 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
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");
1237 THREADED_TEST(SwitchFromJSAccessorToInterceptor) {
1238 v8::HandleScope scope(CcTest::isolate());
1239 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
1240 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1242 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
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");
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);
1270 env->Global()->Set(v8_str("Child"), child->GetFunction());
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);
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);
1289 env->Global()->Set(v8_str("Child"), child->GetFunction());
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);
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;
1308 THREADED_TEST(HiddenPropertiesWithInterceptors) {
1309 LocalContext context;
1310 v8::Isolate* isolate = context->GetIsolate();
1311 v8::HandleScope scope(isolate);
1313 interceptor_for_hidden_properties_called = false;
1315 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
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);
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);
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")));
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")));
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 };"
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")));
1384 THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
1385 v8::Isolate* isolate = CcTest::isolate();
1386 v8::HandleScope scope(isolate);
1387 v8::Local<Context> context1 = Context::New(isolate);
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);
1396 // Force the object into the slow case.
1398 "interceptor_obj.y = 0;"
1399 "delete interceptor_obj.y;");
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);"
1413 "get_x(interceptor_obj)");
1414 // Check that the interceptor was actually invoked.
1415 CHECK(result->Equals(v8_str("x")));
1418 // Return to the original context and force some object to the slow case
1419 // to cause the NormalizedMapCache to verify.
1421 CompileRun("var obj = { x : 0 }; delete obj.x;");
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));
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);
1456 static void IndexedPropertyGetter(
1457 uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) {
1458 ApiTestFuzzer::Fuzz();
1460 info.GetReturnValue().Set(v8_num(625));
1465 static void IndexedPropertySetter(
1466 uint32_t index, Local<Value> value,
1467 const v8::PropertyCallbackInfo<v8::Value>& info) {
1468 ApiTestFuzzer::Fuzz();
1470 info.GetReturnValue().Set(value);
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;});"
1489 Local<Script> interceptor_setter_script = v8_compile(
1490 "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
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));
1505 static void UnboxedDoubleIndexedPropertyGetter(
1506 uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) {
1507 ApiTestFuzzer::Fuzz();
1509 info.GetReturnValue().Set(v8_num(index));
1514 static void UnboxedDoubleIndexedPropertySetter(
1515 uint32_t index, Local<Value> value,
1516 const v8::PropertyCallbackInfo<v8::Value>& info) {
1517 ApiTestFuzzer::Fuzz();
1519 info.GetReturnValue().Set(v8_num(index));
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));
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; } "
1551 "for (x in obj) {key_count++;};"
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));
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(
1566 " return arguments;"
1568 "keys = f(0, 1, 2, 3);"
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));
1579 static void SloppyIndexedPropertyGetter(
1580 uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) {
1581 ApiTestFuzzer::Fuzz();
1583 info.GetReturnValue().Set(v8_num(index));
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));
1607 static void IdentityIndexedPropertyGetter(
1608 uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) {
1609 info.GetReturnValue().Set(index);
1613 THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
1614 v8::Isolate* isolate = CcTest::isolate();
1615 v8::HandleScope scope(isolate);
1616 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1618 v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
1620 LocalContext context;
1621 context->Global()->Set(v8_str("obj"), templ->NewInstance());
1623 // Check fast object case.
1624 const char* fast_case_code =
1625 "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
1626 ExpectString(fast_case_code, "0");
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");
1636 THREADED_TEST(IndexedInterceptorWithNoSetter) {
1637 v8::Isolate* isolate = CcTest::isolate();
1638 v8::HandleScope scope(isolate);
1639 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1641 v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
1643 LocalContext context;
1644 context->Global()->Set(v8_str("obj"), templ->NewInstance());
1649 " for (var i = 0; i < 100; i++) {"
1651 " if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
1657 ExpectString(code, "PASSED");
1661 THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
1662 v8::Isolate* isolate = CcTest::isolate();
1663 v8::HandleScope scope(isolate);
1664 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1666 v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
1668 LocalContext context;
1669 Local<v8::Object> obj = templ->NewInstance();
1670 obj->TurnOnAccessCheck();
1671 context->Global()->Set(v8_str("obj"), obj);
1674 "var result = 'PASSED';"
1675 "for (var i = 0; i < 100; i++) {"
1678 " result = 'Wrong value ' + v + ' at iteration ' + i;"
1685 ExpectString(code, "PASSED");
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);
1695 v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
1697 LocalContext context;
1698 Local<v8::Object> obj = templ->NewInstance();
1699 context->Global()->Set(v8_str("obj"), obj);
1702 "var result = 'PASSED';"
1703 "for (var i = 0; i < 100; i++) {"
1704 " var expected = i;"
1706 " %EnableAccessChecks(obj);"
1711 " result = 'Should not have reached this!';"
1713 " } else if (v != expected) {"
1714 " result = 'Wrong value ' + v + ' at iteration ' + i;"
1722 " if (i == 5) %DisableAccessChecks(obj);"
1725 ExpectString(code, "PASSED");
1729 THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
1730 v8::Isolate* isolate = CcTest::isolate();
1731 v8::HandleScope scope(isolate);
1732 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1734 v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
1736 LocalContext context;
1737 Local<v8::Object> obj = templ->NewInstance();
1738 context->Global()->Set(v8_str("obj"), obj);
1742 " for (var i = 0; i < 100; i++) {"
1744 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
1750 ExpectString(code, "PASSED");
1754 THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
1755 v8::Isolate* isolate = CcTest::isolate();
1756 v8::HandleScope scope(isolate);
1757 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1759 v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
1761 LocalContext context;
1762 Local<v8::Object> obj = templ->NewInstance();
1763 context->Global()->Set(v8_str("obj"), obj);
1767 " for (var i = 0; i < 100; i++) {"
1768 " var expected = i;"
1772 " expected = undefined;"
1775 " /* probe minimal Smi number on 32-bit platforms */"
1776 " key = -(1 << 30);"
1777 " expected = undefined;"
1780 " /* probe minimal Smi number on 64-bit platforms */"
1782 " expected = undefined;"
1784 " var v = obj[key];"
1785 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
1791 ExpectString(code, "PASSED");
1795 THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
1796 v8::Isolate* isolate = CcTest::isolate();
1797 v8::HandleScope scope(isolate);
1798 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1800 v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
1802 LocalContext context;
1803 Local<v8::Object> obj = templ->NewInstance();
1804 context->Global()->Set(v8_str("obj"), obj);
1808 " for (var i = 0; i < 100; i++) {"
1809 " var expected = i;"
1813 " expected = undefined;"
1815 " var v = obj[key];"
1816 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
1822 ExpectString(code, "PASSED");
1826 THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
1827 v8::Isolate* isolate = CcTest::isolate();
1828 v8::HandleScope scope(isolate);
1829 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1831 v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
1833 LocalContext context;
1834 Local<v8::Object> obj = templ->NewInstance();
1835 context->Global()->Set(v8_str("obj"), obj);
1838 "var original = obj;"
1840 " for (var i = 0; i < 100; i++) {"
1841 " var expected = i;"
1843 " obj = {50: 'foobar'};"
1844 " expected = 'foobar';"
1847 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
1848 " if (i == 50) obj = original;"
1854 ExpectString(code, "PASSED");
1858 THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
1859 v8::Isolate* isolate = CcTest::isolate();
1860 v8::HandleScope scope(isolate);
1861 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1863 v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
1865 LocalContext context;
1866 Local<v8::Object> obj = templ->NewInstance();
1867 context->Global()->Set(v8_str("obj"), obj);
1870 "var original = obj;"
1872 " for (var i = 0; i < 100; i++) {"
1873 " var expected = i;"
1876 " expected = undefined;"
1879 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
1880 " if (i == 5) obj = original;"
1886 ExpectString(code, "PASSED");
1890 THREADED_TEST(IndexedInterceptorOnProto) {
1891 v8::Isolate* isolate = CcTest::isolate();
1892 v8::HandleScope scope(isolate);
1893 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1895 v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
1897 LocalContext context;
1898 Local<v8::Object> obj = templ->NewInstance();
1899 context->Global()->Set(v8_str("obj"), obj);
1902 "var o = {__proto__: obj};"
1904 " for (var i = 0; i < 100; i++) {"
1906 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
1912 ExpectString(code, "PASSED");
1916 static void NoBlockGetterX(Local<Name> name,
1917 const v8::PropertyCallbackInfo<v8::Value>&) {}
1920 static void NoBlockGetterI(uint32_t index,
1921 const v8::PropertyCallbackInfo<v8::Value>&) {}
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
1930 info.GetReturnValue().Set(false); // intercepted, don't delete the property
1934 static void IDeleter(uint32_t index,
1935 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
1937 return; // not intercepted
1940 info.GetReturnValue().Set(false); // intercepted, don't delete the property
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());
1959 CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
1960 CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
1962 CHECK(v8_compile("k.foo")->Run()->Equals(v8_str("foo")));
1963 CHECK(v8_compile("k.bar")->Run()->IsUndefined());
1965 CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
1966 CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
1968 CHECK(v8_compile("k[2]")->Run()->Equals(v8_num(2)));
1969 CHECK(v8_compile("k[4]")->Run()->IsUndefined());
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();
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();
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);
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);
2009 THREADED_TEST(Enumerators) {
2010 v8::Isolate* isolate = CcTest::isolate();
2011 v8::HandleScope scope(isolate);
2012 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
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(
2024 "k[4294967295] = 0;"
2026 "k[4294967296] = 0;"
2030 "k[30000000000] = 0;"
2033 "for (var prop in k) {"
2034 " result.push(prop);"
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))));
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))));
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))));
2072 v8::Handle<Value> call_ic_function;
2073 v8::Handle<Value> call_ic_function2;
2074 v8::Handle<Value> call_ic_function3;
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);
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);
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(
2096 "for (var i = 0; i < 1000; i++) {"
2097 " result = o.x(41);"
2099 CHECK_EQ(42, value->Int32Value());
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; };"
2115 "for (var i = 0; i < 7; i++) {"
2116 " result = o.x(41);"
2118 CHECK_EQ(42, value->Int32Value());
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);
2131 // This test checks that if interceptor provides a function,
2132 // even if we cached shadowed variant, interceptor's function
2134 THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
2135 v8::Isolate* isolate = CcTest::isolate();
2136 v8::HandleScope scope(isolate);
2137 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
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; };"
2146 "for (var i = 0; i < 1000; i++) {"
2147 " result = o.x(42);"
2149 CHECK_EQ(41, value->Int32Value());
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++) {"
2172 "proto1.y = function(x) { return x - 1; };"
2174 "for (var i = 0; i < 7; i++) {"
2175 " result += o.y(42);"
2177 CHECK_EQ(41 * 7, value->Int32Value());
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; };"
2195 "for (var i = 0; i < 1000; i++) {"
2196 " result = o.x(42);"
2198 CHECK_EQ(43, value->Int32Value());
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);
2210 // This test checks that if interceptor provides a function,
2211 // even if we cached constant function, interceptor's function
2213 THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
2214 v8::Isolate* isolate = CcTest::isolate();
2215 v8::HandleScope scope(isolate);
2216 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
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; };"
2227 "for (var i = 0; i < 1000; i++) {"
2228 " result = o.x(42);"
2230 CHECK_EQ(41, value->Int32Value());
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);
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);
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; };"
2260 " for (var i = 0; i < 1000; i++) {"
2261 " result = o.x(42);"
2268 "%OptimizeFunctionOnNextCall(test);"
2270 CHECK_EQ(41, value->Int32Value());
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; };"
2286 "proto1 = new Object();"
2287 "proto2 = new Object();"
2288 "o.__proto__ = proto1;"
2289 "proto1.__proto__ = proto2;"
2291 // Invoke it many times to compile a stub
2292 "for (var i = 0; i < 7; i++) {"
2295 "proto1.y = function(x) { return x - 1; };"
2297 "for (var i = 0; i < 7; i++) {"
2298 " result += o.y(42);"
2300 CHECK_EQ(41 * 7, value->Int32Value());
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; };"
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);"
2323 "this.y = function(x) { return x - 1; };"
2325 "for (var i = 0; i < 7; i++) {"
2326 " result += o.y(42);"
2328 CHECK_EQ(41 * 7, value->Int32Value());
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));
2339 LocalContext context;
2340 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
2342 v8::Handle<Value> value = CompileRun(
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.
2351 " for (var i = 0; i < 10; i++) {"
2352 " result += o.parseFloat('239');"
2358 CHECK_EQ(239 * 10, value->Int32Value());
2362 v8::Handle<Value> keyed_call_ic_function;
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);
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());
2383 "proto = new Object();"
2384 "proto.y = function(x) { return x + 1; };"
2385 "proto.z = function(x) { return x - 1; };"
2386 "o.__proto__ = proto;"
2389 "for (var i = 0; i < 10; i++) {"
2390 " if (i == 5) { method = 'z'; };"
2391 " result += o[method](41);"
2393 CHECK_EQ(42 * 5 + 40 * 5,
2394 context->Global()->Get(v8_str("result"))->Int32Value());
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);
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();
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;"
2420 "for (var i = 0; i < 10; i++) {"
2421 " if (i == 5) { method = 'y'; };"
2422 " result += o[method](41);"
2424 CHECK_EQ(42 * 5 + 40 * 5,
2425 context->Global()->Get(v8_str("result"))->Int32Value());
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());
2439 "function inc(x) { return x + 1; };"
2441 "function dec(x) { return x - 1; };"
2443 "o.__proto__ = this;"
2444 "this.__proto__.x = inc;"
2445 "this.__proto__.y = dec;"
2448 "for (var i = 0; i < 10; i++) {"
2449 " if (i == 5) { method = 'y'; };"
2450 " result += o[method](41);"
2452 CHECK_EQ(42 * 5 + 40 * 5,
2453 context->Global()->Get(v8_str("result"))->Int32Value());
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());
2467 "function len(x) { return x.length; };"
2468 "o.__proto__ = this;"
2469 "var m = 'parseFloat';"
2471 "for (var i = 0; i < 10; i++) {"
2474 " saved_result = result;"
2476 " result = o[m]('239');"
2478 CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
2479 CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
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());
2493 "var o = new Object();"
2494 "o.__proto__ = proto;"
2495 "o.method = function(x) { return x + 1; };"
2498 "for (var i = 0; i < 10; i++) {"
2499 " if (i == 5) { o.method = function(x) { return x - 1; }; };"
2500 " result += o[m](41);"
2502 CHECK_EQ(42 * 5 + 40 * 5,
2503 context->Global()->Get(v8_str("result"))->Int32Value());
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());
2517 "var proto = new Object();"
2518 "o.__proto__ = proto;"
2519 "proto.method = function(x) { return x + 1; };"
2522 "for (var i = 0; i < 10; i++) {"
2523 " if (i == 5) { proto.method = function(x) { return x - 1; }; };"
2524 " result += o[m](41);"
2526 CHECK_EQ(42 * 5 + 40 * 5,
2527 context->Global()->Get(v8_str("result"))->Int32Value());
2531 static int interceptor_call_count = 0;
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);
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);
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(
2555 " for (var i = 0; i < 1000; i++) {"
2556 " try { x; } catch(e) { return true; }"
2561 CHECK_EQ(true, value->BooleanValue());
2562 interceptor_call_count = 0;
2565 " for (var i = 0; i < 1000; i++) {"
2566 " try { x(42); } catch(e) { return true; }"
2571 CHECK_EQ(true, value->BooleanValue());
2575 static int interceptor_ic_exception_get_count = 0;
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);
2583 if (interceptor_ic_exception_get_count == 20) {
2584 info.GetIsolate()->ThrowException(v8_num(42));
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);
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(
2603 " for (var i = 0; i < 100; i++) {"
2604 " try { x; } catch(e) { return true; }"
2609 CHECK_EQ(true, value->BooleanValue());
2610 interceptor_ic_exception_get_count = 0;
2613 " for (var i = 0; i < 100; i++) {"
2614 " try { x(42); } catch(e) { return true; }"
2619 CHECK_EQ(true, value->BooleanValue());
2623 static int interceptor_ic_exception_set_count = 0;
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));
2635 // Test interceptor store IC where the interceptor throws an exception
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);
2643 v8::NamedPropertyHandlerConfiguration(0, InterceptorICExceptionSetter));
2644 LocalContext context(0, templ, v8::Handle<Value>());
2645 v8::Handle<Value> value = CompileRun(
2647 " for (var i = 0; i < 100; i++) {"
2648 " try { x = 42; } catch(e) { return true; }"
2653 CHECK_EQ(true, value->BooleanValue());
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());
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());
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));
2698 env->Global()->Set(v8_str("obj"), templ->GetFunction()->NewInstance());
2699 ExpectTrue("obj.x === 42");
2700 ExpectTrue("!obj.propertyIsEnumerable('x')");
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());
2712 "\"use strict\"; var o = new Bug;"
2713 "function f(o) { o.x = 10; };"
2715 "%OptimizeFunctionOnNextCall(f);"
2717 ExpectBoolean("%GetOptimizationStatus(f) != 2", true);
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);
2727 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2729 "var obj = new Obj;"
2730 // Initialize fields to avoid transitions later.
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 });"
2740 "%OptimizeFunctionOnNextCall(setAge);"
2742 // All stores went through the interceptor.
2743 ExpectInt32("obj.interceptor_age", 4);
2744 ExpectInt32("obj.accessor_age", 42);
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);
2754 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2756 "var obj = new Obj;"
2757 // Initialize fields to avoid transitions later.
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 });"
2766 "%OptimizeFunctionOnNextCall(getAge);");
2767 // Access through interceptor.
2768 ExpectInt32("getAge()", 1);
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);
2778 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2780 "var obj = new Obj;"
2781 "obj.__proto__.interceptor_age = 42;"
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);
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);
2799 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2801 "var obj = new Obj;"
2803 "function setAge(i) { obj.age = i };"
2807 "%OptimizeFunctionOnNextCall(setAge);"
2809 ExpectInt32("obj.age", 100000);
2810 ExpectInt32("obj.interceptor_age", 103);
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();");
2824 THREADED_TEST(Regress125988) {
2825 v8::HandleScope scope(CcTest::isolate());
2826 Handle<FunctionTemplate> intercept = FunctionTemplate::New(CcTest::isolate());
2827 AddInterceptor(intercept, EmptyInterceptorGetter, EmptyInterceptorSetter);
2829 env->Global()->Set(v8_str("Intercept"), intercept->GetFunction());
2831 "var a = new Object();"
2832 "var b = new Intercept();"
2833 "var c = new Object();"
2837 "for (var i = 0; i < 3; i++) c.x;");
2838 ExpectBoolean("c.hasOwnProperty('x')", false);
2839 ExpectInt32("c.x", 23);
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);
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);
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);
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);
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));
2880 LocalContext context;
2881 v8::Handle<v8::Object> global = context->Global();
2882 global->Set(v8_str("object"), obj_template->NewInstance());
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)));
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)));
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)));
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);
2923 template <typename T>
2924 T* GetWrappedObject(Local<Value> data) {
2925 return reinterpret_cast<T*>(
2926 Object::Cast(*data)->GetAlignedPointerFromInternalField(0));
2930 struct AccessCheckData {
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;
2944 struct ShouldInterceptData {
2946 bool should_intercept;
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));
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));
2972 THREADED_TEST(NamedAllCanReadInterceptor) {
2973 auto isolate = CcTest::isolate();
2974 v8::HandleScope handle_scope(isolate);
2975 LocalContext context;
2977 AccessCheckData access_check_data;
2978 access_check_data.result = false;
2979 access_check_data.count = 0;
2981 ShouldInterceptData intercept_data_0;
2982 intercept_data_0.value = 239;
2983 intercept_data_0.should_intercept = true;
2985 ShouldInterceptData intercept_data_1;
2986 intercept_data_1.value = 165;
2987 intercept_data_1.should_intercept = false;
2989 auto intercepted_0 = v8::ObjectTemplate::New(isolate);
2991 v8::NamedPropertyHandlerConfiguration conf(ShouldNamedInterceptor);
2992 conf.flags = v8::PropertyHandlerFlags::kAllCanRead;
2994 BuildWrappedObject<ShouldInterceptData>(isolate, &intercept_data_0);
2995 intercepted_0->SetHandler(conf);
2998 auto intercepted_1 = v8::ObjectTemplate::New(isolate);
3000 v8::NamedPropertyHandlerConfiguration conf(ShouldNamedInterceptor);
3001 conf.flags = v8::PropertyHandlerFlags::kAllCanRead;
3003 BuildWrappedObject<ShouldInterceptData>(isolate, &intercept_data_1);
3004 intercepted_1->SetHandler(conf);
3007 auto checked = v8::ObjectTemplate::New(isolate);
3008 checked->SetAccessCheckCallbacks(
3009 SimpleAccessChecker, nullptr,
3010 BuildWrappedObject<AccessCheckData>(isolate, &access_check_data), false);
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);
3018 "checked.__proto__ = intercepted_1;"
3019 "intercepted_1.__proto__ = intercepted_0;");
3021 checked_instance->TurnOnAccessCheck();
3022 CHECK_EQ(0, access_check_data.count);
3024 access_check_data.result = true;
3025 ExpectInt32("checked.whatever", 17);
3026 CHECK(!CompileRun("Object.getOwnPropertyDescriptor(checked, 'whatever')")
3028 CHECK_EQ(2, access_check_data.count);
3030 access_check_data.result = false;
3031 ExpectInt32("checked.whatever", intercept_data_0.value);
3033 v8::TryCatch try_catch(isolate);
3034 CompileRun("Object.getOwnPropertyDescriptor(checked, 'whatever')");
3035 CHECK(try_catch.HasCaught());
3037 CHECK_EQ(4, access_check_data.count);
3039 intercept_data_1.should_intercept = true;
3040 ExpectInt32("checked.whatever", intercept_data_1.value);
3042 v8::TryCatch try_catch(isolate);
3043 CompileRun("Object.getOwnPropertyDescriptor(checked, 'whatever')");
3044 CHECK(try_catch.HasCaught());
3046 CHECK_EQ(6, access_check_data.count);
3050 THREADED_TEST(IndexedAllCanReadInterceptor) {
3051 auto isolate = CcTest::isolate();
3052 v8::HandleScope handle_scope(isolate);
3053 LocalContext context;
3055 AccessCheckData access_check_data;
3056 access_check_data.result = false;
3057 access_check_data.count = 0;
3059 ShouldInterceptData intercept_data_0;
3060 intercept_data_0.value = 239;
3061 intercept_data_0.should_intercept = true;
3063 ShouldInterceptData intercept_data_1;
3064 intercept_data_1.value = 165;
3065 intercept_data_1.should_intercept = false;
3067 auto intercepted_0 = v8::ObjectTemplate::New(isolate);
3069 v8::IndexedPropertyHandlerConfiguration conf(ShouldIndexedInterceptor);
3070 conf.flags = v8::PropertyHandlerFlags::kAllCanRead;
3072 BuildWrappedObject<ShouldInterceptData>(isolate, &intercept_data_0);
3073 intercepted_0->SetHandler(conf);
3076 auto intercepted_1 = v8::ObjectTemplate::New(isolate);
3078 v8::IndexedPropertyHandlerConfiguration conf(ShouldIndexedInterceptor);
3079 conf.flags = v8::PropertyHandlerFlags::kAllCanRead;
3081 BuildWrappedObject<ShouldInterceptData>(isolate, &intercept_data_1);
3082 intercepted_1->SetHandler(conf);
3085 auto checked = v8::ObjectTemplate::New(isolate);
3086 checked->SetAccessCheckCallbacks(
3087 SimpleAccessChecker, nullptr,
3088 BuildWrappedObject<AccessCheckData>(isolate, &access_check_data), false);
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));
3096 "checked.__proto__ = intercepted_1;"
3097 "intercepted_1.__proto__ = intercepted_0;");
3099 checked_instance->TurnOnAccessCheck();
3100 CHECK_EQ(0, access_check_data.count);
3102 access_check_data.result = true;
3103 ExpectInt32("checked[15]", 17);
3104 CHECK(!CompileRun("Object.getOwnPropertyDescriptor(checked, '15')")
3106 CHECK_EQ(3, access_check_data.count);
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')")
3113 CHECK_EQ(6, access_check_data.count);
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')")
3120 CHECK_EQ(9, access_check_data.count);
3124 THREADED_TEST(NonMaskingInterceptorOwnProperty) {
3125 auto isolate = CcTest::isolate();
3126 v8::HandleScope handle_scope(isolate);
3127 LocalContext context;
3129 ShouldInterceptData intercept_data;
3130 intercept_data.value = 239;
3131 intercept_data.should_intercept = true;
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);
3139 auto interceptor = interceptor_templ->NewInstance();
3140 context->Global()->Set(v8_str("obj"), interceptor);
3142 ExpectInt32("obj.whatever", 239);
3144 CompileRun("obj.whatever = 4;");
3145 ExpectInt32("obj.whatever", 4);
3147 CompileRun("delete obj.whatever;");
3148 ExpectInt32("obj.whatever", 239);
3152 THREADED_TEST(NonMaskingInterceptorPrototypeProperty) {
3153 auto isolate = CcTest::isolate();
3154 v8::HandleScope handle_scope(isolate);
3155 LocalContext context;
3157 ShouldInterceptData intercept_data;
3158 intercept_data.value = 239;
3159 intercept_data.should_intercept = true;
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);
3167 auto interceptor = interceptor_templ->NewInstance();
3168 context->Global()->Set(v8_str("obj"), interceptor);
3170 ExpectInt32("obj.whatever", 239);
3172 CompileRun("obj.__proto__ = {'whatever': 4};");
3173 ExpectInt32("obj.whatever", 4);
3175 CompileRun("delete obj.__proto__.whatever;");
3176 ExpectInt32("obj.whatever", 239);
3180 THREADED_TEST(NonMaskingInterceptorPrototypePropertyIC) {
3181 auto isolate = CcTest::isolate();
3182 v8::HandleScope handle_scope(isolate);
3183 LocalContext context;
3185 ShouldInterceptData intercept_data;
3186 intercept_data.value = 239;
3187 intercept_data.should_intercept = true;
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);
3195 auto interceptor = interceptor_templ->NewInstance();
3196 context->Global()->Set(v8_str("obj"), interceptor);
3200 "outer.__proto__ = obj;"
3203 " for (var i = 0; i < 4; i++) {"
3204 " x = obj.whatever;"
3209 // Receiver == holder.
3210 CompileRun("obj.__proto__ = null;");
3211 ExpectInt32("f(obj)", 239);
3212 ExpectInt32("f(outer)", 239);
3214 // Receiver != holder.
3215 CompileRun("Object.setPrototypeOf(obj, {});");
3216 ExpectInt32("f(obj)", 239);
3217 ExpectInt32("f(outer)", 239);
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);
3225 // Masked value on prototype prototype.
3226 CompileRun("delete obj.__proto__.whatever;");
3227 ExpectInt32("f(obj)", 5);
3228 ExpectInt32("f(outer)", 5);
3231 CompileRun("delete obj.__proto__.__proto__.whatever;");
3232 ExpectInt32("f(obj)", 239);
3233 ExpectInt32("f(outer)", 239);
3235 // Masked value on self.
3236 CompileRun("obj.whatever = 4;");
3237 ExpectInt32("f(obj)", 4);
3238 ExpectInt32("f(outer)", 4);
3241 CompileRun("delete obj.whatever;");
3242 ExpectInt32("f(obj)", 239);
3243 ExpectInt32("f(outer)", 239);
3245 CompileRun("outer.whatever = 4;");
3246 ExpectInt32("f(obj)", 239);
3247 ExpectInt32("f(outer)", 4);
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"))
3261 if (!db->Has(context, name).FromJust()) return;
3262 info.GetReturnValue().Set(db->Get(context, name).ToLocalChecked());
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"))
3275 db->Set(context, name, value).FromJust();
3276 info.GetReturnValue().Set(value);
3281 THREADED_TEST(NonMaskingInterceptorGlobalEvalRegression) {
3282 auto isolate = CcTest::isolate();
3283 v8::HandleScope handle_scope(isolate);
3284 LocalContext context;
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);
3291 context->Global()->Set(v8_str("intercepted_1"),
3292 interceptor_templ->NewInstance());
3293 context->Global()->Set(v8_str("intercepted_2"),
3294 interceptor_templ->NewInstance());
3298 "intercepted_1.db = {};"
3299 "intercepted_2.db = {};");
3302 "var obj = intercepted_1;"
3307 "obj = intercepted_2;"