blob: 6be5303cde4643fd85b75b362d40f7905652f063 [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
ulan@chromium.org57ff8812013-05-10 08:16:55 +000030// TODO(dcarney): remove
31#define V8_ALLOW_ACCESS_TO_PERSISTENT_ARROW
32#define V8_ALLOW_ACCESS_TO_RAW_HANDLE_CONSTRUCTOR
33#define V8_ALLOW_ACCESS_TO_PERSISTENT_IMPLICIT
34
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000035#include "v8.h"
36
37#include "heap.h"
38#include "cctest.h"
39
40using namespace v8;
41
42
43enum Expectations {
44 EXPECT_RESULT,
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000045 EXPECT_EXCEPTION,
46 EXPECT_ERROR
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000047};
48
49
50// A DeclarationContext holds a reference to a v8::Context and keeps
51// track of various declaration related counters to make it easier to
52// track if global declarations in the presence of interceptors behave
53// the right way.
54class DeclarationContext {
55 public:
56 DeclarationContext();
57
58 virtual ~DeclarationContext() {
59 if (is_initialized_) {
60 context_->Exit();
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +000061 context_.Dispose(context_->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000062 }
63 }
64
65 void Check(const char* source,
66 int get, int set, int has,
67 Expectations expectations,
68 v8::Handle<Value> value = Local<Value>());
69
70 int get_count() const { return get_count_; }
71 int set_count() const { return set_count_; }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000072 int query_count() const { return query_count_; }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000073
74 protected:
75 virtual v8::Handle<Value> Get(Local<String> key);
76 virtual v8::Handle<Value> Set(Local<String> key, Local<Value> value);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000077 virtual v8::Handle<Integer> Query(Local<String> key);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000078
79 void InitializeIfNeeded();
80
yangguo@chromium.orgde0db002012-06-22 13:44:28 +000081 // Perform optional initialization steps on the context after it has
82 // been created. Defaults to none but may be overwritten.
83 virtual void PostInitializeContext(Handle<Context> context) {}
84
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000085 // Get the holder for the interceptor. Default to the instance template
86 // but may be overwritten.
87 virtual Local<ObjectTemplate> GetHolder(Local<FunctionTemplate> function) {
88 return function->InstanceTemplate();
89 }
90
91 // The handlers are called as static functions that forward
92 // to the instance specific virtual methods.
93 static v8::Handle<Value> HandleGet(Local<String> key,
94 const AccessorInfo& info);
95 static v8::Handle<Value> HandleSet(Local<String> key,
96 Local<Value> value,
97 const AccessorInfo& info);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000098 static v8::Handle<Integer> HandleQuery(Local<String> key,
99 const AccessorInfo& info);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000100
101 private:
102 bool is_initialized_;
103 Persistent<Context> context_;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000104
105 int get_count_;
106 int set_count_;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000107 int query_count_;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000108
109 static DeclarationContext* GetInstance(const AccessorInfo& info);
110};
111
112
113DeclarationContext::DeclarationContext()
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000114 : is_initialized_(false), get_count_(0), set_count_(0), query_count_(0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000115 // Do nothing.
116}
117
118
119void DeclarationContext::InitializeIfNeeded() {
120 if (is_initialized_) return;
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000121 Isolate* isolate = Isolate::GetCurrent();
122 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000123 Local<FunctionTemplate> function = FunctionTemplate::New();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000124 Local<Value> data = External::New(this);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000125 GetHolder(function)->SetNamedPropertyHandler(&HandleGet,
126 &HandleSet,
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000127 &HandleQuery,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000128 0, 0,
129 data);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000130 context_.Reset(isolate,
131 Context::New(isolate,
132 0,
133 function->InstanceTemplate(),
134 Local<Value>()));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000135 context_->Enter();
136 is_initialized_ = true;
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000137 PostInitializeContext(Local<Context>::New(isolate, context_));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000138}
139
140
141void DeclarationContext::Check(const char* source,
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000142 int get, int set, int query,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000143 Expectations expectations,
144 v8::Handle<Value> value) {
145 InitializeIfNeeded();
146 // A retry after a GC may pollute the counts, so perform gc now
147 // to avoid that.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000148 HEAP->CollectGarbage(v8::internal::NEW_SPACE);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000149 HandleScope scope(Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000150 TryCatch catcher;
151 catcher.SetVerbose(true);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000152 Local<Script> script = Script::Compile(String::New(source));
153 if (expectations == EXPECT_ERROR) {
154 CHECK(script.IsEmpty());
155 return;
156 }
157 CHECK(!script.IsEmpty());
158 Local<Value> result = script->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000159 CHECK_EQ(get, get_count());
160 CHECK_EQ(set, set_count());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000161 CHECK_EQ(query, query_count());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000162 if (expectations == EXPECT_RESULT) {
163 CHECK(!catcher.HasCaught());
164 if (!value.IsEmpty()) {
165 CHECK_EQ(value, result);
166 }
167 } else {
168 CHECK(expectations == EXPECT_EXCEPTION);
169 CHECK(catcher.HasCaught());
170 if (!value.IsEmpty()) {
171 CHECK_EQ(value, catcher.Exception());
172 }
173 }
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000174 HEAP->CollectAllAvailableGarbage(); // Clean slate for the next test.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000175}
176
177
178v8::Handle<Value> DeclarationContext::HandleGet(Local<String> key,
179 const AccessorInfo& info) {
180 DeclarationContext* context = GetInstance(info);
181 context->get_count_++;
182 return context->Get(key);
183}
184
185
186v8::Handle<Value> DeclarationContext::HandleSet(Local<String> key,
187 Local<Value> value,
188 const AccessorInfo& info) {
189 DeclarationContext* context = GetInstance(info);
190 context->set_count_++;
191 return context->Set(key, value);
192}
193
194
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000195v8::Handle<Integer> DeclarationContext::HandleQuery(Local<String> key,
196 const AccessorInfo& info) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000197 DeclarationContext* context = GetInstance(info);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000198 context->query_count_++;
199 return context->Query(key);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000200}
201
202
203DeclarationContext* DeclarationContext::GetInstance(const AccessorInfo& info) {
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +0000204 void* value = External::Cast(*info.Data())->Value();
205 return static_cast<DeclarationContext*>(value);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000206}
207
208
209v8::Handle<Value> DeclarationContext::Get(Local<String> key) {
210 return v8::Handle<Value>();
211}
212
213
214v8::Handle<Value> DeclarationContext::Set(Local<String> key,
215 Local<Value> value) {
216 return v8::Handle<Value>();
217}
218
219
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000220v8::Handle<Integer> DeclarationContext::Query(Local<String> key) {
221 return v8::Handle<Integer>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000222}
223
224
225// Test global declaration of a property the interceptor doesn't know
226// about and doesn't handle.
227TEST(Unknown) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000228 HandleScope scope(Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000229
230 { DeclarationContext context;
231 context.Check("var x; x",
232 1, // access
233 1, // declaration
234 2, // declaration + initialization
235 EXPECT_RESULT, Undefined());
236 }
237
238 { DeclarationContext context;
239 context.Check("var x = 0; x",
240 1, // access
241 2, // declaration + initialization
242 2, // declaration + initialization
243 EXPECT_RESULT, Number::New(0));
244 }
245
246 { DeclarationContext context;
247 context.Check("function x() { }; x",
248 1, // access
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000249 0,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000250 0,
251 EXPECT_RESULT);
252 }
253
254 { DeclarationContext context;
255 context.Check("const x; x",
256 1, // access
257 2, // declaration + initialization
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000258 1, // declaration
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000259 EXPECT_RESULT, Undefined());
260 }
261
262 { DeclarationContext context;
263 context.Check("const x = 0; x",
264 1, // access
265 2, // declaration + initialization
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000266 1, // declaration
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000267 EXPECT_RESULT, Undefined()); // SB 0 - BUG 1213579
268 }
269}
270
271
272
273class PresentPropertyContext: public DeclarationContext {
274 protected:
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000275 virtual v8::Handle<Integer> Query(Local<String> key) {
276 return Integer::New(v8::None);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000277 }
278};
279
280
281
282TEST(Present) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000283 HandleScope scope(Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000284
285 { PresentPropertyContext context;
286 context.Check("var x; x",
287 1, // access
288 0,
289 2, // declaration + initialization
290 EXPECT_EXCEPTION); // x is not defined!
291 }
292
293 { PresentPropertyContext context;
294 context.Check("var x = 0; x",
295 1, // access
296 1, // initialization
297 2, // declaration + initialization
298 EXPECT_RESULT, Number::New(0));
299 }
300
301 { PresentPropertyContext context;
302 context.Check("function x() { }; x",
303 1, // access
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000304 0,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000305 0,
306 EXPECT_RESULT);
307 }
308
309 { PresentPropertyContext context;
310 context.Check("const x; x",
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000311 1, // access
312 1, // initialization
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000313 1, // (re-)declaration
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000314 EXPECT_RESULT, Undefined());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000315 }
316
317 { PresentPropertyContext context;
318 context.Check("const x = 0; x",
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000319 1, // access
320 1, // initialization
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000321 1, // (re-)declaration
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000322 EXPECT_RESULT, Number::New(0));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000323 }
324}
325
326
327
328class AbsentPropertyContext: public DeclarationContext {
329 protected:
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000330 virtual v8::Handle<Integer> Query(Local<String> key) {
331 return v8::Handle<Integer>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000332 }
333};
334
335
336TEST(Absent) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000337 HandleScope scope(Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000338
339 { AbsentPropertyContext context;
340 context.Check("var x; x",
341 1, // access
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000342 1, // declaration
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000343 2, // declaration + initialization
344 EXPECT_RESULT, Undefined());
345 }
346
347 { AbsentPropertyContext context;
348 context.Check("var x = 0; x",
349 1, // access
350 2, // declaration + initialization
351 2, // declaration + initialization
352 EXPECT_RESULT, Number::New(0));
353 }
354
355 { AbsentPropertyContext context;
356 context.Check("function x() { }; x",
357 1, // access
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000358 0,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000359 0,
360 EXPECT_RESULT);
361 }
362
363 { AbsentPropertyContext context;
364 context.Check("const x; x",
365 1, // access
366 2, // declaration + initialization
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000367 1, // declaration
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000368 EXPECT_RESULT, Undefined());
369 }
370
371 { AbsentPropertyContext context;
372 context.Check("const x = 0; x",
373 1, // access
374 2, // declaration + initialization
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000375 1, // declaration
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000376 EXPECT_RESULT, Undefined()); // SB 0 - BUG 1213579
377 }
378
379 { AbsentPropertyContext context;
380 context.Check("if (false) { var x = 0 }; x",
381 1, // access
382 1, // declaration
383 1, // declaration + initialization
384 EXPECT_RESULT, Undefined());
385 }
386}
387
388
389
390class AppearingPropertyContext: public DeclarationContext {
391 public:
392 enum State {
393 DECLARE,
394 INITIALIZE_IF_ASSIGN,
395 UNKNOWN
396 };
397
398 AppearingPropertyContext() : state_(DECLARE) { }
399
400 protected:
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000401 virtual v8::Handle<Integer> Query(Local<String> key) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000402 switch (state_) {
403 case DECLARE:
404 // Force declaration by returning that the
405 // property is absent.
406 state_ = INITIALIZE_IF_ASSIGN;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000407 return Handle<Integer>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000408 case INITIALIZE_IF_ASSIGN:
409 // Return that the property is present so we only get the
410 // setter called when initializing with a value.
411 state_ = UNKNOWN;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000412 return Integer::New(v8::None);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000413 default:
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000414 CHECK(state_ == UNKNOWN);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000415 break;
416 }
417 // Do the lookup in the object.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000418 return v8::Handle<Integer>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000419 }
420
421 private:
422 State state_;
423};
424
425
426TEST(Appearing) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000427 HandleScope scope(Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000428
429 { AppearingPropertyContext context;
430 context.Check("var x; x",
431 1, // access
432 1, // declaration
433 2, // declaration + initialization
434 EXPECT_RESULT, Undefined());
435 }
436
437 { AppearingPropertyContext context;
438 context.Check("var x = 0; x",
439 1, // access
440 2, // declaration + initialization
441 2, // declaration + initialization
442 EXPECT_RESULT, Number::New(0));
443 }
444
445 { AppearingPropertyContext context;
446 context.Check("function x() { }; x",
447 1, // access
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000448 0,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000449 0,
450 EXPECT_RESULT);
451 }
452
453 { AppearingPropertyContext context;
454 context.Check("const x; x",
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000455 1, // access
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000456 2, // declaration + initialization
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000457 1, // declaration
458 EXPECT_RESULT, Undefined());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000459 }
460
461 { AppearingPropertyContext context;
462 context.Check("const x = 0; x",
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000463 1, // access
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000464 2, // declaration + initialization
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000465 1, // declaration
466 EXPECT_RESULT, Undefined());
467 // Result is undefined because declaration succeeded but
468 // initialization to 0 failed (due to context behavior).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000469 }
470}
471
472
473
474class ReappearingPropertyContext: public DeclarationContext {
475 public:
476 enum State {
477 DECLARE,
478 DONT_DECLARE,
479 INITIALIZE,
480 UNKNOWN
481 };
482
483 ReappearingPropertyContext() : state_(DECLARE) { }
484
485 protected:
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000486 virtual v8::Handle<Integer> Query(Local<String> key) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000487 switch (state_) {
488 case DECLARE:
489 // Force the first declaration by returning that
490 // the property is absent.
491 state_ = DONT_DECLARE;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000492 return Handle<Integer>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000493 case DONT_DECLARE:
494 // Ignore the second declaration by returning
495 // that the property is already there.
496 state_ = INITIALIZE;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000497 return Integer::New(v8::None);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000498 case INITIALIZE:
499 // Force an initialization by returning that
500 // the property is absent. This will make sure
501 // that the setter is called and it will not
502 // lead to redeclaration conflicts (yet).
503 state_ = UNKNOWN;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000504 return Handle<Integer>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000505 default:
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000506 CHECK(state_ == UNKNOWN);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000507 break;
508 }
509 // Do the lookup in the object.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000510 return Handle<Integer>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000511 }
512
513 private:
514 State state_;
515};
516
517
518TEST(Reappearing) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000519 HandleScope scope(Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000520
521 { ReappearingPropertyContext context;
522 context.Check("const x; var x = 0",
523 0,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000524 3, // const declaration+initialization, var initialization
525 3, // 2 x declaration + var initialization
526 EXPECT_RESULT, Undefined());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000527 }
528}
529
530
531
532class ExistsInPrototypeContext: public DeclarationContext {
533 protected:
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000534 virtual v8::Handle<Integer> Query(Local<String> key) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000535 // Let it seem that the property exists in the prototype object.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000536 return Integer::New(v8::None);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000537 }
538
539 // Use the prototype as the holder for the interceptors.
540 virtual Local<ObjectTemplate> GetHolder(Local<FunctionTemplate> function) {
541 return function->PrototypeTemplate();
542 }
543};
544
545
546TEST(ExistsInPrototype) {
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +0000547 i::FLAG_es52_globals = true;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000548 HandleScope scope(Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000549
550 // Sanity check to make sure that the holder of the interceptor
551 // really is the prototype object.
552 { ExistsInPrototypeContext context;
553 context.Check("this.x = 87; this.x",
554 0,
555 0,
556 0,
557 EXPECT_RESULT, Number::New(87));
558 }
559
560 { ExistsInPrototypeContext context;
561 context.Check("var x; x",
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000562 0,
yangguo@chromium.orgde0db002012-06-22 13:44:28 +0000563 0,
564 0,
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000565 EXPECT_RESULT, Undefined());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000566 }
567
568 { ExistsInPrototypeContext context;
569 context.Check("var x = 0; x",
570 0,
571 0,
yangguo@chromium.orgde0db002012-06-22 13:44:28 +0000572 0,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000573 EXPECT_RESULT, Number::New(0));
574 }
575
576 { ExistsInPrototypeContext context;
577 context.Check("const x; x",
578 0,
579 0,
yangguo@chromium.orgde0db002012-06-22 13:44:28 +0000580 0,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000581 EXPECT_RESULT, Undefined());
582 }
583
584 { ExistsInPrototypeContext context;
585 context.Check("const x = 0; x",
586 0,
587 0,
yangguo@chromium.orgde0db002012-06-22 13:44:28 +0000588 0,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000589 EXPECT_RESULT, Number::New(0));
590 }
591}
592
593
594
595class AbsentInPrototypeContext: public DeclarationContext {
596 protected:
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000597 virtual v8::Handle<Integer> Query(Local<String> key) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000598 // Let it seem that the property is absent in the prototype object.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000599 return Handle<Integer>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000600 }
601
602 // Use the prototype as the holder for the interceptors.
603 virtual Local<ObjectTemplate> GetHolder(Local<FunctionTemplate> function) {
604 return function->PrototypeTemplate();
605 }
606};
607
608
609TEST(AbsentInPrototype) {
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +0000610 i::FLAG_es52_globals = true;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000611 HandleScope scope(Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000612
613 { AbsentInPrototypeContext context;
614 context.Check("if (false) { var x = 0; }; x",
615 0,
616 0,
yangguo@chromium.orgde0db002012-06-22 13:44:28 +0000617 0,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000618 EXPECT_RESULT, Undefined());
619 }
620}
yangguo@chromium.orgde0db002012-06-22 13:44:28 +0000621
622
623
624class ExistsInHiddenPrototypeContext: public DeclarationContext {
625 public:
626 ExistsInHiddenPrototypeContext() {
627 hidden_proto_ = FunctionTemplate::New();
628 hidden_proto_->SetHiddenPrototype(true);
629 }
630
631 protected:
632 virtual v8::Handle<Integer> Query(Local<String> key) {
633 // Let it seem that the property exists in the hidden prototype object.
634 return Integer::New(v8::None);
635 }
636
637 // Install the hidden prototype after the global object has been created.
638 virtual void PostInitializeContext(Handle<Context> context) {
639 Local<Object> global_object = context->Global();
640 Local<Object> hidden_proto = hidden_proto_->GetFunction()->NewInstance();
641 context->DetachGlobal();
642 context->Global()->SetPrototype(hidden_proto);
643 context->ReattachGlobal(global_object);
644 }
645
646 // Use the hidden prototype as the holder for the interceptors.
647 virtual Local<ObjectTemplate> GetHolder(Local<FunctionTemplate> function) {
648 return hidden_proto_->InstanceTemplate();
649 }
650
651 private:
652 Local<FunctionTemplate> hidden_proto_;
653};
654
655
656TEST(ExistsInHiddenPrototype) {
657 i::FLAG_es52_globals = true;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000658 HandleScope scope(Isolate::GetCurrent());
yangguo@chromium.orgde0db002012-06-22 13:44:28 +0000659
660 { ExistsInHiddenPrototypeContext context;
661 context.Check("var x; x",
662 1, // access
663 0,
664 2, // declaration + initialization
665 EXPECT_EXCEPTION); // x is not defined!
666 }
667
668 { ExistsInHiddenPrototypeContext context;
669 context.Check("var x = 0; x",
670 1, // access
671 1, // initialization
672 2, // declaration + initialization
673 EXPECT_RESULT, Number::New(0));
674 }
675
676 { ExistsInHiddenPrototypeContext context;
677 context.Check("function x() { }; x",
678 0,
679 0,
680 0,
681 EXPECT_RESULT);
682 }
683
684 // TODO(mstarzinger): The semantics of global const is vague.
685 { ExistsInHiddenPrototypeContext context;
686 context.Check("const x; x",
687 0,
688 0,
689 1, // (re-)declaration
690 EXPECT_RESULT, Undefined());
691 }
692
693 // TODO(mstarzinger): The semantics of global const is vague.
694 { ExistsInHiddenPrototypeContext context;
695 context.Check("const x = 0; x",
696 0,
697 0,
698 1, // (re-)declaration
699 EXPECT_RESULT, Number::New(0));
700 }
701}
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000702
703
704
705class SimpleContext {
706 public:
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000707 SimpleContext()
708 : handle_scope_(Isolate::GetCurrent()),
709 context_(Context::New(Isolate::GetCurrent())) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000710 context_->Enter();
711 }
712
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000713 ~SimpleContext() {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000714 context_->Exit();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000715 }
716
717 void Check(const char* source,
718 Expectations expectations,
719 v8::Handle<Value> value = Local<Value>()) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000720 HandleScope scope(context_->GetIsolate());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000721 TryCatch catcher;
722 catcher.SetVerbose(true);
723 Local<Script> script = Script::Compile(String::New(source));
724 if (expectations == EXPECT_ERROR) {
725 CHECK(script.IsEmpty());
726 return;
727 }
728 CHECK(!script.IsEmpty());
729 Local<Value> result = script->Run();
730 if (expectations == EXPECT_RESULT) {
731 CHECK(!catcher.HasCaught());
732 if (!value.IsEmpty()) {
733 CHECK_EQ(value, result);
734 }
735 } else {
736 CHECK(expectations == EXPECT_EXCEPTION);
737 CHECK(catcher.HasCaught());
738 if (!value.IsEmpty()) {
739 CHECK_EQ(value, catcher.Exception());
740 }
741 }
742 }
743
744 private:
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000745 HandleScope handle_scope_;
746 Local<Context> context_;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000747};
748
749
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000750TEST(CrossScriptReferences) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000751 HandleScope scope(Isolate::GetCurrent());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000752
753 { SimpleContext context;
754 context.Check("var x = 1; x",
755 EXPECT_RESULT, Number::New(1));
756 context.Check("var x = 2; x",
757 EXPECT_RESULT, Number::New(2));
758 context.Check("const x = 3; x",
759 EXPECT_RESULT, Number::New(3));
760 context.Check("const x = 4; x",
761 EXPECT_RESULT, Number::New(4));
762 context.Check("x = 5; x",
763 EXPECT_RESULT, Number::New(5));
764 context.Check("var x = 6; x",
765 EXPECT_RESULT, Number::New(6));
766 context.Check("this.x",
767 EXPECT_RESULT, Number::New(6));
768 context.Check("function x() { return 7 }; x()",
769 EXPECT_RESULT, Number::New(7));
770 }
771
772 { SimpleContext context;
773 context.Check("const x = 1; x",
774 EXPECT_RESULT, Number::New(1));
775 context.Check("var x = 2; x", // assignment ignored
776 EXPECT_RESULT, Number::New(1));
777 context.Check("const x = 3; x",
778 EXPECT_RESULT, Number::New(1));
779 context.Check("x = 4; x", // assignment ignored
780 EXPECT_RESULT, Number::New(1));
781 context.Check("var x = 5; x", // assignment ignored
782 EXPECT_RESULT, Number::New(1));
783 context.Check("this.x",
784 EXPECT_RESULT, Number::New(1));
785 context.Check("function x() { return 7 }; x",
786 EXPECT_EXCEPTION);
787 }
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000788}
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000789
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000790
791TEST(CrossScriptReferencesHarmony) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000792 i::FLAG_use_strict = true;
793 i::FLAG_harmony_scoping = true;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000794 i::FLAG_harmony_modules = true;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000795
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000796 HandleScope scope(Isolate::GetCurrent());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000797
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000798 const char* decs[] = {
799 "var x = 1; x", "x", "this.x",
800 "function x() { return 1 }; x()", "x()", "this.x()",
801 "let x = 1; x", "x", "this.x",
802 "const x = 1; x", "x", "this.x",
803 "module x { export let a = 1 }; x.a", "x.a", "this.x.a",
804 NULL
805 };
yangguo@chromium.org355cfd12012-08-29 15:32:24 +0000806
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000807 for (int i = 0; decs[i] != NULL; i += 3) {
808 SimpleContext context;
809 context.Check(decs[i], EXPECT_RESULT, Number::New(1));
810 context.Check(decs[i+1], EXPECT_RESULT, Number::New(1));
yangguo@chromium.org355cfd12012-08-29 15:32:24 +0000811 // TODO(rossberg): The current ES6 draft spec does not reflect lexical
812 // bindings on the global object. However, this will probably change, in
813 // which case we reactivate the following test.
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000814 if (i/3 < 2) context.Check(decs[i+2], EXPECT_RESULT, Number::New(1));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000815 }
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000816}
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000817
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000818
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000819TEST(CrossScriptConflicts) {
820 i::FLAG_use_strict = true;
821 i::FLAG_harmony_scoping = true;
822 i::FLAG_harmony_modules = true;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000823
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000824 HandleScope scope(Isolate::GetCurrent());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000825
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000826 const char* firsts[] = {
827 "var x = 1; x",
828 "function x() { return 1 }; x()",
829 "let x = 1; x",
830 "const x = 1; x",
831 "module x { export let a = 1 }; x.a",
832 NULL
833 };
834 const char* seconds[] = {
835 "var x = 2; x",
836 "function x() { return 2 }; x()",
837 "let x = 2; x",
838 "const x = 2; x",
839 "module x { export let a = 2 }; x.a",
840 NULL
841 };
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000842
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000843 for (int i = 0; firsts[i] != NULL; ++i) {
844 for (int j = 0; seconds[j] != NULL; ++j) {
845 SimpleContext context;
846 context.Check(firsts[i], EXPECT_RESULT, Number::New(1));
847 // TODO(rossberg): All tests should actually be errors in Harmony,
848 // but we currently do not detect the cases where the first declaration
849 // is not lexical.
850 context.Check(seconds[j],
851 i < 2 ? EXPECT_RESULT : EXPECT_ERROR, Number::New(2));
852 }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000853 }
854}