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