Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(645)

Side by Side Diff: test/cctest/test-api-interceptors.cc

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

Powered by Google App Engine
This is Rietveld 408576698