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