blob: ae2ec712ab752206e66dba243423c9fbfd555373 [file] [log] [blame]
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001// Copyright 2007-2008 the V8 project authors. All rights reserved.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002// 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 "v8.h"
31
32#include "heap.h"
33#include "cctest.h"
34
35using namespace v8;
36
37
38enum Expectations {
39 EXPECT_RESULT,
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000040 EXPECT_EXCEPTION,
41 EXPECT_ERROR
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000042};
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.
49class DeclarationContext {
50 public:
51 DeclarationContext();
52
53 virtual ~DeclarationContext() {
54 if (is_initialized_) {
55 context_->Exit();
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +000056 context_.Dispose(context_->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000057 }
58 }
59
60 void Check(const char* source,
61 int get, int set, int has,
62 Expectations expectations,
63 v8::Handle<Value> value = Local<Value>());
64
65 int get_count() const { return get_count_; }
66 int set_count() const { return set_count_; }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000067 int query_count() const { return query_count_; }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000068
69 protected:
70 virtual v8::Handle<Value> Get(Local<String> key);
71 virtual v8::Handle<Value> Set(Local<String> key, Local<Value> value);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000072 virtual v8::Handle<Integer> Query(Local<String> key);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000073
74 void InitializeIfNeeded();
75
yangguo@chromium.orgde0db002012-06-22 13:44:28 +000076 // Perform optional initialization steps on the context after it has
77 // been created. Defaults to none but may be overwritten.
78 virtual void PostInitializeContext(Handle<Context> context) {}
79
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000080 // Get the holder for the interceptor. Default to the instance template
81 // but may be overwritten.
82 virtual Local<ObjectTemplate> GetHolder(Local<FunctionTemplate> function) {
83 return function->InstanceTemplate();
84 }
85
86 // The handlers are called as static functions that forward
87 // to the instance specific virtual methods.
88 static v8::Handle<Value> HandleGet(Local<String> key,
89 const AccessorInfo& info);
90 static v8::Handle<Value> HandleSet(Local<String> key,
91 Local<Value> value,
92 const AccessorInfo& info);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000093 static v8::Handle<Integer> HandleQuery(Local<String> key,
94 const AccessorInfo& info);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000095
96 private:
97 bool is_initialized_;
98 Persistent<Context> context_;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000099
100 int get_count_;
101 int set_count_;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000102 int query_count_;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000103
104 static DeclarationContext* GetInstance(const AccessorInfo& info);
105};
106
107
108DeclarationContext::DeclarationContext()
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000109 : is_initialized_(false), get_count_(0), set_count_(0), query_count_(0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000110 // Do nothing.
111}
112
113
114void DeclarationContext::InitializeIfNeeded() {
115 if (is_initialized_) return;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000116 HandleScope scope(Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000117 Local<FunctionTemplate> function = FunctionTemplate::New();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000118 Local<Value> data = External::New(this);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000119 GetHolder(function)->SetNamedPropertyHandler(&HandleGet,
120 &HandleSet,
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000121 &HandleQuery,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000122 0, 0,
123 data);
124 context_ = Context::New(0, function->InstanceTemplate(), Local<Value>());
125 context_->Enter();
126 is_initialized_ = true;
yangguo@chromium.orgde0db002012-06-22 13:44:28 +0000127 PostInitializeContext(context_);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000128}
129
130
131void DeclarationContext::Check(const char* source,
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000132 int get, int set, int query,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000133 Expectations expectations,
134 v8::Handle<Value> value) {
135 InitializeIfNeeded();
136 // A retry after a GC may pollute the counts, so perform gc now
137 // to avoid that.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000138 HEAP->CollectGarbage(v8::internal::NEW_SPACE);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000139 HandleScope scope(Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000140 TryCatch catcher;
141 catcher.SetVerbose(true);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000142 Local<Script> script = Script::Compile(String::New(source));
143 if (expectations == EXPECT_ERROR) {
144 CHECK(script.IsEmpty());
145 return;
146 }
147 CHECK(!script.IsEmpty());
148 Local<Value> result = script->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000149 CHECK_EQ(get, get_count());
150 CHECK_EQ(set, set_count());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000151 CHECK_EQ(query, query_count());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000152 if (expectations == EXPECT_RESULT) {
153 CHECK(!catcher.HasCaught());
154 if (!value.IsEmpty()) {
155 CHECK_EQ(value, result);
156 }
157 } else {
158 CHECK(expectations == EXPECT_EXCEPTION);
159 CHECK(catcher.HasCaught());
160 if (!value.IsEmpty()) {
161 CHECK_EQ(value, catcher.Exception());
162 }
163 }
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000164 HEAP->CollectAllAvailableGarbage(); // Clean slate for the next test.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000165}
166
167
168v8::Handle<Value> DeclarationContext::HandleGet(Local<String> key,
169 const AccessorInfo& info) {
170 DeclarationContext* context = GetInstance(info);
171 context->get_count_++;
172 return context->Get(key);
173}
174
175
176v8::Handle<Value> DeclarationContext::HandleSet(Local<String> key,
177 Local<Value> value,
178 const AccessorInfo& info) {
179 DeclarationContext* context = GetInstance(info);
180 context->set_count_++;
181 return context->Set(key, value);
182}
183
184
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000185v8::Handle<Integer> DeclarationContext::HandleQuery(Local<String> key,
186 const AccessorInfo& info) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000187 DeclarationContext* context = GetInstance(info);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000188 context->query_count_++;
189 return context->Query(key);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000190}
191
192
193DeclarationContext* DeclarationContext::GetInstance(const AccessorInfo& info) {
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +0000194 void* value = External::Cast(*info.Data())->Value();
195 return static_cast<DeclarationContext*>(value);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000196}
197
198
199v8::Handle<Value> DeclarationContext::Get(Local<String> key) {
200 return v8::Handle<Value>();
201}
202
203
204v8::Handle<Value> DeclarationContext::Set(Local<String> key,
205 Local<Value> value) {
206 return v8::Handle<Value>();
207}
208
209
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000210v8::Handle<Integer> DeclarationContext::Query(Local<String> key) {
211 return v8::Handle<Integer>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000212}
213
214
215// Test global declaration of a property the interceptor doesn't know
216// about and doesn't handle.
217TEST(Unknown) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000218 HandleScope scope(Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000219
220 { DeclarationContext context;
221 context.Check("var x; x",
222 1, // access
223 1, // declaration
224 2, // declaration + initialization
225 EXPECT_RESULT, Undefined());
226 }
227
228 { DeclarationContext context;
229 context.Check("var x = 0; x",
230 1, // access
231 2, // declaration + initialization
232 2, // declaration + initialization
233 EXPECT_RESULT, Number::New(0));
234 }
235
236 { DeclarationContext context;
237 context.Check("function x() { }; x",
238 1, // access
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000239 0,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000240 0,
241 EXPECT_RESULT);
242 }
243
244 { DeclarationContext context;
245 context.Check("const x; x",
246 1, // access
247 2, // declaration + initialization
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000248 1, // declaration
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000249 EXPECT_RESULT, Undefined());
250 }
251
252 { DeclarationContext context;
253 context.Check("const x = 0; x",
254 1, // access
255 2, // declaration + initialization
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000256 1, // declaration
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000257 EXPECT_RESULT, Undefined()); // SB 0 - BUG 1213579
258 }
259}
260
261
262
263class PresentPropertyContext: public DeclarationContext {
264 protected:
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000265 virtual v8::Handle<Integer> Query(Local<String> key) {
266 return Integer::New(v8::None);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000267 }
268};
269
270
271
272TEST(Present) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000273 HandleScope scope(Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000274
275 { PresentPropertyContext context;
276 context.Check("var x; x",
277 1, // access
278 0,
279 2, // declaration + initialization
280 EXPECT_EXCEPTION); // x is not defined!
281 }
282
283 { PresentPropertyContext context;
284 context.Check("var x = 0; x",
285 1, // access
286 1, // initialization
287 2, // declaration + initialization
288 EXPECT_RESULT, Number::New(0));
289 }
290
291 { PresentPropertyContext context;
292 context.Check("function x() { }; x",
293 1, // access
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000294 0,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000295 0,
296 EXPECT_RESULT);
297 }
298
299 { PresentPropertyContext context;
300 context.Check("const x; x",
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000301 1, // access
302 1, // initialization
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000303 1, // (re-)declaration
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000304 EXPECT_RESULT, Undefined());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000305 }
306
307 { PresentPropertyContext context;
308 context.Check("const x = 0; x",
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000309 1, // access
310 1, // initialization
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000311 1, // (re-)declaration
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000312 EXPECT_RESULT, Number::New(0));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000313 }
314}
315
316
317
318class AbsentPropertyContext: public DeclarationContext {
319 protected:
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000320 virtual v8::Handle<Integer> Query(Local<String> key) {
321 return v8::Handle<Integer>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000322 }
323};
324
325
326TEST(Absent) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000327 HandleScope scope(Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000328
329 { AbsentPropertyContext context;
330 context.Check("var x; x",
331 1, // access
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000332 1, // declaration
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000333 2, // declaration + initialization
334 EXPECT_RESULT, Undefined());
335 }
336
337 { AbsentPropertyContext context;
338 context.Check("var x = 0; x",
339 1, // access
340 2, // declaration + initialization
341 2, // declaration + initialization
342 EXPECT_RESULT, Number::New(0));
343 }
344
345 { AbsentPropertyContext context;
346 context.Check("function x() { }; x",
347 1, // access
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000348 0,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000349 0,
350 EXPECT_RESULT);
351 }
352
353 { AbsentPropertyContext context;
354 context.Check("const x; x",
355 1, // access
356 2, // declaration + initialization
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000357 1, // declaration
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000358 EXPECT_RESULT, Undefined());
359 }
360
361 { AbsentPropertyContext context;
362 context.Check("const x = 0; x",
363 1, // access
364 2, // declaration + initialization
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000365 1, // declaration
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000366 EXPECT_RESULT, Undefined()); // SB 0 - BUG 1213579
367 }
368
369 { AbsentPropertyContext context;
370 context.Check("if (false) { var x = 0 }; x",
371 1, // access
372 1, // declaration
373 1, // declaration + initialization
374 EXPECT_RESULT, Undefined());
375 }
376}
377
378
379
380class AppearingPropertyContext: public DeclarationContext {
381 public:
382 enum State {
383 DECLARE,
384 INITIALIZE_IF_ASSIGN,
385 UNKNOWN
386 };
387
388 AppearingPropertyContext() : state_(DECLARE) { }
389
390 protected:
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000391 virtual v8::Handle<Integer> Query(Local<String> key) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000392 switch (state_) {
393 case DECLARE:
394 // Force declaration by returning that the
395 // property is absent.
396 state_ = INITIALIZE_IF_ASSIGN;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000397 return Handle<Integer>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000398 case INITIALIZE_IF_ASSIGN:
399 // Return that the property is present so we only get the
400 // setter called when initializing with a value.
401 state_ = UNKNOWN;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000402 return Integer::New(v8::None);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000403 default:
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000404 CHECK(state_ == UNKNOWN);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000405 break;
406 }
407 // Do the lookup in the object.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000408 return v8::Handle<Integer>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000409 }
410
411 private:
412 State state_;
413};
414
415
416TEST(Appearing) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000417 HandleScope scope(Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000418
419 { AppearingPropertyContext context;
420 context.Check("var x; x",
421 1, // access
422 1, // declaration
423 2, // declaration + initialization
424 EXPECT_RESULT, Undefined());
425 }
426
427 { AppearingPropertyContext context;
428 context.Check("var x = 0; x",
429 1, // access
430 2, // declaration + initialization
431 2, // declaration + initialization
432 EXPECT_RESULT, Number::New(0));
433 }
434
435 { AppearingPropertyContext context;
436 context.Check("function x() { }; x",
437 1, // access
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000438 0,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000439 0,
440 EXPECT_RESULT);
441 }
442
443 { AppearingPropertyContext context;
444 context.Check("const x; x",
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000445 1, // access
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000446 2, // declaration + initialization
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000447 1, // declaration
448 EXPECT_RESULT, Undefined());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000449 }
450
451 { AppearingPropertyContext context;
452 context.Check("const x = 0; x",
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000453 1, // access
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000454 2, // declaration + initialization
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000455 1, // declaration
456 EXPECT_RESULT, Undefined());
457 // Result is undefined because declaration succeeded but
458 // initialization to 0 failed (due to context behavior).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000459 }
460}
461
462
463
464class ReappearingPropertyContext: public DeclarationContext {
465 public:
466 enum State {
467 DECLARE,
468 DONT_DECLARE,
469 INITIALIZE,
470 UNKNOWN
471 };
472
473 ReappearingPropertyContext() : state_(DECLARE) { }
474
475 protected:
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000476 virtual v8::Handle<Integer> Query(Local<String> key) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000477 switch (state_) {
478 case DECLARE:
479 // Force the first declaration by returning that
480 // the property is absent.
481 state_ = DONT_DECLARE;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000482 return Handle<Integer>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000483 case DONT_DECLARE:
484 // Ignore the second declaration by returning
485 // that the property is already there.
486 state_ = INITIALIZE;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000487 return Integer::New(v8::None);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000488 case INITIALIZE:
489 // Force an initialization by returning that
490 // the property is absent. This will make sure
491 // that the setter is called and it will not
492 // lead to redeclaration conflicts (yet).
493 state_ = UNKNOWN;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000494 return Handle<Integer>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000495 default:
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000496 CHECK(state_ == UNKNOWN);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000497 break;
498 }
499 // Do the lookup in the object.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000500 return Handle<Integer>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000501 }
502
503 private:
504 State state_;
505};
506
507
508TEST(Reappearing) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000509 HandleScope scope(Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000510
511 { ReappearingPropertyContext context;
512 context.Check("const x; var x = 0",
513 0,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000514 3, // const declaration+initialization, var initialization
515 3, // 2 x declaration + var initialization
516 EXPECT_RESULT, Undefined());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000517 }
518}
519
520
521
522class ExistsInPrototypeContext: public DeclarationContext {
523 protected:
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000524 virtual v8::Handle<Integer> Query(Local<String> key) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000525 // Let it seem that the property exists in the prototype object.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000526 return Integer::New(v8::None);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000527 }
528
529 // Use the prototype as the holder for the interceptors.
530 virtual Local<ObjectTemplate> GetHolder(Local<FunctionTemplate> function) {
531 return function->PrototypeTemplate();
532 }
533};
534
535
536TEST(ExistsInPrototype) {
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +0000537 i::FLAG_es52_globals = true;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000538 HandleScope scope(Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000539
540 // Sanity check to make sure that the holder of the interceptor
541 // really is the prototype object.
542 { ExistsInPrototypeContext context;
543 context.Check("this.x = 87; this.x",
544 0,
545 0,
546 0,
547 EXPECT_RESULT, Number::New(87));
548 }
549
550 { ExistsInPrototypeContext context;
551 context.Check("var x; x",
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000552 0,
yangguo@chromium.orgde0db002012-06-22 13:44:28 +0000553 0,
554 0,
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000555 EXPECT_RESULT, Undefined());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000556 }
557
558 { ExistsInPrototypeContext context;
559 context.Check("var x = 0; x",
560 0,
561 0,
yangguo@chromium.orgde0db002012-06-22 13:44:28 +0000562 0,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000563 EXPECT_RESULT, Number::New(0));
564 }
565
566 { ExistsInPrototypeContext context;
567 context.Check("const x; x",
568 0,
569 0,
yangguo@chromium.orgde0db002012-06-22 13:44:28 +0000570 0,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000571 EXPECT_RESULT, Undefined());
572 }
573
574 { ExistsInPrototypeContext context;
575 context.Check("const x = 0; x",
576 0,
577 0,
yangguo@chromium.orgde0db002012-06-22 13:44:28 +0000578 0,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000579 EXPECT_RESULT, Number::New(0));
580 }
581}
582
583
584
585class AbsentInPrototypeContext: public DeclarationContext {
586 protected:
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000587 virtual v8::Handle<Integer> Query(Local<String> key) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000588 // Let it seem that the property is absent in the prototype object.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000589 return Handle<Integer>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000590 }
591
592 // Use the prototype as the holder for the interceptors.
593 virtual Local<ObjectTemplate> GetHolder(Local<FunctionTemplate> function) {
594 return function->PrototypeTemplate();
595 }
596};
597
598
599TEST(AbsentInPrototype) {
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +0000600 i::FLAG_es52_globals = true;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000601 HandleScope scope(Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000602
603 { AbsentInPrototypeContext context;
604 context.Check("if (false) { var x = 0; }; x",
605 0,
606 0,
yangguo@chromium.orgde0db002012-06-22 13:44:28 +0000607 0,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000608 EXPECT_RESULT, Undefined());
609 }
610}
yangguo@chromium.orgde0db002012-06-22 13:44:28 +0000611
612
613
614class ExistsInHiddenPrototypeContext: public DeclarationContext {
615 public:
616 ExistsInHiddenPrototypeContext() {
617 hidden_proto_ = FunctionTemplate::New();
618 hidden_proto_->SetHiddenPrototype(true);
619 }
620
621 protected:
622 virtual v8::Handle<Integer> Query(Local<String> key) {
623 // Let it seem that the property exists in the hidden prototype object.
624 return Integer::New(v8::None);
625 }
626
627 // Install the hidden prototype after the global object has been created.
628 virtual void PostInitializeContext(Handle<Context> context) {
629 Local<Object> global_object = context->Global();
630 Local<Object> hidden_proto = hidden_proto_->GetFunction()->NewInstance();
631 context->DetachGlobal();
632 context->Global()->SetPrototype(hidden_proto);
633 context->ReattachGlobal(global_object);
634 }
635
636 // Use the hidden prototype as the holder for the interceptors.
637 virtual Local<ObjectTemplate> GetHolder(Local<FunctionTemplate> function) {
638 return hidden_proto_->InstanceTemplate();
639 }
640
641 private:
642 Local<FunctionTemplate> hidden_proto_;
643};
644
645
646TEST(ExistsInHiddenPrototype) {
647 i::FLAG_es52_globals = true;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000648 HandleScope scope(Isolate::GetCurrent());
yangguo@chromium.orgde0db002012-06-22 13:44:28 +0000649
650 { ExistsInHiddenPrototypeContext context;
651 context.Check("var x; x",
652 1, // access
653 0,
654 2, // declaration + initialization
655 EXPECT_EXCEPTION); // x is not defined!
656 }
657
658 { ExistsInHiddenPrototypeContext context;
659 context.Check("var x = 0; x",
660 1, // access
661 1, // initialization
662 2, // declaration + initialization
663 EXPECT_RESULT, Number::New(0));
664 }
665
666 { ExistsInHiddenPrototypeContext context;
667 context.Check("function x() { }; x",
668 0,
669 0,
670 0,
671 EXPECT_RESULT);
672 }
673
674 // TODO(mstarzinger): The semantics of global const is vague.
675 { ExistsInHiddenPrototypeContext context;
676 context.Check("const x; x",
677 0,
678 0,
679 1, // (re-)declaration
680 EXPECT_RESULT, Undefined());
681 }
682
683 // TODO(mstarzinger): The semantics of global const is vague.
684 { ExistsInHiddenPrototypeContext context;
685 context.Check("const x = 0; x",
686 0,
687 0,
688 1, // (re-)declaration
689 EXPECT_RESULT, Number::New(0));
690 }
691}
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000692
693
694
695class SimpleContext {
696 public:
697 SimpleContext() {
698 context_ = Context::New(0);
699 context_->Enter();
700 }
701
702 virtual ~SimpleContext() {
703 context_->Exit();
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000704 context_.Dispose(context_->GetIsolate());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000705 }
706
707 void Check(const char* source,
708 Expectations expectations,
709 v8::Handle<Value> value = Local<Value>()) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000710 HandleScope scope(context_->GetIsolate());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000711 TryCatch catcher;
712 catcher.SetVerbose(true);
713 Local<Script> script = Script::Compile(String::New(source));
714 if (expectations == EXPECT_ERROR) {
715 CHECK(script.IsEmpty());
716 return;
717 }
718 CHECK(!script.IsEmpty());
719 Local<Value> result = script->Run();
720 if (expectations == EXPECT_RESULT) {
721 CHECK(!catcher.HasCaught());
722 if (!value.IsEmpty()) {
723 CHECK_EQ(value, result);
724 }
725 } else {
726 CHECK(expectations == EXPECT_EXCEPTION);
727 CHECK(catcher.HasCaught());
728 if (!value.IsEmpty()) {
729 CHECK_EQ(value, catcher.Exception());
730 }
731 }
732 }
733
734 private:
735 Persistent<Context> context_;
736};
737
738
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000739TEST(CrossScriptReferences) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000740 HandleScope scope(Isolate::GetCurrent());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000741
742 { SimpleContext context;
743 context.Check("var x = 1; x",
744 EXPECT_RESULT, Number::New(1));
745 context.Check("var x = 2; x",
746 EXPECT_RESULT, Number::New(2));
747 context.Check("const x = 3; x",
748 EXPECT_RESULT, Number::New(3));
749 context.Check("const x = 4; x",
750 EXPECT_RESULT, Number::New(4));
751 context.Check("x = 5; x",
752 EXPECT_RESULT, Number::New(5));
753 context.Check("var x = 6; x",
754 EXPECT_RESULT, Number::New(6));
755 context.Check("this.x",
756 EXPECT_RESULT, Number::New(6));
757 context.Check("function x() { return 7 }; x()",
758 EXPECT_RESULT, Number::New(7));
759 }
760
761 { SimpleContext context;
762 context.Check("const x = 1; x",
763 EXPECT_RESULT, Number::New(1));
764 context.Check("var x = 2; x", // assignment ignored
765 EXPECT_RESULT, Number::New(1));
766 context.Check("const x = 3; x",
767 EXPECT_RESULT, Number::New(1));
768 context.Check("x = 4; x", // assignment ignored
769 EXPECT_RESULT, Number::New(1));
770 context.Check("var x = 5; x", // assignment ignored
771 EXPECT_RESULT, Number::New(1));
772 context.Check("this.x",
773 EXPECT_RESULT, Number::New(1));
774 context.Check("function x() { return 7 }; x",
775 EXPECT_EXCEPTION);
776 }
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000777}
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000778
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000779
780TEST(CrossScriptReferencesHarmony) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000781 i::FLAG_use_strict = true;
782 i::FLAG_harmony_scoping = true;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000783 i::FLAG_harmony_modules = true;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000784
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000785 HandleScope scope(Isolate::GetCurrent());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000786
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000787 const char* decs[] = {
788 "var x = 1; x", "x", "this.x",
789 "function x() { return 1 }; x()", "x()", "this.x()",
790 "let x = 1; x", "x", "this.x",
791 "const x = 1; x", "x", "this.x",
792 "module x { export let a = 1 }; x.a", "x.a", "this.x.a",
793 NULL
794 };
yangguo@chromium.org355cfd12012-08-29 15:32:24 +0000795
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000796 for (int i = 0; decs[i] != NULL; i += 3) {
797 SimpleContext context;
798 context.Check(decs[i], EXPECT_RESULT, Number::New(1));
799 context.Check(decs[i+1], EXPECT_RESULT, Number::New(1));
yangguo@chromium.org355cfd12012-08-29 15:32:24 +0000800 // TODO(rossberg): The current ES6 draft spec does not reflect lexical
801 // bindings on the global object. However, this will probably change, in
802 // which case we reactivate the following test.
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000803 if (i/3 < 2) context.Check(decs[i+2], EXPECT_RESULT, Number::New(1));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000804 }
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000805}
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000806
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000807
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000808TEST(CrossScriptConflicts) {
809 i::FLAG_use_strict = true;
810 i::FLAG_harmony_scoping = true;
811 i::FLAG_harmony_modules = true;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000812
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000813 HandleScope scope(Isolate::GetCurrent());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000814
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000815 const char* firsts[] = {
816 "var x = 1; x",
817 "function x() { return 1 }; x()",
818 "let x = 1; x",
819 "const x = 1; x",
820 "module x { export let a = 1 }; x.a",
821 NULL
822 };
823 const char* seconds[] = {
824 "var x = 2; x",
825 "function x() { return 2 }; x()",
826 "let x = 2; x",
827 "const x = 2; x",
828 "module x { export let a = 2 }; x.a",
829 NULL
830 };
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000831
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000832 for (int i = 0; firsts[i] != NULL; ++i) {
833 for (int j = 0; seconds[j] != NULL; ++j) {
834 SimpleContext context;
835 context.Check(firsts[i], EXPECT_RESULT, Number::New(1));
836 // TODO(rossberg): All tests should actually be errors in Harmony,
837 // but we currently do not detect the cases where the first declaration
838 // is not lexical.
839 context.Check(seconds[j],
840 i < 2 ? EXPECT_RESULT : EXPECT_ERROR, Number::New(2));
841 }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000842 }
843}