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