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/snapshot.h"
19 #include "src/unicode-inl.h"
20 #include "src/utils.h"
21 #include "src/vm-state.h"
24 using ::v8::BooleanObject;
26 using ::v8::Extension;
28 using ::v8::FunctionTemplate;
30 using ::v8::HandleScope;
34 using ::v8::MessageCallback;
36 using ::v8::ObjectTemplate;
37 using ::v8::Persistent;
39 using ::v8::StackTrace;
43 using ::v8::Undefined;
51 void Returns42(const v8::FunctionCallbackInfo<v8::Value>& info) {
52 info.GetReturnValue().Set(42);
55 void Return239Callback(Local<String> name,
56 const v8::PropertyCallbackInfo<Value>& info) {
57 ApiTestFuzzer::Fuzz();
58 CheckReturnValue(info, FUNCTION_ADDR(Return239Callback));
59 info.GetReturnValue().Set(v8_str("bad value"));
60 info.GetReturnValue().Set(v8_num(239));
64 void EmptyInterceptorGetter(Local<Name> name,
65 const v8::PropertyCallbackInfo<v8::Value>& info) {}
68 void EmptyInterceptorSetter(Local<Name> name, Local<Value> value,
69 const v8::PropertyCallbackInfo<v8::Value>& info) {}
72 void SimpleAccessorGetter(Local<String> name,
73 const v8::PropertyCallbackInfo<v8::Value>& info) {
74 Handle<Object> self = Handle<Object>::Cast(info.This());
75 info.GetReturnValue().Set(
76 self->Get(String::Concat(v8_str("accessor_"), name)));
79 void SimpleAccessorSetter(Local<String> name, Local<Value> value,
80 const v8::PropertyCallbackInfo<void>& info) {
81 Handle<Object> self = Handle<Object>::Cast(info.This());
82 self->Set(String::Concat(v8_str("accessor_"), name), value);
86 void SymbolAccessorGetter(Local<Name> name,
87 const v8::PropertyCallbackInfo<v8::Value>& info) {
88 CHECK(name->IsSymbol());
89 Local<Symbol> sym = Local<Symbol>::Cast(name);
90 if (sym->Name()->IsUndefined()) return;
91 SimpleAccessorGetter(Local<String>::Cast(sym->Name()), info);
94 void SymbolAccessorSetter(Local<Name> name, Local<Value> value,
95 const v8::PropertyCallbackInfo<void>& info) {
96 CHECK(name->IsSymbol());
97 Local<Symbol> sym = Local<Symbol>::Cast(name);
98 if (sym->Name()->IsUndefined()) return;
99 SimpleAccessorSetter(Local<String>::Cast(sym->Name()), value, info);
102 void StringInterceptorGetter(
104 const v8::PropertyCallbackInfo<v8::Value>&
105 info) { // Intercept names that start with 'interceptor_'.
106 String::Utf8Value utf8(name);
107 char* name_str = *utf8;
108 char prefix[] = "interceptor_";
110 for (i = 0; name_str[i] && prefix[i]; ++i) {
111 if (name_str[i] != prefix[i]) return;
113 Handle<Object> self = Handle<Object>::Cast(info.This());
114 info.GetReturnValue().Set(self->GetHiddenValue(v8_str(name_str + i)));
118 void StringInterceptorSetter(Local<String> name, Local<Value> value,
119 const v8::PropertyCallbackInfo<v8::Value>& info) {
120 // Intercept accesses that set certain integer values, for which the name does
121 // not start with 'accessor_'.
122 String::Utf8Value utf8(name);
123 char* name_str = *utf8;
124 char prefix[] = "accessor_";
126 for (i = 0; name_str[i] && prefix[i]; ++i) {
127 if (name_str[i] != prefix[i]) break;
129 if (!prefix[i]) return;
131 if (value->IsInt32() && value->Int32Value() < 10000) {
132 Handle<Object> self = Handle<Object>::Cast(info.This());
133 self->SetHiddenValue(name, value);
134 info.GetReturnValue().Set(value);
138 void InterceptorGetter(Local<Name> generic_name,
139 const v8::PropertyCallbackInfo<v8::Value>& info) {
140 if (generic_name->IsSymbol()) return;
141 StringInterceptorGetter(Local<String>::Cast(generic_name), info);
144 void InterceptorSetter(Local<Name> generic_name, Local<Value> value,
145 const v8::PropertyCallbackInfo<v8::Value>& info) {
146 if (generic_name->IsSymbol()) return;
147 StringInterceptorSetter(Local<String>::Cast(generic_name), value, info);
150 void GenericInterceptorGetter(Local<Name> generic_name,
151 const v8::PropertyCallbackInfo<v8::Value>& info) {
153 if (generic_name->IsSymbol()) {
154 Local<Value> name = Local<Symbol>::Cast(generic_name)->Name();
155 if (name->IsUndefined()) return;
156 str = String::Concat(v8_str("_sym_"), Local<String>::Cast(name));
158 Local<String> name = Local<String>::Cast(generic_name);
159 String::Utf8Value utf8(name);
160 char* name_str = *utf8;
161 if (*name_str == '_') return;
162 str = String::Concat(v8_str("_str_"), name);
165 Handle<Object> self = Handle<Object>::Cast(info.This());
166 info.GetReturnValue().Set(self->Get(str));
169 void GenericInterceptorSetter(Local<Name> generic_name, Local<Value> value,
170 const v8::PropertyCallbackInfo<v8::Value>& info) {
172 if (generic_name->IsSymbol()) {
173 Local<Value> name = Local<Symbol>::Cast(generic_name)->Name();
174 if (name->IsUndefined()) return;
175 str = String::Concat(v8_str("_sym_"), Local<String>::Cast(name));
177 Local<String> name = Local<String>::Cast(generic_name);
178 String::Utf8Value utf8(name);
179 char* name_str = *utf8;
180 if (*name_str == '_') return;
181 str = String::Concat(v8_str("_str_"), name);
184 Handle<Object> self = Handle<Object>::Cast(info.This());
185 self->Set(str, value);
186 info.GetReturnValue().Set(value);
189 void AddAccessor(Handle<FunctionTemplate> templ, Handle<String> name,
190 v8::AccessorGetterCallback getter,
191 v8::AccessorSetterCallback setter) {
192 templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
195 void AddInterceptor(Handle<FunctionTemplate> templ,
196 v8::NamedPropertyGetterCallback getter,
197 v8::NamedPropertySetterCallback setter) {
198 templ->InstanceTemplate()->SetNamedPropertyHandler(getter, setter);
202 void AddAccessor(Handle<FunctionTemplate> templ, Handle<Name> name,
203 v8::AccessorNameGetterCallback getter,
204 v8::AccessorNameSetterCallback setter) {
205 templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
208 void AddInterceptor(Handle<FunctionTemplate> templ,
209 v8::GenericNamedPropertyGetterCallback getter,
210 v8::GenericNamedPropertySetterCallback setter) {
211 templ->InstanceTemplate()->SetHandler(
212 v8::NamedPropertyHandlerConfiguration(getter, setter));
216 v8::Handle<v8::Object> bottom;
218 void CheckThisIndexedPropertyHandler(
219 uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) {
220 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyHandler));
221 ApiTestFuzzer::Fuzz();
222 CHECK(info.This()->Equals(bottom));
225 void CheckThisNamedPropertyHandler(
226 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
227 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyHandler));
228 ApiTestFuzzer::Fuzz();
229 CHECK(info.This()->Equals(bottom));
232 void CheckThisIndexedPropertySetter(
233 uint32_t index, Local<Value> value,
234 const v8::PropertyCallbackInfo<v8::Value>& info) {
235 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertySetter));
236 ApiTestFuzzer::Fuzz();
237 CHECK(info.This()->Equals(bottom));
241 void CheckThisNamedPropertySetter(
242 Local<Name> property, Local<Value> value,
243 const v8::PropertyCallbackInfo<v8::Value>& info) {
244 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertySetter));
245 ApiTestFuzzer::Fuzz();
246 CHECK(info.This()->Equals(bottom));
249 void CheckThisIndexedPropertyQuery(
250 uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info) {
251 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyQuery));
252 ApiTestFuzzer::Fuzz();
253 CHECK(info.This()->Equals(bottom));
257 void CheckThisNamedPropertyQuery(
258 Local<Name> property, const v8::PropertyCallbackInfo<v8::Integer>& info) {
259 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyQuery));
260 ApiTestFuzzer::Fuzz();
261 CHECK(info.This()->Equals(bottom));
265 void CheckThisIndexedPropertyDeleter(
266 uint32_t index, const v8::PropertyCallbackInfo<v8::Boolean>& info) {
267 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyDeleter));
268 ApiTestFuzzer::Fuzz();
269 CHECK(info.This()->Equals(bottom));
273 void CheckThisNamedPropertyDeleter(
274 Local<Name> property, const v8::PropertyCallbackInfo<v8::Boolean>& info) {
275 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyDeleter));
276 ApiTestFuzzer::Fuzz();
277 CHECK(info.This()->Equals(bottom));
281 void CheckThisIndexedPropertyEnumerator(
282 const v8::PropertyCallbackInfo<v8::Array>& info) {
283 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyEnumerator));
284 ApiTestFuzzer::Fuzz();
285 CHECK(info.This()->Equals(bottom));
289 void CheckThisNamedPropertyEnumerator(
290 const v8::PropertyCallbackInfo<v8::Array>& info) {
291 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyEnumerator));
292 ApiTestFuzzer::Fuzz();
293 CHECK(info.This()->Equals(bottom));
297 int echo_named_call_count;
300 void EchoNamedProperty(Local<Name> name,
301 const v8::PropertyCallbackInfo<v8::Value>& info) {
302 ApiTestFuzzer::Fuzz();
303 CHECK(v8_str("data")->Equals(info.Data()));
304 echo_named_call_count++;
305 info.GetReturnValue().Set(name);
308 void InterceptorHasOwnPropertyGetter(
309 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
310 ApiTestFuzzer::Fuzz();
313 void InterceptorHasOwnPropertyGetterGC(
314 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
315 ApiTestFuzzer::Fuzz();
316 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
322 THREADED_TEST(InterceptorHasOwnProperty) {
323 LocalContext context;
324 v8::Isolate* isolate = context->GetIsolate();
325 v8::HandleScope scope(isolate);
326 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
327 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
328 instance_templ->SetHandler(
329 v8::NamedPropertyHandlerConfiguration(InterceptorHasOwnPropertyGetter));
330 Local<Function> function = fun_templ->GetFunction();
331 context->Global()->Set(v8_str("constructor"), function);
332 v8::Handle<Value> value = CompileRun(
333 "var o = new constructor();"
334 "o.hasOwnProperty('ostehaps');");
335 CHECK_EQ(false, value->BooleanValue());
338 "o.hasOwnProperty('ostehaps');");
339 CHECK_EQ(true, value->BooleanValue());
341 "var p = new constructor();"
342 "p.hasOwnProperty('ostehaps');");
343 CHECK_EQ(false, value->BooleanValue());
347 THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
348 LocalContext context;
349 v8::Isolate* isolate = context->GetIsolate();
350 v8::HandleScope scope(isolate);
351 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
352 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
353 instance_templ->SetHandler(
354 v8::NamedPropertyHandlerConfiguration(InterceptorHasOwnPropertyGetterGC));
355 Local<Function> function = fun_templ->GetFunction();
356 context->Global()->Set(v8_str("constructor"), function);
357 // Let's first make some stuff so we can be sure to get a good GC.
359 "function makestr(size) {"
361 " case 1: return 'f';"
362 " case 2: return 'fo';"
363 " case 3: return 'foo';"
365 " return makestr(size >> 1) + makestr((size + 1) >> 1);"
367 "var x = makestr(12345);"
368 "x = makestr(31415);"
369 "x = makestr(23456);");
370 v8::Handle<Value> value = CompileRun(
371 "var o = new constructor();"
372 "o.__proto__ = new String(x);"
373 "o.hasOwnProperty('ostehaps');");
374 CHECK_EQ(false, value->BooleanValue());
378 static void CheckInterceptorLoadIC(
379 v8::GenericNamedPropertyGetterCallback getter, const char* source,
381 v8::Isolate* isolate = CcTest::isolate();
382 v8::HandleScope scope(isolate);
383 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
384 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(getter, 0, 0, 0, 0,
386 LocalContext context;
387 context->Global()->Set(v8_str("o"), templ->NewInstance());
388 v8::Handle<Value> value = CompileRun(source);
389 CHECK_EQ(expected, value->Int32Value());
393 static void InterceptorLoadICGetter(
394 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
395 ApiTestFuzzer::Fuzz();
396 v8::Isolate* isolate = CcTest::isolate();
397 CHECK_EQ(isolate, info.GetIsolate());
398 CHECK(v8_str("data")->Equals(info.Data()));
399 CHECK(v8_str("x")->Equals(name));
400 info.GetReturnValue().Set(v8::Integer::New(isolate, 42));
404 // This test should hit the load IC for the interceptor case.
405 THREADED_TEST(InterceptorLoadIC) {
406 CheckInterceptorLoadIC(InterceptorLoadICGetter,
408 "for (var i = 0; i < 1000; i++) {"
415 // Below go several tests which verify that JITing for various
416 // configurations of interceptor and explicit fields works fine
417 // (those cases are special cased to get better performance).
419 static void InterceptorLoadXICGetter(
420 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
421 ApiTestFuzzer::Fuzz();
422 info.GetReturnValue().Set(
423 v8_str("x")->Equals(name)
424 ? v8::Handle<v8::Value>(v8::Integer::New(info.GetIsolate(), 42))
425 : v8::Handle<v8::Value>());
429 THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
430 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
433 "for (var i = 0; i < 1000; i++) {"
440 THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
441 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
443 "o.__proto__ = { 'y': 239 };"
444 "for (var i = 0; i < 1000; i++) {"
445 " result = o.y + o.x;"
451 THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
452 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
454 "o.__proto__.y = 239;"
455 "for (var i = 0; i < 1000; i++) {"
456 " result = o.y + o.x;"
462 THREADED_TEST(InterceptorLoadICUndefined) {
463 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
465 "for (var i = 0; i < 1000; i++) {"
466 " result = (o.y == undefined) ? 239 : 42;"
472 THREADED_TEST(InterceptorLoadICWithOverride) {
473 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
474 "fst = new Object(); fst.__proto__ = o;"
475 "snd = new Object(); snd.__proto__ = fst;"
477 "for (var i = 0; i < 1000; i++) {"
482 "for (var i = 0; i < 1000; i++) {"
490 // Test the case when we stored field into
491 // a stub, but interceptor produced value on its own.
492 THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
493 CheckInterceptorLoadIC(
494 InterceptorLoadXICGetter,
495 "proto = new Object();"
496 "o.__proto__ = proto;"
498 "for (var i = 0; i < 1000; i++) {"
500 // Now it should be ICed and keep a reference to x defined on proto
503 "for (var i = 0; i < 1000; i++) {"
511 // Test the case when we stored field into
512 // a stub, but it got invalidated later on.
513 THREADED_TEST(InterceptorLoadICInvalidatedField) {
514 CheckInterceptorLoadIC(
515 InterceptorLoadXICGetter,
516 "proto1 = new Object();"
517 "proto2 = new Object();"
518 "o.__proto__ = proto1;"
519 "proto1.__proto__ = proto2;"
521 "for (var i = 0; i < 1000; i++) {"
523 // Now it should be ICed and keep a reference to y defined on proto2
527 "for (var i = 0; i < 1000; i++) {"
535 static int interceptor_load_not_handled_calls = 0;
536 static void InterceptorLoadNotHandled(
537 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
538 ++interceptor_load_not_handled_calls;
542 // Test how post-interceptor lookups are done in the non-cacheable
543 // case: the interceptor should not be invoked during this lookup.
544 THREADED_TEST(InterceptorLoadICPostInterceptor) {
545 interceptor_load_not_handled_calls = 0;
546 CheckInterceptorLoadIC(InterceptorLoadNotHandled,
547 "receiver = new Object();"
548 "receiver.__proto__ = o;"
549 "proto = new Object();"
550 "/* Make proto a slow-case object. */"
551 "for (var i = 0; i < 1000; i++) {"
552 " proto[\"xxxxxxxx\" + i] = [];"
555 "o.__proto__ = proto;"
557 "for (var i = 0; i < 1000; i++) {"
558 " result += receiver.x;"
562 CHECK_EQ(1000, interceptor_load_not_handled_calls);
566 // Test the case when we stored field into
567 // a stub, but it got invalidated later on due to override on
568 // global object which is between interceptor and fields' holders.
569 THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
570 CheckInterceptorLoadIC(
571 InterceptorLoadXICGetter,
572 "o.__proto__ = this;" // set a global to be a proto of o.
573 "this.__proto__.y = 239;"
574 "for (var i = 0; i < 10; i++) {"
575 " if (o.y != 239) throw 'oops: ' + o.y;"
576 // Now it should be ICed and keep a reference to y defined on
579 "this.y = 42;" // Assign on a global.
581 "for (var i = 0; i < 10; i++) {"
589 static void SetOnThis(Local<String> name, Local<Value> value,
590 const v8::PropertyCallbackInfo<void>& info) {
591 Local<Object>::Cast(info.This())->ForceSet(name, value);
595 THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
596 v8::Isolate* isolate = CcTest::isolate();
597 v8::HandleScope scope(isolate);
598 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
600 v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
601 templ->SetAccessor(v8_str("y"), Return239Callback);
602 LocalContext context;
603 context->Global()->Set(v8_str("o"), templ->NewInstance());
605 // Check the case when receiver and interceptor's holder
606 // are the same objects.
607 v8::Handle<Value> value = CompileRun(
609 "for (var i = 0; i < 7; i++) {"
612 CHECK_EQ(239, value->Int32Value());
614 // Check the case when interceptor's holder is in proto chain
617 "r = { __proto__: o };"
619 "for (var i = 0; i < 7; i++) {"
622 CHECK_EQ(239, value->Int32Value());
626 THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
627 v8::Isolate* isolate = CcTest::isolate();
628 v8::HandleScope scope(isolate);
629 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
631 v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
632 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
633 templ_p->SetAccessor(v8_str("y"), Return239Callback);
635 LocalContext context;
636 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
637 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
639 // Check the case when receiver and interceptor's holder
640 // are the same objects.
641 v8::Handle<Value> value = CompileRun(
644 "for (var i = 0; i < 7; i++) {"
645 " result = o.x + o.y;"
647 CHECK_EQ(239 + 42, value->Int32Value());
649 // Check the case when interceptor's holder is in proto chain
652 "r = { __proto__: o };"
654 "for (var i = 0; i < 7; i++) {"
655 " result = r.x + r.y;"
657 CHECK_EQ(239 + 42, value->Int32Value());
661 THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
662 v8::Isolate* isolate = CcTest::isolate();
663 v8::HandleScope scope(isolate);
664 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
666 v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
667 templ->SetAccessor(v8_str("y"), Return239Callback);
669 LocalContext context;
670 context->Global()->Set(v8_str("o"), templ->NewInstance());
672 v8::Handle<Value> value = CompileRun(
673 "fst = new Object(); fst.__proto__ = o;"
674 "snd = new Object(); snd.__proto__ = fst;"
676 "for (var i = 0; i < 7; i++) {"
681 "for (var i = 0; i < 7; i++) {"
685 CHECK_EQ(239 + 42, value->Int32Value());
689 // Test the case when we stored callback into
690 // a stub, but interceptor produced value on its own.
691 THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
692 v8::Isolate* isolate = CcTest::isolate();
693 v8::HandleScope scope(isolate);
694 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
696 v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
697 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
698 templ_p->SetAccessor(v8_str("y"), Return239Callback);
700 LocalContext context;
701 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
702 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
704 v8::Handle<Value> value = CompileRun(
706 "for (var i = 0; i < 7; i++) {"
708 // Now it should be ICed and keep a reference to x defined on p
711 "for (var i = 0; i < 7; i++) {"
715 CHECK_EQ(42 * 7, value->Int32Value());
719 // Test the case when we stored callback into
720 // a stub, but it got invalidated later on.
721 THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
722 v8::Isolate* isolate = CcTest::isolate();
723 v8::HandleScope scope(isolate);
724 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
726 v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
727 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
728 templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
730 LocalContext context;
731 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
732 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
734 v8::Handle<Value> value = CompileRun(
735 "inbetween = new Object();"
736 "o.__proto__ = inbetween;"
737 "inbetween.__proto__ = p;"
738 "for (var i = 0; i < 10; i++) {"
740 // Now it should be ICed and keep a reference to y defined on p
744 "for (var i = 0; i < 10; i++) {"
748 CHECK_EQ(42 * 10, value->Int32Value());
752 // Test the case when we stored callback into
753 // a stub, but it got invalidated later on due to override on
754 // global object which is between interceptor and callbacks' holders.
755 THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
756 v8::Isolate* isolate = CcTest::isolate();
757 v8::HandleScope scope(isolate);
758 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
760 v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
761 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
762 templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
764 LocalContext context;
765 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
766 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
768 v8::Handle<Value> value = CompileRun(
769 "o.__proto__ = this;"
770 "this.__proto__ = p;"
771 "for (var i = 0; i < 10; i++) {"
772 " if (o.y != 239) throw 'oops: ' + o.y;"
773 // Now it should be ICed and keep a reference to y defined on p
777 "for (var i = 0; i < 10; i++) {"
781 CHECK_EQ(42 * 10, value->Int32Value());
785 static void InterceptorLoadICGetter0(
786 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
787 ApiTestFuzzer::Fuzz();
788 CHECK(v8_str("x")->Equals(name));
789 info.GetReturnValue().Set(v8::Integer::New(info.GetIsolate(), 0));
793 THREADED_TEST(InterceptorReturningZero) {
794 CheckInterceptorLoadIC(InterceptorLoadICGetter0, "o.x == undefined ? 1 : 0",
799 static void InterceptorStoreICSetter(
800 Local<Name> key, Local<Value> value,
801 const v8::PropertyCallbackInfo<v8::Value>& info) {
802 CHECK(v8_str("x")->Equals(key));
803 CHECK_EQ(42, value->Int32Value());
804 info.GetReturnValue().Set(value);
808 // This test should hit the store IC for the interceptor case.
809 THREADED_TEST(InterceptorStoreIC) {
810 v8::Isolate* isolate = CcTest::isolate();
811 v8::HandleScope scope(isolate);
812 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
813 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
814 InterceptorLoadICGetter, InterceptorStoreICSetter, 0, 0, 0,
816 LocalContext context;
817 context->Global()->Set(v8_str("o"), templ->NewInstance());
819 "for (var i = 0; i < 1000; i++) {"
825 THREADED_TEST(InterceptorStoreICWithNoSetter) {
826 v8::Isolate* isolate = CcTest::isolate();
827 v8::HandleScope scope(isolate);
828 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
830 v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
831 LocalContext context;
832 context->Global()->Set(v8_str("o"), templ->NewInstance());
833 v8::Handle<Value> value = CompileRun(
834 "for (var i = 0; i < 1000; i++) {"
838 CHECK_EQ(239 + 42, value->Int32Value());
842 THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
843 v8::HandleScope scope(CcTest::isolate());
844 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
845 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
846 child->Inherit(parent);
847 AddAccessor(parent, v8_str("age"), SimpleAccessorGetter,
848 SimpleAccessorSetter);
849 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
851 env->Global()->Set(v8_str("Child"), child->GetFunction());
853 "var child = new Child;"
855 ExpectBoolean("child.hasOwnProperty('age')", false);
856 ExpectInt32("child.age", 10);
857 ExpectInt32("child.accessor_age", 10);
861 THREADED_TEST(LegacyInterceptorDoesNotSeeSymbols) {
863 v8::Isolate* isolate = CcTest::isolate();
864 v8::HandleScope scope(isolate);
865 Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
866 Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
867 v8::Local<v8::Symbol> age = v8::Symbol::New(isolate, v8_str("age"));
869 child->Inherit(parent);
870 AddAccessor(parent, age, SymbolAccessorGetter, SymbolAccessorSetter);
871 AddInterceptor(child, StringInterceptorGetter, StringInterceptorSetter);
873 env->Global()->Set(v8_str("Child"), child->GetFunction());
874 env->Global()->Set(v8_str("age"), age);
876 "var child = new Child;"
878 ExpectInt32("child[age]", 10);
879 ExpectBoolean("child.hasOwnProperty('age')", false);
880 ExpectBoolean("child.hasOwnProperty('accessor_age')", true);
884 THREADED_TEST(GenericInterceptorDoesSeeSymbols) {
886 v8::Isolate* isolate = CcTest::isolate();
887 v8::HandleScope scope(isolate);
888 Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
889 Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
890 v8::Local<v8::Symbol> age = v8::Symbol::New(isolate, v8_str("age"));
891 v8::Local<v8::Symbol> anon = v8::Symbol::New(isolate);
893 child->Inherit(parent);
894 AddAccessor(parent, age, SymbolAccessorGetter, SymbolAccessorSetter);
895 AddInterceptor(child, GenericInterceptorGetter, GenericInterceptorSetter);
897 env->Global()->Set(v8_str("Child"), child->GetFunction());
898 env->Global()->Set(v8_str("age"), age);
899 env->Global()->Set(v8_str("anon"), anon);
901 "var child = new Child;"
903 ExpectInt32("child[age]", 10);
904 ExpectInt32("child._sym_age", 10);
906 // Check that it also sees strings.
907 CompileRun("child.foo = 47");
908 ExpectInt32("child.foo", 47);
909 ExpectInt32("child._str_foo", 47);
911 // Check that the interceptor can punt (in this case, on anonymous symbols).
912 CompileRun("child[anon] = 31337");
913 ExpectInt32("child[anon]", 31337);
917 THREADED_TEST(NamedPropertyHandlerGetter) {
918 echo_named_call_count = 0;
919 v8::HandleScope scope(CcTest::isolate());
920 v8::Handle<v8::FunctionTemplate> templ =
921 v8::FunctionTemplate::New(CcTest::isolate());
922 templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
923 EchoNamedProperty, 0, 0, 0, 0, v8_str("data")));
925 env->Global()->Set(v8_str("obj"), templ->GetFunction()->NewInstance());
926 CHECK_EQ(echo_named_call_count, 0);
927 v8_compile("obj.x")->Run();
928 CHECK_EQ(echo_named_call_count, 1);
929 const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
930 v8::Handle<Value> str = CompileRun(code);
931 String::Utf8Value value(str);
932 CHECK_EQ(0, strcmp(*value, "oddlepoddle"));
933 // Check default behavior
934 CHECK_EQ(10, v8_compile("obj.flob = 10;")->Run()->Int32Value());
935 CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
936 CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
940 int echo_indexed_call_count = 0;
943 static void EchoIndexedProperty(
944 uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) {
945 ApiTestFuzzer::Fuzz();
946 CHECK(v8_num(637)->Equals(info.Data()));
947 echo_indexed_call_count++;
948 info.GetReturnValue().Set(v8_num(index));
952 THREADED_TEST(IndexedPropertyHandlerGetter) {
953 v8::Isolate* isolate = CcTest::isolate();
954 v8::HandleScope scope(isolate);
955 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
956 templ->InstanceTemplate()->SetHandler(v8::IndexedPropertyHandlerConfiguration(
957 EchoIndexedProperty, 0, 0, 0, 0, v8_num(637)));
959 env->Global()->Set(v8_str("obj"), templ->GetFunction()->NewInstance());
960 Local<Script> script = v8_compile("obj[900]");
961 CHECK_EQ(script->Run()->Int32Value(), 900);
965 THREADED_TEST(PropertyHandlerInPrototype) {
967 v8::Isolate* isolate = env->GetIsolate();
968 v8::HandleScope scope(isolate);
970 // Set up a prototype chain with three interceptors.
971 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
972 templ->InstanceTemplate()->SetHandler(v8::IndexedPropertyHandlerConfiguration(
973 CheckThisIndexedPropertyHandler, CheckThisIndexedPropertySetter,
974 CheckThisIndexedPropertyQuery, CheckThisIndexedPropertyDeleter,
975 CheckThisIndexedPropertyEnumerator));
977 templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
978 CheckThisNamedPropertyHandler, CheckThisNamedPropertySetter,
979 CheckThisNamedPropertyQuery, CheckThisNamedPropertyDeleter,
980 CheckThisNamedPropertyEnumerator));
982 bottom = templ->GetFunction()->NewInstance();
983 Local<v8::Object> top = templ->GetFunction()->NewInstance();
984 Local<v8::Object> middle = templ->GetFunction()->NewInstance();
986 bottom->SetPrototype(middle);
987 middle->SetPrototype(top);
988 env->Global()->Set(v8_str("obj"), bottom);
990 // Indexed and named get.
991 CompileRun("obj[0]");
994 // Indexed and named set.
995 CompileRun("obj[1] = 42");
996 CompileRun("obj.y = 42");
998 // Indexed and named query.
999 CompileRun("0 in obj");
1000 CompileRun("'x' in obj");
1002 // Indexed and named deleter.
1003 CompileRun("delete obj[0]");
1004 CompileRun("delete obj.x");
1007 CompileRun("for (var p in obj) ;");
1011 static void PrePropertyHandlerGet(
1012 Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>& info) {
1013 ApiTestFuzzer::Fuzz();
1014 if (v8_str("pre")->Equals(key)) {
1015 info.GetReturnValue().Set(v8_str("PrePropertyHandler: pre"));
1020 static void PrePropertyHandlerQuery(
1021 Local<Name> key, const v8::PropertyCallbackInfo<v8::Integer>& info) {
1022 if (v8_str("pre")->Equals(key)) {
1023 info.GetReturnValue().Set(static_cast<int32_t>(v8::None));
1028 THREADED_TEST(PrePropertyHandler) {
1029 v8::Isolate* isolate = CcTest::isolate();
1030 v8::HandleScope scope(isolate);
1031 v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
1032 desc->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
1033 PrePropertyHandlerGet, 0, PrePropertyHandlerQuery));
1034 LocalContext env(NULL, desc->InstanceTemplate());
1035 CompileRun("var pre = 'Object: pre'; var on = 'Object: on';");
1036 v8::Handle<Value> result_pre = CompileRun("pre");
1037 CHECK(v8_str("PrePropertyHandler: pre")->Equals(result_pre));
1038 v8::Handle<Value> result_on = CompileRun("on");
1039 CHECK(v8_str("Object: on")->Equals(result_on));
1040 v8::Handle<Value> result_post = CompileRun("post");
1041 CHECK(result_post.IsEmpty());
1045 THREADED_TEST(EmptyInterceptorBreakTransitions) {
1046 v8::HandleScope scope(CcTest::isolate());
1047 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
1048 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
1050 env->Global()->Set(v8_str("Constructor"), templ->GetFunction());
1052 "var o1 = new Constructor;"
1053 "o1.a = 1;" // Ensure a and x share the descriptor array.
1054 "Object.defineProperty(o1, 'x', {value: 10});");
1056 "var o2 = new Constructor;"
1058 "Object.defineProperty(o2, 'x', {value: 10});");
1062 THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) {
1063 v8::Isolate* isolate = CcTest::isolate();
1064 v8::HandleScope scope(isolate);
1065 Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
1066 Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
1067 child->Inherit(parent);
1068 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1070 env->Global()->Set(v8_str("Child"), child->GetFunction());
1072 "var child = new Child;"
1073 "var parent = child.__proto__;"
1074 "Object.defineProperty(parent, 'age', "
1075 " {get: function(){ return this.accessor_age; }, "
1076 " set: function(v){ this.accessor_age = v; }, "
1077 " enumerable: true, configurable: true});"
1079 ExpectBoolean("child.hasOwnProperty('age')", false);
1080 ExpectInt32("child.age", 10);
1081 ExpectInt32("child.accessor_age", 10);
1085 THREADED_TEST(EmptyInterceptorDoesNotShadowApiAccessors) {
1086 v8::Isolate* isolate = CcTest::isolate();
1087 v8::HandleScope scope(isolate);
1088 Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
1089 auto returns_42 = FunctionTemplate::New(isolate, Returns42);
1090 parent->PrototypeTemplate()->SetAccessorProperty(v8_str("age"), returns_42);
1091 Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
1092 child->Inherit(parent);
1093 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1095 env->Global()->Set(v8_str("Child"), child->GetFunction());
1097 "var child = new Child;"
1098 "var parent = child.__proto__;");
1099 ExpectBoolean("child.hasOwnProperty('age')", false);
1100 ExpectInt32("child.age", 42);
1101 // Check interceptor followup.
1104 "for (var i = 0; i < 4; ++i) {"
1105 " result = child.age;"
1112 THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) {
1113 v8::Isolate* isolate = CcTest::isolate();
1114 v8::HandleScope scope(isolate);
1115 Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
1116 Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
1117 child->Inherit(parent);
1118 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1120 env->Global()->Set(v8_str("Child"), child->GetFunction());
1122 "var child = new Child;"
1123 "var parent = child.__proto__;"
1124 "parent.name = 'Alice';");
1125 ExpectBoolean("child.hasOwnProperty('name')", false);
1126 ExpectString("child.name", "Alice");
1127 CompileRun("child.name = 'Bob';");
1128 ExpectString("child.name", "Bob");
1129 ExpectBoolean("child.hasOwnProperty('name')", true);
1130 ExpectString("parent.name", "Alice");
1134 THREADED_TEST(SwitchFromInterceptorToAccessor) {
1135 v8::HandleScope scope(CcTest::isolate());
1136 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
1137 AddAccessor(templ, v8_str("age"), SimpleAccessorGetter, SimpleAccessorSetter);
1138 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1140 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
1142 "var obj = new Obj;"
1143 "function setAge(i){ obj.age = i; };"
1144 "for(var i = 0; i <= 10000; i++) setAge(i);");
1145 // All i < 10000 go to the interceptor.
1146 ExpectInt32("obj.interceptor_age", 9999);
1147 // The last i goes to the accessor.
1148 ExpectInt32("obj.accessor_age", 10000);
1152 THREADED_TEST(SwitchFromAccessorToInterceptor) {
1153 v8::HandleScope scope(CcTest::isolate());
1154 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
1155 AddAccessor(templ, v8_str("age"), SimpleAccessorGetter, SimpleAccessorSetter);
1156 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1158 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
1160 "var obj = new Obj;"
1161 "function setAge(i){ obj.age = i; };"
1162 "for(var i = 20000; i >= 9999; i--) setAge(i);");
1163 // All i >= 10000 go to the accessor.
1164 ExpectInt32("obj.accessor_age", 10000);
1165 // The last i goes to the interceptor.
1166 ExpectInt32("obj.interceptor_age", 9999);
1170 THREADED_TEST(SwitchFromInterceptorToAccessorWithInheritance) {
1171 v8::HandleScope scope(CcTest::isolate());
1172 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
1173 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
1174 child->Inherit(parent);
1175 AddAccessor(parent, v8_str("age"), SimpleAccessorGetter,
1176 SimpleAccessorSetter);
1177 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1179 env->Global()->Set(v8_str("Child"), child->GetFunction());
1181 "var child = new Child;"
1182 "function setAge(i){ child.age = i; };"
1183 "for(var i = 0; i <= 10000; i++) setAge(i);");
1184 // All i < 10000 go to the interceptor.
1185 ExpectInt32("child.interceptor_age", 9999);
1186 // The last i goes to the accessor.
1187 ExpectInt32("child.accessor_age", 10000);
1191 THREADED_TEST(SwitchFromAccessorToInterceptorWithInheritance) {
1192 v8::HandleScope scope(CcTest::isolate());
1193 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
1194 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
1195 child->Inherit(parent);
1196 AddAccessor(parent, v8_str("age"), SimpleAccessorGetter,
1197 SimpleAccessorSetter);
1198 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1200 env->Global()->Set(v8_str("Child"), child->GetFunction());
1202 "var child = new Child;"
1203 "function setAge(i){ child.age = i; };"
1204 "for(var i = 20000; i >= 9999; i--) setAge(i);");
1205 // All i >= 10000 go to the accessor.
1206 ExpectInt32("child.accessor_age", 10000);
1207 // The last i goes to the interceptor.
1208 ExpectInt32("child.interceptor_age", 9999);
1212 THREADED_TEST(SwitchFromInterceptorToJSAccessor) {
1213 v8::HandleScope scope(CcTest::isolate());
1214 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
1215 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1217 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
1219 "var obj = new Obj;"
1220 "function setter(i) { this.accessor_age = i; };"
1221 "function getter() { return this.accessor_age; };"
1222 "function setAge(i) { obj.age = i; };"
1223 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
1224 "for(var i = 0; i <= 10000; i++) setAge(i);");
1225 // All i < 10000 go to the interceptor.
1226 ExpectInt32("obj.interceptor_age", 9999);
1227 // The last i goes to the JavaScript accessor.
1228 ExpectInt32("obj.accessor_age", 10000);
1229 // The installed JavaScript getter is still intact.
1230 // This last part is a regression test for issue 1651 and relies on the fact
1231 // that both interceptor and accessor are being installed on the same object.
1232 ExpectInt32("obj.age", 10000);
1233 ExpectBoolean("obj.hasOwnProperty('age')", true);
1234 ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
1238 THREADED_TEST(SwitchFromJSAccessorToInterceptor) {
1239 v8::HandleScope scope(CcTest::isolate());
1240 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
1241 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1243 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
1245 "var obj = new Obj;"
1246 "function setter(i) { this.accessor_age = i; };"
1247 "function getter() { return this.accessor_age; };"
1248 "function setAge(i) { obj.age = i; };"
1249 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
1250 "for(var i = 20000; i >= 9999; i--) setAge(i);");
1251 // All i >= 10000 go to the accessor.
1252 ExpectInt32("obj.accessor_age", 10000);
1253 // The last i goes to the interceptor.
1254 ExpectInt32("obj.interceptor_age", 9999);
1255 // The installed JavaScript getter is still intact.
1256 // This last part is a regression test for issue 1651 and relies on the fact
1257 // that both interceptor and accessor are being installed on the same object.
1258 ExpectInt32("obj.age", 10000);
1259 ExpectBoolean("obj.hasOwnProperty('age')", true);
1260 ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
1264 THREADED_TEST(SwitchFromInterceptorToProperty) {
1265 v8::HandleScope scope(CcTest::isolate());
1266 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
1267 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
1268 child->Inherit(parent);
1269 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1271 env->Global()->Set(v8_str("Child"), child->GetFunction());
1273 "var child = new Child;"
1274 "function setAge(i){ child.age = i; };"
1275 "for(var i = 0; i <= 10000; i++) setAge(i);");
1276 // All i < 10000 go to the interceptor.
1277 ExpectInt32("child.interceptor_age", 9999);
1278 // The last i goes to child's own property.
1279 ExpectInt32("child.age", 10000);
1283 THREADED_TEST(SwitchFromPropertyToInterceptor) {
1284 v8::HandleScope scope(CcTest::isolate());
1285 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
1286 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
1287 child->Inherit(parent);
1288 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1290 env->Global()->Set(v8_str("Child"), child->GetFunction());
1292 "var child = new Child;"
1293 "function setAge(i){ child.age = i; };"
1294 "for(var i = 20000; i >= 9999; i--) setAge(i);");
1295 // All i >= 10000 go to child's own property.
1296 ExpectInt32("child.age", 10000);
1297 // The last i goes to the interceptor.
1298 ExpectInt32("child.interceptor_age", 9999);
1302 static bool interceptor_for_hidden_properties_called;
1303 static void InterceptorForHiddenProperties(
1304 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
1305 interceptor_for_hidden_properties_called = true;
1309 THREADED_TEST(HiddenPropertiesWithInterceptors) {
1310 LocalContext context;
1311 v8::Isolate* isolate = context->GetIsolate();
1312 v8::HandleScope scope(isolate);
1314 interceptor_for_hidden_properties_called = false;
1316 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1318 // Associate an interceptor with an object and start setting hidden values.
1319 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
1320 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
1321 instance_templ->SetHandler(
1322 v8::NamedPropertyHandlerConfiguration(InterceptorForHiddenProperties));
1323 Local<v8::Function> function = fun_templ->GetFunction();
1324 Local<v8::Object> obj = function->NewInstance();
1325 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2302)));
1326 CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
1327 CHECK(!interceptor_for_hidden_properties_called);
1331 static void XPropertyGetter(Local<Name> property,
1332 const v8::PropertyCallbackInfo<v8::Value>& info) {
1333 ApiTestFuzzer::Fuzz();
1334 CHECK(info.Data()->IsUndefined());
1335 info.GetReturnValue().Set(property);
1339 THREADED_TEST(NamedInterceptorPropertyRead) {
1340 v8::Isolate* isolate = CcTest::isolate();
1341 v8::HandleScope scope(isolate);
1342 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1343 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(XPropertyGetter));
1344 LocalContext context;
1345 context->Global()->Set(v8_str("obj"), templ->NewInstance());
1346 Local<Script> script = v8_compile("obj.x");
1347 for (int i = 0; i < 10; i++) {
1348 Local<Value> result = script->Run();
1349 CHECK(result->Equals(v8_str("x")));
1354 THREADED_TEST(NamedInterceptorDictionaryIC) {
1355 v8::Isolate* isolate = CcTest::isolate();
1356 v8::HandleScope scope(isolate);
1357 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1358 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(XPropertyGetter));
1359 LocalContext context;
1360 // Create an object with a named interceptor.
1361 context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
1362 Local<Script> script = v8_compile("interceptor_obj.x");
1363 for (int i = 0; i < 10; i++) {
1364 Local<Value> result = script->Run();
1365 CHECK(result->Equals(v8_str("x")));
1367 // Create a slow case object and a function accessing a property in
1368 // that slow case object (with dictionary probing in generated
1369 // code). Then force object with a named interceptor into slow-case,
1370 // pass it to the function, and check that the interceptor is called
1371 // instead of accessing the local property.
1372 Local<Value> result = CompileRun(
1373 "function get_x(o) { return o.x; };"
1374 "var obj = { x : 42, y : 0 };"
1376 "for (var i = 0; i < 10; i++) get_x(obj);"
1377 "interceptor_obj.x = 42;"
1378 "interceptor_obj.y = 10;"
1379 "delete interceptor_obj.y;"
1380 "get_x(interceptor_obj)");
1381 CHECK(result->Equals(v8_str("x")));
1385 THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
1386 v8::Isolate* isolate = CcTest::isolate();
1387 v8::HandleScope scope(isolate);
1388 v8::Local<Context> context1 = Context::New(isolate);
1391 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1392 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(XPropertyGetter));
1393 // Create an object with a named interceptor.
1394 v8::Local<v8::Object> object = templ->NewInstance();
1395 context1->Global()->Set(v8_str("interceptor_obj"), object);
1397 // Force the object into the slow case.
1399 "interceptor_obj.y = 0;"
1400 "delete interceptor_obj.y;");
1404 // Introduce the object into a different context.
1405 // Repeat named loads to exercise ICs.
1406 LocalContext context2;
1407 context2->Global()->Set(v8_str("interceptor_obj"), object);
1408 Local<Value> result = CompileRun(
1409 "function get_x(o) { return o.x; }"
1410 "interceptor_obj.x = 42;"
1411 "for (var i=0; i != 10; i++) {"
1412 " get_x(interceptor_obj);"
1414 "get_x(interceptor_obj)");
1415 // Check that the interceptor was actually invoked.
1416 CHECK(result->Equals(v8_str("x")));
1419 // Return to the original context and force some object to the slow case
1420 // to cause the NormalizedMapCache to verify.
1422 CompileRun("var obj = { x : 0 }; delete obj.x;");
1427 static void SetXOnPrototypeGetter(
1428 Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {
1429 // Set x on the prototype object and do not handle the get request.
1430 v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
1431 proto.As<v8::Object>()->Set(v8_str("x"),
1432 v8::Integer::New(info.GetIsolate(), 23));
1436 // This is a regression test for http://crbug.com/20104. Map
1437 // transitions should not interfere with post interceptor lookup.
1438 THREADED_TEST(NamedInterceptorMapTransitionRead) {
1439 v8::Isolate* isolate = CcTest::isolate();
1440 v8::HandleScope scope(isolate);
1441 Local<v8::FunctionTemplate> function_template =
1442 v8::FunctionTemplate::New(isolate);
1443 Local<v8::ObjectTemplate> instance_template =
1444 function_template->InstanceTemplate();
1445 instance_template->SetHandler(
1446 v8::NamedPropertyHandlerConfiguration(SetXOnPrototypeGetter));
1447 LocalContext context;
1448 context->Global()->Set(v8_str("F"), function_template->GetFunction());
1449 // Create an instance of F and introduce a map transition for x.
1450 CompileRun("var o = new F(); o.x = 23;");
1451 // Create an instance of F and invoke the getter. The result should be 23.
1452 Local<Value> result = CompileRun("o = new F(); o.x");
1453 CHECK_EQ(result->Int32Value(), 23);
1457 static void IndexedPropertyGetter(
1458 uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) {
1459 ApiTestFuzzer::Fuzz();
1461 info.GetReturnValue().Set(v8_num(625));
1466 static void IndexedPropertySetter(
1467 uint32_t index, Local<Value> value,
1468 const v8::PropertyCallbackInfo<v8::Value>& info) {
1469 ApiTestFuzzer::Fuzz();
1471 info.GetReturnValue().Set(value);
1476 THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
1477 v8::Isolate* isolate = CcTest::isolate();
1478 v8::HandleScope scope(isolate);
1479 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1480 templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
1481 IndexedPropertyGetter, IndexedPropertySetter));
1482 LocalContext context;
1483 context->Global()->Set(v8_str("obj"), templ->NewInstance());
1484 Local<Script> getter_script =
1485 v8_compile("obj.__defineGetter__(\"3\", function(){return 5;});obj[3];");
1486 Local<Script> setter_script = v8_compile(
1487 "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
1490 Local<Script> interceptor_setter_script = v8_compile(
1491 "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
1493 "obj.foo;"); // This setter should not run, due to the interceptor.
1494 Local<Script> interceptor_getter_script = v8_compile("obj[37];");
1495 Local<Value> result = getter_script->Run();
1496 CHECK(v8_num(5)->Equals(result));
1497 result = setter_script->Run();
1498 CHECK(v8_num(23)->Equals(result));
1499 result = interceptor_setter_script->Run();
1500 CHECK(v8_num(23)->Equals(result));
1501 result = interceptor_getter_script->Run();
1502 CHECK(v8_num(625)->Equals(result));
1506 static void UnboxedDoubleIndexedPropertyGetter(
1507 uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) {
1508 ApiTestFuzzer::Fuzz();
1510 info.GetReturnValue().Set(v8_num(index));
1515 static void UnboxedDoubleIndexedPropertySetter(
1516 uint32_t index, Local<Value> value,
1517 const v8::PropertyCallbackInfo<v8::Value>& info) {
1518 ApiTestFuzzer::Fuzz();
1520 info.GetReturnValue().Set(v8_num(index));
1525 void UnboxedDoubleIndexedPropertyEnumerator(
1526 const v8::PropertyCallbackInfo<v8::Array>& info) {
1527 // Force the list of returned keys to be stored in a FastDoubleArray.
1528 Local<Script> indexed_property_names_script = v8_compile(
1529 "keys = new Array(); keys[125000] = 1;"
1530 "for(i = 0; i < 80000; i++) { keys[i] = i; };"
1531 "keys.length = 25; keys;");
1532 Local<Value> result = indexed_property_names_script->Run();
1533 info.GetReturnValue().Set(Local<v8::Array>::Cast(result));
1537 // Make sure that the the interceptor code in the runtime properly handles
1538 // merging property name lists for double-array-backed arrays.
1539 THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
1540 v8::Isolate* isolate = CcTest::isolate();
1541 v8::HandleScope scope(isolate);
1542 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1543 templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
1544 UnboxedDoubleIndexedPropertyGetter, UnboxedDoubleIndexedPropertySetter, 0,
1545 0, UnboxedDoubleIndexedPropertyEnumerator));
1546 LocalContext context;
1547 context->Global()->Set(v8_str("obj"), templ->NewInstance());
1548 // When obj is created, force it to be Stored in a FastDoubleArray.
1549 Local<Script> create_unboxed_double_script = v8_compile(
1550 "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
1552 "for (x in obj) {key_count++;};"
1554 Local<Value> result = create_unboxed_double_script->Run();
1555 CHECK(result->ToObject(isolate)->HasRealIndexedProperty(2000));
1556 Local<Script> key_count_check = v8_compile("key_count;");
1557 result = key_count_check->Run();
1558 CHECK(v8_num(40013)->Equals(result));
1562 void SloppyArgsIndexedPropertyEnumerator(
1563 const v8::PropertyCallbackInfo<v8::Array>& info) {
1564 // Force the list of returned keys to be stored in a Arguments object.
1565 Local<Script> indexed_property_names_script = v8_compile(
1567 " return arguments;"
1569 "keys = f(0, 1, 2, 3);"
1571 Local<Object> result =
1572 Local<Object>::Cast(indexed_property_names_script->Run());
1573 // Have to populate the handle manually, as it's not Cast-able.
1574 i::Handle<i::JSObject> o = v8::Utils::OpenHandle<Object, i::JSObject>(result);
1575 i::Handle<i::JSArray> array(reinterpret_cast<i::JSArray*>(*o));
1576 info.GetReturnValue().Set(v8::Utils::ToLocal(array));
1580 static void SloppyIndexedPropertyGetter(
1581 uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) {
1582 ApiTestFuzzer::Fuzz();
1584 info.GetReturnValue().Set(v8_num(index));
1589 // Make sure that the the interceptor code in the runtime properly handles
1590 // merging property name lists for non-string arguments arrays.
1591 THREADED_TEST(IndexedInterceptorSloppyArgsWithIndexedAccessor) {
1592 v8::Isolate* isolate = CcTest::isolate();
1593 v8::HandleScope scope(isolate);
1594 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1595 templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
1596 SloppyIndexedPropertyGetter, 0, 0, 0,
1597 SloppyArgsIndexedPropertyEnumerator));
1598 LocalContext context;
1599 context->Global()->Set(v8_str("obj"), templ->NewInstance());
1600 Local<Script> create_args_script = v8_compile(
1601 "var key_count = 0;"
1602 "for (x in obj) {key_count++;} key_count;");
1603 Local<Value> result = create_args_script->Run();
1604 CHECK(v8_num(4)->Equals(result));
1608 static void IdentityIndexedPropertyGetter(
1609 uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) {
1610 info.GetReturnValue().Set(index);
1614 THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
1615 v8::Isolate* isolate = CcTest::isolate();
1616 v8::HandleScope scope(isolate);
1617 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1619 v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
1621 LocalContext context;
1622 context->Global()->Set(v8_str("obj"), templ->NewInstance());
1624 // Check fast object case.
1625 const char* fast_case_code =
1626 "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
1627 ExpectString(fast_case_code, "0");
1630 const char* slow_case_code =
1631 "obj.x = 1; delete obj.x;"
1632 "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
1633 ExpectString(slow_case_code, "1");
1637 THREADED_TEST(IndexedInterceptorWithNoSetter) {
1638 v8::Isolate* isolate = CcTest::isolate();
1639 v8::HandleScope scope(isolate);
1640 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1642 v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
1644 LocalContext context;
1645 context->Global()->Set(v8_str("obj"), templ->NewInstance());
1650 " for (var i = 0; i < 100; i++) {"
1652 " if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
1658 ExpectString(code, "PASSED");
1662 THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
1663 v8::Isolate* isolate = CcTest::isolate();
1664 v8::HandleScope scope(isolate);
1665 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1667 v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
1669 LocalContext context;
1670 Local<v8::Object> obj = templ->NewInstance();
1671 obj->TurnOnAccessCheck();
1672 context->Global()->Set(v8_str("obj"), obj);
1675 "var result = 'PASSED';"
1676 "for (var i = 0; i < 100; i++) {"
1679 " result = 'Wrong value ' + v + ' at iteration ' + i;"
1686 ExpectString(code, "PASSED");
1690 THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
1691 i::FLAG_allow_natives_syntax = true;
1692 v8::Isolate* isolate = CcTest::isolate();
1693 v8::HandleScope scope(isolate);
1694 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1696 v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
1698 LocalContext context;
1699 Local<v8::Object> obj = templ->NewInstance();
1700 context->Global()->Set(v8_str("obj"), obj);
1703 "var result = 'PASSED';"
1704 "for (var i = 0; i < 100; i++) {"
1705 " var expected = i;"
1707 " %EnableAccessChecks(obj);"
1712 " result = 'Should not have reached this!';"
1714 " } else if (v != expected) {"
1715 " result = 'Wrong value ' + v + ' at iteration ' + i;"
1723 " if (i == 5) %DisableAccessChecks(obj);"
1726 ExpectString(code, "PASSED");
1730 THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
1731 v8::Isolate* isolate = CcTest::isolate();
1732 v8::HandleScope scope(isolate);
1733 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1735 v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
1737 LocalContext context;
1738 Local<v8::Object> obj = templ->NewInstance();
1739 context->Global()->Set(v8_str("obj"), obj);
1743 " for (var i = 0; i < 100; i++) {"
1745 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
1751 ExpectString(code, "PASSED");
1755 THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
1756 v8::Isolate* isolate = CcTest::isolate();
1757 v8::HandleScope scope(isolate);
1758 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1760 v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
1762 LocalContext context;
1763 Local<v8::Object> obj = templ->NewInstance();
1764 context->Global()->Set(v8_str("obj"), obj);
1768 " for (var i = 0; i < 100; i++) {"
1769 " var expected = i;"
1773 " expected = undefined;"
1776 " /* probe minimal Smi number on 32-bit platforms */"
1777 " key = -(1 << 30);"
1778 " expected = undefined;"
1781 " /* probe minimal Smi number on 64-bit platforms */"
1783 " expected = undefined;"
1785 " var v = obj[key];"
1786 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
1792 ExpectString(code, "PASSED");
1796 THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
1797 v8::Isolate* isolate = CcTest::isolate();
1798 v8::HandleScope scope(isolate);
1799 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1801 v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
1803 LocalContext context;
1804 Local<v8::Object> obj = templ->NewInstance();
1805 context->Global()->Set(v8_str("obj"), obj);
1809 " for (var i = 0; i < 100; i++) {"
1810 " var expected = i;"
1814 " expected = undefined;"
1816 " var v = obj[key];"
1817 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
1823 ExpectString(code, "PASSED");
1827 THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
1828 v8::Isolate* isolate = CcTest::isolate();
1829 v8::HandleScope scope(isolate);
1830 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1832 v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
1834 LocalContext context;
1835 Local<v8::Object> obj = templ->NewInstance();
1836 context->Global()->Set(v8_str("obj"), obj);
1839 "var original = obj;"
1841 " for (var i = 0; i < 100; i++) {"
1842 " var expected = i;"
1844 " obj = {50: 'foobar'};"
1845 " expected = 'foobar';"
1848 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
1849 " if (i == 50) obj = original;"
1855 ExpectString(code, "PASSED");
1859 THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
1860 v8::Isolate* isolate = CcTest::isolate();
1861 v8::HandleScope scope(isolate);
1862 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1864 v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
1866 LocalContext context;
1867 Local<v8::Object> obj = templ->NewInstance();
1868 context->Global()->Set(v8_str("obj"), obj);
1871 "var original = obj;"
1873 " for (var i = 0; i < 100; i++) {"
1874 " var expected = i;"
1877 " expected = undefined;"
1880 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
1881 " if (i == 5) obj = original;"
1887 ExpectString(code, "PASSED");
1891 THREADED_TEST(IndexedInterceptorOnProto) {
1892 v8::Isolate* isolate = CcTest::isolate();
1893 v8::HandleScope scope(isolate);
1894 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
1896 v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
1898 LocalContext context;
1899 Local<v8::Object> obj = templ->NewInstance();
1900 context->Global()->Set(v8_str("obj"), obj);
1903 "var o = {__proto__: obj};"
1905 " for (var i = 0; i < 100; i++) {"
1907 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
1913 ExpectString(code, "PASSED");
1917 static void NoBlockGetterX(Local<Name> name,
1918 const v8::PropertyCallbackInfo<v8::Value>&) {}
1921 static void NoBlockGetterI(uint32_t index,
1922 const v8::PropertyCallbackInfo<v8::Value>&) {}
1925 static void PDeleter(Local<Name> name,
1926 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
1927 if (!name->Equals(v8_str("foo"))) {
1928 return; // not intercepted
1931 info.GetReturnValue().Set(false); // intercepted, don't delete the property
1935 static void IDeleter(uint32_t index,
1936 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
1938 return; // not intercepted
1941 info.GetReturnValue().Set(false); // intercepted, don't delete the property
1945 THREADED_TEST(Deleter) {
1946 v8::Isolate* isolate = CcTest::isolate();
1947 v8::HandleScope scope(isolate);
1948 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
1949 obj->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX, NULL,
1950 NULL, PDeleter, NULL));
1951 obj->SetHandler(v8::IndexedPropertyHandlerConfiguration(
1952 NoBlockGetterI, NULL, NULL, IDeleter, NULL));
1953 LocalContext context;
1954 context->Global()->Set(v8_str("k"), obj->NewInstance());
1960 CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
1961 CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
1963 CHECK(v8_compile("k.foo")->Run()->Equals(v8_str("foo")));
1964 CHECK(v8_compile("k.bar")->Run()->IsUndefined());
1966 CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
1967 CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
1969 CHECK(v8_compile("k[2]")->Run()->Equals(v8_num(2)));
1970 CHECK(v8_compile("k[4]")->Run()->IsUndefined());
1974 static void GetK(Local<Name> name,
1975 const v8::PropertyCallbackInfo<v8::Value>& info) {
1976 ApiTestFuzzer::Fuzz();
1977 if (name->Equals(v8_str("foo")) || name->Equals(v8_str("bar")) ||
1978 name->Equals(v8_str("baz"))) {
1979 info.GetReturnValue().SetUndefined();
1984 static void IndexedGetK(uint32_t index,
1985 const v8::PropertyCallbackInfo<v8::Value>& info) {
1986 ApiTestFuzzer::Fuzz();
1987 if (index == 0 || index == 1) info.GetReturnValue().SetUndefined();
1991 static void NamedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
1992 ApiTestFuzzer::Fuzz();
1993 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 3);
1994 result->Set(v8::Integer::New(info.GetIsolate(), 0), v8_str("foo"));
1995 result->Set(v8::Integer::New(info.GetIsolate(), 1), v8_str("bar"));
1996 result->Set(v8::Integer::New(info.GetIsolate(), 2), v8_str("baz"));
1997 info.GetReturnValue().Set(result);
2001 static void IndexedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
2002 ApiTestFuzzer::Fuzz();
2003 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
2004 result->Set(v8::Integer::New(info.GetIsolate(), 0), v8_str("0"));
2005 result->Set(v8::Integer::New(info.GetIsolate(), 1), v8_str("1"));
2006 info.GetReturnValue().Set(result);
2010 THREADED_TEST(Enumerators) {
2011 v8::Isolate* isolate = CcTest::isolate();
2012 v8::HandleScope scope(isolate);
2013 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
2015 v8::NamedPropertyHandlerConfiguration(GetK, NULL, NULL, NULL, NamedEnum));
2016 obj->SetHandler(v8::IndexedPropertyHandlerConfiguration(
2017 IndexedGetK, NULL, NULL, NULL, IndexedEnum));
2018 LocalContext context;
2019 context->Global()->Set(v8_str("k"), obj->NewInstance());
2020 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
2025 "k[4294967295] = 0;"
2027 "k[4294967296] = 0;"
2031 "k[30000000000] = 0;"
2034 "for (var prop in k) {"
2035 " result.push(prop);"
2038 // Check that we get all the property names returned including the
2039 // ones from the enumerators in the right order: indexed properties
2040 // in numerical order, indexed interceptor properties, named
2041 // properties in insertion order, named interceptor properties.
2042 // This order is not mandated by the spec, so this test is just
2043 // documenting our behavior.
2044 CHECK_EQ(17u, result->Length());
2045 // Indexed properties in numerical order.
2046 CHECK(v8_str("5")->Equals(result->Get(v8::Integer::New(isolate, 0))));
2047 CHECK(v8_str("10")->Equals(result->Get(v8::Integer::New(isolate, 1))));
2048 CHECK(v8_str("140000")->Equals(result->Get(v8::Integer::New(isolate, 2))));
2050 v8_str("4294967295")->Equals(result->Get(v8::Integer::New(isolate, 3))));
2051 // Indexed interceptor properties in the order they are returned
2052 // from the enumerator interceptor.
2053 CHECK(v8_str("0")->Equals(result->Get(v8::Integer::New(isolate, 4))));
2054 CHECK(v8_str("1")->Equals(result->Get(v8::Integer::New(isolate, 5))));
2055 // Named properties in insertion order.
2056 CHECK(v8_str("a")->Equals(result->Get(v8::Integer::New(isolate, 6))));
2057 CHECK(v8_str("b")->Equals(result->Get(v8::Integer::New(isolate, 7))));
2058 CHECK(v8_str("c")->Equals(result->Get(v8::Integer::New(isolate, 8))));
2060 v8_str("4294967296")->Equals(result->Get(v8::Integer::New(isolate, 9))));
2061 CHECK(v8_str("d")->Equals(result->Get(v8::Integer::New(isolate, 10))));
2062 CHECK(v8_str("e")->Equals(result->Get(v8::Integer::New(isolate, 11))));
2063 CHECK(v8_str("30000000000")
2064 ->Equals(result->Get(v8::Integer::New(isolate, 12))));
2065 CHECK(v8_str("f")->Equals(result->Get(v8::Integer::New(isolate, 13))));
2066 // Named interceptor properties.
2067 CHECK(v8_str("foo")->Equals(result->Get(v8::Integer::New(isolate, 14))));
2068 CHECK(v8_str("bar")->Equals(result->Get(v8::Integer::New(isolate, 15))));
2069 CHECK(v8_str("baz")->Equals(result->Get(v8::Integer::New(isolate, 16))));
2073 v8::Handle<Value> call_ic_function;
2074 v8::Handle<Value> call_ic_function2;
2075 v8::Handle<Value> call_ic_function3;
2077 static void InterceptorCallICGetter(
2078 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2079 ApiTestFuzzer::Fuzz();
2080 CHECK(v8_str("x")->Equals(name));
2081 info.GetReturnValue().Set(call_ic_function);
2085 // This test should hit the call IC for the interceptor case.
2086 THREADED_TEST(InterceptorCallIC) {
2087 v8::Isolate* isolate = CcTest::isolate();
2088 v8::HandleScope scope(isolate);
2089 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2091 v8::NamedPropertyHandlerConfiguration(InterceptorCallICGetter));
2092 LocalContext context;
2093 context->Global()->Set(v8_str("o"), templ->NewInstance());
2094 call_ic_function = v8_compile("function f(x) { return x + 1; }; f")->Run();
2095 v8::Handle<Value> value = CompileRun(
2097 "for (var i = 0; i < 1000; i++) {"
2098 " result = o.x(41);"
2100 CHECK_EQ(42, value->Int32Value());
2104 // This test checks that if interceptor doesn't provide
2105 // a value, we can fetch regular value.
2106 THREADED_TEST(InterceptorCallICSeesOthers) {
2107 v8::Isolate* isolate = CcTest::isolate();
2108 v8::HandleScope scope(isolate);
2109 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2110 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
2111 LocalContext context;
2112 context->Global()->Set(v8_str("o"), templ->NewInstance());
2113 v8::Handle<Value> value = CompileRun(
2114 "o.x = function f(x) { return x + 1; };"
2116 "for (var i = 0; i < 7; i++) {"
2117 " result = o.x(41);"
2119 CHECK_EQ(42, value->Int32Value());
2123 static v8::Handle<Value> call_ic_function4;
2124 static void InterceptorCallICGetter4(
2125 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2126 ApiTestFuzzer::Fuzz();
2127 CHECK(v8_str("x")->Equals(name));
2128 info.GetReturnValue().Set(call_ic_function4);
2132 // This test checks that if interceptor provides a function,
2133 // even if we cached shadowed variant, interceptor's function
2135 THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
2136 v8::Isolate* isolate = CcTest::isolate();
2137 v8::HandleScope scope(isolate);
2138 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2140 v8::NamedPropertyHandlerConfiguration(InterceptorCallICGetter4));
2141 LocalContext context;
2142 context->Global()->Set(v8_str("o"), templ->NewInstance());
2143 call_ic_function4 = v8_compile("function f(x) { return x - 1; }; f")->Run();
2144 v8::Handle<Value> value = CompileRun(
2145 "Object.getPrototypeOf(o).x = function(x) { return x + 1; };"
2147 "for (var i = 0; i < 1000; i++) {"
2148 " result = o.x(42);"
2150 CHECK_EQ(41, value->Int32Value());
2154 // Test the case when we stored cacheable lookup into
2155 // a stub, but it got invalidated later on
2156 THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
2157 v8::Isolate* isolate = CcTest::isolate();
2158 v8::HandleScope scope(isolate);
2159 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2160 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
2161 LocalContext context;
2162 context->Global()->Set(v8_str("o"), templ->NewInstance());
2163 v8::Handle<Value> value = CompileRun(
2164 "proto1 = new Object();"
2165 "proto2 = new Object();"
2166 "o.__proto__ = proto1;"
2167 "proto1.__proto__ = proto2;"
2168 "proto2.y = function(x) { return x + 1; };"
2169 // Invoke it many times to compile a stub
2170 "for (var i = 0; i < 7; i++) {"
2173 "proto1.y = function(x) { return x - 1; };"
2175 "for (var i = 0; i < 7; i++) {"
2176 " result += o.y(42);"
2178 CHECK_EQ(41 * 7, value->Int32Value());
2182 // This test checks that if interceptor doesn't provide a function,
2183 // cached constant function is used
2184 THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
2185 v8::Isolate* isolate = CcTest::isolate();
2186 v8::HandleScope scope(isolate);
2187 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2188 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
2189 LocalContext context;
2190 context->Global()->Set(v8_str("o"), templ->NewInstance());
2191 v8::Handle<Value> value = CompileRun(
2192 "function inc(x) { return x + 1; };"
2196 "for (var i = 0; i < 1000; i++) {"
2197 " result = o.x(42);"
2199 CHECK_EQ(43, value->Int32Value());
2203 static v8::Handle<Value> call_ic_function5;
2204 static void InterceptorCallICGetter5(
2205 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2206 ApiTestFuzzer::Fuzz();
2207 if (v8_str("x")->Equals(name)) info.GetReturnValue().Set(call_ic_function5);
2211 // This test checks that if interceptor provides a function,
2212 // even if we cached constant function, interceptor's function
2214 THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
2215 v8::Isolate* isolate = CcTest::isolate();
2216 v8::HandleScope scope(isolate);
2217 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2219 v8::NamedPropertyHandlerConfiguration(InterceptorCallICGetter5));
2220 LocalContext context;
2221 context->Global()->Set(v8_str("o"), templ->NewInstance());
2222 call_ic_function5 = v8_compile("function f(x) { return x - 1; }; f")->Run();
2223 v8::Handle<Value> value = CompileRun(
2224 "function inc(x) { return x + 1; };"
2228 "for (var i = 0; i < 1000; i++) {"
2229 " result = o.x(42);"
2231 CHECK_EQ(41, value->Int32Value());
2235 static v8::Handle<Value> call_ic_function6;
2236 static void InterceptorCallICGetter6(
2237 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2238 ApiTestFuzzer::Fuzz();
2239 if (v8_str("x")->Equals(name)) info.GetReturnValue().Set(call_ic_function6);
2243 // Same test as above, except the code is wrapped in a function
2244 // to test the optimized compiler.
2245 THREADED_TEST(InterceptorCallICConstantFunctionNotNeededWrapped) {
2246 i::FLAG_allow_natives_syntax = true;
2247 v8::Isolate* isolate = CcTest::isolate();
2248 v8::HandleScope scope(isolate);
2249 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2251 v8::NamedPropertyHandlerConfiguration(InterceptorCallICGetter6));
2252 LocalContext context;
2253 context->Global()->Set(v8_str("o"), templ->NewInstance());
2254 call_ic_function6 = v8_compile("function f(x) { return x - 1; }; f")->Run();
2255 v8::Handle<Value> value = CompileRun(
2256 "function inc(x) { return x + 1; };"
2261 " for (var i = 0; i < 1000; i++) {"
2262 " result = o.x(42);"
2269 "%OptimizeFunctionOnNextCall(test);"
2271 CHECK_EQ(41, value->Int32Value());
2275 // Test the case when we stored constant function into
2276 // a stub, but it got invalidated later on
2277 THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
2278 v8::Isolate* isolate = CcTest::isolate();
2279 v8::HandleScope scope(isolate);
2280 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2281 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
2282 LocalContext context;
2283 context->Global()->Set(v8_str("o"), templ->NewInstance());
2284 v8::Handle<Value> value = CompileRun(
2285 "function inc(x) { return x + 1; };"
2287 "proto1 = new Object();"
2288 "proto2 = new Object();"
2289 "o.__proto__ = proto1;"
2290 "proto1.__proto__ = proto2;"
2292 // Invoke it many times to compile a stub
2293 "for (var i = 0; i < 7; i++) {"
2296 "proto1.y = function(x) { return x - 1; };"
2298 "for (var i = 0; i < 7; i++) {"
2299 " result += o.y(42);"
2301 CHECK_EQ(41 * 7, value->Int32Value());
2305 // Test the case when we stored constant function into
2306 // a stub, but it got invalidated later on due to override on
2307 // global object which is between interceptor and constant function' holders.
2308 THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
2309 v8::Isolate* isolate = CcTest::isolate();
2310 v8::HandleScope scope(isolate);
2311 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2312 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
2313 LocalContext context;
2314 context->Global()->Set(v8_str("o"), templ->NewInstance());
2315 v8::Handle<Value> value = CompileRun(
2316 "function inc(x) { return x + 1; };"
2318 "o.__proto__ = this;"
2319 "this.__proto__.y = inc;"
2320 // Invoke it many times to compile a stub
2321 "for (var i = 0; i < 7; i++) {"
2322 " if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
2324 "this.y = function(x) { return x - 1; };"
2326 "for (var i = 0; i < 7; i++) {"
2327 " result += o.y(42);"
2329 CHECK_EQ(41 * 7, value->Int32Value());
2333 // Test the case when actual function to call sits on global object.
2334 THREADED_TEST(InterceptorCallICCachedFromGlobal) {
2335 v8::Isolate* isolate = CcTest::isolate();
2336 v8::HandleScope scope(isolate);
2337 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
2338 templ_o->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
2340 LocalContext context;
2341 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
2343 v8::Handle<Value> value = CompileRun(
2345 " o.__proto__ = this;"
2346 " for (var i = 0; i < 10; i++) {"
2347 " var v = o.parseFloat('239');"
2348 " if (v != 239) throw v;"
2349 // Now it should be ICed and keep a reference to parseFloat.
2352 " for (var i = 0; i < 10; i++) {"
2353 " result += o.parseFloat('239');"
2359 CHECK_EQ(239 * 10, value->Int32Value());
2363 v8::Handle<Value> keyed_call_ic_function;
2365 static void InterceptorKeyedCallICGetter(
2366 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2367 ApiTestFuzzer::Fuzz();
2368 if (v8_str("x")->Equals(name)) {
2369 info.GetReturnValue().Set(keyed_call_ic_function);
2374 // Test the case when we stored cacheable lookup into
2375 // a stub, but the function name changed (to another cacheable function).
2376 THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
2377 v8::Isolate* isolate = CcTest::isolate();
2378 v8::HandleScope scope(isolate);
2379 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2380 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
2381 LocalContext context;
2382 context->Global()->Set(v8_str("o"), templ->NewInstance());
2384 "proto = new Object();"
2385 "proto.y = function(x) { return x + 1; };"
2386 "proto.z = function(x) { return x - 1; };"
2387 "o.__proto__ = proto;"
2390 "for (var i = 0; i < 10; i++) {"
2391 " if (i == 5) { method = 'z'; };"
2392 " result += o[method](41);"
2394 CHECK_EQ(42 * 5 + 40 * 5,
2395 context->Global()->Get(v8_str("result"))->Int32Value());
2399 // Test the case when we stored cacheable lookup into
2400 // a stub, but the function name changed (and the new function is present
2401 // both before and after the interceptor in the prototype chain).
2402 THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
2403 v8::Isolate* isolate = CcTest::isolate();
2404 v8::HandleScope scope(isolate);
2405 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2407 v8::NamedPropertyHandlerConfiguration(InterceptorKeyedCallICGetter));
2408 LocalContext context;
2409 context->Global()->Set(v8_str("proto1"), templ->NewInstance());
2410 keyed_call_ic_function =
2411 v8_compile("function f(x) { return x - 1; }; f")->Run();
2414 "proto2 = new Object();"
2415 "o.y = function(x) { return x + 1; };"
2416 "proto2.y = function(x) { return x + 2; };"
2417 "o.__proto__ = proto1;"
2418 "proto1.__proto__ = proto2;"
2421 "for (var i = 0; i < 10; i++) {"
2422 " if (i == 5) { method = 'y'; };"
2423 " result += o[method](41);"
2425 CHECK_EQ(42 * 5 + 40 * 5,
2426 context->Global()->Get(v8_str("result"))->Int32Value());
2430 // Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
2431 // on the global object.
2432 THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
2433 v8::Isolate* isolate = CcTest::isolate();
2434 v8::HandleScope scope(isolate);
2435 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2436 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
2437 LocalContext context;
2438 context->Global()->Set(v8_str("o"), templ->NewInstance());
2440 "function inc(x) { return x + 1; };"
2442 "function dec(x) { return x - 1; };"
2444 "o.__proto__ = this;"
2445 "this.__proto__.x = inc;"
2446 "this.__proto__.y = dec;"
2449 "for (var i = 0; i < 10; i++) {"
2450 " if (i == 5) { method = 'y'; };"
2451 " result += o[method](41);"
2453 CHECK_EQ(42 * 5 + 40 * 5,
2454 context->Global()->Get(v8_str("result"))->Int32Value());
2458 // Test the case when actual function to call sits on global object.
2459 THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
2460 v8::Isolate* isolate = CcTest::isolate();
2461 v8::HandleScope scope(isolate);
2462 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
2463 templ_o->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
2464 LocalContext context;
2465 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
2468 "function len(x) { return x.length; };"
2469 "o.__proto__ = this;"
2470 "var m = 'parseFloat';"
2472 "for (var i = 0; i < 10; i++) {"
2475 " saved_result = result;"
2477 " result = o[m]('239');"
2479 CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
2480 CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
2484 // Test the map transition before the interceptor.
2485 THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
2486 v8::Isolate* isolate = CcTest::isolate();
2487 v8::HandleScope scope(isolate);
2488 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
2489 templ_o->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
2490 LocalContext context;
2491 context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
2494 "var o = new Object();"
2495 "o.__proto__ = proto;"
2496 "o.method = function(x) { return x + 1; };"
2499 "for (var i = 0; i < 10; i++) {"
2500 " if (i == 5) { o.method = function(x) { return x - 1; }; };"
2501 " result += o[m](41);"
2503 CHECK_EQ(42 * 5 + 40 * 5,
2504 context->Global()->Get(v8_str("result"))->Int32Value());
2508 // Test the map transition after the interceptor.
2509 THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
2510 v8::Isolate* isolate = CcTest::isolate();
2511 v8::HandleScope scope(isolate);
2512 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
2513 templ_o->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
2514 LocalContext context;
2515 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
2518 "var proto = new Object();"
2519 "o.__proto__ = proto;"
2520 "proto.method = function(x) { return x + 1; };"
2523 "for (var i = 0; i < 10; i++) {"
2524 " if (i == 5) { proto.method = function(x) { return x - 1; }; };"
2525 " result += o[m](41);"
2527 CHECK_EQ(42 * 5 + 40 * 5,
2528 context->Global()->Get(v8_str("result"))->Int32Value());
2532 static int interceptor_call_count = 0;
2534 static void InterceptorICRefErrorGetter(
2535 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2536 ApiTestFuzzer::Fuzz();
2537 if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
2538 info.GetReturnValue().Set(call_ic_function2);
2543 // This test should hit load and call ICs for the interceptor case.
2544 // Once in a while, the interceptor will reply that a property was not
2545 // found in which case we should get a reference error.
2546 THREADED_TEST(InterceptorICReferenceErrors) {
2547 v8::Isolate* isolate = CcTest::isolate();
2548 v8::HandleScope scope(isolate);
2549 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2551 v8::NamedPropertyHandlerConfiguration(InterceptorICRefErrorGetter));
2552 LocalContext context(0, templ, v8::Handle<Value>());
2553 call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
2554 v8::Handle<Value> value = CompileRun(
2556 " for (var i = 0; i < 1000; i++) {"
2557 " try { x; } catch(e) { return true; }"
2562 CHECK_EQ(true, value->BooleanValue());
2563 interceptor_call_count = 0;
2566 " for (var i = 0; i < 1000; i++) {"
2567 " try { x(42); } catch(e) { return true; }"
2572 CHECK_EQ(true, value->BooleanValue());
2576 static int interceptor_ic_exception_get_count = 0;
2578 static void InterceptorICExceptionGetter(
2579 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2580 ApiTestFuzzer::Fuzz();
2581 if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
2582 info.GetReturnValue().Set(call_ic_function3);
2584 if (interceptor_ic_exception_get_count == 20) {
2585 info.GetIsolate()->ThrowException(v8_num(42));
2591 // Test interceptor load/call IC where the interceptor throws an
2592 // exception once in a while.
2593 THREADED_TEST(InterceptorICGetterExceptions) {
2594 interceptor_ic_exception_get_count = 0;
2595 v8::Isolate* isolate = CcTest::isolate();
2596 v8::HandleScope scope(isolate);
2597 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2599 v8::NamedPropertyHandlerConfiguration(InterceptorICExceptionGetter));
2600 LocalContext context(0, templ, v8::Handle<Value>());
2601 call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
2602 v8::Handle<Value> value = CompileRun(
2604 " for (var i = 0; i < 100; i++) {"
2605 " try { x; } catch(e) { return true; }"
2610 CHECK_EQ(true, value->BooleanValue());
2611 interceptor_ic_exception_get_count = 0;
2614 " for (var i = 0; i < 100; i++) {"
2615 " try { x(42); } catch(e) { return true; }"
2620 CHECK_EQ(true, value->BooleanValue());
2624 static int interceptor_ic_exception_set_count = 0;
2626 static void InterceptorICExceptionSetter(
2627 Local<Name> key, Local<Value> value,
2628 const v8::PropertyCallbackInfo<v8::Value>& info) {
2629 ApiTestFuzzer::Fuzz();
2630 if (++interceptor_ic_exception_set_count > 20) {
2631 info.GetIsolate()->ThrowException(v8_num(42));
2636 // Test interceptor store IC where the interceptor throws an exception
2638 THREADED_TEST(InterceptorICSetterExceptions) {
2639 interceptor_ic_exception_set_count = 0;
2640 v8::Isolate* isolate = CcTest::isolate();
2641 v8::HandleScope scope(isolate);
2642 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2644 v8::NamedPropertyHandlerConfiguration(0, InterceptorICExceptionSetter));
2645 LocalContext context(0, templ, v8::Handle<Value>());
2646 v8::Handle<Value> value = CompileRun(
2648 " for (var i = 0; i < 100; i++) {"
2649 " try { x = 42; } catch(e) { return true; }"
2654 CHECK_EQ(true, value->BooleanValue());
2658 // Test that we ignore null interceptors.
2659 THREADED_TEST(NullNamedInterceptor) {
2660 v8::Isolate* isolate = CcTest::isolate();
2661 v8::HandleScope scope(isolate);
2662 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2663 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
2664 static_cast<v8::GenericNamedPropertyGetterCallback>(0)));
2665 LocalContext context;
2666 templ->Set(CcTest::isolate(), "x", v8_num(42));
2667 v8::Handle<v8::Object> obj = templ->NewInstance();
2668 context->Global()->Set(v8_str("obj"), obj);
2669 v8::Handle<Value> value = CompileRun("obj.x");
2670 CHECK(value->IsInt32());
2671 CHECK_EQ(42, value->Int32Value());
2675 // Test that we ignore null interceptors.
2676 THREADED_TEST(NullIndexedInterceptor) {
2677 v8::Isolate* isolate = CcTest::isolate();
2678 v8::HandleScope scope(isolate);
2679 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
2680 templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
2681 static_cast<v8::IndexedPropertyGetterCallback>(0)));
2682 LocalContext context;
2683 templ->Set(CcTest::isolate(), "42", v8_num(42));
2684 v8::Handle<v8::Object> obj = templ->NewInstance();
2685 context->Global()->Set(v8_str("obj"), obj);
2686 v8::Handle<Value> value = CompileRun("obj[42]");
2687 CHECK(value->IsInt32());
2688 CHECK_EQ(42, value->Int32Value());
2692 THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
2693 v8::Isolate* isolate = CcTest::isolate();
2694 v8::HandleScope scope(isolate);
2695 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2696 templ->InstanceTemplate()->SetHandler(
2697 v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
2699 env->Global()->Set(v8_str("obj"), templ->GetFunction()->NewInstance());
2700 ExpectTrue("obj.x === 42");
2701 ExpectTrue("!obj.propertyIsEnumerable('x')");
2705 THREADED_TEST(Regress256330) {
2706 i::FLAG_allow_natives_syntax = true;
2707 LocalContext context;
2708 v8::HandleScope scope(context->GetIsolate());
2709 Handle<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
2710 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2711 context->Global()->Set(v8_str("Bug"), templ->GetFunction());
2713 "\"use strict\"; var o = new Bug;"
2714 "function f(o) { o.x = 10; };"
2716 "%OptimizeFunctionOnNextCall(f);"
2718 ExpectBoolean("%GetOptimizationStatus(f) != 2", true);
2722 THREADED_TEST(CrankshaftInterceptorSetter) {
2723 i::FLAG_allow_natives_syntax = true;
2724 v8::HandleScope scope(CcTest::isolate());
2725 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2726 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2728 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2730 "var obj = new Obj;"
2731 // Initialize fields to avoid transitions later.
2733 "obj.accessor_age = 42;"
2734 "function setter(i) { this.accessor_age = i; };"
2735 "function getter() { return this.accessor_age; };"
2736 "function setAge(i) { obj.age = i; };"
2737 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
2741 "%OptimizeFunctionOnNextCall(setAge);"
2743 // All stores went through the interceptor.
2744 ExpectInt32("obj.interceptor_age", 4);
2745 ExpectInt32("obj.accessor_age", 42);
2749 THREADED_TEST(CrankshaftInterceptorGetter) {
2750 i::FLAG_allow_natives_syntax = true;
2751 v8::HandleScope scope(CcTest::isolate());
2752 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2753 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2755 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2757 "var obj = new Obj;"
2758 // Initialize fields to avoid transitions later.
2760 "obj.accessor_age = 42;"
2761 "function getter() { return this.accessor_age; };"
2762 "function getAge() { return obj.interceptor_age; };"
2763 "Object.defineProperty(obj, 'interceptor_age', { get:getter });"
2767 "%OptimizeFunctionOnNextCall(getAge);");
2768 // Access through interceptor.
2769 ExpectInt32("getAge()", 1);
2773 THREADED_TEST(CrankshaftInterceptorFieldRead) {
2774 i::FLAG_allow_natives_syntax = true;
2775 v8::HandleScope scope(CcTest::isolate());
2776 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2777 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2779 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2781 "var obj = new Obj;"
2782 "obj.__proto__.interceptor_age = 42;"
2784 "function getAge() { return obj.interceptor_age; };");
2785 ExpectInt32("getAge();", 100);
2786 ExpectInt32("getAge();", 100);
2787 ExpectInt32("getAge();", 100);
2788 CompileRun("%OptimizeFunctionOnNextCall(getAge);");
2789 // Access through interceptor.
2790 ExpectInt32("getAge();", 100);
2794 THREADED_TEST(CrankshaftInterceptorFieldWrite) {
2795 i::FLAG_allow_natives_syntax = true;
2796 v8::HandleScope scope(CcTest::isolate());
2797 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2798 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2800 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2802 "var obj = new Obj;"
2804 "function setAge(i) { obj.age = i };"
2808 "%OptimizeFunctionOnNextCall(setAge);"
2810 ExpectInt32("obj.age", 100000);
2811 ExpectInt32("obj.interceptor_age", 103);
2815 THREADED_TEST(Regress149912) {
2816 LocalContext context;
2817 v8::HandleScope scope(context->GetIsolate());
2818 Handle<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
2819 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
2820 context->Global()->Set(v8_str("Bug"), templ->GetFunction());
2821 CompileRun("Number.prototype.__proto__ = new Bug; var x = 0; x.foo();");
2825 THREADED_TEST(Regress125988) {
2826 v8::HandleScope scope(CcTest::isolate());
2827 Handle<FunctionTemplate> intercept = FunctionTemplate::New(CcTest::isolate());
2828 AddInterceptor(intercept, EmptyInterceptorGetter, EmptyInterceptorSetter);
2830 env->Global()->Set(v8_str("Intercept"), intercept->GetFunction());
2832 "var a = new Object();"
2833 "var b = new Intercept();"
2834 "var c = new Object();"
2838 "for (var i = 0; i < 3; i++) c.x;");
2839 ExpectBoolean("c.hasOwnProperty('x')", false);
2840 ExpectInt32("c.x", 23);
2843 "for (var i = 0; i < 3; i++) c.x;");
2844 ExpectBoolean("c.hasOwnProperty('x')", false);
2845 ExpectInt32("c.x", 23);
2846 ExpectBoolean("c.hasOwnProperty('y')", false);
2847 ExpectInt32("c.y", 42);
2851 static void IndexedPropertyEnumerator(
2852 const v8::PropertyCallbackInfo<v8::Array>& info) {
2853 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 1);
2854 result->Set(0, v8::Integer::New(info.GetIsolate(), 7));
2855 info.GetReturnValue().Set(result);
2859 static void NamedPropertyEnumerator(
2860 const v8::PropertyCallbackInfo<v8::Array>& info) {
2861 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
2862 result->Set(0, v8_str("x"));
2863 result->Set(1, v8::Symbol::GetIterator(info.GetIsolate()));
2864 info.GetReturnValue().Set(result);
2868 THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
2869 v8::Isolate* isolate = CcTest::isolate();
2870 v8::HandleScope handle_scope(isolate);
2871 v8::Handle<v8::ObjectTemplate> obj_template =
2872 v8::ObjectTemplate::New(isolate);
2874 obj_template->Set(v8_str("7"), v8::Integer::New(CcTest::isolate(), 7));
2875 obj_template->Set(v8_str("x"), v8::Integer::New(CcTest::isolate(), 42));
2876 obj_template->SetHandler(v8::IndexedPropertyHandlerConfiguration(
2877 NULL, NULL, NULL, NULL, IndexedPropertyEnumerator));
2878 obj_template->SetHandler(v8::NamedPropertyHandlerConfiguration(
2879 NULL, NULL, NULL, NULL, NamedPropertyEnumerator));
2881 LocalContext context;
2882 v8::Handle<v8::Object> global = context->Global();
2883 global->Set(v8_str("object"), obj_template->NewInstance());
2885 v8::Handle<v8::Value> result =
2886 CompileRun("Object.getOwnPropertyNames(object)");
2887 CHECK(result->IsArray());
2888 v8::Handle<v8::Array> result_array = v8::Handle<v8::Array>::Cast(result);
2889 CHECK_EQ(2u, result_array->Length());
2890 CHECK(result_array->Get(0)->IsString());
2891 CHECK(result_array->Get(1)->IsString());
2892 CHECK(v8_str("7")->Equals(result_array->Get(0)));
2893 CHECK(v8_str("x")->Equals(result_array->Get(1)));
2895 result = CompileRun("var ret = []; for (var k in object) ret.push(k); ret");
2896 CHECK(result->IsArray());
2897 result_array = v8::Handle<v8::Array>::Cast(result);
2898 CHECK_EQ(2u, result_array->Length());
2899 CHECK(result_array->Get(0)->IsString());
2900 CHECK(result_array->Get(1)->IsString());
2901 CHECK(v8_str("7")->Equals(result_array->Get(0)));
2902 CHECK(v8_str("x")->Equals(result_array->Get(1)));
2904 result = CompileRun("Object.getOwnPropertySymbols(object)");
2905 CHECK(result->IsArray());
2906 result_array = v8::Handle<v8::Array>::Cast(result);
2907 CHECK_EQ(1u, result_array->Length());
2908 CHECK(result_array->Get(0)->Equals(v8::Symbol::GetIterator(isolate)));
2914 template <typename T>
2915 Local<Object> BuildWrappedObject(v8::Isolate* isolate, T* data) {
2916 auto templ = v8::ObjectTemplate::New(isolate);
2917 templ->SetInternalFieldCount(1);
2918 auto instance = templ->NewInstance();
2919 instance->SetAlignedPointerInInternalField(0, data);
2924 template <typename T>
2925 T* GetWrappedObject(Local<Value> data) {
2926 return reinterpret_cast<T*>(
2927 Object::Cast(*data)->GetAlignedPointerFromInternalField(0));
2931 struct AccessCheckData {
2937 bool SimpleNamedAccessChecker(Local<v8::Object> global, Local<Value> name,
2938 v8::AccessType type, Local<Value> data) {
2939 auto access_check_data = GetWrappedObject<AccessCheckData>(data);
2940 access_check_data->count++;
2941 return access_check_data->result;
2945 bool SimpleIndexedAccessChecker(Local<v8::Object> global, uint32_t index,
2946 v8::AccessType type, Local<Value> data) {
2947 auto access_check_data = GetWrappedObject<AccessCheckData>(data);
2948 access_check_data->count++;
2949 return access_check_data->result;
2953 struct ShouldInterceptData {
2955 bool should_intercept;
2959 void ShouldNamedInterceptor(Local<Name> name,
2960 const v8::PropertyCallbackInfo<Value>& info) {
2961 ApiTestFuzzer::Fuzz();
2962 CheckReturnValue(info, FUNCTION_ADDR(ShouldNamedInterceptor));
2963 auto data = GetWrappedObject<ShouldInterceptData>(info.Data());
2964 if (!data->should_intercept) return;
2965 info.GetReturnValue().Set(v8_num(data->value));
2969 void ShouldIndexedInterceptor(uint32_t,
2970 const v8::PropertyCallbackInfo<Value>& info) {
2971 ApiTestFuzzer::Fuzz();
2972 CheckReturnValue(info, FUNCTION_ADDR(ShouldIndexedInterceptor));
2973 auto data = GetWrappedObject<ShouldInterceptData>(info.Data());
2974 if (!data->should_intercept) return;
2975 info.GetReturnValue().Set(v8_num(data->value));
2981 THREADED_TEST(NamedAllCanReadInterceptor) {
2982 auto isolate = CcTest::isolate();
2983 v8::HandleScope handle_scope(isolate);
2984 LocalContext context;
2986 AccessCheckData access_check_data;
2987 access_check_data.result = false;
2988 access_check_data.count = 0;
2990 ShouldInterceptData intercept_data_0;
2991 intercept_data_0.value = 239;
2992 intercept_data_0.should_intercept = true;
2994 ShouldInterceptData intercept_data_1;
2995 intercept_data_1.value = 165;
2996 intercept_data_1.should_intercept = false;
2998 auto intercepted_0 = v8::ObjectTemplate::New(isolate);
3000 v8::NamedPropertyHandlerConfiguration conf(ShouldNamedInterceptor);
3001 conf.flags = v8::PropertyHandlerFlags::kAllCanRead;
3003 BuildWrappedObject<ShouldInterceptData>(isolate, &intercept_data_0);
3004 intercepted_0->SetHandler(conf);
3007 auto intercepted_1 = v8::ObjectTemplate::New(isolate);
3009 v8::NamedPropertyHandlerConfiguration conf(ShouldNamedInterceptor);
3010 conf.flags = v8::PropertyHandlerFlags::kAllCanRead;
3012 BuildWrappedObject<ShouldInterceptData>(isolate, &intercept_data_1);
3013 intercepted_1->SetHandler(conf);
3016 auto checked = v8::ObjectTemplate::New(isolate);
3017 checked->SetAccessCheckCallbacks(
3018 SimpleNamedAccessChecker, nullptr,
3019 BuildWrappedObject<AccessCheckData>(isolate, &access_check_data), false);
3021 context->Global()->Set(v8_str("intercepted_0"), intercepted_0->NewInstance());
3022 context->Global()->Set(v8_str("intercepted_1"), intercepted_1->NewInstance());
3023 auto checked_instance = checked->NewInstance();
3024 checked_instance->Set(v8_str("whatever"), v8_num(17));
3025 context->Global()->Set(v8_str("checked"), checked_instance);
3027 "checked.__proto__ = intercepted_1;"
3028 "intercepted_1.__proto__ = intercepted_0;");
3030 checked_instance->TurnOnAccessCheck();
3031 CHECK_EQ(0, access_check_data.count);
3033 access_check_data.result = true;
3034 ExpectInt32("checked.whatever", 17);
3035 CHECK_EQ(1, access_check_data.count);
3037 access_check_data.result = false;
3038 ExpectInt32("checked.whatever", intercept_data_0.value);
3039 CHECK_EQ(2, access_check_data.count);
3041 intercept_data_1.should_intercept = true;
3042 ExpectInt32("checked.whatever", intercept_data_1.value);
3043 CHECK_EQ(3, access_check_data.count);
3047 THREADED_TEST(IndexedAllCanReadInterceptor) {
3048 auto isolate = CcTest::isolate();
3049 v8::HandleScope handle_scope(isolate);
3050 LocalContext context;
3052 AccessCheckData access_check_data;
3053 access_check_data.result = false;
3054 access_check_data.count = 0;
3056 ShouldInterceptData intercept_data_0;
3057 intercept_data_0.value = 239;
3058 intercept_data_0.should_intercept = true;
3060 ShouldInterceptData intercept_data_1;
3061 intercept_data_1.value = 165;
3062 intercept_data_1.should_intercept = false;
3064 auto intercepted_0 = v8::ObjectTemplate::New(isolate);
3066 v8::IndexedPropertyHandlerConfiguration conf(ShouldIndexedInterceptor);
3067 conf.flags = v8::PropertyHandlerFlags::kAllCanRead;
3069 BuildWrappedObject<ShouldInterceptData>(isolate, &intercept_data_0);
3070 intercepted_0->SetHandler(conf);
3073 auto intercepted_1 = v8::ObjectTemplate::New(isolate);
3075 v8::IndexedPropertyHandlerConfiguration conf(ShouldIndexedInterceptor);
3076 conf.flags = v8::PropertyHandlerFlags::kAllCanRead;
3078 BuildWrappedObject<ShouldInterceptData>(isolate, &intercept_data_1);
3079 intercepted_1->SetHandler(conf);
3082 auto checked = v8::ObjectTemplate::New(isolate);
3083 checked->SetAccessCheckCallbacks(
3084 nullptr, SimpleIndexedAccessChecker,
3085 BuildWrappedObject<AccessCheckData>(isolate, &access_check_data), false);
3087 context->Global()->Set(v8_str("intercepted_0"), intercepted_0->NewInstance());
3088 context->Global()->Set(v8_str("intercepted_1"), intercepted_1->NewInstance());
3089 auto checked_instance = checked->NewInstance();
3090 context->Global()->Set(v8_str("checked"), checked_instance);
3091 checked_instance->Set(15, v8_num(17));
3093 "checked.__proto__ = intercepted_1;"
3094 "intercepted_1.__proto__ = intercepted_0;");
3096 checked_instance->TurnOnAccessCheck();
3097 CHECK_EQ(0, access_check_data.count);
3099 access_check_data.result = true;
3100 ExpectInt32("checked[15]", 17);
3101 CHECK_EQ(1, access_check_data.count);
3103 access_check_data.result = false;
3104 ExpectInt32("checked[15]", intercept_data_0.value);
3105 CHECK_EQ(2, access_check_data.count);
3107 intercept_data_1.should_intercept = true;
3108 ExpectInt32("checked[15]", intercept_data_1.value);
3109 CHECK_EQ(3, access_check_data.count);