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
// 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
}