1 // Copyright 2007-2008 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 #include <stdlib.h> 29 30 #include "src/v8.h" 31 32 #include "src/heap/heap.h" 33 #include "test/cctest/cctest.h" 34 35 using namespace v8; 36 37 38 enum Expectations { 39 EXPECT_RESULT, 40 EXPECT_EXCEPTION, 41 EXPECT_ERROR 42 }; 43 44 45 // A DeclarationContext holds a reference to a v8::Context and keeps 46 // track of various declaration related counters to make it easier to 47 // track if global declarations in the presence of interceptors behave 48 // the right way. 49 class DeclarationContext { 50 public: 51 DeclarationContext(); 52 53 virtual ~DeclarationContext() { 54 if (is_initialized_) { 55 Isolate* isolate = CcTest::isolate(); 56 HandleScope scope(isolate); 57 Local<Context> context = Local<Context>::New(isolate, context_); 58 context->Exit(); 59 context_.Reset(); 60 } 61 } 62 63 void Check(const char* source, int get, int set, int has, 64 Expectations expectations, 65 v8::Local<Value> value = Local<Value>()); 66 67 int get_count() const { return get_count_; } 68 int set_count() const { return set_count_; } 69 int query_count() const { return query_count_; } 70 71 protected: 72 virtual v8::Local<Value> Get(Local<Name> key); 73 virtual v8::Local<Value> Set(Local<Name> key, Local<Value> value); 74 virtual v8::Local<Integer> Query(Local<Name> key); 75 76 void InitializeIfNeeded(); 77 78 // Perform optional initialization steps on the context after it has 79 // been created. Defaults to none but may be overwritten. 80 virtual void PostInitializeContext(Local<Context> context) {} 81 82 // Get the holder for the interceptor. Default to the instance template 83 // but may be overwritten. 84 virtual Local<ObjectTemplate> GetHolder(Local<FunctionTemplate> function) { 85 return function->InstanceTemplate(); 86 } 87 88 // The handlers are called as static functions that forward 89 // to the instance specific virtual methods. 90 static void HandleGet(Local<Name> key, 91 const v8::PropertyCallbackInfo<v8::Value>& info); 92 static void HandleSet(Local<Name> key, Local<Value> value, 93 const v8::PropertyCallbackInfo<v8::Value>& info); 94 static void HandleQuery(Local<Name> key, 95 const v8::PropertyCallbackInfo<v8::Integer>& info); 96 97 v8::Isolate* isolate() const { return CcTest::isolate(); } 98 99 private: 100 bool is_initialized_; 101 Persistent<Context> context_; 102 103 int get_count_; 104 int set_count_; 105 int query_count_; 106 107 static DeclarationContext* GetInstance(Local<Value> data); 108 }; 109 110 111 DeclarationContext::DeclarationContext() 112 : is_initialized_(false), get_count_(0), set_count_(0), query_count_(0) { 113 // Do nothing. 114 } 115 116 117 void DeclarationContext::InitializeIfNeeded() { 118 if (is_initialized_) return; 119 Isolate* isolate = CcTest::isolate(); 120 HandleScope scope(isolate); 121 Local<FunctionTemplate> function = FunctionTemplate::New(isolate); 122 Local<Value> data = External::New(CcTest::isolate(), this); 123 GetHolder(function)->SetHandler(v8::NamedPropertyHandlerConfiguration( 124 &HandleGet, &HandleSet, &HandleQuery, 0, 0, data)); 125 Local<Context> context = Context::New(isolate, 126 0, 127 function->InstanceTemplate(), 128 Local<Value>()); 129 context_.Reset(isolate, context); 130 context->Enter(); 131 is_initialized_ = true; 132 // Reset counts. Bootstrapping might have called into the interceptor. 133 get_count_ = 0; 134 set_count_ = 0; 135 query_count_ = 0; 136 PostInitializeContext(context); 137 } 138 139 140 void DeclarationContext::Check(const char* source, int get, int set, int query, 141 Expectations expectations, 142 v8::Local<Value> value) { 143 InitializeIfNeeded(); 144 // A retry after a GC may pollute the counts, so perform gc now 145 // to avoid that. 146 CcTest::heap()->CollectGarbage(v8::internal::NEW_SPACE); 147 HandleScope scope(CcTest::isolate()); 148 TryCatch catcher(CcTest::isolate()); 149 catcher.SetVerbose(true); 150 Local<Context> context = CcTest::isolate()->GetCurrentContext(); 151 MaybeLocal<Script> script = Script::Compile( 152 context, 153 String::NewFromUtf8(CcTest::isolate(), source, v8::NewStringType::kNormal) 154 .ToLocalChecked()); 155 if (expectations == EXPECT_ERROR) { 156 CHECK(script.IsEmpty()); 157 return; 158 } 159 CHECK(!script.IsEmpty()); 160 MaybeLocal<Value> result = script.ToLocalChecked()->Run(context); 161 CHECK_EQ(get, get_count()); 162 CHECK_EQ(set, set_count()); 163 CHECK_EQ(query, query_count()); 164 if (expectations == EXPECT_RESULT) { 165 CHECK(!catcher.HasCaught()); 166 if (!value.IsEmpty()) { 167 CHECK(value->Equals(context, result.ToLocalChecked()).FromJust()); 168 } 169 } else { 170 CHECK(expectations == EXPECT_EXCEPTION); 171 CHECK(catcher.HasCaught()); 172 if (!value.IsEmpty()) { 173 CHECK(value->Equals(context, catcher.Exception()).FromJust()); 174 } 175 } 176 // Clean slate for the next test. 177 CcTest::heap()->CollectAllAvailableGarbage(); 178 } 179 180 181 void DeclarationContext::HandleGet( 182 Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>& info) { 183 DeclarationContext* context = GetInstance(info.Data()); 184 context->get_count_++; 185 info.GetReturnValue().Set(context->Get(key)); 186 } 187 188 189 void DeclarationContext::HandleSet( 190 Local<Name> key, Local<Value> value, 191 const v8::PropertyCallbackInfo<v8::Value>& info) { 192 DeclarationContext* context = GetInstance(info.Data()); 193 context->set_count_++; 194 info.GetReturnValue().Set(context->Set(key, value)); 195 } 196 197 198 void DeclarationContext::HandleQuery( 199 Local<Name> key, const v8::PropertyCallbackInfo<v8::Integer>& info) { 200 DeclarationContext* context = GetInstance(info.Data()); 201 context->query_count_++; 202 info.GetReturnValue().Set(context->Query(key)); 203 } 204 205 206 DeclarationContext* DeclarationContext::GetInstance(Local<Value> data) { 207 void* value = Local<External>::Cast(data)->Value(); 208 return static_cast<DeclarationContext*>(value); 209 } 210 211 212 v8::Local<Value> DeclarationContext::Get(Local<Name> key) { 213 return v8::Local<Value>(); 214 } 215 216 217 v8::Local<Value> DeclarationContext::Set(Local<Name> key, Local<Value> value) { 218 return v8::Local<Value>(); 219 } 220 221 222 v8::Local<Integer> DeclarationContext::Query(Local<Name> key) { 223 return v8::Local<Integer>(); 224 } 225 226 227 // Test global declaration of a property the interceptor doesn't know 228 // about and doesn't handle. 229 TEST(Unknown) { 230 i::FLAG_legacy_const = true; 231 HandleScope scope(CcTest::isolate()); 232 v8::V8::Initialize(); 233 234 { DeclarationContext context; 235 context.Check("var x; x", 236 1, // access 237 0, 0, EXPECT_RESULT, Undefined(CcTest::isolate())); 238 } 239 240 { DeclarationContext context; 241 context.Check("var x = 0; x", 242 1, // access 243 1, // initialization 244 0, EXPECT_RESULT, Number::New(CcTest::isolate(), 0)); 245 } 246 247 { DeclarationContext context; 248 context.Check("function x() { }; x", 249 1, // access 250 0, 251 0, 252 EXPECT_RESULT); 253 } 254 255 { DeclarationContext context; 256 context.Check("const x; x", 257 1, // access 258 0, 0, EXPECT_RESULT, Undefined(CcTest::isolate())); 259 } 260 261 { DeclarationContext context; 262 context.Check("const x = 0; x", 263 1, // access 264 0, 265 0, 266 EXPECT_RESULT, Number::New(CcTest::isolate(), 0)); 267 } 268 } 269 270 271 class AbsentPropertyContext: public DeclarationContext { 272 protected: 273 virtual v8::Local<Integer> Query(Local<Name> key) { 274 return v8::Local<Integer>(); 275 } 276 }; 277 278 279 TEST(Absent) { 280 i::FLAG_legacy_const = true; 281 v8::Isolate* isolate = CcTest::isolate(); 282 v8::V8::Initialize(); 283 HandleScope scope(isolate); 284 285 { AbsentPropertyContext context; 286 context.Check("var x; x", 287 1, // access 288 0, 0, EXPECT_RESULT, Undefined(isolate)); 289 } 290 291 { AbsentPropertyContext context; 292 context.Check("var x = 0; x", 293 1, // access 294 1, // initialization 295 0, EXPECT_RESULT, Number::New(isolate, 0)); 296 } 297 298 { AbsentPropertyContext context; 299 context.Check("function x() { }; x", 300 1, // access 301 0, 302 0, 303 EXPECT_RESULT); 304 } 305 306 { AbsentPropertyContext context; 307 context.Check("const x; x", 308 1, // access 309 0, 0, EXPECT_RESULT, Undefined(isolate)); 310 } 311 312 { AbsentPropertyContext context; 313 context.Check("const x = 0; x", 314 1, // access 315 0, 0, EXPECT_RESULT, Number::New(isolate, 0)); 316 } 317 318 { AbsentPropertyContext context; 319 context.Check("if (false) { var x = 0 }; x", 320 1, // access 321 0, 0, EXPECT_RESULT, Undefined(isolate)); 322 } 323 } 324 325 326 327 class AppearingPropertyContext: public DeclarationContext { 328 public: 329 enum State { 330 DECLARE, 331 INITIALIZE_IF_ASSIGN, 332 UNKNOWN 333 }; 334 335 AppearingPropertyContext() : state_(DECLARE) { } 336 337 protected: 338 virtual v8::Local<Integer> Query(Local<Name> key) { 339 switch (state_) { 340 case DECLARE: 341 // Force declaration by returning that the 342 // property is absent. 343 state_ = INITIALIZE_IF_ASSIGN; 344 return Local<Integer>(); 345 case INITIALIZE_IF_ASSIGN: 346 // Return that the property is present so we only get the 347 // setter called when initializing with a value. 348 state_ = UNKNOWN; 349 return Integer::New(isolate(), v8::None); 350 default: 351 CHECK(state_ == UNKNOWN); 352 break; 353 } 354 // Do the lookup in the object. 355 return v8::Local<Integer>(); 356 } 357 358 private: 359 State state_; 360 }; 361 362 363 TEST(Appearing) { 364 i::FLAG_legacy_const = true; 365 v8::V8::Initialize(); 366 HandleScope scope(CcTest::isolate()); 367 368 { AppearingPropertyContext context; 369 context.Check("var x; x", 370 1, // access 371 0, 0, EXPECT_RESULT, Undefined(CcTest::isolate())); 372 } 373 374 { AppearingPropertyContext context; 375 context.Check("var x = 0; x", 376 1, // access 377 1, // initialization 378 0, EXPECT_RESULT, Number::New(CcTest::isolate(), 0)); 379 } 380 381 { AppearingPropertyContext context; 382 context.Check("function x() { }; x", 383 1, // access 384 0, 385 0, 386 EXPECT_RESULT); 387 } 388 389 { AppearingPropertyContext context; 390 context.Check("const x; x", 391 1, // access 392 0, 0, EXPECT_RESULT, Undefined(CcTest::isolate())); 393 } 394 395 { AppearingPropertyContext context; 396 context.Check("const x = 0; x", 397 1, // access 398 0, 0, EXPECT_RESULT, Number::New(CcTest::isolate(), 0)); 399 } 400 } 401 402 403 404 class ExistsInPrototypeContext: public DeclarationContext { 405 public: 406 ExistsInPrototypeContext() { InitializeIfNeeded(); } 407 protected: 408 virtual v8::Local<Integer> Query(Local<Name> key) { 409 // Let it seem that the property exists in the prototype object. 410 return Integer::New(isolate(), v8::None); 411 } 412 413 // Use the prototype as the holder for the interceptors. 414 virtual Local<ObjectTemplate> GetHolder(Local<FunctionTemplate> function) { 415 return function->PrototypeTemplate(); 416 } 417 }; 418 419 420 TEST(ExistsInPrototype) { 421 i::FLAG_legacy_const = true; 422 HandleScope scope(CcTest::isolate()); 423 424 // Sanity check to make sure that the holder of the interceptor 425 // really is the prototype object. 426 { ExistsInPrototypeContext context; 427 context.Check("this.x = 87; this.x", 0, 0, 1, EXPECT_RESULT, 428 Number::New(CcTest::isolate(), 87)); 429 } 430 431 { ExistsInPrototypeContext context; 432 context.Check("var x; x", 433 0, 434 0, 435 0, 436 EXPECT_RESULT, Undefined(CcTest::isolate())); 437 } 438 439 { ExistsInPrototypeContext context; 440 context.Check("var x = 0; x", 441 0, 442 0, 443 0, 444 EXPECT_RESULT, Number::New(CcTest::isolate(), 0)); 445 } 446 447 { ExistsInPrototypeContext context; 448 context.Check("const x; x", 449 0, 450 0, 451 0, 452 EXPECT_RESULT, Undefined(CcTest::isolate())); 453 } 454 455 { ExistsInPrototypeContext context; 456 context.Check("const x = 0; x", 457 0, 458 0, 459 0, 460 EXPECT_RESULT, Number::New(CcTest::isolate(), 0)); 461 } 462 } 463 464 465 466 class AbsentInPrototypeContext: public DeclarationContext { 467 protected: 468 virtual v8::Local<Integer> Query(Local<Name> key) { 469 // Let it seem that the property is absent in the prototype object. 470 return Local<Integer>(); 471 } 472 473 // Use the prototype as the holder for the interceptors. 474 virtual Local<ObjectTemplate> GetHolder(Local<FunctionTemplate> function) { 475 return function->PrototypeTemplate(); 476 } 477 }; 478 479 480 TEST(AbsentInPrototype) { 481 v8::V8::Initialize(); 482 HandleScope scope(CcTest::isolate()); 483 484 { AbsentInPrototypeContext context; 485 context.Check("if (false) { var x = 0; }; x", 486 0, 487 0, 488 0, 489 EXPECT_RESULT, Undefined(CcTest::isolate())); 490 } 491 } 492 493 494 495 class ExistsInHiddenPrototypeContext: public DeclarationContext { 496 public: 497 ExistsInHiddenPrototypeContext() { 498 hidden_proto_ = FunctionTemplate::New(CcTest::isolate()); 499 hidden_proto_->SetHiddenPrototype(true); 500 } 501 502 protected: 503 virtual v8::Local<Integer> Query(Local<Name> key) { 504 // Let it seem that the property exists in the hidden prototype object. 505 return Integer::New(isolate(), v8::None); 506 } 507 508 // Install the hidden prototype after the global object has been created. 509 virtual void PostInitializeContext(Local<Context> context) { 510 Local<Object> global_object = context->Global(); 511 Local<Object> hidden_proto = hidden_proto_->GetFunction(context) 512 .ToLocalChecked() 513 ->NewInstance(context) 514 .ToLocalChecked(); 515 Local<Object> inner_global = 516 Local<Object>::Cast(global_object->GetPrototype()); 517 inner_global->SetPrototype(context, hidden_proto).FromJust(); 518 } 519 520 // Use the hidden prototype as the holder for the interceptors. 521 virtual Local<ObjectTemplate> GetHolder(Local<FunctionTemplate> function) { 522 return hidden_proto_->InstanceTemplate(); 523 } 524 525 private: 526 Local<FunctionTemplate> hidden_proto_; 527 }; 528 529 530 TEST(ExistsInHiddenPrototype) { 531 i::FLAG_legacy_const = true; 532 HandleScope scope(CcTest::isolate()); 533 534 { ExistsInHiddenPrototypeContext context; 535 context.Check("var x; x", 0, 0, 0, EXPECT_RESULT, 536 Undefined(CcTest::isolate())); 537 } 538 539 { ExistsInHiddenPrototypeContext context; 540 context.Check("var x = 0; x", 0, 0, 0, EXPECT_RESULT, 541 Number::New(CcTest::isolate(), 0)); 542 } 543 544 { ExistsInHiddenPrototypeContext context; 545 context.Check("function x() { }; x", 546 0, 547 0, 548 0, 549 EXPECT_RESULT); 550 } 551 552 // TODO(mstarzinger): The semantics of global const is vague. 553 { ExistsInHiddenPrototypeContext context; 554 context.Check("const x; x", 0, 0, 0, EXPECT_RESULT, 555 Undefined(CcTest::isolate())); 556 } 557 558 // TODO(mstarzinger): The semantics of global const is vague. 559 { ExistsInHiddenPrototypeContext context; 560 context.Check("const x = 0; x", 0, 0, 0, EXPECT_RESULT, 561 Number::New(CcTest::isolate(), 0)); 562 } 563 } 564 565 566 567 class SimpleContext { 568 public: 569 SimpleContext() 570 : handle_scope_(CcTest::isolate()), 571 context_(Context::New(CcTest::isolate())) { 572 context_->Enter(); 573 } 574 575 ~SimpleContext() { 576 context_->Exit(); 577 } 578 579 void Check(const char* source, Expectations expectations, 580 v8::Local<Value> value = Local<Value>()) { 581 HandleScope scope(context_->GetIsolate()); 582 TryCatch catcher(context_->GetIsolate()); 583 catcher.SetVerbose(true); 584 MaybeLocal<Script> script = Script::Compile( 585 context_, String::NewFromUtf8(context_->GetIsolate(), source, 586 v8::NewStringType::kNormal) 587 .ToLocalChecked()); 588 if (expectations == EXPECT_ERROR) { 589 CHECK(script.IsEmpty()); 590 return; 591 } 592 CHECK(!script.IsEmpty()); 593 MaybeLocal<Value> result = script.ToLocalChecked()->Run(context_); 594 if (expectations == EXPECT_RESULT) { 595 CHECK(!catcher.HasCaught()); 596 if (!value.IsEmpty()) { 597 CHECK(value->Equals(context_, result.ToLocalChecked()).FromJust()); 598 } 599 } else { 600 CHECK(expectations == EXPECT_EXCEPTION); 601 CHECK(catcher.HasCaught()); 602 if (!value.IsEmpty()) { 603 CHECK(value->Equals(context_, catcher.Exception()).FromJust()); 604 } 605 } 606 } 607 608 private: 609 HandleScope handle_scope_; 610 Local<Context> context_; 611 }; 612 613 614 TEST(CrossScriptReferences) { 615 i::FLAG_legacy_const = true; 616 v8::Isolate* isolate = CcTest::isolate(); 617 HandleScope scope(isolate); 618 619 { SimpleContext context; 620 context.Check("var x = 1; x", 621 EXPECT_RESULT, Number::New(isolate, 1)); 622 context.Check("var x = 2; x", 623 EXPECT_RESULT, Number::New(isolate, 2)); 624 context.Check("const x = 3; x", EXPECT_EXCEPTION); 625 context.Check("const x = 4; x", EXPECT_EXCEPTION); 626 context.Check("x = 5; x", 627 EXPECT_RESULT, Number::New(isolate, 5)); 628 context.Check("var x = 6; x", 629 EXPECT_RESULT, Number::New(isolate, 6)); 630 context.Check("this.x", 631 EXPECT_RESULT, Number::New(isolate, 6)); 632 context.Check("function x() { return 7 }; x()", 633 EXPECT_RESULT, Number::New(isolate, 7)); 634 } 635 636 { SimpleContext context; 637 context.Check("const x = 1; x", 638 EXPECT_RESULT, Number::New(isolate, 1)); 639 context.Check("var x = 2; x", // assignment ignored 640 EXPECT_RESULT, Number::New(isolate, 1)); 641 context.Check("const x = 3; x", EXPECT_EXCEPTION); 642 context.Check("x = 4; x", // assignment ignored 643 EXPECT_RESULT, Number::New(isolate, 1)); 644 context.Check("var x = 5; x", // assignment ignored 645 EXPECT_RESULT, Number::New(isolate, 1)); 646 context.Check("this.x", 647 EXPECT_RESULT, Number::New(isolate, 1)); 648 context.Check("function x() { return 7 }; x", 649 EXPECT_EXCEPTION); 650 } 651 } 652 653 654 TEST(CrossScriptReferences_Simple) { 655 i::FLAG_use_strict = true; 656 657 v8::Isolate* isolate = CcTest::isolate(); 658 HandleScope scope(isolate); 659 660 { 661 SimpleContext context; 662 context.Check("let x = 1; x", EXPECT_RESULT, Number::New(isolate, 1)); 663 context.Check("let x = 5; x", EXPECT_EXCEPTION); 664 } 665 } 666 667 668 TEST(CrossScriptReferences_Simple2) { 669 i::FLAG_use_strict = true; 670 671 v8::Isolate* isolate = CcTest::isolate(); 672 HandleScope scope(isolate); 673 674 for (int k = 0; k < 100; k++) { 675 SimpleContext context; 676 bool cond = (k % 2) == 0; 677 if (cond) { 678 context.Check("let x = 1; x", EXPECT_RESULT, Number::New(isolate, 1)); 679 context.Check("let z = 4; z", EXPECT_RESULT, Number::New(isolate, 4)); 680 } else { 681 context.Check("let z = 1; z", EXPECT_RESULT, Number::New(isolate, 1)); 682 context.Check("let x = 4; x", EXPECT_RESULT, Number::New(isolate, 4)); 683 } 684 context.Check("let y = 2; x", EXPECT_RESULT, 685 Number::New(isolate, cond ? 1 : 4)); 686 } 687 } 688 689 690 TEST(CrossScriptReferencesHarmony) { 691 v8::Isolate* isolate = CcTest::isolate(); 692 HandleScope scope(isolate); 693 694 // Check that simple cross-script global scope access works. 695 const char* decs[] = { 696 "'use strict'; var x = 1; x", "x", 697 "'use strict'; function x() { return 1 }; x()", "x()", 698 "'use strict'; let x = 1; x", "x", 699 "'use strict'; const x = 1; x", "x", 700 NULL 701 }; 702 703 for (int i = 0; decs[i] != NULL; i += 2) { 704 SimpleContext context; 705 context.Check(decs[i], EXPECT_RESULT, Number::New(isolate, 1)); 706 context.Check(decs[i+1], EXPECT_RESULT, Number::New(isolate, 1)); 707 } 708 709 // Check that cross-script global scope access works with late declarations. 710 { 711 SimpleContext context; 712 context.Check("function d0() { return x0 }", // dynamic lookup 713 EXPECT_RESULT, Undefined(isolate)); 714 context.Check("this.x0 = -1;" 715 "d0()", 716 EXPECT_RESULT, Number::New(isolate, -1)); 717 context.Check("'use strict';" 718 "function f0() { let y = 10; return x0 + y }" 719 "function g0() { let y = 10; return eval('x0 + y') }" 720 "function h0() { let y = 10; return (1,eval)('x0') + y }" 721 "x0 + f0() + g0() + h0()", 722 EXPECT_RESULT, Number::New(isolate, 26)); 723 724 context.Check("'use strict';" 725 "let x1 = 1;" 726 "function f1() { let y = 10; return x1 + y }" 727 "function g1() { let y = 10; return eval('x1 + y') }" 728 "function h1() { let y = 10; return (1,eval)('x1') + y }" 729 "function i1() { " 730 " let y = 10; return (typeof x2 === 'undefined' ? 0 : 2) + y" 731 "}" 732 "function j1() { let y = 10; return eval('x2 + y') }" 733 "function k1() { let y = 10; return (1,eval)('x2') + y }" 734 "function cl() { " 735 " let y = 10; " 736 " return { " 737 " f: function(){ return x1 + y }," 738 " g: function(){ return eval('x1 + y') }," 739 " h: function(){ return (1,eval)('x1') + y }," 740 " i: function(){" 741 " return (typeof x2 == 'undefined' ? 0 : 2) + y" 742 " }," 743 " j: function(){ return eval('x2 + y') }," 744 " k: function(){ return (1,eval)('x2') + y }," 745 " }" 746 "}" 747 "let o = cl();" 748 "x1 + eval('x1') + (1,eval)('x1') + f1() + g1() + h1();", 749 EXPECT_RESULT, Number::New(isolate, 36)); 750 context.Check("x1 + eval('x1') + (1,eval)('x1') + f1() + g1() + h1();", 751 EXPECT_RESULT, Number::New(isolate, 36)); 752 context.Check("o.f() + o.g() + o.h();", 753 EXPECT_RESULT, Number::New(isolate, 33)); 754 context.Check("i1() + o.i();", 755 EXPECT_RESULT, Number::New(isolate, 20)); 756 757 context.Check("'use strict';" 758 "let x2 = 2;" 759 "function f2() { let y = 20; return x2 + y }" 760 "function g2() { let y = 20; return eval('x2 + y') }" 761 "function h2() { let y = 20; return (1,eval)('x2') + y }" 762 "function i2() { let y = 20; return x1 + y }" 763 "function j2() { let y = 20; return eval('x1 + y') }" 764 "function k2() { let y = 20; return (1,eval)('x1') + y }" 765 "x2 + eval('x2') + (1,eval)('x2') + f2() + g2() + h2();", 766 EXPECT_RESULT, Number::New(isolate, 72)); 767 context.Check("x1 + eval('x1') + (1,eval)('x1') + f1() + g1() + h1();", 768 EXPECT_RESULT, Number::New(isolate, 36)); 769 context.Check("i1() + j1() + k1();", 770 EXPECT_RESULT, Number::New(isolate, 36)); 771 context.Check("i2() + j2() + k2();", 772 EXPECT_RESULT, Number::New(isolate, 63)); 773 context.Check("o.f() + o.g() + o.h();", 774 EXPECT_RESULT, Number::New(isolate, 33)); 775 context.Check("o.i() + o.j() + o.k();", 776 EXPECT_RESULT, Number::New(isolate, 36)); 777 context.Check("i1() + o.i();", 778 EXPECT_RESULT, Number::New(isolate, 24)); 779 780 context.Check("'use strict';" 781 "let x0 = 100;" 782 "x0 + eval('x0') + (1,eval)('x0') + " 783 " d0() + f0() + g0() + h0();", 784 EXPECT_RESULT, Number::New(isolate, 730)); 785 context.Check("x0 + eval('x0') + (1,eval)('x0') + " 786 " d0() + f0() + g0() + h0();", 787 EXPECT_RESULT, Number::New(isolate, 730)); 788 context.Check("delete this.x0;" 789 "x0 + eval('x0') + (1,eval)('x0') + " 790 " d0() + f0() + g0() + h0();", 791 EXPECT_RESULT, Number::New(isolate, 730)); 792 context.Check("this.x1 = 666;" 793 "x1 + eval('x1') + (1,eval)('x1') + f1() + g1() + h1();", 794 EXPECT_RESULT, Number::New(isolate, 36)); 795 context.Check("delete this.x1;" 796 "x1 + eval('x1') + (1,eval)('x1') + f1() + g1() + h1();", 797 EXPECT_RESULT, Number::New(isolate, 36)); 798 } 799 800 // Check that caching does respect scopes. 801 { 802 SimpleContext context; 803 const char* script1 = "(function(){ return y1 })()"; 804 const char* script2 = "(function(){ return y2 })()"; 805 806 context.Check(script1, EXPECT_EXCEPTION); 807 context.Check("this.y1 = 1; this.y2 = 2; 0;", 808 EXPECT_RESULT, Number::New(isolate, 0)); 809 context.Check(script1, 810 EXPECT_RESULT, Number::New(isolate, 1)); 811 context.Check("'use strict'; let y1 = 3; 0;", 812 EXPECT_RESULT, Number::New(isolate, 0)); 813 context.Check(script1, 814 EXPECT_RESULT, Number::New(isolate, 3)); 815 context.Check("y1 = 4;", 816 EXPECT_RESULT, Number::New(isolate, 4)); 817 context.Check(script1, 818 EXPECT_RESULT, Number::New(isolate, 4)); 819 820 context.Check(script2, 821 EXPECT_RESULT, Number::New(isolate, 2)); 822 context.Check("'use strict'; let y2 = 5; 0;", 823 EXPECT_RESULT, Number::New(isolate, 0)); 824 context.Check(script1, 825 EXPECT_RESULT, Number::New(isolate, 4)); 826 context.Check(script2, 827 EXPECT_RESULT, Number::New(isolate, 5)); 828 } 829 } 830 831 832 TEST(CrossScriptReferencesHarmonyRegress) { 833 v8::Isolate* isolate = CcTest::isolate(); 834 HandleScope scope(isolate); 835 SimpleContext context; 836 context.Check( 837 "'use strict';" 838 "function i1() { " 839 " let y = 10; return (typeof x2 === 'undefined' ? 0 : 2) + y" 840 "}" 841 "i1();" 842 "i1();", 843 EXPECT_RESULT, Number::New(isolate, 10)); 844 context.Check( 845 "'use strict';" 846 "let x2 = 2; i1();", 847 EXPECT_RESULT, Number::New(isolate, 12)); 848 } 849 850 851 TEST(GlobalLexicalOSR) { 852 i::FLAG_use_strict = true; 853 854 v8::Isolate* isolate = CcTest::isolate(); 855 HandleScope scope(isolate); 856 SimpleContext context; 857 858 context.Check("'use strict';" 859 "let x = 1; x;", 860 EXPECT_RESULT, Number::New(isolate, 1)); 861 context.Check("'use strict';" 862 "let y = 2*x;" 863 "++x;" 864 "let z = 0;" 865 "const limit = 100000;" 866 "for (var i = 0; i < limit; ++i) {" 867 " z += x + y;" 868 "}" 869 "z;", 870 EXPECT_RESULT, Number::New(isolate, 400000)); 871 } 872 873 874 TEST(CrossScriptConflicts) { 875 i::FLAG_use_strict = true; 876 877 HandleScope scope(CcTest::isolate()); 878 879 const char* firsts[] = { 880 "var x = 1; x", 881 "function x() { return 1 }; x()", 882 "let x = 1; x", 883 "const x = 1; x", 884 NULL 885 }; 886 const char* seconds[] = { 887 "var x = 2; x", 888 "function x() { return 2 }; x()", 889 "let x = 2; x", 890 "const x = 2; x", 891 NULL 892 }; 893 894 for (int i = 0; firsts[i] != NULL; ++i) { 895 for (int j = 0; seconds[j] != NULL; ++j) { 896 SimpleContext context; 897 context.Check(firsts[i], EXPECT_RESULT, 898 Number::New(CcTest::isolate(), 1)); 899 bool success_case = i < 2 && j < 2; 900 Local<Value> success_result; 901 if (success_case) success_result = Number::New(CcTest::isolate(), 2); 902 903 context.Check(seconds[j], success_case ? EXPECT_RESULT : EXPECT_EXCEPTION, 904 success_result); 905 } 906 } 907 } 908 909 910 TEST(CrossScriptDynamicLookup) { 911 HandleScope handle_scope(CcTest::isolate()); 912 913 { 914 SimpleContext context; 915 Local<String> undefined_string = 916 String::NewFromUtf8(CcTest::isolate(), "undefined", 917 v8::NewStringType::kInternalized) 918 .ToLocalChecked(); 919 Local<String> number_string = 920 String::NewFromUtf8(CcTest::isolate(), "number", 921 v8::NewStringType::kInternalized) 922 .ToLocalChecked(); 923 924 context.Check( 925 "function f(o) { with(o) { return x; } }" 926 "function g(o) { with(o) { x = 15; } }" 927 "function h(o) { with(o) { return typeof x; } }", 928 EXPECT_RESULT, Undefined(CcTest::isolate())); 929 context.Check("h({})", EXPECT_RESULT, undefined_string); 930 context.Check( 931 "'use strict';" 932 "let x = 1;" 933 "f({})", 934 EXPECT_RESULT, Number::New(CcTest::isolate(), 1)); 935 context.Check( 936 "'use strict';" 937 "g({});0", 938 EXPECT_RESULT, Number::New(CcTest::isolate(), 0)); 939 context.Check("f({})", EXPECT_RESULT, Number::New(CcTest::isolate(), 15)); 940 context.Check("h({})", EXPECT_RESULT, number_string); 941 } 942 } 943 944 945 TEST(CrossScriptGlobal) { 946 HandleScope handle_scope(CcTest::isolate()); 947 { 948 SimpleContext context; 949 950 context.Check( 951 "var global = this;" 952 "global.x = 255;" 953 "x", 954 EXPECT_RESULT, Number::New(CcTest::isolate(), 255)); 955 context.Check( 956 "'use strict';" 957 "let x = 1;" 958 "global.x", 959 EXPECT_RESULT, Number::New(CcTest::isolate(), 255)); 960 context.Check("global.x = 15; x", EXPECT_RESULT, 961 Number::New(CcTest::isolate(), 1)); 962 context.Check("x = 221; global.x", EXPECT_RESULT, 963 Number::New(CcTest::isolate(), 15)); 964 context.Check( 965 "z = 15;" 966 "function f() { return z; };" 967 "for (var k = 0; k < 3; k++) { f(); }" 968 "f()", 969 EXPECT_RESULT, Number::New(CcTest::isolate(), 15)); 970 context.Check( 971 "'use strict';" 972 "let z = 5; f()", 973 EXPECT_RESULT, Number::New(CcTest::isolate(), 5)); 974 context.Check( 975 "function f() { konst = 10; return konst; };" 976 "f()", 977 EXPECT_RESULT, Number::New(CcTest::isolate(), 10)); 978 context.Check( 979 "'use strict';" 980 "const konst = 255;" 981 "f()", 982 EXPECT_EXCEPTION); 983 } 984 } 985 986 987 TEST(CrossScriptStaticLookupUndeclared) { 988 HandleScope handle_scope(CcTest::isolate()); 989 990 { 991 SimpleContext context; 992 Local<String> undefined_string = 993 String::NewFromUtf8(CcTest::isolate(), "undefined", 994 v8::NewStringType::kInternalized) 995 .ToLocalChecked(); 996 Local<String> number_string = 997 String::NewFromUtf8(CcTest::isolate(), "number", 998 v8::NewStringType::kInternalized) 999 .ToLocalChecked(); 1000 1001 context.Check( 1002 "function f(o) { return x; }" 1003 "function g(v) { x = v; }" 1004 "function h(o) { return typeof x; }", 1005 EXPECT_RESULT, Undefined(CcTest::isolate())); 1006 context.Check("h({})", EXPECT_RESULT, undefined_string); 1007 context.Check( 1008 "'use strict';" 1009 "let x = 1;" 1010 "f({})", 1011 EXPECT_RESULT, Number::New(CcTest::isolate(), 1)); 1012 context.Check( 1013 "'use strict';" 1014 "g(15);x", 1015 EXPECT_RESULT, Number::New(CcTest::isolate(), 15)); 1016 context.Check("h({})", EXPECT_RESULT, number_string); 1017 context.Check("f({})", EXPECT_RESULT, Number::New(CcTest::isolate(), 15)); 1018 context.Check("h({})", EXPECT_RESULT, number_string); 1019 } 1020 } 1021 1022 1023 TEST(CrossScriptLoadICs) { 1024 i::FLAG_allow_natives_syntax = true; 1025 1026 HandleScope handle_scope(CcTest::isolate()); 1027 1028 { 1029 SimpleContext context; 1030 context.Check( 1031 "x = 15;" 1032 "function f() { return x; }" 1033 "function g() { return x; }" 1034 "f()", 1035 EXPECT_RESULT, Number::New(CcTest::isolate(), 15)); 1036 context.Check( 1037 "'use strict';" 1038 "let x = 5;" 1039 "f()", 1040 EXPECT_RESULT, Number::New(CcTest::isolate(), 5)); 1041 for (int k = 0; k < 3; k++) { 1042 context.Check("g()", EXPECT_RESULT, Number::New(CcTest::isolate(), 5)); 1043 } 1044 for (int k = 0; k < 3; k++) { 1045 context.Check("f()", EXPECT_RESULT, Number::New(CcTest::isolate(), 5)); 1046 } 1047 context.Check("%OptimizeFunctionOnNextCall(g); g()", EXPECT_RESULT, 1048 Number::New(CcTest::isolate(), 5)); 1049 context.Check("%OptimizeFunctionOnNextCall(f); f()", EXPECT_RESULT, 1050 Number::New(CcTest::isolate(), 5)); 1051 } 1052 { 1053 SimpleContext context; 1054 context.Check( 1055 "x = 15;" 1056 "function f() { return x; }" 1057 "f()", 1058 EXPECT_RESULT, Number::New(CcTest::isolate(), 15)); 1059 for (int k = 0; k < 3; k++) { 1060 context.Check("f()", EXPECT_RESULT, Number::New(CcTest::isolate(), 15)); 1061 } 1062 context.Check("%OptimizeFunctionOnNextCall(f); f()", EXPECT_RESULT, 1063 Number::New(CcTest::isolate(), 15)); 1064 context.Check( 1065 "'use strict';" 1066 "let x = 5;" 1067 "f()", 1068 EXPECT_RESULT, Number::New(CcTest::isolate(), 5)); 1069 for (int k = 0; k < 3; k++) { 1070 context.Check("f()", EXPECT_RESULT, Number::New(CcTest::isolate(), 5)); 1071 } 1072 context.Check("%OptimizeFunctionOnNextCall(f); f()", EXPECT_RESULT, 1073 Number::New(CcTest::isolate(), 5)); 1074 } 1075 } 1076 1077 1078 TEST(CrossScriptStoreICs) { 1079 i::FLAG_allow_natives_syntax = true; 1080 1081 HandleScope handle_scope(CcTest::isolate()); 1082 1083 { 1084 SimpleContext context; 1085 context.Check( 1086 "var global = this;" 1087 "x = 15;" 1088 "function f(v) { x = v; }" 1089 "function g(v) { x = v; }" 1090 "f(10); x", 1091 EXPECT_RESULT, Number::New(CcTest::isolate(), 10)); 1092 context.Check( 1093 "'use strict';" 1094 "let x = 5;" 1095 "f(7); x", 1096 EXPECT_RESULT, Number::New(CcTest::isolate(), 7)); 1097 context.Check("global.x", EXPECT_RESULT, 1098 Number::New(CcTest::isolate(), 10)); 1099 for (int k = 0; k < 3; k++) { 1100 context.Check("g(31); x", EXPECT_RESULT, 1101 Number::New(CcTest::isolate(), 31)); 1102 } 1103 context.Check("global.x", EXPECT_RESULT, 1104 Number::New(CcTest::isolate(), 10)); 1105 for (int k = 0; k < 3; k++) { 1106 context.Check("f(32); x", EXPECT_RESULT, 1107 Number::New(CcTest::isolate(), 32)); 1108 } 1109 context.Check("global.x", EXPECT_RESULT, 1110 Number::New(CcTest::isolate(), 10)); 1111 context.Check("%OptimizeFunctionOnNextCall(g); g(18); x", EXPECT_RESULT, 1112 Number::New(CcTest::isolate(), 18)); 1113 context.Check("global.x", EXPECT_RESULT, 1114 Number::New(CcTest::isolate(), 10)); 1115 context.Check("%OptimizeFunctionOnNextCall(f); f(33); x", EXPECT_RESULT, 1116 Number::New(CcTest::isolate(), 33)); 1117 context.Check("global.x", EXPECT_RESULT, 1118 Number::New(CcTest::isolate(), 10)); 1119 } 1120 { 1121 SimpleContext context; 1122 context.Check( 1123 "var global = this;" 1124 "x = 15;" 1125 "function f(v) { x = v; }" 1126 "f(10); x", 1127 EXPECT_RESULT, Number::New(CcTest::isolate(), 10)); 1128 for (int k = 0; k < 3; k++) { 1129 context.Check("f(18); x", EXPECT_RESULT, 1130 Number::New(CcTest::isolate(), 18)); 1131 } 1132 context.Check("%OptimizeFunctionOnNextCall(f); f(20); x", EXPECT_RESULT, 1133 Number::New(CcTest::isolate(), 20)); 1134 context.Check( 1135 "'use strict';" 1136 "let x = 5;" 1137 "f(8); x", 1138 EXPECT_RESULT, Number::New(CcTest::isolate(), 8)); 1139 context.Check("global.x", EXPECT_RESULT, 1140 Number::New(CcTest::isolate(), 20)); 1141 for (int k = 0; k < 3; k++) { 1142 context.Check("f(13); x", EXPECT_RESULT, 1143 Number::New(CcTest::isolate(), 13)); 1144 } 1145 context.Check("global.x", EXPECT_RESULT, 1146 Number::New(CcTest::isolate(), 20)); 1147 context.Check("%OptimizeFunctionOnNextCall(f); f(41); x", EXPECT_RESULT, 1148 Number::New(CcTest::isolate(), 41)); 1149 context.Check("global.x", EXPECT_RESULT, 1150 Number::New(CcTest::isolate(), 20)); 1151 } 1152 } 1153 1154 1155 TEST(CrossScriptAssignmentToConst) { 1156 i::FLAG_allow_natives_syntax = true; 1157 1158 HandleScope handle_scope(CcTest::isolate()); 1159 1160 { 1161 SimpleContext context; 1162 1163 context.Check("function f() { x = 27; }", EXPECT_RESULT, 1164 Undefined(CcTest::isolate())); 1165 context.Check("'use strict';const x = 1; x", EXPECT_RESULT, 1166 Number::New(CcTest::isolate(), 1)); 1167 context.Check("f();", EXPECT_EXCEPTION); 1168 context.Check("x", EXPECT_RESULT, Number::New(CcTest::isolate(), 1)); 1169 context.Check("f();", EXPECT_EXCEPTION); 1170 context.Check("x", EXPECT_RESULT, Number::New(CcTest::isolate(), 1)); 1171 context.Check("%OptimizeFunctionOnNextCall(f);f();", EXPECT_EXCEPTION); 1172 context.Check("x", EXPECT_RESULT, Number::New(CcTest::isolate(), 1)); 1173 } 1174 } 1175 1176 1177 TEST(Regress425510) { 1178 i::FLAG_allow_natives_syntax = true; 1179 1180 HandleScope handle_scope(CcTest::isolate()); 1181 1182 { 1183 SimpleContext context; 1184 1185 context.Check("'use strict'; o; const o = 10", EXPECT_EXCEPTION); 1186 1187 for (int i = 0; i < 100; i++) { 1188 context.Check("o.prototype", EXPECT_EXCEPTION); 1189 } 1190 } 1191 } 1192 1193 1194 TEST(Regress3941) { 1195 i::FLAG_allow_natives_syntax = true; 1196 1197 HandleScope handle_scope(CcTest::isolate()); 1198 1199 { 1200 SimpleContext context; 1201 context.Check("function f() { x = 1; }", EXPECT_RESULT, 1202 Undefined(CcTest::isolate())); 1203 context.Check("'use strict'; f(); let x = 2; x", EXPECT_EXCEPTION); 1204 } 1205 1206 1207 { 1208 // Train ICs. 1209 SimpleContext context; 1210 context.Check("function f() { x = 1; }", EXPECT_RESULT, 1211 Undefined(CcTest::isolate())); 1212 for (int i = 0; i < 4; i++) { 1213 context.Check("f(); x", EXPECT_RESULT, Number::New(CcTest::isolate(), 1)); 1214 } 1215 context.Check("'use strict'; f(); let x = 2; x", EXPECT_EXCEPTION); 1216 } 1217 1218 1219 { 1220 // Optimize. 1221 SimpleContext context; 1222 context.Check("function f() { x = 1; }", EXPECT_RESULT, 1223 Undefined(CcTest::isolate())); 1224 for (int i = 0; i < 4; i++) { 1225 context.Check("f(); x", EXPECT_RESULT, Number::New(CcTest::isolate(), 1)); 1226 } 1227 context.Check("%OptimizeFunctionOnNextCall(f); f(); x", EXPECT_RESULT, 1228 Number::New(CcTest::isolate(), 1)); 1229 1230 context.Check("'use strict'; f(); let x = 2; x", EXPECT_EXCEPTION); 1231 } 1232 } 1233 1234 1235 TEST(Regress3941_Reads) { 1236 i::FLAG_allow_natives_syntax = true; 1237 1238 HandleScope handle_scope(CcTest::isolate()); 1239 1240 { 1241 SimpleContext context; 1242 context.Check("function f() { return x; }", EXPECT_RESULT, 1243 Undefined(CcTest::isolate())); 1244 context.Check("'use strict'; f(); let x = 2; x", EXPECT_EXCEPTION); 1245 } 1246 1247 1248 { 1249 // Train ICs. 1250 SimpleContext context; 1251 context.Check("function f() { return x; }", EXPECT_RESULT, 1252 Undefined(CcTest::isolate())); 1253 for (int i = 0; i < 4; i++) { 1254 context.Check("f()", EXPECT_EXCEPTION); 1255 } 1256 context.Check("'use strict'; f(); let x = 2; x", EXPECT_EXCEPTION); 1257 } 1258 1259 1260 { 1261 // Optimize. 1262 SimpleContext context; 1263 context.Check("function f() { return x; }", EXPECT_RESULT, 1264 Undefined(CcTest::isolate())); 1265 for (int i = 0; i < 4; i++) { 1266 context.Check("f()", EXPECT_EXCEPTION); 1267 } 1268 context.Check("%OptimizeFunctionOnNextCall(f);", EXPECT_RESULT, 1269 Undefined(CcTest::isolate())); 1270 1271 context.Check("'use strict'; f(); let x = 2; x", EXPECT_EXCEPTION); 1272 } 1273 } 1274