The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / deps / v8 / test / cctest / test-decls.cc @ 40c0f755

History | View | Annotate | Download (16.7 KB)

1 40c0f755 Ryan
// 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 "v8.h"
31
32
#include "heap.h"
33
#include "cctest.h"
34
35
using namespace v8;
36
37
38
enum Expectations {
39
  EXPECT_RESULT,
40
  EXPECT_EXCEPTION
41
};
42
43
44
// A DeclarationContext holds a reference to a v8::Context and keeps
45
// track of various declaration related counters to make it easier to
46
// track if global declarations in the presence of interceptors behave
47
// the right way.
48
class DeclarationContext {
49
 public:
50
  DeclarationContext();
51
52
  virtual ~DeclarationContext() {
53
    if (is_initialized_) {
54
      context_->Exit();
55
      context_.Dispose();
56
    }
57
  }
58
59
  void Check(const char* source,
60
             int get, int set, int has,
61
             Expectations expectations,
62
             v8::Handle<Value> value = Local<Value>());
63
64
  int get_count() const { return get_count_; }
65
  int set_count() const { return set_count_; }
66
  int has_count() const { return has_count_; }
67
68
 protected:
69
  virtual v8::Handle<Value> Get(Local<String> key);
70
  virtual v8::Handle<Value> Set(Local<String> key, Local<Value> value);
71
  virtual v8::Handle<Boolean> Has(Local<String> key);
72
73
  void InitializeIfNeeded();
74
75
  // Get the holder for the interceptor. Default to the instance template
76
  // but may be overwritten.
77
  virtual Local<ObjectTemplate> GetHolder(Local<FunctionTemplate> function) {
78
    return function->InstanceTemplate();
79
  }
80
81
  // The handlers are called as static functions that forward
82
  // to the instance specific virtual methods.
83
  static v8::Handle<Value> HandleGet(Local<String> key,
84
                                     const AccessorInfo& info);
85
  static v8::Handle<Value> HandleSet(Local<String> key,
86
                                     Local<Value> value,
87
                                     const AccessorInfo& info);
88
  static v8::Handle<Boolean> HandleHas(Local<String> key,
89
                                       const AccessorInfo& info);
90
91
 private:
92
  bool is_initialized_;
93
  Persistent<Context> context_;
94
  Local<String> property_;
95
96
  int get_count_;
97
  int set_count_;
98
  int has_count_;
99
100
  static DeclarationContext* GetInstance(const AccessorInfo& info);
101
};
102
103
104
DeclarationContext::DeclarationContext()
105
    : is_initialized_(false), get_count_(0), set_count_(0), has_count_(0) {
106
  // Do nothing.
107
}
108
109
110
void DeclarationContext::InitializeIfNeeded() {
111
  if (is_initialized_) return;
112
  HandleScope scope;
113
  Local<FunctionTemplate> function = FunctionTemplate::New();
114
  Local<Value> data = Integer::New(reinterpret_cast<intptr_t>(this));
115
  GetHolder(function)->SetNamedPropertyHandler(&HandleGet,
116
                                               &HandleSet,
117
                                               &HandleHas,
118
                                               0, 0,
119
                                               data);
120
  context_ = Context::New(0, function->InstanceTemplate(), Local<Value>());
121
  context_->Enter();
122
  is_initialized_ = true;
123
}
124
125
126
void DeclarationContext::Check(const char* source,
127
                               int get, int set, int has,
128
                               Expectations expectations,
129
                               v8::Handle<Value> value) {
130
  InitializeIfNeeded();
131
  // A retry after a GC may pollute the counts, so perform gc now
132
  // to avoid that.
133
  v8::internal::Heap::CollectGarbage(0, v8::internal::NEW_SPACE);
134
  HandleScope scope;
135
  TryCatch catcher;
136
  catcher.SetVerbose(true);
137
  Local<Value> result = Script::Compile(String::New(source))->Run();
138
  CHECK_EQ(get, get_count());
139
  CHECK_EQ(set, set_count());
140
  CHECK_EQ(has, has_count());
141
  if (expectations == EXPECT_RESULT) {
142
    CHECK(!catcher.HasCaught());
143
    if (!value.IsEmpty()) {
144
      CHECK_EQ(value, result);
145
    }
146
  } else {
147
    CHECK(expectations == EXPECT_EXCEPTION);
148
    CHECK(catcher.HasCaught());
149
    if (!value.IsEmpty()) {
150
      CHECK_EQ(value, catcher.Exception());
151
    }
152
  }
153
}
154
155
156
v8::Handle<Value> DeclarationContext::HandleGet(Local<String> key,
157
                                                const AccessorInfo& info) {
158
  DeclarationContext* context = GetInstance(info);
159
  context->get_count_++;
160
  return context->Get(key);
161
}
162
163
164
v8::Handle<Value> DeclarationContext::HandleSet(Local<String> key,
165
                                                Local<Value> value,
166
                                                const AccessorInfo& info) {
167
  DeclarationContext* context = GetInstance(info);
168
  context->set_count_++;
169
  return context->Set(key, value);
170
}
171
172
173
v8::Handle<Boolean> DeclarationContext::HandleHas(Local<String> key,
174
                                                  const AccessorInfo& info) {
175
  DeclarationContext* context = GetInstance(info);
176
  context->has_count_++;
177
  return context->Has(key);
178
}
179
180
181
DeclarationContext* DeclarationContext::GetInstance(const AccessorInfo& info) {
182
  Local<Value> data = info.Data();
183
  return reinterpret_cast<DeclarationContext*>(Int32::Cast(*data)->Value());
184
}
185
186
187
v8::Handle<Value> DeclarationContext::Get(Local<String> key) {
188
  return v8::Handle<Value>();
189
}
190
191
192
v8::Handle<Value> DeclarationContext::Set(Local<String> key,
193
                                          Local<Value> value) {
194
  return v8::Handle<Value>();
195
}
196
197
198
v8::Handle<Boolean> DeclarationContext::Has(Local<String> key) {
199
  return v8::Handle<Boolean>();
200
}
201
202
203
// Test global declaration of a property the interceptor doesn't know
204
// about and doesn't handle.
205
TEST(Unknown) {
206
  HandleScope scope;
207
208
  { DeclarationContext context;
209
    context.Check("var x; x",
210
                  1,  // access
211
                  1,  // declaration
212
                  2,  // declaration + initialization
213
                  EXPECT_RESULT, Undefined());
214
  }
215
216
  { DeclarationContext context;
217
    context.Check("var x = 0; x",
218
                  1,  // access
219
                  2,  // declaration + initialization
220
                  2,  // declaration + initialization
221
                  EXPECT_RESULT, Number::New(0));
222
  }
223
224
  { DeclarationContext context;
225
    context.Check("function x() { }; x",
226
                  1,  // access
227
                  1,  // declaration
228
                  0,
229
                  EXPECT_RESULT);
230
  }
231
232
  { DeclarationContext context;
233
    context.Check("const x; x",
234
                  1,  // access
235
                  2,  // declaration + initialization
236
                  2,  // declaration + initialization
237
                  EXPECT_RESULT, Undefined());
238
  }
239
240
  { DeclarationContext context;
241
    context.Check("const x = 0; x",
242
                  1,  // access
243
                  2,  // declaration + initialization
244
                  2,  // declaration + initialization
245
                  EXPECT_RESULT, Undefined());  // SB 0 - BUG 1213579
246
  }
247
}
248
249
250
251
class PresentPropertyContext: public DeclarationContext {
252
 protected:
253
  virtual v8::Handle<Boolean> Has(Local<String> key) {
254
    return True();
255
  }
256
};
257
258
259
260
TEST(Present) {
261
  HandleScope scope;
262
263
  { PresentPropertyContext context;
264
    context.Check("var x; x",
265
                  1,  // access
266
                  0,
267
                  2,  // declaration + initialization
268
                  EXPECT_EXCEPTION);  // x is not defined!
269
  }
270
271
  { PresentPropertyContext context;
272
    context.Check("var x = 0; x",
273
                  1,  // access
274
                  1,  // initialization
275
                  2,  // declaration + initialization
276
                  EXPECT_RESULT, Number::New(0));
277
  }
278
279
  { PresentPropertyContext context;
280
    context.Check("function x() { }; x",
281
                  1,  // access
282
                  1,  // declaration
283
                  0,
284
                  EXPECT_RESULT);
285
  }
286
287
  { PresentPropertyContext context;
288
    context.Check("const x; x",
289
                  0,
290
                  0,
291
                  1,  // (re-)declaration
292
                  EXPECT_EXCEPTION);  // x has already been declared!
293
  }
294
295
  { PresentPropertyContext context;
296
    context.Check("const x = 0; x",
297
                  0,
298
                  0,
299
                  1,  // (re-)declaration
300
                  EXPECT_EXCEPTION);  // x has already been declared!
301
  }
302
}
303
304
305
306
class AbsentPropertyContext: public DeclarationContext {
307
 protected:
308
  virtual v8::Handle<Boolean> Has(Local<String> key) {
309
    return False();
310
  }
311
};
312
313
314
TEST(Absent) {
315
  HandleScope scope;
316
317
  { AbsentPropertyContext context;
318
    context.Check("var x; x",
319
                  1,  // access
320
                  2,  // declaration + initialization
321
                  2,  // declaration + initialization
322
                  EXPECT_RESULT, Undefined());
323
  }
324
325
  { AbsentPropertyContext context;
326
    context.Check("var x = 0; x",
327
                  1,  // access
328
                  2,  // declaration + initialization
329
                  2,  // declaration + initialization
330
                  EXPECT_RESULT, Number::New(0));
331
  }
332
333
  { AbsentPropertyContext context;
334
    context.Check("function x() { }; x",
335
                  1,  // access
336
                  1,  // declaration
337
                  0,
338
                  EXPECT_RESULT);
339
  }
340
341
  { AbsentPropertyContext context;
342
    context.Check("const x; x",
343
                  1,  // access
344
                  2,  // declaration + initialization
345
                  2,  // declaration + initializetion
346
                  EXPECT_RESULT, Undefined());
347
  }
348
349
  { AbsentPropertyContext context;
350
    context.Check("const x = 0; x",
351
                  1,  // access
352
                  2,  // declaration + initialization
353
                  2,  // declaration + initialization
354
                  EXPECT_RESULT, Undefined());  // SB 0 - BUG 1213579
355
  }
356
357
  { AbsentPropertyContext context;
358
    context.Check("if (false) { var x = 0 }; x",
359
                  1,  // access
360
                  1,  // declaration
361
                  1,  // declaration + initialization
362
                  EXPECT_RESULT, Undefined());
363
  }
364
}
365
366
367
368
class AppearingPropertyContext: public DeclarationContext {
369
 public:
370
  enum State {
371
    DECLARE,
372
    INITIALIZE_IF_ASSIGN,
373
    UNKNOWN
374
  };
375
376
  AppearingPropertyContext() : state_(DECLARE) { }
377
378
 protected:
379
  virtual v8::Handle<Boolean> Has(Local<String> key) {
380
    switch (state_) {
381
      case DECLARE:
382
        // Force declaration by returning that the
383
        // property is absent.
384
        state_ = INITIALIZE_IF_ASSIGN;
385
        return False();
386
      case INITIALIZE_IF_ASSIGN:
387
        // Return that the property is present so we only get the
388
        // setter called when initializing with a value.
389
        state_ = UNKNOWN;
390
        return True();
391
      default:
392
        ASSERT(state_ == UNKNOWN);
393
        break;
394
    }
395
    // Do the lookup in the object.
396
    return v8::Local<Boolean>();
397
  }
398
399
 private:
400
  State state_;
401
};
402
403
404
TEST(Appearing) {
405
  HandleScope scope;
406
407
  { AppearingPropertyContext context;
408
    context.Check("var x; x",
409
                  1,  // access
410
                  1,  // declaration
411
                  2,  // declaration + initialization
412
                  EXPECT_RESULT, Undefined());
413
  }
414
415
  { AppearingPropertyContext context;
416
    context.Check("var x = 0; x",
417
                  1,  // access
418
                  2,  // declaration + initialization
419
                  2,  // declaration + initialization
420
                  EXPECT_RESULT, Number::New(0));
421
  }
422
423
  { AppearingPropertyContext context;
424
    context.Check("function x() { }; x",
425
                  1,  // access
426
                  1,  // declaration
427
                  0,
428
                  EXPECT_RESULT);
429
  }
430
431
  { AppearingPropertyContext context;
432
    context.Check("const x; x",
433
                  0,
434
                  1,  // declaration
435
                  2,  // declaration + initialization
436
                  EXPECT_EXCEPTION);  // x has already been declared!
437
  }
438
439
  { AppearingPropertyContext context;
440
    context.Check("const x = 0; x",
441
                  0,
442
                  1,  // declaration
443
                  2,  // declaration + initialization
444
                  EXPECT_EXCEPTION);  //  x has already been declared!
445
  }
446
}
447
448
449
450
class ReappearingPropertyContext: public DeclarationContext {
451
 public:
452
  enum State {
453
    DECLARE,
454
    DONT_DECLARE,
455
    INITIALIZE,
456
    UNKNOWN
457
  };
458
459
  ReappearingPropertyContext() : state_(DECLARE) { }
460
461
 protected:
462
  virtual v8::Handle<Boolean> Has(Local<String> key) {
463
    switch (state_) {
464
      case DECLARE:
465
        // Force the first declaration by returning that
466
        // the property is absent.
467
        state_ = DONT_DECLARE;
468
        return False();
469
      case DONT_DECLARE:
470
        // Ignore the second declaration by returning
471
        // that the property is already there.
472
        state_ = INITIALIZE;
473
        return True();
474
      case INITIALIZE:
475
        // Force an initialization by returning that
476
        // the property is absent. This will make sure
477
        // that the setter is called and it will not
478
        // lead to redeclaration conflicts (yet).
479
        state_ = UNKNOWN;
480
        return False();
481
      default:
482
        ASSERT(state_ == UNKNOWN);
483
        break;
484
    }
485
    // Do the lookup in the object.
486
    return v8::Local<Boolean>();
487
  }
488
489
 private:
490
  State state_;
491
};
492
493
494
TEST(Reappearing) {
495
  HandleScope scope;
496
497
  { ReappearingPropertyContext context;
498
    context.Check("const x; var x = 0",
499
                  0,
500
                  2,  // var declaration + const initialization
501
                  4,  // 2 x declaration + 2 x initialization
502
                  EXPECT_EXCEPTION);  // x has already been declared!
503
  }
504
}
505
506
507
508
class ExistsInPrototypeContext: public DeclarationContext {
509
 protected:
510
  virtual v8::Handle<Boolean> Has(Local<String> key) {
511
    // Let it seem that the property exists in the prototype object.
512
    return True();
513
  }
514
515
  // Use the prototype as the holder for the interceptors.
516
  virtual Local<ObjectTemplate> GetHolder(Local<FunctionTemplate> function) {
517
    return function->PrototypeTemplate();
518
  }
519
};
520
521
522
TEST(ExistsInPrototype) {
523
  HandleScope scope;
524
525
  // Sanity check to make sure that the holder of the interceptor
526
  // really is the prototype object.
527
  { ExistsInPrototypeContext context;
528
    context.Check("this.x = 87; this.x",
529
                  0,
530
                  0,
531
                  0,
532
                  EXPECT_RESULT, Number::New(87));
533
  }
534
535
  { ExistsInPrototypeContext context;
536
    context.Check("var x; x",
537
                  0,
538
                  0,
539
                  1,  // declaration
540
                  EXPECT_RESULT, Undefined());
541
  }
542
543
  { ExistsInPrototypeContext context;
544
    context.Check("var x = 0; x",
545
                  0,
546
                  0,
547
                  1,  // declaration
548
                  EXPECT_RESULT, Number::New(0));
549
  }
550
551
  { ExistsInPrototypeContext context;
552
    context.Check("const x; x",
553
                  0,
554
                  0,
555
                  1,  // declaration
556
                  EXPECT_RESULT, Undefined());
557
  }
558
559
  { ExistsInPrototypeContext context;
560
    context.Check("const x = 0; x",
561
                  0,
562
                  0,
563
                  1,  // declaration
564
                  EXPECT_RESULT, Number::New(0));
565
  }
566
}
567
568
569
570
class AbsentInPrototypeContext: public DeclarationContext {
571
 protected:
572
  virtual v8::Handle<Boolean> Has(Local<String> key) {
573
    // Let it seem that the property is absent in the prototype object.
574
    return False();
575
  }
576
577
  // Use the prototype as the holder for the interceptors.
578
  virtual Local<ObjectTemplate> GetHolder(Local<FunctionTemplate> function) {
579
    return function->PrototypeTemplate();
580
  }
581
};
582
583
584
TEST(AbsentInPrototype) {
585
  HandleScope scope;
586
587
  { AbsentInPrototypeContext context;
588
    context.Check("if (false) { var x = 0; }; x",
589
                  0,
590
                  0,
591
                  1,  // declaration
592
                  EXPECT_RESULT, Undefined());
593
  }
594
}