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