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