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