• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
~DeclarationContext()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 
get_count() const67   int get_count() const { return get_count_; }
set_count() const68   int set_count() const { return set_count_; }
query_count() const69   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.
PostInitializeContext(Local<Context> context)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.
GetHolder(Local<FunctionTemplate> function)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 
isolate() const97   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 
DeclarationContext()111 DeclarationContext::DeclarationContext()
112     : is_initialized_(false), get_count_(0), set_count_(0), query_count_(0) {
113   // Do nothing.
114 }
115 
116 
InitializeIfNeeded()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 
Check(const char * source,int get,int set,int query,Expectations expectations,v8::Local<Value> value)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 
HandleGet(Local<Name> key,const v8::PropertyCallbackInfo<v8::Value> & info)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 
HandleSet(Local<Name> key,Local<Value> value,const v8::PropertyCallbackInfo<v8::Value> & info)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 
HandleQuery(Local<Name> key,const v8::PropertyCallbackInfo<v8::Integer> & info)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 
GetInstance(Local<Value> data)206 DeclarationContext* DeclarationContext::GetInstance(Local<Value> data) {
207   void* value = Local<External>::Cast(data)->Value();
208   return static_cast<DeclarationContext*>(value);
209 }
210 
211 
Get(Local<Name> key)212 v8::Local<Value> DeclarationContext::Get(Local<Name> key) {
213   return v8::Local<Value>();
214 }
215 
216 
Set(Local<Name> key,Local<Value> value)217 v8::Local<Value> DeclarationContext::Set(Local<Name> key, Local<Value> value) {
218   return v8::Local<Value>();
219 }
220 
221 
Query(Local<Name> key)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.
TEST(Unknown)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:
Query(Local<Name> key)273   virtual v8::Local<Integer> Query(Local<Name> key) {
274     return v8::Local<Integer>();
275   }
276 };
277 
278 
TEST(Absent)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 
AppearingPropertyContext()335   AppearingPropertyContext() : state_(DECLARE) { }
336 
337  protected:
Query(Local<Name> key)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 
TEST(Appearing)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:
ExistsInPrototypeContext()406   ExistsInPrototypeContext() { InitializeIfNeeded(); }
407  protected:
Query(Local<Name> key)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.
GetHolder(Local<FunctionTemplate> function)414   virtual Local<ObjectTemplate> GetHolder(Local<FunctionTemplate> function) {
415     return function->PrototypeTemplate();
416   }
417 };
418 
419 
TEST(ExistsInPrototype)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:
Query(Local<Name> key)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.
GetHolder(Local<FunctionTemplate> function)474   virtual Local<ObjectTemplate> GetHolder(Local<FunctionTemplate> function) {
475     return function->PrototypeTemplate();
476   }
477 };
478 
479 
TEST(AbsentInPrototype)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:
ExistsInHiddenPrototypeContext()497   ExistsInHiddenPrototypeContext() {
498     hidden_proto_ = FunctionTemplate::New(CcTest::isolate());
499     hidden_proto_->SetHiddenPrototype(true);
500   }
501 
502  protected:
Query(Local<Name> key)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.
PostInitializeContext(Local<Context> context)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.
GetHolder(Local<FunctionTemplate> function)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 
TEST(ExistsInHiddenPrototype)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:
SimpleContext()569   SimpleContext()
570       : handle_scope_(CcTest::isolate()),
571         context_(Context::New(CcTest::isolate())) {
572     context_->Enter();
573   }
574 
~SimpleContext()575   ~SimpleContext() {
576     context_->Exit();
577   }
578 
Check(const char * source,Expectations expectations,v8::Local<Value> value=Local<Value> ())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 
TEST(CrossScriptReferences)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 
TEST(CrossScriptReferences_Simple)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 
TEST(CrossScriptReferences_Simple2)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 
TEST(CrossScriptReferencesHarmony)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 
TEST(CrossScriptReferencesHarmonyRegress)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 
TEST(GlobalLexicalOSR)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 
TEST(CrossScriptConflicts)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 
TEST(CrossScriptDynamicLookup)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 
TEST(CrossScriptGlobal)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 
TEST(CrossScriptStaticLookupUndeclared)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 
TEST(CrossScriptLoadICs)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 
TEST(CrossScriptStoreICs)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 
TEST(CrossScriptAssignmentToConst)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 
TEST(Regress425510)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 
TEST(Regress3941)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 
TEST(Regress3941_Reads)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