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   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