Home | History | Annotate | Download | only in cctest
      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