Line data Source code
1 : // Copyright 2015 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #include <stdlib.h>
6 :
7 : #include "test/cctest/test-api.h"
8 :
9 : #include "include/v8-util.h"
10 : #include "src/api-inl.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-inl.h"
16 : #include "src/objects.h"
17 : #include "src/runtime/runtime.h"
18 : #include "src/unicode-inl.h"
19 : #include "src/utils.h"
20 :
21 : using ::v8::Boolean;
22 : using ::v8::BooleanObject;
23 : using ::v8::Context;
24 : using ::v8::Extension;
25 : using ::v8::Function;
26 : using ::v8::FunctionTemplate;
27 : using ::v8::HandleScope;
28 : using ::v8::Local;
29 : using ::v8::Name;
30 : using ::v8::Message;
31 : using ::v8::MessageCallback;
32 : using ::v8::Object;
33 : using ::v8::ObjectTemplate;
34 : using ::v8::Persistent;
35 : using ::v8::Script;
36 : using ::v8::StackTrace;
37 : using ::v8::String;
38 : using ::v8::Symbol;
39 : using ::v8::TryCatch;
40 : using ::v8::Undefined;
41 : using ::v8::V8;
42 : using ::v8::Value;
43 :
44 :
45 : namespace {
46 :
47 30 : void Returns42(const v8::FunctionCallbackInfo<v8::Value>& info) {
48 : info.GetReturnValue().Set(42);
49 30 : }
50 :
51 288 : void Return239Callback(Local<String> name,
52 : const v8::PropertyCallbackInfo<Value>& info) {
53 288 : ApiTestFuzzer::Fuzz();
54 288 : CheckReturnValue(info, FUNCTION_ADDR(Return239Callback));
55 288 : info.GetReturnValue().Set(v8_str("bad value"));
56 288 : info.GetReturnValue().Set(v8_num(239));
57 288 : }
58 :
59 :
60 1098 : void EmptyInterceptorGetter(Local<Name> name,
61 1098 : const v8::PropertyCallbackInfo<v8::Value>& info) {}
62 :
63 :
64 276 : void EmptyInterceptorSetter(Local<Name> name, Local<Value> value,
65 276 : const v8::PropertyCallbackInfo<v8::Value>& info) {}
66 :
67 6 : void EmptyInterceptorQuery(Local<Name> name,
68 6 : const v8::PropertyCallbackInfo<v8::Integer>& info) {}
69 :
70 0 : void EmptyInterceptorDeleter(
71 0 : Local<Name> name, const v8::PropertyCallbackInfo<v8::Boolean>& info) {}
72 :
73 6 : void EmptyInterceptorEnumerator(
74 6 : const v8::PropertyCallbackInfo<v8::Array>& info) {}
75 :
76 12 : void SimpleAccessorGetter(Local<String> name,
77 : const v8::PropertyCallbackInfo<v8::Value>& info) {
78 : Local<Object> self = Local<Object>::Cast(info.This());
79 : info.GetReturnValue().Set(
80 12 : self->Get(info.GetIsolate()->GetCurrentContext(),
81 48 : String::Concat(info.GetIsolate(), v8_str("accessor_"), name))
82 : .ToLocalChecked());
83 12 : }
84 :
85 120036 : void SimpleAccessorSetter(Local<String> name, Local<Value> value,
86 : const v8::PropertyCallbackInfo<void>& info) {
87 : Local<Object> self = Local<Object>::Cast(info.This());
88 240072 : self->Set(info.GetIsolate()->GetCurrentContext(),
89 480144 : String::Concat(info.GetIsolate(), v8_str("accessor_"), name), value)
90 : .FromJust();
91 120036 : }
92 :
93 :
94 6 : void SymbolAccessorGetter(Local<Name> name,
95 : const v8::PropertyCallbackInfo<v8::Value>& info) {
96 6 : CHECK(name->IsSymbol());
97 : Local<Symbol> sym = Local<Symbol>::Cast(name);
98 12 : if (sym->Name()->IsUndefined()) return;
99 6 : SimpleAccessorGetter(Local<String>::Cast(sym->Name()), info);
100 : }
101 :
102 6 : void SymbolAccessorSetter(Local<Name> name, Local<Value> value,
103 : const v8::PropertyCallbackInfo<void>& info) {
104 6 : CHECK(name->IsSymbol());
105 : Local<Symbol> sym = Local<Symbol>::Cast(name);
106 12 : if (sym->Name()->IsUndefined()) return;
107 6 : SimpleAccessorSetter(Local<String>::Cast(sym->Name()), value, info);
108 : }
109 :
110 276 : void InterceptorGetter(Local<Name> generic_name,
111 : const v8::PropertyCallbackInfo<v8::Value>& info) {
112 432 : if (generic_name->IsSymbol()) return;
113 : Local<String> name = Local<String>::Cast(generic_name);
114 396 : String::Utf8Value utf8(info.GetIsolate(), name);
115 : char* name_str = *utf8;
116 276 : char prefix[] = "interceptor_";
117 : int i;
118 3156 : for (i = 0; name_str[i] && prefix[i]; ++i) {
119 1752 : if (name_str[i] != prefix[i]) return;
120 : }
121 : Local<Object> self = Local<Object>::Cast(info.This());
122 : info.GetReturnValue().Set(
123 120 : self->GetPrivate(
124 : info.GetIsolate()->GetCurrentContext(),
125 360 : v8::Private::ForApi(info.GetIsolate(), v8_str(name_str + i)))
126 : .ToLocalChecked());
127 : }
128 :
129 660218 : void InterceptorSetter(Local<Name> generic_name, Local<Value> value,
130 : const v8::PropertyCallbackInfo<v8::Value>& info) {
131 840272 : if (generic_name->IsSymbol()) return;
132 : Local<String> name = Local<String>::Cast(generic_name);
133 : // Intercept accesses that set certain integer values, for which the name does
134 : // not start with 'accessor_'.
135 1140382 : String::Utf8Value utf8(info.GetIsolate(), name);
136 : char* name_str = *utf8;
137 660218 : char prefix[] = "accessor_";
138 : int i;
139 4861478 : for (i = 0; name_str[i] && prefix[i]; ++i) {
140 2580794 : if (name_str[i] != prefix[i]) break;
141 : }
142 840272 : if (!prefix[i]) return;
143 :
144 480164 : Local<Context> context = info.GetIsolate()->GetCurrentContext();
145 960328 : if (value->IsInt32() && value->Int32Value(context).FromJust() < 10000) {
146 : Local<Object> self = Local<Object>::Cast(info.This());
147 240110 : Local<v8::Private> symbol = v8::Private::ForApi(info.GetIsolate(), name);
148 480220 : self->SetPrivate(context, symbol, value).FromJust();
149 : info.GetReturnValue().Set(value);
150 : }
151 : }
152 :
153 18066 : void GenericInterceptorGetter(Local<Name> generic_name,
154 : const v8::PropertyCallbackInfo<v8::Value>& info) {
155 : Local<String> str;
156 18066 : if (generic_name->IsSymbol()) {
157 12 : Local<Value> name = Local<Symbol>::Cast(generic_name)->Name();
158 18 : if (name->IsUndefined()) return;
159 : str = String::Concat(info.GetIsolate(), v8_str("_sym_"),
160 12 : Local<String>::Cast(name));
161 : } else {
162 : Local<String> name = Local<String>::Cast(generic_name);
163 27084 : String::Utf8Value utf8(info.GetIsolate(), name);
164 : char* name_str = *utf8;
165 27078 : if (*name_str == '_') return;
166 18060 : str = String::Concat(info.GetIsolate(), v8_str("_str_"), name);
167 : }
168 :
169 : Local<Object> self = Local<Object>::Cast(info.This());
170 : info.GetReturnValue().Set(
171 18072 : self->Get(info.GetIsolate()->GetCurrentContext(), str).ToLocalChecked());
172 : }
173 :
174 30 : void GenericInterceptorSetter(Local<Name> generic_name, Local<Value> value,
175 : const v8::PropertyCallbackInfo<v8::Value>& info) {
176 : Local<String> str;
177 30 : if (generic_name->IsSymbol()) {
178 12 : Local<Value> name = Local<Symbol>::Cast(generic_name)->Name();
179 18 : if (name->IsUndefined()) return;
180 : str = String::Concat(info.GetIsolate(), v8_str("_sym_"),
181 12 : Local<String>::Cast(name));
182 : } else {
183 : Local<String> name = Local<String>::Cast(generic_name);
184 24 : String::Utf8Value utf8(info.GetIsolate(), name);
185 : char* name_str = *utf8;
186 30 : if (*name_str == '_') return;
187 12 : str = String::Concat(info.GetIsolate(), v8_str("_str_"), name);
188 : }
189 :
190 : Local<Object> self = Local<Object>::Cast(info.This());
191 24 : self->Set(info.GetIsolate()->GetCurrentContext(), str, value).FromJust();
192 : info.GetReturnValue().Set(value);
193 : }
194 :
195 30 : void AddAccessor(Local<FunctionTemplate> templ, Local<String> name,
196 : v8::AccessorGetterCallback getter,
197 : v8::AccessorSetterCallback setter) {
198 60 : templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
199 30 : }
200 :
201 12 : void AddAccessor(Local<FunctionTemplate> templ, Local<Name> name,
202 : v8::AccessorNameGetterCallback getter,
203 : v8::AccessorNameSetterCallback setter) {
204 24 : templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
205 12 : }
206 :
207 6 : void AddStringOnlyInterceptor(Local<FunctionTemplate> templ,
208 : v8::GenericNamedPropertyGetterCallback getter,
209 : v8::GenericNamedPropertySetterCallback setter) {
210 12 : templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
211 : getter, setter, nullptr, nullptr, nullptr, Local<v8::Value>(),
212 6 : v8::PropertyHandlerFlags::kOnlyInterceptStrings));
213 6 : }
214 :
215 131 : void AddInterceptor(Local<FunctionTemplate> templ,
216 : v8::GenericNamedPropertyGetterCallback getter,
217 : v8::GenericNamedPropertySetterCallback setter) {
218 262 : templ->InstanceTemplate()->SetHandler(
219 131 : v8::NamedPropertyHandlerConfiguration(getter, setter));
220 131 : }
221 :
222 :
223 : v8::Local<v8::Object> bottom;
224 :
225 48 : void CheckThisIndexedPropertyHandler(
226 : uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) {
227 48 : CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyHandler));
228 48 : ApiTestFuzzer::Fuzz();
229 144 : CHECK(info.This()
230 : ->Equals(info.GetIsolate()->GetCurrentContext(), bottom)
231 : .FromJust());
232 48 : }
233 :
234 48 : void CheckThisNamedPropertyHandler(
235 : Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
236 48 : CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyHandler));
237 48 : ApiTestFuzzer::Fuzz();
238 144 : CHECK(info.This()
239 : ->Equals(info.GetIsolate()->GetCurrentContext(), bottom)
240 : .FromJust());
241 48 : }
242 :
243 5 : void CheckThisIndexedPropertyDefiner(
244 : uint32_t index, const v8::PropertyDescriptor& desc,
245 : const v8::PropertyCallbackInfo<v8::Value>& info) {
246 5 : CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyDefiner));
247 5 : ApiTestFuzzer::Fuzz();
248 15 : CHECK(info.This()
249 : ->Equals(info.GetIsolate()->GetCurrentContext(), bottom)
250 : .FromJust());
251 5 : }
252 :
253 5 : void CheckThisNamedPropertyDefiner(
254 : Local<Name> property, const v8::PropertyDescriptor& desc,
255 : const v8::PropertyCallbackInfo<v8::Value>& info) {
256 5 : CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyDefiner));
257 5 : ApiTestFuzzer::Fuzz();
258 15 : CHECK(info.This()
259 : ->Equals(info.GetIsolate()->GetCurrentContext(), bottom)
260 : .FromJust());
261 5 : }
262 :
263 16 : void CheckThisIndexedPropertySetter(
264 : uint32_t index, Local<Value> value,
265 : const v8::PropertyCallbackInfo<v8::Value>& info) {
266 16 : CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertySetter));
267 16 : ApiTestFuzzer::Fuzz();
268 48 : CHECK(info.This()
269 : ->Equals(info.GetIsolate()->GetCurrentContext(), bottom)
270 : .FromJust());
271 16 : }
272 :
273 10 : void CheckThisIndexedPropertyDescriptor(
274 : uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) {
275 10 : CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyDescriptor));
276 10 : ApiTestFuzzer::Fuzz();
277 30 : CHECK(info.This()
278 : ->Equals(info.GetIsolate()->GetCurrentContext(), bottom)
279 : .FromJust());
280 10 : }
281 :
282 10 : void CheckThisNamedPropertyDescriptor(
283 : Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {
284 10 : CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyDescriptor));
285 10 : ApiTestFuzzer::Fuzz();
286 30 : CHECK(info.This()
287 : ->Equals(info.GetIsolate()->GetCurrentContext(), bottom)
288 : .FromJust());
289 10 : }
290 :
291 16 : void CheckThisNamedPropertySetter(
292 : Local<Name> property, Local<Value> value,
293 : const v8::PropertyCallbackInfo<v8::Value>& info) {
294 16 : CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertySetter));
295 16 : ApiTestFuzzer::Fuzz();
296 48 : CHECK(info.This()
297 : ->Equals(info.GetIsolate()->GetCurrentContext(), bottom)
298 : .FromJust());
299 16 : }
300 :
301 36 : void CheckThisIndexedPropertyQuery(
302 : uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info) {
303 36 : CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyQuery));
304 36 : ApiTestFuzzer::Fuzz();
305 108 : CHECK(info.This()
306 : ->Equals(info.GetIsolate()->GetCurrentContext(), bottom)
307 : .FromJust());
308 36 : }
309 :
310 :
311 36 : void CheckThisNamedPropertyQuery(
312 : Local<Name> property, const v8::PropertyCallbackInfo<v8::Integer>& info) {
313 36 : CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyQuery));
314 36 : ApiTestFuzzer::Fuzz();
315 108 : CHECK(info.This()
316 : ->Equals(info.GetIsolate()->GetCurrentContext(), bottom)
317 : .FromJust());
318 36 : }
319 :
320 :
321 11 : void CheckThisIndexedPropertyDeleter(
322 : uint32_t index, const v8::PropertyCallbackInfo<v8::Boolean>& info) {
323 11 : CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyDeleter));
324 11 : ApiTestFuzzer::Fuzz();
325 33 : CHECK(info.This()
326 : ->Equals(info.GetIsolate()->GetCurrentContext(), bottom)
327 : .FromJust());
328 11 : }
329 :
330 :
331 11 : void CheckThisNamedPropertyDeleter(
332 : Local<Name> property, const v8::PropertyCallbackInfo<v8::Boolean>& info) {
333 11 : CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyDeleter));
334 11 : ApiTestFuzzer::Fuzz();
335 33 : CHECK(info.This()
336 : ->Equals(info.GetIsolate()->GetCurrentContext(), bottom)
337 : .FromJust());
338 11 : }
339 :
340 :
341 33 : void CheckThisIndexedPropertyEnumerator(
342 : const v8::PropertyCallbackInfo<v8::Array>& info) {
343 33 : CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyEnumerator));
344 33 : ApiTestFuzzer::Fuzz();
345 99 : CHECK(info.This()
346 : ->Equals(info.GetIsolate()->GetCurrentContext(), bottom)
347 : .FromJust());
348 33 : }
349 :
350 :
351 33 : void CheckThisNamedPropertyEnumerator(
352 : const v8::PropertyCallbackInfo<v8::Array>& info) {
353 33 : CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyEnumerator));
354 33 : ApiTestFuzzer::Fuzz();
355 99 : CHECK(info.This()
356 : ->Equals(info.GetIsolate()->GetCurrentContext(), bottom)
357 : .FromJust());
358 33 : }
359 :
360 :
361 : int echo_named_call_count;
362 :
363 :
364 24 : void EchoNamedProperty(Local<Name> name,
365 : const v8::PropertyCallbackInfo<v8::Value>& info) {
366 24 : ApiTestFuzzer::Fuzz();
367 72 : CHECK(v8_str("data")
368 : ->Equals(info.GetIsolate()->GetCurrentContext(), info.Data())
369 : .FromJust());
370 24 : echo_named_call_count++;
371 : info.GetReturnValue().Set(name);
372 24 : }
373 :
374 30 : void InterceptorHasOwnPropertyGetter(
375 : Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
376 30 : ApiTestFuzzer::Fuzz();
377 30 : }
378 :
379 12 : void InterceptorHasOwnPropertyGetterGC(
380 : Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
381 12 : ApiTestFuzzer::Fuzz();
382 12 : CcTest::CollectAllGarbage();
383 12 : }
384 :
385 : int query_counter_int = 0;
386 :
387 54 : void QueryCallback(Local<Name> property,
388 : const v8::PropertyCallbackInfo<v8::Integer>& info) {
389 54 : query_counter_int++;
390 54 : }
391 :
392 : } // namespace
393 :
394 : // Examples that show when the query callback is triggered.
395 26645 : THREADED_TEST(QueryInterceptor) {
396 6 : v8::Isolate* isolate = CcTest::isolate();
397 12 : v8::HandleScope scope(isolate);
398 6 : v8::Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
399 12 : templ->InstanceTemplate()->SetHandler(
400 6 : v8::NamedPropertyHandlerConfiguration(nullptr, nullptr, QueryCallback));
401 6 : LocalContext env;
402 12 : env->Global()
403 18 : ->Set(env.local(), v8_str("obj"), templ->GetFunction(env.local())
404 : .ToLocalChecked()
405 : ->NewInstance(env.local())
406 12 : .ToLocalChecked())
407 : .FromJust();
408 6 : CHECK_EQ(0, query_counter_int);
409 : v8::Local<Value> result =
410 : v8_compile("Object.getOwnPropertyDescriptor(obj, 'x');")
411 6 : ->Run(env.local())
412 : .ToLocalChecked();
413 6 : CHECK_EQ(1, query_counter_int);
414 12 : CHECK_EQ(v8::PropertyAttribute::None,
415 : static_cast<v8::PropertyAttribute>(
416 : result->Int32Value(env.local()).FromJust()));
417 :
418 : v8_compile("Object.defineProperty(obj, 'not_enum', {value: 17});")
419 6 : ->Run(env.local())
420 : .ToLocalChecked();
421 6 : CHECK_EQ(2, query_counter_int);
422 :
423 : v8_compile(
424 : "Object.defineProperty(obj, 'enum', {value: 17, enumerable: true, "
425 : "writable: true});")
426 6 : ->Run(env.local())
427 : .ToLocalChecked();
428 6 : CHECK_EQ(3, query_counter_int);
429 :
430 12 : CHECK(v8_compile("obj.propertyIsEnumerable('enum');")
431 : ->Run(env.local())
432 : .ToLocalChecked()
433 : ->BooleanValue(isolate));
434 6 : CHECK_EQ(4, query_counter_int);
435 :
436 12 : CHECK(!v8_compile("obj.propertyIsEnumerable('not_enum');")
437 : ->Run(env.local())
438 : .ToLocalChecked()
439 : ->BooleanValue(isolate));
440 6 : CHECK_EQ(5, query_counter_int);
441 :
442 12 : CHECK(v8_compile("obj.hasOwnProperty('enum');")
443 : ->Run(env.local())
444 : .ToLocalChecked()
445 : ->BooleanValue(isolate));
446 6 : CHECK_EQ(5, query_counter_int);
447 :
448 12 : CHECK(v8_compile("obj.hasOwnProperty('not_enum');")
449 : ->Run(env.local())
450 : .ToLocalChecked()
451 : ->BooleanValue(isolate));
452 6 : CHECK_EQ(5, query_counter_int);
453 :
454 12 : CHECK(!v8_compile("obj.hasOwnProperty('x');")
455 : ->Run(env.local())
456 : .ToLocalChecked()
457 : ->BooleanValue(isolate));
458 6 : CHECK_EQ(6, query_counter_int);
459 :
460 12 : CHECK(!v8_compile("obj.propertyIsEnumerable('undef');")
461 : ->Run(env.local())
462 : .ToLocalChecked()
463 : ->BooleanValue(isolate));
464 6 : CHECK_EQ(7, query_counter_int);
465 :
466 : v8_compile("Object.defineProperty(obj, 'enum', {value: 42});")
467 6 : ->Run(env.local())
468 : .ToLocalChecked();
469 6 : CHECK_EQ(8, query_counter_int);
470 :
471 6 : v8_compile("Object.isFrozen('obj.x');")->Run(env.local()).ToLocalChecked();
472 6 : CHECK_EQ(8, query_counter_int);
473 :
474 6 : v8_compile("'x' in obj;")->Run(env.local()).ToLocalChecked();
475 6 : CHECK_EQ(9, query_counter_int);
476 6 : }
477 :
478 : namespace {
479 :
480 : bool get_was_called = false;
481 : bool set_was_called = false;
482 :
483 : int set_was_called_counter = 0;
484 :
485 6 : void GetterCallback(Local<Name> property,
486 : const v8::PropertyCallbackInfo<v8::Value>& info) {
487 6 : get_was_called = true;
488 6 : }
489 :
490 30 : void SetterCallback(Local<Name> property, Local<Value> value,
491 : const v8::PropertyCallbackInfo<v8::Value>& info) {
492 30 : set_was_called = true;
493 30 : set_was_called_counter++;
494 30 : }
495 :
496 6 : void InterceptingSetterCallback(
497 : Local<Name> property, Local<Value> value,
498 : const v8::PropertyCallbackInfo<v8::Value>& info) {
499 : info.GetReturnValue().Set(value);
500 6 : }
501 :
502 : } // namespace
503 :
504 : // Check that get callback is called in defineProperty with accessor descriptor.
505 26645 : THREADED_TEST(DefinerCallbackAccessorInterceptor) {
506 12 : v8::HandleScope scope(CcTest::isolate());
507 : v8::Local<v8::FunctionTemplate> templ =
508 6 : v8::FunctionTemplate::New(CcTest::isolate());
509 12 : templ->InstanceTemplate()->SetHandler(
510 6 : v8::NamedPropertyHandlerConfiguration(GetterCallback, SetterCallback));
511 6 : LocalContext env;
512 12 : env->Global()
513 18 : ->Set(env.local(), v8_str("obj"), templ->GetFunction(env.local())
514 : .ToLocalChecked()
515 : ->NewInstance(env.local())
516 12 : .ToLocalChecked())
517 : .FromJust();
518 :
519 6 : get_was_called = false;
520 6 : set_was_called = false;
521 :
522 : v8_compile("Object.defineProperty(obj, 'x', {set: function() {return 17;}});")
523 6 : ->Run(env.local())
524 : .ToLocalChecked();
525 6 : CHECK(get_was_called);
526 6 : CHECK(!set_was_called);
527 6 : }
528 :
529 : // Check that set callback is called for function declarations.
530 26645 : THREADED_TEST(SetterCallbackFunctionDeclarationInterceptor) {
531 12 : v8::HandleScope scope(CcTest::isolate());
532 6 : LocalContext env;
533 : v8::Local<v8::FunctionTemplate> templ =
534 6 : v8::FunctionTemplate::New(CcTest::isolate());
535 :
536 6 : v8::Local<ObjectTemplate> object_template = templ->InstanceTemplate();
537 6 : object_template->SetHandler(
538 6 : v8::NamedPropertyHandlerConfiguration(nullptr, SetterCallback));
539 : v8::Local<v8::Context> ctx =
540 6 : v8::Context::New(CcTest::isolate(), nullptr, object_template);
541 :
542 6 : set_was_called_counter = 0;
543 :
544 : // Declare function.
545 6 : v8::Local<v8::String> code = v8_str("function x() {return 42;}; x();");
546 24 : CHECK_EQ(42, v8::Script::Compile(ctx, code)
547 : .ToLocalChecked()
548 : ->Run(ctx)
549 : .ToLocalChecked()
550 : ->Int32Value(ctx)
551 : .FromJust());
552 6 : CHECK_EQ(1, set_was_called_counter);
553 :
554 : // Redeclare function.
555 6 : code = v8_str("function x() {return 43;}; x();");
556 24 : CHECK_EQ(43, v8::Script::Compile(ctx, code)
557 : .ToLocalChecked()
558 : ->Run(ctx)
559 : .ToLocalChecked()
560 : ->Int32Value(ctx)
561 : .FromJust());
562 6 : CHECK_EQ(2, set_was_called_counter);
563 :
564 : // Redefine function.
565 6 : code = v8_str("x = function() {return 44;}; x();");
566 24 : CHECK_EQ(44, v8::Script::Compile(ctx, code)
567 : .ToLocalChecked()
568 : ->Run(ctx)
569 : .ToLocalChecked()
570 : ->Int32Value(ctx)
571 : .FromJust());
572 6 : CHECK_EQ(3, set_was_called_counter);
573 6 : }
574 :
575 : namespace {
576 : int descriptor_was_called;
577 :
578 6 : void PropertyDescriptorCallback(
579 : Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
580 : // Intercept the callback by setting a different descriptor.
581 6 : descriptor_was_called++;
582 : const char* code =
583 : "var desc = {value: 5};"
584 : "desc;";
585 : Local<Value> descriptor = v8_compile(code)
586 12 : ->Run(info.GetIsolate()->GetCurrentContext())
587 : .ToLocalChecked();
588 : info.GetReturnValue().Set(descriptor);
589 6 : }
590 : } // namespace
591 :
592 : // Check that the descriptor callback is called on the global object.
593 26645 : THREADED_TEST(DescriptorCallbackOnGlobalObject) {
594 12 : v8::HandleScope scope(CcTest::isolate());
595 6 : LocalContext env;
596 : v8::Local<v8::FunctionTemplate> templ =
597 6 : v8::FunctionTemplate::New(CcTest::isolate());
598 :
599 6 : v8::Local<ObjectTemplate> object_template = templ->InstanceTemplate();
600 6 : object_template->SetHandler(v8::NamedPropertyHandlerConfiguration(
601 6 : nullptr, nullptr, PropertyDescriptorCallback, nullptr, nullptr, nullptr));
602 : v8::Local<v8::Context> ctx =
603 6 : v8::Context::New(CcTest::isolate(), nullptr, object_template);
604 :
605 6 : descriptor_was_called = 0;
606 :
607 : // Declare function.
608 : v8::Local<v8::String> code = v8_str(
609 : "var x = 42; var desc = Object.getOwnPropertyDescriptor(this, 'x'); "
610 6 : "desc.value;");
611 24 : CHECK_EQ(5, v8::Script::Compile(ctx, code)
612 : .ToLocalChecked()
613 : ->Run(ctx)
614 : .ToLocalChecked()
615 : ->Int32Value(ctx)
616 : .FromJust());
617 6 : CHECK_EQ(1, descriptor_was_called);
618 6 : }
619 :
620 : namespace {
621 12 : void QueryCallbackSetDontDelete(
622 : Local<Name> property, const v8::PropertyCallbackInfo<v8::Integer>& info) {
623 : info.GetReturnValue().Set(v8::PropertyAttribute::DontDelete);
624 12 : }
625 :
626 : } // namespace
627 :
628 : // Regression for a Node.js test that fails in debug mode.
629 26645 : THREADED_TEST(InterceptorFunctionRedeclareWithQueryCallback) {
630 12 : v8::HandleScope scope(CcTest::isolate());
631 6 : LocalContext env;
632 : v8::Local<v8::FunctionTemplate> templ =
633 6 : v8::FunctionTemplate::New(CcTest::isolate());
634 :
635 6 : v8::Local<ObjectTemplate> object_template = templ->InstanceTemplate();
636 6 : object_template->SetHandler(v8::NamedPropertyHandlerConfiguration(
637 6 : nullptr, nullptr, QueryCallbackSetDontDelete));
638 : v8::Local<v8::Context> ctx =
639 6 : v8::Context::New(CcTest::isolate(), nullptr, object_template);
640 :
641 : // Declare and redeclare function.
642 : v8::Local<v8::String> code = v8_str(
643 : "function x() {return 42;};"
644 6 : "function x() {return 43;};");
645 12 : v8::Script::Compile(ctx, code).ToLocalChecked()->Run(ctx).ToLocalChecked();
646 6 : }
647 :
648 : // Regression test for chromium bug 656648.
649 : // Do not crash on non-masking, intercepting setter callbacks.
650 26645 : THREADED_TEST(NonMaskingInterceptor) {
651 12 : v8::HandleScope scope(CcTest::isolate());
652 6 : LocalContext env;
653 : v8::Local<v8::FunctionTemplate> templ =
654 6 : v8::FunctionTemplate::New(CcTest::isolate());
655 :
656 6 : v8::Local<ObjectTemplate> object_template = templ->InstanceTemplate();
657 6 : object_template->SetHandler(v8::NamedPropertyHandlerConfiguration(
658 : nullptr, InterceptingSetterCallback, nullptr, nullptr, nullptr,
659 6 : Local<Value>(), v8::PropertyHandlerFlags::kNonMasking));
660 : v8::Local<v8::Context> ctx =
661 6 : v8::Context::New(CcTest::isolate(), nullptr, object_template);
662 :
663 6 : v8::Local<v8::String> code = v8_str("function x() {return 43;};");
664 12 : v8::Script::Compile(ctx, code).ToLocalChecked()->Run(ctx).ToLocalChecked();
665 6 : }
666 :
667 : // Check that function re-declarations throw if they are read-only.
668 26645 : THREADED_TEST(SetterCallbackFunctionDeclarationInterceptorThrow) {
669 12 : v8::HandleScope scope(CcTest::isolate());
670 6 : LocalContext env;
671 : v8::Local<v8::FunctionTemplate> templ =
672 6 : v8::FunctionTemplate::New(CcTest::isolate());
673 :
674 6 : v8::Local<ObjectTemplate> object_template = templ->InstanceTemplate();
675 6 : object_template->SetHandler(
676 6 : v8::NamedPropertyHandlerConfiguration(nullptr, SetterCallback));
677 : v8::Local<v8::Context> ctx =
678 6 : v8::Context::New(CcTest::isolate(), nullptr, object_template);
679 :
680 6 : set_was_called = false;
681 :
682 : v8::Local<v8::String> code = v8_str(
683 : "function x() {return 42;};"
684 : "Object.defineProperty(this, 'x', {"
685 : "configurable: false, "
686 : "writable: false});"
687 6 : "x();");
688 24 : CHECK_EQ(42, v8::Script::Compile(ctx, code)
689 : .ToLocalChecked()
690 : ->Run(ctx)
691 : .ToLocalChecked()
692 : ->Int32Value(ctx)
693 : .FromJust());
694 :
695 6 : CHECK(set_was_called);
696 :
697 12 : v8::TryCatch try_catch(CcTest::isolate());
698 6 : set_was_called = false;
699 :
700 : // Redeclare function that is read-only.
701 6 : code = v8_str("function x() {return 43;};");
702 18 : CHECK(v8::Script::Compile(ctx, code).ToLocalChecked()->Run(ctx).IsEmpty());
703 6 : CHECK(try_catch.HasCaught());
704 :
705 6 : CHECK(!set_was_called);
706 6 : }
707 :
708 :
709 : namespace {
710 :
711 : bool get_was_called_in_order = false;
712 : bool define_was_called_in_order = false;
713 :
714 12 : void GetterCallbackOrder(Local<Name> property,
715 : const v8::PropertyCallbackInfo<v8::Value>& info) {
716 12 : get_was_called_in_order = true;
717 12 : CHECK(!define_was_called_in_order);
718 : info.GetReturnValue().Set(property);
719 12 : }
720 :
721 6 : void DefinerCallbackOrder(Local<Name> property,
722 : const v8::PropertyDescriptor& desc,
723 : const v8::PropertyCallbackInfo<v8::Value>& info) {
724 : // Get called before DefineProperty because we query the descriptor first.
725 6 : CHECK(get_was_called_in_order);
726 6 : define_was_called_in_order = true;
727 6 : }
728 :
729 : } // namespace
730 :
731 : // Check that getter callback is called before definer callback.
732 26645 : THREADED_TEST(DefinerCallbackGetAndDefine) {
733 12 : v8::HandleScope scope(CcTest::isolate());
734 : v8::Local<v8::FunctionTemplate> templ =
735 6 : v8::FunctionTemplate::New(CcTest::isolate());
736 12 : templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
737 : GetterCallbackOrder, SetterCallback, nullptr, nullptr, nullptr,
738 6 : DefinerCallbackOrder));
739 6 : LocalContext env;
740 12 : env->Global()
741 18 : ->Set(env.local(), v8_str("obj"), templ->GetFunction(env.local())
742 : .ToLocalChecked()
743 : ->NewInstance(env.local())
744 12 : .ToLocalChecked())
745 : .FromJust();
746 :
747 6 : CHECK(!get_was_called_in_order);
748 6 : CHECK(!define_was_called_in_order);
749 :
750 : v8_compile("Object.defineProperty(obj, 'x', {set: function() {return 17;}});")
751 6 : ->Run(env.local())
752 : .ToLocalChecked();
753 6 : CHECK(get_was_called_in_order);
754 6 : CHECK(define_was_called_in_order);
755 6 : }
756 :
757 : namespace { // namespace for InObjectLiteralDefinitionWithInterceptor
758 :
759 : // Workaround for no-snapshot builds: only intercept once Context::New() is
760 : // done, otherwise we'll intercept
761 : // bootstrapping like defining array on the global object.
762 : bool context_is_done = false;
763 : bool getter_callback_was_called = false;
764 :
765 6 : void ReturnUndefinedGetterCallback(
766 : Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {
767 6 : if (context_is_done) {
768 6 : getter_callback_was_called = true;
769 : info.GetReturnValue().SetUndefined();
770 : }
771 6 : }
772 :
773 : } // namespace
774 :
775 : // Check that an interceptor is not invoked during ES6 style definitions inside
776 : // an object literal.
777 26645 : THREADED_TEST(InObjectLiteralDefinitionWithInterceptor) {
778 12 : v8::HandleScope scope(CcTest::isolate());
779 6 : LocalContext env;
780 :
781 : // Set up a context in which all global object definitions are intercepted.
782 : v8::Local<v8::FunctionTemplate> templ =
783 6 : v8::FunctionTemplate::New(CcTest::isolate());
784 6 : v8::Local<ObjectTemplate> object_template = templ->InstanceTemplate();
785 6 : object_template->SetHandler(
786 6 : v8::NamedPropertyHandlerConfiguration(ReturnUndefinedGetterCallback));
787 : v8::Local<v8::Context> ctx =
788 6 : v8::Context::New(CcTest::isolate(), nullptr, object_template);
789 :
790 6 : context_is_done = true;
791 :
792 : // The interceptor returns undefined for any global object,
793 : // so setting a property on an object should throw.
794 6 : v8::Local<v8::String> code = v8_str("var o = {}; o.x = 5");
795 : {
796 6 : getter_callback_was_called = false;
797 12 : v8::TryCatch try_catch(CcTest::isolate());
798 18 : CHECK(v8::Script::Compile(ctx, code).ToLocalChecked()->Run(ctx).IsEmpty());
799 6 : CHECK(try_catch.HasCaught());
800 6 : CHECK(getter_callback_was_called);
801 : }
802 :
803 : // Defining a property in the object literal should not throw
804 : // because the interceptor is not invoked.
805 : {
806 6 : getter_callback_was_called = false;
807 12 : v8::TryCatch try_catch(CcTest::isolate());
808 6 : code = v8_str("var l = {x: 5};");
809 18 : CHECK(v8::Script::Compile(ctx, code)
810 : .ToLocalChecked()
811 : ->Run(ctx)
812 : .ToLocalChecked()
813 : ->IsUndefined());
814 6 : CHECK(!try_catch.HasCaught());
815 6 : CHECK(!getter_callback_was_called);
816 : }
817 6 : }
818 :
819 26645 : THREADED_TEST(InterceptorHasOwnProperty) {
820 6 : LocalContext context;
821 6 : v8::Isolate* isolate = context->GetIsolate();
822 12 : v8::HandleScope scope(isolate);
823 6 : Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
824 6 : Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
825 6 : instance_templ->SetHandler(
826 6 : v8::NamedPropertyHandlerConfiguration(InterceptorHasOwnPropertyGetter));
827 : Local<Function> function =
828 6 : fun_templ->GetFunction(context.local()).ToLocalChecked();
829 12 : context->Global()
830 24 : ->Set(context.local(), v8_str("constructor"), function)
831 : .FromJust();
832 : v8::Local<Value> value = CompileRun(
833 : "var o = new constructor();"
834 : "o.hasOwnProperty('ostehaps');");
835 6 : CHECK(!value->BooleanValue(isolate));
836 : value = CompileRun(
837 : "o.ostehaps = 42;"
838 : "o.hasOwnProperty('ostehaps');");
839 6 : CHECK(value->BooleanValue(isolate));
840 : value = CompileRun(
841 : "var p = new constructor();"
842 : "p.hasOwnProperty('ostehaps');");
843 6 : CHECK(!value->BooleanValue(isolate));
844 6 : }
845 :
846 :
847 26645 : THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
848 6 : LocalContext context;
849 6 : v8::Isolate* isolate = context->GetIsolate();
850 12 : v8::HandleScope scope(isolate);
851 6 : Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
852 6 : Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
853 6 : instance_templ->SetHandler(
854 6 : v8::NamedPropertyHandlerConfiguration(InterceptorHasOwnPropertyGetterGC));
855 : Local<Function> function =
856 6 : fun_templ->GetFunction(context.local()).ToLocalChecked();
857 12 : context->Global()
858 24 : ->Set(context.local(), v8_str("constructor"), function)
859 : .FromJust();
860 : // Let's first make some stuff so we can be sure to get a good GC.
861 : CompileRun(
862 : "function makestr(size) {"
863 : " switch (size) {"
864 : " case 1: return 'f';"
865 : " case 2: return 'fo';"
866 : " case 3: return 'foo';"
867 : " }"
868 : " return makestr(size >> 1) + makestr((size + 1) >> 1);"
869 : "}"
870 : "var x = makestr(12345);"
871 : "x = makestr(31415);"
872 : "x = makestr(23456);");
873 : v8::Local<Value> value = CompileRun(
874 : "var o = new constructor();"
875 : "o.__proto__ = new String(x);"
876 : "o.hasOwnProperty('ostehaps');");
877 6 : CHECK(!value->BooleanValue(isolate));
878 6 : }
879 :
880 102 : static void CheckInterceptorIC(v8::GenericNamedPropertyGetterCallback getter,
881 : v8::GenericNamedPropertyQueryCallback query,
882 : const char* source, int expected) {
883 102 : v8::Isolate* isolate = CcTest::isolate();
884 204 : v8::HandleScope scope(isolate);
885 102 : v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
886 204 : templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
887 102 : getter, nullptr, query, nullptr, nullptr, v8_str("data")));
888 102 : LocalContext context;
889 204 : context->Global()
890 204 : ->Set(context.local(), v8_str("o"),
891 306 : templ->NewInstance(context.local()).ToLocalChecked())
892 : .FromJust();
893 : v8::Local<Value> value = CompileRun(source);
894 204 : CHECK_EQ(expected, value->Int32Value(context.local()).FromJust());
895 102 : }
896 :
897 : static void CheckInterceptorLoadIC(
898 : v8::GenericNamedPropertyGetterCallback getter, const char* source,
899 : int expected) {
900 66 : CheckInterceptorIC(getter, nullptr, source, expected);
901 : }
902 :
903 12000 : static void InterceptorLoadICGetter(
904 : Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
905 12000 : ApiTestFuzzer::Fuzz();
906 12000 : v8::Isolate* isolate = CcTest::isolate();
907 12000 : CHECK_EQ(isolate, info.GetIsolate());
908 12000 : v8::Local<v8::Context> context = isolate->GetCurrentContext();
909 36000 : CHECK(v8_str("data")->Equals(context, info.Data()).FromJust());
910 36000 : CHECK(v8_str("x")->Equals(context, name).FromJust());
911 12000 : info.GetReturnValue().Set(v8::Integer::New(isolate, 42));
912 12000 : }
913 :
914 :
915 : // This test should hit the load IC for the interceptor case.
916 26645 : THREADED_TEST(InterceptorLoadIC) {
917 : CheckInterceptorLoadIC(InterceptorLoadICGetter,
918 : "var result = 0;"
919 : "for (var i = 0; i < 1000; i++) {"
920 : " result = o.x;"
921 : "}",
922 : 42);
923 6 : }
924 :
925 :
926 : // Below go several tests which verify that JITing for various
927 : // configurations of interceptor and explicit fields works fine
928 : // (those cases are special cased to get better performance).
929 :
930 66780 : static void InterceptorLoadXICGetter(
931 : Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
932 66780 : ApiTestFuzzer::Fuzz();
933 97014 : info.GetReturnValue().Set(
934 133560 : v8_str("x")
935 267120 : ->Equals(info.GetIsolate()->GetCurrentContext(), name)
936 : .FromJust()
937 : ? v8::Local<v8::Value>(v8::Integer::New(info.GetIsolate(), 42))
938 : : v8::Local<v8::Value>());
939 66780 : }
940 :
941 :
942 26645 : THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
943 : CheckInterceptorLoadIC(InterceptorLoadXICGetter,
944 : "var result = 0;"
945 : "o.y = 239;"
946 : "for (var i = 0; i < 1000; i++) {"
947 : " result = o.y;"
948 : "}",
949 : 239);
950 6 : }
951 :
952 :
953 26645 : THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
954 : CheckInterceptorLoadIC(InterceptorLoadXICGetter,
955 : "var result = 0;"
956 : "o.__proto__ = { 'y': 239 };"
957 : "for (var i = 0; i < 1000; i++) {"
958 : " result = o.y + o.x;"
959 : "}",
960 : 239 + 42);
961 6 : }
962 :
963 :
964 26645 : THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
965 : CheckInterceptorLoadIC(InterceptorLoadXICGetter,
966 : "var result = 0;"
967 : "o.__proto__.y = 239;"
968 : "for (var i = 0; i < 1000; i++) {"
969 : " result = o.y + o.x;"
970 : "}",
971 : 239 + 42);
972 6 : }
973 :
974 :
975 26645 : THREADED_TEST(InterceptorLoadICUndefined) {
976 : CheckInterceptorLoadIC(InterceptorLoadXICGetter,
977 : "var result = 0;"
978 : "for (var i = 0; i < 1000; i++) {"
979 : " result = (o.y == undefined) ? 239 : 42;"
980 : "}",
981 : 239);
982 6 : }
983 :
984 :
985 26645 : THREADED_TEST(InterceptorLoadICWithOverride) {
986 : CheckInterceptorLoadIC(InterceptorLoadXICGetter,
987 : "fst = new Object(); fst.__proto__ = o;"
988 : "snd = new Object(); snd.__proto__ = fst;"
989 : "var result1 = 0;"
990 : "for (var i = 0; i < 1000; i++) {"
991 : " result1 = snd.x;"
992 : "}"
993 : "fst.x = 239;"
994 : "var result = 0;"
995 : "for (var i = 0; i < 1000; i++) {"
996 : " result = snd.x;"
997 : "}"
998 : "result + result1",
999 : 239 + 42);
1000 6 : }
1001 :
1002 :
1003 : // Test the case when we stored field into
1004 : // a stub, but interceptor produced value on its own.
1005 26645 : THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
1006 : CheckInterceptorLoadIC(
1007 : InterceptorLoadXICGetter,
1008 : "proto = new Object();"
1009 : "o.__proto__ = proto;"
1010 : "proto.x = 239;"
1011 : "for (var i = 0; i < 1000; i++) {"
1012 : " o.x;"
1013 : // Now it should be ICed and keep a reference to x defined on proto
1014 : "}"
1015 : "var result = 0;"
1016 : "for (var i = 0; i < 1000; i++) {"
1017 : " result += o.x;"
1018 : "}"
1019 : "result;",
1020 : 42 * 1000);
1021 6 : }
1022 :
1023 :
1024 : // Test the case when we stored field into
1025 : // a stub, but it got invalidated later on.
1026 26645 : THREADED_TEST(InterceptorLoadICInvalidatedField) {
1027 : CheckInterceptorLoadIC(
1028 : InterceptorLoadXICGetter,
1029 : "proto1 = new Object();"
1030 : "proto2 = new Object();"
1031 : "o.__proto__ = proto1;"
1032 : "proto1.__proto__ = proto2;"
1033 : "proto2.y = 239;"
1034 : "for (var i = 0; i < 1000; i++) {"
1035 : " o.y;"
1036 : // Now it should be ICed and keep a reference to y defined on proto2
1037 : "}"
1038 : "proto1.y = 42;"
1039 : "var result = 0;"
1040 : "for (var i = 0; i < 1000; i++) {"
1041 : " result += o.y;"
1042 : "}"
1043 : "result;",
1044 : 42 * 1000);
1045 6 : }
1046 :
1047 :
1048 : static int interceptor_load_not_handled_calls = 0;
1049 6000 : static void InterceptorLoadNotHandled(
1050 : Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
1051 6000 : ++interceptor_load_not_handled_calls;
1052 6000 : }
1053 :
1054 :
1055 : // Test how post-interceptor lookups are done in the non-cacheable
1056 : // case: the interceptor should not be invoked during this lookup.
1057 26645 : THREADED_TEST(InterceptorLoadICPostInterceptor) {
1058 6 : interceptor_load_not_handled_calls = 0;
1059 : CheckInterceptorLoadIC(InterceptorLoadNotHandled,
1060 : "receiver = new Object();"
1061 : "receiver.__proto__ = o;"
1062 : "proto = new Object();"
1063 : "/* Make proto a slow-case object. */"
1064 : "for (var i = 0; i < 1000; i++) {"
1065 : " proto[\"xxxxxxxx\" + i] = [];"
1066 : "}"
1067 : "proto.x = 17;"
1068 : "o.__proto__ = proto;"
1069 : "var result = 0;"
1070 : "for (var i = 0; i < 1000; i++) {"
1071 : " result += receiver.x;"
1072 : "}"
1073 : "result;",
1074 : 17 * 1000);
1075 6 : CHECK_EQ(1000, interceptor_load_not_handled_calls);
1076 6 : }
1077 :
1078 :
1079 : // Test the case when we stored field into
1080 : // a stub, but it got invalidated later on due to override on
1081 : // global object which is between interceptor and fields' holders.
1082 26645 : THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
1083 : CheckInterceptorLoadIC(
1084 : InterceptorLoadXICGetter,
1085 : "o.__proto__ = this;" // set a global to be a proto of o.
1086 : "this.__proto__.y = 239;"
1087 : "for (var i = 0; i < 10; i++) {"
1088 : " if (o.y != 239) throw 'oops: ' + o.y;"
1089 : // Now it should be ICed and keep a reference to y defined on
1090 : // field_holder.
1091 : "}"
1092 : "this.y = 42;" // Assign on a global.
1093 : "var result = 0;"
1094 : "for (var i = 0; i < 10; i++) {"
1095 : " result += o.y;"
1096 : "}"
1097 : "result;",
1098 : 42 * 10);
1099 6 : }
1100 :
1101 :
1102 12 : static void SetOnThis(Local<String> name, Local<Value> value,
1103 : const v8::PropertyCallbackInfo<void>& info) {
1104 : Local<Object>::Cast(info.This())
1105 36 : ->CreateDataProperty(info.GetIsolate()->GetCurrentContext(), name, value)
1106 : .FromJust();
1107 12 : }
1108 :
1109 :
1110 26645 : THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
1111 6 : v8::Isolate* isolate = CcTest::isolate();
1112 12 : v8::HandleScope scope(isolate);
1113 6 : v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
1114 6 : templ->SetHandler(
1115 6 : v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
1116 6 : templ->SetAccessor(v8_str("y"), Return239Callback);
1117 6 : LocalContext context;
1118 12 : context->Global()
1119 12 : ->Set(context.local(), v8_str("o"),
1120 18 : templ->NewInstance(context.local()).ToLocalChecked())
1121 : .FromJust();
1122 :
1123 : // Check the case when receiver and interceptor's holder
1124 : // are the same objects.
1125 : v8::Local<Value> value = CompileRun(
1126 : "var result = 0;"
1127 : "for (var i = 0; i < 7; i++) {"
1128 : " result = o.y;"
1129 : "}");
1130 12 : CHECK_EQ(239, value->Int32Value(context.local()).FromJust());
1131 :
1132 : // Check the case when interceptor's holder is in proto chain
1133 : // of receiver.
1134 : value = CompileRun(
1135 : "r = { __proto__: o };"
1136 : "var result = 0;"
1137 : "for (var i = 0; i < 7; i++) {"
1138 : " result = r.y;"
1139 : "}");
1140 12 : CHECK_EQ(239, value->Int32Value(context.local()).FromJust());
1141 6 : }
1142 :
1143 :
1144 26645 : THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
1145 6 : v8::Isolate* isolate = CcTest::isolate();
1146 12 : v8::HandleScope scope(isolate);
1147 6 : v8::Local<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
1148 6 : templ_o->SetHandler(
1149 6 : v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
1150 6 : v8::Local<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
1151 6 : templ_p->SetAccessor(v8_str("y"), Return239Callback);
1152 :
1153 6 : LocalContext context;
1154 12 : context->Global()
1155 12 : ->Set(context.local(), v8_str("o"),
1156 18 : templ_o->NewInstance(context.local()).ToLocalChecked())
1157 : .FromJust();
1158 12 : context->Global()
1159 12 : ->Set(context.local(), v8_str("p"),
1160 18 : templ_p->NewInstance(context.local()).ToLocalChecked())
1161 : .FromJust();
1162 :
1163 : // Check the case when receiver and interceptor's holder
1164 : // are the same objects.
1165 : v8::Local<Value> value = CompileRun(
1166 : "o.__proto__ = p;"
1167 : "var result = 0;"
1168 : "for (var i = 0; i < 7; i++) {"
1169 : " result = o.x + o.y;"
1170 : "}");
1171 12 : CHECK_EQ(239 + 42, value->Int32Value(context.local()).FromJust());
1172 :
1173 : // Check the case when interceptor's holder is in proto chain
1174 : // of receiver.
1175 : value = CompileRun(
1176 : "r = { __proto__: o };"
1177 : "var result = 0;"
1178 : "for (var i = 0; i < 7; i++) {"
1179 : " result = r.x + r.y;"
1180 : "}");
1181 12 : CHECK_EQ(239 + 42, value->Int32Value(context.local()).FromJust());
1182 6 : }
1183 :
1184 :
1185 26645 : THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
1186 6 : v8::Isolate* isolate = CcTest::isolate();
1187 12 : v8::HandleScope scope(isolate);
1188 6 : v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
1189 6 : templ->SetHandler(
1190 6 : v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
1191 6 : templ->SetAccessor(v8_str("y"), Return239Callback);
1192 :
1193 6 : LocalContext context;
1194 12 : context->Global()
1195 12 : ->Set(context.local(), v8_str("o"),
1196 18 : templ->NewInstance(context.local()).ToLocalChecked())
1197 : .FromJust();
1198 :
1199 : v8::Local<Value> value = CompileRun(
1200 : "fst = new Object(); fst.__proto__ = o;"
1201 : "snd = new Object(); snd.__proto__ = fst;"
1202 : "var result1 = 0;"
1203 : "for (var i = 0; i < 7; i++) {"
1204 : " result1 = snd.x;"
1205 : "}"
1206 : "fst.x = 239;"
1207 : "var result = 0;"
1208 : "for (var i = 0; i < 7; i++) {"
1209 : " result = snd.x;"
1210 : "}"
1211 : "result + result1");
1212 12 : CHECK_EQ(239 + 42, value->Int32Value(context.local()).FromJust());
1213 6 : }
1214 :
1215 :
1216 : // Test the case when we stored callback into
1217 : // a stub, but interceptor produced value on its own.
1218 26645 : THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
1219 6 : v8::Isolate* isolate = CcTest::isolate();
1220 12 : v8::HandleScope scope(isolate);
1221 6 : v8::Local<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
1222 6 : templ_o->SetHandler(
1223 6 : v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
1224 6 : v8::Local<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
1225 6 : templ_p->SetAccessor(v8_str("y"), Return239Callback);
1226 :
1227 6 : LocalContext context;
1228 12 : context->Global()
1229 12 : ->Set(context.local(), v8_str("o"),
1230 18 : templ_o->NewInstance(context.local()).ToLocalChecked())
1231 : .FromJust();
1232 12 : context->Global()
1233 12 : ->Set(context.local(), v8_str("p"),
1234 18 : templ_p->NewInstance(context.local()).ToLocalChecked())
1235 : .FromJust();
1236 :
1237 : v8::Local<Value> value = CompileRun(
1238 : "o.__proto__ = p;"
1239 : "for (var i = 0; i < 7; i++) {"
1240 : " o.x;"
1241 : // Now it should be ICed and keep a reference to x defined on p
1242 : "}"
1243 : "var result = 0;"
1244 : "for (var i = 0; i < 7; i++) {"
1245 : " result += o.x;"
1246 : "}"
1247 : "result");
1248 12 : CHECK_EQ(42 * 7, value->Int32Value(context.local()).FromJust());
1249 6 : }
1250 :
1251 :
1252 : // Test the case when we stored callback into
1253 : // a stub, but it got invalidated later on.
1254 26645 : THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
1255 6 : v8::Isolate* isolate = CcTest::isolate();
1256 12 : v8::HandleScope scope(isolate);
1257 6 : v8::Local<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
1258 6 : templ_o->SetHandler(
1259 6 : v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
1260 6 : v8::Local<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
1261 6 : templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
1262 :
1263 6 : LocalContext context;
1264 12 : context->Global()
1265 12 : ->Set(context.local(), v8_str("o"),
1266 18 : templ_o->NewInstance(context.local()).ToLocalChecked())
1267 : .FromJust();
1268 12 : context->Global()
1269 12 : ->Set(context.local(), v8_str("p"),
1270 18 : templ_p->NewInstance(context.local()).ToLocalChecked())
1271 : .FromJust();
1272 :
1273 : v8::Local<Value> value = CompileRun(
1274 : "inbetween = new Object();"
1275 : "o.__proto__ = inbetween;"
1276 : "inbetween.__proto__ = p;"
1277 : "for (var i = 0; i < 10; i++) {"
1278 : " o.y;"
1279 : // Now it should be ICed and keep a reference to y defined on p
1280 : "}"
1281 : "inbetween.y = 42;"
1282 : "var result = 0;"
1283 : "for (var i = 0; i < 10; i++) {"
1284 : " result += o.y;"
1285 : "}"
1286 : "result");
1287 12 : CHECK_EQ(42 * 10, value->Int32Value(context.local()).FromJust());
1288 6 : }
1289 :
1290 :
1291 : // Test the case when we stored callback into
1292 : // a stub, but it got invalidated later on due to override on
1293 : // global object which is between interceptor and callbacks' holders.
1294 26645 : THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
1295 6 : v8::Isolate* isolate = CcTest::isolate();
1296 12 : v8::HandleScope scope(isolate);
1297 6 : v8::Local<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
1298 6 : templ_o->SetHandler(
1299 6 : v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
1300 6 : v8::Local<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
1301 6 : templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
1302 :
1303 6 : LocalContext context;
1304 12 : context->Global()
1305 12 : ->Set(context.local(), v8_str("o"),
1306 18 : templ_o->NewInstance(context.local()).ToLocalChecked())
1307 : .FromJust();
1308 12 : context->Global()
1309 12 : ->Set(context.local(), v8_str("p"),
1310 18 : templ_p->NewInstance(context.local()).ToLocalChecked())
1311 : .FromJust();
1312 :
1313 : v8::Local<Value> value = CompileRun(
1314 : "o.__proto__ = this;"
1315 : "this.__proto__ = p;"
1316 : "for (var i = 0; i < 10; i++) {"
1317 : " if (o.y != 239) throw 'oops: ' + o.y;"
1318 : // Now it should be ICed and keep a reference to y defined on p
1319 : "}"
1320 : "this.y = 42;"
1321 : "var result = 0;"
1322 : "for (var i = 0; i < 10; i++) {"
1323 : " result += o.y;"
1324 : "}"
1325 : "result");
1326 12 : CHECK_EQ(42 * 10, value->Int32Value(context.local()).FromJust());
1327 6 : }
1328 :
1329 : // Test load of a non-existing global when a global object has an interceptor.
1330 26645 : THREADED_TEST(InterceptorLoadGlobalICGlobalWithInterceptor) {
1331 6 : v8::Isolate* isolate = CcTest::isolate();
1332 12 : v8::HandleScope scope(isolate);
1333 6 : v8::Local<v8::ObjectTemplate> templ_global = v8::ObjectTemplate::New(isolate);
1334 6 : templ_global->SetHandler(v8::NamedPropertyHandlerConfiguration(
1335 6 : EmptyInterceptorGetter, EmptyInterceptorSetter));
1336 :
1337 6 : LocalContext context(nullptr, templ_global);
1338 : i::Handle<i::JSReceiver> global_proxy =
1339 6 : v8::Utils::OpenHandle<Object, i::JSReceiver>(context->Global());
1340 6 : CHECK(global_proxy->IsJSGlobalProxy());
1341 : i::Handle<i::JSGlobalObject> global(
1342 : i::JSGlobalObject::cast(global_proxy->map()->prototype()),
1343 : global_proxy->GetIsolate());
1344 6 : CHECK(global->map()->has_named_interceptor());
1345 :
1346 : v8::Local<Value> value = CompileRun(
1347 : "var f = function() { "
1348 : " try {"
1349 : " x1;"
1350 : " } catch(e) {"
1351 : " }"
1352 : " return typeof x1 === 'undefined';"
1353 : "};"
1354 : "for (var i = 0; i < 10; i++) {"
1355 : " f();"
1356 : "};"
1357 : "f();");
1358 6 : CHECK(value->BooleanValue(isolate));
1359 :
1360 : value = CompileRun(
1361 : "var f = function() { "
1362 : " try {"
1363 : " x2;"
1364 : " return false;"
1365 : " } catch(e) {"
1366 : " return true;"
1367 : " }"
1368 : "};"
1369 : "for (var i = 0; i < 10; i++) {"
1370 : " f();"
1371 : "};"
1372 : "f();");
1373 6 : CHECK(value->BooleanValue(isolate));
1374 :
1375 : value = CompileRun(
1376 : "var f = function() { "
1377 : " try {"
1378 : " typeof(x3);"
1379 : " return true;"
1380 : " } catch(e) {"
1381 : " return false;"
1382 : " }"
1383 : "};"
1384 : "for (var i = 0; i < 10; i++) {"
1385 : " f();"
1386 : "};"
1387 : "f();");
1388 6 : CHECK(value->BooleanValue(isolate));
1389 6 : }
1390 :
1391 : // Test load of a non-existing global through prototype chain when a global
1392 : // object has an interceptor.
1393 26645 : THREADED_TEST(InterceptorLoadICGlobalWithInterceptor) {
1394 6 : i::FLAG_allow_natives_syntax = true;
1395 6 : v8::Isolate* isolate = CcTest::isolate();
1396 12 : v8::HandleScope scope(isolate);
1397 6 : v8::Local<v8::ObjectTemplate> templ_global = v8::ObjectTemplate::New(isolate);
1398 6 : templ_global->SetHandler(v8::NamedPropertyHandlerConfiguration(
1399 6 : GenericInterceptorGetter, GenericInterceptorSetter));
1400 :
1401 6 : LocalContext context(nullptr, templ_global);
1402 : i::Handle<i::JSReceiver> global_proxy =
1403 6 : v8::Utils::OpenHandle<Object, i::JSReceiver>(context->Global());
1404 6 : CHECK(global_proxy->IsJSGlobalProxy());
1405 : i::Handle<i::JSGlobalObject> global(
1406 : i::JSGlobalObject::cast(global_proxy->map()->prototype()),
1407 : global_proxy->GetIsolate());
1408 6 : CHECK(global->map()->has_named_interceptor());
1409 :
1410 : ExpectInt32(
1411 : "(function() {"
1412 : " var f = function(obj) { "
1413 : " return obj.foo;"
1414 : " };"
1415 : " var obj = { __proto__: this, _str_foo: 42 };"
1416 : " for (var i = 0; i < 1500; i++) obj['p' + i] = 0;"
1417 : " /* Ensure that |obj| is in dictionary mode. */"
1418 : " if (%HasFastProperties(obj)) return -1;"
1419 : " for (var i = 0; i < 3; i++) {"
1420 : " f(obj);"
1421 : " };"
1422 : " return f(obj);"
1423 : "})();",
1424 6 : 42);
1425 6 : }
1426 :
1427 6 : static void InterceptorLoadICGetter0(
1428 : Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
1429 6 : ApiTestFuzzer::Fuzz();
1430 18 : CHECK(v8_str("x")
1431 : ->Equals(info.GetIsolate()->GetCurrentContext(), name)
1432 : .FromJust());
1433 6 : info.GetReturnValue().Set(v8::Integer::New(info.GetIsolate(), 0));
1434 6 : }
1435 :
1436 :
1437 26645 : THREADED_TEST(InterceptorReturningZero) {
1438 : CheckInterceptorLoadIC(InterceptorLoadICGetter0, "o.x == undefined ? 1 : 0",
1439 : 0);
1440 6 : }
1441 :
1442 : namespace {
1443 :
1444 : template <typename TKey, v8::internal::PropertyAttributes attribute>
1445 30000 : void HasICQuery(TKey name, const v8::PropertyCallbackInfo<v8::Integer>& info) {
1446 30000 : ApiTestFuzzer::Fuzz();
1447 30000 : v8::Isolate* isolate = CcTest::isolate();
1448 30000 : CHECK_EQ(isolate, info.GetIsolate());
1449 30000 : info.GetReturnValue().Set(v8::Integer::New(isolate, attribute));
1450 30000 : }
1451 :
1452 : template <typename TKey>
1453 12000 : void HasICQueryToggle(TKey name,
1454 : const v8::PropertyCallbackInfo<v8::Integer>& info) {
1455 12000 : ApiTestFuzzer::Fuzz();
1456 : static bool toggle = false;
1457 12000 : toggle = !toggle;
1458 12000 : v8::Isolate* isolate = CcTest::isolate();
1459 12000 : CHECK_EQ(isolate, info.GetIsolate());
1460 12000 : info.GetReturnValue().Set(v8::Integer::New(
1461 : isolate, toggle ? v8::internal::ABSENT : v8::internal::NONE));
1462 12000 : }
1463 :
1464 : int named_query_counter = 0;
1465 6000 : void NamedQueryCallback(Local<Name> name,
1466 : const v8::PropertyCallbackInfo<v8::Integer>& info) {
1467 6000 : named_query_counter++;
1468 6000 : }
1469 :
1470 : } // namespace
1471 :
1472 26645 : THREADED_TEST(InterceptorHasIC) {
1473 6 : named_query_counter = 0;
1474 : CheckInterceptorIC(nullptr, NamedQueryCallback,
1475 : "var result = 0;"
1476 : "for (var i = 0; i < 1000; i++) {"
1477 : " 'x' in o;"
1478 : "}",
1479 6 : 0);
1480 6 : CHECK_EQ(1000, named_query_counter);
1481 6 : }
1482 :
1483 26645 : THREADED_TEST(InterceptorHasICQueryAbsent) {
1484 : CheckInterceptorIC(nullptr, HasICQuery<Local<Name>, v8::internal::ABSENT>,
1485 : "var result = 0;"
1486 : "for (var i = 0; i < 1000; i++) {"
1487 : " if ('x' in o) ++result;"
1488 : "}",
1489 6 : 0);
1490 6 : }
1491 :
1492 26645 : THREADED_TEST(InterceptorHasICQueryNone) {
1493 : CheckInterceptorIC(nullptr, HasICQuery<Local<Name>, v8::internal::NONE>,
1494 : "var result = 0;"
1495 : "for (var i = 0; i < 1000; i++) {"
1496 : " if ('x' in o) ++result;"
1497 : "}",
1498 6 : 1000);
1499 6 : }
1500 :
1501 26645 : THREADED_TEST(InterceptorHasICGetter) {
1502 : CheckInterceptorIC(InterceptorLoadICGetter, nullptr,
1503 : "var result = 0;"
1504 : "for (var i = 0; i < 1000; i++) {"
1505 : " if ('x' in o) ++result;"
1506 : "}",
1507 6 : 1000);
1508 6 : }
1509 :
1510 26645 : THREADED_TEST(InterceptorHasICQueryGetter) {
1511 : CheckInterceptorIC(InterceptorLoadICGetter,
1512 : HasICQuery<Local<Name>, v8::internal::ABSENT>,
1513 : "var result = 0;"
1514 : "for (var i = 0; i < 1000; i++) {"
1515 : " if ('x' in o) ++result;"
1516 : "}",
1517 6 : 0);
1518 6 : }
1519 :
1520 26645 : THREADED_TEST(InterceptorHasICQueryToggle) {
1521 : CheckInterceptorIC(InterceptorLoadICGetter, HasICQueryToggle<Local<Name>>,
1522 : "var result = 0;"
1523 : "for (var i = 0; i < 1000; i++) {"
1524 : " if ('x' in o) ++result;"
1525 : "}",
1526 6 : 500);
1527 6 : }
1528 :
1529 6000 : static void InterceptorStoreICSetter(
1530 : Local<Name> key, Local<Value> value,
1531 : const v8::PropertyCallbackInfo<v8::Value>& info) {
1532 6000 : v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
1533 18000 : CHECK(v8_str("x")->Equals(context, key).FromJust());
1534 12000 : CHECK_EQ(42, value->Int32Value(context).FromJust());
1535 : info.GetReturnValue().Set(value);
1536 6000 : }
1537 :
1538 :
1539 : // This test should hit the store IC for the interceptor case.
1540 26645 : THREADED_TEST(InterceptorStoreIC) {
1541 6 : v8::Isolate* isolate = CcTest::isolate();
1542 12 : v8::HandleScope scope(isolate);
1543 6 : v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
1544 12 : templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
1545 : InterceptorLoadICGetter, InterceptorStoreICSetter, nullptr, nullptr,
1546 6 : nullptr, v8_str("data")));
1547 6 : LocalContext context;
1548 12 : context->Global()
1549 12 : ->Set(context.local(), v8_str("o"),
1550 18 : templ->NewInstance(context.local()).ToLocalChecked())
1551 : .FromJust();
1552 : CompileRun(
1553 : "for (var i = 0; i < 1000; i++) {"
1554 : " o.x = 42;"
1555 : "}");
1556 6 : }
1557 :
1558 :
1559 26645 : THREADED_TEST(InterceptorStoreICWithNoSetter) {
1560 6 : v8::Isolate* isolate = CcTest::isolate();
1561 12 : v8::HandleScope scope(isolate);
1562 6 : v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
1563 6 : templ->SetHandler(
1564 6 : v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
1565 6 : LocalContext context;
1566 12 : context->Global()
1567 12 : ->Set(context.local(), v8_str("o"),
1568 18 : templ->NewInstance(context.local()).ToLocalChecked())
1569 : .FromJust();
1570 : v8::Local<Value> value = CompileRun(
1571 : "for (var i = 0; i < 1000; i++) {"
1572 : " o.y = 239;"
1573 : "}"
1574 : "42 + o.y");
1575 12 : CHECK_EQ(239 + 42, value->Int32Value(context.local()).FromJust());
1576 6 : }
1577 :
1578 :
1579 26645 : THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
1580 12 : v8::HandleScope scope(CcTest::isolate());
1581 6 : Local<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
1582 6 : Local<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
1583 6 : child->Inherit(parent);
1584 6 : AddAccessor(parent, v8_str("age"), SimpleAccessorGetter,
1585 6 : SimpleAccessorSetter);
1586 6 : AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1587 6 : LocalContext env;
1588 12 : env->Global()
1589 12 : ->Set(env.local(), v8_str("Child"),
1590 18 : child->GetFunction(env.local()).ToLocalChecked())
1591 : .FromJust();
1592 : CompileRun(
1593 : "var child = new Child;"
1594 : "child.age = 10;");
1595 6 : ExpectBoolean("child.hasOwnProperty('age')", false);
1596 6 : ExpectInt32("child.age", 10);
1597 6 : ExpectInt32("child.accessor_age", 10);
1598 6 : }
1599 :
1600 :
1601 26645 : THREADED_TEST(LegacyInterceptorDoesNotSeeSymbols) {
1602 6 : LocalContext env;
1603 6 : v8::Isolate* isolate = CcTest::isolate();
1604 12 : v8::HandleScope scope(isolate);
1605 6 : Local<FunctionTemplate> parent = FunctionTemplate::New(isolate);
1606 6 : Local<FunctionTemplate> child = FunctionTemplate::New(isolate);
1607 6 : v8::Local<v8::Symbol> age = v8::Symbol::New(isolate, v8_str("age"));
1608 :
1609 6 : child->Inherit(parent);
1610 6 : AddAccessor(parent, age, SymbolAccessorGetter, SymbolAccessorSetter);
1611 6 : AddStringOnlyInterceptor(child, InterceptorGetter, InterceptorSetter);
1612 :
1613 12 : env->Global()
1614 12 : ->Set(env.local(), v8_str("Child"),
1615 18 : child->GetFunction(env.local()).ToLocalChecked())
1616 : .FromJust();
1617 24 : env->Global()->Set(env.local(), v8_str("age"), age).FromJust();
1618 : CompileRun(
1619 : "var child = new Child;"
1620 : "child[age] = 10;");
1621 6 : ExpectInt32("child[age]", 10);
1622 6 : ExpectBoolean("child.hasOwnProperty('age')", false);
1623 6 : ExpectBoolean("child.hasOwnProperty('accessor_age')", true);
1624 6 : }
1625 :
1626 :
1627 26645 : THREADED_TEST(GenericInterceptorDoesSeeSymbols) {
1628 6 : LocalContext env;
1629 6 : v8::Isolate* isolate = CcTest::isolate();
1630 12 : v8::HandleScope scope(isolate);
1631 6 : Local<FunctionTemplate> parent = FunctionTemplate::New(isolate);
1632 6 : Local<FunctionTemplate> child = FunctionTemplate::New(isolate);
1633 6 : v8::Local<v8::Symbol> age = v8::Symbol::New(isolate, v8_str("age"));
1634 6 : v8::Local<v8::Symbol> anon = v8::Symbol::New(isolate);
1635 :
1636 6 : child->Inherit(parent);
1637 6 : AddAccessor(parent, age, SymbolAccessorGetter, SymbolAccessorSetter);
1638 6 : AddInterceptor(child, GenericInterceptorGetter, GenericInterceptorSetter);
1639 :
1640 12 : env->Global()
1641 12 : ->Set(env.local(), v8_str("Child"),
1642 18 : child->GetFunction(env.local()).ToLocalChecked())
1643 : .FromJust();
1644 24 : env->Global()->Set(env.local(), v8_str("age"), age).FromJust();
1645 24 : env->Global()->Set(env.local(), v8_str("anon"), anon).FromJust();
1646 : CompileRun(
1647 : "var child = new Child;"
1648 : "child[age] = 10;");
1649 6 : ExpectInt32("child[age]", 10);
1650 6 : ExpectInt32("child._sym_age", 10);
1651 :
1652 : // Check that it also sees strings.
1653 : CompileRun("child.foo = 47");
1654 6 : ExpectInt32("child.foo", 47);
1655 6 : ExpectInt32("child._str_foo", 47);
1656 :
1657 : // Check that the interceptor can punt (in this case, on anonymous symbols).
1658 : CompileRun("child[anon] = 31337");
1659 6 : ExpectInt32("child[anon]", 31337);
1660 6 : }
1661 :
1662 :
1663 26645 : THREADED_TEST(NamedPropertyHandlerGetter) {
1664 6 : echo_named_call_count = 0;
1665 6 : v8::Isolate* isolate = CcTest::isolate();
1666 12 : v8::HandleScope scope(isolate);
1667 6 : v8::Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
1668 18 : templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
1669 6 : EchoNamedProperty, nullptr, nullptr, nullptr, nullptr, v8_str("data")));
1670 6 : LocalContext env;
1671 12 : env->Global()
1672 18 : ->Set(env.local(), v8_str("obj"), templ->GetFunction(env.local())
1673 : .ToLocalChecked()
1674 : ->NewInstance(env.local())
1675 12 : .ToLocalChecked())
1676 : .FromJust();
1677 6 : CHECK_EQ(0, echo_named_call_count);
1678 6 : v8_compile("obj.x")->Run(env.local()).ToLocalChecked();
1679 6 : CHECK_EQ(1, echo_named_call_count);
1680 : const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
1681 6 : v8::Local<Value> str = CompileRun(code);
1682 12 : String::Utf8Value value(isolate, str);
1683 6 : CHECK_EQ(0, strcmp(*value, "oddlepoddle"));
1684 : // Check default behavior
1685 18 : CHECK_EQ(10, v8_compile("obj.flob = 10;")
1686 : ->Run(env.local())
1687 : .ToLocalChecked()
1688 : ->Int32Value(env.local())
1689 : .FromJust());
1690 12 : CHECK(v8_compile("'myProperty' in obj")
1691 : ->Run(env.local())
1692 : .ToLocalChecked()
1693 : ->BooleanValue(isolate));
1694 12 : CHECK(v8_compile("delete obj.myProperty")
1695 : ->Run(env.local())
1696 : .ToLocalChecked()
1697 : ->BooleanValue(isolate));
1698 6 : }
1699 :
1700 : namespace {
1701 6 : void NotInterceptingPropertyDefineCallback(
1702 : Local<Name> name, const v8::PropertyDescriptor& desc,
1703 : const v8::PropertyCallbackInfo<v8::Value>& info) {
1704 : // Do not intercept by not calling info.GetReturnValue().Set().
1705 6 : }
1706 :
1707 6 : void InterceptingPropertyDefineCallback(
1708 : Local<Name> name, const v8::PropertyDescriptor& desc,
1709 : const v8::PropertyCallbackInfo<v8::Value>& info) {
1710 : // Intercept the callback by setting a non-empty handle
1711 : info.GetReturnValue().Set(name);
1712 6 : }
1713 :
1714 6 : void CheckDescriptorInDefineCallback(
1715 : Local<Name> name, const v8::PropertyDescriptor& desc,
1716 : const v8::PropertyCallbackInfo<v8::Value>& info) {
1717 6 : CHECK(!desc.has_writable());
1718 6 : CHECK(!desc.has_value());
1719 6 : CHECK(!desc.has_enumerable());
1720 6 : CHECK(desc.has_configurable());
1721 6 : CHECK(!desc.configurable());
1722 6 : CHECK(desc.has_get());
1723 12 : CHECK(desc.get()->IsFunction());
1724 6 : CHECK(desc.has_set());
1725 12 : CHECK(desc.set()->IsUndefined());
1726 : // intercept the callback by setting a non-empty handle
1727 : info.GetReturnValue().Set(name);
1728 6 : }
1729 : } // namespace
1730 :
1731 26645 : THREADED_TEST(PropertyDefinerCallback) {
1732 12 : v8::HandleScope scope(CcTest::isolate());
1733 6 : LocalContext env;
1734 :
1735 : { // Intercept defineProperty()
1736 : v8::Local<v8::FunctionTemplate> templ =
1737 6 : v8::FunctionTemplate::New(CcTest::isolate());
1738 12 : templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
1739 : nullptr, nullptr, nullptr, nullptr, nullptr,
1740 6 : NotInterceptingPropertyDefineCallback));
1741 12 : env->Global()
1742 18 : ->Set(env.local(), v8_str("obj"), templ->GetFunction(env.local())
1743 : .ToLocalChecked()
1744 : ->NewInstance(env.local())
1745 12 : .ToLocalChecked())
1746 : .FromJust();
1747 : const char* code =
1748 : "obj.x = 17; "
1749 : "Object.defineProperty(obj, 'x', {value: 42});"
1750 : "obj.x;";
1751 18 : CHECK_EQ(42, v8_compile(code)
1752 : ->Run(env.local())
1753 : .ToLocalChecked()
1754 : ->Int32Value(env.local())
1755 : .FromJust());
1756 : }
1757 :
1758 : { // Intercept defineProperty() for correct accessor descriptor
1759 : v8::Local<v8::FunctionTemplate> templ =
1760 6 : v8::FunctionTemplate::New(CcTest::isolate());
1761 12 : templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
1762 : nullptr, nullptr, nullptr, nullptr, nullptr,
1763 6 : CheckDescriptorInDefineCallback));
1764 12 : env->Global()
1765 18 : ->Set(env.local(), v8_str("obj"), templ->GetFunction(env.local())
1766 : .ToLocalChecked()
1767 : ->NewInstance(env.local())
1768 12 : .ToLocalChecked())
1769 : .FromJust();
1770 : const char* code =
1771 : "obj.x = 17; "
1772 : "Object.defineProperty(obj, 'x', {"
1773 : "get: function(){ return 42; }, "
1774 : "set: undefined,"
1775 : "configurable: 0"
1776 : "});"
1777 : "obj.x;";
1778 18 : CHECK_EQ(17, v8_compile(code)
1779 : ->Run(env.local())
1780 : .ToLocalChecked()
1781 : ->Int32Value(env.local())
1782 : .FromJust());
1783 : }
1784 :
1785 : { // Do not intercept defineProperty()
1786 : v8::Local<v8::FunctionTemplate> templ2 =
1787 6 : v8::FunctionTemplate::New(CcTest::isolate());
1788 12 : templ2->InstanceTemplate()->SetHandler(
1789 : v8::NamedPropertyHandlerConfiguration(
1790 : nullptr, nullptr, nullptr, nullptr, nullptr,
1791 6 : InterceptingPropertyDefineCallback));
1792 12 : env->Global()
1793 18 : ->Set(env.local(), v8_str("obj"), templ2->GetFunction(env.local())
1794 : .ToLocalChecked()
1795 : ->NewInstance(env.local())
1796 12 : .ToLocalChecked())
1797 : .FromJust();
1798 :
1799 : const char* code =
1800 : "obj.x = 17; "
1801 : "Object.defineProperty(obj, 'x', {value: 42});"
1802 : "obj.x;";
1803 18 : CHECK_EQ(17, v8_compile(code)
1804 : ->Run(env.local())
1805 : .ToLocalChecked()
1806 : ->Int32Value(env.local())
1807 : .FromJust());
1808 : }
1809 6 : }
1810 :
1811 : namespace {
1812 6 : void NotInterceptingPropertyDefineCallbackIndexed(
1813 : uint32_t index, const v8::PropertyDescriptor& desc,
1814 : const v8::PropertyCallbackInfo<v8::Value>& info) {
1815 : // Do not intercept by not calling info.GetReturnValue().Set()
1816 6 : }
1817 :
1818 6 : void InterceptingPropertyDefineCallbackIndexed(
1819 : uint32_t index, const v8::PropertyDescriptor& desc,
1820 : const v8::PropertyCallbackInfo<v8::Value>& info) {
1821 : // intercept the callback by setting a non-empty handle
1822 : info.GetReturnValue().Set(index);
1823 6 : }
1824 :
1825 6 : void CheckDescriptorInDefineCallbackIndexed(
1826 : uint32_t index, const v8::PropertyDescriptor& desc,
1827 : const v8::PropertyCallbackInfo<v8::Value>& info) {
1828 6 : CHECK(!desc.has_writable());
1829 6 : CHECK(!desc.has_value());
1830 6 : CHECK(desc.has_enumerable());
1831 6 : CHECK(desc.enumerable());
1832 6 : CHECK(!desc.has_configurable());
1833 6 : CHECK(desc.has_get());
1834 12 : CHECK(desc.get()->IsFunction());
1835 6 : CHECK(desc.has_set());
1836 12 : CHECK(desc.set()->IsUndefined());
1837 : // intercept the callback by setting a non-empty handle
1838 : info.GetReturnValue().Set(index);
1839 6 : }
1840 : } // namespace
1841 :
1842 26645 : THREADED_TEST(PropertyDefinerCallbackIndexed) {
1843 12 : v8::HandleScope scope(CcTest::isolate());
1844 6 : LocalContext env;
1845 :
1846 : { // Intercept defineProperty()
1847 : v8::Local<v8::FunctionTemplate> templ =
1848 6 : v8::FunctionTemplate::New(CcTest::isolate());
1849 12 : templ->InstanceTemplate()->SetHandler(
1850 : v8::IndexedPropertyHandlerConfiguration(
1851 : nullptr, nullptr, nullptr, nullptr, nullptr,
1852 6 : NotInterceptingPropertyDefineCallbackIndexed));
1853 12 : env->Global()
1854 18 : ->Set(env.local(), v8_str("obj"), templ->GetFunction(env.local())
1855 : .ToLocalChecked()
1856 : ->NewInstance(env.local())
1857 12 : .ToLocalChecked())
1858 : .FromJust();
1859 : const char* code =
1860 : "obj[2] = 17; "
1861 : "Object.defineProperty(obj, 2, {value: 42});"
1862 : "obj[2];";
1863 18 : CHECK_EQ(42, v8_compile(code)
1864 : ->Run(env.local())
1865 : .ToLocalChecked()
1866 : ->Int32Value(env.local())
1867 : .FromJust());
1868 : }
1869 :
1870 : { // Intercept defineProperty() for correct accessor descriptor
1871 : v8::Local<v8::FunctionTemplate> templ =
1872 6 : v8::FunctionTemplate::New(CcTest::isolate());
1873 12 : templ->InstanceTemplate()->SetHandler(
1874 : v8::IndexedPropertyHandlerConfiguration(
1875 : nullptr, nullptr, nullptr, nullptr, nullptr,
1876 6 : CheckDescriptorInDefineCallbackIndexed));
1877 12 : env->Global()
1878 18 : ->Set(env.local(), v8_str("obj"), templ->GetFunction(env.local())
1879 : .ToLocalChecked()
1880 : ->NewInstance(env.local())
1881 12 : .ToLocalChecked())
1882 : .FromJust();
1883 : const char* code =
1884 : "obj[2] = 17; "
1885 : "Object.defineProperty(obj, 2, {"
1886 : "get: function(){ return 42; }, "
1887 : "set: undefined,"
1888 : "enumerable: true"
1889 : "});"
1890 : "obj[2];";
1891 18 : CHECK_EQ(17, v8_compile(code)
1892 : ->Run(env.local())
1893 : .ToLocalChecked()
1894 : ->Int32Value(env.local())
1895 : .FromJust());
1896 : }
1897 :
1898 : { // Do not intercept defineProperty()
1899 : v8::Local<v8::FunctionTemplate> templ2 =
1900 6 : v8::FunctionTemplate::New(CcTest::isolate());
1901 12 : templ2->InstanceTemplate()->SetHandler(
1902 : v8::IndexedPropertyHandlerConfiguration(
1903 : nullptr, nullptr, nullptr, nullptr, nullptr,
1904 6 : InterceptingPropertyDefineCallbackIndexed));
1905 12 : env->Global()
1906 18 : ->Set(env.local(), v8_str("obj"), templ2->GetFunction(env.local())
1907 : .ToLocalChecked()
1908 : ->NewInstance(env.local())
1909 12 : .ToLocalChecked())
1910 : .FromJust();
1911 :
1912 : const char* code =
1913 : "obj[2] = 17; "
1914 : "Object.defineProperty(obj, 2, {value: 42});"
1915 : "obj[2];";
1916 18 : CHECK_EQ(17, v8_compile(code)
1917 : ->Run(env.local())
1918 : .ToLocalChecked()
1919 : ->Int32Value(env.local())
1920 : .FromJust());
1921 : }
1922 6 : }
1923 :
1924 : // Test that freeze() is intercepted.
1925 26645 : THREADED_TEST(PropertyDefinerCallbackForFreeze) {
1926 6 : v8::Isolate* isolate = CcTest::isolate();
1927 12 : v8::HandleScope scope(isolate);
1928 6 : LocalContext env;
1929 6 : v8::Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
1930 12 : templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
1931 : nullptr, nullptr, nullptr, nullptr, nullptr,
1932 6 : InterceptingPropertyDefineCallback));
1933 12 : env->Global()
1934 18 : ->Set(env.local(), v8_str("obj"), templ->GetFunction(env.local())
1935 : .ToLocalChecked()
1936 : ->NewInstance(env.local())
1937 12 : .ToLocalChecked())
1938 : .FromJust();
1939 : const char* code =
1940 : "obj.x = 17; "
1941 : "Object.freeze(obj.x); "
1942 : "Object.isFrozen(obj.x);";
1943 :
1944 12 : CHECK(v8_compile(code)
1945 : ->Run(env.local())
1946 : .ToLocalChecked()
1947 : ->BooleanValue(isolate));
1948 6 : }
1949 :
1950 : // Check that the descriptor passed to the callback is enumerable.
1951 : namespace {
1952 6 : void CheckEnumerablePropertyDefineCallback(
1953 : Local<Name> name, const v8::PropertyDescriptor& desc,
1954 : const v8::PropertyCallbackInfo<v8::Value>& info) {
1955 6 : CHECK(desc.has_value());
1956 18 : CHECK_EQ(42, desc.value()
1957 : ->Int32Value(info.GetIsolate()->GetCurrentContext())
1958 : .FromJust());
1959 6 : CHECK(desc.has_enumerable());
1960 6 : CHECK(desc.enumerable());
1961 6 : CHECK(!desc.has_writable());
1962 :
1963 : // intercept the callback by setting a non-empty handle
1964 : info.GetReturnValue().Set(name);
1965 6 : }
1966 : } // namespace
1967 26645 : THREADED_TEST(PropertyDefinerCallbackEnumerable) {
1968 12 : v8::HandleScope scope(CcTest::isolate());
1969 6 : LocalContext env;
1970 : v8::Local<v8::FunctionTemplate> templ =
1971 6 : v8::FunctionTemplate::New(CcTest::isolate());
1972 12 : templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
1973 : nullptr, nullptr, nullptr, nullptr, nullptr,
1974 6 : CheckEnumerablePropertyDefineCallback));
1975 12 : env->Global()
1976 18 : ->Set(env.local(), v8_str("obj"), templ->GetFunction(env.local())
1977 : .ToLocalChecked()
1978 : ->NewInstance(env.local())
1979 12 : .ToLocalChecked())
1980 : .FromJust();
1981 : const char* code =
1982 : "obj.x = 17; "
1983 : "Object.defineProperty(obj, 'x', {value: 42, enumerable: true});"
1984 : "obj.x;";
1985 18 : CHECK_EQ(17, v8_compile(code)
1986 : ->Run(env.local())
1987 : .ToLocalChecked()
1988 : ->Int32Value(env.local())
1989 : .FromJust());
1990 6 : }
1991 :
1992 : // Check that the descriptor passed to the callback is configurable.
1993 : namespace {
1994 6 : void CheckConfigurablePropertyDefineCallback(
1995 : Local<Name> name, const v8::PropertyDescriptor& desc,
1996 : const v8::PropertyCallbackInfo<v8::Value>& info) {
1997 6 : CHECK(desc.has_value());
1998 18 : CHECK_EQ(42, desc.value()
1999 : ->Int32Value(info.GetIsolate()->GetCurrentContext())
2000 : .FromJust());
2001 6 : CHECK(desc.has_configurable());
2002 6 : CHECK(desc.configurable());
2003 :
2004 : // intercept the callback by setting a non-empty handle
2005 : info.GetReturnValue().Set(name);
2006 6 : }
2007 : } // namespace
2008 26645 : THREADED_TEST(PropertyDefinerCallbackConfigurable) {
2009 12 : v8::HandleScope scope(CcTest::isolate());
2010 6 : LocalContext env;
2011 : v8::Local<v8::FunctionTemplate> templ =
2012 6 : v8::FunctionTemplate::New(CcTest::isolate());
2013 12 : templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
2014 : nullptr, nullptr, nullptr, nullptr, nullptr,
2015 6 : CheckConfigurablePropertyDefineCallback));
2016 12 : env->Global()
2017 18 : ->Set(env.local(), v8_str("obj"), templ->GetFunction(env.local())
2018 : .ToLocalChecked()
2019 : ->NewInstance(env.local())
2020 12 : .ToLocalChecked())
2021 : .FromJust();
2022 : const char* code =
2023 : "obj.x = 17; "
2024 : "Object.defineProperty(obj, 'x', {value: 42, configurable: true});"
2025 : "obj.x;";
2026 18 : CHECK_EQ(17, v8_compile(code)
2027 : ->Run(env.local())
2028 : .ToLocalChecked()
2029 : ->Int32Value(env.local())
2030 : .FromJust());
2031 6 : }
2032 :
2033 : // Check that the descriptor passed to the callback is writable.
2034 : namespace {
2035 6 : void CheckWritablePropertyDefineCallback(
2036 : Local<Name> name, const v8::PropertyDescriptor& desc,
2037 : const v8::PropertyCallbackInfo<v8::Value>& info) {
2038 6 : CHECK(desc.has_writable());
2039 6 : CHECK(desc.writable());
2040 :
2041 : // intercept the callback by setting a non-empty handle
2042 : info.GetReturnValue().Set(name);
2043 6 : }
2044 : } // namespace
2045 26645 : THREADED_TEST(PropertyDefinerCallbackWritable) {
2046 12 : v8::HandleScope scope(CcTest::isolate());
2047 6 : LocalContext env;
2048 : v8::Local<v8::FunctionTemplate> templ =
2049 6 : v8::FunctionTemplate::New(CcTest::isolate());
2050 12 : templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
2051 : nullptr, nullptr, nullptr, nullptr, nullptr,
2052 6 : CheckWritablePropertyDefineCallback));
2053 12 : env->Global()
2054 18 : ->Set(env.local(), v8_str("obj"), templ->GetFunction(env.local())
2055 : .ToLocalChecked()
2056 : ->NewInstance(env.local())
2057 12 : .ToLocalChecked())
2058 : .FromJust();
2059 : const char* code =
2060 : "obj.x = 17; "
2061 : "Object.defineProperty(obj, 'x', {value: 42, writable: true});"
2062 : "obj.x;";
2063 18 : CHECK_EQ(17, v8_compile(code)
2064 : ->Run(env.local())
2065 : .ToLocalChecked()
2066 : ->Int32Value(env.local())
2067 : .FromJust());
2068 6 : }
2069 :
2070 : // Check that the descriptor passed to the callback has a getter.
2071 : namespace {
2072 6 : void CheckGetterPropertyDefineCallback(
2073 : Local<Name> name, const v8::PropertyDescriptor& desc,
2074 : const v8::PropertyCallbackInfo<v8::Value>& info) {
2075 6 : CHECK(desc.has_get());
2076 6 : CHECK(!desc.has_set());
2077 : // intercept the callback by setting a non-empty handle
2078 : info.GetReturnValue().Set(name);
2079 6 : }
2080 : } // namespace
2081 26645 : THREADED_TEST(PropertyDefinerCallbackWithGetter) {
2082 12 : v8::HandleScope scope(CcTest::isolate());
2083 6 : LocalContext env;
2084 : v8::Local<v8::FunctionTemplate> templ =
2085 6 : v8::FunctionTemplate::New(CcTest::isolate());
2086 12 : templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
2087 : nullptr, nullptr, nullptr, nullptr, nullptr,
2088 6 : CheckGetterPropertyDefineCallback));
2089 12 : env->Global()
2090 18 : ->Set(env.local(), v8_str("obj"), templ->GetFunction(env.local())
2091 : .ToLocalChecked()
2092 : ->NewInstance(env.local())
2093 12 : .ToLocalChecked())
2094 : .FromJust();
2095 : const char* code =
2096 : "obj.x = 17;"
2097 : "Object.defineProperty(obj, 'x', {get: function() {return 42;}});"
2098 : "obj.x;";
2099 18 : CHECK_EQ(17, v8_compile(code)
2100 : ->Run(env.local())
2101 : .ToLocalChecked()
2102 : ->Int32Value(env.local())
2103 : .FromJust());
2104 6 : }
2105 :
2106 : // Check that the descriptor passed to the callback has a setter.
2107 : namespace {
2108 6 : void CheckSetterPropertyDefineCallback(
2109 : Local<Name> name, const v8::PropertyDescriptor& desc,
2110 : const v8::PropertyCallbackInfo<v8::Value>& info) {
2111 6 : CHECK(desc.has_set());
2112 6 : CHECK(!desc.has_get());
2113 : // intercept the callback by setting a non-empty handle
2114 : info.GetReturnValue().Set(name);
2115 6 : }
2116 : } // namespace
2117 26645 : THREADED_TEST(PropertyDefinerCallbackWithSetter) {
2118 12 : v8::HandleScope scope(CcTest::isolate());
2119 6 : LocalContext env;
2120 : v8::Local<v8::FunctionTemplate> templ =
2121 6 : v8::FunctionTemplate::New(CcTest::isolate());
2122 12 : templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
2123 : nullptr, nullptr, nullptr, nullptr, nullptr,
2124 6 : CheckSetterPropertyDefineCallback));
2125 12 : env->Global()
2126 18 : ->Set(env.local(), v8_str("obj"), templ->GetFunction(env.local())
2127 : .ToLocalChecked()
2128 : ->NewInstance(env.local())
2129 12 : .ToLocalChecked())
2130 : .FromJust();
2131 : const char* code =
2132 : "Object.defineProperty(obj, 'x', {set: function() {return 42;}});"
2133 : "obj.x = 17;";
2134 18 : CHECK_EQ(17, v8_compile(code)
2135 : ->Run(env.local())
2136 : .ToLocalChecked()
2137 : ->Int32Value(env.local())
2138 : .FromJust());
2139 6 : }
2140 :
2141 : namespace {
2142 6 : void EmptyPropertyDescriptorCallback(
2143 : Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2144 : // Do not intercept by not calling info.GetReturnValue().Set().
2145 6 : }
2146 :
2147 6 : void InterceptingPropertyDescriptorCallback(
2148 : Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2149 : // Intercept the callback by setting a different descriptor.
2150 : const char* code =
2151 : "var desc = {value: 42};"
2152 : "desc;";
2153 : Local<Value> descriptor = v8_compile(code)
2154 12 : ->Run(info.GetIsolate()->GetCurrentContext())
2155 : .ToLocalChecked();
2156 : info.GetReturnValue().Set(descriptor);
2157 6 : }
2158 : } // namespace
2159 :
2160 26645 : THREADED_TEST(PropertyDescriptorCallback) {
2161 12 : v8::HandleScope scope(CcTest::isolate());
2162 6 : LocalContext env;
2163 :
2164 : { // Normal behavior of getOwnPropertyDescriptor() with empty callback.
2165 : v8::Local<v8::FunctionTemplate> templ =
2166 6 : v8::FunctionTemplate::New(CcTest::isolate());
2167 12 : templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
2168 : nullptr, nullptr, EmptyPropertyDescriptorCallback, nullptr, nullptr,
2169 6 : nullptr));
2170 12 : env->Global()
2171 18 : ->Set(env.local(), v8_str("obj"), templ->GetFunction(env.local())
2172 : .ToLocalChecked()
2173 : ->NewInstance(env.local())
2174 12 : .ToLocalChecked())
2175 : .FromJust();
2176 : const char* code =
2177 : "obj.x = 17; "
2178 : "var desc = Object.getOwnPropertyDescriptor(obj, 'x');"
2179 : "desc.value;";
2180 18 : CHECK_EQ(17, v8_compile(code)
2181 : ->Run(env.local())
2182 : .ToLocalChecked()
2183 : ->Int32Value(env.local())
2184 : .FromJust());
2185 : }
2186 :
2187 : { // Intercept getOwnPropertyDescriptor().
2188 : v8::Local<v8::FunctionTemplate> templ =
2189 6 : v8::FunctionTemplate::New(CcTest::isolate());
2190 12 : templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
2191 : nullptr, nullptr, InterceptingPropertyDescriptorCallback, nullptr,
2192 6 : nullptr, nullptr));
2193 12 : env->Global()
2194 18 : ->Set(env.local(), v8_str("obj"), templ->GetFunction(env.local())
2195 : .ToLocalChecked()
2196 : ->NewInstance(env.local())
2197 12 : .ToLocalChecked())
2198 : .FromJust();
2199 : const char* code =
2200 : "obj.x = 17; "
2201 : "var desc = Object.getOwnPropertyDescriptor(obj, 'x');"
2202 : "desc.value;";
2203 18 : CHECK_EQ(42, v8_compile(code)
2204 : ->Run(env.local())
2205 : .ToLocalChecked()
2206 : ->Int32Value(env.local())
2207 : .FromJust());
2208 : }
2209 6 : }
2210 :
2211 : namespace {
2212 : int echo_indexed_call_count = 0;
2213 : } // namespace
2214 :
2215 6 : static void EchoIndexedProperty(
2216 : uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) {
2217 6 : ApiTestFuzzer::Fuzz();
2218 18 : CHECK(v8_num(637)
2219 : ->Equals(info.GetIsolate()->GetCurrentContext(), info.Data())
2220 : .FromJust());
2221 6 : echo_indexed_call_count++;
2222 6 : info.GetReturnValue().Set(v8_num(index));
2223 6 : }
2224 :
2225 :
2226 26645 : THREADED_TEST(IndexedPropertyHandlerGetter) {
2227 6 : v8::Isolate* isolate = CcTest::isolate();
2228 12 : v8::HandleScope scope(isolate);
2229 6 : v8::Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2230 18 : templ->InstanceTemplate()->SetHandler(v8::IndexedPropertyHandlerConfiguration(
2231 6 : EchoIndexedProperty, nullptr, nullptr, nullptr, nullptr, v8_num(637)));
2232 6 : LocalContext env;
2233 12 : env->Global()
2234 18 : ->Set(env.local(), v8_str("obj"), templ->GetFunction(env.local())
2235 : .ToLocalChecked()
2236 : ->NewInstance(env.local())
2237 12 : .ToLocalChecked())
2238 : .FromJust();
2239 : Local<Script> script = v8_compile("obj[900]");
2240 18 : CHECK_EQ(900, script->Run(env.local())
2241 : .ToLocalChecked()
2242 : ->Int32Value(env.local())
2243 : .FromJust());
2244 6 : }
2245 :
2246 :
2247 26645 : THREADED_TEST(PropertyHandlerInPrototype) {
2248 6 : LocalContext env;
2249 6 : v8::Isolate* isolate = env->GetIsolate();
2250 12 : v8::HandleScope scope(isolate);
2251 :
2252 6 : v8::Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2253 12 : templ->InstanceTemplate()->SetHandler(v8::IndexedPropertyHandlerConfiguration(
2254 : CheckThisIndexedPropertyHandler, CheckThisIndexedPropertySetter,
2255 : CheckThisIndexedPropertyQuery, CheckThisIndexedPropertyDeleter,
2256 6 : CheckThisIndexedPropertyEnumerator));
2257 :
2258 12 : templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
2259 : CheckThisNamedPropertyHandler, CheckThisNamedPropertySetter,
2260 : CheckThisNamedPropertyQuery, CheckThisNamedPropertyDeleter,
2261 6 : CheckThisNamedPropertyEnumerator));
2262 :
2263 6 : bottom = templ->GetFunction(env.local())
2264 : .ToLocalChecked()
2265 : ->NewInstance(env.local())
2266 6 : .ToLocalChecked();
2267 6 : Local<v8::Object> top = templ->GetFunction(env.local())
2268 : .ToLocalChecked()
2269 : ->NewInstance(env.local())
2270 : .ToLocalChecked();
2271 6 : Local<v8::Object> middle = templ->GetFunction(env.local())
2272 : .ToLocalChecked()
2273 : ->NewInstance(env.local())
2274 : .ToLocalChecked();
2275 :
2276 12 : bottom->SetPrototype(env.local(), middle).FromJust();
2277 12 : middle->SetPrototype(env.local(), top).FromJust();
2278 24 : env->Global()->Set(env.local(), v8_str("obj"), bottom).FromJust();
2279 :
2280 : // Indexed and named get.
2281 : CompileRun("obj[0]");
2282 : CompileRun("obj.x");
2283 :
2284 : // Indexed and named set.
2285 : CompileRun("obj[1] = 42");
2286 : CompileRun("obj.y = 42");
2287 :
2288 : // Indexed and named query.
2289 : CompileRun("0 in obj");
2290 : CompileRun("'x' in obj");
2291 :
2292 : // Indexed and named deleter.
2293 : CompileRun("delete obj[0]");
2294 : CompileRun("delete obj.x");
2295 :
2296 : // Enumerators.
2297 : CompileRun("for (var p in obj) ;");
2298 6 : }
2299 :
2300 26644 : TEST(PropertyHandlerInPrototypeWithDefine) {
2301 5 : LocalContext env;
2302 5 : v8::Isolate* isolate = env->GetIsolate();
2303 10 : v8::HandleScope scope(isolate);
2304 :
2305 5 : v8::Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2306 10 : templ->InstanceTemplate()->SetHandler(v8::IndexedPropertyHandlerConfiguration(
2307 : CheckThisIndexedPropertyHandler, CheckThisIndexedPropertySetter,
2308 : CheckThisIndexedPropertyDescriptor, CheckThisIndexedPropertyDeleter,
2309 5 : CheckThisIndexedPropertyEnumerator, CheckThisIndexedPropertyDefiner));
2310 :
2311 10 : templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
2312 : CheckThisNamedPropertyHandler, CheckThisNamedPropertySetter,
2313 : CheckThisNamedPropertyDescriptor, CheckThisNamedPropertyDeleter,
2314 5 : CheckThisNamedPropertyEnumerator, CheckThisNamedPropertyDefiner));
2315 :
2316 5 : bottom = templ->GetFunction(env.local())
2317 : .ToLocalChecked()
2318 : ->NewInstance(env.local())
2319 5 : .ToLocalChecked();
2320 5 : Local<v8::Object> top = templ->GetFunction(env.local())
2321 : .ToLocalChecked()
2322 : ->NewInstance(env.local())
2323 : .ToLocalChecked();
2324 5 : Local<v8::Object> middle = templ->GetFunction(env.local())
2325 : .ToLocalChecked()
2326 : ->NewInstance(env.local())
2327 : .ToLocalChecked();
2328 :
2329 10 : bottom->SetPrototype(env.local(), middle).FromJust();
2330 10 : middle->SetPrototype(env.local(), top).FromJust();
2331 20 : env->Global()->Set(env.local(), v8_str("obj"), bottom).FromJust();
2332 :
2333 : // Indexed and named get.
2334 : CompileRun("obj[0]");
2335 : CompileRun("obj.x");
2336 :
2337 : // Indexed and named set.
2338 : CompileRun("obj[1] = 42");
2339 : CompileRun("obj.y = 42");
2340 :
2341 : // Indexed and named deleter.
2342 : CompileRun("delete obj[0]");
2343 : CompileRun("delete obj.x");
2344 :
2345 : // Enumerators.
2346 : CompileRun("for (var p in obj) ;");
2347 :
2348 : // Indexed and named definer.
2349 : CompileRun("Object.defineProperty(obj, 2, {});");
2350 : CompileRun("Object.defineProperty(obj, 'z', {});");
2351 :
2352 : // Indexed and named propertyDescriptor.
2353 : CompileRun("Object.getOwnPropertyDescriptor(obj, 2);");
2354 : CompileRun("Object.getOwnPropertyDescriptor(obj, 'z');");
2355 5 : }
2356 :
2357 :
2358 : bool is_bootstrapping = false;
2359 18 : static void PrePropertyHandlerGet(
2360 : Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>& info) {
2361 18 : ApiTestFuzzer::Fuzz();
2362 36 : if (!is_bootstrapping &&
2363 18 : v8_str("pre")
2364 36 : ->Equals(info.GetIsolate()->GetCurrentContext(), key)
2365 : .FromJust()) {
2366 6 : info.GetReturnValue().Set(v8_str("PrePropertyHandler: pre"));
2367 : }
2368 18 : }
2369 :
2370 :
2371 0 : static void PrePropertyHandlerQuery(
2372 : Local<Name> key, const v8::PropertyCallbackInfo<v8::Integer>& info) {
2373 0 : if (!is_bootstrapping &&
2374 0 : v8_str("pre")
2375 0 : ->Equals(info.GetIsolate()->GetCurrentContext(), key)
2376 : .FromJust()) {
2377 : info.GetReturnValue().Set(static_cast<int32_t>(v8::None));
2378 : }
2379 0 : }
2380 :
2381 :
2382 26645 : THREADED_TEST(PrePropertyHandler) {
2383 6 : v8::Isolate* isolate = CcTest::isolate();
2384 12 : v8::HandleScope scope(isolate);
2385 6 : v8::Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
2386 12 : desc->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
2387 6 : PrePropertyHandlerGet, nullptr, PrePropertyHandlerQuery));
2388 6 : is_bootstrapping = true;
2389 12 : LocalContext env(nullptr, desc->InstanceTemplate());
2390 6 : is_bootstrapping = false;
2391 : CompileRun("var pre = 'Object: pre'; var on = 'Object: on';");
2392 6 : v8::Local<Value> result_pre = CompileRun("pre");
2393 18 : CHECK(v8_str("PrePropertyHandler: pre")
2394 : ->Equals(env.local(), result_pre)
2395 : .FromJust());
2396 6 : v8::Local<Value> result_on = CompileRun("on");
2397 18 : CHECK(v8_str("Object: on")->Equals(env.local(), result_on).FromJust());
2398 : v8::Local<Value> result_post = CompileRun("post");
2399 6 : CHECK(result_post.IsEmpty());
2400 6 : }
2401 :
2402 :
2403 26645 : THREADED_TEST(EmptyInterceptorBreakTransitions) {
2404 12 : v8::HandleScope scope(CcTest::isolate());
2405 6 : Local<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2406 6 : AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
2407 6 : LocalContext env;
2408 12 : env->Global()
2409 12 : ->Set(env.local(), v8_str("Constructor"),
2410 18 : templ->GetFunction(env.local()).ToLocalChecked())
2411 : .FromJust();
2412 : CompileRun(
2413 : "var o1 = new Constructor;"
2414 : "o1.a = 1;" // Ensure a and x share the descriptor array.
2415 : "Object.defineProperty(o1, 'x', {value: 10});");
2416 : CompileRun(
2417 : "var o2 = new Constructor;"
2418 : "o2.a = 1;"
2419 : "Object.defineProperty(o2, 'x', {value: 10});");
2420 6 : }
2421 :
2422 :
2423 26645 : THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) {
2424 6 : v8::Isolate* isolate = CcTest::isolate();
2425 12 : v8::HandleScope scope(isolate);
2426 6 : Local<FunctionTemplate> parent = FunctionTemplate::New(isolate);
2427 6 : Local<FunctionTemplate> child = FunctionTemplate::New(isolate);
2428 6 : child->Inherit(parent);
2429 6 : AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
2430 6 : LocalContext env;
2431 12 : env->Global()
2432 12 : ->Set(env.local(), v8_str("Child"),
2433 18 : child->GetFunction(env.local()).ToLocalChecked())
2434 : .FromJust();
2435 : CompileRun(
2436 : "var child = new Child;"
2437 : "var parent = child.__proto__;"
2438 : "Object.defineProperty(parent, 'age', "
2439 : " {get: function(){ return this.accessor_age; }, "
2440 : " set: function(v){ this.accessor_age = v; }, "
2441 : " enumerable: true, configurable: true});"
2442 : "child.age = 10;");
2443 6 : ExpectBoolean("child.hasOwnProperty('age')", false);
2444 6 : ExpectInt32("child.age", 10);
2445 6 : ExpectInt32("child.accessor_age", 10);
2446 6 : }
2447 :
2448 :
2449 26645 : THREADED_TEST(EmptyInterceptorDoesNotShadowApiAccessors) {
2450 6 : v8::Isolate* isolate = CcTest::isolate();
2451 12 : v8::HandleScope scope(isolate);
2452 6 : Local<FunctionTemplate> parent = FunctionTemplate::New(isolate);
2453 6 : auto returns_42 = FunctionTemplate::New(isolate, Returns42);
2454 18 : parent->PrototypeTemplate()->SetAccessorProperty(v8_str("age"), returns_42);
2455 6 : Local<FunctionTemplate> child = FunctionTemplate::New(isolate);
2456 6 : child->Inherit(parent);
2457 6 : AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
2458 6 : LocalContext env;
2459 12 : env->Global()
2460 12 : ->Set(env.local(), v8_str("Child"),
2461 18 : child->GetFunction(env.local()).ToLocalChecked())
2462 : .FromJust();
2463 : CompileRun(
2464 : "var child = new Child;"
2465 : "var parent = child.__proto__;");
2466 6 : ExpectBoolean("child.hasOwnProperty('age')", false);
2467 6 : ExpectInt32("child.age", 42);
2468 : // Check interceptor followup.
2469 : ExpectInt32(
2470 : "var result;"
2471 : "for (var i = 0; i < 4; ++i) {"
2472 : " result = child.age;"
2473 : "}"
2474 : "result",
2475 6 : 42);
2476 6 : }
2477 :
2478 :
2479 26645 : THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) {
2480 6 : v8::Isolate* isolate = CcTest::isolate();
2481 12 : v8::HandleScope scope(isolate);
2482 6 : Local<FunctionTemplate> parent = FunctionTemplate::New(isolate);
2483 6 : Local<FunctionTemplate> child = FunctionTemplate::New(isolate);
2484 6 : child->Inherit(parent);
2485 6 : AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
2486 6 : LocalContext env;
2487 12 : env->Global()
2488 12 : ->Set(env.local(), v8_str("Child"),
2489 18 : child->GetFunction(env.local()).ToLocalChecked())
2490 : .FromJust();
2491 : CompileRun(
2492 : "var child = new Child;"
2493 : "var parent = child.__proto__;"
2494 : "parent.name = 'Alice';");
2495 6 : ExpectBoolean("child.hasOwnProperty('name')", false);
2496 6 : ExpectString("child.name", "Alice");
2497 : CompileRun("child.name = 'Bob';");
2498 6 : ExpectString("child.name", "Bob");
2499 6 : ExpectBoolean("child.hasOwnProperty('name')", true);
2500 6 : ExpectString("parent.name", "Alice");
2501 6 : }
2502 :
2503 :
2504 26645 : THREADED_TEST(SwitchFromInterceptorToAccessor) {
2505 12 : v8::HandleScope scope(CcTest::isolate());
2506 6 : Local<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2507 6 : AddAccessor(templ, v8_str("age"), SimpleAccessorGetter, SimpleAccessorSetter);
2508 6 : AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2509 6 : LocalContext env;
2510 12 : env->Global()
2511 12 : ->Set(env.local(), v8_str("Obj"),
2512 18 : templ->GetFunction(env.local()).ToLocalChecked())
2513 : .FromJust();
2514 : CompileRun(
2515 : "var obj = new Obj;"
2516 : "function setAge(i){ obj.age = i; };"
2517 : "for(var i = 0; i <= 10000; i++) setAge(i);");
2518 : // All i < 10000 go to the interceptor.
2519 6 : ExpectInt32("obj.interceptor_age", 9999);
2520 : // The last i goes to the accessor.
2521 6 : ExpectInt32("obj.accessor_age", 10000);
2522 6 : }
2523 :
2524 :
2525 26645 : THREADED_TEST(SwitchFromAccessorToInterceptor) {
2526 12 : v8::HandleScope scope(CcTest::isolate());
2527 6 : Local<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2528 6 : AddAccessor(templ, v8_str("age"), SimpleAccessorGetter, SimpleAccessorSetter);
2529 6 : AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2530 6 : LocalContext env;
2531 12 : env->Global()
2532 12 : ->Set(env.local(), v8_str("Obj"),
2533 18 : templ->GetFunction(env.local()).ToLocalChecked())
2534 : .FromJust();
2535 : CompileRun(
2536 : "var obj = new Obj;"
2537 : "function setAge(i){ obj.age = i; };"
2538 : "for(var i = 20000; i >= 9999; i--) setAge(i);");
2539 : // All i >= 10000 go to the accessor.
2540 6 : ExpectInt32("obj.accessor_age", 10000);
2541 : // The last i goes to the interceptor.
2542 6 : ExpectInt32("obj.interceptor_age", 9999);
2543 6 : }
2544 :
2545 :
2546 26645 : THREADED_TEST(SwitchFromInterceptorToAccessorWithInheritance) {
2547 12 : v8::HandleScope scope(CcTest::isolate());
2548 6 : Local<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2549 6 : Local<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2550 6 : child->Inherit(parent);
2551 6 : AddAccessor(parent, v8_str("age"), SimpleAccessorGetter,
2552 6 : SimpleAccessorSetter);
2553 6 : AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2554 6 : LocalContext env;
2555 12 : env->Global()
2556 12 : ->Set(env.local(), v8_str("Child"),
2557 18 : child->GetFunction(env.local()).ToLocalChecked())
2558 : .FromJust();
2559 : CompileRun(
2560 : "var child = new Child;"
2561 : "function setAge(i){ child.age = i; };"
2562 : "for(var i = 0; i <= 10000; i++) setAge(i);");
2563 : // All i < 10000 go to the interceptor.
2564 6 : ExpectInt32("child.interceptor_age", 9999);
2565 : // The last i goes to the accessor.
2566 6 : ExpectInt32("child.accessor_age", 10000);
2567 6 : }
2568 :
2569 :
2570 26645 : THREADED_TEST(SwitchFromAccessorToInterceptorWithInheritance) {
2571 12 : v8::HandleScope scope(CcTest::isolate());
2572 6 : Local<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2573 6 : Local<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2574 6 : child->Inherit(parent);
2575 6 : AddAccessor(parent, v8_str("age"), SimpleAccessorGetter,
2576 6 : SimpleAccessorSetter);
2577 6 : AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2578 6 : LocalContext env;
2579 12 : env->Global()
2580 12 : ->Set(env.local(), v8_str("Child"),
2581 18 : child->GetFunction(env.local()).ToLocalChecked())
2582 : .FromJust();
2583 : CompileRun(
2584 : "var child = new Child;"
2585 : "function setAge(i){ child.age = i; };"
2586 : "for(var i = 20000; i >= 9999; i--) setAge(i);");
2587 : // All i >= 10000 go to the accessor.
2588 6 : ExpectInt32("child.accessor_age", 10000);
2589 : // The last i goes to the interceptor.
2590 6 : ExpectInt32("child.interceptor_age", 9999);
2591 6 : }
2592 :
2593 :
2594 26645 : THREADED_TEST(SwitchFromInterceptorToJSAccessor) {
2595 12 : v8::HandleScope scope(CcTest::isolate());
2596 6 : Local<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2597 6 : AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2598 6 : LocalContext env;
2599 12 : env->Global()
2600 12 : ->Set(env.local(), v8_str("Obj"),
2601 18 : templ->GetFunction(env.local()).ToLocalChecked())
2602 : .FromJust();
2603 : CompileRun(
2604 : "var obj = new Obj;"
2605 : "function setter(i) { this.accessor_age = i; };"
2606 : "function getter() { return this.accessor_age; };"
2607 : "function setAge(i) { obj.age = i; };"
2608 : "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
2609 : "for(var i = 0; i <= 10000; i++) setAge(i);");
2610 : // All i < 10000 go to the interceptor.
2611 6 : ExpectInt32("obj.interceptor_age", 9999);
2612 : // The last i goes to the JavaScript accessor.
2613 6 : ExpectInt32("obj.accessor_age", 10000);
2614 : // The installed JavaScript getter is still intact.
2615 : // This last part is a regression test for issue 1651 and relies on the fact
2616 : // that both interceptor and accessor are being installed on the same object.
2617 6 : ExpectInt32("obj.age", 10000);
2618 6 : ExpectBoolean("obj.hasOwnProperty('age')", true);
2619 6 : ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
2620 6 : }
2621 :
2622 :
2623 26645 : THREADED_TEST(SwitchFromJSAccessorToInterceptor) {
2624 12 : v8::HandleScope scope(CcTest::isolate());
2625 6 : Local<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2626 6 : AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2627 6 : LocalContext env;
2628 12 : env->Global()
2629 12 : ->Set(env.local(), v8_str("Obj"),
2630 18 : templ->GetFunction(env.local()).ToLocalChecked())
2631 : .FromJust();
2632 : CompileRun(
2633 : "var obj = new Obj;"
2634 : "function setter(i) { this.accessor_age = i; };"
2635 : "function getter() { return this.accessor_age; };"
2636 : "function setAge(i) { obj.age = i; };"
2637 : "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
2638 : "for(var i = 20000; i >= 9999; i--) setAge(i);");
2639 : // All i >= 10000 go to the accessor.
2640 6 : ExpectInt32("obj.accessor_age", 10000);
2641 : // The last i goes to the interceptor.
2642 6 : ExpectInt32("obj.interceptor_age", 9999);
2643 : // The installed JavaScript getter is still intact.
2644 : // This last part is a regression test for issue 1651 and relies on the fact
2645 : // that both interceptor and accessor are being installed on the same object.
2646 6 : ExpectInt32("obj.age", 10000);
2647 6 : ExpectBoolean("obj.hasOwnProperty('age')", true);
2648 6 : ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
2649 6 : }
2650 :
2651 :
2652 26645 : THREADED_TEST(SwitchFromInterceptorToProperty) {
2653 12 : v8::HandleScope scope(CcTest::isolate());
2654 6 : Local<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2655 6 : Local<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2656 6 : child->Inherit(parent);
2657 6 : AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2658 6 : LocalContext env;
2659 12 : env->Global()
2660 12 : ->Set(env.local(), v8_str("Child"),
2661 18 : child->GetFunction(env.local()).ToLocalChecked())
2662 : .FromJust();
2663 : CompileRun(
2664 : "var child = new Child;"
2665 : "function setAge(i){ child.age = i; };"
2666 : "for(var i = 0; i <= 10000; i++) setAge(i);");
2667 : // All i < 10000 go to the interceptor.
2668 6 : ExpectInt32("child.interceptor_age", 9999);
2669 : // The last i goes to child's own property.
2670 6 : ExpectInt32("child.age", 10000);
2671 6 : }
2672 :
2673 :
2674 26645 : THREADED_TEST(SwitchFromPropertyToInterceptor) {
2675 12 : v8::HandleScope scope(CcTest::isolate());
2676 6 : Local<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2677 6 : Local<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2678 6 : child->Inherit(parent);
2679 6 : AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2680 6 : LocalContext env;
2681 12 : env->Global()
2682 12 : ->Set(env.local(), v8_str("Child"),
2683 18 : child->GetFunction(env.local()).ToLocalChecked())
2684 : .FromJust();
2685 : CompileRun(
2686 : "var child = new Child;"
2687 : "function setAge(i){ child.age = i; };"
2688 : "for(var i = 20000; i >= 9999; i--) setAge(i);");
2689 : // All i >= 10000 go to child's own property.
2690 6 : ExpectInt32("child.age", 10000);
2691 : // The last i goes to the interceptor.
2692 6 : ExpectInt32("child.interceptor_age", 9999);
2693 6 : }
2694 :
2695 :
2696 : static bool interceptor_for_hidden_properties_called;
2697 0 : static void InterceptorForHiddenProperties(
2698 : Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2699 0 : interceptor_for_hidden_properties_called = true;
2700 0 : }
2701 :
2702 26645 : THREADED_TEST(NoSideEffectPropertyHandler) {
2703 6 : v8::Isolate* isolate = CcTest::isolate();
2704 12 : v8::HandleScope scope(isolate);
2705 6 : LocalContext context;
2706 :
2707 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
2708 6 : templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
2709 : EmptyInterceptorGetter, EmptyInterceptorSetter, EmptyInterceptorQuery,
2710 6 : EmptyInterceptorDeleter, EmptyInterceptorEnumerator));
2711 : v8::Local<v8::Object> object =
2712 6 : templ->NewInstance(context.local()).ToLocalChecked();
2713 24 : context->Global()->Set(context.local(), v8_str("obj"), object).FromJust();
2714 :
2715 12 : CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("obj.x"), true).IsEmpty());
2716 12 : CHECK(
2717 : v8::debug::EvaluateGlobal(isolate, v8_str("obj.x = 1"), true).IsEmpty());
2718 12 : CHECK(
2719 : v8::debug::EvaluateGlobal(isolate, v8_str("'x' in obj"), true).IsEmpty());
2720 12 : CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("delete obj.x"), true)
2721 : .IsEmpty());
2722 : // Wrap the variable declaration since declaring globals is a side effect.
2723 12 : CHECK(v8::debug::EvaluateGlobal(
2724 : isolate, v8_str("(function() { for (var p in obj) ; })()"), true)
2725 : .IsEmpty());
2726 :
2727 : // Side-effect-free version.
2728 6 : Local<ObjectTemplate> templ2 = ObjectTemplate::New(isolate);
2729 6 : templ2->SetHandler(v8::NamedPropertyHandlerConfiguration(
2730 : EmptyInterceptorGetter, EmptyInterceptorSetter, EmptyInterceptorQuery,
2731 : EmptyInterceptorDeleter, EmptyInterceptorEnumerator,
2732 6 : v8::Local<v8::Value>(), v8::PropertyHandlerFlags::kHasNoSideEffect));
2733 : v8::Local<v8::Object> object2 =
2734 6 : templ2->NewInstance(context.local()).ToLocalChecked();
2735 24 : context->Global()->Set(context.local(), v8_str("obj2"), object2).FromJust();
2736 :
2737 6 : v8::debug::EvaluateGlobal(isolate, v8_str("obj2.x"), true).ToLocalChecked();
2738 12 : CHECK(
2739 : v8::debug::EvaluateGlobal(isolate, v8_str("obj2.x = 1"), true).IsEmpty());
2740 6 : v8::debug::EvaluateGlobal(isolate, v8_str("'x' in obj2"), true)
2741 : .ToLocalChecked();
2742 12 : CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("delete obj2.x"), true)
2743 : .IsEmpty());
2744 6 : v8::debug::EvaluateGlobal(
2745 6 : isolate, v8_str("(function() { for (var p in obj2) ; })()"), true)
2746 : .ToLocalChecked();
2747 6 : }
2748 :
2749 26645 : THREADED_TEST(HiddenPropertiesWithInterceptors) {
2750 6 : LocalContext context;
2751 6 : v8::Isolate* isolate = context->GetIsolate();
2752 12 : v8::HandleScope scope(isolate);
2753 :
2754 6 : interceptor_for_hidden_properties_called = false;
2755 :
2756 : v8::Local<v8::Private> key =
2757 6 : v8::Private::New(isolate, v8_str("api-test::hidden-key"));
2758 :
2759 : // Associate an interceptor with an object and start setting hidden values.
2760 6 : Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
2761 6 : Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
2762 6 : instance_templ->SetHandler(
2763 6 : v8::NamedPropertyHandlerConfiguration(InterceptorForHiddenProperties));
2764 : Local<v8::Function> function =
2765 6 : fun_templ->GetFunction(context.local()).ToLocalChecked();
2766 : Local<v8::Object> obj =
2767 : function->NewInstance(context.local()).ToLocalChecked();
2768 18 : CHECK(obj->SetPrivate(context.local(), key, v8::Integer::New(isolate, 2302))
2769 : .FromJust());
2770 18 : CHECK_EQ(2302, obj->GetPrivate(context.local(), key)
2771 : .ToLocalChecked()
2772 : ->Int32Value(context.local())
2773 : .FromJust());
2774 6 : CHECK(!interceptor_for_hidden_properties_called);
2775 6 : }
2776 :
2777 :
2778 192 : static void XPropertyGetter(Local<Name> property,
2779 : const v8::PropertyCallbackInfo<v8::Value>& info) {
2780 192 : ApiTestFuzzer::Fuzz();
2781 192 : CHECK(info.Data()->IsUndefined());
2782 : info.GetReturnValue().Set(property);
2783 192 : }
2784 :
2785 :
2786 26645 : THREADED_TEST(NamedInterceptorPropertyRead) {
2787 6 : v8::Isolate* isolate = CcTest::isolate();
2788 12 : v8::HandleScope scope(isolate);
2789 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
2790 6 : templ->SetHandler(v8::NamedPropertyHandlerConfiguration(XPropertyGetter));
2791 6 : LocalContext context;
2792 12 : context->Global()
2793 12 : ->Set(context.local(), v8_str("obj"),
2794 18 : templ->NewInstance(context.local()).ToLocalChecked())
2795 : .FromJust();
2796 : Local<Script> script = v8_compile("obj.x");
2797 126 : for (int i = 0; i < 10; i++) {
2798 60 : Local<Value> result = script->Run(context.local()).ToLocalChecked();
2799 180 : CHECK(result->Equals(context.local(), v8_str("x")).FromJust());
2800 : }
2801 6 : }
2802 :
2803 :
2804 26645 : THREADED_TEST(NamedInterceptorDictionaryIC) {
2805 6 : v8::Isolate* isolate = CcTest::isolate();
2806 12 : v8::HandleScope scope(isolate);
2807 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
2808 6 : templ->SetHandler(v8::NamedPropertyHandlerConfiguration(XPropertyGetter));
2809 6 : LocalContext context;
2810 : // Create an object with a named interceptor.
2811 12 : context->Global()
2812 12 : ->Set(context.local(), v8_str("interceptor_obj"),
2813 18 : templ->NewInstance(context.local()).ToLocalChecked())
2814 : .FromJust();
2815 : Local<Script> script = v8_compile("interceptor_obj.x");
2816 126 : for (int i = 0; i < 10; i++) {
2817 60 : Local<Value> result = script->Run(context.local()).ToLocalChecked();
2818 180 : CHECK(result->Equals(context.local(), v8_str("x")).FromJust());
2819 : }
2820 : // Create a slow case object and a function accessing a property in
2821 : // that slow case object (with dictionary probing in generated
2822 : // code). Then force object with a named interceptor into slow-case,
2823 : // pass it to the function, and check that the interceptor is called
2824 : // instead of accessing the local property.
2825 : Local<Value> result = CompileRun(
2826 : "function get_x(o) { return o.x; };"
2827 : "var obj = { x : 42, y : 0 };"
2828 : "delete obj.y;"
2829 : "for (var i = 0; i < 10; i++) get_x(obj);"
2830 : "interceptor_obj.x = 42;"
2831 : "interceptor_obj.y = 10;"
2832 : "delete interceptor_obj.y;"
2833 : "get_x(interceptor_obj)");
2834 18 : CHECK(result->Equals(context.local(), v8_str("x")).FromJust());
2835 6 : }
2836 :
2837 :
2838 26645 : THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
2839 6 : v8::Isolate* isolate = CcTest::isolate();
2840 12 : v8::HandleScope scope(isolate);
2841 6 : v8::Local<Context> context1 = Context::New(isolate);
2842 :
2843 6 : context1->Enter();
2844 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
2845 6 : templ->SetHandler(v8::NamedPropertyHandlerConfiguration(XPropertyGetter));
2846 : // Create an object with a named interceptor.
2847 6 : v8::Local<v8::Object> object = templ->NewInstance(context1).ToLocalChecked();
2848 12 : context1->Global()
2849 24 : ->Set(context1, v8_str("interceptor_obj"), object)
2850 : .FromJust();
2851 :
2852 : // Force the object into the slow case.
2853 : CompileRun(
2854 : "interceptor_obj.y = 0;"
2855 : "delete interceptor_obj.y;");
2856 6 : context1->Exit();
2857 :
2858 : {
2859 : // Introduce the object into a different context.
2860 : // Repeat named loads to exercise ICs.
2861 6 : LocalContext context2;
2862 12 : context2->Global()
2863 24 : ->Set(context2.local(), v8_str("interceptor_obj"), object)
2864 : .FromJust();
2865 : Local<Value> result = CompileRun(
2866 : "function get_x(o) { return o.x; }"
2867 : "interceptor_obj.x = 42;"
2868 : "for (var i=0; i != 10; i++) {"
2869 : " get_x(interceptor_obj);"
2870 : "}"
2871 : "get_x(interceptor_obj)");
2872 : // Check that the interceptor was actually invoked.
2873 18 : CHECK(result->Equals(context2.local(), v8_str("x")).FromJust());
2874 : }
2875 :
2876 : // Return to the original context and force some object to the slow case
2877 : // to cause the NormalizedMapCache to verify.
2878 6 : context1->Enter();
2879 : CompileRun("var obj = { x : 0 }; delete obj.x;");
2880 6 : context1->Exit();
2881 6 : }
2882 :
2883 :
2884 6 : static void SetXOnPrototypeGetter(
2885 : Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {
2886 : // Set x on the prototype object and do not handle the get request.
2887 6 : v8::Local<v8::Value> proto = info.Holder()->GetPrototype();
2888 : proto.As<v8::Object>()
2889 12 : ->Set(info.GetIsolate()->GetCurrentContext(), v8_str("x"),
2890 24 : v8::Integer::New(info.GetIsolate(), 23))
2891 : .FromJust();
2892 6 : }
2893 :
2894 :
2895 : // This is a regression test for http://crbug.com/20104. Map
2896 : // transitions should not interfere with post interceptor lookup.
2897 26645 : THREADED_TEST(NamedInterceptorMapTransitionRead) {
2898 6 : v8::Isolate* isolate = CcTest::isolate();
2899 12 : v8::HandleScope scope(isolate);
2900 : Local<v8::FunctionTemplate> function_template =
2901 6 : v8::FunctionTemplate::New(isolate);
2902 : Local<v8::ObjectTemplate> instance_template =
2903 6 : function_template->InstanceTemplate();
2904 6 : instance_template->SetHandler(
2905 6 : v8::NamedPropertyHandlerConfiguration(SetXOnPrototypeGetter));
2906 6 : LocalContext context;
2907 12 : context->Global()
2908 12 : ->Set(context.local(), v8_str("F"),
2909 18 : function_template->GetFunction(context.local()).ToLocalChecked())
2910 : .FromJust();
2911 : // Create an instance of F and introduce a map transition for x.
2912 : CompileRun("var o = new F(); o.x = 23;");
2913 : // Create an instance of F and invoke the getter. The result should be 23.
2914 : Local<Value> result = CompileRun("o = new F(); o.x");
2915 12 : CHECK_EQ(23, result->Int32Value(context.local()).FromJust());
2916 6 : }
2917 :
2918 :
2919 30 : static void IndexedPropertyGetter(
2920 : uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) {
2921 30 : ApiTestFuzzer::Fuzz();
2922 30 : if (index == 37) {
2923 6 : info.GetReturnValue().Set(v8_num(625));
2924 : }
2925 30 : }
2926 :
2927 :
2928 12 : static void IndexedPropertySetter(
2929 : uint32_t index, Local<Value> value,
2930 : const v8::PropertyCallbackInfo<v8::Value>& info) {
2931 12 : ApiTestFuzzer::Fuzz();
2932 12 : if (index == 39) {
2933 : info.GetReturnValue().Set(value);
2934 : }
2935 12 : }
2936 :
2937 :
2938 26645 : THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
2939 6 : v8::Isolate* isolate = CcTest::isolate();
2940 12 : v8::HandleScope scope(isolate);
2941 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
2942 6 : templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
2943 6 : IndexedPropertyGetter, IndexedPropertySetter));
2944 6 : LocalContext context;
2945 12 : context->Global()
2946 12 : ->Set(context.local(), v8_str("obj"),
2947 18 : templ->NewInstance(context.local()).ToLocalChecked())
2948 : .FromJust();
2949 : Local<Script> getter_script =
2950 : v8_compile("obj.__defineGetter__(\"3\", function(){return 5;});obj[3];");
2951 : Local<Script> setter_script = v8_compile(
2952 : "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
2953 : "obj[17] = 23;"
2954 : "obj.foo;");
2955 : Local<Script> interceptor_setter_script = v8_compile(
2956 : "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
2957 : "obj[39] = 47;"
2958 : "obj.foo;"); // This setter should not run, due to the interceptor.
2959 : Local<Script> interceptor_getter_script = v8_compile("obj[37];");
2960 12 : Local<Value> result = getter_script->Run(context.local()).ToLocalChecked();
2961 18 : CHECK(v8_num(5)->Equals(context.local(), result).FromJust());
2962 12 : result = setter_script->Run(context.local()).ToLocalChecked();
2963 18 : CHECK(v8_num(23)->Equals(context.local(), result).FromJust());
2964 12 : result = interceptor_setter_script->Run(context.local()).ToLocalChecked();
2965 18 : CHECK(v8_num(23)->Equals(context.local(), result).FromJust());
2966 12 : result = interceptor_getter_script->Run(context.local()).ToLocalChecked();
2967 18 : CHECK(v8_num(625)->Equals(context.local(), result).FromJust());
2968 6 : }
2969 :
2970 :
2971 240078 : static void UnboxedDoubleIndexedPropertyGetter(
2972 : uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) {
2973 240078 : ApiTestFuzzer::Fuzz();
2974 240078 : if (index < 25) {
2975 150 : info.GetReturnValue().Set(v8_num(index));
2976 : }
2977 240078 : }
2978 :
2979 :
2980 65634 : static void UnboxedDoubleIndexedPropertySetter(
2981 : uint32_t index, Local<Value> value,
2982 : const v8::PropertyCallbackInfo<v8::Value>& info) {
2983 65634 : ApiTestFuzzer::Fuzz();
2984 65634 : if (index < 25) {
2985 78 : info.GetReturnValue().Set(v8_num(index));
2986 : }
2987 65634 : }
2988 :
2989 :
2990 6 : void UnboxedDoubleIndexedPropertyEnumerator(
2991 : const v8::PropertyCallbackInfo<v8::Array>& info) {
2992 : // Force the list of returned keys to be stored in a FastDoubleArray.
2993 : Local<Script> indexed_property_names_script = v8_compile(
2994 : "keys = new Array(); keys[125000] = 1;"
2995 : "for(i = 0; i < 80000; i++) { keys[i] = i; };"
2996 : "keys.length = 25; keys;");
2997 : Local<Value> result =
2998 6 : indexed_property_names_script->Run(info.GetIsolate()->GetCurrentContext())
2999 : .ToLocalChecked();
3000 : info.GetReturnValue().Set(Local<v8::Array>::Cast(result));
3001 6 : }
3002 :
3003 :
3004 : // Make sure that the the interceptor code in the runtime properly handles
3005 : // merging property name lists for double-array-backed arrays.
3006 26645 : THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
3007 6 : v8::Isolate* isolate = CcTest::isolate();
3008 12 : v8::HandleScope scope(isolate);
3009 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
3010 6 : templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
3011 : UnboxedDoubleIndexedPropertyGetter, UnboxedDoubleIndexedPropertySetter,
3012 6 : nullptr, nullptr, UnboxedDoubleIndexedPropertyEnumerator));
3013 6 : LocalContext context;
3014 12 : context->Global()
3015 12 : ->Set(context.local(), v8_str("obj"),
3016 18 : templ->NewInstance(context.local()).ToLocalChecked())
3017 : .FromJust();
3018 : // When obj is created, force it to be Stored in a FastDoubleArray.
3019 : Local<Script> create_unboxed_double_script = v8_compile(
3020 : "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
3021 : "key_count = 0; "
3022 : "for (x in obj) {key_count++;};"
3023 : "obj;");
3024 : Local<Value> result =
3025 6 : create_unboxed_double_script->Run(context.local()).ToLocalChecked();
3026 18 : CHECK(result->ToObject(context.local())
3027 : .ToLocalChecked()
3028 : ->HasRealIndexedProperty(context.local(), 2000)
3029 : .FromJust());
3030 : Local<Script> key_count_check = v8_compile("key_count;");
3031 6 : result = key_count_check->Run(context.local()).ToLocalChecked();
3032 18 : CHECK(v8_num(40013)->Equals(context.local(), result).FromJust());
3033 6 : }
3034 :
3035 :
3036 78 : void SloppyArgsIndexedPropertyEnumerator(
3037 : const v8::PropertyCallbackInfo<v8::Array>& info) {
3038 : // Force the list of returned keys to be stored in a Arguments object.
3039 : Local<Script> indexed_property_names_script = v8_compile(
3040 : "function f(w,x) {"
3041 : " return arguments;"
3042 : "}"
3043 : "keys = f(0, 1, 2, 3);"
3044 : "keys;");
3045 : Local<Object> result = Local<Object>::Cast(
3046 78 : indexed_property_names_script->Run(info.GetIsolate()->GetCurrentContext())
3047 : .ToLocalChecked());
3048 : // Have to populate the handle manually, as it's not Cast-able.
3049 : i::Handle<i::JSReceiver> o =
3050 : v8::Utils::OpenHandle<Object, i::JSReceiver>(result);
3051 : i::Handle<i::JSArray> array(i::JSArray::unchecked_cast(*o), o->GetIsolate());
3052 : info.GetReturnValue().Set(v8::Utils::ToLocal(array));
3053 78 : }
3054 :
3055 :
3056 24 : static void SloppyIndexedPropertyGetter(
3057 : uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) {
3058 24 : ApiTestFuzzer::Fuzz();
3059 24 : if (index < 4) {
3060 24 : info.GetReturnValue().Set(v8_num(index));
3061 : }
3062 24 : }
3063 :
3064 :
3065 : // Make sure that the the interceptor code in the runtime properly handles
3066 : // merging property name lists for non-string arguments arrays.
3067 26645 : THREADED_TEST(IndexedInterceptorSloppyArgsWithIndexedAccessor) {
3068 6 : v8::Isolate* isolate = CcTest::isolate();
3069 12 : v8::HandleScope scope(isolate);
3070 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
3071 6 : templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
3072 : SloppyIndexedPropertyGetter, nullptr, nullptr, nullptr,
3073 6 : SloppyArgsIndexedPropertyEnumerator));
3074 6 : LocalContext context;
3075 12 : context->Global()
3076 12 : ->Set(context.local(), v8_str("obj"),
3077 18 : templ->NewInstance(context.local()).ToLocalChecked())
3078 : .FromJust();
3079 : Local<Script> create_args_script = v8_compile(
3080 : "var key_count = 0;"
3081 : "for (x in obj) {key_count++;} key_count;");
3082 : Local<Value> result =
3083 12 : create_args_script->Run(context.local()).ToLocalChecked();
3084 18 : CHECK(v8_num(4)->Equals(context.local(), result).FromJust());
3085 6 : }
3086 :
3087 :
3088 10188 : static void IdentityIndexedPropertyGetter(
3089 : uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) {
3090 : info.GetReturnValue().Set(index);
3091 10188 : }
3092 :
3093 :
3094 26645 : THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
3095 6 : v8::Isolate* isolate = CcTest::isolate();
3096 12 : v8::HandleScope scope(isolate);
3097 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
3098 6 : templ->SetHandler(
3099 6 : v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
3100 :
3101 6 : LocalContext context;
3102 12 : context->Global()
3103 12 : ->Set(context.local(), v8_str("obj"),
3104 18 : templ->NewInstance(context.local()).ToLocalChecked())
3105 : .FromJust();
3106 :
3107 : // Check fast object case.
3108 : const char* fast_case_code =
3109 : "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
3110 6 : ExpectString(fast_case_code, "0");
3111 :
3112 : // Check slow case.
3113 : const char* slow_case_code =
3114 : "obj.x = 1; delete obj.x;"
3115 : "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
3116 6 : ExpectString(slow_case_code, "1");
3117 6 : }
3118 :
3119 :
3120 26645 : THREADED_TEST(IndexedInterceptorWithNoSetter) {
3121 6 : v8::Isolate* isolate = CcTest::isolate();
3122 12 : v8::HandleScope scope(isolate);
3123 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
3124 6 : templ->SetHandler(
3125 6 : v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
3126 :
3127 6 : LocalContext context;
3128 12 : context->Global()
3129 12 : ->Set(context.local(), v8_str("obj"),
3130 18 : templ->NewInstance(context.local()).ToLocalChecked())
3131 : .FromJust();
3132 :
3133 : const char* code =
3134 : "try {"
3135 : " obj[0] = 239;"
3136 : " for (var i = 0; i < 100; i++) {"
3137 : " var v = obj[0];"
3138 : " if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
3139 : " }"
3140 : " 'PASSED'"
3141 : "} catch(e) {"
3142 : " e"
3143 : "}";
3144 6 : ExpectString(code, "PASSED");
3145 6 : }
3146 :
3147 600 : static bool AccessAlwaysBlocked(Local<v8::Context> accessing_context,
3148 : Local<v8::Object> accessed_object,
3149 : Local<v8::Value> data) {
3150 600 : return false;
3151 : }
3152 :
3153 :
3154 26645 : THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
3155 6 : v8::Isolate* isolate = CcTest::isolate();
3156 12 : v8::HandleScope scope(isolate);
3157 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
3158 6 : templ->SetHandler(
3159 6 : v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
3160 :
3161 6 : templ->SetAccessCheckCallback(AccessAlwaysBlocked);
3162 :
3163 6 : LocalContext context;
3164 6 : Local<v8::Object> obj = templ->NewInstance(context.local()).ToLocalChecked();
3165 24 : context->Global()->Set(context.local(), v8_str("obj"), obj).FromJust();
3166 :
3167 : const char* code =
3168 : "var result = 'PASSED';"
3169 : "for (var i = 0; i < 100; i++) {"
3170 : " try {"
3171 : " var v = obj[0];"
3172 : " result = 'Wrong value ' + v + ' at iteration ' + i;"
3173 : " break;"
3174 : " } catch (e) {"
3175 : " /* pass */"
3176 : " }"
3177 : "}"
3178 : "result";
3179 6 : ExpectString(code, "PASSED");
3180 6 : }
3181 :
3182 :
3183 26645 : THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
3184 6 : v8::Isolate* isolate = CcTest::isolate();
3185 12 : v8::HandleScope scope(isolate);
3186 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
3187 6 : templ->SetHandler(
3188 6 : v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
3189 :
3190 6 : LocalContext context;
3191 6 : Local<v8::Object> obj = templ->NewInstance(context.local()).ToLocalChecked();
3192 24 : context->Global()->Set(context.local(), v8_str("obj"), obj).FromJust();
3193 :
3194 : const char* code =
3195 : "try {"
3196 : " for (var i = 0; i < 100; i++) {"
3197 : " var v = obj[i];"
3198 : " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
3199 : " }"
3200 : " 'PASSED'"
3201 : "} catch(e) {"
3202 : " e"
3203 : "}";
3204 6 : ExpectString(code, "PASSED");
3205 6 : }
3206 :
3207 :
3208 26645 : THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
3209 6 : v8::Isolate* isolate = CcTest::isolate();
3210 12 : v8::HandleScope scope(isolate);
3211 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
3212 6 : templ->SetHandler(
3213 6 : v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
3214 :
3215 6 : LocalContext context;
3216 6 : Local<v8::Object> obj = templ->NewInstance(context.local()).ToLocalChecked();
3217 24 : context->Global()->Set(context.local(), v8_str("obj"), obj).FromJust();
3218 :
3219 : const char* code =
3220 : "try {"
3221 : " for (var i = 0; i < 100; i++) {"
3222 : " var expected = i;"
3223 : " var key = i;"
3224 : " if (i == 25) {"
3225 : " key = -1;"
3226 : " expected = undefined;"
3227 : " }"
3228 : " if (i == 50) {"
3229 : " /* probe minimal Smi number on 32-bit platforms */"
3230 : " key = -(1 << 30);"
3231 : " expected = undefined;"
3232 : " }"
3233 : " if (i == 75) {"
3234 : " /* probe minimal Smi number on 64-bit platforms */"
3235 : " key = 1 << 31;"
3236 : " expected = undefined;"
3237 : " }"
3238 : " var v = obj[key];"
3239 : " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3240 : " }"
3241 : " 'PASSED'"
3242 : "} catch(e) {"
3243 : " e"
3244 : "}";
3245 6 : ExpectString(code, "PASSED");
3246 6 : }
3247 :
3248 :
3249 26645 : THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
3250 6 : v8::Isolate* isolate = CcTest::isolate();
3251 12 : v8::HandleScope scope(isolate);
3252 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
3253 6 : templ->SetHandler(
3254 6 : v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
3255 :
3256 6 : LocalContext context;
3257 6 : Local<v8::Object> obj = templ->NewInstance(context.local()).ToLocalChecked();
3258 24 : context->Global()->Set(context.local(), v8_str("obj"), obj).FromJust();
3259 :
3260 : const char* code =
3261 : "try {"
3262 : " for (var i = 0; i < 100; i++) {"
3263 : " var expected = i;"
3264 : " var key = i;"
3265 : " if (i == 50) {"
3266 : " key = 'foobar';"
3267 : " expected = undefined;"
3268 : " }"
3269 : " var v = obj[key];"
3270 : " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3271 : " }"
3272 : " 'PASSED'"
3273 : "} catch(e) {"
3274 : " e"
3275 : "}";
3276 6 : ExpectString(code, "PASSED");
3277 6 : }
3278 :
3279 :
3280 26645 : THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
3281 6 : v8::Isolate* isolate = CcTest::isolate();
3282 12 : v8::HandleScope scope(isolate);
3283 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
3284 6 : templ->SetHandler(
3285 6 : v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
3286 :
3287 6 : LocalContext context;
3288 6 : Local<v8::Object> obj = templ->NewInstance(context.local()).ToLocalChecked();
3289 24 : context->Global()->Set(context.local(), v8_str("obj"), obj).FromJust();
3290 :
3291 : const char* code =
3292 : "var original = obj;"
3293 : "try {"
3294 : " for (var i = 0; i < 100; i++) {"
3295 : " var expected = i;"
3296 : " if (i == 50) {"
3297 : " obj = {50: 'foobar'};"
3298 : " expected = 'foobar';"
3299 : " }"
3300 : " var v = obj[i];"
3301 : " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3302 : " if (i == 50) obj = original;"
3303 : " }"
3304 : " 'PASSED'"
3305 : "} catch(e) {"
3306 : " e"
3307 : "}";
3308 6 : ExpectString(code, "PASSED");
3309 6 : }
3310 :
3311 :
3312 26645 : THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
3313 6 : v8::Isolate* isolate = CcTest::isolate();
3314 12 : v8::HandleScope scope(isolate);
3315 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
3316 6 : templ->SetHandler(
3317 6 : v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
3318 :
3319 6 : LocalContext context;
3320 6 : Local<v8::Object> obj = templ->NewInstance(context.local()).ToLocalChecked();
3321 24 : context->Global()->Set(context.local(), v8_str("obj"), obj).FromJust();
3322 :
3323 : const char* code =
3324 : "var original = obj;"
3325 : "try {"
3326 : " for (var i = 0; i < 100; i++) {"
3327 : " var expected = i;"
3328 : " if (i == 5) {"
3329 : " obj = 239;"
3330 : " expected = undefined;"
3331 : " }"
3332 : " var v = obj[i];"
3333 : " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3334 : " if (i == 5) obj = original;"
3335 : " }"
3336 : " 'PASSED'"
3337 : "} catch(e) {"
3338 : " e"
3339 : "}";
3340 6 : ExpectString(code, "PASSED");
3341 6 : }
3342 :
3343 :
3344 26645 : THREADED_TEST(IndexedInterceptorOnProto) {
3345 6 : v8::Isolate* isolate = CcTest::isolate();
3346 12 : v8::HandleScope scope(isolate);
3347 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
3348 6 : templ->SetHandler(
3349 6 : v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
3350 :
3351 6 : LocalContext context;
3352 6 : Local<v8::Object> obj = templ->NewInstance(context.local()).ToLocalChecked();
3353 24 : context->Global()->Set(context.local(), v8_str("obj"), obj).FromJust();
3354 :
3355 : const char* code =
3356 : "var o = {__proto__: obj};"
3357 : "try {"
3358 : " for (var i = 0; i < 100; i++) {"
3359 : " var v = o[i];"
3360 : " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
3361 : " }"
3362 : " 'PASSED'"
3363 : "} catch(e) {"
3364 : " e"
3365 : "}";
3366 6 : ExpectString(code, "PASSED");
3367 6 : }
3368 :
3369 : namespace {
3370 :
3371 36 : void CheckIndexedInterceptorHasIC(v8::IndexedPropertyGetterCallback getter,
3372 : v8::IndexedPropertyQueryCallback query,
3373 : const char* source, int expected) {
3374 36 : v8::Isolate* isolate = CcTest::isolate();
3375 72 : v8::HandleScope scope(isolate);
3376 36 : v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
3377 72 : templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
3378 36 : getter, nullptr, query, nullptr, nullptr, v8_str("data")));
3379 36 : LocalContext context;
3380 72 : context->Global()
3381 72 : ->Set(context.local(), v8_str("o"),
3382 108 : templ->NewInstance(context.local()).ToLocalChecked())
3383 : .FromJust();
3384 : v8::Local<Value> value = CompileRun(source);
3385 72 : CHECK_EQ(expected, value->Int32Value(context.local()).FromJust());
3386 36 : }
3387 :
3388 : int indexed_query_counter = 0;
3389 6000 : void IndexedQueryCallback(uint32_t index,
3390 : const v8::PropertyCallbackInfo<v8::Integer>& info) {
3391 6000 : indexed_query_counter++;
3392 6000 : }
3393 :
3394 6000 : void IndexHasICQueryAbsent(uint32_t index,
3395 : const v8::PropertyCallbackInfo<v8::Integer>& info) {
3396 6000 : ApiTestFuzzer::Fuzz();
3397 6000 : v8::Isolate* isolate = CcTest::isolate();
3398 6000 : CHECK_EQ(isolate, info.GetIsolate());
3399 6000 : info.GetReturnValue().Set(v8::Integer::New(isolate, v8::internal::ABSENT));
3400 6000 : }
3401 :
3402 : } // namespace
3403 :
3404 26645 : THREADED_TEST(IndexedInterceptorHasIC) {
3405 6 : indexed_query_counter = 0;
3406 : CheckIndexedInterceptorHasIC(nullptr, IndexedQueryCallback,
3407 : "var result = 0;"
3408 : "for (var i = 0; i < 1000; i++) {"
3409 : " i in o;"
3410 : "}",
3411 6 : 0);
3412 6 : CHECK_EQ(1000, indexed_query_counter);
3413 6 : }
3414 :
3415 26645 : THREADED_TEST(IndexedInterceptorHasICQueryAbsent) {
3416 : CheckIndexedInterceptorHasIC(nullptr,
3417 : // HasICQuery<uint32_t, v8::internal::ABSENT>,
3418 : IndexHasICQueryAbsent,
3419 : "var result = 0;"
3420 : "for (var i = 0; i < 1000; i++) {"
3421 : " if (i in o) ++result;"
3422 : "}",
3423 6 : 0);
3424 6 : }
3425 :
3426 26645 : THREADED_TEST(IndexedInterceptorHasICQueryNone) {
3427 : CheckIndexedInterceptorHasIC(nullptr,
3428 : HasICQuery<uint32_t, v8::internal::NONE>,
3429 : "var result = 0;"
3430 : "for (var i = 0; i < 1000; i++) {"
3431 : " if (i in o) ++result;"
3432 : "}",
3433 6 : 1000);
3434 6 : }
3435 :
3436 26645 : THREADED_TEST(IndexedInterceptorHasICGetter) {
3437 : CheckIndexedInterceptorHasIC(IdentityIndexedPropertyGetter, nullptr,
3438 : "var result = 0;"
3439 : "for (var i = 0; i < 1000; i++) {"
3440 : " if (i in o) ++result;"
3441 : "}",
3442 6 : 1000);
3443 6 : }
3444 :
3445 26645 : THREADED_TEST(IndexedInterceptorHasICQueryGetter) {
3446 : CheckIndexedInterceptorHasIC(IdentityIndexedPropertyGetter,
3447 : HasICQuery<uint32_t, v8::internal::ABSENT>,
3448 : "var result = 0;"
3449 : "for (var i = 0; i < 1000; i++) {"
3450 : " if (i in o) ++result;"
3451 : "}",
3452 6 : 0);
3453 6 : }
3454 :
3455 26645 : THREADED_TEST(IndexedInterceptorHasICQueryToggle) {
3456 : CheckIndexedInterceptorHasIC(IdentityIndexedPropertyGetter,
3457 : HasICQueryToggle<uint32_t>,
3458 : "var result = 0;"
3459 : "for (var i = 0; i < 1000; i++) {"
3460 : " if (i in o) ++result;"
3461 : "}",
3462 6 : 500);
3463 6 : }
3464 :
3465 6666 : static void NoBlockGetterX(Local<Name> name,
3466 6666 : const v8::PropertyCallbackInfo<v8::Value>&) {}
3467 :
3468 :
3469 12 : static void NoBlockGetterI(uint32_t index,
3470 12 : const v8::PropertyCallbackInfo<v8::Value>&) {}
3471 :
3472 :
3473 12 : static void PDeleter(Local<Name> name,
3474 : const v8::PropertyCallbackInfo<v8::Boolean>& info) {
3475 48 : if (!name->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("foo"))
3476 : .FromJust()) {
3477 : return; // not intercepted
3478 : }
3479 :
3480 : info.GetReturnValue().Set(false); // intercepted, don't delete the property
3481 : }
3482 :
3483 :
3484 12 : static void IDeleter(uint32_t index,
3485 : const v8::PropertyCallbackInfo<v8::Boolean>& info) {
3486 12 : if (index != 2) {
3487 : return; // not intercepted
3488 : }
3489 :
3490 : info.GetReturnValue().Set(false); // intercepted, don't delete the property
3491 : }
3492 :
3493 :
3494 26645 : THREADED_TEST(Deleter) {
3495 6 : v8::Isolate* isolate = CcTest::isolate();
3496 12 : v8::HandleScope scope(isolate);
3497 6 : v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
3498 6 : obj->SetHandler(v8::NamedPropertyHandlerConfiguration(
3499 6 : NoBlockGetterX, nullptr, nullptr, PDeleter, nullptr));
3500 6 : obj->SetHandler(v8::IndexedPropertyHandlerConfiguration(
3501 6 : NoBlockGetterI, nullptr, nullptr, IDeleter, nullptr));
3502 6 : LocalContext context;
3503 12 : context->Global()
3504 12 : ->Set(context.local(), v8_str("k"),
3505 18 : obj->NewInstance(context.local()).ToLocalChecked())
3506 : .FromJust();
3507 : CompileRun(
3508 : "k.foo = 'foo';"
3509 : "k.bar = 'bar';"
3510 : "k[2] = 2;"
3511 : "k[4] = 4;");
3512 12 : CHECK(v8_compile("delete k.foo")
3513 : ->Run(context.local())
3514 : .ToLocalChecked()
3515 : ->IsFalse());
3516 12 : CHECK(v8_compile("delete k.bar")
3517 : ->Run(context.local())
3518 : .ToLocalChecked()
3519 : ->IsTrue());
3520 :
3521 24 : CHECK(v8_compile("k.foo")
3522 : ->Run(context.local())
3523 : .ToLocalChecked()
3524 : ->Equals(context.local(), v8_str("foo"))
3525 : .FromJust());
3526 12 : CHECK(v8_compile("k.bar")
3527 : ->Run(context.local())
3528 : .ToLocalChecked()
3529 : ->IsUndefined());
3530 :
3531 12 : CHECK(v8_compile("delete k[2]")
3532 : ->Run(context.local())
3533 : .ToLocalChecked()
3534 : ->IsFalse());
3535 12 : CHECK(v8_compile("delete k[4]")
3536 : ->Run(context.local())
3537 : .ToLocalChecked()
3538 : ->IsTrue());
3539 :
3540 24 : CHECK(v8_compile("k[2]")
3541 : ->Run(context.local())
3542 : .ToLocalChecked()
3543 : ->Equals(context.local(), v8_num(2))
3544 : .FromJust());
3545 12 : CHECK(
3546 : v8_compile("k[4]")->Run(context.local()).ToLocalChecked()->IsUndefined());
3547 6 : }
3548 :
3549 :
3550 66 : static void GetK(Local<Name> name,
3551 : const v8::PropertyCallbackInfo<v8::Value>& info) {
3552 66 : ApiTestFuzzer::Fuzz();
3553 66 : v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
3554 258 : if (name->Equals(context, v8_str("foo")).FromJust() ||
3555 180 : name->Equals(context, v8_str("bar")).FromJust() ||
3556 108 : name->Equals(context, v8_str("baz")).FromJust()) {
3557 : info.GetReturnValue().SetUndefined();
3558 : }
3559 66 : }
3560 :
3561 :
3562 36 : static void IndexedGetK(uint32_t index,
3563 : const v8::PropertyCallbackInfo<v8::Value>& info) {
3564 36 : ApiTestFuzzer::Fuzz();
3565 36 : if (index == 0 || index == 1) info.GetReturnValue().SetUndefined();
3566 36 : }
3567 :
3568 :
3569 24 : static void NamedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
3570 24 : ApiTestFuzzer::Fuzz();
3571 24 : v8::Local<v8::Array> result = v8::Array::New(info.GetIsolate(), 3);
3572 24 : v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
3573 96 : CHECK(
3574 : result
3575 : ->Set(context, v8::Integer::New(info.GetIsolate(), 0), v8_str("foo"))
3576 : .FromJust());
3577 96 : CHECK(
3578 : result
3579 : ->Set(context, v8::Integer::New(info.GetIsolate(), 1), v8_str("bar"))
3580 : .FromJust());
3581 96 : CHECK(
3582 : result
3583 : ->Set(context, v8::Integer::New(info.GetIsolate(), 2), v8_str("baz"))
3584 : .FromJust());
3585 : info.GetReturnValue().Set(result);
3586 24 : }
3587 :
3588 :
3589 6 : static void IndexedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
3590 6 : ApiTestFuzzer::Fuzz();
3591 6 : v8::Local<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
3592 6 : v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
3593 24 : CHECK(
3594 : result->Set(context, v8::Integer::New(info.GetIsolate(), 0), v8_str("0"))
3595 : .FromJust());
3596 24 : CHECK(
3597 : result->Set(context, v8::Integer::New(info.GetIsolate(), 1), v8_str("1"))
3598 : .FromJust());
3599 : info.GetReturnValue().Set(result);
3600 6 : }
3601 :
3602 :
3603 26645 : THREADED_TEST(Enumerators) {
3604 6 : v8::Isolate* isolate = CcTest::isolate();
3605 12 : v8::HandleScope scope(isolate);
3606 6 : v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
3607 6 : obj->SetHandler(v8::NamedPropertyHandlerConfiguration(GetK, nullptr, nullptr,
3608 6 : nullptr, NamedEnum));
3609 6 : obj->SetHandler(v8::IndexedPropertyHandlerConfiguration(
3610 6 : IndexedGetK, nullptr, nullptr, nullptr, IndexedEnum));
3611 6 : LocalContext context;
3612 12 : context->Global()
3613 12 : ->Set(context.local(), v8_str("k"),
3614 18 : obj->NewInstance(context.local()).ToLocalChecked())
3615 : .FromJust();
3616 : v8::Local<v8::Array> result =
3617 : v8::Local<v8::Array>::Cast(CompileRun("k[10] = 0;"
3618 : "k.a = 0;"
3619 : "k[5] = 0;"
3620 : "k.b = 0;"
3621 : "k[4294967294] = 0;"
3622 : "k.c = 0;"
3623 : "k[4294967295] = 0;"
3624 : "k.d = 0;"
3625 : "k[140000] = 0;"
3626 : "k.e = 0;"
3627 : "k[30000000000] = 0;"
3628 : "k.f = 0;"
3629 : "var result = [];"
3630 : "for (var prop in k) {"
3631 : " result.push(prop);"
3632 : "}"
3633 : "result"));
3634 : // Check that we get all the property names returned including the
3635 : // ones from the enumerators in the right order: indexed properties
3636 : // in numerical order, indexed interceptor properties, named
3637 : // properties in insertion order, named interceptor properties.
3638 : // This order is not mandated by the spec, so this test is just
3639 : // documenting our behavior.
3640 6 : CHECK_EQ(17u, result->Length());
3641 : // Indexed properties.
3642 30 : CHECK(v8_str("5")
3643 : ->Equals(context.local(),
3644 : result->Get(context.local(), v8::Integer::New(isolate, 0))
3645 : .ToLocalChecked())
3646 : .FromJust());
3647 30 : CHECK(v8_str("10")
3648 : ->Equals(context.local(),
3649 : result->Get(context.local(), v8::Integer::New(isolate, 1))
3650 : .ToLocalChecked())
3651 : .FromJust());
3652 30 : CHECK(v8_str("140000")
3653 : ->Equals(context.local(),
3654 : result->Get(context.local(), v8::Integer::New(isolate, 2))
3655 : .ToLocalChecked())
3656 : .FromJust());
3657 30 : CHECK(v8_str("4294967294")
3658 : ->Equals(context.local(),
3659 : result->Get(context.local(), v8::Integer::New(isolate, 3))
3660 : .ToLocalChecked())
3661 : .FromJust());
3662 : // Indexed Interceptor properties
3663 30 : CHECK(v8_str("0")
3664 : ->Equals(context.local(),
3665 : result->Get(context.local(), v8::Integer::New(isolate, 4))
3666 : .ToLocalChecked())
3667 : .FromJust());
3668 30 : CHECK(v8_str("1")
3669 : ->Equals(context.local(),
3670 : result->Get(context.local(), v8::Integer::New(isolate, 5))
3671 : .ToLocalChecked())
3672 : .FromJust());
3673 : // Named properties in insertion order.
3674 30 : CHECK(v8_str("a")
3675 : ->Equals(context.local(),
3676 : result->Get(context.local(), v8::Integer::New(isolate, 6))
3677 : .ToLocalChecked())
3678 : .FromJust());
3679 30 : CHECK(v8_str("b")
3680 : ->Equals(context.local(),
3681 : result->Get(context.local(), v8::Integer::New(isolate, 7))
3682 : .ToLocalChecked())
3683 : .FromJust());
3684 30 : CHECK(v8_str("c")
3685 : ->Equals(context.local(),
3686 : result->Get(context.local(), v8::Integer::New(isolate, 8))
3687 : .ToLocalChecked())
3688 : .FromJust());
3689 30 : CHECK(v8_str("4294967295")
3690 : ->Equals(context.local(),
3691 : result->Get(context.local(), v8::Integer::New(isolate, 9))
3692 : .ToLocalChecked())
3693 : .FromJust());
3694 30 : CHECK(v8_str("d")
3695 : ->Equals(context.local(),
3696 : result->Get(context.local(), v8::Integer::New(isolate, 10))
3697 : .ToLocalChecked())
3698 : .FromJust());
3699 30 : CHECK(v8_str("e")
3700 : ->Equals(context.local(),
3701 : result->Get(context.local(), v8::Integer::New(isolate, 11))
3702 : .ToLocalChecked())
3703 : .FromJust());
3704 30 : CHECK(v8_str("30000000000")
3705 : ->Equals(context.local(),
3706 : result->Get(context.local(), v8::Integer::New(isolate, 12))
3707 : .ToLocalChecked())
3708 : .FromJust());
3709 30 : CHECK(v8_str("f")
3710 : ->Equals(context.local(),
3711 : result->Get(context.local(), v8::Integer::New(isolate, 13))
3712 : .ToLocalChecked())
3713 : .FromJust());
3714 : // Named interceptor properties.
3715 30 : CHECK(v8_str("foo")
3716 : ->Equals(context.local(),
3717 : result->Get(context.local(), v8::Integer::New(isolate, 14))
3718 : .ToLocalChecked())
3719 : .FromJust());
3720 30 : CHECK(v8_str("bar")
3721 : ->Equals(context.local(),
3722 : result->Get(context.local(), v8::Integer::New(isolate, 15))
3723 : .ToLocalChecked())
3724 : .FromJust());
3725 30 : CHECK(v8_str("baz")
3726 : ->Equals(context.local(),
3727 : result->Get(context.local(), v8::Integer::New(isolate, 16))
3728 : .ToLocalChecked())
3729 : .FromJust());
3730 6 : }
3731 :
3732 :
3733 : v8::Local<Value> call_ic_function;
3734 : v8::Local<Value> call_ic_function2;
3735 : v8::Local<Value> call_ic_function3;
3736 :
3737 6000 : static void InterceptorCallICGetter(
3738 : Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
3739 6000 : ApiTestFuzzer::Fuzz();
3740 18000 : CHECK(v8_str("x")
3741 : ->Equals(info.GetIsolate()->GetCurrentContext(), name)
3742 : .FromJust());
3743 : info.GetReturnValue().Set(call_ic_function);
3744 6000 : }
3745 :
3746 :
3747 : // This test should hit the call IC for the interceptor case.
3748 26645 : THREADED_TEST(InterceptorCallIC) {
3749 6 : v8::Isolate* isolate = CcTest::isolate();
3750 12 : v8::HandleScope scope(isolate);
3751 6 : v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
3752 6 : templ->SetHandler(
3753 6 : v8::NamedPropertyHandlerConfiguration(InterceptorCallICGetter));
3754 6 : LocalContext context;
3755 12 : context->Global()
3756 12 : ->Set(context.local(), v8_str("o"),
3757 18 : templ->NewInstance(context.local()).ToLocalChecked())
3758 : .FromJust();
3759 : call_ic_function = v8_compile("function f(x) { return x + 1; }; f")
3760 6 : ->Run(context.local())
3761 6 : .ToLocalChecked();
3762 : v8::Local<Value> value = CompileRun(
3763 : "var result = 0;"
3764 : "for (var i = 0; i < 1000; i++) {"
3765 : " result = o.x(41);"
3766 : "}");
3767 12 : CHECK_EQ(42, value->Int32Value(context.local()).FromJust());
3768 6 : }
3769 :
3770 :
3771 : // This test checks that if interceptor doesn't provide
3772 : // a value, we can fetch regular value.
3773 26645 : THREADED_TEST(InterceptorCallICSeesOthers) {
3774 6 : v8::Isolate* isolate = CcTest::isolate();
3775 12 : v8::HandleScope scope(isolate);
3776 6 : v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
3777 6 : templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
3778 6 : LocalContext context;
3779 12 : context->Global()
3780 12 : ->Set(context.local(), v8_str("o"),
3781 18 : templ->NewInstance(context.local()).ToLocalChecked())
3782 : .FromJust();
3783 : v8::Local<Value> value = CompileRun(
3784 : "o.x = function f(x) { return x + 1; };"
3785 : "var result = 0;"
3786 : "for (var i = 0; i < 7; i++) {"
3787 : " result = o.x(41);"
3788 : "}");
3789 12 : CHECK_EQ(42, value->Int32Value(context.local()).FromJust());
3790 6 : }
3791 :
3792 :
3793 : static v8::Local<Value> call_ic_function4;
3794 6000 : static void InterceptorCallICGetter4(
3795 : Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
3796 6000 : ApiTestFuzzer::Fuzz();
3797 18000 : CHECK(v8_str("x")
3798 : ->Equals(info.GetIsolate()->GetCurrentContext(), name)
3799 : .FromJust());
3800 : info.GetReturnValue().Set(call_ic_function4);
3801 6000 : }
3802 :
3803 :
3804 : // This test checks that if interceptor provides a function,
3805 : // even if we cached shadowed variant, interceptor's function
3806 : // is invoked
3807 26645 : THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
3808 6 : v8::Isolate* isolate = CcTest::isolate();
3809 12 : v8::HandleScope scope(isolate);
3810 6 : v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
3811 6 : templ->SetHandler(
3812 6 : v8::NamedPropertyHandlerConfiguration(InterceptorCallICGetter4));
3813 6 : LocalContext context;
3814 12 : context->Global()
3815 12 : ->Set(context.local(), v8_str("o"),
3816 18 : templ->NewInstance(context.local()).ToLocalChecked())
3817 : .FromJust();
3818 : call_ic_function4 = v8_compile("function f(x) { return x - 1; }; f")
3819 6 : ->Run(context.local())
3820 6 : .ToLocalChecked();
3821 : v8::Local<Value> value = CompileRun(
3822 : "Object.getPrototypeOf(o).x = function(x) { return x + 1; };"
3823 : "var result = 0;"
3824 : "for (var i = 0; i < 1000; i++) {"
3825 : " result = o.x(42);"
3826 : "}");
3827 12 : CHECK_EQ(41, value->Int32Value(context.local()).FromJust());
3828 6 : }
3829 :
3830 :
3831 : // Test the case when we stored cacheable lookup into
3832 : // a stub, but it got invalidated later on
3833 26645 : THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
3834 6 : v8::Isolate* isolate = CcTest::isolate();
3835 12 : v8::HandleScope scope(isolate);
3836 6 : v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
3837 6 : templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
3838 6 : LocalContext context;
3839 12 : context->Global()
3840 12 : ->Set(context.local(), v8_str("o"),
3841 18 : templ->NewInstance(context.local()).ToLocalChecked())
3842 : .FromJust();
3843 : v8::Local<Value> value = CompileRun(
3844 : "proto1 = new Object();"
3845 : "proto2 = new Object();"
3846 : "o.__proto__ = proto1;"
3847 : "proto1.__proto__ = proto2;"
3848 : "proto2.y = function(x) { return x + 1; };"
3849 : // Invoke it many times to compile a stub
3850 : "for (var i = 0; i < 7; i++) {"
3851 : " o.y(42);"
3852 : "}"
3853 : "proto1.y = function(x) { return x - 1; };"
3854 : "var result = 0;"
3855 : "for (var i = 0; i < 7; i++) {"
3856 : " result += o.y(42);"
3857 : "}");
3858 12 : CHECK_EQ(41 * 7, value->Int32Value(context.local()).FromJust());
3859 6 : }
3860 :
3861 :
3862 : // This test checks that if interceptor doesn't provide a function,
3863 : // cached constant function is used
3864 26645 : THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
3865 6 : v8::Isolate* isolate = CcTest::isolate();
3866 12 : v8::HandleScope scope(isolate);
3867 6 : v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
3868 6 : templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
3869 6 : LocalContext context;
3870 12 : context->Global()
3871 12 : ->Set(context.local(), v8_str("o"),
3872 18 : templ->NewInstance(context.local()).ToLocalChecked())
3873 : .FromJust();
3874 : v8::Local<Value> value = CompileRun(
3875 : "function inc(x) { return x + 1; };"
3876 : "inc(1);"
3877 : "o.x = inc;"
3878 : "var result = 0;"
3879 : "for (var i = 0; i < 1000; i++) {"
3880 : " result = o.x(42);"
3881 : "}");
3882 12 : CHECK_EQ(43, value->Int32Value(context.local()).FromJust());
3883 6 : }
3884 :
3885 :
3886 : static v8::Local<Value> call_ic_function5;
3887 6000 : static void InterceptorCallICGetter5(
3888 : Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
3889 6000 : ApiTestFuzzer::Fuzz();
3890 18000 : if (v8_str("x")
3891 24000 : ->Equals(info.GetIsolate()->GetCurrentContext(), name)
3892 : .FromJust())
3893 : info.GetReturnValue().Set(call_ic_function5);
3894 6000 : }
3895 :
3896 :
3897 : // This test checks that if interceptor provides a function,
3898 : // even if we cached constant function, interceptor's function
3899 : // is invoked
3900 26645 : THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
3901 6 : v8::Isolate* isolate = CcTest::isolate();
3902 12 : v8::HandleScope scope(isolate);
3903 6 : v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
3904 6 : templ->SetHandler(
3905 6 : v8::NamedPropertyHandlerConfiguration(InterceptorCallICGetter5));
3906 6 : LocalContext context;
3907 12 : context->Global()
3908 12 : ->Set(context.local(), v8_str("o"),
3909 18 : templ->NewInstance(context.local()).ToLocalChecked())
3910 : .FromJust();
3911 : call_ic_function5 = v8_compile("function f(x) { return x - 1; }; f")
3912 6 : ->Run(context.local())
3913 6 : .ToLocalChecked();
3914 : v8::Local<Value> value = CompileRun(
3915 : "function inc(x) { return x + 1; };"
3916 : "inc(1);"
3917 : "o.x = inc;"
3918 : "var result = 0;"
3919 : "for (var i = 0; i < 1000; i++) {"
3920 : " result = o.x(42);"
3921 : "}");
3922 12 : CHECK_EQ(41, value->Int32Value(context.local()).FromJust());
3923 6 : }
3924 :
3925 :
3926 : static v8::Local<Value> call_ic_function6;
3927 24000 : static void InterceptorCallICGetter6(
3928 : Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
3929 24000 : ApiTestFuzzer::Fuzz();
3930 72000 : if (v8_str("x")
3931 96000 : ->Equals(info.GetIsolate()->GetCurrentContext(), name)
3932 : .FromJust())
3933 : info.GetReturnValue().Set(call_ic_function6);
3934 24000 : }
3935 :
3936 :
3937 : // Same test as above, except the code is wrapped in a function
3938 : // to test the optimized compiler.
3939 26645 : THREADED_TEST(InterceptorCallICConstantFunctionNotNeededWrapped) {
3940 6 : i::FLAG_allow_natives_syntax = true;
3941 6 : v8::Isolate* isolate = CcTest::isolate();
3942 12 : v8::HandleScope scope(isolate);
3943 6 : v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
3944 6 : templ->SetHandler(
3945 6 : v8::NamedPropertyHandlerConfiguration(InterceptorCallICGetter6));
3946 6 : LocalContext context;
3947 12 : context->Global()
3948 12 : ->Set(context.local(), v8_str("o"),
3949 18 : templ->NewInstance(context.local()).ToLocalChecked())
3950 : .FromJust();
3951 : call_ic_function6 = v8_compile("function f(x) { return x - 1; }; f")
3952 6 : ->Run(context.local())
3953 6 : .ToLocalChecked();
3954 : v8::Local<Value> value = CompileRun(
3955 : "function inc(x) { return x + 1; };"
3956 : "inc(1);"
3957 : "o.x = inc;"
3958 : "function test() {"
3959 : " var result = 0;"
3960 : " for (var i = 0; i < 1000; i++) {"
3961 : " result = o.x(42);"
3962 : " }"
3963 : " return result;"
3964 : "};"
3965 : "test();"
3966 : "test();"
3967 : "test();"
3968 : "%OptimizeFunctionOnNextCall(test);"
3969 : "test()");
3970 12 : CHECK_EQ(41, value->Int32Value(context.local()).FromJust());
3971 6 : }
3972 :
3973 :
3974 : // Test the case when we stored constant function into
3975 : // a stub, but it got invalidated later on
3976 26645 : THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
3977 6 : v8::Isolate* isolate = CcTest::isolate();
3978 12 : v8::HandleScope scope(isolate);
3979 6 : v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
3980 6 : templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
3981 6 : LocalContext context;
3982 12 : context->Global()
3983 12 : ->Set(context.local(), v8_str("o"),
3984 18 : templ->NewInstance(context.local()).ToLocalChecked())
3985 : .FromJust();
3986 : v8::Local<Value> value = CompileRun(
3987 : "function inc(x) { return x + 1; };"
3988 : "inc(1);"
3989 : "proto1 = new Object();"
3990 : "proto2 = new Object();"
3991 : "o.__proto__ = proto1;"
3992 : "proto1.__proto__ = proto2;"
3993 : "proto2.y = inc;"
3994 : // Invoke it many times to compile a stub
3995 : "for (var i = 0; i < 7; i++) {"
3996 : " o.y(42);"
3997 : "}"
3998 : "proto1.y = function(x) { return x - 1; };"
3999 : "var result = 0;"
4000 : "for (var i = 0; i < 7; i++) {"
4001 : " result += o.y(42);"
4002 : "}");
4003 12 : CHECK_EQ(41 * 7, value->Int32Value(context.local()).FromJust());
4004 6 : }
4005 :
4006 :
4007 : // Test the case when we stored constant function into
4008 : // a stub, but it got invalidated later on due to override on
4009 : // global object which is between interceptor and constant function' holders.
4010 26645 : THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
4011 6 : v8::Isolate* isolate = CcTest::isolate();
4012 12 : v8::HandleScope scope(isolate);
4013 6 : v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
4014 6 : templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
4015 6 : LocalContext context;
4016 12 : context->Global()
4017 12 : ->Set(context.local(), v8_str("o"),
4018 18 : templ->NewInstance(context.local()).ToLocalChecked())
4019 : .FromJust();
4020 : v8::Local<Value> value = CompileRun(
4021 : "function inc(x) { return x + 1; };"
4022 : "inc(1);"
4023 : "o.__proto__ = this;"
4024 : "this.__proto__.y = inc;"
4025 : // Invoke it many times to compile a stub
4026 : "for (var i = 0; i < 7; i++) {"
4027 : " if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
4028 : "}"
4029 : "this.y = function(x) { return x - 1; };"
4030 : "var result = 0;"
4031 : "for (var i = 0; i < 7; i++) {"
4032 : " result += o.y(42);"
4033 : "}");
4034 12 : CHECK_EQ(41 * 7, value->Int32Value(context.local()).FromJust());
4035 6 : }
4036 :
4037 :
4038 : // Test the case when actual function to call sits on global object.
4039 26645 : THREADED_TEST(InterceptorCallICCachedFromGlobal) {
4040 6 : v8::Isolate* isolate = CcTest::isolate();
4041 12 : v8::HandleScope scope(isolate);
4042 6 : v8::Local<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
4043 6 : templ_o->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
4044 :
4045 6 : LocalContext context;
4046 12 : context->Global()
4047 12 : ->Set(context.local(), v8_str("o"),
4048 18 : templ_o->NewInstance(context.local()).ToLocalChecked())
4049 : .FromJust();
4050 :
4051 : v8::Local<Value> value = CompileRun(
4052 : "try {"
4053 : " o.__proto__ = this;"
4054 : " for (var i = 0; i < 10; i++) {"
4055 : " var v = o.parseFloat('239');"
4056 : " if (v != 239) throw v;"
4057 : // Now it should be ICed and keep a reference to parseFloat.
4058 : " }"
4059 : " var result = 0;"
4060 : " for (var i = 0; i < 10; i++) {"
4061 : " result += o.parseFloat('239');"
4062 : " }"
4063 : " result"
4064 : "} catch(e) {"
4065 : " e"
4066 : "};");
4067 12 : CHECK_EQ(239 * 10, value->Int32Value(context.local()).FromJust());
4068 6 : }
4069 :
4070 :
4071 : v8::Local<Value> keyed_call_ic_function;
4072 :
4073 30 : static void InterceptorKeyedCallICGetter(
4074 : Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
4075 30 : ApiTestFuzzer::Fuzz();
4076 90 : if (v8_str("x")
4077 120 : ->Equals(info.GetIsolate()->GetCurrentContext(), name)
4078 : .FromJust()) {
4079 : info.GetReturnValue().Set(keyed_call_ic_function);
4080 : }
4081 30 : }
4082 :
4083 :
4084 : // Test the case when we stored cacheable lookup into
4085 : // a stub, but the function name changed (to another cacheable function).
4086 26645 : THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
4087 6 : v8::Isolate* isolate = CcTest::isolate();
4088 12 : v8::HandleScope scope(isolate);
4089 6 : v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
4090 6 : templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
4091 6 : LocalContext context;
4092 12 : context->Global()
4093 12 : ->Set(context.local(), v8_str("o"),
4094 18 : templ->NewInstance(context.local()).ToLocalChecked())
4095 : .FromJust();
4096 : CompileRun(
4097 : "proto = new Object();"
4098 : "proto.y = function(x) { return x + 1; };"
4099 : "proto.z = function(x) { return x - 1; };"
4100 : "o.__proto__ = proto;"
4101 : "var result = 0;"
4102 : "var method = 'y';"
4103 : "for (var i = 0; i < 10; i++) {"
4104 : " if (i == 5) { method = 'z'; };"
4105 : " result += o[method](41);"
4106 : "}");
4107 30 : CHECK_EQ(42 * 5 + 40 * 5, context->Global()
4108 : ->Get(context.local(), v8_str("result"))
4109 : .ToLocalChecked()
4110 : ->Int32Value(context.local())
4111 : .FromJust());
4112 6 : }
4113 :
4114 :
4115 : // Test the case when we stored cacheable lookup into
4116 : // a stub, but the function name changed (and the new function is present
4117 : // both before and after the interceptor in the prototype chain).
4118 26645 : THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
4119 6 : v8::Isolate* isolate = CcTest::isolate();
4120 12 : v8::HandleScope scope(isolate);
4121 6 : v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
4122 6 : templ->SetHandler(
4123 6 : v8::NamedPropertyHandlerConfiguration(InterceptorKeyedCallICGetter));
4124 6 : LocalContext context;
4125 12 : context->Global()
4126 12 : ->Set(context.local(), v8_str("proto1"),
4127 18 : templ->NewInstance(context.local()).ToLocalChecked())
4128 : .FromJust();
4129 : keyed_call_ic_function = v8_compile("function f(x) { return x - 1; }; f")
4130 6 : ->Run(context.local())
4131 6 : .ToLocalChecked();
4132 : CompileRun(
4133 : "o = new Object();"
4134 : "proto2 = new Object();"
4135 : "o.y = function(x) { return x + 1; };"
4136 : "proto2.y = function(x) { return x + 2; };"
4137 : "o.__proto__ = proto1;"
4138 : "proto1.__proto__ = proto2;"
4139 : "var result = 0;"
4140 : "var method = 'x';"
4141 : "for (var i = 0; i < 10; i++) {"
4142 : " if (i == 5) { method = 'y'; };"
4143 : " result += o[method](41);"
4144 : "}");
4145 30 : CHECK_EQ(42 * 5 + 40 * 5, context->Global()
4146 : ->Get(context.local(), v8_str("result"))
4147 : .ToLocalChecked()
4148 : ->Int32Value(context.local())
4149 : .FromJust());
4150 6 : }
4151 :
4152 :
4153 : // Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
4154 : // on the global object.
4155 26645 : THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
4156 6 : v8::Isolate* isolate = CcTest::isolate();
4157 12 : v8::HandleScope scope(isolate);
4158 6 : v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
4159 6 : templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
4160 6 : LocalContext context;
4161 12 : context->Global()
4162 12 : ->Set(context.local(), v8_str("o"),
4163 18 : templ->NewInstance(context.local()).ToLocalChecked())
4164 : .FromJust();
4165 : CompileRun(
4166 : "function inc(x) { return x + 1; };"
4167 : "inc(1);"
4168 : "function dec(x) { return x - 1; };"
4169 : "dec(1);"
4170 : "o.__proto__ = this;"
4171 : "this.__proto__.x = inc;"
4172 : "this.__proto__.y = dec;"
4173 : "var result = 0;"
4174 : "var method = 'x';"
4175 : "for (var i = 0; i < 10; i++) {"
4176 : " if (i == 5) { method = 'y'; };"
4177 : " result += o[method](41);"
4178 : "}");
4179 30 : CHECK_EQ(42 * 5 + 40 * 5, context->Global()
4180 : ->Get(context.local(), v8_str("result"))
4181 : .ToLocalChecked()
4182 : ->Int32Value(context.local())
4183 : .FromJust());
4184 6 : }
4185 :
4186 :
4187 : // Test the case when actual function to call sits on global object.
4188 26645 : THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
4189 6 : v8::Isolate* isolate = CcTest::isolate();
4190 12 : v8::HandleScope scope(isolate);
4191 6 : v8::Local<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
4192 6 : templ_o->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
4193 6 : LocalContext context;
4194 12 : context->Global()
4195 12 : ->Set(context.local(), v8_str("o"),
4196 18 : templ_o->NewInstance(context.local()).ToLocalChecked())
4197 : .FromJust();
4198 :
4199 : CompileRun(
4200 : "function len(x) { return x.length; };"
4201 : "o.__proto__ = this;"
4202 : "var m = 'parseFloat';"
4203 : "var result = 0;"
4204 : "for (var i = 0; i < 10; i++) {"
4205 : " if (i == 5) {"
4206 : " m = 'len';"
4207 : " saved_result = result;"
4208 : " };"
4209 : " result = o[m]('239');"
4210 : "}");
4211 30 : CHECK_EQ(3, context->Global()
4212 : ->Get(context.local(), v8_str("result"))
4213 : .ToLocalChecked()
4214 : ->Int32Value(context.local())
4215 : .FromJust());
4216 30 : CHECK_EQ(239, context->Global()
4217 : ->Get(context.local(), v8_str("saved_result"))
4218 : .ToLocalChecked()
4219 : ->Int32Value(context.local())
4220 : .FromJust());
4221 6 : }
4222 :
4223 :
4224 : // Test the map transition before the interceptor.
4225 26645 : THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
4226 6 : v8::Isolate* isolate = CcTest::isolate();
4227 12 : v8::HandleScope scope(isolate);
4228 6 : v8::Local<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
4229 6 : templ_o->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
4230 6 : LocalContext context;
4231 12 : context->Global()
4232 12 : ->Set(context.local(), v8_str("proto"),
4233 18 : templ_o->NewInstance(context.local()).ToLocalChecked())
4234 : .FromJust();
4235 :
4236 : CompileRun(
4237 : "var o = new Object();"
4238 : "o.__proto__ = proto;"
4239 : "o.method = function(x) { return x + 1; };"
4240 : "var m = 'method';"
4241 : "var result = 0;"
4242 : "for (var i = 0; i < 10; i++) {"
4243 : " if (i == 5) { o.method = function(x) { return x - 1; }; };"
4244 : " result += o[m](41);"
4245 : "}");
4246 30 : CHECK_EQ(42 * 5 + 40 * 5, context->Global()
4247 : ->Get(context.local(), v8_str("result"))
4248 : .ToLocalChecked()
4249 : ->Int32Value(context.local())
4250 : .FromJust());
4251 6 : }
4252 :
4253 :
4254 : // Test the map transition after the interceptor.
4255 26645 : THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
4256 6 : v8::Isolate* isolate = CcTest::isolate();
4257 12 : v8::HandleScope scope(isolate);
4258 6 : v8::Local<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
4259 6 : templ_o->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
4260 6 : LocalContext context;
4261 12 : context->Global()
4262 12 : ->Set(context.local(), v8_str("o"),
4263 18 : templ_o->NewInstance(context.local()).ToLocalChecked())
4264 : .FromJust();
4265 :
4266 : CompileRun(
4267 : "var proto = new Object();"
4268 : "o.__proto__ = proto;"
4269 : "proto.method = function(x) { return x + 1; };"
4270 : "var m = 'method';"
4271 : "var result = 0;"
4272 : "for (var i = 0; i < 10; i++) {"
4273 : " if (i == 5) { proto.method = function(x) { return x - 1; }; };"
4274 : " result += o[m](41);"
4275 : "}");
4276 30 : CHECK_EQ(42 * 5 + 40 * 5, context->Global()
4277 : ->Get(context.local(), v8_str("result"))
4278 : .ToLocalChecked()
4279 : ->Int32Value(context.local())
4280 : .FromJust());
4281 6 : }
4282 :
4283 :
4284 : static int interceptor_call_count = 0;
4285 :
4286 288 : static void InterceptorICRefErrorGetter(
4287 : Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
4288 288 : ApiTestFuzzer::Fuzz();
4289 864 : if (!is_bootstrapping &&
4290 288 : v8_str("x")
4291 576 : ->Equals(info.GetIsolate()->GetCurrentContext(), name)
4292 540 : .FromJust() &&
4293 252 : interceptor_call_count++ < 20) {
4294 : info.GetReturnValue().Set(call_ic_function2);
4295 : }
4296 288 : }
4297 :
4298 :
4299 : // This test should hit load and call ICs for the interceptor case.
4300 : // Once in a while, the interceptor will reply that a property was not
4301 : // found in which case we should get a reference error.
4302 26645 : THREADED_TEST(InterceptorICReferenceErrors) {
4303 6 : v8::Isolate* isolate = CcTest::isolate();
4304 12 : v8::HandleScope scope(isolate);
4305 6 : v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
4306 6 : templ->SetHandler(
4307 6 : v8::NamedPropertyHandlerConfiguration(InterceptorICRefErrorGetter));
4308 6 : is_bootstrapping = true;
4309 6 : LocalContext context(nullptr, templ, v8::Local<Value>());
4310 6 : is_bootstrapping = false;
4311 : call_ic_function2 = v8_compile("function h(x) { return x; }; h")
4312 6 : ->Run(context.local())
4313 6 : .ToLocalChecked();
4314 : v8::Local<Value> value = CompileRun(
4315 : "function f() {"
4316 : " for (var i = 0; i < 1000; i++) {"
4317 : " try { x; } catch(e) { return true; }"
4318 : " }"
4319 : " return false;"
4320 : "};"
4321 : "f();");
4322 6 : CHECK(value->BooleanValue(isolate));
4323 6 : interceptor_call_count = 0;
4324 : value = CompileRun(
4325 : "function g() {"
4326 : " for (var i = 0; i < 1000; i++) {"
4327 : " try { x(42); } catch(e) { return true; }"
4328 : " }"
4329 : " return false;"
4330 : "};"
4331 : "g();");
4332 6 : CHECK(value->BooleanValue(isolate));
4333 6 : }
4334 :
4335 :
4336 : static int interceptor_ic_exception_get_count = 0;
4337 :
4338 276 : static void InterceptorICExceptionGetter(
4339 : Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
4340 276 : ApiTestFuzzer::Fuzz();
4341 276 : if (is_bootstrapping) return;
4342 828 : if (v8_str("x")
4343 1104 : ->Equals(info.GetIsolate()->GetCurrentContext(), name)
4344 516 : .FromJust() &&
4345 240 : ++interceptor_ic_exception_get_count < 20) {
4346 : info.GetReturnValue().Set(call_ic_function3);
4347 : }
4348 276 : if (interceptor_ic_exception_get_count == 20) {
4349 24 : info.GetIsolate()->ThrowException(v8_num(42));
4350 12 : return;
4351 : }
4352 : }
4353 :
4354 :
4355 : // Test interceptor load/call IC where the interceptor throws an
4356 : // exception once in a while.
4357 26645 : THREADED_TEST(InterceptorICGetterExceptions) {
4358 6 : interceptor_ic_exception_get_count = 0;
4359 6 : v8::Isolate* isolate = CcTest::isolate();
4360 12 : v8::HandleScope scope(isolate);
4361 6 : v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
4362 6 : templ->SetHandler(
4363 6 : v8::NamedPropertyHandlerConfiguration(InterceptorICExceptionGetter));
4364 6 : is_bootstrapping = true;
4365 6 : LocalContext context(nullptr, templ, v8::Local<Value>());
4366 6 : is_bootstrapping = false;
4367 : call_ic_function3 = v8_compile("function h(x) { return x; }; h")
4368 6 : ->Run(context.local())
4369 6 : .ToLocalChecked();
4370 : v8::Local<Value> value = CompileRun(
4371 : "function f() {"
4372 : " for (var i = 0; i < 100; i++) {"
4373 : " try { x; } catch(e) { return true; }"
4374 : " }"
4375 : " return false;"
4376 : "};"
4377 : "f();");
4378 6 : CHECK(value->BooleanValue(isolate));
4379 6 : interceptor_ic_exception_get_count = 0;
4380 : value = CompileRun(
4381 : "function f() {"
4382 : " for (var i = 0; i < 100; i++) {"
4383 : " try { x(42); } catch(e) { return true; }"
4384 : " }"
4385 : " return false;"
4386 : "};"
4387 : "f();");
4388 6 : CHECK(value->BooleanValue(isolate));
4389 6 : }
4390 :
4391 :
4392 : static int interceptor_ic_exception_set_count = 0;
4393 :
4394 126 : static void InterceptorICExceptionSetter(
4395 : Local<Name> key, Local<Value> value,
4396 : const v8::PropertyCallbackInfo<v8::Value>& info) {
4397 126 : ApiTestFuzzer::Fuzz();
4398 126 : if (++interceptor_ic_exception_set_count > 20) {
4399 12 : info.GetIsolate()->ThrowException(v8_num(42));
4400 : }
4401 126 : }
4402 :
4403 :
4404 : // Test interceptor store IC where the interceptor throws an exception
4405 : // once in a while.
4406 26645 : THREADED_TEST(InterceptorICSetterExceptions) {
4407 6 : interceptor_ic_exception_set_count = 0;
4408 6 : v8::Isolate* isolate = CcTest::isolate();
4409 12 : v8::HandleScope scope(isolate);
4410 6 : v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
4411 6 : templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
4412 6 : nullptr, InterceptorICExceptionSetter));
4413 6 : LocalContext context(nullptr, templ, v8::Local<Value>());
4414 : v8::Local<Value> value = CompileRun(
4415 : "function f() {"
4416 : " for (var i = 0; i < 100; i++) {"
4417 : " try { x = 42; } catch(e) { return true; }"
4418 : " }"
4419 : " return false;"
4420 : "};"
4421 : "f();");
4422 6 : CHECK(value->BooleanValue(isolate));
4423 6 : }
4424 :
4425 :
4426 : // Test that we ignore null interceptors.
4427 26645 : THREADED_TEST(NullNamedInterceptor) {
4428 6 : v8::Isolate* isolate = CcTest::isolate();
4429 12 : v8::HandleScope scope(isolate);
4430 6 : v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
4431 6 : templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
4432 6 : static_cast<v8::GenericNamedPropertyGetterCallback>(nullptr)));
4433 6 : LocalContext context;
4434 6 : templ->Set(CcTest::isolate(), "x", v8_num(42));
4435 : v8::Local<v8::Object> obj =
4436 6 : templ->NewInstance(context.local()).ToLocalChecked();
4437 24 : context->Global()->Set(context.local(), v8_str("obj"), obj).FromJust();
4438 : v8::Local<Value> value = CompileRun("obj.x");
4439 6 : CHECK(value->IsInt32());
4440 12 : CHECK_EQ(42, value->Int32Value(context.local()).FromJust());
4441 6 : }
4442 :
4443 :
4444 : // Test that we ignore null interceptors.
4445 26645 : THREADED_TEST(NullIndexedInterceptor) {
4446 6 : v8::Isolate* isolate = CcTest::isolate();
4447 12 : v8::HandleScope scope(isolate);
4448 6 : v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
4449 6 : templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
4450 6 : static_cast<v8::IndexedPropertyGetterCallback>(nullptr)));
4451 6 : LocalContext context;
4452 6 : templ->Set(CcTest::isolate(), "42", v8_num(42));
4453 : v8::Local<v8::Object> obj =
4454 6 : templ->NewInstance(context.local()).ToLocalChecked();
4455 24 : context->Global()->Set(context.local(), v8_str("obj"), obj).FromJust();
4456 : v8::Local<Value> value = CompileRun("obj[42]");
4457 6 : CHECK(value->IsInt32());
4458 12 : CHECK_EQ(42, value->Int32Value(context.local()).FromJust());
4459 6 : }
4460 :
4461 :
4462 26645 : THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
4463 6 : v8::Isolate* isolate = CcTest::isolate();
4464 12 : v8::HandleScope scope(isolate);
4465 6 : v8::Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
4466 12 : templ->InstanceTemplate()->SetHandler(
4467 6 : v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
4468 6 : LocalContext env;
4469 12 : env->Global()
4470 18 : ->Set(env.local(), v8_str("obj"), templ->GetFunction(env.local())
4471 : .ToLocalChecked()
4472 : ->NewInstance(env.local())
4473 12 : .ToLocalChecked())
4474 : .FromJust();
4475 : ExpectTrue("obj.x === 42");
4476 : ExpectTrue("!obj.propertyIsEnumerable('x')");
4477 6 : }
4478 :
4479 :
4480 26645 : THREADED_TEST(Regress256330) {
4481 7 : if (!i::FLAG_opt) return;
4482 5 : i::FLAG_allow_natives_syntax = true;
4483 5 : LocalContext context;
4484 10 : v8::HandleScope scope(context->GetIsolate());
4485 5 : Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
4486 5 : AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
4487 10 : context->Global()
4488 10 : ->Set(context.local(), v8_str("Bug"),
4489 15 : templ->GetFunction(context.local()).ToLocalChecked())
4490 : .FromJust();
4491 : CompileRun(
4492 : "\"use strict\"; var o = new Bug;"
4493 : "function f(o) { o.x = 10; };"
4494 : "f(o); f(o); f(o);"
4495 : "%OptimizeFunctionOnNextCall(f);"
4496 : "f(o);");
4497 5 : int status = v8_run_int32value(v8_compile("%GetOptimizationStatus(f)"));
4498 : int mask = static_cast<int>(i::OptimizationStatus::kIsFunction) |
4499 : static_cast<int>(i::OptimizationStatus::kOptimized);
4500 5 : CHECK_EQ(mask, status & mask);
4501 : }
4502 :
4503 26645 : THREADED_TEST(OptimizedInterceptorSetter) {
4504 6 : i::FLAG_allow_natives_syntax = true;
4505 12 : v8::HandleScope scope(CcTest::isolate());
4506 6 : Local<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
4507 6 : AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
4508 6 : LocalContext env;
4509 12 : env->Global()
4510 12 : ->Set(env.local(), v8_str("Obj"),
4511 18 : templ->GetFunction(env.local()).ToLocalChecked())
4512 : .FromJust();
4513 : CompileRun(
4514 : "var obj = new Obj;"
4515 : // Initialize fields to avoid transitions later.
4516 : "obj.age = 0;"
4517 : "obj.accessor_age = 42;"
4518 : "function setter(i) { this.accessor_age = i; };"
4519 : "function getter() { return this.accessor_age; };"
4520 : "function setAge(i) { obj.age = i; };"
4521 : "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
4522 : "setAge(1);"
4523 : "setAge(2);"
4524 : "setAge(3);"
4525 : "%OptimizeFunctionOnNextCall(setAge);"
4526 : "setAge(4);");
4527 : // All stores went through the interceptor.
4528 6 : ExpectInt32("obj.interceptor_age", 4);
4529 6 : ExpectInt32("obj.accessor_age", 42);
4530 6 : }
4531 :
4532 26645 : THREADED_TEST(OptimizedInterceptorGetter) {
4533 6 : i::FLAG_allow_natives_syntax = true;
4534 12 : v8::HandleScope scope(CcTest::isolate());
4535 6 : Local<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
4536 6 : AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
4537 6 : LocalContext env;
4538 12 : env->Global()
4539 12 : ->Set(env.local(), v8_str("Obj"),
4540 18 : templ->GetFunction(env.local()).ToLocalChecked())
4541 : .FromJust();
4542 : CompileRun(
4543 : "var obj = new Obj;"
4544 : // Initialize fields to avoid transitions later.
4545 : "obj.age = 1;"
4546 : "obj.accessor_age = 42;"
4547 : "function getter() { return this.accessor_age; };"
4548 : "function getAge() { return obj.interceptor_age; };"
4549 : "Object.defineProperty(obj, 'interceptor_age', { get:getter });"
4550 : "getAge();"
4551 : "getAge();"
4552 : "getAge();"
4553 : "%OptimizeFunctionOnNextCall(getAge);");
4554 : // Access through interceptor.
4555 6 : ExpectInt32("getAge()", 1);
4556 6 : }
4557 :
4558 26645 : THREADED_TEST(OptimizedInterceptorFieldRead) {
4559 6 : i::FLAG_allow_natives_syntax = true;
4560 12 : v8::HandleScope scope(CcTest::isolate());
4561 6 : Local<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
4562 6 : AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
4563 6 : LocalContext env;
4564 12 : env->Global()
4565 12 : ->Set(env.local(), v8_str("Obj"),
4566 18 : templ->GetFunction(env.local()).ToLocalChecked())
4567 : .FromJust();
4568 : CompileRun(
4569 : "var obj = new Obj;"
4570 : "obj.__proto__.interceptor_age = 42;"
4571 : "obj.age = 100;"
4572 : "function getAge() { return obj.interceptor_age; };");
4573 6 : ExpectInt32("getAge();", 100);
4574 6 : ExpectInt32("getAge();", 100);
4575 6 : ExpectInt32("getAge();", 100);
4576 : CompileRun("%OptimizeFunctionOnNextCall(getAge);");
4577 : // Access through interceptor.
4578 6 : ExpectInt32("getAge();", 100);
4579 6 : }
4580 :
4581 26645 : THREADED_TEST(OptimizedInterceptorFieldWrite) {
4582 6 : i::FLAG_allow_natives_syntax = true;
4583 12 : v8::HandleScope scope(CcTest::isolate());
4584 6 : Local<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
4585 6 : AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
4586 6 : LocalContext env;
4587 12 : env->Global()
4588 12 : ->Set(env.local(), v8_str("Obj"),
4589 18 : templ->GetFunction(env.local()).ToLocalChecked())
4590 : .FromJust();
4591 : CompileRun(
4592 : "var obj = new Obj;"
4593 : "obj.age = 100000;"
4594 : "function setAge(i) { obj.age = i };"
4595 : "setAge(100);"
4596 : "setAge(101);"
4597 : "setAge(102);"
4598 : "%OptimizeFunctionOnNextCall(setAge);"
4599 : "setAge(103);");
4600 6 : ExpectInt32("obj.age", 100000);
4601 6 : ExpectInt32("obj.interceptor_age", 103);
4602 6 : }
4603 :
4604 :
4605 26645 : THREADED_TEST(Regress149912) {
4606 6 : LocalContext context;
4607 12 : v8::HandleScope scope(context->GetIsolate());
4608 6 : Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
4609 6 : AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
4610 12 : context->Global()
4611 12 : ->Set(context.local(), v8_str("Bug"),
4612 18 : templ->GetFunction(context.local()).ToLocalChecked())
4613 : .FromJust();
4614 : CompileRun("Number.prototype.__proto__ = new Bug; var x = 0; x.foo();");
4615 6 : }
4616 :
4617 26645 : THREADED_TEST(Regress625155) {
4618 6 : LocalContext context;
4619 12 : v8::HandleScope scope(context->GetIsolate());
4620 6 : Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
4621 6 : AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
4622 12 : context->Global()
4623 12 : ->Set(context.local(), v8_str("Bug"),
4624 18 : templ->GetFunction(context.local()).ToLocalChecked())
4625 : .FromJust();
4626 : CompileRun(
4627 : "Number.prototype.__proto__ = new Bug;"
4628 : "var x;"
4629 : "x = 0xDEAD;"
4630 : "x.boom = 0;"
4631 : "x = 's';"
4632 : "x.boom = 0;"
4633 : "x = 1.5;"
4634 : "x.boom = 0;");
4635 6 : }
4636 :
4637 26645 : THREADED_TEST(Regress125988) {
4638 12 : v8::HandleScope scope(CcTest::isolate());
4639 6 : Local<FunctionTemplate> intercept = FunctionTemplate::New(CcTest::isolate());
4640 6 : AddInterceptor(intercept, EmptyInterceptorGetter, EmptyInterceptorSetter);
4641 6 : LocalContext env;
4642 12 : env->Global()
4643 12 : ->Set(env.local(), v8_str("Intercept"),
4644 18 : intercept->GetFunction(env.local()).ToLocalChecked())
4645 : .FromJust();
4646 : CompileRun(
4647 : "var a = new Object();"
4648 : "var b = new Intercept();"
4649 : "var c = new Object();"
4650 : "c.__proto__ = b;"
4651 : "b.__proto__ = a;"
4652 : "a.x = 23;"
4653 : "for (var i = 0; i < 3; i++) c.x;");
4654 6 : ExpectBoolean("c.hasOwnProperty('x')", false);
4655 6 : ExpectInt32("c.x", 23);
4656 : CompileRun(
4657 : "a.y = 42;"
4658 : "for (var i = 0; i < 3; i++) c.x;");
4659 6 : ExpectBoolean("c.hasOwnProperty('x')", false);
4660 6 : ExpectInt32("c.x", 23);
4661 6 : ExpectBoolean("c.hasOwnProperty('y')", false);
4662 6 : ExpectInt32("c.y", 42);
4663 6 : }
4664 :
4665 :
4666 12 : static void IndexedPropertyEnumerator(
4667 : const v8::PropertyCallbackInfo<v8::Array>& info) {
4668 12 : v8::Local<v8::Array> result = v8::Array::New(info.GetIsolate(), 1);
4669 24 : result->Set(info.GetIsolate()->GetCurrentContext(), 0,
4670 36 : v8::Integer::New(info.GetIsolate(), 7))
4671 : .FromJust();
4672 : info.GetReturnValue().Set(result);
4673 12 : }
4674 :
4675 :
4676 18 : static void NamedPropertyEnumerator(
4677 : const v8::PropertyCallbackInfo<v8::Array>& info) {
4678 18 : v8::Local<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
4679 18 : v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
4680 54 : result->Set(context, 0, v8_str("x")).FromJust();
4681 54 : result->Set(context, 1, v8::Symbol::GetIterator(info.GetIsolate()))
4682 : .FromJust();
4683 : info.GetReturnValue().Set(result);
4684 18 : }
4685 :
4686 :
4687 26645 : THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
4688 6 : v8::Isolate* isolate = CcTest::isolate();
4689 12 : v8::HandleScope handle_scope(isolate);
4690 6 : v8::Local<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New(isolate);
4691 :
4692 18 : obj_template->Set(v8_str("7"), v8::Integer::New(CcTest::isolate(), 7));
4693 18 : obj_template->Set(v8_str("x"), v8::Integer::New(CcTest::isolate(), 42));
4694 6 : obj_template->SetHandler(v8::IndexedPropertyHandlerConfiguration(
4695 6 : nullptr, nullptr, nullptr, nullptr, IndexedPropertyEnumerator));
4696 6 : obj_template->SetHandler(v8::NamedPropertyHandlerConfiguration(
4697 6 : nullptr, nullptr, nullptr, nullptr, NamedPropertyEnumerator));
4698 :
4699 6 : LocalContext context;
4700 6 : v8::Local<v8::Object> global = context->Global();
4701 12 : global->Set(context.local(), v8_str("object"),
4702 18 : obj_template->NewInstance(context.local()).ToLocalChecked())
4703 : .FromJust();
4704 :
4705 : v8::Local<v8::Value> result =
4706 : CompileRun("Object.getOwnPropertyNames(object)");
4707 6 : CHECK(result->IsArray());
4708 : v8::Local<v8::Array> result_array = v8::Local<v8::Array>::Cast(result);
4709 6 : CHECK_EQ(2u, result_array->Length());
4710 12 : CHECK(result_array->Get(context.local(), 0).ToLocalChecked()->IsString());
4711 12 : CHECK(result_array->Get(context.local(), 1).ToLocalChecked()->IsString());
4712 24 : CHECK(v8_str("7")
4713 : ->Equals(context.local(),
4714 : result_array->Get(context.local(), 0).ToLocalChecked())
4715 : .FromJust());
4716 24 : CHECK(v8_str("x")
4717 : ->Equals(context.local(),
4718 : result_array->Get(context.local(), 1).ToLocalChecked())
4719 : .FromJust());
4720 :
4721 : result = CompileRun("var ret = []; for (var k in object) ret.push(k); ret");
4722 6 : CHECK(result->IsArray());
4723 : result_array = v8::Local<v8::Array>::Cast(result);
4724 6 : CHECK_EQ(2u, result_array->Length());
4725 12 : CHECK(result_array->Get(context.local(), 0).ToLocalChecked()->IsString());
4726 12 : CHECK(result_array->Get(context.local(), 1).ToLocalChecked()->IsString());
4727 24 : CHECK(v8_str("7")
4728 : ->Equals(context.local(),
4729 : result_array->Get(context.local(), 0).ToLocalChecked())
4730 : .FromJust());
4731 24 : CHECK(v8_str("x")
4732 : ->Equals(context.local(),
4733 : result_array->Get(context.local(), 1).ToLocalChecked())
4734 : .FromJust());
4735 :
4736 : result = CompileRun("Object.getOwnPropertySymbols(object)");
4737 6 : CHECK(result->IsArray());
4738 : result_array = v8::Local<v8::Array>::Cast(result);
4739 6 : CHECK_EQ(1u, result_array->Length());
4740 24 : CHECK(result_array->Get(context.local(), 0)
4741 : .ToLocalChecked()
4742 : ->Equals(context.local(), v8::Symbol::GetIterator(isolate))
4743 : .FromJust());
4744 6 : }
4745 :
4746 :
4747 12 : static void IndexedPropertyEnumeratorException(
4748 : const v8::PropertyCallbackInfo<v8::Array>& info) {
4749 24 : info.GetIsolate()->ThrowException(v8_num(42));
4750 12 : }
4751 :
4752 :
4753 26645 : THREADED_TEST(GetOwnPropertyNamesWithIndexedInterceptorExceptions_regress4026) {
4754 6 : v8::Isolate* isolate = CcTest::isolate();
4755 12 : v8::HandleScope handle_scope(isolate);
4756 6 : v8::Local<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New(isolate);
4757 :
4758 18 : obj_template->Set(v8_str("7"), v8::Integer::New(CcTest::isolate(), 7));
4759 18 : obj_template->Set(v8_str("x"), v8::Integer::New(CcTest::isolate(), 42));
4760 : // First just try a failing indexed interceptor.
4761 6 : obj_template->SetHandler(v8::IndexedPropertyHandlerConfiguration(
4762 6 : nullptr, nullptr, nullptr, nullptr, IndexedPropertyEnumeratorException));
4763 :
4764 6 : LocalContext context;
4765 6 : v8::Local<v8::Object> global = context->Global();
4766 12 : global->Set(context.local(), v8_str("object"),
4767 18 : obj_template->NewInstance(context.local()).ToLocalChecked())
4768 : .FromJust();
4769 : v8::Local<v8::Value> result = CompileRun(
4770 : "var result = []; "
4771 : "try { "
4772 : " for (var k in object) result .push(k);"
4773 : "} catch (e) {"
4774 : " result = e"
4775 : "}"
4776 : "result ");
4777 6 : CHECK(!result->IsArray());
4778 18 : CHECK(v8_num(42)->Equals(context.local(), result).FromJust());
4779 :
4780 : result = CompileRun(
4781 : "var result = [];"
4782 : "try { "
4783 : " result = Object.keys(object);"
4784 : "} catch (e) {"
4785 : " result = e;"
4786 : "}"
4787 : "result");
4788 6 : CHECK(!result->IsArray());
4789 18 : CHECK(v8_num(42)->Equals(context.local(), result).FromJust());
4790 6 : }
4791 :
4792 :
4793 12 : static void NamedPropertyEnumeratorException(
4794 : const v8::PropertyCallbackInfo<v8::Array>& info) {
4795 24 : info.GetIsolate()->ThrowException(v8_num(43));
4796 12 : }
4797 :
4798 :
4799 26645 : THREADED_TEST(GetOwnPropertyNamesWithNamedInterceptorExceptions_regress4026) {
4800 6 : v8::Isolate* isolate = CcTest::isolate();
4801 12 : v8::HandleScope handle_scope(isolate);
4802 6 : v8::Local<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New(isolate);
4803 :
4804 18 : obj_template->Set(v8_str("7"), v8::Integer::New(CcTest::isolate(), 7));
4805 18 : obj_template->Set(v8_str("x"), v8::Integer::New(CcTest::isolate(), 42));
4806 : // First just try a failing indexed interceptor.
4807 6 : obj_template->SetHandler(v8::NamedPropertyHandlerConfiguration(
4808 6 : nullptr, nullptr, nullptr, nullptr, NamedPropertyEnumeratorException));
4809 :
4810 6 : LocalContext context;
4811 6 : v8::Local<v8::Object> global = context->Global();
4812 12 : global->Set(context.local(), v8_str("object"),
4813 18 : obj_template->NewInstance(context.local()).ToLocalChecked())
4814 : .FromJust();
4815 :
4816 : v8::Local<v8::Value> result = CompileRun(
4817 : "var result = []; "
4818 : "try { "
4819 : " for (var k in object) result.push(k);"
4820 : "} catch (e) {"
4821 : " result = e"
4822 : "}"
4823 : "result");
4824 6 : CHECK(!result->IsArray());
4825 18 : CHECK(v8_num(43)->Equals(context.local(), result).FromJust());
4826 :
4827 : result = CompileRun(
4828 : "var result = [];"
4829 : "try { "
4830 : " result = Object.keys(object);"
4831 : "} catch (e) {"
4832 : " result = e;"
4833 : "}"
4834 : "result");
4835 6 : CHECK(!result->IsArray());
4836 18 : CHECK(v8_num(43)->Equals(context.local(), result).FromJust());
4837 6 : }
4838 :
4839 : namespace {
4840 :
4841 : template <typename T>
4842 38 : Local<Object> BuildWrappedObject(v8::Isolate* isolate, T* data) {
4843 38 : auto templ = v8::ObjectTemplate::New(isolate);
4844 38 : templ->SetInternalFieldCount(1);
4845 : auto instance =
4846 38 : templ->NewInstance(isolate->GetCurrentContext()).ToLocalChecked();
4847 38 : instance->SetAlignedPointerInInternalField(0, data);
4848 38 : return instance;
4849 : }
4850 :
4851 :
4852 : template <typename T>
4853 276 : T* GetWrappedObject(Local<Value> data) {
4854 : return reinterpret_cast<T*>(
4855 276 : Object::Cast(*data)->GetAlignedPointerFromInternalField(0));
4856 : }
4857 :
4858 :
4859 : struct AccessCheckData {
4860 : int count;
4861 : bool result;
4862 : };
4863 :
4864 : AccessCheckData* g_access_check_data = nullptr;
4865 :
4866 110 : bool SimpleAccessChecker(Local<v8::Context> accessing_context,
4867 : Local<v8::Object> access_object,
4868 : Local<v8::Value> data) {
4869 110 : g_access_check_data->count++;
4870 110 : return g_access_check_data->result;
4871 : }
4872 :
4873 :
4874 : struct ShouldInterceptData {
4875 : int value;
4876 : bool should_intercept;
4877 : };
4878 :
4879 :
4880 261 : void ShouldNamedInterceptor(Local<Name> name,
4881 : const v8::PropertyCallbackInfo<Value>& info) {
4882 261 : ApiTestFuzzer::Fuzz();
4883 261 : CheckReturnValue(info, FUNCTION_ADDR(ShouldNamedInterceptor));
4884 261 : auto data = GetWrappedObject<ShouldInterceptData>(info.Data());
4885 261 : if (!data->should_intercept) return;
4886 256 : info.GetReturnValue().Set(v8_num(data->value));
4887 : }
4888 :
4889 :
4890 15 : void ShouldIndexedInterceptor(uint32_t,
4891 : const v8::PropertyCallbackInfo<Value>& info) {
4892 15 : ApiTestFuzzer::Fuzz();
4893 15 : CheckReturnValue(info, FUNCTION_ADDR(ShouldIndexedInterceptor));
4894 15 : auto data = GetWrappedObject<ShouldInterceptData>(info.Data());
4895 15 : if (!data->should_intercept) return;
4896 10 : info.GetReturnValue().Set(v8_num(data->value));
4897 : }
4898 :
4899 : } // namespace
4900 :
4901 :
4902 26644 : TEST(NamedAllCanReadInterceptor) {
4903 5 : auto isolate = CcTest::isolate();
4904 10 : v8::HandleScope handle_scope(isolate);
4905 5 : LocalContext context;
4906 :
4907 : AccessCheckData access_check_data;
4908 5 : access_check_data.result = true;
4909 5 : access_check_data.count = 0;
4910 :
4911 5 : g_access_check_data = &access_check_data;
4912 :
4913 : ShouldInterceptData intercept_data_0;
4914 5 : intercept_data_0.value = 239;
4915 5 : intercept_data_0.should_intercept = true;
4916 :
4917 : ShouldInterceptData intercept_data_1;
4918 5 : intercept_data_1.value = 165;
4919 5 : intercept_data_1.should_intercept = false;
4920 :
4921 5 : auto intercepted_0 = v8::ObjectTemplate::New(isolate);
4922 : {
4923 : v8::NamedPropertyHandlerConfiguration conf(ShouldNamedInterceptor);
4924 5 : conf.flags = v8::PropertyHandlerFlags::kAllCanRead;
4925 : conf.data =
4926 5 : BuildWrappedObject<ShouldInterceptData>(isolate, &intercept_data_0);
4927 5 : intercepted_0->SetHandler(conf);
4928 : }
4929 :
4930 5 : auto intercepted_1 = v8::ObjectTemplate::New(isolate);
4931 : {
4932 : v8::NamedPropertyHandlerConfiguration conf(ShouldNamedInterceptor);
4933 5 : conf.flags = v8::PropertyHandlerFlags::kAllCanRead;
4934 : conf.data =
4935 5 : BuildWrappedObject<ShouldInterceptData>(isolate, &intercept_data_1);
4936 5 : intercepted_1->SetHandler(conf);
4937 : }
4938 :
4939 5 : auto checked = v8::ObjectTemplate::New(isolate);
4940 5 : checked->SetAccessCheckCallback(SimpleAccessChecker);
4941 :
4942 10 : context->Global()
4943 10 : ->Set(context.local(), v8_str("intercepted_0"),
4944 15 : intercepted_0->NewInstance(context.local()).ToLocalChecked())
4945 : .FromJust();
4946 10 : context->Global()
4947 10 : ->Set(context.local(), v8_str("intercepted_1"),
4948 15 : intercepted_1->NewInstance(context.local()).ToLocalChecked())
4949 : .FromJust();
4950 : auto checked_instance =
4951 5 : checked->NewInstance(context.local()).ToLocalChecked();
4952 15 : checked_instance->Set(context.local(), v8_str("whatever"), v8_num(17))
4953 : .FromJust();
4954 10 : context->Global()
4955 20 : ->Set(context.local(), v8_str("checked"), checked_instance)
4956 : .FromJust();
4957 : CompileRun(
4958 : "checked.__proto__ = intercepted_1;"
4959 : "intercepted_1.__proto__ = intercepted_0;");
4960 :
4961 5 : CHECK_EQ(3, access_check_data.count);
4962 :
4963 5 : ExpectInt32("checked.whatever", 17);
4964 5 : CHECK(!CompileRun("Object.getOwnPropertyDescriptor(checked, 'whatever')")
4965 : ->IsUndefined());
4966 5 : CHECK_EQ(5, access_check_data.count);
4967 :
4968 5 : access_check_data.result = false;
4969 5 : ExpectInt32("checked.whatever", intercept_data_0.value);
4970 : {
4971 10 : v8::TryCatch try_catch(isolate);
4972 : CompileRun("Object.getOwnPropertyDescriptor(checked, 'whatever')");
4973 5 : CHECK(try_catch.HasCaught());
4974 : }
4975 5 : CHECK_EQ(8, access_check_data.count);
4976 :
4977 5 : intercept_data_1.should_intercept = true;
4978 5 : ExpectInt32("checked.whatever", intercept_data_1.value);
4979 : {
4980 10 : v8::TryCatch try_catch(isolate);
4981 : CompileRun("Object.getOwnPropertyDescriptor(checked, 'whatever')");
4982 5 : CHECK(try_catch.HasCaught());
4983 : }
4984 5 : CHECK_EQ(11, access_check_data.count);
4985 5 : g_access_check_data = nullptr;
4986 5 : }
4987 :
4988 :
4989 26644 : TEST(IndexedAllCanReadInterceptor) {
4990 5 : auto isolate = CcTest::isolate();
4991 10 : v8::HandleScope handle_scope(isolate);
4992 5 : LocalContext context;
4993 :
4994 : AccessCheckData access_check_data;
4995 5 : access_check_data.result = true;
4996 5 : access_check_data.count = 0;
4997 :
4998 5 : g_access_check_data = &access_check_data;
4999 :
5000 : ShouldInterceptData intercept_data_0;
5001 5 : intercept_data_0.value = 239;
5002 5 : intercept_data_0.should_intercept = true;
5003 :
5004 : ShouldInterceptData intercept_data_1;
5005 5 : intercept_data_1.value = 165;
5006 5 : intercept_data_1.should_intercept = false;
5007 :
5008 5 : auto intercepted_0 = v8::ObjectTemplate::New(isolate);
5009 : {
5010 : v8::IndexedPropertyHandlerConfiguration conf(ShouldIndexedInterceptor);
5011 5 : conf.flags = v8::PropertyHandlerFlags::kAllCanRead;
5012 : conf.data =
5013 5 : BuildWrappedObject<ShouldInterceptData>(isolate, &intercept_data_0);
5014 5 : intercepted_0->SetHandler(conf);
5015 : }
5016 :
5017 5 : auto intercepted_1 = v8::ObjectTemplate::New(isolate);
5018 : {
5019 : v8::IndexedPropertyHandlerConfiguration conf(ShouldIndexedInterceptor);
5020 5 : conf.flags = v8::PropertyHandlerFlags::kAllCanRead;
5021 : conf.data =
5022 5 : BuildWrappedObject<ShouldInterceptData>(isolate, &intercept_data_1);
5023 5 : intercepted_1->SetHandler(conf);
5024 : }
5025 :
5026 5 : auto checked = v8::ObjectTemplate::New(isolate);
5027 5 : checked->SetAccessCheckCallback(SimpleAccessChecker);
5028 :
5029 10 : context->Global()
5030 10 : ->Set(context.local(), v8_str("intercepted_0"),
5031 15 : intercepted_0->NewInstance(context.local()).ToLocalChecked())
5032 : .FromJust();
5033 10 : context->Global()
5034 10 : ->Set(context.local(), v8_str("intercepted_1"),
5035 15 : intercepted_1->NewInstance(context.local()).ToLocalChecked())
5036 : .FromJust();
5037 : auto checked_instance =
5038 5 : checked->NewInstance(context.local()).ToLocalChecked();
5039 10 : context->Global()
5040 20 : ->Set(context.local(), v8_str("checked"), checked_instance)
5041 : .FromJust();
5042 15 : checked_instance->Set(context.local(), 15, v8_num(17)).FromJust();
5043 : CompileRun(
5044 : "checked.__proto__ = intercepted_1;"
5045 : "intercepted_1.__proto__ = intercepted_0;");
5046 :
5047 5 : CHECK_EQ(3, access_check_data.count);
5048 :
5049 5 : access_check_data.result = true;
5050 5 : ExpectInt32("checked[15]", 17);
5051 5 : CHECK(!CompileRun("Object.getOwnPropertyDescriptor(checked, '15')")
5052 : ->IsUndefined());
5053 5 : CHECK_EQ(5, access_check_data.count);
5054 :
5055 5 : access_check_data.result = false;
5056 5 : ExpectInt32("checked[15]", intercept_data_0.value);
5057 : {
5058 10 : v8::TryCatch try_catch(isolate);
5059 : CompileRun("Object.getOwnPropertyDescriptor(checked, '15')");
5060 5 : CHECK(try_catch.HasCaught());
5061 : }
5062 5 : CHECK_EQ(8, access_check_data.count);
5063 :
5064 5 : intercept_data_1.should_intercept = true;
5065 5 : ExpectInt32("checked[15]", intercept_data_1.value);
5066 : {
5067 10 : v8::TryCatch try_catch(isolate);
5068 : CompileRun("Object.getOwnPropertyDescriptor(checked, '15')");
5069 5 : CHECK(try_catch.HasCaught());
5070 : }
5071 5 : CHECK_EQ(11, access_check_data.count);
5072 :
5073 5 : g_access_check_data = nullptr;
5074 5 : }
5075 :
5076 :
5077 26645 : THREADED_TEST(NonMaskingInterceptorOwnProperty) {
5078 6 : auto isolate = CcTest::isolate();
5079 12 : v8::HandleScope handle_scope(isolate);
5080 6 : LocalContext context;
5081 :
5082 : ShouldInterceptData intercept_data;
5083 6 : intercept_data.value = 239;
5084 6 : intercept_data.should_intercept = true;
5085 :
5086 6 : auto interceptor_templ = v8::ObjectTemplate::New(isolate);
5087 : v8::NamedPropertyHandlerConfiguration conf(ShouldNamedInterceptor);
5088 6 : conf.flags = v8::PropertyHandlerFlags::kNonMasking;
5089 6 : conf.data = BuildWrappedObject<ShouldInterceptData>(isolate, &intercept_data);
5090 6 : interceptor_templ->SetHandler(conf);
5091 :
5092 : auto interceptor =
5093 6 : interceptor_templ->NewInstance(context.local()).ToLocalChecked();
5094 12 : context->Global()
5095 24 : ->Set(context.local(), v8_str("obj"), interceptor)
5096 : .FromJust();
5097 :
5098 6 : ExpectInt32("obj.whatever", 239);
5099 :
5100 : CompileRun("obj.whatever = 4;");
5101 :
5102 : // obj.whatever exists, thus it is not affected by the non-masking
5103 : // interceptor.
5104 6 : ExpectInt32("obj.whatever", 4);
5105 :
5106 : CompileRun("delete obj.whatever;");
5107 6 : ExpectInt32("obj.whatever", 239);
5108 6 : }
5109 :
5110 :
5111 26645 : THREADED_TEST(NonMaskingInterceptorPrototypeProperty) {
5112 6 : auto isolate = CcTest::isolate();
5113 12 : v8::HandleScope handle_scope(isolate);
5114 6 : LocalContext context;
5115 :
5116 : ShouldInterceptData intercept_data;
5117 6 : intercept_data.value = 239;
5118 6 : intercept_data.should_intercept = true;
5119 :
5120 6 : auto interceptor_templ = v8::ObjectTemplate::New(isolate);
5121 : v8::NamedPropertyHandlerConfiguration conf(ShouldNamedInterceptor);
5122 6 : conf.flags = v8::PropertyHandlerFlags::kNonMasking;
5123 6 : conf.data = BuildWrappedObject<ShouldInterceptData>(isolate, &intercept_data);
5124 6 : interceptor_templ->SetHandler(conf);
5125 :
5126 : auto interceptor =
5127 6 : interceptor_templ->NewInstance(context.local()).ToLocalChecked();
5128 12 : context->Global()
5129 24 : ->Set(context.local(), v8_str("obj"), interceptor)
5130 : .FromJust();
5131 :
5132 6 : ExpectInt32("obj.whatever", 239);
5133 :
5134 : CompileRun("obj.__proto__ = {'whatever': 4};");
5135 6 : ExpectInt32("obj.whatever", 4);
5136 :
5137 : CompileRun("delete obj.__proto__.whatever;");
5138 6 : ExpectInt32("obj.whatever", 239);
5139 6 : }
5140 :
5141 :
5142 26645 : THREADED_TEST(NonMaskingInterceptorPrototypePropertyIC) {
5143 6 : auto isolate = CcTest::isolate();
5144 12 : v8::HandleScope handle_scope(isolate);
5145 6 : LocalContext context;
5146 :
5147 : ShouldInterceptData intercept_data;
5148 6 : intercept_data.value = 239;
5149 6 : intercept_data.should_intercept = true;
5150 :
5151 6 : auto interceptor_templ = v8::ObjectTemplate::New(isolate);
5152 : v8::NamedPropertyHandlerConfiguration conf(ShouldNamedInterceptor);
5153 6 : conf.flags = v8::PropertyHandlerFlags::kNonMasking;
5154 6 : conf.data = BuildWrappedObject<ShouldInterceptData>(isolate, &intercept_data);
5155 6 : interceptor_templ->SetHandler(conf);
5156 :
5157 : auto interceptor =
5158 6 : interceptor_templ->NewInstance(context.local()).ToLocalChecked();
5159 12 : context->Global()
5160 24 : ->Set(context.local(), v8_str("obj"), interceptor)
5161 : .FromJust();
5162 :
5163 : CompileRun(
5164 : "outer = {};"
5165 : "outer.__proto__ = obj;"
5166 : "function f(obj) {"
5167 : " var x;"
5168 : " for (var i = 0; i < 4; i++) {"
5169 : " x = obj.whatever;"
5170 : " }"
5171 : " return x;"
5172 : "}");
5173 :
5174 : // Receiver == holder.
5175 : CompileRun("obj.__proto__ = null;");
5176 6 : ExpectInt32("f(obj)", 239);
5177 6 : ExpectInt32("f(outer)", 239);
5178 :
5179 : // Receiver != holder.
5180 : CompileRun("Object.setPrototypeOf(obj, {});");
5181 6 : ExpectInt32("f(obj)", 239);
5182 6 : ExpectInt32("f(outer)", 239);
5183 :
5184 : // Masked value on prototype.
5185 : CompileRun("obj.__proto__.whatever = 4;");
5186 : CompileRun("obj.__proto__.__proto__ = { 'whatever' : 5 };");
5187 6 : ExpectInt32("f(obj)", 4);
5188 6 : ExpectInt32("f(outer)", 4);
5189 :
5190 : // Masked value on prototype prototype.
5191 : CompileRun("delete obj.__proto__.whatever;");
5192 6 : ExpectInt32("f(obj)", 5);
5193 6 : ExpectInt32("f(outer)", 5);
5194 :
5195 : // Reset.
5196 : CompileRun("delete obj.__proto__.__proto__.whatever;");
5197 6 : ExpectInt32("f(obj)", 239);
5198 6 : ExpectInt32("f(outer)", 239);
5199 :
5200 : // Masked value on self.
5201 : CompileRun("obj.whatever = 4;");
5202 6 : ExpectInt32("f(obj)", 4);
5203 6 : ExpectInt32("f(outer)", 4);
5204 :
5205 : // Reset.
5206 : CompileRun("delete obj.whatever;");
5207 6 : ExpectInt32("f(obj)", 239);
5208 6 : ExpectInt32("f(outer)", 239);
5209 :
5210 : CompileRun("outer.whatever = 4;");
5211 6 : ExpectInt32("f(obj)", 239);
5212 6 : ExpectInt32("f(outer)", 4);
5213 6 : }
5214 :
5215 : namespace {
5216 :
5217 120 : void ConcatNamedPropertyGetter(
5218 : Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
5219 120 : info.GetReturnValue().Set(
5220 : // Return the property name concatenated with itself.
5221 : String::Concat(info.GetIsolate(), name.As<String>(), name.As<String>()));
5222 120 : }
5223 :
5224 288 : void ConcatIndexedPropertyGetter(
5225 : uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) {
5226 288 : info.GetReturnValue().Set(
5227 : // Return the double value of the index.
5228 288 : v8_num(index + index));
5229 288 : }
5230 :
5231 96 : void EnumCallbackWithNames(const v8::PropertyCallbackInfo<v8::Array>& info) {
5232 96 : ApiTestFuzzer::Fuzz();
5233 96 : v8::Local<v8::Array> result = v8::Array::New(info.GetIsolate(), 4);
5234 96 : v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
5235 384 : CHECK(
5236 : result
5237 : ->Set(context, v8::Integer::New(info.GetIsolate(), 0), v8_str("foo"))
5238 : .FromJust());
5239 384 : CHECK(
5240 : result
5241 : ->Set(context, v8::Integer::New(info.GetIsolate(), 1), v8_str("bar"))
5242 : .FromJust());
5243 384 : CHECK(
5244 : result
5245 : ->Set(context, v8::Integer::New(info.GetIsolate(), 2), v8_str("baz"))
5246 : .FromJust());
5247 384 : CHECK(
5248 : result->Set(context, v8::Integer::New(info.GetIsolate(), 3), v8_str("10"))
5249 : .FromJust());
5250 :
5251 : // Create a holey array.
5252 288 : CHECK(result->Delete(context, v8::Integer::New(info.GetIsolate(), 1))
5253 : .FromJust());
5254 : info.GetReturnValue().Set(result);
5255 96 : }
5256 :
5257 66 : void EnumCallbackWithIndices(const v8::PropertyCallbackInfo<v8::Array>& info) {
5258 66 : ApiTestFuzzer::Fuzz();
5259 66 : v8::Local<v8::Array> result = v8::Array::New(info.GetIsolate(), 4);
5260 66 : v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
5261 :
5262 264 : CHECK(result->Set(context, v8::Integer::New(info.GetIsolate(), 0), v8_num(10))
5263 : .FromJust());
5264 264 : CHECK(result->Set(context, v8::Integer::New(info.GetIsolate(), 1), v8_num(11))
5265 : .FromJust());
5266 264 : CHECK(result->Set(context, v8::Integer::New(info.GetIsolate(), 2), v8_num(12))
5267 : .FromJust());
5268 264 : CHECK(result->Set(context, v8::Integer::New(info.GetIsolate(), 3), v8_num(14))
5269 : .FromJust());
5270 :
5271 : // Create a holey array.
5272 198 : CHECK(result->Delete(context, v8::Integer::New(info.GetIsolate(), 1))
5273 : .FromJust());
5274 : info.GetReturnValue().Set(result);
5275 66 : }
5276 :
5277 138 : void RestrictiveNamedQuery(Local<Name> property,
5278 : const v8::PropertyCallbackInfo<v8::Integer>& info) {
5279 : // Only "foo" is enumerable.
5280 414 : if (v8_str("foo")
5281 552 : ->Equals(info.GetIsolate()->GetCurrentContext(), property)
5282 : .FromJust()) {
5283 : info.GetReturnValue().Set(v8::PropertyAttribute::None);
5284 66 : return;
5285 : }
5286 : info.GetReturnValue().Set(v8::PropertyAttribute::DontEnum);
5287 : }
5288 :
5289 312 : void RestrictiveIndexedQuery(
5290 : uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info) {
5291 : // Only index 2 and 12 are enumerable.
5292 312 : if (index == 2 || index == 12) {
5293 : info.GetReturnValue().Set(v8::PropertyAttribute::None);
5294 96 : return;
5295 : }
5296 : info.GetReturnValue().Set(v8::PropertyAttribute::DontEnum);
5297 : }
5298 : } // namespace
5299 :
5300 : // Regression test for V8 bug 6627.
5301 : // Object.keys() must return enumerable keys only.
5302 26645 : THREADED_TEST(EnumeratorsAndUnenumerableNamedProperties) {
5303 : // The enumerator interceptor returns a list
5304 : // of items which are filtered according to the
5305 : // properties defined in the query interceptor.
5306 6 : v8::Isolate* isolate = CcTest::isolate();
5307 12 : v8::HandleScope scope(isolate);
5308 6 : v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
5309 6 : obj->SetHandler(v8::NamedPropertyHandlerConfiguration(
5310 : ConcatNamedPropertyGetter, nullptr, RestrictiveNamedQuery, nullptr,
5311 6 : EnumCallbackWithNames));
5312 6 : LocalContext context;
5313 12 : context->Global()
5314 12 : ->Set(context.local(), v8_str("obj"),
5315 18 : obj->NewInstance(context.local()).ToLocalChecked())
5316 : .FromJust();
5317 :
5318 6 : ExpectInt32("Object.getOwnPropertyNames(obj).length", 3);
5319 6 : ExpectString("Object.getOwnPropertyNames(obj)[0]", "foo");
5320 6 : ExpectString("Object.getOwnPropertyNames(obj)[1]", "baz");
5321 6 : ExpectString("Object.getOwnPropertyNames(obj)[2]", "10");
5322 :
5323 : ExpectTrue("Object.getOwnPropertyDescriptor(obj, 'foo').enumerable");
5324 : ExpectFalse("Object.getOwnPropertyDescriptor(obj, 'baz').enumerable");
5325 :
5326 6 : ExpectInt32("Object.entries(obj).length", 1);
5327 6 : ExpectString("Object.entries(obj)[0][0]", "foo");
5328 6 : ExpectString("Object.entries(obj)[0][1]", "foofoo");
5329 :
5330 6 : ExpectInt32("Object.keys(obj).length", 1);
5331 6 : ExpectString("Object.keys(obj)[0]", "foo");
5332 :
5333 6 : ExpectInt32("Object.values(obj).length", 1);
5334 6 : ExpectString("Object.values(obj)[0]", "foofoo");
5335 6 : }
5336 :
5337 : namespace {
5338 24 : void QueryInterceptorForFoo(Local<Name> property,
5339 : const v8::PropertyCallbackInfo<v8::Integer>& info) {
5340 : // Don't intercept anything except "foo."
5341 72 : if (!v8_str("foo")
5342 96 : ->Equals(info.GetIsolate()->GetCurrentContext(), property)
5343 : .FromJust()) {
5344 : return;
5345 : }
5346 : // "foo" is enumerable.
5347 : info.GetReturnValue().Set(v8::PropertyAttribute::None);
5348 : }
5349 : } // namespace
5350 :
5351 : // Test that calls to the query interceptor are independent of each
5352 : // other.
5353 26645 : THREADED_TEST(EnumeratorsAndUnenumerableNamedPropertiesWithoutSet) {
5354 : // The enumerator interceptor returns a list
5355 : // of items which are filtered according to the
5356 : // properties defined in the query interceptor.
5357 6 : v8::Isolate* isolate = CcTest::isolate();
5358 12 : v8::HandleScope scope(isolate);
5359 6 : v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
5360 6 : obj->SetHandler(v8::NamedPropertyHandlerConfiguration(
5361 : ConcatNamedPropertyGetter, nullptr, QueryInterceptorForFoo, nullptr,
5362 6 : EnumCallbackWithNames));
5363 6 : LocalContext context;
5364 12 : context->Global()
5365 12 : ->Set(context.local(), v8_str("obj"),
5366 18 : obj->NewInstance(context.local()).ToLocalChecked())
5367 : .FromJust();
5368 :
5369 6 : ExpectInt32("Object.getOwnPropertyNames(obj).length", 3);
5370 6 : ExpectString("Object.getOwnPropertyNames(obj)[0]", "foo");
5371 6 : ExpectString("Object.getOwnPropertyNames(obj)[1]", "baz");
5372 6 : ExpectString("Object.getOwnPropertyNames(obj)[2]", "10");
5373 :
5374 : ExpectTrue("Object.getOwnPropertyDescriptor(obj, 'foo').enumerable");
5375 6 : ExpectInt32("Object.keys(obj).length", 1);
5376 6 : }
5377 :
5378 26645 : THREADED_TEST(EnumeratorsAndUnenumerableIndexedPropertiesArgumentsElements) {
5379 6 : v8::Isolate* isolate = CcTest::isolate();
5380 12 : v8::HandleScope scope(isolate);
5381 6 : v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
5382 6 : obj->SetHandler(v8::IndexedPropertyHandlerConfiguration(
5383 : ConcatIndexedPropertyGetter, nullptr, RestrictiveIndexedQuery, nullptr,
5384 6 : SloppyArgsIndexedPropertyEnumerator));
5385 6 : LocalContext context;
5386 12 : context->Global()
5387 12 : ->Set(context.local(), v8_str("obj"),
5388 18 : obj->NewInstance(context.local()).ToLocalChecked())
5389 : .FromJust();
5390 :
5391 6 : ExpectInt32("Object.getOwnPropertyNames(obj).length", 4);
5392 6 : ExpectString("Object.getOwnPropertyNames(obj)[0]", "0");
5393 6 : ExpectString("Object.getOwnPropertyNames(obj)[1]", "1");
5394 6 : ExpectString("Object.getOwnPropertyNames(obj)[2]", "2");
5395 6 : ExpectString("Object.getOwnPropertyNames(obj)[3]", "3");
5396 :
5397 : ExpectTrue("Object.getOwnPropertyDescriptor(obj, '2').enumerable");
5398 :
5399 6 : ExpectInt32("Object.entries(obj).length", 1);
5400 6 : ExpectString("Object.entries(obj)[0][0]", "2");
5401 6 : ExpectInt32("Object.entries(obj)[0][1]", 4);
5402 :
5403 6 : ExpectInt32("Object.keys(obj).length", 1);
5404 6 : ExpectString("Object.keys(obj)[0]", "2");
5405 :
5406 6 : ExpectInt32("Object.values(obj).length", 1);
5407 6 : ExpectInt32("Object.values(obj)[0]", 4);
5408 6 : }
5409 :
5410 26645 : THREADED_TEST(EnumeratorsAndUnenumerableIndexedProperties) {
5411 : // The enumerator interceptor returns a list
5412 : // of items which are filtered according to the
5413 : // properties defined in the query interceptor.
5414 6 : v8::Isolate* isolate = CcTest::isolate();
5415 12 : v8::HandleScope scope(isolate);
5416 6 : v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
5417 6 : obj->SetHandler(v8::IndexedPropertyHandlerConfiguration(
5418 : ConcatIndexedPropertyGetter, nullptr, RestrictiveIndexedQuery, nullptr,
5419 6 : EnumCallbackWithIndices));
5420 6 : LocalContext context;
5421 12 : context->Global()
5422 12 : ->Set(context.local(), v8_str("obj"),
5423 18 : obj->NewInstance(context.local()).ToLocalChecked())
5424 : .FromJust();
5425 :
5426 6 : ExpectInt32("Object.getOwnPropertyNames(obj).length", 3);
5427 6 : ExpectString("Object.getOwnPropertyNames(obj)[0]", "10");
5428 6 : ExpectString("Object.getOwnPropertyNames(obj)[1]", "12");
5429 6 : ExpectString("Object.getOwnPropertyNames(obj)[2]", "14");
5430 :
5431 : ExpectFalse("Object.getOwnPropertyDescriptor(obj, '10').enumerable");
5432 : ExpectTrue("Object.getOwnPropertyDescriptor(obj, '12').enumerable");
5433 :
5434 6 : ExpectInt32("Object.entries(obj).length", 1);
5435 6 : ExpectString("Object.entries(obj)[0][0]", "12");
5436 6 : ExpectInt32("Object.entries(obj)[0][1]", 24);
5437 :
5438 6 : ExpectInt32("Object.keys(obj).length", 1);
5439 6 : ExpectString("Object.keys(obj)[0]", "12");
5440 :
5441 6 : ExpectInt32("Object.values(obj).length", 1);
5442 6 : ExpectInt32("Object.values(obj)[0]", 24);
5443 6 : }
5444 :
5445 26645 : THREADED_TEST(EnumeratorsAndForIn) {
5446 6 : v8::Isolate* isolate = CcTest::isolate();
5447 12 : v8::HandleScope scope(isolate);
5448 6 : v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
5449 6 : obj->SetHandler(v8::NamedPropertyHandlerConfiguration(
5450 : ConcatNamedPropertyGetter, nullptr, RestrictiveNamedQuery, nullptr,
5451 6 : NamedEnum));
5452 6 : LocalContext context;
5453 12 : context->Global()
5454 12 : ->Set(context.local(), v8_str("obj"),
5455 18 : obj->NewInstance(context.local()).ToLocalChecked())
5456 : .FromJust();
5457 :
5458 6 : ExpectInt32("Object.getOwnPropertyNames(obj).length", 3);
5459 6 : ExpectString("Object.getOwnPropertyNames(obj)[0]", "foo");
5460 :
5461 : ExpectTrue("Object.getOwnPropertyDescriptor(obj, 'foo').enumerable");
5462 :
5463 : CompileRun(
5464 : "let concat = '';"
5465 : "for(var prop in obj) {"
5466 : " concat += `key:${prop}:value:${obj[prop]}`;"
5467 : "}");
5468 :
5469 : // Check that for...in only iterates over enumerable properties.
5470 6 : ExpectString("concat", "key:foo:value:foofoo");
5471 6 : }
5472 :
5473 : namespace {
5474 :
5475 24 : void DatabaseGetter(Local<Name> name,
5476 : const v8::PropertyCallbackInfo<Value>& info) {
5477 24 : ApiTestFuzzer::Fuzz();
5478 24 : auto context = info.GetIsolate()->GetCurrentContext();
5479 : Local<v8::Object> db = info.Holder()
5480 72 : ->GetRealNamedProperty(context, v8_str("db"))
5481 : .ToLocalChecked()
5482 : .As<v8::Object>();
5483 48 : if (!db->Has(context, name).FromJust()) return;
5484 48 : info.GetReturnValue().Set(db->Get(context, name).ToLocalChecked());
5485 : }
5486 :
5487 :
5488 24 : void DatabaseSetter(Local<Name> name, Local<Value> value,
5489 : const v8::PropertyCallbackInfo<Value>& info) {
5490 24 : ApiTestFuzzer::Fuzz();
5491 24 : auto context = info.GetIsolate()->GetCurrentContext();
5492 84 : if (name->Equals(context, v8_str("db")).FromJust()) return;
5493 : Local<v8::Object> db = info.Holder()
5494 36 : ->GetRealNamedProperty(context, v8_str("db"))
5495 : .ToLocalChecked()
5496 : .As<v8::Object>();
5497 24 : db->Set(context, name, value).FromJust();
5498 : info.GetReturnValue().Set(value);
5499 : }
5500 :
5501 : } // namespace
5502 :
5503 :
5504 26645 : THREADED_TEST(NonMaskingInterceptorGlobalEvalRegression) {
5505 6 : auto isolate = CcTest::isolate();
5506 12 : v8::HandleScope handle_scope(isolate);
5507 6 : LocalContext context;
5508 :
5509 6 : auto interceptor_templ = v8::ObjectTemplate::New(isolate);
5510 : v8::NamedPropertyHandlerConfiguration conf(DatabaseGetter, DatabaseSetter);
5511 6 : conf.flags = v8::PropertyHandlerFlags::kNonMasking;
5512 6 : interceptor_templ->SetHandler(conf);
5513 :
5514 12 : context->Global()
5515 12 : ->Set(context.local(), v8_str("intercepted_1"),
5516 18 : interceptor_templ->NewInstance(context.local()).ToLocalChecked())
5517 : .FromJust();
5518 12 : context->Global()
5519 12 : ->Set(context.local(), v8_str("intercepted_2"),
5520 18 : interceptor_templ->NewInstance(context.local()).ToLocalChecked())
5521 : .FromJust();
5522 :
5523 : // Init dbs.
5524 : CompileRun(
5525 : "intercepted_1.db = {};"
5526 : "intercepted_2.db = {};");
5527 :
5528 : ExpectInt32(
5529 : "var obj = intercepted_1;"
5530 : "obj.x = 4;"
5531 : "eval('obj.x');"
5532 : "eval('obj.x');"
5533 : "eval('obj.x');"
5534 : "obj = intercepted_2;"
5535 : "obj.x = 9;"
5536 : "eval('obj.x');",
5537 6 : 9);
5538 6 : }
5539 :
5540 15 : static void CheckReceiver(Local<Name> name,
5541 : const v8::PropertyCallbackInfo<v8::Value>& info) {
5542 15 : CHECK(info.This()->IsObject());
5543 15 : }
5544 :
5545 26644 : TEST(Regress609134Interceptor) {
5546 5 : LocalContext env;
5547 5 : v8::Isolate* isolate = env->GetIsolate();
5548 10 : v8::HandleScope scope(isolate);
5549 5 : auto fun_templ = v8::FunctionTemplate::New(isolate);
5550 10 : fun_templ->InstanceTemplate()->SetHandler(
5551 5 : v8::NamedPropertyHandlerConfiguration(CheckReceiver));
5552 :
5553 25 : CHECK(env->Global()
5554 : ->Set(env.local(), v8_str("Fun"),
5555 : fun_templ->GetFunction(env.local()).ToLocalChecked())
5556 : .FromJust());
5557 :
5558 : CompileRun(
5559 : "var f = new Fun();"
5560 : "Number.prototype.__proto__ = f;"
5561 : "var a = 42;"
5562 : "for (var i = 0; i<3; i++) { a.foo; }");
5563 79922 : }
|