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 HandleScope scope(CcTest::isolate()); 231 v8::V8::Initialize(); 232 233 { DeclarationContext context; 234 context.Check("var x; x", 235 1, // access 236 0, 0, EXPECT_RESULT, Undefined(CcTest::isolate())); 237 } 238 239 { DeclarationContext context; 240 context.Check("var x = 0; x", 241 1, // access 242 1, // initialization 243 0, EXPECT_RESULT, Number::New(CcTest::isolate(), 0)); 244 } 245 246 { DeclarationContext context; 247 context.Check("function x() { }; x", 248 1, // access 249 0, 250 0, 251 EXPECT_RESULT); 252 } 253 } 254 255 256 class AbsentPropertyContext: public DeclarationContext { 257 protected: 258 virtual v8::Local<Integer> Query(Local<Name> key) { 259 return v8::Local<Integer>(); 260 } 261 }; 262 263 264 TEST(Absent) { 265 v8::Isolate* isolate = CcTest::isolate(); 266 v8::V8::Initialize(); 267 HandleScope scope(isolate); 268 269 { AbsentPropertyContext context; 270 context.Check("var x; x", 271 1, // access 272 0, 0, EXPECT_RESULT, Undefined(isolate)); 273 } 274 275 { AbsentPropertyContext context; 276 context.Check("var x = 0; x", 277 1, // access 278 1, // initialization 279 0, EXPECT_RESULT, Number::New(isolate, 0)); 280 } 281 282 { AbsentPropertyContext context; 283 context.Check("function x() { }; x", 284 1, // access 285 0, 286 0, 287 EXPECT_RESULT); 288 } 289 290 { AbsentPropertyContext context; 291 context.Check("if (false) { var x = 0 }; x", 292 1, // access 293 0, 0, EXPECT_RESULT, Undefined(isolate)); 294 } 295 } 296 297 298 299 class AppearingPropertyContext: public DeclarationContext { 300 public: 301 enum State { 302 DECLARE, 303 INITIALIZE_IF_ASSIGN, 304 UNKNOWN 305 }; 306 307 AppearingPropertyContext() : state_(DECLARE) { } 308 309 protected: 310 virtual v8::Local<Integer> Query(Local<Name> key) { 311 switch (state_) { 312 case DECLARE: 313 // Force declaration by returning that the 314 // property is absent. 315 state_ = INITIALIZE_IF_ASSIGN; 316 return Local<Integer>(); 317 case INITIALIZE_IF_ASSIGN: 318 // Return that the property is present so we only get the 319 // setter called when initializing with a value. 320 state_ = UNKNOWN; 321 return Integer::New(isolate(), v8::None); 322 default: 323 CHECK(state_ == UNKNOWN); 324 break; 325 } 326 // Do the lookup in the object. 327 return v8::Local<Integer>(); 328 } 329 330 private: 331 State state_; 332 }; 333 334 335 TEST(Appearing) { 336 v8::V8::Initialize(); 337 HandleScope scope(CcTest::isolate()); 338 339 { AppearingPropertyContext context; 340 context.Check("var x; x", 341 1, // access 342 0, 0, EXPECT_RESULT, Undefined(CcTest::isolate())); 343 } 344 345 { AppearingPropertyContext context; 346 context.Check("var x = 0; x", 347 1, // access 348 1, // initialization 349 0, EXPECT_RESULT, Number::New(CcTest::isolate(), 0)); 350 } 351 352 { AppearingPropertyContext context; 353 context.Check("function x() { }; x", 354 1, // access 355 0, 356 0, 357 EXPECT_RESULT); 358 } 359 } 360 361 362 363 class ExistsInPrototypeContext: public DeclarationContext { 364 public: 365 ExistsInPrototypeContext() { InitializeIfNeeded(); } 366 protected: 367 virtual v8::Local<Integer> Query(Local<Name> key) { 368 // Let it seem that the property exists in the prototype object. 369 return Integer::New(isolate(), v8::None); 370 } 371 372 // Use the prototype as the holder for the interceptors. 373 virtual Local<ObjectTemplate> GetHolder(Local<FunctionTemplate> function) { 374 return function->PrototypeTemplate(); 375 } 376 }; 377 378 379 TEST(ExistsInPrototype) { 380 HandleScope scope(CcTest::isolate()); 381 382 // Sanity check to make sure that the holder of the interceptor 383 // really is the prototype object. 384 { ExistsInPrototypeContext context; 385 context.Check("this.x = 87; this.x", 0, 0, 1, EXPECT_RESULT, 386 Number::New(CcTest::isolate(), 87)); 387 } 388 389 { ExistsInPrototypeContext context; 390 context.Check("var x; x", 391 0, 392 0, 393 0, 394 EXPECT_RESULT, Undefined(CcTest::isolate())); 395 } 396 397 { ExistsInPrototypeContext context; 398 context.Check("var x = 0; x", 399 0, 400 0, 401 0, 402 EXPECT_RESULT, Number::New(CcTest::isolate(), 0)); 403 } 404 } 405 406 407 408 class AbsentInPrototypeContext: public DeclarationContext { 409 protected: 410 virtual v8::Local<Integer> Query(Local<Name> key) { 411 // Let it seem that the property is absent in the prototype object. 412 return Local<Integer>(); 413 } 414 415 // Use the prototype as the holder for the interceptors. 416 virtual Local<ObjectTemplate> GetHolder(Local<FunctionTemplate> function) { 417 return function->PrototypeTemplate(); 418 } 419 }; 420 421 422 TEST(AbsentInPrototype) { 423 v8::V8::Initialize(); 424 HandleScope scope(CcTest::isolate()); 425 426 { AbsentInPrototypeContext context; 427 context.Check("if (false) { var x = 0; }; x", 428 0, 429 0, 430 0, 431 EXPECT_RESULT, Undefined(CcTest::isolate())); 432 } 433 } 434 435 436 437 class ExistsInHiddenPrototypeContext: public DeclarationContext { 438 public: 439 ExistsInHiddenPrototypeContext() { 440 hidden_proto_ = FunctionTemplate::New(CcTest::isolate()); 441 hidden_proto_->SetHiddenPrototype(true); 442 } 443 444 protected: 445 virtual v8::Local<Integer> Query(Local<Name> key) { 446 // Let it seem that the property exists in the hidden prototype object. 447 return Integer::New(isolate(), v8::None); 448 } 449 450 // Install the hidden prototype after the global object has been created. 451 virtual void PostInitializeContext(Local<Context> context) { 452 Local<Object> global_object = context->Global(); 453 Local<Object> hidden_proto = hidden_proto_->GetFunction(context) 454 .ToLocalChecked() 455 ->NewInstance(context) 456 .ToLocalChecked(); 457 Local<Object> inner_global = 458 Local<Object>::Cast(global_object->GetPrototype()); 459 inner_global->SetPrototype(context, hidden_proto).FromJust(); 460 } 461 462 // Use the hidden prototype as the holder for the interceptors. 463 virtual Local<ObjectTemplate> GetHolder(Local<FunctionTemplate> function) { 464 return hidden_proto_->InstanceTemplate(); 465 } 466 467 private: 468 Local<FunctionTemplate> hidden_proto_; 469 }; 470 471 472 TEST(ExistsInHiddenPrototype) { 473 HandleScope scope(CcTest::isolate()); 474 475 { ExistsInHiddenPrototypeContext context; 476 context.Check("var x; x", 0, 0, 0, EXPECT_RESULT, 477 Undefined(CcTest::isolate())); 478 } 479 480 { ExistsInHiddenPrototypeContext context; 481 context.Check("var x = 0; x", 0, 0, 0, EXPECT_RESULT, 482 Number::New(CcTest::isolate(), 0)); 483 } 484 485 { ExistsInHiddenPrototypeContext context; 486 context.Check("function x() { }; x", 487 0, 488 0, 489 0, 490 EXPECT_RESULT); 491 } 492 } 493 494 495 496 class SimpleContext { 497 public: 498 SimpleContext() 499 : handle_scope_(CcTest::isolate()), 500 context_(Context::New(CcTest::isolate())) { 501 context_->Enter(); 502 } 503 504 ~SimpleContext() { 505 context_->Exit(); 506 } 507 508 void Check(const char* source, Expectations expectations, 509 v8::Local<Value> value = Local<Value>()) { 510 HandleScope scope(context_->GetIsolate()); 511 TryCatch catcher(context_->GetIsolate()); 512 catcher.SetVerbose(true); 513 MaybeLocal<Script> script = Script::Compile( 514 context_, String::NewFromUtf8(context_->GetIsolate(), source, 515 v8::NewStringType::kNormal) 516 .ToLocalChecked()); 517 if (expectations == EXPECT_ERROR) { 518 CHECK(script.IsEmpty()); 519 return; 520 } 521 CHECK(!script.IsEmpty()); 522 MaybeLocal<Value> result = script.ToLocalChecked()->Run(context_); 523 if (expectations == EXPECT_RESULT) { 524 CHECK(!catcher.HasCaught()); 525 if (!value.IsEmpty()) { 526 CHECK(value->Equals(context_, result.ToLocalChecked()).FromJust()); 527 } 528 } else { 529 CHECK(expectations == EXPECT_EXCEPTION); 530 CHECK(catcher.HasCaught()); 531 if (!value.IsEmpty()) { 532 CHECK(value->Equals(context_, catcher.Exception()).FromJust()); 533 } 534 } 535 } 536 537 private: 538 HandleScope handle_scope_; 539 Local<Context> context_; 540 }; 541 542 543 TEST(CrossScriptReferences) { 544 v8::Isolate* isolate = CcTest::isolate(); 545 HandleScope scope(isolate); 546 547 { SimpleContext context; 548 context.Check("var x = 1; x", 549 EXPECT_RESULT, Number::New(isolate, 1)); 550 context.Check("var x = 2; x", 551 EXPECT_RESULT, Number::New(isolate, 2)); 552 context.Check("x = 5; x", 553 EXPECT_RESULT, Number::New(isolate, 5)); 554 context.Check("var x = 6; x", 555 EXPECT_RESULT, Number::New(isolate, 6)); 556 context.Check("this.x", 557 EXPECT_RESULT, Number::New(isolate, 6)); 558 context.Check("function x() { return 7 }; x()", 559 EXPECT_RESULT, Number::New(isolate, 7)); 560 } 561 } 562 563 564 TEST(CrossScriptReferences_Simple) { 565 i::FLAG_use_strict = true; 566 567 v8::Isolate* isolate = CcTest::isolate(); 568 HandleScope scope(isolate); 569 570 { 571 SimpleContext context; 572 context.Check("let x = 1; x", EXPECT_RESULT, Number::New(isolate, 1)); 573 context.Check("let x = 5; x", EXPECT_EXCEPTION); 574 } 575 } 576 577 578 TEST(CrossScriptReferences_Simple2) { 579 i::FLAG_use_strict = true; 580 581 v8::Isolate* isolate = CcTest::isolate(); 582 HandleScope scope(isolate); 583 584 for (int k = 0; k < 100; k++) { 585 SimpleContext context; 586 bool cond = (k % 2) == 0; 587 if (cond) { 588 context.Check("let x = 1; x", EXPECT_RESULT, Number::New(isolate, 1)); 589 context.Check("let z = 4; z", EXPECT_RESULT, Number::New(isolate, 4)); 590 } else { 591 context.Check("let z = 1; z", EXPECT_RESULT, Number::New(isolate, 1)); 592 context.Check("let x = 4; x", EXPECT_RESULT, Number::New(isolate, 4)); 593 } 594 context.Check("let y = 2; x", EXPECT_RESULT, 595 Number::New(isolate, cond ? 1 : 4)); 596 } 597 } 598 599 600 TEST(CrossScriptReferencesHarmony) { 601 v8::Isolate* isolate = CcTest::isolate(); 602 HandleScope scope(isolate); 603 604 // Check that simple cross-script global scope access works. 605 const char* decs[] = { 606 "'use strict'; var x = 1; x", "x", 607 "'use strict'; function x() { return 1 }; x()", "x()", 608 "'use strict'; let x = 1; x", "x", 609 "'use strict'; const x = 1; x", "x", 610 NULL 611 }; 612 613 for (int i = 0; decs[i] != NULL; i += 2) { 614 SimpleContext context; 615 context.Check(decs[i], EXPECT_RESULT, Number::New(isolate, 1)); 616 context.Check(decs[i+1], EXPECT_RESULT, Number::New(isolate, 1)); 617 } 618 619 // Check that cross-script global scope access works with late declarations. 620 { 621 SimpleContext context; 622 context.Check("function d0() { return x0 }", // dynamic lookup 623 EXPECT_RESULT, Undefined(isolate)); 624 context.Check("this.x0 = -1;" 625 "d0()", 626 EXPECT_RESULT, Number::New(isolate, -1)); 627 context.Check("'use strict';" 628 "function f0() { let y = 10; return x0 + y }" 629 "function g0() { let y = 10; return eval('x0 + y') }" 630 "function h0() { let y = 10; return (1,eval)('x0') + y }" 631 "x0 + f0() + g0() + h0()", 632 EXPECT_RESULT, Number::New(isolate, 26)); 633 634 context.Check("'use strict';" 635 "let x1 = 1;" 636 "function f1() { let y = 10; return x1 + y }" 637 "function g1() { let y = 10; return eval('x1 + y') }" 638 "function h1() { let y = 10; return (1,eval)('x1') + y }" 639 "function i1() { " 640 " let y = 10; return (typeof x2 === 'undefined' ? 0 : 2) + y" 641 "}" 642 "function j1() { let y = 10; return eval('x2 + y') }" 643 "function k1() { let y = 10; return (1,eval)('x2') + y }" 644 "function cl() { " 645 " let y = 10; " 646 " return { " 647 " f: function(){ return x1 + y }," 648 " g: function(){ return eval('x1 + y') }," 649 " h: function(){ return (1,eval)('x1') + y }," 650 " i: function(){" 651 " return (typeof x2 == 'undefined' ? 0 : 2) + y" 652 " }," 653 " j: function(){ return eval('x2 + y') }," 654 " k: function(){ return (1,eval)('x2') + y }," 655 " }" 656 "}" 657 "let o = cl();" 658 "x1 + eval('x1') + (1,eval)('x1') + f1() + g1() + h1();", 659 EXPECT_RESULT, Number::New(isolate, 36)); 660 context.Check("x1 + eval('x1') + (1,eval)('x1') + f1() + g1() + h1();", 661 EXPECT_RESULT, Number::New(isolate, 36)); 662 context.Check("o.f() + o.g() + o.h();", 663 EXPECT_RESULT, Number::New(isolate, 33)); 664 context.Check("i1() + o.i();", 665 EXPECT_RESULT, Number::New(isolate, 20)); 666 667 context.Check("'use strict';" 668 "let x2 = 2;" 669 "function f2() { let y = 20; return x2 + y }" 670 "function g2() { let y = 20; return eval('x2 + y') }" 671 "function h2() { let y = 20; return (1,eval)('x2') + y }" 672 "function i2() { let y = 20; return x1 + y }" 673 "function j2() { let y = 20; return eval('x1 + y') }" 674 "function k2() { let y = 20; return (1,eval)('x1') + y }" 675 "x2 + eval('x2') + (1,eval)('x2') + f2() + g2() + h2();", 676 EXPECT_RESULT, Number::New(isolate, 72)); 677 context.Check("x1 + eval('x1') + (1,eval)('x1') + f1() + g1() + h1();", 678 EXPECT_RESULT, Number::New(isolate, 36)); 679 context.Check("i1() + j1() + k1();", 680 EXPECT_RESULT, Number::New(isolate, 36)); 681 context.Check("i2() + j2() + k2();", 682 EXPECT_RESULT, Number::New(isolate, 63)); 683 context.Check("o.f() + o.g() + o.h();", 684 EXPECT_RESULT, Number::New(isolate, 33)); 685 context.Check("o.i() + o.j() + o.k();", 686 EXPECT_RESULT, Number::New(isolate, 36)); 687 context.Check("i1() + o.i();", 688 EXPECT_RESULT, Number::New(isolate, 24)); 689 690 context.Check("'use strict';" 691 "let x0 = 100;" 692 "x0 + eval('x0') + (1,eval)('x0') + " 693 " d0() + f0() + g0() + h0();", 694 EXPECT_RESULT, Number::New(isolate, 730)); 695 context.Check("x0 + eval('x0') + (1,eval)('x0') + " 696 " d0() + f0() + g0() + h0();", 697 EXPECT_RESULT, Number::New(isolate, 730)); 698 context.Check("delete this.x0;" 699 "x0 + eval('x0') + (1,eval)('x0') + " 700 " d0() + f0() + g0() + h0();", 701 EXPECT_RESULT, Number::New(isolate, 730)); 702 context.Check("this.x1 = 666;" 703 "x1 + eval('x1') + (1,eval)('x1') + f1() + g1() + h1();", 704 EXPECT_RESULT, Number::New(isolate, 36)); 705 context.Check("delete this.x1;" 706 "x1 + eval('x1') + (1,eval)('x1') + f1() + g1() + h1();", 707 EXPECT_RESULT, Number::New(isolate, 36)); 708 } 709 710 // Check that caching does respect scopes. 711 { 712 SimpleContext context; 713 const char* script1 = "(function(){ return y1 })()"; 714 const char* script2 = "(function(){ return y2 })()"; 715 716 context.Check(script1, EXPECT_EXCEPTION); 717 context.Check("this.y1 = 1; this.y2 = 2; 0;", 718 EXPECT_RESULT, Number::New(isolate, 0)); 719 context.Check(script1, 720 EXPECT_RESULT, Number::New(isolate, 1)); 721 context.Check("'use strict'; let y1 = 3; 0;", 722 EXPECT_RESULT, Number::New(isolate, 0)); 723 context.Check(script1, 724 EXPECT_RESULT, Number::New(isolate, 3)); 725 context.Check("y1 = 4;", 726 EXPECT_RESULT, Number::New(isolate, 4)); 727 context.Check(script1, 728 EXPECT_RESULT, Number::New(isolate, 4)); 729 730 context.Check(script2, 731 EXPECT_RESULT, Number::New(isolate, 2)); 732 context.Check("'use strict'; let y2 = 5; 0;", 733 EXPECT_RESULT, Number::New(isolate, 0)); 734 context.Check(script1, 735 EXPECT_RESULT, Number::New(isolate, 4)); 736 context.Check(script2, 737 EXPECT_RESULT, Number::New(isolate, 5)); 738 } 739 } 740 741 742 TEST(CrossScriptReferencesHarmonyRegress) { 743 v8::Isolate* isolate = CcTest::isolate(); 744 HandleScope scope(isolate); 745 SimpleContext context; 746 context.Check( 747 "'use strict';" 748 "function i1() { " 749 " let y = 10; return (typeof x2 === 'undefined' ? 0 : 2) + y" 750 "}" 751 "i1();" 752 "i1();", 753 EXPECT_RESULT, Number::New(isolate, 10)); 754 context.Check( 755 "'use strict';" 756 "let x2 = 2; i1();", 757 EXPECT_RESULT, Number::New(isolate, 12)); 758 } 759 760 761 TEST(GlobalLexicalOSR) { 762 i::FLAG_use_strict = true; 763 764 v8::Isolate* isolate = CcTest::isolate(); 765 HandleScope scope(isolate); 766 SimpleContext context; 767 768 context.Check("'use strict';" 769 "let x = 1; x;", 770 EXPECT_RESULT, Number::New(isolate, 1)); 771 context.Check("'use strict';" 772 "let y = 2*x;" 773 "++x;" 774 "let z = 0;" 775 "const limit = 100000;" 776 "for (var i = 0; i < limit; ++i) {" 777 " z += x + y;" 778 "}" 779 "z;", 780 EXPECT_RESULT, Number::New(isolate, 400000)); 781 } 782 783 784 TEST(CrossScriptConflicts) { 785 i::FLAG_use_strict = true; 786 787 HandleScope scope(CcTest::isolate()); 788 789 const char* firsts[] = { 790 "var x = 1; x", 791 "function x() { return 1 }; x()", 792 "let x = 1; x", 793 "const x = 1; x", 794 NULL 795 }; 796 const char* seconds[] = { 797 "var x = 2; x", 798 "function x() { return 2 }; x()", 799 "let x = 2; x", 800 "const x = 2; x", 801 NULL 802 }; 803 804 for (int i = 0; firsts[i] != NULL; ++i) { 805 for (int j = 0; seconds[j] != NULL; ++j) { 806 SimpleContext context; 807 context.Check(firsts[i], EXPECT_RESULT, 808 Number::New(CcTest::isolate(), 1)); 809 bool success_case = i < 2 && j < 2; 810 Local<Value> success_result; 811 if (success_case) success_result = Number::New(CcTest::isolate(), 2); 812 813 context.Check(seconds[j], success_case ? EXPECT_RESULT : EXPECT_EXCEPTION, 814 success_result); 815 } 816 } 817 } 818 819 820 TEST(CrossScriptDynamicLookup) { 821 HandleScope handle_scope(CcTest::isolate()); 822 823 { 824 SimpleContext context; 825 Local<String> undefined_string = 826 String::NewFromUtf8(CcTest::isolate(), "undefined", 827 v8::NewStringType::kInternalized) 828 .ToLocalChecked(); 829 Local<String> number_string = 830 String::NewFromUtf8(CcTest::isolate(), "number", 831 v8::NewStringType::kInternalized) 832 .ToLocalChecked(); 833 834 context.Check( 835 "function f(o) { with(o) { return x; } }" 836 "function g(o) { with(o) { x = 15; } }" 837 "function h(o) { with(o) { return typeof x; } }", 838 EXPECT_RESULT, Undefined(CcTest::isolate())); 839 context.Check("h({})", EXPECT_RESULT, undefined_string); 840 context.Check( 841 "'use strict';" 842 "let x = 1;" 843 "f({})", 844 EXPECT_RESULT, Number::New(CcTest::isolate(), 1)); 845 context.Check( 846 "'use strict';" 847 "g({});0", 848 EXPECT_RESULT, Number::New(CcTest::isolate(), 0)); 849 context.Check("f({})", EXPECT_RESULT, Number::New(CcTest::isolate(), 15)); 850 context.Check("h({})", EXPECT_RESULT, number_string); 851 } 852 } 853 854 855 TEST(CrossScriptGlobal) { 856 HandleScope handle_scope(CcTest::isolate()); 857 { 858 SimpleContext context; 859 860 context.Check( 861 "var global = this;" 862 "global.x = 255;" 863 "x", 864 EXPECT_RESULT, Number::New(CcTest::isolate(), 255)); 865 context.Check( 866 "'use strict';" 867 "let x = 1;" 868 "global.x", 869 EXPECT_RESULT, Number::New(CcTest::isolate(), 255)); 870 context.Check("global.x = 15; x", EXPECT_RESULT, 871 Number::New(CcTest::isolate(), 1)); 872 context.Check("x = 221; global.x", EXPECT_RESULT, 873 Number::New(CcTest::isolate(), 15)); 874 context.Check( 875 "z = 15;" 876 "function f() { return z; };" 877 "for (var k = 0; k < 3; k++) { f(); }" 878 "f()", 879 EXPECT_RESULT, Number::New(CcTest::isolate(), 15)); 880 context.Check( 881 "'use strict';" 882 "let z = 5; f()", 883 EXPECT_RESULT, Number::New(CcTest::isolate(), 5)); 884 context.Check( 885 "function f() { konst = 10; return konst; };" 886 "f()", 887 EXPECT_RESULT, Number::New(CcTest::isolate(), 10)); 888 context.Check( 889 "'use strict';" 890 "const konst = 255;" 891 "f()", 892 EXPECT_EXCEPTION); 893 } 894 } 895 896 897 TEST(CrossScriptStaticLookupUndeclared) { 898 HandleScope handle_scope(CcTest::isolate()); 899 900 { 901 SimpleContext context; 902 Local<String> undefined_string = 903 String::NewFromUtf8(CcTest::isolate(), "undefined", 904 v8::NewStringType::kInternalized) 905 .ToLocalChecked(); 906 Local<String> number_string = 907 String::NewFromUtf8(CcTest::isolate(), "number", 908 v8::NewStringType::kInternalized) 909 .ToLocalChecked(); 910 911 context.Check( 912 "function f(o) { return x; }" 913 "function g(v) { x = v; }" 914 "function h(o) { return typeof x; }", 915 EXPECT_RESULT, Undefined(CcTest::isolate())); 916 context.Check("h({})", EXPECT_RESULT, undefined_string); 917 context.Check( 918 "'use strict';" 919 "let x = 1;" 920 "f({})", 921 EXPECT_RESULT, Number::New(CcTest::isolate(), 1)); 922 context.Check( 923 "'use strict';" 924 "g(15);x", 925 EXPECT_RESULT, Number::New(CcTest::isolate(), 15)); 926 context.Check("h({})", EXPECT_RESULT, number_string); 927 context.Check("f({})", EXPECT_RESULT, Number::New(CcTest::isolate(), 15)); 928 context.Check("h({})", EXPECT_RESULT, number_string); 929 } 930 } 931 932 933 TEST(CrossScriptLoadICs) { 934 i::FLAG_allow_natives_syntax = true; 935 936 HandleScope handle_scope(CcTest::isolate()); 937 938 { 939 SimpleContext context; 940 context.Check( 941 "x = 15;" 942 "function f() { return x; }" 943 "function g() { return x; }" 944 "f()", 945 EXPECT_RESULT, Number::New(CcTest::isolate(), 15)); 946 context.Check( 947 "'use strict';" 948 "let x = 5;" 949 "f()", 950 EXPECT_RESULT, Number::New(CcTest::isolate(), 5)); 951 for (int k = 0; k < 3; k++) { 952 context.Check("g()", EXPECT_RESULT, Number::New(CcTest::isolate(), 5)); 953 } 954 for (int k = 0; k < 3; k++) { 955 context.Check("f()", EXPECT_RESULT, Number::New(CcTest::isolate(), 5)); 956 } 957 context.Check("%OptimizeFunctionOnNextCall(g); g()", EXPECT_RESULT, 958 Number::New(CcTest::isolate(), 5)); 959 context.Check("%OptimizeFunctionOnNextCall(f); f()", EXPECT_RESULT, 960 Number::New(CcTest::isolate(), 5)); 961 } 962 { 963 SimpleContext context; 964 context.Check( 965 "x = 15;" 966 "function f() { return x; }" 967 "f()", 968 EXPECT_RESULT, Number::New(CcTest::isolate(), 15)); 969 for (int k = 0; k < 3; k++) { 970 context.Check("f()", EXPECT_RESULT, Number::New(CcTest::isolate(), 15)); 971 } 972 context.Check("%OptimizeFunctionOnNextCall(f); f()", EXPECT_RESULT, 973 Number::New(CcTest::isolate(), 15)); 974 context.Check( 975 "'use strict';" 976 "let x = 5;" 977 "f()", 978 EXPECT_RESULT, Number::New(CcTest::isolate(), 5)); 979 for (int k = 0; k < 3; k++) { 980 context.Check("f()", EXPECT_RESULT, Number::New(CcTest::isolate(), 5)); 981 } 982 context.Check("%OptimizeFunctionOnNextCall(f); f()", EXPECT_RESULT, 983 Number::New(CcTest::isolate(), 5)); 984 } 985 } 986 987 988 TEST(CrossScriptStoreICs) { 989 i::FLAG_allow_natives_syntax = true; 990 991 HandleScope handle_scope(CcTest::isolate()); 992 993 { 994 SimpleContext context; 995 context.Check( 996 "var global = this;" 997 "x = 15;" 998 "function f(v) { x = v; }" 999 "function g(v) { x = v; }" 1000 "f(10); x", 1001 EXPECT_RESULT, Number::New(CcTest::isolate(), 10)); 1002 context.Check( 1003 "'use strict';" 1004 "let x = 5;" 1005 "f(7); x", 1006 EXPECT_RESULT, Number::New(CcTest::isolate(), 7)); 1007 context.Check("global.x", EXPECT_RESULT, 1008 Number::New(CcTest::isolate(), 10)); 1009 for (int k = 0; k < 3; k++) { 1010 context.Check("g(31); x", EXPECT_RESULT, 1011 Number::New(CcTest::isolate(), 31)); 1012 } 1013 context.Check("global.x", EXPECT_RESULT, 1014 Number::New(CcTest::isolate(), 10)); 1015 for (int k = 0; k < 3; k++) { 1016 context.Check("f(32); x", EXPECT_RESULT, 1017 Number::New(CcTest::isolate(), 32)); 1018 } 1019 context.Check("global.x", EXPECT_RESULT, 1020 Number::New(CcTest::isolate(), 10)); 1021 context.Check("%OptimizeFunctionOnNextCall(g); g(18); x", EXPECT_RESULT, 1022 Number::New(CcTest::isolate(), 18)); 1023 context.Check("global.x", EXPECT_RESULT, 1024 Number::New(CcTest::isolate(), 10)); 1025 context.Check("%OptimizeFunctionOnNextCall(f); f(33); x", EXPECT_RESULT, 1026 Number::New(CcTest::isolate(), 33)); 1027 context.Check("global.x", EXPECT_RESULT, 1028 Number::New(CcTest::isolate(), 10)); 1029 } 1030 { 1031 SimpleContext context; 1032 context.Check( 1033 "var global = this;" 1034 "x = 15;" 1035 "function f(v) { x = v; }" 1036 "f(10); x", 1037 EXPECT_RESULT, Number::New(CcTest::isolate(), 10)); 1038 for (int k = 0; k < 3; k++) { 1039 context.Check("f(18); x", EXPECT_RESULT, 1040 Number::New(CcTest::isolate(), 18)); 1041 } 1042 context.Check("%OptimizeFunctionOnNextCall(f); f(20); x", EXPECT_RESULT, 1043 Number::New(CcTest::isolate(), 20)); 1044 context.Check( 1045 "'use strict';" 1046 "let x = 5;" 1047 "f(8); x", 1048 EXPECT_RESULT, Number::New(CcTest::isolate(), 8)); 1049 context.Check("global.x", EXPECT_RESULT, 1050 Number::New(CcTest::isolate(), 20)); 1051 for (int k = 0; k < 3; k++) { 1052 context.Check("f(13); x", EXPECT_RESULT, 1053 Number::New(CcTest::isolate(), 13)); 1054 } 1055 context.Check("global.x", EXPECT_RESULT, 1056 Number::New(CcTest::isolate(), 20)); 1057 context.Check("%OptimizeFunctionOnNextCall(f); f(41); x", EXPECT_RESULT, 1058 Number::New(CcTest::isolate(), 41)); 1059 context.Check("global.x", EXPECT_RESULT, 1060 Number::New(CcTest::isolate(), 20)); 1061 } 1062 } 1063 1064 1065 TEST(CrossScriptAssignmentToConst) { 1066 i::FLAG_allow_natives_syntax = true; 1067 1068 HandleScope handle_scope(CcTest::isolate()); 1069 1070 { 1071 SimpleContext context; 1072 1073 context.Check("function f() { x = 27; }", EXPECT_RESULT, 1074 Undefined(CcTest::isolate())); 1075 context.Check("'use strict';const x = 1; x", EXPECT_RESULT, 1076 Number::New(CcTest::isolate(), 1)); 1077 context.Check("f();", EXPECT_EXCEPTION); 1078 context.Check("x", EXPECT_RESULT, Number::New(CcTest::isolate(), 1)); 1079 context.Check("f();", EXPECT_EXCEPTION); 1080 context.Check("x", EXPECT_RESULT, Number::New(CcTest::isolate(), 1)); 1081 context.Check("%OptimizeFunctionOnNextCall(f);f();", EXPECT_EXCEPTION); 1082 context.Check("x", EXPECT_RESULT, Number::New(CcTest::isolate(), 1)); 1083 } 1084 } 1085 1086 1087 TEST(Regress425510) { 1088 i::FLAG_allow_natives_syntax = true; 1089 1090 HandleScope handle_scope(CcTest::isolate()); 1091 1092 { 1093 SimpleContext context; 1094 1095 context.Check("'use strict'; o; const o = 10", EXPECT_EXCEPTION); 1096 1097 for (int i = 0; i < 100; i++) { 1098 context.Check("o.prototype", EXPECT_EXCEPTION); 1099 } 1100 } 1101 } 1102 1103 1104 TEST(Regress3941) { 1105 i::FLAG_allow_natives_syntax = true; 1106 1107 HandleScope handle_scope(CcTest::isolate()); 1108 1109 { 1110 SimpleContext context; 1111 context.Check("function f() { x = 1; }", EXPECT_RESULT, 1112 Undefined(CcTest::isolate())); 1113 context.Check("'use strict'; f(); let x = 2; x", EXPECT_EXCEPTION); 1114 } 1115 1116 1117 { 1118 // Train ICs. 1119 SimpleContext context; 1120 context.Check("function f() { x = 1; }", EXPECT_RESULT, 1121 Undefined(CcTest::isolate())); 1122 for (int i = 0; i < 4; i++) { 1123 context.Check("f(); x", EXPECT_RESULT, Number::New(CcTest::isolate(), 1)); 1124 } 1125 context.Check("'use strict'; f(); let x = 2; x", EXPECT_EXCEPTION); 1126 } 1127 1128 1129 { 1130 // Optimize. 1131 SimpleContext context; 1132 context.Check("function f() { x = 1; }", EXPECT_RESULT, 1133 Undefined(CcTest::isolate())); 1134 for (int i = 0; i < 4; i++) { 1135 context.Check("f(); x", EXPECT_RESULT, Number::New(CcTest::isolate(), 1)); 1136 } 1137 context.Check("%OptimizeFunctionOnNextCall(f); f(); x", EXPECT_RESULT, 1138 Number::New(CcTest::isolate(), 1)); 1139 1140 context.Check("'use strict'; f(); let x = 2; x", EXPECT_EXCEPTION); 1141 } 1142 } 1143 1144 1145 TEST(Regress3941_Reads) { 1146 i::FLAG_allow_natives_syntax = true; 1147 1148 HandleScope handle_scope(CcTest::isolate()); 1149 1150 { 1151 SimpleContext context; 1152 context.Check("function f() { return x; }", EXPECT_RESULT, 1153 Undefined(CcTest::isolate())); 1154 context.Check("'use strict'; f(); let x = 2; x", EXPECT_EXCEPTION); 1155 } 1156 1157 1158 { 1159 // Train ICs. 1160 SimpleContext context; 1161 context.Check("function f() { return x; }", EXPECT_RESULT, 1162 Undefined(CcTest::isolate())); 1163 for (int i = 0; i < 4; i++) { 1164 context.Check("f()", EXPECT_EXCEPTION); 1165 } 1166 context.Check("'use strict'; f(); let x = 2; x", EXPECT_EXCEPTION); 1167 } 1168 1169 1170 { 1171 // Optimize. 1172 SimpleContext context; 1173 context.Check("function f() { return x; }", EXPECT_RESULT, 1174 Undefined(CcTest::isolate())); 1175 for (int i = 0; i < 4; i++) { 1176 context.Check("f()", EXPECT_EXCEPTION); 1177 } 1178 context.Check("%OptimizeFunctionOnNextCall(f);", EXPECT_RESULT, 1179 Undefined(CcTest::isolate())); 1180 1181 context.Check("'use strict'; f(); let x = 2; x", EXPECT_EXCEPTION); 1182 } 1183 } 1184