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