test-api.cc revision 80d68eab642096c1a48b6474d6ec33064b0ad1f5
1// Copyright 2007-2009 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 <limits.h>
29
30#include "v8.h"
31
32#include "api.h"
33#include "compilation-cache.h"
34#include "execution.h"
35#include "snapshot.h"
36#include "platform.h"
37#include "top.h"
38#include "utils.h"
39#include "cctest.h"
40
41static const bool kLogThreading = true;
42
43static bool IsNaN(double x) {
44#ifdef WIN32
45  return _isnan(x);
46#else
47  return isnan(x);
48#endif
49}
50
51using ::v8::ObjectTemplate;
52using ::v8::Value;
53using ::v8::Context;
54using ::v8::Local;
55using ::v8::String;
56using ::v8::Script;
57using ::v8::Function;
58using ::v8::AccessorInfo;
59using ::v8::Extension;
60
61namespace i = ::i;
62
63
64static void ExpectString(const char* code, const char* expected) {
65  Local<Value> result = CompileRun(code);
66  CHECK(result->IsString());
67  String::AsciiValue ascii(result);
68  CHECK_EQ(expected, *ascii);
69}
70
71
72static void ExpectBoolean(const char* code, bool expected) {
73  Local<Value> result = CompileRun(code);
74  CHECK(result->IsBoolean());
75  CHECK_EQ(expected, result->BooleanValue());
76}
77
78
79static void ExpectTrue(const char* code) {
80  ExpectBoolean(code, true);
81}
82
83
84static void ExpectFalse(const char* code) {
85  ExpectBoolean(code, false);
86}
87
88
89static void ExpectObject(const char* code, Local<Value> expected) {
90  Local<Value> result = CompileRun(code);
91  CHECK(result->Equals(expected));
92}
93
94
95static void ExpectUndefined(const char* code) {
96  Local<Value> result = CompileRun(code);
97  CHECK(result->IsUndefined());
98}
99
100
101static int signature_callback_count;
102static v8::Handle<Value> IncrementingSignatureCallback(
103    const v8::Arguments& args) {
104  ApiTestFuzzer::Fuzz();
105  signature_callback_count++;
106  v8::Handle<v8::Array> result = v8::Array::New(args.Length());
107  for (int i = 0; i < args.Length(); i++)
108    result->Set(v8::Integer::New(i), args[i]);
109  return result;
110}
111
112
113static v8::Handle<Value> SignatureCallback(const v8::Arguments& args) {
114  ApiTestFuzzer::Fuzz();
115  v8::Handle<v8::Array> result = v8::Array::New(args.Length());
116  for (int i = 0; i < args.Length(); i++) {
117    result->Set(v8::Integer::New(i), args[i]);
118  }
119  return result;
120}
121
122
123THREADED_TEST(Handles) {
124  v8::HandleScope scope;
125  Local<Context> local_env;
126  {
127    LocalContext env;
128    local_env = env.local();
129  }
130
131  // Local context should still be live.
132  CHECK(!local_env.IsEmpty());
133  local_env->Enter();
134
135  v8::Handle<v8::Primitive> undef = v8::Undefined();
136  CHECK(!undef.IsEmpty());
137  CHECK(undef->IsUndefined());
138
139  const char* c_source = "1 + 2 + 3";
140  Local<String> source = String::New(c_source);
141  Local<Script> script = Script::Compile(source);
142  CHECK_EQ(6, script->Run()->Int32Value());
143
144  local_env->Exit();
145}
146
147
148THREADED_TEST(ReceiverSignature) {
149  v8::HandleScope scope;
150  LocalContext env;
151  v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
152  v8::Handle<v8::Signature> sig = v8::Signature::New(fun);
153  fun->PrototypeTemplate()->Set(
154      v8_str("m"),
155      v8::FunctionTemplate::New(IncrementingSignatureCallback,
156                                v8::Handle<Value>(),
157                                sig));
158  env->Global()->Set(v8_str("Fun"), fun->GetFunction());
159  signature_callback_count = 0;
160  CompileRun(
161      "var o = new Fun();"
162      "o.m();");
163  CHECK_EQ(1, signature_callback_count);
164  v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New();
165  sub_fun->Inherit(fun);
166  env->Global()->Set(v8_str("SubFun"), sub_fun->GetFunction());
167  CompileRun(
168      "var o = new SubFun();"
169      "o.m();");
170  CHECK_EQ(2, signature_callback_count);
171
172  v8::TryCatch try_catch;
173  CompileRun(
174      "var o = { };"
175      "o.m = Fun.prototype.m;"
176      "o.m();");
177  CHECK_EQ(2, signature_callback_count);
178  CHECK(try_catch.HasCaught());
179  try_catch.Reset();
180  v8::Handle<v8::FunctionTemplate> unrel_fun = v8::FunctionTemplate::New();
181  sub_fun->Inherit(fun);
182  env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
183  CompileRun(
184      "var o = new UnrelFun();"
185      "o.m = Fun.prototype.m;"
186      "o.m();");
187  CHECK_EQ(2, signature_callback_count);
188  CHECK(try_catch.HasCaught());
189}
190
191
192
193
194THREADED_TEST(ArgumentSignature) {
195  v8::HandleScope scope;
196  LocalContext env;
197  v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New();
198  cons->SetClassName(v8_str("Cons"));
199  v8::Handle<v8::Signature> sig =
200      v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 1, &cons);
201  v8::Handle<v8::FunctionTemplate> fun =
202      v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), sig);
203  env->Global()->Set(v8_str("Cons"), cons->GetFunction());
204  env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
205
206  v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
207  CHECK(value1->IsTrue());
208
209  v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
210  CHECK(value2->IsTrue());
211
212  v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
213  CHECK(value3->IsTrue());
214
215  v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New();
216  cons1->SetClassName(v8_str("Cons1"));
217  v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New();
218  cons2->SetClassName(v8_str("Cons2"));
219  v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New();
220  cons3->SetClassName(v8_str("Cons3"));
221
222  v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
223  v8::Handle<v8::Signature> wsig =
224      v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 3, args);
225  v8::Handle<v8::FunctionTemplate> fun2 =
226      v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), wsig);
227
228  env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
229  env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
230  env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
231  env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
232  v8::Handle<Value> value4 = CompileRun(
233      "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
234      "'[object Cons1],[object Cons2],[object Cons3]'");
235  CHECK(value4->IsTrue());
236
237  v8::Handle<Value> value5 = CompileRun(
238      "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
239  CHECK(value5->IsTrue());
240
241  v8::Handle<Value> value6 = CompileRun(
242      "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
243  CHECK(value6->IsTrue());
244
245  v8::Handle<Value> value7 = CompileRun(
246      "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
247      "'[object Cons1],[object Cons2],[object Cons3],d';");
248  CHECK(value7->IsTrue());
249
250  v8::Handle<Value> value8 = CompileRun(
251      "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
252  CHECK(value8->IsTrue());
253}
254
255
256THREADED_TEST(HulIgennem) {
257  v8::HandleScope scope;
258  LocalContext env;
259  v8::Handle<v8::Primitive> undef = v8::Undefined();
260  Local<String> undef_str = undef->ToString();
261  char* value = i::NewArray<char>(undef_str->Length() + 1);
262  undef_str->WriteAscii(value);
263  CHECK_EQ(0, strcmp(value, "undefined"));
264  i::DeleteArray(value);
265}
266
267
268THREADED_TEST(Access) {
269  v8::HandleScope scope;
270  LocalContext env;
271  Local<v8::Object> obj = v8::Object::New();
272  Local<Value> foo_before = obj->Get(v8_str("foo"));
273  CHECK(foo_before->IsUndefined());
274  Local<String> bar_str = v8_str("bar");
275  obj->Set(v8_str("foo"), bar_str);
276  Local<Value> foo_after = obj->Get(v8_str("foo"));
277  CHECK(!foo_after->IsUndefined());
278  CHECK(foo_after->IsString());
279  CHECK_EQ(bar_str, foo_after);
280}
281
282
283THREADED_TEST(AccessElement) {
284  v8::HandleScope scope;
285  LocalContext env;
286  Local<v8::Object> obj = v8::Object::New();
287  Local<Value> before = obj->Get(1);
288  CHECK(before->IsUndefined());
289  Local<String> bar_str = v8_str("bar");
290  obj->Set(1, bar_str);
291  Local<Value> after = obj->Get(1);
292  CHECK(!after->IsUndefined());
293  CHECK(after->IsString());
294  CHECK_EQ(bar_str, after);
295
296  Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
297  CHECK_EQ(v8_str("a"), value->Get(0));
298  CHECK_EQ(v8_str("b"), value->Get(1));
299}
300
301
302THREADED_TEST(Script) {
303  v8::HandleScope scope;
304  LocalContext env;
305  const char* c_source = "1 + 2 + 3";
306  Local<String> source = String::New(c_source);
307  Local<Script> script = Script::Compile(source);
308  CHECK_EQ(6, script->Run()->Int32Value());
309}
310
311
312static uint16_t* AsciiToTwoByteString(const char* source) {
313  int array_length = i::StrLength(source) + 1;
314  uint16_t* converted = i::NewArray<uint16_t>(array_length);
315  for (int i = 0; i < array_length; i++) converted[i] = source[i];
316  return converted;
317}
318
319
320class TestResource: public String::ExternalStringResource {
321 public:
322  static int dispose_count;
323
324  explicit TestResource(uint16_t* data)
325      : data_(data), length_(0) {
326    while (data[length_]) ++length_;
327  }
328
329  ~TestResource() {
330    i::DeleteArray(data_);
331    ++dispose_count;
332  }
333
334  const uint16_t* data() const {
335    return data_;
336  }
337
338  size_t length() const {
339    return length_;
340  }
341 private:
342  uint16_t* data_;
343  size_t length_;
344};
345
346
347int TestResource::dispose_count = 0;
348
349
350class TestAsciiResource: public String::ExternalAsciiStringResource {
351 public:
352  static int dispose_count;
353
354  explicit TestAsciiResource(const char* data)
355      : data_(data),
356        length_(strlen(data)) { }
357
358  ~TestAsciiResource() {
359    i::DeleteArray(data_);
360    ++dispose_count;
361  }
362
363  const char* data() const {
364    return data_;
365  }
366
367  size_t length() const {
368    return length_;
369  }
370 private:
371  const char* data_;
372  size_t length_;
373};
374
375
376int TestAsciiResource::dispose_count = 0;
377
378
379THREADED_TEST(ScriptUsingStringResource) {
380  TestResource::dispose_count = 0;
381  const char* c_source = "1 + 2 * 3";
382  uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
383  {
384    v8::HandleScope scope;
385    LocalContext env;
386    TestResource* resource = new TestResource(two_byte_source);
387    Local<String> source = String::NewExternal(resource);
388    Local<Script> script = Script::Compile(source);
389    Local<Value> value = script->Run();
390    CHECK(value->IsNumber());
391    CHECK_EQ(7, value->Int32Value());
392    CHECK(source->IsExternal());
393    CHECK_EQ(resource,
394             static_cast<TestResource*>(source->GetExternalStringResource()));
395    i::Heap::CollectAllGarbage(false);
396    CHECK_EQ(0, TestResource::dispose_count);
397  }
398  i::CompilationCache::Clear();
399  i::Heap::CollectAllGarbage(false);
400  CHECK_EQ(1, TestResource::dispose_count);
401}
402
403
404THREADED_TEST(ScriptUsingAsciiStringResource) {
405  TestAsciiResource::dispose_count = 0;
406  const char* c_source = "1 + 2 * 3";
407  {
408    v8::HandleScope scope;
409    LocalContext env;
410    Local<String> source =
411        String::NewExternal(new TestAsciiResource(i::StrDup(c_source)));
412    Local<Script> script = Script::Compile(source);
413    Local<Value> value = script->Run();
414    CHECK(value->IsNumber());
415    CHECK_EQ(7, value->Int32Value());
416    i::Heap::CollectAllGarbage(false);
417    CHECK_EQ(0, TestAsciiResource::dispose_count);
418  }
419  i::CompilationCache::Clear();
420  i::Heap::CollectAllGarbage(false);
421  CHECK_EQ(1, TestAsciiResource::dispose_count);
422}
423
424
425THREADED_TEST(ScriptMakingExternalString) {
426  TestResource::dispose_count = 0;
427  uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
428  {
429    v8::HandleScope scope;
430    LocalContext env;
431    Local<String> source = String::New(two_byte_source);
432    // Trigger GCs so that the newly allocated string moves to old gen.
433    i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in survivor space now
434    i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in old gen now
435    bool success = source->MakeExternal(new TestResource(two_byte_source));
436    CHECK(success);
437    Local<Script> script = Script::Compile(source);
438    Local<Value> value = script->Run();
439    CHECK(value->IsNumber());
440    CHECK_EQ(7, value->Int32Value());
441    i::Heap::CollectAllGarbage(false);
442    CHECK_EQ(0, TestResource::dispose_count);
443  }
444  i::CompilationCache::Clear();
445  i::Heap::CollectAllGarbage(false);
446  CHECK_EQ(1, TestResource::dispose_count);
447}
448
449
450THREADED_TEST(ScriptMakingExternalAsciiString) {
451  TestAsciiResource::dispose_count = 0;
452  const char* c_source = "1 + 2 * 3";
453  {
454    v8::HandleScope scope;
455    LocalContext env;
456    Local<String> source = v8_str(c_source);
457    // Trigger GCs so that the newly allocated string moves to old gen.
458    i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in survivor space now
459    i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in old gen now
460    bool success = source->MakeExternal(
461        new TestAsciiResource(i::StrDup(c_source)));
462    CHECK(success);
463    Local<Script> script = Script::Compile(source);
464    Local<Value> value = script->Run();
465    CHECK(value->IsNumber());
466    CHECK_EQ(7, value->Int32Value());
467    i::Heap::CollectAllGarbage(false);
468    CHECK_EQ(0, TestAsciiResource::dispose_count);
469  }
470  i::CompilationCache::Clear();
471  i::Heap::CollectAllGarbage(false);
472  CHECK_EQ(1, TestAsciiResource::dispose_count);
473}
474
475
476TEST(MakingExternalStringConditions) {
477  v8::HandleScope scope;
478  LocalContext env;
479
480  // Free some space in the new space so that we can check freshness.
481  i::Heap::CollectGarbage(0, i::NEW_SPACE);
482  i::Heap::CollectGarbage(0, i::NEW_SPACE);
483
484  uint16_t* two_byte_string = AsciiToTwoByteString("small");
485  Local<String> small_string = String::New(two_byte_string);
486  i::DeleteArray(two_byte_string);
487
488  // We should refuse to externalize newly created small string.
489  CHECK(!small_string->CanMakeExternal());
490  // Trigger GCs so that the newly allocated string moves to old gen.
491  i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in survivor space now
492  i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in old gen now
493  // Old space strings should be accepted.
494  CHECK(small_string->CanMakeExternal());
495
496  two_byte_string = AsciiToTwoByteString("small 2");
497  small_string = String::New(two_byte_string);
498  i::DeleteArray(two_byte_string);
499
500  // We should refuse externalizing newly created small string.
501  CHECK(!small_string->CanMakeExternal());
502  for (int i = 0; i < 100; i++) {
503    String::Value value(small_string);
504  }
505  // Frequently used strings should be accepted.
506  CHECK(small_string->CanMakeExternal());
507
508  const int buf_size = 10 * 1024;
509  char* buf = i::NewArray<char>(buf_size);
510  memset(buf, 'a', buf_size);
511  buf[buf_size - 1] = '\0';
512
513  two_byte_string = AsciiToTwoByteString(buf);
514  Local<String> large_string = String::New(two_byte_string);
515  i::DeleteArray(buf);
516  i::DeleteArray(two_byte_string);
517  // Large strings should be immediately accepted.
518  CHECK(large_string->CanMakeExternal());
519}
520
521
522TEST(MakingExternalAsciiStringConditions) {
523  v8::HandleScope scope;
524  LocalContext env;
525
526  // Free some space in the new space so that we can check freshness.
527  i::Heap::CollectGarbage(0, i::NEW_SPACE);
528  i::Heap::CollectGarbage(0, i::NEW_SPACE);
529
530  Local<String> small_string = String::New("small");
531  // We should refuse to externalize newly created small string.
532  CHECK(!small_string->CanMakeExternal());
533  // Trigger GCs so that the newly allocated string moves to old gen.
534  i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in survivor space now
535  i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in old gen now
536  // Old space strings should be accepted.
537  CHECK(small_string->CanMakeExternal());
538
539  small_string = String::New("small 2");
540  // We should refuse externalizing newly created small string.
541  CHECK(!small_string->CanMakeExternal());
542  for (int i = 0; i < 100; i++) {
543    String::Value value(small_string);
544  }
545  // Frequently used strings should be accepted.
546  CHECK(small_string->CanMakeExternal());
547
548  const int buf_size = 10 * 1024;
549  char* buf = i::NewArray<char>(buf_size);
550  memset(buf, 'a', buf_size);
551  buf[buf_size - 1] = '\0';
552  Local<String> large_string = String::New(buf);
553  i::DeleteArray(buf);
554  // Large strings should be immediately accepted.
555  CHECK(large_string->CanMakeExternal());
556}
557
558
559THREADED_TEST(UsingExternalString) {
560  {
561    v8::HandleScope scope;
562    uint16_t* two_byte_string = AsciiToTwoByteString("test string");
563    Local<String> string =
564        String::NewExternal(new TestResource(two_byte_string));
565    i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
566    // Trigger GCs so that the newly allocated string moves to old gen.
567    i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in survivor space now
568    i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in old gen now
569    i::Handle<i::String> isymbol = i::Factory::SymbolFromString(istring);
570    CHECK(isymbol->IsSymbol());
571  }
572  i::Heap::CollectAllGarbage(false);
573  i::Heap::CollectAllGarbage(false);
574}
575
576
577THREADED_TEST(UsingExternalAsciiString) {
578  {
579    v8::HandleScope scope;
580    const char* one_byte_string = "test string";
581    Local<String> string = String::NewExternal(
582        new TestAsciiResource(i::StrDup(one_byte_string)));
583    i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
584    // Trigger GCs so that the newly allocated string moves to old gen.
585    i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in survivor space now
586    i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in old gen now
587    i::Handle<i::String> isymbol = i::Factory::SymbolFromString(istring);
588    CHECK(isymbol->IsSymbol());
589  }
590  i::Heap::CollectAllGarbage(false);
591  i::Heap::CollectAllGarbage(false);
592}
593
594
595THREADED_TEST(ScavengeExternalString) {
596  TestResource::dispose_count = 0;
597  bool in_new_space = false;
598  {
599    v8::HandleScope scope;
600    uint16_t* two_byte_string = AsciiToTwoByteString("test string");
601    Local<String> string =
602        String::NewExternal(new TestResource(two_byte_string));
603    i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
604    i::Heap::CollectGarbage(0, i::NEW_SPACE);
605    in_new_space = i::Heap::InNewSpace(*istring);
606    CHECK(in_new_space || i::Heap::old_data_space()->Contains(*istring));
607    CHECK_EQ(0, TestResource::dispose_count);
608  }
609  i::Heap::CollectGarbage(0, in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
610  CHECK_EQ(1, TestResource::dispose_count);
611}
612
613
614THREADED_TEST(ScavengeExternalAsciiString) {
615  TestAsciiResource::dispose_count = 0;
616  bool in_new_space = false;
617  {
618    v8::HandleScope scope;
619    const char* one_byte_string = "test string";
620    Local<String> string = String::NewExternal(
621        new TestAsciiResource(i::StrDup(one_byte_string)));
622    i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
623    i::Heap::CollectGarbage(0, i::NEW_SPACE);
624    in_new_space = i::Heap::InNewSpace(*istring);
625    CHECK(in_new_space || i::Heap::old_data_space()->Contains(*istring));
626    CHECK_EQ(0, TestAsciiResource::dispose_count);
627  }
628  i::Heap::CollectGarbage(0, in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
629  CHECK_EQ(1, TestAsciiResource::dispose_count);
630}
631
632
633class TestAsciiResourceWithDisposeControl: public TestAsciiResource {
634 public:
635  static int dispose_calls;
636
637  TestAsciiResourceWithDisposeControl(const char* data, bool dispose)
638      : TestAsciiResource(data),
639        dispose_(dispose) { }
640
641  void Dispose() {
642    ++dispose_calls;
643    if (dispose_) delete this;
644  }
645 private:
646  bool dispose_;
647};
648
649
650int TestAsciiResourceWithDisposeControl::dispose_calls = 0;
651
652
653TEST(ExternalStringWithDisposeHandling) {
654  const char* c_source = "1 + 2 * 3";
655
656  // Use a stack allocated external string resource allocated object.
657  TestAsciiResource::dispose_count = 0;
658  TestAsciiResourceWithDisposeControl::dispose_calls = 0;
659  TestAsciiResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
660  {
661    v8::HandleScope scope;
662    LocalContext env;
663    Local<String> source =  String::NewExternal(&res_stack);
664    Local<Script> script = Script::Compile(source);
665    Local<Value> value = script->Run();
666    CHECK(value->IsNumber());
667    CHECK_EQ(7, value->Int32Value());
668    i::Heap::CollectAllGarbage(false);
669    CHECK_EQ(0, TestAsciiResource::dispose_count);
670  }
671  i::CompilationCache::Clear();
672  i::Heap::CollectAllGarbage(false);
673  CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
674  CHECK_EQ(0, TestAsciiResource::dispose_count);
675
676  // Use a heap allocated external string resource allocated object.
677  TestAsciiResource::dispose_count = 0;
678  TestAsciiResourceWithDisposeControl::dispose_calls = 0;
679  TestAsciiResource* res_heap =
680      new TestAsciiResourceWithDisposeControl(i::StrDup(c_source), true);
681  {
682    v8::HandleScope scope;
683    LocalContext env;
684    Local<String> source =  String::NewExternal(res_heap);
685    Local<Script> script = Script::Compile(source);
686    Local<Value> value = script->Run();
687    CHECK(value->IsNumber());
688    CHECK_EQ(7, value->Int32Value());
689    i::Heap::CollectAllGarbage(false);
690    CHECK_EQ(0, TestAsciiResource::dispose_count);
691  }
692  i::CompilationCache::Clear();
693  i::Heap::CollectAllGarbage(false);
694  CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
695  CHECK_EQ(1, TestAsciiResource::dispose_count);
696}
697
698
699THREADED_TEST(StringConcat) {
700  {
701    v8::HandleScope scope;
702    LocalContext env;
703    const char* one_byte_string_1 = "function a_times_t";
704    const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
705    const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
706    const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
707    const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
708    const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
709    const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
710    Local<String> left = v8_str(one_byte_string_1);
711
712    uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
713    Local<String> right = String::New(two_byte_source);
714    i::DeleteArray(two_byte_source);
715
716    Local<String> source = String::Concat(left, right);
717    right = String::NewExternal(
718        new TestAsciiResource(i::StrDup(one_byte_extern_1)));
719    source = String::Concat(source, right);
720    right = String::NewExternal(
721        new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
722    source = String::Concat(source, right);
723    right = v8_str(one_byte_string_2);
724    source = String::Concat(source, right);
725
726    two_byte_source = AsciiToTwoByteString(two_byte_string_2);
727    right = String::New(two_byte_source);
728    i::DeleteArray(two_byte_source);
729
730    source = String::Concat(source, right);
731    right = String::NewExternal(
732        new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
733    source = String::Concat(source, right);
734    Local<Script> script = Script::Compile(source);
735    Local<Value> value = script->Run();
736    CHECK(value->IsNumber());
737    CHECK_EQ(68, value->Int32Value());
738  }
739  i::CompilationCache::Clear();
740  i::Heap::CollectAllGarbage(false);
741  i::Heap::CollectAllGarbage(false);
742}
743
744
745THREADED_TEST(GlobalProperties) {
746  v8::HandleScope scope;
747  LocalContext env;
748  v8::Handle<v8::Object> global = env->Global();
749  global->Set(v8_str("pi"), v8_num(3.1415926));
750  Local<Value> pi = global->Get(v8_str("pi"));
751  CHECK_EQ(3.1415926, pi->NumberValue());
752}
753
754
755static v8::Handle<Value> handle_call(const v8::Arguments& args) {
756  ApiTestFuzzer::Fuzz();
757  return v8_num(102);
758}
759
760
761static v8::Handle<Value> construct_call(const v8::Arguments& args) {
762  ApiTestFuzzer::Fuzz();
763  args.This()->Set(v8_str("x"), v8_num(1));
764  args.This()->Set(v8_str("y"), v8_num(2));
765  return args.This();
766}
767
768THREADED_TEST(FunctionTemplate) {
769  v8::HandleScope scope;
770  LocalContext env;
771  {
772    Local<v8::FunctionTemplate> fun_templ =
773        v8::FunctionTemplate::New(handle_call);
774    Local<Function> fun = fun_templ->GetFunction();
775    env->Global()->Set(v8_str("obj"), fun);
776    Local<Script> script = v8_compile("obj()");
777    CHECK_EQ(102, script->Run()->Int32Value());
778  }
779  // Use SetCallHandler to initialize a function template, should work like the
780  // previous one.
781  {
782    Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
783    fun_templ->SetCallHandler(handle_call);
784    Local<Function> fun = fun_templ->GetFunction();
785    env->Global()->Set(v8_str("obj"), fun);
786    Local<Script> script = v8_compile("obj()");
787    CHECK_EQ(102, script->Run()->Int32Value());
788  }
789  // Test constructor calls.
790  {
791    Local<v8::FunctionTemplate> fun_templ =
792        v8::FunctionTemplate::New(construct_call);
793    fun_templ->SetClassName(v8_str("funky"));
794    Local<Function> fun = fun_templ->GetFunction();
795    env->Global()->Set(v8_str("obj"), fun);
796    Local<Script> script = v8_compile("var s = new obj(); s.x");
797    CHECK_EQ(1, script->Run()->Int32Value());
798
799    Local<Value> result = v8_compile("(new obj()).toString()")->Run();
800    CHECK_EQ(v8_str("[object funky]"), result);
801  }
802}
803
804
805THREADED_TEST(FindInstanceInPrototypeChain) {
806  v8::HandleScope scope;
807  LocalContext env;
808
809  Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New();
810  Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New();
811  Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New();
812  derived->Inherit(base);
813
814  Local<v8::Function> base_function = base->GetFunction();
815  Local<v8::Function> derived_function = derived->GetFunction();
816  Local<v8::Function> other_function = other->GetFunction();
817
818  Local<v8::Object> base_instance = base_function->NewInstance();
819  Local<v8::Object> derived_instance = derived_function->NewInstance();
820  Local<v8::Object> derived_instance2 = derived_function->NewInstance();
821  Local<v8::Object> other_instance = other_function->NewInstance();
822  derived_instance2->Set(v8_str("__proto__"), derived_instance);
823  other_instance->Set(v8_str("__proto__"), derived_instance2);
824
825  // base_instance is only an instance of base.
826  CHECK_EQ(base_instance,
827           base_instance->FindInstanceInPrototypeChain(base));
828  CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
829  CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
830
831  // derived_instance is an instance of base and derived.
832  CHECK_EQ(derived_instance,
833           derived_instance->FindInstanceInPrototypeChain(base));
834  CHECK_EQ(derived_instance,
835           derived_instance->FindInstanceInPrototypeChain(derived));
836  CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
837
838  // other_instance is an instance of other and its immediate
839  // prototype derived_instance2 is an instance of base and derived.
840  // Note, derived_instance is an instance of base and derived too,
841  // but it comes after derived_instance2 in the prototype chain of
842  // other_instance.
843  CHECK_EQ(derived_instance2,
844           other_instance->FindInstanceInPrototypeChain(base));
845  CHECK_EQ(derived_instance2,
846           other_instance->FindInstanceInPrototypeChain(derived));
847  CHECK_EQ(other_instance,
848           other_instance->FindInstanceInPrototypeChain(other));
849}
850
851
852THREADED_TEST(TinyInteger) {
853  v8::HandleScope scope;
854  LocalContext env;
855  int32_t value = 239;
856  Local<v8::Integer> value_obj = v8::Integer::New(value);
857  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
858}
859
860
861THREADED_TEST(BigSmiInteger) {
862  v8::HandleScope scope;
863  LocalContext env;
864  int32_t value = i::Smi::kMaxValue;
865  // We cannot add one to a Smi::kMaxValue without wrapping.
866  if (i::kSmiValueSize < 32) {
867    CHECK(i::Smi::IsValid(value));
868    CHECK(!i::Smi::IsValid(value + 1));
869    Local<v8::Integer> value_obj = v8::Integer::New(value);
870    CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
871  }
872}
873
874
875THREADED_TEST(BigInteger) {
876  v8::HandleScope scope;
877  LocalContext env;
878  // We cannot add one to a Smi::kMaxValue without wrapping.
879  if (i::kSmiValueSize < 32) {
880    // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
881    // The code will not be run in that case, due to the "if" guard.
882    int32_t value =
883        static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
884    CHECK(value > i::Smi::kMaxValue);
885    CHECK(!i::Smi::IsValid(value));
886    Local<v8::Integer> value_obj = v8::Integer::New(value);
887    CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
888  }
889}
890
891
892THREADED_TEST(TinyUnsignedInteger) {
893  v8::HandleScope scope;
894  LocalContext env;
895  uint32_t value = 239;
896  Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
897  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
898}
899
900
901THREADED_TEST(BigUnsignedSmiInteger) {
902  v8::HandleScope scope;
903  LocalContext env;
904  uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
905  CHECK(i::Smi::IsValid(value));
906  CHECK(!i::Smi::IsValid(value + 1));
907  Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
908  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
909}
910
911
912THREADED_TEST(BigUnsignedInteger) {
913  v8::HandleScope scope;
914  LocalContext env;
915  uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
916  CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
917  CHECK(!i::Smi::IsValid(value));
918  Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
919  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
920}
921
922
923THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
924  v8::HandleScope scope;
925  LocalContext env;
926  uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
927  uint32_t value = INT32_MAX_AS_UINT + 1;
928  CHECK(value > INT32_MAX_AS_UINT);  // No overflow.
929  Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
930  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
931}
932
933
934THREADED_TEST(Number) {
935  v8::HandleScope scope;
936  LocalContext env;
937  double PI = 3.1415926;
938  Local<v8::Number> pi_obj = v8::Number::New(PI);
939  CHECK_EQ(PI, pi_obj->NumberValue());
940}
941
942
943THREADED_TEST(ToNumber) {
944  v8::HandleScope scope;
945  LocalContext env;
946  Local<String> str = v8_str("3.1415926");
947  CHECK_EQ(3.1415926, str->NumberValue());
948  v8::Handle<v8::Boolean> t = v8::True();
949  CHECK_EQ(1.0, t->NumberValue());
950  v8::Handle<v8::Boolean> f = v8::False();
951  CHECK_EQ(0.0, f->NumberValue());
952}
953
954
955THREADED_TEST(Date) {
956  v8::HandleScope scope;
957  LocalContext env;
958  double PI = 3.1415926;
959  Local<Value> date_obj = v8::Date::New(PI);
960  CHECK_EQ(3.0, date_obj->NumberValue());
961}
962
963
964THREADED_TEST(Boolean) {
965  v8::HandleScope scope;
966  LocalContext env;
967  v8::Handle<v8::Boolean> t = v8::True();
968  CHECK(t->Value());
969  v8::Handle<v8::Boolean> f = v8::False();
970  CHECK(!f->Value());
971  v8::Handle<v8::Primitive> u = v8::Undefined();
972  CHECK(!u->BooleanValue());
973  v8::Handle<v8::Primitive> n = v8::Null();
974  CHECK(!n->BooleanValue());
975  v8::Handle<String> str1 = v8_str("");
976  CHECK(!str1->BooleanValue());
977  v8::Handle<String> str2 = v8_str("x");
978  CHECK(str2->BooleanValue());
979  CHECK(!v8::Number::New(0)->BooleanValue());
980  CHECK(v8::Number::New(-1)->BooleanValue());
981  CHECK(v8::Number::New(1)->BooleanValue());
982  CHECK(v8::Number::New(42)->BooleanValue());
983  CHECK(!v8_compile("NaN")->Run()->BooleanValue());
984}
985
986
987static v8::Handle<Value> DummyCallHandler(const v8::Arguments& args) {
988  ApiTestFuzzer::Fuzz();
989  return v8_num(13.4);
990}
991
992
993static v8::Handle<Value> GetM(Local<String> name, const AccessorInfo&) {
994  ApiTestFuzzer::Fuzz();
995  return v8_num(876);
996}
997
998
999THREADED_TEST(GlobalPrototype) {
1000  v8::HandleScope scope;
1001  v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
1002  func_templ->PrototypeTemplate()->Set(
1003      "dummy",
1004      v8::FunctionTemplate::New(DummyCallHandler));
1005  v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1006  templ->Set("x", v8_num(200));
1007  templ->SetAccessor(v8_str("m"), GetM);
1008  LocalContext env(0, templ);
1009  v8::Handle<v8::Object> obj = env->Global();
1010  v8::Handle<Script> script = v8_compile("dummy()");
1011  v8::Handle<Value> result = script->Run();
1012  CHECK_EQ(13.4, result->NumberValue());
1013  CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1014  CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1015}
1016
1017
1018THREADED_TEST(ObjectTemplate) {
1019  v8::HandleScope scope;
1020  Local<ObjectTemplate> templ1 = ObjectTemplate::New();
1021  templ1->Set("x", v8_num(10));
1022  templ1->Set("y", v8_num(13));
1023  LocalContext env;
1024  Local<v8::Object> instance1 = templ1->NewInstance();
1025  env->Global()->Set(v8_str("p"), instance1);
1026  CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1027  CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1028  Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
1029  fun->PrototypeTemplate()->Set("nirk", v8_num(123));
1030  Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1031  templ2->Set("a", v8_num(12));
1032  templ2->Set("b", templ1);
1033  Local<v8::Object> instance2 = templ2->NewInstance();
1034  env->Global()->Set(v8_str("q"), instance2);
1035  CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1036  CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1037  CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1038  CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1039}
1040
1041
1042static v8::Handle<Value> GetFlabby(const v8::Arguments& args) {
1043  ApiTestFuzzer::Fuzz();
1044  return v8_num(17.2);
1045}
1046
1047
1048static v8::Handle<Value> GetKnurd(Local<String> property, const AccessorInfo&) {
1049  ApiTestFuzzer::Fuzz();
1050  return v8_num(15.2);
1051}
1052
1053
1054THREADED_TEST(DescriptorInheritance) {
1055  v8::HandleScope scope;
1056  v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New();
1057  super->PrototypeTemplate()->Set("flabby",
1058                                  v8::FunctionTemplate::New(GetFlabby));
1059  super->PrototypeTemplate()->Set("PI", v8_num(3.14));
1060
1061  super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1062
1063  v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New();
1064  base1->Inherit(super);
1065  base1->PrototypeTemplate()->Set("v1", v8_num(20.1));
1066
1067  v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New();
1068  base2->Inherit(super);
1069  base2->PrototypeTemplate()->Set("v2", v8_num(10.1));
1070
1071  LocalContext env;
1072
1073  env->Global()->Set(v8_str("s"), super->GetFunction());
1074  env->Global()->Set(v8_str("base1"), base1->GetFunction());
1075  env->Global()->Set(v8_str("base2"), base2->GetFunction());
1076
1077  // Checks right __proto__ chain.
1078  CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1079  CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1080
1081  CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1082
1083  // Instance accessor should not be visible on function object or its prototype
1084  CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1085  CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1086  CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1087
1088  env->Global()->Set(v8_str("obj"),
1089                     base1->GetFunction()->NewInstance());
1090  CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1091  CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1092  CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1093  CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1094  CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1095
1096  env->Global()->Set(v8_str("obj2"),
1097                     base2->GetFunction()->NewInstance());
1098  CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1099  CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1100  CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1101  CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1102  CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1103
1104  // base1 and base2 cannot cross reference to each's prototype
1105  CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1106  CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1107}
1108
1109
1110int echo_named_call_count;
1111
1112
1113static v8::Handle<Value> EchoNamedProperty(Local<String> name,
1114                                           const AccessorInfo& info) {
1115  ApiTestFuzzer::Fuzz();
1116  CHECK_EQ(v8_str("data"), info.Data());
1117  echo_named_call_count++;
1118  return name;
1119}
1120
1121
1122THREADED_TEST(NamedPropertyHandlerGetter) {
1123  echo_named_call_count = 0;
1124  v8::HandleScope scope;
1125  v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1126  templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
1127                                                     0, 0, 0, 0,
1128                                                     v8_str("data"));
1129  LocalContext env;
1130  env->Global()->Set(v8_str("obj"),
1131                     templ->GetFunction()->NewInstance());
1132  CHECK_EQ(echo_named_call_count, 0);
1133  v8_compile("obj.x")->Run();
1134  CHECK_EQ(echo_named_call_count, 1);
1135  const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
1136  v8::Handle<Value> str = CompileRun(code);
1137  String::AsciiValue value(str);
1138  CHECK_EQ(*value, "oddlepoddle");
1139  // Check default behavior
1140  CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
1141  CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
1142  CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
1143}
1144
1145
1146int echo_indexed_call_count = 0;
1147
1148
1149static v8::Handle<Value> EchoIndexedProperty(uint32_t index,
1150                                             const AccessorInfo& info) {
1151  ApiTestFuzzer::Fuzz();
1152  CHECK_EQ(v8_num(637), info.Data());
1153  echo_indexed_call_count++;
1154  return v8_num(index);
1155}
1156
1157
1158THREADED_TEST(IndexedPropertyHandlerGetter) {
1159  v8::HandleScope scope;
1160  v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1161  templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
1162                                                       0, 0, 0, 0,
1163                                                       v8_num(637));
1164  LocalContext env;
1165  env->Global()->Set(v8_str("obj"),
1166                     templ->GetFunction()->NewInstance());
1167  Local<Script> script = v8_compile("obj[900]");
1168  CHECK_EQ(script->Run()->Int32Value(), 900);
1169}
1170
1171
1172v8::Handle<v8::Object> bottom;
1173
1174static v8::Handle<Value> CheckThisIndexedPropertyHandler(
1175    uint32_t index,
1176    const AccessorInfo& info) {
1177  ApiTestFuzzer::Fuzz();
1178  CHECK(info.This()->Equals(bottom));
1179  return v8::Handle<Value>();
1180}
1181
1182static v8::Handle<Value> CheckThisNamedPropertyHandler(
1183    Local<String> name,
1184    const AccessorInfo& info) {
1185  ApiTestFuzzer::Fuzz();
1186  CHECK(info.This()->Equals(bottom));
1187  return v8::Handle<Value>();
1188}
1189
1190
1191v8::Handle<Value> CheckThisIndexedPropertySetter(uint32_t index,
1192                                                 Local<Value> value,
1193                                                 const AccessorInfo& info) {
1194  ApiTestFuzzer::Fuzz();
1195  CHECK(info.This()->Equals(bottom));
1196  return v8::Handle<Value>();
1197}
1198
1199
1200v8::Handle<Value> CheckThisNamedPropertySetter(Local<String> property,
1201                                               Local<Value> value,
1202                                               const AccessorInfo& info) {
1203  ApiTestFuzzer::Fuzz();
1204  CHECK(info.This()->Equals(bottom));
1205  return v8::Handle<Value>();
1206}
1207
1208v8::Handle<v8::Integer> CheckThisIndexedPropertyQuery(
1209    uint32_t index,
1210    const AccessorInfo& info) {
1211  ApiTestFuzzer::Fuzz();
1212  CHECK(info.This()->Equals(bottom));
1213  return v8::Handle<v8::Integer>();
1214}
1215
1216
1217v8::Handle<v8::Integer> CheckThisNamedPropertyQuery(Local<String> property,
1218                                                    const AccessorInfo& info) {
1219  ApiTestFuzzer::Fuzz();
1220  CHECK(info.This()->Equals(bottom));
1221  return v8::Handle<v8::Integer>();
1222}
1223
1224
1225v8::Handle<v8::Boolean> CheckThisIndexedPropertyDeleter(
1226    uint32_t index,
1227    const AccessorInfo& info) {
1228  ApiTestFuzzer::Fuzz();
1229  CHECK(info.This()->Equals(bottom));
1230  return v8::Handle<v8::Boolean>();
1231}
1232
1233
1234v8::Handle<v8::Boolean> CheckThisNamedPropertyDeleter(
1235    Local<String> property,
1236    const AccessorInfo& info) {
1237  ApiTestFuzzer::Fuzz();
1238  CHECK(info.This()->Equals(bottom));
1239  return v8::Handle<v8::Boolean>();
1240}
1241
1242
1243v8::Handle<v8::Array> CheckThisIndexedPropertyEnumerator(
1244    const AccessorInfo& info) {
1245  ApiTestFuzzer::Fuzz();
1246  CHECK(info.This()->Equals(bottom));
1247  return v8::Handle<v8::Array>();
1248}
1249
1250
1251v8::Handle<v8::Array> CheckThisNamedPropertyEnumerator(
1252    const AccessorInfo& info) {
1253  ApiTestFuzzer::Fuzz();
1254  CHECK(info.This()->Equals(bottom));
1255  return v8::Handle<v8::Array>();
1256}
1257
1258
1259THREADED_TEST(PropertyHandlerInPrototype) {
1260  v8::HandleScope scope;
1261  LocalContext env;
1262
1263  // Set up a prototype chain with three interceptors.
1264  v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1265  templ->InstanceTemplate()->SetIndexedPropertyHandler(
1266      CheckThisIndexedPropertyHandler,
1267      CheckThisIndexedPropertySetter,
1268      CheckThisIndexedPropertyQuery,
1269      CheckThisIndexedPropertyDeleter,
1270      CheckThisIndexedPropertyEnumerator);
1271
1272  templ->InstanceTemplate()->SetNamedPropertyHandler(
1273      CheckThisNamedPropertyHandler,
1274      CheckThisNamedPropertySetter,
1275      CheckThisNamedPropertyQuery,
1276      CheckThisNamedPropertyDeleter,
1277      CheckThisNamedPropertyEnumerator);
1278
1279  bottom = templ->GetFunction()->NewInstance();
1280  Local<v8::Object> top = templ->GetFunction()->NewInstance();
1281  Local<v8::Object> middle = templ->GetFunction()->NewInstance();
1282
1283  bottom->Set(v8_str("__proto__"), middle);
1284  middle->Set(v8_str("__proto__"), top);
1285  env->Global()->Set(v8_str("obj"), bottom);
1286
1287  // Indexed and named get.
1288  Script::Compile(v8_str("obj[0]"))->Run();
1289  Script::Compile(v8_str("obj.x"))->Run();
1290
1291  // Indexed and named set.
1292  Script::Compile(v8_str("obj[1] = 42"))->Run();
1293  Script::Compile(v8_str("obj.y = 42"))->Run();
1294
1295  // Indexed and named query.
1296  Script::Compile(v8_str("0 in obj"))->Run();
1297  Script::Compile(v8_str("'x' in obj"))->Run();
1298
1299  // Indexed and named deleter.
1300  Script::Compile(v8_str("delete obj[0]"))->Run();
1301  Script::Compile(v8_str("delete obj.x"))->Run();
1302
1303  // Enumerators.
1304  Script::Compile(v8_str("for (var p in obj) ;"))->Run();
1305}
1306
1307
1308static v8::Handle<Value> PrePropertyHandlerGet(Local<String> key,
1309                                               const AccessorInfo& info) {
1310  ApiTestFuzzer::Fuzz();
1311  if (v8_str("pre")->Equals(key)) {
1312    return v8_str("PrePropertyHandler: pre");
1313  }
1314  return v8::Handle<String>();
1315}
1316
1317
1318static v8::Handle<v8::Integer> PrePropertyHandlerQuery(Local<String> key,
1319                                                       const AccessorInfo&) {
1320  if (v8_str("pre")->Equals(key)) {
1321    return v8::Integer::New(v8::None);
1322  }
1323
1324  return v8::Handle<v8::Integer>();  // do not intercept the call
1325}
1326
1327
1328THREADED_TEST(PrePropertyHandler) {
1329  v8::HandleScope scope;
1330  v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
1331  desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
1332                                                    0,
1333                                                    PrePropertyHandlerQuery);
1334  LocalContext env(NULL, desc->InstanceTemplate());
1335  Script::Compile(v8_str(
1336      "var pre = 'Object: pre'; var on = 'Object: on';"))->Run();
1337  v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run();
1338  CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
1339  v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run();
1340  CHECK_EQ(v8_str("Object: on"), result_on);
1341  v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run();
1342  CHECK(result_post.IsEmpty());
1343}
1344
1345
1346THREADED_TEST(UndefinedIsNotEnumerable) {
1347  v8::HandleScope scope;
1348  LocalContext env;
1349  v8::Handle<Value> result = Script::Compile(v8_str(
1350      "this.propertyIsEnumerable(undefined)"))->Run();
1351  CHECK(result->IsFalse());
1352}
1353
1354
1355v8::Handle<Script> call_recursively_script;
1356static const int kTargetRecursionDepth = 200;  // near maximum
1357
1358
1359static v8::Handle<Value> CallScriptRecursivelyCall(const v8::Arguments& args) {
1360  ApiTestFuzzer::Fuzz();
1361  int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1362  if (depth == kTargetRecursionDepth) return v8::Undefined();
1363  args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1364  return call_recursively_script->Run();
1365}
1366
1367
1368static v8::Handle<Value> CallFunctionRecursivelyCall(
1369    const v8::Arguments& args) {
1370  ApiTestFuzzer::Fuzz();
1371  int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1372  if (depth == kTargetRecursionDepth) {
1373    printf("[depth = %d]\n", depth);
1374    return v8::Undefined();
1375  }
1376  args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1377  v8::Handle<Value> function =
1378      args.This()->Get(v8_str("callFunctionRecursively"));
1379  return function.As<Function>()->Call(args.This(), 0, NULL);
1380}
1381
1382
1383THREADED_TEST(DeepCrossLanguageRecursion) {
1384  v8::HandleScope scope;
1385  v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
1386  global->Set(v8_str("callScriptRecursively"),
1387              v8::FunctionTemplate::New(CallScriptRecursivelyCall));
1388  global->Set(v8_str("callFunctionRecursively"),
1389              v8::FunctionTemplate::New(CallFunctionRecursivelyCall));
1390  LocalContext env(NULL, global);
1391
1392  env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1393  call_recursively_script = v8_compile("callScriptRecursively()");
1394  v8::Handle<Value> result = call_recursively_script->Run();
1395  call_recursively_script = v8::Handle<Script>();
1396
1397  env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1398  Script::Compile(v8_str("callFunctionRecursively()"))->Run();
1399}
1400
1401
1402static v8::Handle<Value>
1403    ThrowingPropertyHandlerGet(Local<String> key, const AccessorInfo&) {
1404  ApiTestFuzzer::Fuzz();
1405  return v8::ThrowException(key);
1406}
1407
1408
1409static v8::Handle<Value> ThrowingPropertyHandlerSet(Local<String> key,
1410                                                    Local<Value>,
1411                                                    const AccessorInfo&) {
1412  v8::ThrowException(key);
1413  return v8::Undefined();  // not the same as v8::Handle<v8::Value>()
1414}
1415
1416
1417THREADED_TEST(CallbackExceptionRegression) {
1418  v8::HandleScope scope;
1419  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
1420  obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
1421                               ThrowingPropertyHandlerSet);
1422  LocalContext env;
1423  env->Global()->Set(v8_str("obj"), obj->NewInstance());
1424  v8::Handle<Value> otto = Script::Compile(v8_str(
1425      "try { with (obj) { otto; } } catch (e) { e; }"))->Run();
1426  CHECK_EQ(v8_str("otto"), otto);
1427  v8::Handle<Value> netto = Script::Compile(v8_str(
1428      "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run();
1429  CHECK_EQ(v8_str("netto"), netto);
1430}
1431
1432
1433THREADED_TEST(FunctionPrototype) {
1434  v8::HandleScope scope;
1435  Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New();
1436  Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
1437  LocalContext env;
1438  env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
1439  Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak"));
1440  CHECK_EQ(script->Run()->Int32Value(), 321);
1441}
1442
1443
1444THREADED_TEST(InternalFields) {
1445  v8::HandleScope scope;
1446  LocalContext env;
1447
1448  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1449  Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1450  instance_templ->SetInternalFieldCount(1);
1451  Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1452  CHECK_EQ(1, obj->InternalFieldCount());
1453  CHECK(obj->GetInternalField(0)->IsUndefined());
1454  obj->SetInternalField(0, v8_num(17));
1455  CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
1456}
1457
1458
1459THREADED_TEST(GlobalObjectInternalFields) {
1460  v8::HandleScope scope;
1461  Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
1462  global_template->SetInternalFieldCount(1);
1463  LocalContext env(NULL, global_template);
1464  v8::Handle<v8::Object> global_proxy = env->Global();
1465  v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
1466  CHECK_EQ(1, global->InternalFieldCount());
1467  CHECK(global->GetInternalField(0)->IsUndefined());
1468  global->SetInternalField(0, v8_num(17));
1469  CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
1470}
1471
1472
1473THREADED_TEST(InternalFieldsNativePointers) {
1474  v8::HandleScope scope;
1475  LocalContext env;
1476
1477  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1478  Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1479  instance_templ->SetInternalFieldCount(1);
1480  Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1481  CHECK_EQ(1, obj->InternalFieldCount());
1482  CHECK(obj->GetPointerFromInternalField(0) == NULL);
1483
1484  char* data = new char[100];
1485
1486  void* aligned = data;
1487  CHECK_EQ(0, reinterpret_cast<uintptr_t>(aligned) & 0x1);
1488  void* unaligned = data + 1;
1489  CHECK_EQ(1, reinterpret_cast<uintptr_t>(unaligned) & 0x1);
1490
1491  // Check reading and writing aligned pointers.
1492  obj->SetPointerInInternalField(0, aligned);
1493  i::Heap::CollectAllGarbage(false);
1494  CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1495
1496  // Check reading and writing unaligned pointers.
1497  obj->SetPointerInInternalField(0, unaligned);
1498  i::Heap::CollectAllGarbage(false);
1499  CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1500
1501  delete[] data;
1502}
1503
1504
1505THREADED_TEST(InternalFieldsNativePointersAndExternal) {
1506  v8::HandleScope scope;
1507  LocalContext env;
1508
1509  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1510  Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1511  instance_templ->SetInternalFieldCount(1);
1512  Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1513  CHECK_EQ(1, obj->InternalFieldCount());
1514  CHECK(obj->GetPointerFromInternalField(0) == NULL);
1515
1516  char* data = new char[100];
1517
1518  void* aligned = data;
1519  CHECK_EQ(0, reinterpret_cast<uintptr_t>(aligned) & 0x1);
1520  void* unaligned = data + 1;
1521  CHECK_EQ(1, reinterpret_cast<uintptr_t>(unaligned) & 0x1);
1522
1523  obj->SetPointerInInternalField(0, aligned);
1524  i::Heap::CollectAllGarbage(false);
1525  CHECK_EQ(aligned, v8::External::Unwrap(obj->GetInternalField(0)));
1526
1527  obj->SetPointerInInternalField(0, unaligned);
1528  i::Heap::CollectAllGarbage(false);
1529  CHECK_EQ(unaligned, v8::External::Unwrap(obj->GetInternalField(0)));
1530
1531  obj->SetInternalField(0, v8::External::Wrap(aligned));
1532  i::Heap::CollectAllGarbage(false);
1533  CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1534
1535  obj->SetInternalField(0, v8::External::Wrap(unaligned));
1536  i::Heap::CollectAllGarbage(false);
1537  CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1538
1539  delete[] data;
1540}
1541
1542
1543THREADED_TEST(IdentityHash) {
1544  v8::HandleScope scope;
1545  LocalContext env;
1546
1547  // Ensure that the test starts with an fresh heap to test whether the hash
1548  // code is based on the address.
1549  i::Heap::CollectAllGarbage(false);
1550  Local<v8::Object> obj = v8::Object::New();
1551  int hash = obj->GetIdentityHash();
1552  int hash1 = obj->GetIdentityHash();
1553  CHECK_EQ(hash, hash1);
1554  int hash2 = v8::Object::New()->GetIdentityHash();
1555  // Since the identity hash is essentially a random number two consecutive
1556  // objects should not be assigned the same hash code. If the test below fails
1557  // the random number generator should be evaluated.
1558  CHECK_NE(hash, hash2);
1559  i::Heap::CollectAllGarbage(false);
1560  int hash3 = v8::Object::New()->GetIdentityHash();
1561  // Make sure that the identity hash is not based on the initial address of
1562  // the object alone. If the test below fails the random number generator
1563  // should be evaluated.
1564  CHECK_NE(hash, hash3);
1565  int hash4 = obj->GetIdentityHash();
1566  CHECK_EQ(hash, hash4);
1567}
1568
1569
1570THREADED_TEST(HiddenProperties) {
1571  v8::HandleScope scope;
1572  LocalContext env;
1573
1574  v8::Local<v8::Object> obj = v8::Object::New();
1575  v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1576  v8::Local<v8::String> empty = v8_str("");
1577  v8::Local<v8::String> prop_name = v8_str("prop_name");
1578
1579  i::Heap::CollectAllGarbage(false);
1580
1581  // Make sure delete of a non-existent hidden value works
1582  CHECK(obj->DeleteHiddenValue(key));
1583
1584  CHECK(obj->SetHiddenValue(key, v8::Integer::New(1503)));
1585  CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
1586  CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
1587  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1588
1589  i::Heap::CollectAllGarbage(false);
1590
1591  // Make sure we do not find the hidden property.
1592  CHECK(!obj->Has(empty));
1593  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1594  CHECK(obj->Get(empty)->IsUndefined());
1595  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1596  CHECK(obj->Set(empty, v8::Integer::New(2003)));
1597  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1598  CHECK_EQ(2003, obj->Get(empty)->Int32Value());
1599
1600  i::Heap::CollectAllGarbage(false);
1601
1602  // Add another property and delete it afterwards to force the object in
1603  // slow case.
1604  CHECK(obj->Set(prop_name, v8::Integer::New(2008)));
1605  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1606  CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
1607  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1608  CHECK(obj->Delete(prop_name));
1609  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1610
1611  i::Heap::CollectAllGarbage(false);
1612
1613  CHECK(obj->DeleteHiddenValue(key));
1614  CHECK(obj->GetHiddenValue(key).IsEmpty());
1615}
1616
1617
1618static bool interceptor_for_hidden_properties_called;
1619static v8::Handle<Value> InterceptorForHiddenProperties(
1620    Local<String> name, const AccessorInfo& info) {
1621  interceptor_for_hidden_properties_called = true;
1622  return v8::Handle<Value>();
1623}
1624
1625
1626THREADED_TEST(HiddenPropertiesWithInterceptors) {
1627  v8::HandleScope scope;
1628  LocalContext context;
1629
1630  interceptor_for_hidden_properties_called = false;
1631
1632  v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1633
1634  // Associate an interceptor with an object and start setting hidden values.
1635  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
1636  Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
1637  instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
1638  Local<v8::Function> function = fun_templ->GetFunction();
1639  Local<v8::Object> obj = function->NewInstance();
1640  CHECK(obj->SetHiddenValue(key, v8::Integer::New(2302)));
1641  CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
1642  CHECK(!interceptor_for_hidden_properties_called);
1643}
1644
1645
1646THREADED_TEST(External) {
1647  v8::HandleScope scope;
1648  int x = 3;
1649  Local<v8::External> ext = v8::External::New(&x);
1650  LocalContext env;
1651  env->Global()->Set(v8_str("ext"), ext);
1652  Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
1653  v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
1654  int* ptr = static_cast<int*>(reext->Value());
1655  CHECK_EQ(x, 3);
1656  *ptr = 10;
1657  CHECK_EQ(x, 10);
1658
1659  // Make sure unaligned pointers are wrapped properly.
1660  char* data = i::StrDup("0123456789");
1661  Local<v8::Value> zero = v8::External::Wrap(&data[0]);
1662  Local<v8::Value> one = v8::External::Wrap(&data[1]);
1663  Local<v8::Value> two = v8::External::Wrap(&data[2]);
1664  Local<v8::Value> three = v8::External::Wrap(&data[3]);
1665
1666  char* char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(zero));
1667  CHECK_EQ('0', *char_ptr);
1668  char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(one));
1669  CHECK_EQ('1', *char_ptr);
1670  char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(two));
1671  CHECK_EQ('2', *char_ptr);
1672  char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(three));
1673  CHECK_EQ('3', *char_ptr);
1674  i::DeleteArray(data);
1675}
1676
1677
1678THREADED_TEST(GlobalHandle) {
1679  v8::Persistent<String> global;
1680  {
1681    v8::HandleScope scope;
1682    Local<String> str = v8_str("str");
1683    global = v8::Persistent<String>::New(str);
1684  }
1685  CHECK_EQ(global->Length(), 3);
1686  global.Dispose();
1687}
1688
1689
1690THREADED_TEST(ScriptException) {
1691  v8::HandleScope scope;
1692  LocalContext env;
1693  Local<Script> script = Script::Compile(v8_str("throw 'panama!';"));
1694  v8::TryCatch try_catch;
1695  Local<Value> result = script->Run();
1696  CHECK(result.IsEmpty());
1697  CHECK(try_catch.HasCaught());
1698  String::AsciiValue exception_value(try_catch.Exception());
1699  CHECK_EQ(*exception_value, "panama!");
1700}
1701
1702
1703bool message_received;
1704
1705
1706static void check_message(v8::Handle<v8::Message> message,
1707                          v8::Handle<Value> data) {
1708  CHECK_EQ(5.76, data->NumberValue());
1709  CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
1710  CHECK_EQ(7.56, message->GetScriptData()->NumberValue());
1711  message_received = true;
1712}
1713
1714
1715THREADED_TEST(MessageHandlerData) {
1716  message_received = false;
1717  v8::HandleScope scope;
1718  CHECK(!message_received);
1719  v8::V8::AddMessageListener(check_message, v8_num(5.76));
1720  LocalContext context;
1721  v8::ScriptOrigin origin =
1722      v8::ScriptOrigin(v8_str("6.75"));
1723  v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
1724                                                  &origin);
1725  script->SetData(v8_str("7.56"));
1726  script->Run();
1727  CHECK(message_received);
1728  // clear out the message listener
1729  v8::V8::RemoveMessageListeners(check_message);
1730}
1731
1732
1733THREADED_TEST(GetSetProperty) {
1734  v8::HandleScope scope;
1735  LocalContext context;
1736  context->Global()->Set(v8_str("foo"), v8_num(14));
1737  context->Global()->Set(v8_str("12"), v8_num(92));
1738  context->Global()->Set(v8::Integer::New(16), v8_num(32));
1739  context->Global()->Set(v8_num(13), v8_num(56));
1740  Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run();
1741  CHECK_EQ(14, foo->Int32Value());
1742  Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run();
1743  CHECK_EQ(92, twelve->Int32Value());
1744  Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run();
1745  CHECK_EQ(32, sixteen->Int32Value());
1746  Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run();
1747  CHECK_EQ(56, thirteen->Int32Value());
1748  CHECK_EQ(92, context->Global()->Get(v8::Integer::New(12))->Int32Value());
1749  CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
1750  CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
1751  CHECK_EQ(32, context->Global()->Get(v8::Integer::New(16))->Int32Value());
1752  CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
1753  CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
1754  CHECK_EQ(56, context->Global()->Get(v8::Integer::New(13))->Int32Value());
1755  CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
1756  CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
1757}
1758
1759
1760THREADED_TEST(PropertyAttributes) {
1761  v8::HandleScope scope;
1762  LocalContext context;
1763  // read-only
1764  Local<String> prop = v8_str("read_only");
1765  context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
1766  CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
1767  Script::Compile(v8_str("read_only = 9"))->Run();
1768  CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
1769  context->Global()->Set(prop, v8_num(10));
1770  CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
1771  // dont-delete
1772  prop = v8_str("dont_delete");
1773  context->Global()->Set(prop, v8_num(13), v8::DontDelete);
1774  CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
1775  Script::Compile(v8_str("delete dont_delete"))->Run();
1776  CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
1777}
1778
1779
1780THREADED_TEST(Array) {
1781  v8::HandleScope scope;
1782  LocalContext context;
1783  Local<v8::Array> array = v8::Array::New();
1784  CHECK_EQ(0, array->Length());
1785  CHECK(array->Get(0)->IsUndefined());
1786  CHECK(!array->Has(0));
1787  CHECK(array->Get(100)->IsUndefined());
1788  CHECK(!array->Has(100));
1789  array->Set(2, v8_num(7));
1790  CHECK_EQ(3, array->Length());
1791  CHECK(!array->Has(0));
1792  CHECK(!array->Has(1));
1793  CHECK(array->Has(2));
1794  CHECK_EQ(7, array->Get(2)->Int32Value());
1795  Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
1796  Local<v8::Array> arr = obj.As<v8::Array>();
1797  CHECK_EQ(3, arr->Length());
1798  CHECK_EQ(1, arr->Get(0)->Int32Value());
1799  CHECK_EQ(2, arr->Get(1)->Int32Value());
1800  CHECK_EQ(3, arr->Get(2)->Int32Value());
1801}
1802
1803
1804v8::Handle<Value> HandleF(const v8::Arguments& args) {
1805  v8::HandleScope scope;
1806  ApiTestFuzzer::Fuzz();
1807  Local<v8::Array> result = v8::Array::New(args.Length());
1808  for (int i = 0; i < args.Length(); i++)
1809    result->Set(i, args[i]);
1810  return scope.Close(result);
1811}
1812
1813
1814THREADED_TEST(Vector) {
1815  v8::HandleScope scope;
1816  Local<ObjectTemplate> global = ObjectTemplate::New();
1817  global->Set(v8_str("f"), v8::FunctionTemplate::New(HandleF));
1818  LocalContext context(0, global);
1819
1820  const char* fun = "f()";
1821  Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
1822  CHECK_EQ(0, a0->Length());
1823
1824  const char* fun2 = "f(11)";
1825  Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
1826  CHECK_EQ(1, a1->Length());
1827  CHECK_EQ(11, a1->Get(0)->Int32Value());
1828
1829  const char* fun3 = "f(12, 13)";
1830  Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
1831  CHECK_EQ(2, a2->Length());
1832  CHECK_EQ(12, a2->Get(0)->Int32Value());
1833  CHECK_EQ(13, a2->Get(1)->Int32Value());
1834
1835  const char* fun4 = "f(14, 15, 16)";
1836  Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
1837  CHECK_EQ(3, a3->Length());
1838  CHECK_EQ(14, a3->Get(0)->Int32Value());
1839  CHECK_EQ(15, a3->Get(1)->Int32Value());
1840  CHECK_EQ(16, a3->Get(2)->Int32Value());
1841
1842  const char* fun5 = "f(17, 18, 19, 20)";
1843  Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
1844  CHECK_EQ(4, a4->Length());
1845  CHECK_EQ(17, a4->Get(0)->Int32Value());
1846  CHECK_EQ(18, a4->Get(1)->Int32Value());
1847  CHECK_EQ(19, a4->Get(2)->Int32Value());
1848  CHECK_EQ(20, a4->Get(3)->Int32Value());
1849}
1850
1851
1852THREADED_TEST(FunctionCall) {
1853  v8::HandleScope scope;
1854  LocalContext context;
1855  CompileRun(
1856    "function Foo() {"
1857    "  var result = [];"
1858    "  for (var i = 0; i < arguments.length; i++) {"
1859    "    result.push(arguments[i]);"
1860    "  }"
1861    "  return result;"
1862    "}");
1863  Local<Function> Foo =
1864      Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
1865
1866  v8::Handle<Value>* args0 = NULL;
1867  Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
1868  CHECK_EQ(0, a0->Length());
1869
1870  v8::Handle<Value> args1[] = { v8_num(1.1) };
1871  Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
1872  CHECK_EQ(1, a1->Length());
1873  CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
1874
1875  v8::Handle<Value> args2[] = { v8_num(2.2),
1876                                v8_num(3.3) };
1877  Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
1878  CHECK_EQ(2, a2->Length());
1879  CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
1880  CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
1881
1882  v8::Handle<Value> args3[] = { v8_num(4.4),
1883                                v8_num(5.5),
1884                                v8_num(6.6) };
1885  Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
1886  CHECK_EQ(3, a3->Length());
1887  CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
1888  CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
1889  CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
1890
1891  v8::Handle<Value> args4[] = { v8_num(7.7),
1892                                v8_num(8.8),
1893                                v8_num(9.9),
1894                                v8_num(10.11) };
1895  Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
1896  CHECK_EQ(4, a4->Length());
1897  CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
1898  CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
1899  CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
1900  CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
1901}
1902
1903
1904static const char* js_code_causing_out_of_memory =
1905    "var a = new Array(); while(true) a.push(a);";
1906
1907
1908// These tests run for a long time and prevent us from running tests
1909// that come after them so they cannot run in parallel.
1910TEST(OutOfMemory) {
1911  // It's not possible to read a snapshot into a heap with different dimensions.
1912  if (i::Snapshot::IsEnabled()) return;
1913  // Set heap limits.
1914  static const int K = 1024;
1915  v8::ResourceConstraints constraints;
1916  constraints.set_max_young_space_size(256 * K);
1917  constraints.set_max_old_space_size(4 * K * K);
1918  v8::SetResourceConstraints(&constraints);
1919
1920  // Execute a script that causes out of memory.
1921  v8::HandleScope scope;
1922  LocalContext context;
1923  v8::V8::IgnoreOutOfMemoryException();
1924  Local<Script> script =
1925      Script::Compile(String::New(js_code_causing_out_of_memory));
1926  Local<Value> result = script->Run();
1927
1928  // Check for out of memory state.
1929  CHECK(result.IsEmpty());
1930  CHECK(context->HasOutOfMemoryException());
1931}
1932
1933
1934v8::Handle<Value> ProvokeOutOfMemory(const v8::Arguments& args) {
1935  ApiTestFuzzer::Fuzz();
1936
1937  v8::HandleScope scope;
1938  LocalContext context;
1939  Local<Script> script =
1940      Script::Compile(String::New(js_code_causing_out_of_memory));
1941  Local<Value> result = script->Run();
1942
1943  // Check for out of memory state.
1944  CHECK(result.IsEmpty());
1945  CHECK(context->HasOutOfMemoryException());
1946
1947  return result;
1948}
1949
1950
1951TEST(OutOfMemoryNested) {
1952  // It's not possible to read a snapshot into a heap with different dimensions.
1953  if (i::Snapshot::IsEnabled()) return;
1954  // Set heap limits.
1955  static const int K = 1024;
1956  v8::ResourceConstraints constraints;
1957  constraints.set_max_young_space_size(256 * K);
1958  constraints.set_max_old_space_size(4 * K * K);
1959  v8::SetResourceConstraints(&constraints);
1960
1961  v8::HandleScope scope;
1962  Local<ObjectTemplate> templ = ObjectTemplate::New();
1963  templ->Set(v8_str("ProvokeOutOfMemory"),
1964             v8::FunctionTemplate::New(ProvokeOutOfMemory));
1965  LocalContext context(0, templ);
1966  v8::V8::IgnoreOutOfMemoryException();
1967  Local<Value> result = CompileRun(
1968    "var thrown = false;"
1969    "try {"
1970    "  ProvokeOutOfMemory();"
1971    "} catch (e) {"
1972    "  thrown = true;"
1973    "}");
1974  // Check for out of memory state.
1975  CHECK(result.IsEmpty());
1976  CHECK(context->HasOutOfMemoryException());
1977}
1978
1979
1980TEST(HugeConsStringOutOfMemory) {
1981  // It's not possible to read a snapshot into a heap with different dimensions.
1982  if (i::Snapshot::IsEnabled()) return;
1983  v8::HandleScope scope;
1984  LocalContext context;
1985  // Set heap limits.
1986  static const int K = 1024;
1987  v8::ResourceConstraints constraints;
1988  constraints.set_max_young_space_size(256 * K);
1989  constraints.set_max_old_space_size(2 * K * K);
1990  v8::SetResourceConstraints(&constraints);
1991
1992  // Execute a script that causes out of memory.
1993  v8::V8::IgnoreOutOfMemoryException();
1994
1995  // Build huge string. This should fail with out of memory exception.
1996  Local<Value> result = CompileRun(
1997    "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();"
1998    "for (var i = 0; i < 22; i++) { str = str + str; }");
1999
2000  // Check for out of memory state.
2001  CHECK(result.IsEmpty());
2002  CHECK(context->HasOutOfMemoryException());
2003}
2004
2005
2006THREADED_TEST(ConstructCall) {
2007  v8::HandleScope scope;
2008  LocalContext context;
2009  CompileRun(
2010    "function Foo() {"
2011    "  var result = [];"
2012    "  for (var i = 0; i < arguments.length; i++) {"
2013    "    result.push(arguments[i]);"
2014    "  }"
2015    "  return result;"
2016    "}");
2017  Local<Function> Foo =
2018      Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
2019
2020  v8::Handle<Value>* args0 = NULL;
2021  Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
2022  CHECK_EQ(0, a0->Length());
2023
2024  v8::Handle<Value> args1[] = { v8_num(1.1) };
2025  Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
2026  CHECK_EQ(1, a1->Length());
2027  CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
2028
2029  v8::Handle<Value> args2[] = { v8_num(2.2),
2030                                v8_num(3.3) };
2031  Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
2032  CHECK_EQ(2, a2->Length());
2033  CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
2034  CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
2035
2036  v8::Handle<Value> args3[] = { v8_num(4.4),
2037                                v8_num(5.5),
2038                                v8_num(6.6) };
2039  Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
2040  CHECK_EQ(3, a3->Length());
2041  CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
2042  CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
2043  CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
2044
2045  v8::Handle<Value> args4[] = { v8_num(7.7),
2046                                v8_num(8.8),
2047                                v8_num(9.9),
2048                                v8_num(10.11) };
2049  Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
2050  CHECK_EQ(4, a4->Length());
2051  CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
2052  CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
2053  CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
2054  CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
2055}
2056
2057
2058static void CheckUncle(v8::TryCatch* try_catch) {
2059  CHECK(try_catch->HasCaught());
2060  String::AsciiValue str_value(try_catch->Exception());
2061  CHECK_EQ(*str_value, "uncle?");
2062  try_catch->Reset();
2063}
2064
2065
2066THREADED_TEST(ConversionNumber) {
2067  v8::HandleScope scope;
2068  LocalContext env;
2069  // Very large number.
2070  CompileRun("var obj = Math.pow(2,32) * 1237;");
2071  Local<Value> obj = env->Global()->Get(v8_str("obj"));
2072  CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
2073  CHECK_EQ(0, obj->ToInt32()->Value());
2074  CHECK(0u == obj->ToUint32()->Value());  // NOLINT - no CHECK_EQ for unsigned.
2075  // Large number.
2076  CompileRun("var obj = -1234567890123;");
2077  obj = env->Global()->Get(v8_str("obj"));
2078  CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
2079  CHECK_EQ(-1912276171, obj->ToInt32()->Value());
2080  CHECK(2382691125u == obj->ToUint32()->Value());  // NOLINT
2081  // Small positive integer.
2082  CompileRun("var obj = 42;");
2083  obj = env->Global()->Get(v8_str("obj"));
2084  CHECK_EQ(42.0, obj->ToNumber()->Value());
2085  CHECK_EQ(42, obj->ToInt32()->Value());
2086  CHECK(42u == obj->ToUint32()->Value());  // NOLINT
2087  // Negative integer.
2088  CompileRun("var obj = -37;");
2089  obj = env->Global()->Get(v8_str("obj"));
2090  CHECK_EQ(-37.0, obj->ToNumber()->Value());
2091  CHECK_EQ(-37, obj->ToInt32()->Value());
2092  CHECK(4294967259u == obj->ToUint32()->Value());  // NOLINT
2093  // Positive non-int32 integer.
2094  CompileRun("var obj = 0x81234567;");
2095  obj = env->Global()->Get(v8_str("obj"));
2096  CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
2097  CHECK_EQ(-2128394905, obj->ToInt32()->Value());
2098  CHECK(2166572391u == obj->ToUint32()->Value());  // NOLINT
2099  // Fraction.
2100  CompileRun("var obj = 42.3;");
2101  obj = env->Global()->Get(v8_str("obj"));
2102  CHECK_EQ(42.3, obj->ToNumber()->Value());
2103  CHECK_EQ(42, obj->ToInt32()->Value());
2104  CHECK(42u == obj->ToUint32()->Value());  // NOLINT
2105  // Large negative fraction.
2106  CompileRun("var obj = -5726623061.75;");
2107  obj = env->Global()->Get(v8_str("obj"));
2108  CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
2109  CHECK_EQ(-1431655765, obj->ToInt32()->Value());
2110  CHECK(2863311531u == obj->ToUint32()->Value());  // NOLINT
2111}
2112
2113
2114THREADED_TEST(isNumberType) {
2115  v8::HandleScope scope;
2116  LocalContext env;
2117  // Very large number.
2118  CompileRun("var obj = Math.pow(2,32) * 1237;");
2119  Local<Value> obj = env->Global()->Get(v8_str("obj"));
2120  CHECK(!obj->IsInt32());
2121  CHECK(!obj->IsUint32());
2122  // Large negative number.
2123  CompileRun("var obj = -1234567890123;");
2124  obj = env->Global()->Get(v8_str("obj"));
2125  CHECK(!obj->IsInt32());
2126  CHECK(!obj->IsUint32());
2127  // Small positive integer.
2128  CompileRun("var obj = 42;");
2129  obj = env->Global()->Get(v8_str("obj"));
2130  CHECK(obj->IsInt32());
2131  CHECK(obj->IsUint32());
2132  // Negative integer.
2133  CompileRun("var obj = -37;");
2134  obj = env->Global()->Get(v8_str("obj"));
2135  CHECK(obj->IsInt32());
2136  CHECK(!obj->IsUint32());
2137  // Positive non-int32 integer.
2138  CompileRun("var obj = 0x81234567;");
2139  obj = env->Global()->Get(v8_str("obj"));
2140  CHECK(!obj->IsInt32());
2141  CHECK(obj->IsUint32());
2142  // Fraction.
2143  CompileRun("var obj = 42.3;");
2144  obj = env->Global()->Get(v8_str("obj"));
2145  CHECK(!obj->IsInt32());
2146  CHECK(!obj->IsUint32());
2147  // Large negative fraction.
2148  CompileRun("var obj = -5726623061.75;");
2149  obj = env->Global()->Get(v8_str("obj"));
2150  CHECK(!obj->IsInt32());
2151  CHECK(!obj->IsUint32());
2152}
2153
2154
2155THREADED_TEST(ConversionException) {
2156  v8::HandleScope scope;
2157  LocalContext env;
2158  CompileRun(
2159    "function TestClass() { };"
2160    "TestClass.prototype.toString = function () { throw 'uncle?'; };"
2161    "var obj = new TestClass();");
2162  Local<Value> obj = env->Global()->Get(v8_str("obj"));
2163
2164  v8::TryCatch try_catch;
2165
2166  Local<Value> to_string_result = obj->ToString();
2167  CHECK(to_string_result.IsEmpty());
2168  CheckUncle(&try_catch);
2169
2170  Local<Value> to_number_result = obj->ToNumber();
2171  CHECK(to_number_result.IsEmpty());
2172  CheckUncle(&try_catch);
2173
2174  Local<Value> to_integer_result = obj->ToInteger();
2175  CHECK(to_integer_result.IsEmpty());
2176  CheckUncle(&try_catch);
2177
2178  Local<Value> to_uint32_result = obj->ToUint32();
2179  CHECK(to_uint32_result.IsEmpty());
2180  CheckUncle(&try_catch);
2181
2182  Local<Value> to_int32_result = obj->ToInt32();
2183  CHECK(to_int32_result.IsEmpty());
2184  CheckUncle(&try_catch);
2185
2186  Local<Value> to_object_result = v8::Undefined()->ToObject();
2187  CHECK(to_object_result.IsEmpty());
2188  CHECK(try_catch.HasCaught());
2189  try_catch.Reset();
2190
2191  int32_t int32_value = obj->Int32Value();
2192  CHECK_EQ(0, int32_value);
2193  CheckUncle(&try_catch);
2194
2195  uint32_t uint32_value = obj->Uint32Value();
2196  CHECK_EQ(0, uint32_value);
2197  CheckUncle(&try_catch);
2198
2199  double number_value = obj->NumberValue();
2200  CHECK_NE(0, IsNaN(number_value));
2201  CheckUncle(&try_catch);
2202
2203  int64_t integer_value = obj->IntegerValue();
2204  CHECK_EQ(0.0, static_cast<double>(integer_value));
2205  CheckUncle(&try_catch);
2206}
2207
2208
2209v8::Handle<Value> ThrowFromC(const v8::Arguments& args) {
2210  ApiTestFuzzer::Fuzz();
2211  return v8::ThrowException(v8_str("konto"));
2212}
2213
2214
2215v8::Handle<Value> CCatcher(const v8::Arguments& args) {
2216  if (args.Length() < 1) return v8::Boolean::New(false);
2217  v8::HandleScope scope;
2218  v8::TryCatch try_catch;
2219  Local<Value> result = v8::Script::Compile(args[0]->ToString())->Run();
2220  CHECK(!try_catch.HasCaught() || result.IsEmpty());
2221  return v8::Boolean::New(try_catch.HasCaught());
2222}
2223
2224
2225THREADED_TEST(APICatch) {
2226  v8::HandleScope scope;
2227  Local<ObjectTemplate> templ = ObjectTemplate::New();
2228  templ->Set(v8_str("ThrowFromC"),
2229             v8::FunctionTemplate::New(ThrowFromC));
2230  LocalContext context(0, templ);
2231  CompileRun(
2232    "var thrown = false;"
2233    "try {"
2234    "  ThrowFromC();"
2235    "} catch (e) {"
2236    "  thrown = true;"
2237    "}");
2238  Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
2239  CHECK(thrown->BooleanValue());
2240}
2241
2242
2243THREADED_TEST(APIThrowTryCatch) {
2244  v8::HandleScope scope;
2245  Local<ObjectTemplate> templ = ObjectTemplate::New();
2246  templ->Set(v8_str("ThrowFromC"),
2247             v8::FunctionTemplate::New(ThrowFromC));
2248  LocalContext context(0, templ);
2249  v8::TryCatch try_catch;
2250  CompileRun("ThrowFromC();");
2251  CHECK(try_catch.HasCaught());
2252}
2253
2254
2255// Test that a try-finally block doesn't shadow a try-catch block
2256// when setting up an external handler.
2257//
2258// BUG(271): Some of the exception propagation does not work on the
2259// ARM simulator because the simulator separates the C++ stack and the
2260// JS stack.  This test therefore fails on the simulator.  The test is
2261// not threaded to allow the threading tests to run on the simulator.
2262TEST(TryCatchInTryFinally) {
2263  v8::HandleScope scope;
2264  Local<ObjectTemplate> templ = ObjectTemplate::New();
2265  templ->Set(v8_str("CCatcher"),
2266             v8::FunctionTemplate::New(CCatcher));
2267  LocalContext context(0, templ);
2268  Local<Value> result = CompileRun("try {"
2269                                   "  try {"
2270                                   "    CCatcher('throw 7;');"
2271                                   "  } finally {"
2272                                   "  }"
2273                                   "} catch (e) {"
2274                                   "}");
2275  CHECK(result->IsTrue());
2276}
2277
2278
2279static void receive_message(v8::Handle<v8::Message> message,
2280                            v8::Handle<v8::Value> data) {
2281  message->Get();
2282  message_received = true;
2283}
2284
2285
2286TEST(APIThrowMessage) {
2287  message_received = false;
2288  v8::HandleScope scope;
2289  v8::V8::AddMessageListener(receive_message);
2290  Local<ObjectTemplate> templ = ObjectTemplate::New();
2291  templ->Set(v8_str("ThrowFromC"),
2292             v8::FunctionTemplate::New(ThrowFromC));
2293  LocalContext context(0, templ);
2294  CompileRun("ThrowFromC();");
2295  CHECK(message_received);
2296  v8::V8::RemoveMessageListeners(check_message);
2297}
2298
2299
2300TEST(APIThrowMessageAndVerboseTryCatch) {
2301  message_received = false;
2302  v8::HandleScope scope;
2303  v8::V8::AddMessageListener(receive_message);
2304  Local<ObjectTemplate> templ = ObjectTemplate::New();
2305  templ->Set(v8_str("ThrowFromC"),
2306             v8::FunctionTemplate::New(ThrowFromC));
2307  LocalContext context(0, templ);
2308  v8::TryCatch try_catch;
2309  try_catch.SetVerbose(true);
2310  Local<Value> result = CompileRun("ThrowFromC();");
2311  CHECK(try_catch.HasCaught());
2312  CHECK(result.IsEmpty());
2313  CHECK(message_received);
2314  v8::V8::RemoveMessageListeners(check_message);
2315}
2316
2317
2318THREADED_TEST(ExternalScriptException) {
2319  v8::HandleScope scope;
2320  Local<ObjectTemplate> templ = ObjectTemplate::New();
2321  templ->Set(v8_str("ThrowFromC"),
2322             v8::FunctionTemplate::New(ThrowFromC));
2323  LocalContext context(0, templ);
2324
2325  v8::TryCatch try_catch;
2326  Local<Script> script
2327      = Script::Compile(v8_str("ThrowFromC(); throw 'panama';"));
2328  Local<Value> result = script->Run();
2329  CHECK(result.IsEmpty());
2330  CHECK(try_catch.HasCaught());
2331  String::AsciiValue exception_value(try_catch.Exception());
2332  CHECK_EQ("konto", *exception_value);
2333}
2334
2335
2336
2337v8::Handle<Value> CThrowCountDown(const v8::Arguments& args) {
2338  ApiTestFuzzer::Fuzz();
2339  CHECK_EQ(4, args.Length());
2340  int count = args[0]->Int32Value();
2341  int cInterval = args[2]->Int32Value();
2342  if (count == 0) {
2343    return v8::ThrowException(v8_str("FromC"));
2344  } else {
2345    Local<v8::Object> global = Context::GetCurrent()->Global();
2346    Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
2347    v8::Handle<Value> argv[] = { v8_num(count - 1),
2348                                 args[1],
2349                                 args[2],
2350                                 args[3] };
2351    if (count % cInterval == 0) {
2352      v8::TryCatch try_catch;
2353      Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
2354      int expected = args[3]->Int32Value();
2355      if (try_catch.HasCaught()) {
2356        CHECK_EQ(expected, count);
2357        CHECK(result.IsEmpty());
2358        CHECK(!i::Top::has_scheduled_exception());
2359      } else {
2360        CHECK_NE(expected, count);
2361      }
2362      return result;
2363    } else {
2364      return fun.As<Function>()->Call(global, 4, argv);
2365    }
2366  }
2367}
2368
2369
2370v8::Handle<Value> JSCheck(const v8::Arguments& args) {
2371  ApiTestFuzzer::Fuzz();
2372  CHECK_EQ(3, args.Length());
2373  bool equality = args[0]->BooleanValue();
2374  int count = args[1]->Int32Value();
2375  int expected = args[2]->Int32Value();
2376  if (equality) {
2377    CHECK_EQ(count, expected);
2378  } else {
2379    CHECK_NE(count, expected);
2380  }
2381  return v8::Undefined();
2382}
2383
2384
2385THREADED_TEST(EvalInTryFinally) {
2386  v8::HandleScope scope;
2387  LocalContext context;
2388  v8::TryCatch try_catch;
2389  CompileRun("(function() {"
2390             "  try {"
2391             "    eval('asldkf (*&^&*^');"
2392             "  } finally {"
2393             "    return;"
2394             "  }"
2395             "})()");
2396  CHECK(!try_catch.HasCaught());
2397}
2398
2399
2400// This test works by making a stack of alternating JavaScript and C
2401// activations.  These activations set up exception handlers with regular
2402// intervals, one interval for C activations and another for JavaScript
2403// activations.  When enough activations have been created an exception is
2404// thrown and we check that the right activation catches the exception and that
2405// no other activations do.  The right activation is always the topmost one with
2406// a handler, regardless of whether it is in JavaScript or C.
2407//
2408// The notation used to describe a test case looks like this:
2409//
2410//    *JS[4] *C[3] @JS[2] C[1] JS[0]
2411//
2412// Each entry is an activation, either JS or C.  The index is the count at that
2413// level.  Stars identify activations with exception handlers, the @ identifies
2414// the exception handler that should catch the exception.
2415//
2416// BUG(271): Some of the exception propagation does not work on the
2417// ARM simulator because the simulator separates the C++ stack and the
2418// JS stack.  This test therefore fails on the simulator.  The test is
2419// not threaded to allow the threading tests to run on the simulator.
2420TEST(ExceptionOrder) {
2421  v8::HandleScope scope;
2422  Local<ObjectTemplate> templ = ObjectTemplate::New();
2423  templ->Set(v8_str("check"), v8::FunctionTemplate::New(JSCheck));
2424  templ->Set(v8_str("CThrowCountDown"),
2425             v8::FunctionTemplate::New(CThrowCountDown));
2426  LocalContext context(0, templ);
2427  CompileRun(
2428    "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
2429    "  if (count == 0) throw 'FromJS';"
2430    "  if (count % jsInterval == 0) {"
2431    "    try {"
2432    "      var value = CThrowCountDown(count - 1,"
2433    "                                  jsInterval,"
2434    "                                  cInterval,"
2435    "                                  expected);"
2436    "      check(false, count, expected);"
2437    "      return value;"
2438    "    } catch (e) {"
2439    "      check(true, count, expected);"
2440    "    }"
2441    "  } else {"
2442    "    return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
2443    "  }"
2444    "}");
2445  Local<Function> fun =
2446      Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
2447
2448  const int argc = 4;
2449  //                             count      jsInterval cInterval  expected
2450
2451  // *JS[4] *C[3] @JS[2] C[1] JS[0]
2452  v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
2453  fun->Call(fun, argc, a0);
2454
2455  // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
2456  v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
2457  fun->Call(fun, argc, a1);
2458
2459  // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
2460  v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
2461  fun->Call(fun, argc, a2);
2462
2463  // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
2464  v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
2465  fun->Call(fun, argc, a3);
2466
2467  // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
2468  v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
2469  fun->Call(fun, argc, a4);
2470
2471  // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
2472  v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
2473  fun->Call(fun, argc, a5);
2474}
2475
2476
2477v8::Handle<Value> ThrowValue(const v8::Arguments& args) {
2478  ApiTestFuzzer::Fuzz();
2479  CHECK_EQ(1, args.Length());
2480  return v8::ThrowException(args[0]);
2481}
2482
2483
2484THREADED_TEST(ThrowValues) {
2485  v8::HandleScope scope;
2486  Local<ObjectTemplate> templ = ObjectTemplate::New();
2487  templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(ThrowValue));
2488  LocalContext context(0, templ);
2489  v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
2490    "function Run(obj) {"
2491    "  try {"
2492    "    Throw(obj);"
2493    "  } catch (e) {"
2494    "    return e;"
2495    "  }"
2496    "  return 'no exception';"
2497    "}"
2498    "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
2499  CHECK_EQ(5, result->Length());
2500  CHECK(result->Get(v8::Integer::New(0))->IsString());
2501  CHECK(result->Get(v8::Integer::New(1))->IsNumber());
2502  CHECK_EQ(1, result->Get(v8::Integer::New(1))->Int32Value());
2503  CHECK(result->Get(v8::Integer::New(2))->IsNumber());
2504  CHECK_EQ(0, result->Get(v8::Integer::New(2))->Int32Value());
2505  CHECK(result->Get(v8::Integer::New(3))->IsNull());
2506  CHECK(result->Get(v8::Integer::New(4))->IsUndefined());
2507}
2508
2509
2510THREADED_TEST(CatchZero) {
2511  v8::HandleScope scope;
2512  LocalContext context;
2513  v8::TryCatch try_catch;
2514  CHECK(!try_catch.HasCaught());
2515  Script::Compile(v8_str("throw 10"))->Run();
2516  CHECK(try_catch.HasCaught());
2517  CHECK_EQ(10, try_catch.Exception()->Int32Value());
2518  try_catch.Reset();
2519  CHECK(!try_catch.HasCaught());
2520  Script::Compile(v8_str("throw 0"))->Run();
2521  CHECK(try_catch.HasCaught());
2522  CHECK_EQ(0, try_catch.Exception()->Int32Value());
2523}
2524
2525
2526THREADED_TEST(CatchExceptionFromWith) {
2527  v8::HandleScope scope;
2528  LocalContext context;
2529  v8::TryCatch try_catch;
2530  CHECK(!try_catch.HasCaught());
2531  Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run();
2532  CHECK(try_catch.HasCaught());
2533}
2534
2535
2536THREADED_TEST(Equality) {
2537  v8::HandleScope scope;
2538  LocalContext context;
2539  // Check that equality works at all before relying on CHECK_EQ
2540  CHECK(v8_str("a")->Equals(v8_str("a")));
2541  CHECK(!v8_str("a")->Equals(v8_str("b")));
2542
2543  CHECK_EQ(v8_str("a"), v8_str("a"));
2544  CHECK_NE(v8_str("a"), v8_str("b"));
2545  CHECK_EQ(v8_num(1), v8_num(1));
2546  CHECK_EQ(v8_num(1.00), v8_num(1));
2547  CHECK_NE(v8_num(1), v8_num(2));
2548
2549  // Assume String is not symbol.
2550  CHECK(v8_str("a")->StrictEquals(v8_str("a")));
2551  CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
2552  CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
2553  CHECK(v8_num(1)->StrictEquals(v8_num(1)));
2554  CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
2555  CHECK(v8_num(0)->StrictEquals(v8_num(-0)));
2556  Local<Value> not_a_number = v8_num(i::OS::nan_value());
2557  CHECK(!not_a_number->StrictEquals(not_a_number));
2558  CHECK(v8::False()->StrictEquals(v8::False()));
2559  CHECK(!v8::False()->StrictEquals(v8::Undefined()));
2560
2561  v8::Handle<v8::Object> obj = v8::Object::New();
2562  v8::Persistent<v8::Object> alias = v8::Persistent<v8::Object>::New(obj);
2563  CHECK(alias->StrictEquals(obj));
2564  alias.Dispose();
2565}
2566
2567
2568THREADED_TEST(MultiRun) {
2569  v8::HandleScope scope;
2570  LocalContext context;
2571  Local<Script> script = Script::Compile(v8_str("x"));
2572  for (int i = 0; i < 10; i++)
2573    script->Run();
2574}
2575
2576
2577static v8::Handle<Value> GetXValue(Local<String> name,
2578                                   const AccessorInfo& info) {
2579  ApiTestFuzzer::Fuzz();
2580  CHECK_EQ(info.Data(), v8_str("donut"));
2581  CHECK_EQ(name, v8_str("x"));
2582  return name;
2583}
2584
2585
2586THREADED_TEST(SimplePropertyRead) {
2587  v8::HandleScope scope;
2588  Local<ObjectTemplate> templ = ObjectTemplate::New();
2589  templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
2590  LocalContext context;
2591  context->Global()->Set(v8_str("obj"), templ->NewInstance());
2592  Local<Script> script = Script::Compile(v8_str("obj.x"));
2593  for (int i = 0; i < 10; i++) {
2594    Local<Value> result = script->Run();
2595    CHECK_EQ(result, v8_str("x"));
2596  }
2597}
2598
2599THREADED_TEST(DefinePropertyOnAPIAccessor) {
2600  v8::HandleScope scope;
2601  Local<ObjectTemplate> templ = ObjectTemplate::New();
2602  templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
2603  LocalContext context;
2604  context->Global()->Set(v8_str("obj"), templ->NewInstance());
2605
2606  // Uses getOwnPropertyDescriptor to check the configurable status
2607  Local<Script> script_desc
2608    = Script::Compile(v8_str("var prop = Object.getOwnPropertyDescriptor( "
2609                             "obj, 'x');"
2610                             "prop.configurable;"));
2611  Local<Value> result = script_desc->Run();
2612  CHECK_EQ(result->BooleanValue(), true);
2613
2614  // Redefine get - but still configurable
2615  Local<Script> script_define
2616    = Script::Compile(v8_str("var desc = { get: function(){return 42; },"
2617                             "            configurable: true };"
2618                             "Object.defineProperty(obj, 'x', desc);"
2619                             "obj.x"));
2620  result = script_define->Run();
2621  CHECK_EQ(result, v8_num(42));
2622
2623  // Check that the accessor is still configurable
2624  result = script_desc->Run();
2625  CHECK_EQ(result->BooleanValue(), true);
2626
2627  // Redefine to a non-configurable
2628  script_define
2629    = Script::Compile(v8_str("var desc = { get: function(){return 43; },"
2630                             "             configurable: false };"
2631                             "Object.defineProperty(obj, 'x', desc);"
2632                             "obj.x"));
2633  result = script_define->Run();
2634  CHECK_EQ(result, v8_num(43));
2635  result = script_desc->Run();
2636  CHECK_EQ(result->BooleanValue(), false);
2637
2638  // Make sure that it is not possible to redefine again
2639  v8::TryCatch try_catch;
2640  result = script_define->Run();
2641  CHECK(try_catch.HasCaught());
2642  String::AsciiValue exception_value(try_catch.Exception());
2643  CHECK_EQ(*exception_value,
2644           "TypeError: Cannot redefine property: defineProperty");
2645}
2646
2647THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
2648  v8::HandleScope scope;
2649  Local<ObjectTemplate> templ = ObjectTemplate::New();
2650  templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
2651  LocalContext context;
2652  context->Global()->Set(v8_str("obj"), templ->NewInstance());
2653
2654  Local<Script> script_desc = Script::Compile(v8_str("var prop ="
2655                                    "Object.getOwnPropertyDescriptor( "
2656                                    "obj, 'x');"
2657                                    "prop.configurable;"));
2658  Local<Value> result = script_desc->Run();
2659  CHECK_EQ(result->BooleanValue(), true);
2660
2661  Local<Script> script_define =
2662    Script::Compile(v8_str("var desc = {get: function(){return 42; },"
2663                           "            configurable: true };"
2664                           "Object.defineProperty(obj, 'x', desc);"
2665                           "obj.x"));
2666  result = script_define->Run();
2667  CHECK_EQ(result, v8_num(42));
2668
2669
2670  result = script_desc->Run();
2671  CHECK_EQ(result->BooleanValue(), true);
2672
2673
2674  script_define =
2675    Script::Compile(v8_str("var desc = {get: function(){return 43; },"
2676                           "            configurable: false };"
2677                           "Object.defineProperty(obj, 'x', desc);"
2678                           "obj.x"));
2679  result = script_define->Run();
2680  CHECK_EQ(result, v8_num(43));
2681  result = script_desc->Run();
2682
2683  CHECK_EQ(result->BooleanValue(), false);
2684
2685  v8::TryCatch try_catch;
2686  result = script_define->Run();
2687  CHECK(try_catch.HasCaught());
2688  String::AsciiValue exception_value(try_catch.Exception());
2689  CHECK_EQ(*exception_value,
2690           "TypeError: Cannot redefine property: defineProperty");
2691}
2692
2693
2694static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
2695                                                char const* name) {
2696  return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
2697}
2698
2699
2700THREADED_TEST(DefineAPIAccessorOnObject) {
2701  v8::HandleScope scope;
2702  Local<ObjectTemplate> templ = ObjectTemplate::New();
2703  LocalContext context;
2704
2705  context->Global()->Set(v8_str("obj1"), templ->NewInstance());
2706  CompileRun("var obj2 = {};");
2707
2708  CHECK(CompileRun("obj1.x")->IsUndefined());
2709  CHECK(CompileRun("obj2.x")->IsUndefined());
2710
2711  CHECK(GetGlobalProperty(&context, "obj1")->
2712      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2713
2714  ExpectString("obj1.x", "x");
2715  CHECK(CompileRun("obj2.x")->IsUndefined());
2716
2717  CHECK(GetGlobalProperty(&context, "obj2")->
2718      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2719
2720  ExpectString("obj1.x", "x");
2721  ExpectString("obj2.x", "x");
2722
2723  ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
2724  ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
2725
2726  CompileRun("Object.defineProperty(obj1, 'x',"
2727             "{ get: function() { return 'y'; }, configurable: true })");
2728
2729  ExpectString("obj1.x", "y");
2730  ExpectString("obj2.x", "x");
2731
2732  CompileRun("Object.defineProperty(obj2, 'x',"
2733             "{ get: function() { return 'y'; }, configurable: true })");
2734
2735  ExpectString("obj1.x", "y");
2736  ExpectString("obj2.x", "y");
2737
2738  ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
2739  ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
2740
2741  CHECK(GetGlobalProperty(&context, "obj1")->
2742      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2743  CHECK(GetGlobalProperty(&context, "obj2")->
2744      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2745
2746  ExpectString("obj1.x", "x");
2747  ExpectString("obj2.x", "x");
2748
2749  ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
2750  ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
2751
2752  // Define getters/setters, but now make them not configurable.
2753  CompileRun("Object.defineProperty(obj1, 'x',"
2754             "{ get: function() { return 'z'; }, configurable: false })");
2755  CompileRun("Object.defineProperty(obj2, 'x',"
2756             "{ get: function() { return 'z'; }, configurable: false })");
2757
2758  ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
2759  ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
2760
2761  ExpectString("obj1.x", "z");
2762  ExpectString("obj2.x", "z");
2763
2764  CHECK(!GetGlobalProperty(&context, "obj1")->
2765      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2766  CHECK(!GetGlobalProperty(&context, "obj2")->
2767      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2768
2769  ExpectString("obj1.x", "z");
2770  ExpectString("obj2.x", "z");
2771}
2772
2773
2774THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
2775  v8::HandleScope scope;
2776  Local<ObjectTemplate> templ = ObjectTemplate::New();
2777  LocalContext context;
2778
2779  context->Global()->Set(v8_str("obj1"), templ->NewInstance());
2780  CompileRun("var obj2 = {};");
2781
2782  CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
2783        v8_str("x"),
2784        GetXValue, NULL,
2785        v8_str("donut"), v8::DEFAULT, v8::DontDelete));
2786  CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
2787        v8_str("x"),
2788        GetXValue, NULL,
2789        v8_str("donut"), v8::DEFAULT, v8::DontDelete));
2790
2791  ExpectString("obj1.x", "x");
2792  ExpectString("obj2.x", "x");
2793
2794  ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
2795  ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
2796
2797  CHECK(!GetGlobalProperty(&context, "obj1")->
2798      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2799  CHECK(!GetGlobalProperty(&context, "obj2")->
2800      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2801
2802  {
2803    v8::TryCatch try_catch;
2804    CompileRun("Object.defineProperty(obj1, 'x',"
2805        "{get: function() { return 'func'; }})");
2806    CHECK(try_catch.HasCaught());
2807    String::AsciiValue exception_value(try_catch.Exception());
2808    CHECK_EQ(*exception_value,
2809            "TypeError: Cannot redefine property: defineProperty");
2810  }
2811  {
2812    v8::TryCatch try_catch;
2813    CompileRun("Object.defineProperty(obj2, 'x',"
2814        "{get: function() { return 'func'; }})");
2815    CHECK(try_catch.HasCaught());
2816    String::AsciiValue exception_value(try_catch.Exception());
2817    CHECK_EQ(*exception_value,
2818            "TypeError: Cannot redefine property: defineProperty");
2819  }
2820}
2821
2822
2823static v8::Handle<Value> Get239Value(Local<String> name,
2824                                     const AccessorInfo& info) {
2825  ApiTestFuzzer::Fuzz();
2826  CHECK_EQ(info.Data(), v8_str("donut"));
2827  CHECK_EQ(name, v8_str("239"));
2828  return name;
2829}
2830
2831
2832THREADED_TEST(ElementAPIAccessor) {
2833  v8::HandleScope scope;
2834  Local<ObjectTemplate> templ = ObjectTemplate::New();
2835  LocalContext context;
2836
2837  context->Global()->Set(v8_str("obj1"), templ->NewInstance());
2838  CompileRun("var obj2 = {};");
2839
2840  CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
2841        v8_str("239"),
2842        Get239Value, NULL,
2843        v8_str("donut")));
2844  CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
2845        v8_str("239"),
2846        Get239Value, NULL,
2847        v8_str("donut")));
2848
2849  ExpectString("obj1[239]", "239");
2850  ExpectString("obj2[239]", "239");
2851  ExpectString("obj1['239']", "239");
2852  ExpectString("obj2['239']", "239");
2853}
2854
2855
2856v8::Persistent<Value> xValue;
2857
2858
2859static void SetXValue(Local<String> name,
2860                      Local<Value> value,
2861                      const AccessorInfo& info) {
2862  CHECK_EQ(value, v8_num(4));
2863  CHECK_EQ(info.Data(), v8_str("donut"));
2864  CHECK_EQ(name, v8_str("x"));
2865  CHECK(xValue.IsEmpty());
2866  xValue = v8::Persistent<Value>::New(value);
2867}
2868
2869
2870THREADED_TEST(SimplePropertyWrite) {
2871  v8::HandleScope scope;
2872  Local<ObjectTemplate> templ = ObjectTemplate::New();
2873  templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
2874  LocalContext context;
2875  context->Global()->Set(v8_str("obj"), templ->NewInstance());
2876  Local<Script> script = Script::Compile(v8_str("obj.x = 4"));
2877  for (int i = 0; i < 10; i++) {
2878    CHECK(xValue.IsEmpty());
2879    script->Run();
2880    CHECK_EQ(v8_num(4), xValue);
2881    xValue.Dispose();
2882    xValue = v8::Persistent<Value>();
2883  }
2884}
2885
2886
2887static v8::Handle<Value> XPropertyGetter(Local<String> property,
2888                                         const AccessorInfo& info) {
2889  ApiTestFuzzer::Fuzz();
2890  CHECK(info.Data()->IsUndefined());
2891  return property;
2892}
2893
2894
2895THREADED_TEST(NamedInterceptorPropertyRead) {
2896  v8::HandleScope scope;
2897  Local<ObjectTemplate> templ = ObjectTemplate::New();
2898  templ->SetNamedPropertyHandler(XPropertyGetter);
2899  LocalContext context;
2900  context->Global()->Set(v8_str("obj"), templ->NewInstance());
2901  Local<Script> script = Script::Compile(v8_str("obj.x"));
2902  for (int i = 0; i < 10; i++) {
2903    Local<Value> result = script->Run();
2904    CHECK_EQ(result, v8_str("x"));
2905  }
2906}
2907
2908
2909THREADED_TEST(NamedInterceptorDictionaryIC) {
2910  v8::HandleScope scope;
2911  Local<ObjectTemplate> templ = ObjectTemplate::New();
2912  templ->SetNamedPropertyHandler(XPropertyGetter);
2913  LocalContext context;
2914  // Create an object with a named interceptor.
2915  context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
2916  Local<Script> script = Script::Compile(v8_str("interceptor_obj.x"));
2917  for (int i = 0; i < 10; i++) {
2918    Local<Value> result = script->Run();
2919    CHECK_EQ(result, v8_str("x"));
2920  }
2921  // Create a slow case object and a function accessing a property in
2922  // that slow case object (with dictionary probing in generated
2923  // code). Then force object with a named interceptor into slow-case,
2924  // pass it to the function, and check that the interceptor is called
2925  // instead of accessing the local property.
2926  Local<Value> result =
2927      CompileRun("function get_x(o) { return o.x; };"
2928                 "var obj = { x : 42, y : 0 };"
2929                 "delete obj.y;"
2930                 "for (var i = 0; i < 10; i++) get_x(obj);"
2931                 "interceptor_obj.x = 42;"
2932                 "interceptor_obj.y = 10;"
2933                 "delete interceptor_obj.y;"
2934                 "get_x(interceptor_obj)");
2935  CHECK_EQ(result, v8_str("x"));
2936}
2937
2938
2939static v8::Handle<Value> SetXOnPrototypeGetter(Local<String> property,
2940                                               const AccessorInfo& info) {
2941  // Set x on the prototype object and do not handle the get request.
2942  v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
2943  proto.As<v8::Object>()->Set(v8_str("x"), v8::Integer::New(23));
2944  return v8::Handle<Value>();
2945}
2946
2947
2948// This is a regression test for http://crbug.com/20104. Map
2949// transitions should not interfere with post interceptor lookup.
2950THREADED_TEST(NamedInterceptorMapTransitionRead) {
2951  v8::HandleScope scope;
2952  Local<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New();
2953  Local<v8::ObjectTemplate> instance_template
2954      = function_template->InstanceTemplate();
2955  instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
2956  LocalContext context;
2957  context->Global()->Set(v8_str("F"), function_template->GetFunction());
2958  // Create an instance of F and introduce a map transition for x.
2959  CompileRun("var o = new F(); o.x = 23;");
2960  // Create an instance of F and invoke the getter. The result should be 23.
2961  Local<Value> result = CompileRun("o = new F(); o.x");
2962  CHECK_EQ(result->Int32Value(), 23);
2963}
2964
2965
2966static v8::Handle<Value> IndexedPropertyGetter(uint32_t index,
2967                                               const AccessorInfo& info) {
2968  ApiTestFuzzer::Fuzz();
2969  if (index == 37) {
2970    return v8::Handle<Value>(v8_num(625));
2971  }
2972  return v8::Handle<Value>();
2973}
2974
2975
2976static v8::Handle<Value> IndexedPropertySetter(uint32_t index,
2977                                               Local<Value> value,
2978                                               const AccessorInfo& info) {
2979  ApiTestFuzzer::Fuzz();
2980  if (index == 39) {
2981    return value;
2982  }
2983  return v8::Handle<Value>();
2984}
2985
2986
2987THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
2988  v8::HandleScope scope;
2989  Local<ObjectTemplate> templ = ObjectTemplate::New();
2990  templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
2991                                   IndexedPropertySetter);
2992  LocalContext context;
2993  context->Global()->Set(v8_str("obj"), templ->NewInstance());
2994  Local<Script> getter_script = Script::Compile(v8_str(
2995      "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];"));
2996  Local<Script> setter_script = Script::Compile(v8_str(
2997      "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
2998      "obj[17] = 23;"
2999      "obj.foo;"));
3000  Local<Script> interceptor_setter_script = Script::Compile(v8_str(
3001      "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
3002      "obj[39] = 47;"
3003      "obj.foo;"));  // This setter should not run, due to the interceptor.
3004  Local<Script> interceptor_getter_script = Script::Compile(v8_str(
3005      "obj[37];"));
3006  Local<Value> result = getter_script->Run();
3007  CHECK_EQ(v8_num(5), result);
3008  result = setter_script->Run();
3009  CHECK_EQ(v8_num(23), result);
3010  result = interceptor_setter_script->Run();
3011  CHECK_EQ(v8_num(23), result);
3012  result = interceptor_getter_script->Run();
3013  CHECK_EQ(v8_num(625), result);
3014}
3015
3016
3017static v8::Handle<Value> IdentityIndexedPropertyGetter(
3018    uint32_t index,
3019    const AccessorInfo& info) {
3020  return v8::Integer::New(index);
3021}
3022
3023
3024THREADED_TEST(IndexedInterceptorWithNoSetter) {
3025  v8::HandleScope scope;
3026  Local<ObjectTemplate> templ = ObjectTemplate::New();
3027  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3028
3029  LocalContext context;
3030  context->Global()->Set(v8_str("obj"), templ->NewInstance());
3031
3032  const char* code =
3033      "try {"
3034      "  obj[0] = 239;"
3035      "  for (var i = 0; i < 100; i++) {"
3036      "    var v = obj[0];"
3037      "    if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
3038      "  }"
3039      "  'PASSED'"
3040      "} catch(e) {"
3041      "  e"
3042      "}";
3043  ExpectString(code, "PASSED");
3044}
3045
3046
3047THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
3048  v8::HandleScope scope;
3049  Local<ObjectTemplate> templ = ObjectTemplate::New();
3050  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3051
3052  LocalContext context;
3053  Local<v8::Object> obj = templ->NewInstance();
3054  obj->TurnOnAccessCheck();
3055  context->Global()->Set(v8_str("obj"), obj);
3056
3057  const char* code =
3058      "try {"
3059      "  for (var i = 0; i < 100; i++) {"
3060      "    var v = obj[0];"
3061      "    if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
3062      "  }"
3063      "  'PASSED'"
3064      "} catch(e) {"
3065      "  e"
3066      "}";
3067  ExpectString(code, "PASSED");
3068}
3069
3070
3071THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
3072  i::FLAG_allow_natives_syntax = true;
3073  v8::HandleScope scope;
3074  Local<ObjectTemplate> templ = ObjectTemplate::New();
3075  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3076
3077  LocalContext context;
3078  Local<v8::Object> obj = templ->NewInstance();
3079  context->Global()->Set(v8_str("obj"), obj);
3080
3081  const char* code =
3082      "try {"
3083      "  for (var i = 0; i < 100; i++) {"
3084      "    var expected = i;"
3085      "    if (i == 5) {"
3086      "      %EnableAccessChecks(obj);"
3087      "      expected = undefined;"
3088      "    }"
3089      "    var v = obj[i];"
3090      "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3091      "    if (i == 5) %DisableAccessChecks(obj);"
3092      "  }"
3093      "  'PASSED'"
3094      "} catch(e) {"
3095      "  e"
3096      "}";
3097  ExpectString(code, "PASSED");
3098}
3099
3100
3101THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
3102  v8::HandleScope scope;
3103  Local<ObjectTemplate> templ = ObjectTemplate::New();
3104  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3105
3106  LocalContext context;
3107  Local<v8::Object> obj = templ->NewInstance();
3108  context->Global()->Set(v8_str("obj"), obj);
3109
3110  const char* code =
3111      "try {"
3112      "  for (var i = 0; i < 100; i++) {"
3113      "    var v = obj[i];"
3114      "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
3115      "  }"
3116      "  'PASSED'"
3117      "} catch(e) {"
3118      "  e"
3119      "}";
3120  ExpectString(code, "PASSED");
3121}
3122
3123
3124THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
3125  v8::HandleScope scope;
3126  Local<ObjectTemplate> templ = ObjectTemplate::New();
3127  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3128
3129  LocalContext context;
3130  Local<v8::Object> obj = templ->NewInstance();
3131  context->Global()->Set(v8_str("obj"), obj);
3132
3133  const char* code =
3134      "try {"
3135      "  for (var i = 0; i < 100; i++) {"
3136      "    var expected = i;"
3137      "    if (i == 50) {"
3138      "       i = 'foobar';"
3139      "       expected = undefined;"
3140      "    }"
3141      "    var v = obj[i];"
3142      "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3143      "  }"
3144      "  'PASSED'"
3145      "} catch(e) {"
3146      "  e"
3147      "}";
3148  ExpectString(code, "PASSED");
3149}
3150
3151
3152THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
3153  v8::HandleScope scope;
3154  Local<ObjectTemplate> templ = ObjectTemplate::New();
3155  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3156
3157  LocalContext context;
3158  Local<v8::Object> obj = templ->NewInstance();
3159  context->Global()->Set(v8_str("obj"), obj);
3160
3161  const char* code =
3162      "var original = obj;"
3163      "try {"
3164      "  for (var i = 0; i < 100; i++) {"
3165      "    var expected = i;"
3166      "    if (i == 50) {"
3167      "       obj = {50: 'foobar'};"
3168      "       expected = 'foobar';"
3169      "    }"
3170      "    var v = obj[i];"
3171      "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3172      "    if (i == 50) obj = original;"
3173      "  }"
3174      "  'PASSED'"
3175      "} catch(e) {"
3176      "  e"
3177      "}";
3178  ExpectString(code, "PASSED");
3179}
3180
3181
3182THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
3183  v8::HandleScope scope;
3184  Local<ObjectTemplate> templ = ObjectTemplate::New();
3185  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3186
3187  LocalContext context;
3188  Local<v8::Object> obj = templ->NewInstance();
3189  context->Global()->Set(v8_str("obj"), obj);
3190
3191  const char* code =
3192      "var original = obj;"
3193      "try {"
3194      "  for (var i = 0; i < 100; i++) {"
3195      "    var expected = i;"
3196      "    if (i == 5) {"
3197      "       obj = 239;"
3198      "       expected = undefined;"
3199      "    }"
3200      "    var v = obj[i];"
3201      "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3202      "    if (i == 5) obj = original;"
3203      "  }"
3204      "  'PASSED'"
3205      "} catch(e) {"
3206      "  e"
3207      "}";
3208  ExpectString(code, "PASSED");
3209}
3210
3211
3212THREADED_TEST(IndexedInterceptorOnProto) {
3213  v8::HandleScope scope;
3214  Local<ObjectTemplate> templ = ObjectTemplate::New();
3215  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3216
3217  LocalContext context;
3218  Local<v8::Object> obj = templ->NewInstance();
3219  context->Global()->Set(v8_str("obj"), obj);
3220
3221  const char* code =
3222      "var o = {__proto__: obj};"
3223      "try {"
3224      "  for (var i = 0; i < 100; i++) {"
3225      "    var v = o[i];"
3226      "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
3227      "  }"
3228      "  'PASSED'"
3229      "} catch(e) {"
3230      "  e"
3231      "}";
3232  ExpectString(code, "PASSED");
3233}
3234
3235
3236THREADED_TEST(MultiContexts) {
3237  v8::HandleScope scope;
3238  v8::Handle<ObjectTemplate> templ = ObjectTemplate::New();
3239  templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(DummyCallHandler));
3240
3241  Local<String> password = v8_str("Password");
3242
3243  // Create an environment
3244  LocalContext context0(0, templ);
3245  context0->SetSecurityToken(password);
3246  v8::Handle<v8::Object> global0 = context0->Global();
3247  global0->Set(v8_str("custom"), v8_num(1234));
3248  CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
3249
3250  // Create an independent environment
3251  LocalContext context1(0, templ);
3252  context1->SetSecurityToken(password);
3253  v8::Handle<v8::Object> global1 = context1->Global();
3254  global1->Set(v8_str("custom"), v8_num(1234));
3255  CHECK_NE(global0, global1);
3256  CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
3257  CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
3258
3259  // Now create a new context with the old global
3260  LocalContext context2(0, templ, global1);
3261  context2->SetSecurityToken(password);
3262  v8::Handle<v8::Object> global2 = context2->Global();
3263  CHECK_EQ(global1, global2);
3264  CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
3265  CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
3266}
3267
3268
3269THREADED_TEST(FunctionPrototypeAcrossContexts) {
3270  // Make sure that functions created by cloning boilerplates cannot
3271  // communicate through their __proto__ field.
3272
3273  v8::HandleScope scope;
3274
3275  LocalContext env0;
3276  v8::Handle<v8::Object> global0 =
3277      env0->Global();
3278  v8::Handle<v8::Object> object0 =
3279      global0->Get(v8_str("Object")).As<v8::Object>();
3280  v8::Handle<v8::Object> tostring0 =
3281      object0->Get(v8_str("toString")).As<v8::Object>();
3282  v8::Handle<v8::Object> proto0 =
3283      tostring0->Get(v8_str("__proto__")).As<v8::Object>();
3284  proto0->Set(v8_str("custom"), v8_num(1234));
3285
3286  LocalContext env1;
3287  v8::Handle<v8::Object> global1 =
3288      env1->Global();
3289  v8::Handle<v8::Object> object1 =
3290      global1->Get(v8_str("Object")).As<v8::Object>();
3291  v8::Handle<v8::Object> tostring1 =
3292      object1->Get(v8_str("toString")).As<v8::Object>();
3293  v8::Handle<v8::Object> proto1 =
3294      tostring1->Get(v8_str("__proto__")).As<v8::Object>();
3295  CHECK(!proto1->Has(v8_str("custom")));
3296}
3297
3298
3299THREADED_TEST(Regress892105) {
3300  // Make sure that object and array literals created by cloning
3301  // boilerplates cannot communicate through their __proto__
3302  // field. This is rather difficult to check, but we try to add stuff
3303  // to Object.prototype and Array.prototype and create a new
3304  // environment. This should succeed.
3305
3306  v8::HandleScope scope;
3307
3308  Local<String> source = v8_str("Object.prototype.obj = 1234;"
3309                                "Array.prototype.arr = 4567;"
3310                                "8901");
3311
3312  LocalContext env0;
3313  Local<Script> script0 = Script::Compile(source);
3314  CHECK_EQ(8901.0, script0->Run()->NumberValue());
3315
3316  LocalContext env1;
3317  Local<Script> script1 = Script::Compile(source);
3318  CHECK_EQ(8901.0, script1->Run()->NumberValue());
3319}
3320
3321
3322THREADED_TEST(UndetectableObject) {
3323  v8::HandleScope scope;
3324  LocalContext env;
3325
3326  Local<v8::FunctionTemplate> desc =
3327      v8::FunctionTemplate::New(0, v8::Handle<Value>());
3328  desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
3329
3330  Local<v8::Object> obj = desc->GetFunction()->NewInstance();
3331  env->Global()->Set(v8_str("undetectable"), obj);
3332
3333  ExpectString("undetectable.toString()", "[object Object]");
3334  ExpectString("typeof undetectable", "undefined");
3335  ExpectString("typeof(undetectable)", "undefined");
3336  ExpectBoolean("typeof undetectable == 'undefined'", true);
3337  ExpectBoolean("typeof undetectable == 'object'", false);
3338  ExpectBoolean("if (undetectable) { true; } else { false; }", false);
3339  ExpectBoolean("!undetectable", true);
3340
3341  ExpectObject("true&&undetectable", obj);
3342  ExpectBoolean("false&&undetectable", false);
3343  ExpectBoolean("true||undetectable", true);
3344  ExpectObject("false||undetectable", obj);
3345
3346  ExpectObject("undetectable&&true", obj);
3347  ExpectObject("undetectable&&false", obj);
3348  ExpectBoolean("undetectable||true", true);
3349  ExpectBoolean("undetectable||false", false);
3350
3351  ExpectBoolean("undetectable==null", true);
3352  ExpectBoolean("null==undetectable", true);
3353  ExpectBoolean("undetectable==undefined", true);
3354  ExpectBoolean("undefined==undetectable", true);
3355  ExpectBoolean("undetectable==undetectable", true);
3356
3357
3358  ExpectBoolean("undetectable===null", false);
3359  ExpectBoolean("null===undetectable", false);
3360  ExpectBoolean("undetectable===undefined", false);
3361  ExpectBoolean("undefined===undetectable", false);
3362  ExpectBoolean("undetectable===undetectable", true);
3363}
3364
3365
3366
3367THREADED_TEST(ExtensibleOnUndetectable) {
3368  v8::HandleScope scope;
3369  LocalContext env;
3370
3371  Local<v8::FunctionTemplate> desc =
3372      v8::FunctionTemplate::New(0, v8::Handle<Value>());
3373  desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
3374
3375  Local<v8::Object> obj = desc->GetFunction()->NewInstance();
3376  env->Global()->Set(v8_str("undetectable"), obj);
3377
3378  Local<String> source = v8_str("undetectable.x = 42;"
3379                                "undetectable.x");
3380
3381  Local<Script> script = Script::Compile(source);
3382
3383  CHECK_EQ(v8::Integer::New(42), script->Run());
3384
3385  ExpectBoolean("Object.isExtensible(undetectable)", true);
3386
3387  source = v8_str("Object.preventExtensions(undetectable);");
3388  script = Script::Compile(source);
3389  script->Run();
3390  ExpectBoolean("Object.isExtensible(undetectable)", false);
3391
3392  source = v8_str("undetectable.y = 2000;");
3393  script = Script::Compile(source);
3394  v8::TryCatch try_catch;
3395  Local<Value> result = script->Run();
3396  CHECK(result.IsEmpty());
3397  CHECK(try_catch.HasCaught());
3398}
3399
3400
3401
3402THREADED_TEST(UndetectableString) {
3403  v8::HandleScope scope;
3404  LocalContext env;
3405
3406  Local<String> obj = String::NewUndetectable("foo");
3407  env->Global()->Set(v8_str("undetectable"), obj);
3408
3409  ExpectString("undetectable", "foo");
3410  ExpectString("typeof undetectable", "undefined");
3411  ExpectString("typeof(undetectable)", "undefined");
3412  ExpectBoolean("typeof undetectable == 'undefined'", true);
3413  ExpectBoolean("typeof undetectable == 'string'", false);
3414  ExpectBoolean("if (undetectable) { true; } else { false; }", false);
3415  ExpectBoolean("!undetectable", true);
3416
3417  ExpectObject("true&&undetectable", obj);
3418  ExpectBoolean("false&&undetectable", false);
3419  ExpectBoolean("true||undetectable", true);
3420  ExpectObject("false||undetectable", obj);
3421
3422  ExpectObject("undetectable&&true", obj);
3423  ExpectObject("undetectable&&false", obj);
3424  ExpectBoolean("undetectable||true", true);
3425  ExpectBoolean("undetectable||false", false);
3426
3427  ExpectBoolean("undetectable==null", true);
3428  ExpectBoolean("null==undetectable", true);
3429  ExpectBoolean("undetectable==undefined", true);
3430  ExpectBoolean("undefined==undetectable", true);
3431  ExpectBoolean("undetectable==undetectable", true);
3432
3433
3434  ExpectBoolean("undetectable===null", false);
3435  ExpectBoolean("null===undetectable", false);
3436  ExpectBoolean("undetectable===undefined", false);
3437  ExpectBoolean("undefined===undetectable", false);
3438  ExpectBoolean("undetectable===undetectable", true);
3439}
3440
3441
3442template <typename T> static void USE(T) { }
3443
3444
3445// This test is not intended to be run, just type checked.
3446static void PersistentHandles() {
3447  USE(PersistentHandles);
3448  Local<String> str = v8_str("foo");
3449  v8::Persistent<String> p_str = v8::Persistent<String>::New(str);
3450  USE(p_str);
3451  Local<Script> scr = Script::Compile(v8_str(""));
3452  v8::Persistent<Script> p_scr = v8::Persistent<Script>::New(scr);
3453  USE(p_scr);
3454  Local<ObjectTemplate> templ = ObjectTemplate::New();
3455  v8::Persistent<ObjectTemplate> p_templ =
3456    v8::Persistent<ObjectTemplate>::New(templ);
3457  USE(p_templ);
3458}
3459
3460
3461static v8::Handle<Value> HandleLogDelegator(const v8::Arguments& args) {
3462  ApiTestFuzzer::Fuzz();
3463  return v8::Undefined();
3464}
3465
3466
3467THREADED_TEST(GlobalObjectTemplate) {
3468  v8::HandleScope handle_scope;
3469  Local<ObjectTemplate> global_template = ObjectTemplate::New();
3470  global_template->Set(v8_str("JSNI_Log"),
3471                       v8::FunctionTemplate::New(HandleLogDelegator));
3472  v8::Persistent<Context> context = Context::New(0, global_template);
3473  Context::Scope context_scope(context);
3474  Script::Compile(v8_str("JSNI_Log('LOG')"))->Run();
3475  context.Dispose();
3476}
3477
3478
3479static const char* kSimpleExtensionSource =
3480  "function Foo() {"
3481  "  return 4;"
3482  "}";
3483
3484
3485THREADED_TEST(SimpleExtensions) {
3486  v8::HandleScope handle_scope;
3487  v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
3488  const char* extension_names[] = { "simpletest" };
3489  v8::ExtensionConfiguration extensions(1, extension_names);
3490  v8::Handle<Context> context = Context::New(&extensions);
3491  Context::Scope lock(context);
3492  v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
3493  CHECK_EQ(result, v8::Integer::New(4));
3494}
3495
3496
3497static const char* kEvalExtensionSource1 =
3498  "function UseEval1() {"
3499  "  var x = 42;"
3500  "  return eval('x');"
3501  "}";
3502
3503
3504static const char* kEvalExtensionSource2 =
3505  "(function() {"
3506  "  var x = 42;"
3507  "  function e() {"
3508  "    return eval('x');"
3509  "  }"
3510  "  this.UseEval2 = e;"
3511  "})()";
3512
3513
3514THREADED_TEST(UseEvalFromExtension) {
3515  v8::HandleScope handle_scope;
3516  v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
3517  v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
3518  const char* extension_names[] = { "evaltest1", "evaltest2" };
3519  v8::ExtensionConfiguration extensions(2, extension_names);
3520  v8::Handle<Context> context = Context::New(&extensions);
3521  Context::Scope lock(context);
3522  v8::Handle<Value> result = Script::Compile(v8_str("UseEval1()"))->Run();
3523  CHECK_EQ(result, v8::Integer::New(42));
3524  result = Script::Compile(v8_str("UseEval2()"))->Run();
3525  CHECK_EQ(result, v8::Integer::New(42));
3526}
3527
3528
3529static const char* kWithExtensionSource1 =
3530  "function UseWith1() {"
3531  "  var x = 42;"
3532  "  with({x:87}) { return x; }"
3533  "}";
3534
3535
3536
3537static const char* kWithExtensionSource2 =
3538  "(function() {"
3539  "  var x = 42;"
3540  "  function e() {"
3541  "    with ({x:87}) { return x; }"
3542  "  }"
3543  "  this.UseWith2 = e;"
3544  "})()";
3545
3546
3547THREADED_TEST(UseWithFromExtension) {
3548  v8::HandleScope handle_scope;
3549  v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
3550  v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
3551  const char* extension_names[] = { "withtest1", "withtest2" };
3552  v8::ExtensionConfiguration extensions(2, extension_names);
3553  v8::Handle<Context> context = Context::New(&extensions);
3554  Context::Scope lock(context);
3555  v8::Handle<Value> result = Script::Compile(v8_str("UseWith1()"))->Run();
3556  CHECK_EQ(result, v8::Integer::New(87));
3557  result = Script::Compile(v8_str("UseWith2()"))->Run();
3558  CHECK_EQ(result, v8::Integer::New(87));
3559}
3560
3561
3562THREADED_TEST(AutoExtensions) {
3563  v8::HandleScope handle_scope;
3564  Extension* extension = new Extension("autotest", kSimpleExtensionSource);
3565  extension->set_auto_enable(true);
3566  v8::RegisterExtension(extension);
3567  v8::Handle<Context> context = Context::New();
3568  Context::Scope lock(context);
3569  v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
3570  CHECK_EQ(result, v8::Integer::New(4));
3571}
3572
3573
3574static const char* kSyntaxErrorInExtensionSource =
3575    "[";
3576
3577
3578// Test that a syntax error in an extension does not cause a fatal
3579// error but results in an empty context.
3580THREADED_TEST(SyntaxErrorExtensions) {
3581  v8::HandleScope handle_scope;
3582  v8::RegisterExtension(new Extension("syntaxerror",
3583                                      kSyntaxErrorInExtensionSource));
3584  const char* extension_names[] = { "syntaxerror" };
3585  v8::ExtensionConfiguration extensions(1, extension_names);
3586  v8::Handle<Context> context = Context::New(&extensions);
3587  CHECK(context.IsEmpty());
3588}
3589
3590
3591static const char* kExceptionInExtensionSource =
3592    "throw 42";
3593
3594
3595// Test that an exception when installing an extension does not cause
3596// a fatal error but results in an empty context.
3597THREADED_TEST(ExceptionExtensions) {
3598  v8::HandleScope handle_scope;
3599  v8::RegisterExtension(new Extension("exception",
3600                                      kExceptionInExtensionSource));
3601  const char* extension_names[] = { "exception" };
3602  v8::ExtensionConfiguration extensions(1, extension_names);
3603  v8::Handle<Context> context = Context::New(&extensions);
3604  CHECK(context.IsEmpty());
3605}
3606
3607
3608static void CheckDependencies(const char* name, const char* expected) {
3609  v8::HandleScope handle_scope;
3610  v8::ExtensionConfiguration config(1, &name);
3611  LocalContext context(&config);
3612  CHECK_EQ(String::New(expected), context->Global()->Get(v8_str("loaded")));
3613}
3614
3615
3616/*
3617 * Configuration:
3618 *
3619 *     /-- B <--\
3620 * A <-          -- D <-- E
3621 *     \-- C <--/
3622 */
3623THREADED_TEST(ExtensionDependency) {
3624  static const char* kEDeps[] = { "D" };
3625  v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
3626  static const char* kDDeps[] = { "B", "C" };
3627  v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
3628  static const char* kBCDeps[] = { "A" };
3629  v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
3630  v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
3631  v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
3632  CheckDependencies("A", "undefinedA");
3633  CheckDependencies("B", "undefinedAB");
3634  CheckDependencies("C", "undefinedAC");
3635  CheckDependencies("D", "undefinedABCD");
3636  CheckDependencies("E", "undefinedABCDE");
3637  v8::HandleScope handle_scope;
3638  static const char* exts[2] = { "C", "E" };
3639  v8::ExtensionConfiguration config(2, exts);
3640  LocalContext context(&config);
3641  CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
3642}
3643
3644
3645static const char* kExtensionTestScript =
3646  "native function A();"
3647  "native function B();"
3648  "native function C();"
3649  "function Foo(i) {"
3650  "  if (i == 0) return A();"
3651  "  if (i == 1) return B();"
3652  "  if (i == 2) return C();"
3653  "}";
3654
3655
3656static v8::Handle<Value> CallFun(const v8::Arguments& args) {
3657  ApiTestFuzzer::Fuzz();
3658  if (args.IsConstructCall()) {
3659    args.This()->Set(v8_str("data"), args.Data());
3660    return v8::Null();
3661  }
3662  return args.Data();
3663}
3664
3665
3666class FunctionExtension : public Extension {
3667 public:
3668  FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
3669  virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
3670      v8::Handle<String> name);
3671};
3672
3673
3674static int lookup_count = 0;
3675v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunction(
3676      v8::Handle<String> name) {
3677  lookup_count++;
3678  if (name->Equals(v8_str("A"))) {
3679    return v8::FunctionTemplate::New(CallFun, v8::Integer::New(8));
3680  } else if (name->Equals(v8_str("B"))) {
3681    return v8::FunctionTemplate::New(CallFun, v8::Integer::New(7));
3682  } else if (name->Equals(v8_str("C"))) {
3683    return v8::FunctionTemplate::New(CallFun, v8::Integer::New(6));
3684  } else {
3685    return v8::Handle<v8::FunctionTemplate>();
3686  }
3687}
3688
3689
3690THREADED_TEST(FunctionLookup) {
3691  v8::RegisterExtension(new FunctionExtension());
3692  v8::HandleScope handle_scope;
3693  static const char* exts[1] = { "functiontest" };
3694  v8::ExtensionConfiguration config(1, exts);
3695  LocalContext context(&config);
3696  CHECK_EQ(3, lookup_count);
3697  CHECK_EQ(v8::Integer::New(8), Script::Compile(v8_str("Foo(0)"))->Run());
3698  CHECK_EQ(v8::Integer::New(7), Script::Compile(v8_str("Foo(1)"))->Run());
3699  CHECK_EQ(v8::Integer::New(6), Script::Compile(v8_str("Foo(2)"))->Run());
3700}
3701
3702
3703THREADED_TEST(NativeFunctionConstructCall) {
3704  v8::RegisterExtension(new FunctionExtension());
3705  v8::HandleScope handle_scope;
3706  static const char* exts[1] = { "functiontest" };
3707  v8::ExtensionConfiguration config(1, exts);
3708  LocalContext context(&config);
3709  for (int i = 0; i < 10; i++) {
3710    // Run a few times to ensure that allocation of objects doesn't
3711    // change behavior of a constructor function.
3712    CHECK_EQ(v8::Integer::New(8),
3713             Script::Compile(v8_str("(new A()).data"))->Run());
3714    CHECK_EQ(v8::Integer::New(7),
3715             Script::Compile(v8_str("(new B()).data"))->Run());
3716    CHECK_EQ(v8::Integer::New(6),
3717             Script::Compile(v8_str("(new C()).data"))->Run());
3718  }
3719}
3720
3721
3722static const char* last_location;
3723static const char* last_message;
3724void StoringErrorCallback(const char* location, const char* message) {
3725  if (last_location == NULL) {
3726    last_location = location;
3727    last_message = message;
3728  }
3729}
3730
3731
3732// ErrorReporting creates a circular extensions configuration and
3733// tests that the fatal error handler gets called.  This renders V8
3734// unusable and therefore this test cannot be run in parallel.
3735TEST(ErrorReporting) {
3736  v8::V8::SetFatalErrorHandler(StoringErrorCallback);
3737  static const char* aDeps[] = { "B" };
3738  v8::RegisterExtension(new Extension("A", "", 1, aDeps));
3739  static const char* bDeps[] = { "A" };
3740  v8::RegisterExtension(new Extension("B", "", 1, bDeps));
3741  last_location = NULL;
3742  v8::ExtensionConfiguration config(1, bDeps);
3743  v8::Handle<Context> context = Context::New(&config);
3744  CHECK(context.IsEmpty());
3745  CHECK_NE(last_location, NULL);
3746}
3747
3748
3749static const char* js_code_causing_huge_string_flattening =
3750    "var str = 'X';"
3751    "for (var i = 0; i < 30; i++) {"
3752    "  str = str + str;"
3753    "}"
3754    "str.match(/X/);";
3755
3756
3757void OOMCallback(const char* location, const char* message) {
3758  exit(0);
3759}
3760
3761
3762TEST(RegexpOutOfMemory) {
3763  // Execute a script that causes out of memory when flattening a string.
3764  v8::HandleScope scope;
3765  v8::V8::SetFatalErrorHandler(OOMCallback);
3766  LocalContext context;
3767  Local<Script> script =
3768      Script::Compile(String::New(js_code_causing_huge_string_flattening));
3769  last_location = NULL;
3770  Local<Value> result = script->Run();
3771
3772  CHECK(false);  // Should not return.
3773}
3774
3775
3776static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
3777                                             v8::Handle<Value> data) {
3778  CHECK_EQ(v8::Undefined(), data);
3779  CHECK(message->GetScriptResourceName()->IsUndefined());
3780  CHECK_EQ(v8::Undefined(), message->GetScriptResourceName());
3781  message->GetLineNumber();
3782  message->GetSourceLine();
3783}
3784
3785
3786THREADED_TEST(ErrorWithMissingScriptInfo) {
3787  v8::HandleScope scope;
3788  LocalContext context;
3789  v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
3790  Script::Compile(v8_str("throw Error()"))->Run();
3791  v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
3792}
3793
3794
3795int global_index = 0;
3796
3797class Snorkel {
3798 public:
3799  Snorkel() { index_ = global_index++; }
3800  int index_;
3801};
3802
3803class Whammy {
3804 public:
3805  Whammy() {
3806    cursor_ = 0;
3807  }
3808  ~Whammy() {
3809    script_.Dispose();
3810  }
3811  v8::Handle<Script> getScript() {
3812    if (script_.IsEmpty())
3813      script_ = v8::Persistent<Script>::New(v8_compile("({}).blammo"));
3814    return Local<Script>(*script_);
3815  }
3816
3817 public:
3818  static const int kObjectCount = 256;
3819  int cursor_;
3820  v8::Persistent<v8::Object> objects_[kObjectCount];
3821  v8::Persistent<Script> script_;
3822};
3823
3824static void HandleWeakReference(v8::Persistent<v8::Value> obj, void* data) {
3825  Snorkel* snorkel = reinterpret_cast<Snorkel*>(data);
3826  delete snorkel;
3827  obj.ClearWeak();
3828}
3829
3830v8::Handle<Value> WhammyPropertyGetter(Local<String> name,
3831                                       const AccessorInfo& info) {
3832  Whammy* whammy =
3833    static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
3834
3835  v8::Persistent<v8::Object> prev = whammy->objects_[whammy->cursor_];
3836
3837  v8::Handle<v8::Object> obj = v8::Object::New();
3838  v8::Persistent<v8::Object> global = v8::Persistent<v8::Object>::New(obj);
3839  if (!prev.IsEmpty()) {
3840    prev->Set(v8_str("next"), obj);
3841    prev.MakeWeak(new Snorkel(), &HandleWeakReference);
3842    whammy->objects_[whammy->cursor_].Clear();
3843  }
3844  whammy->objects_[whammy->cursor_] = global;
3845  whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount;
3846  return whammy->getScript()->Run();
3847}
3848
3849THREADED_TEST(WeakReference) {
3850  v8::HandleScope handle_scope;
3851  v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New();
3852  Whammy* whammy = new Whammy();
3853  templ->SetNamedPropertyHandler(WhammyPropertyGetter,
3854                                 0, 0, 0, 0,
3855                                 v8::External::New(whammy));
3856  const char* extension_list[] = { "v8/gc" };
3857  v8::ExtensionConfiguration extensions(1, extension_list);
3858  v8::Persistent<Context> context = Context::New(&extensions);
3859  Context::Scope context_scope(context);
3860
3861  v8::Handle<v8::Object> interceptor = templ->NewInstance();
3862  context->Global()->Set(v8_str("whammy"), interceptor);
3863  const char* code =
3864      "var last;"
3865      "for (var i = 0; i < 10000; i++) {"
3866      "  var obj = whammy.length;"
3867      "  if (last) last.next = obj;"
3868      "  last = obj;"
3869      "}"
3870      "gc();"
3871      "4";
3872  v8::Handle<Value> result = CompileRun(code);
3873  CHECK_EQ(4.0, result->NumberValue());
3874  delete whammy;
3875  context.Dispose();
3876}
3877
3878
3879static bool in_scavenge = false;
3880static int last = -1;
3881
3882static void ForceScavenge(v8::Persistent<v8::Value> obj, void* data) {
3883  CHECK_EQ(-1, last);
3884  last = 0;
3885  obj.Dispose();
3886  obj.Clear();
3887  in_scavenge = true;
3888  i::Heap::PerformScavenge();
3889  in_scavenge = false;
3890  *(reinterpret_cast<bool*>(data)) = true;
3891}
3892
3893static void CheckIsNotInvokedInScavenge(v8::Persistent<v8::Value> obj,
3894                                        void* data) {
3895  CHECK_EQ(0, last);
3896  last = 1;
3897  *(reinterpret_cast<bool*>(data)) = in_scavenge;
3898  obj.Dispose();
3899  obj.Clear();
3900}
3901
3902THREADED_TEST(NoWeakRefCallbacksInScavenge) {
3903  // Test verifies that scavenge cannot invoke WeakReferenceCallbacks.
3904  // Calling callbacks from scavenges is unsafe as objects held by those
3905  // handlers might have become strongly reachable, but scavenge doesn't
3906  // check that.
3907  v8::Persistent<Context> context = Context::New();
3908  Context::Scope context_scope(context);
3909
3910  v8::Persistent<v8::Object> object_a;
3911  v8::Persistent<v8::Object> object_b;
3912
3913  {
3914    v8::HandleScope handle_scope;
3915    object_b = v8::Persistent<v8::Object>::New(v8::Object::New());
3916    object_a = v8::Persistent<v8::Object>::New(v8::Object::New());
3917  }
3918
3919  bool object_a_disposed = false;
3920  object_a.MakeWeak(&object_a_disposed, &ForceScavenge);
3921  bool released_in_scavenge = false;
3922  object_b.MakeWeak(&released_in_scavenge, &CheckIsNotInvokedInScavenge);
3923
3924  while (!object_a_disposed) {
3925    i::Heap::CollectAllGarbage(false);
3926  }
3927  CHECK(!released_in_scavenge);
3928}
3929
3930
3931v8::Handle<Function> args_fun;
3932
3933
3934static v8::Handle<Value> ArgumentsTestCallback(const v8::Arguments& args) {
3935  ApiTestFuzzer::Fuzz();
3936  CHECK_EQ(args_fun, args.Callee());
3937  CHECK_EQ(3, args.Length());
3938  CHECK_EQ(v8::Integer::New(1), args[0]);
3939  CHECK_EQ(v8::Integer::New(2), args[1]);
3940  CHECK_EQ(v8::Integer::New(3), args[2]);
3941  CHECK_EQ(v8::Undefined(), args[3]);
3942  v8::HandleScope scope;
3943  i::Heap::CollectAllGarbage(false);
3944  return v8::Undefined();
3945}
3946
3947
3948THREADED_TEST(Arguments) {
3949  v8::HandleScope scope;
3950  v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
3951  global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback));
3952  LocalContext context(NULL, global);
3953  args_fun = context->Global()->Get(v8_str("f")).As<Function>();
3954  v8_compile("f(1, 2, 3)")->Run();
3955}
3956
3957
3958static v8::Handle<Value> NoBlockGetterX(Local<String> name,
3959                                        const AccessorInfo&) {
3960  return v8::Handle<Value>();
3961}
3962
3963
3964static v8::Handle<Value> NoBlockGetterI(uint32_t index,
3965                                        const AccessorInfo&) {
3966  return v8::Handle<Value>();
3967}
3968
3969
3970static v8::Handle<v8::Boolean> PDeleter(Local<String> name,
3971                                        const AccessorInfo&) {
3972  if (!name->Equals(v8_str("foo"))) {
3973    return v8::Handle<v8::Boolean>();  // not intercepted
3974  }
3975
3976  return v8::False();  // intercepted, and don't delete the property
3977}
3978
3979
3980static v8::Handle<v8::Boolean> IDeleter(uint32_t index, const AccessorInfo&) {
3981  if (index != 2) {
3982    return v8::Handle<v8::Boolean>();  // not intercepted
3983  }
3984
3985  return v8::False();  // intercepted, and don't delete the property
3986}
3987
3988
3989THREADED_TEST(Deleter) {
3990  v8::HandleScope scope;
3991  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
3992  obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
3993  obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
3994  LocalContext context;
3995  context->Global()->Set(v8_str("k"), obj->NewInstance());
3996  CompileRun(
3997    "k.foo = 'foo';"
3998    "k.bar = 'bar';"
3999    "k[2] = 2;"
4000    "k[4] = 4;");
4001  CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
4002  CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
4003
4004  CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
4005  CHECK(v8_compile("k.bar")->Run()->IsUndefined());
4006
4007  CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
4008  CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
4009
4010  CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
4011  CHECK(v8_compile("k[4]")->Run()->IsUndefined());
4012}
4013
4014
4015static v8::Handle<Value> GetK(Local<String> name, const AccessorInfo&) {
4016  ApiTestFuzzer::Fuzz();
4017  if (name->Equals(v8_str("foo")) ||
4018      name->Equals(v8_str("bar")) ||
4019      name->Equals(v8_str("baz"))) {
4020    return v8::Undefined();
4021  }
4022  return v8::Handle<Value>();
4023}
4024
4025
4026static v8::Handle<Value> IndexedGetK(uint32_t index, const AccessorInfo&) {
4027  ApiTestFuzzer::Fuzz();
4028  if (index == 0 || index == 1) return v8::Undefined();
4029  return v8::Handle<Value>();
4030}
4031
4032
4033static v8::Handle<v8::Array> NamedEnum(const AccessorInfo&) {
4034  ApiTestFuzzer::Fuzz();
4035  v8::Handle<v8::Array> result = v8::Array::New(3);
4036  result->Set(v8::Integer::New(0), v8_str("foo"));
4037  result->Set(v8::Integer::New(1), v8_str("bar"));
4038  result->Set(v8::Integer::New(2), v8_str("baz"));
4039  return result;
4040}
4041
4042
4043static v8::Handle<v8::Array> IndexedEnum(const AccessorInfo&) {
4044  ApiTestFuzzer::Fuzz();
4045  v8::Handle<v8::Array> result = v8::Array::New(2);
4046  result->Set(v8::Integer::New(0), v8_str("0"));
4047  result->Set(v8::Integer::New(1), v8_str("1"));
4048  return result;
4049}
4050
4051
4052THREADED_TEST(Enumerators) {
4053  v8::HandleScope scope;
4054  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4055  obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
4056  obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
4057  LocalContext context;
4058  context->Global()->Set(v8_str("k"), obj->NewInstance());
4059  v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
4060    "k[10] = 0;"
4061    "k.a = 0;"
4062    "k[5] = 0;"
4063    "k.b = 0;"
4064    "k[4294967295] = 0;"
4065    "k.c = 0;"
4066    "k[4294967296] = 0;"
4067    "k.d = 0;"
4068    "k[140000] = 0;"
4069    "k.e = 0;"
4070    "k[30000000000] = 0;"
4071    "k.f = 0;"
4072    "var result = [];"
4073    "for (var prop in k) {"
4074    "  result.push(prop);"
4075    "}"
4076    "result"));
4077  // Check that we get all the property names returned including the
4078  // ones from the enumerators in the right order: indexed properties
4079  // in numerical order, indexed interceptor properties, named
4080  // properties in insertion order, named interceptor properties.
4081  // This order is not mandated by the spec, so this test is just
4082  // documenting our behavior.
4083  CHECK_EQ(17, result->Length());
4084  // Indexed properties in numerical order.
4085  CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(0)));
4086  CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(1)));
4087  CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(2)));
4088  CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(3)));
4089  // Indexed interceptor properties in the order they are returned
4090  // from the enumerator interceptor.
4091  CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(4)));
4092  CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(5)));
4093  // Named properties in insertion order.
4094  CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(6)));
4095  CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(7)));
4096  CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(8)));
4097  CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(9)));
4098  CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(10)));
4099  CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(11)));
4100  CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(12)));
4101  CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(13)));
4102  // Named interceptor properties.
4103  CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(14)));
4104  CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(15)));
4105  CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(16)));
4106}
4107
4108
4109int p_getter_count;
4110int p_getter_count2;
4111
4112
4113static v8::Handle<Value> PGetter(Local<String> name, const AccessorInfo& info) {
4114  ApiTestFuzzer::Fuzz();
4115  p_getter_count++;
4116  v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
4117  CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
4118  if (name->Equals(v8_str("p1"))) {
4119    CHECK_EQ(info.This(), global->Get(v8_str("o1")));
4120  } else if (name->Equals(v8_str("p2"))) {
4121    CHECK_EQ(info.This(), global->Get(v8_str("o2")));
4122  } else if (name->Equals(v8_str("p3"))) {
4123    CHECK_EQ(info.This(), global->Get(v8_str("o3")));
4124  } else if (name->Equals(v8_str("p4"))) {
4125    CHECK_EQ(info.This(), global->Get(v8_str("o4")));
4126  }
4127  return v8::Undefined();
4128}
4129
4130
4131static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
4132  ApiTestFuzzer::Fuzz();
4133  LocalContext context;
4134  context->Global()->Set(v8_str("o1"), obj->NewInstance());
4135  CompileRun(
4136    "o1.__proto__ = { };"
4137    "var o2 = { __proto__: o1 };"
4138    "var o3 = { __proto__: o2 };"
4139    "var o4 = { __proto__: o3 };"
4140    "for (var i = 0; i < 10; i++) o4.p4;"
4141    "for (var i = 0; i < 10; i++) o3.p3;"
4142    "for (var i = 0; i < 10; i++) o2.p2;"
4143    "for (var i = 0; i < 10; i++) o1.p1;");
4144}
4145
4146
4147static v8::Handle<Value> PGetter2(Local<String> name,
4148                                  const AccessorInfo& info) {
4149  ApiTestFuzzer::Fuzz();
4150  p_getter_count2++;
4151  v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
4152  CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
4153  if (name->Equals(v8_str("p1"))) {
4154    CHECK_EQ(info.This(), global->Get(v8_str("o1")));
4155  } else if (name->Equals(v8_str("p2"))) {
4156    CHECK_EQ(info.This(), global->Get(v8_str("o2")));
4157  } else if (name->Equals(v8_str("p3"))) {
4158    CHECK_EQ(info.This(), global->Get(v8_str("o3")));
4159  } else if (name->Equals(v8_str("p4"))) {
4160    CHECK_EQ(info.This(), global->Get(v8_str("o4")));
4161  }
4162  return v8::Undefined();
4163}
4164
4165
4166THREADED_TEST(GetterHolders) {
4167  v8::HandleScope scope;
4168  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4169  obj->SetAccessor(v8_str("p1"), PGetter);
4170  obj->SetAccessor(v8_str("p2"), PGetter);
4171  obj->SetAccessor(v8_str("p3"), PGetter);
4172  obj->SetAccessor(v8_str("p4"), PGetter);
4173  p_getter_count = 0;
4174  RunHolderTest(obj);
4175  CHECK_EQ(40, p_getter_count);
4176}
4177
4178
4179THREADED_TEST(PreInterceptorHolders) {
4180  v8::HandleScope scope;
4181  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4182  obj->SetNamedPropertyHandler(PGetter2);
4183  p_getter_count2 = 0;
4184  RunHolderTest(obj);
4185  CHECK_EQ(40, p_getter_count2);
4186}
4187
4188
4189THREADED_TEST(ObjectInstantiation) {
4190  v8::HandleScope scope;
4191  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
4192  templ->SetAccessor(v8_str("t"), PGetter2);
4193  LocalContext context;
4194  context->Global()->Set(v8_str("o"), templ->NewInstance());
4195  for (int i = 0; i < 100; i++) {
4196    v8::HandleScope inner_scope;
4197    v8::Handle<v8::Object> obj = templ->NewInstance();
4198    CHECK_NE(obj, context->Global()->Get(v8_str("o")));
4199    context->Global()->Set(v8_str("o2"), obj);
4200    v8::Handle<Value> value =
4201        Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run();
4202    CHECK_EQ(v8::True(), value);
4203    context->Global()->Set(v8_str("o"), obj);
4204  }
4205}
4206
4207
4208THREADED_TEST(StringWrite) {
4209  v8::HandleScope scope;
4210  v8::Handle<String> str = v8_str("abcde");
4211
4212  char buf[100];
4213  int len;
4214
4215  memset(buf, 0x1, sizeof(buf));
4216  len = str->WriteAscii(buf);
4217  CHECK_EQ(len, 5);
4218  CHECK_EQ(strncmp("abcde\0", buf, 6), 0);
4219
4220  memset(buf, 0x1, sizeof(buf));
4221  len = str->WriteAscii(buf, 0, 4);
4222  CHECK_EQ(len, 4);
4223  CHECK_EQ(strncmp("abcd\1", buf, 5), 0);
4224
4225  memset(buf, 0x1, sizeof(buf));
4226  len = str->WriteAscii(buf, 0, 5);
4227  CHECK_EQ(len, 5);
4228  CHECK_EQ(strncmp("abcde\1", buf, 6), 0);
4229
4230  memset(buf, 0x1, sizeof(buf));
4231  len = str->WriteAscii(buf, 0, 6);
4232  CHECK_EQ(len, 5);
4233  CHECK_EQ(strncmp("abcde\0", buf, 6), 0);
4234
4235  memset(buf, 0x1, sizeof(buf));
4236  len = str->WriteAscii(buf, 4, -1);
4237  CHECK_EQ(len, 1);
4238  CHECK_EQ(strncmp("e\0", buf, 2), 0);
4239
4240  memset(buf, 0x1, sizeof(buf));
4241  len = str->WriteAscii(buf, 4, 6);
4242  CHECK_EQ(len, 1);
4243  CHECK_EQ(strncmp("e\0", buf, 2), 0);
4244
4245  memset(buf, 0x1, sizeof(buf));
4246  len = str->WriteAscii(buf, 4, 1);
4247  CHECK_EQ(len, 1);
4248  CHECK_EQ(strncmp("e\1", buf, 2), 0);
4249}
4250
4251
4252THREADED_TEST(ToArrayIndex) {
4253  v8::HandleScope scope;
4254  LocalContext context;
4255
4256  v8::Handle<String> str = v8_str("42");
4257  v8::Handle<v8::Uint32> index = str->ToArrayIndex();
4258  CHECK(!index.IsEmpty());
4259  CHECK_EQ(42.0, index->Uint32Value());
4260  str = v8_str("42asdf");
4261  index = str->ToArrayIndex();
4262  CHECK(index.IsEmpty());
4263  str = v8_str("-42");
4264  index = str->ToArrayIndex();
4265  CHECK(index.IsEmpty());
4266  str = v8_str("4294967295");
4267  index = str->ToArrayIndex();
4268  CHECK(!index.IsEmpty());
4269  CHECK_EQ(4294967295.0, index->Uint32Value());
4270  v8::Handle<v8::Number> num = v8::Number::New(1);
4271  index = num->ToArrayIndex();
4272  CHECK(!index.IsEmpty());
4273  CHECK_EQ(1.0, index->Uint32Value());
4274  num = v8::Number::New(-1);
4275  index = num->ToArrayIndex();
4276  CHECK(index.IsEmpty());
4277  v8::Handle<v8::Object> obj = v8::Object::New();
4278  index = obj->ToArrayIndex();
4279  CHECK(index.IsEmpty());
4280}
4281
4282
4283THREADED_TEST(ErrorConstruction) {
4284  v8::HandleScope scope;
4285  LocalContext context;
4286
4287  v8::Handle<String> foo = v8_str("foo");
4288  v8::Handle<String> message = v8_str("message");
4289  v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
4290  CHECK(range_error->IsObject());
4291  v8::Handle<v8::Object> range_obj = range_error.As<v8::Object>();
4292  CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
4293  v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
4294  CHECK(reference_error->IsObject());
4295  CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
4296  v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
4297  CHECK(syntax_error->IsObject());
4298  CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
4299  v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
4300  CHECK(type_error->IsObject());
4301  CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
4302  v8::Handle<Value> error = v8::Exception::Error(foo);
4303  CHECK(error->IsObject());
4304  CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
4305}
4306
4307
4308static v8::Handle<Value> YGetter(Local<String> name, const AccessorInfo& info) {
4309  ApiTestFuzzer::Fuzz();
4310  return v8_num(10);
4311}
4312
4313
4314static void YSetter(Local<String> name,
4315                    Local<Value> value,
4316                    const AccessorInfo& info) {
4317  if (info.This()->Has(name)) {
4318    info.This()->Delete(name);
4319  }
4320  info.This()->Set(name, value);
4321}
4322
4323
4324THREADED_TEST(DeleteAccessor) {
4325  v8::HandleScope scope;
4326  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4327  obj->SetAccessor(v8_str("y"), YGetter, YSetter);
4328  LocalContext context;
4329  v8::Handle<v8::Object> holder = obj->NewInstance();
4330  context->Global()->Set(v8_str("holder"), holder);
4331  v8::Handle<Value> result = CompileRun(
4332      "holder.y = 11; holder.y = 12; holder.y");
4333  CHECK_EQ(12, result->Uint32Value());
4334}
4335
4336
4337THREADED_TEST(TypeSwitch) {
4338  v8::HandleScope scope;
4339  v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New();
4340  v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New();
4341  v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New();
4342  v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
4343  v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
4344  LocalContext context;
4345  v8::Handle<v8::Object> obj0 = v8::Object::New();
4346  v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
4347  v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
4348  v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
4349  for (int i = 0; i < 10; i++) {
4350    CHECK_EQ(0, type_switch->match(obj0));
4351    CHECK_EQ(1, type_switch->match(obj1));
4352    CHECK_EQ(2, type_switch->match(obj2));
4353    CHECK_EQ(3, type_switch->match(obj3));
4354    CHECK_EQ(3, type_switch->match(obj3));
4355    CHECK_EQ(2, type_switch->match(obj2));
4356    CHECK_EQ(1, type_switch->match(obj1));
4357    CHECK_EQ(0, type_switch->match(obj0));
4358  }
4359}
4360
4361
4362// For use within the TestSecurityHandler() test.
4363static bool g_security_callback_result = false;
4364static bool NamedSecurityTestCallback(Local<v8::Object> global,
4365                                      Local<Value> name,
4366                                      v8::AccessType type,
4367                                      Local<Value> data) {
4368  // Always allow read access.
4369  if (type == v8::ACCESS_GET)
4370    return true;
4371
4372  // Sometimes allow other access.
4373  return g_security_callback_result;
4374}
4375
4376
4377static bool IndexedSecurityTestCallback(Local<v8::Object> global,
4378                                        uint32_t key,
4379                                        v8::AccessType type,
4380                                        Local<Value> data) {
4381  // Always allow read access.
4382  if (type == v8::ACCESS_GET)
4383    return true;
4384
4385  // Sometimes allow other access.
4386  return g_security_callback_result;
4387}
4388
4389
4390static int trouble_nesting = 0;
4391static v8::Handle<Value> TroubleCallback(const v8::Arguments& args) {
4392  ApiTestFuzzer::Fuzz();
4393  trouble_nesting++;
4394
4395  // Call a JS function that throws an uncaught exception.
4396  Local<v8::Object> arg_this = Context::GetCurrent()->Global();
4397  Local<Value> trouble_callee = (trouble_nesting == 3) ?
4398    arg_this->Get(v8_str("trouble_callee")) :
4399    arg_this->Get(v8_str("trouble_caller"));
4400  CHECK(trouble_callee->IsFunction());
4401  return Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL);
4402}
4403
4404
4405static int report_count = 0;
4406static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
4407                                             v8::Handle<Value>) {
4408  report_count++;
4409}
4410
4411
4412// Counts uncaught exceptions, but other tests running in parallel
4413// also have uncaught exceptions.
4414TEST(ApiUncaughtException) {
4415  report_count = 0;
4416  v8::HandleScope scope;
4417  LocalContext env;
4418  v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
4419
4420  Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
4421  v8::Local<v8::Object> global = env->Global();
4422  global->Set(v8_str("trouble"), fun->GetFunction());
4423
4424  Script::Compile(v8_str("function trouble_callee() {"
4425                         "  var x = null;"
4426                         "  return x.foo;"
4427                         "};"
4428                         "function trouble_caller() {"
4429                         "  trouble();"
4430                         "};"))->Run();
4431  Local<Value> trouble = global->Get(v8_str("trouble"));
4432  CHECK(trouble->IsFunction());
4433  Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
4434  CHECK(trouble_callee->IsFunction());
4435  Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
4436  CHECK(trouble_caller->IsFunction());
4437  Function::Cast(*trouble_caller)->Call(global, 0, NULL);
4438  CHECK_EQ(1, report_count);
4439  v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
4440}
4441
4442static const char* script_resource_name = "ExceptionInNativeScript.js";
4443static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
4444                                                v8::Handle<Value>) {
4445  v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
4446  CHECK(!name_val.IsEmpty() && name_val->IsString());
4447  v8::String::AsciiValue name(message->GetScriptResourceName());
4448  CHECK_EQ(script_resource_name, *name);
4449  CHECK_EQ(3, message->GetLineNumber());
4450  v8::String::AsciiValue source_line(message->GetSourceLine());
4451  CHECK_EQ("  new o.foo();", *source_line);
4452}
4453
4454TEST(ExceptionInNativeScript) {
4455  v8::HandleScope scope;
4456  LocalContext env;
4457  v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
4458
4459  Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
4460  v8::Local<v8::Object> global = env->Global();
4461  global->Set(v8_str("trouble"), fun->GetFunction());
4462
4463  Script::Compile(v8_str("function trouble() {\n"
4464                         "  var o = {};\n"
4465                         "  new o.foo();\n"
4466                         "};"), v8::String::New(script_resource_name))->Run();
4467  Local<Value> trouble = global->Get(v8_str("trouble"));
4468  CHECK(trouble->IsFunction());
4469  Function::Cast(*trouble)->Call(global, 0, NULL);
4470  v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
4471}
4472
4473
4474TEST(CompilationErrorUsingTryCatchHandler) {
4475  v8::HandleScope scope;
4476  LocalContext env;
4477  v8::TryCatch try_catch;
4478  Script::Compile(v8_str("This doesn't &*&@#$&*^ compile."));
4479  CHECK_NE(NULL, *try_catch.Exception());
4480  CHECK(try_catch.HasCaught());
4481}
4482
4483
4484TEST(TryCatchFinallyUsingTryCatchHandler) {
4485  v8::HandleScope scope;
4486  LocalContext env;
4487  v8::TryCatch try_catch;
4488  Script::Compile(v8_str("try { throw ''; } catch (e) {}"))->Run();
4489  CHECK(!try_catch.HasCaught());
4490  Script::Compile(v8_str("try { throw ''; } finally {}"))->Run();
4491  CHECK(try_catch.HasCaught());
4492  try_catch.Reset();
4493  Script::Compile(v8_str("(function() {"
4494                         "try { throw ''; } finally { return; }"
4495                         "})()"))->Run();
4496  CHECK(!try_catch.HasCaught());
4497  Script::Compile(v8_str("(function()"
4498                         "  { try { throw ''; } finally { throw 0; }"
4499                         "})()"))->Run();
4500  CHECK(try_catch.HasCaught());
4501}
4502
4503
4504// SecurityHandler can't be run twice
4505TEST(SecurityHandler) {
4506  v8::HandleScope scope0;
4507  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
4508  global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
4509                                           IndexedSecurityTestCallback);
4510  // Create an environment
4511  v8::Persistent<Context> context0 =
4512    Context::New(NULL, global_template);
4513  context0->Enter();
4514
4515  v8::Handle<v8::Object> global0 = context0->Global();
4516  v8::Handle<Script> script0 = v8_compile("foo = 111");
4517  script0->Run();
4518  global0->Set(v8_str("0"), v8_num(999));
4519  v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
4520  CHECK_EQ(111, foo0->Int32Value());
4521  v8::Handle<Value> z0 = global0->Get(v8_str("0"));
4522  CHECK_EQ(999, z0->Int32Value());
4523
4524  // Create another environment, should fail security checks.
4525  v8::HandleScope scope1;
4526
4527  v8::Persistent<Context> context1 =
4528    Context::New(NULL, global_template);
4529  context1->Enter();
4530
4531  v8::Handle<v8::Object> global1 = context1->Global();
4532  global1->Set(v8_str("othercontext"), global0);
4533  // This set will fail the security check.
4534  v8::Handle<Script> script1 =
4535    v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
4536  script1->Run();
4537  // This read will pass the security check.
4538  v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
4539  CHECK_EQ(111, foo1->Int32Value());
4540  // This read will pass the security check.
4541  v8::Handle<Value> z1 = global0->Get(v8_str("0"));
4542  CHECK_EQ(999, z1->Int32Value());
4543
4544  // Create another environment, should pass security checks.
4545  { g_security_callback_result = true;  // allow security handler to pass.
4546    v8::HandleScope scope2;
4547    LocalContext context2;
4548    v8::Handle<v8::Object> global2 = context2->Global();
4549    global2->Set(v8_str("othercontext"), global0);
4550    v8::Handle<Script> script2 =
4551        v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
4552    script2->Run();
4553    v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
4554    CHECK_EQ(333, foo2->Int32Value());
4555    v8::Handle<Value> z2 = global0->Get(v8_str("0"));
4556    CHECK_EQ(888, z2->Int32Value());
4557  }
4558
4559  context1->Exit();
4560  context1.Dispose();
4561
4562  context0->Exit();
4563  context0.Dispose();
4564}
4565
4566
4567THREADED_TEST(SecurityChecks) {
4568  v8::HandleScope handle_scope;
4569  LocalContext env1;
4570  v8::Persistent<Context> env2 = Context::New();
4571
4572  Local<Value> foo = v8_str("foo");
4573  Local<Value> bar = v8_str("bar");
4574
4575  // Set to the same domain.
4576  env1->SetSecurityToken(foo);
4577
4578  // Create a function in env1.
4579  Script::Compile(v8_str("spy=function(){return spy;}"))->Run();
4580  Local<Value> spy = env1->Global()->Get(v8_str("spy"));
4581  CHECK(spy->IsFunction());
4582
4583  // Create another function accessing global objects.
4584  Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run();
4585  Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
4586  CHECK(spy2->IsFunction());
4587
4588  // Switch to env2 in the same domain and invoke spy on env2.
4589  {
4590    env2->SetSecurityToken(foo);
4591    // Enter env2
4592    Context::Scope scope_env2(env2);
4593    Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
4594    CHECK(result->IsFunction());
4595  }
4596
4597  {
4598    env2->SetSecurityToken(bar);
4599    Context::Scope scope_env2(env2);
4600
4601    // Call cross_domain_call, it should throw an exception
4602    v8::TryCatch try_catch;
4603    Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
4604    CHECK(try_catch.HasCaught());
4605  }
4606
4607  env2.Dispose();
4608}
4609
4610
4611// Regression test case for issue 1183439.
4612THREADED_TEST(SecurityChecksForPrototypeChain) {
4613  v8::HandleScope scope;
4614  LocalContext current;
4615  v8::Persistent<Context> other = Context::New();
4616
4617  // Change context to be able to get to the Object function in the
4618  // other context without hitting the security checks.
4619  v8::Local<Value> other_object;
4620  { Context::Scope scope(other);
4621    other_object = other->Global()->Get(v8_str("Object"));
4622    other->Global()->Set(v8_num(42), v8_num(87));
4623  }
4624
4625  current->Global()->Set(v8_str("other"), other->Global());
4626  CHECK(v8_compile("other")->Run()->Equals(other->Global()));
4627
4628  // Make sure the security check fails here and we get an undefined
4629  // result instead of getting the Object function. Repeat in a loop
4630  // to make sure to exercise the IC code.
4631  v8::Local<Script> access_other0 = v8_compile("other.Object");
4632  v8::Local<Script> access_other1 = v8_compile("other[42]");
4633  for (int i = 0; i < 5; i++) {
4634    CHECK(!access_other0->Run()->Equals(other_object));
4635    CHECK(access_other0->Run()->IsUndefined());
4636    CHECK(!access_other1->Run()->Equals(v8_num(87)));
4637    CHECK(access_other1->Run()->IsUndefined());
4638  }
4639
4640  // Create an object that has 'other' in its prototype chain and make
4641  // sure we cannot access the Object function indirectly through
4642  // that. Repeat in a loop to make sure to exercise the IC code.
4643  v8_compile("function F() { };"
4644             "F.prototype = other;"
4645             "var f = new F();")->Run();
4646  v8::Local<Script> access_f0 = v8_compile("f.Object");
4647  v8::Local<Script> access_f1 = v8_compile("f[42]");
4648  for (int j = 0; j < 5; j++) {
4649    CHECK(!access_f0->Run()->Equals(other_object));
4650    CHECK(access_f0->Run()->IsUndefined());
4651    CHECK(!access_f1->Run()->Equals(v8_num(87)));
4652    CHECK(access_f1->Run()->IsUndefined());
4653  }
4654
4655  // Now it gets hairy: Set the prototype for the other global object
4656  // to be the current global object. The prototype chain for 'f' now
4657  // goes through 'other' but ends up in the current global object.
4658  { Context::Scope scope(other);
4659    other->Global()->Set(v8_str("__proto__"), current->Global());
4660  }
4661  // Set a named and an index property on the current global
4662  // object. To force the lookup to go through the other global object,
4663  // the properties must not exist in the other global object.
4664  current->Global()->Set(v8_str("foo"), v8_num(100));
4665  current->Global()->Set(v8_num(99), v8_num(101));
4666  // Try to read the properties from f and make sure that the access
4667  // gets stopped by the security checks on the other global object.
4668  Local<Script> access_f2 = v8_compile("f.foo");
4669  Local<Script> access_f3 = v8_compile("f[99]");
4670  for (int k = 0; k < 5; k++) {
4671    CHECK(!access_f2->Run()->Equals(v8_num(100)));
4672    CHECK(access_f2->Run()->IsUndefined());
4673    CHECK(!access_f3->Run()->Equals(v8_num(101)));
4674    CHECK(access_f3->Run()->IsUndefined());
4675  }
4676  other.Dispose();
4677}
4678
4679
4680THREADED_TEST(CrossDomainDelete) {
4681  v8::HandleScope handle_scope;
4682  LocalContext env1;
4683  v8::Persistent<Context> env2 = Context::New();
4684
4685  Local<Value> foo = v8_str("foo");
4686  Local<Value> bar = v8_str("bar");
4687
4688  // Set to the same domain.
4689  env1->SetSecurityToken(foo);
4690  env2->SetSecurityToken(foo);
4691
4692  env1->Global()->Set(v8_str("prop"), v8_num(3));
4693  env2->Global()->Set(v8_str("env1"), env1->Global());
4694
4695  // Change env2 to a different domain and delete env1.prop.
4696  env2->SetSecurityToken(bar);
4697  {
4698    Context::Scope scope_env2(env2);
4699    Local<Value> result =
4700        Script::Compile(v8_str("delete env1.prop"))->Run();
4701    CHECK(result->IsFalse());
4702  }
4703
4704  // Check that env1.prop still exists.
4705  Local<Value> v = env1->Global()->Get(v8_str("prop"));
4706  CHECK(v->IsNumber());
4707  CHECK_EQ(3, v->Int32Value());
4708
4709  env2.Dispose();
4710}
4711
4712
4713THREADED_TEST(CrossDomainIsPropertyEnumerable) {
4714  v8::HandleScope handle_scope;
4715  LocalContext env1;
4716  v8::Persistent<Context> env2 = Context::New();
4717
4718  Local<Value> foo = v8_str("foo");
4719  Local<Value> bar = v8_str("bar");
4720
4721  // Set to the same domain.
4722  env1->SetSecurityToken(foo);
4723  env2->SetSecurityToken(foo);
4724
4725  env1->Global()->Set(v8_str("prop"), v8_num(3));
4726  env2->Global()->Set(v8_str("env1"), env1->Global());
4727
4728  // env1.prop is enumerable in env2.
4729  Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
4730  {
4731    Context::Scope scope_env2(env2);
4732    Local<Value> result = Script::Compile(test)->Run();
4733    CHECK(result->IsTrue());
4734  }
4735
4736  // Change env2 to a different domain and test again.
4737  env2->SetSecurityToken(bar);
4738  {
4739    Context::Scope scope_env2(env2);
4740    Local<Value> result = Script::Compile(test)->Run();
4741    CHECK(result->IsFalse());
4742  }
4743
4744  env2.Dispose();
4745}
4746
4747
4748THREADED_TEST(CrossDomainForIn) {
4749  v8::HandleScope handle_scope;
4750  LocalContext env1;
4751  v8::Persistent<Context> env2 = Context::New();
4752
4753  Local<Value> foo = v8_str("foo");
4754  Local<Value> bar = v8_str("bar");
4755
4756  // Set to the same domain.
4757  env1->SetSecurityToken(foo);
4758  env2->SetSecurityToken(foo);
4759
4760  env1->Global()->Set(v8_str("prop"), v8_num(3));
4761  env2->Global()->Set(v8_str("env1"), env1->Global());
4762
4763  // Change env2 to a different domain and set env1's global object
4764  // as the __proto__ of an object in env2 and enumerate properties
4765  // in for-in. It shouldn't enumerate properties on env1's global
4766  // object.
4767  env2->SetSecurityToken(bar);
4768  {
4769    Context::Scope scope_env2(env2);
4770    Local<Value> result =
4771        CompileRun("(function(){var obj = {'__proto__':env1};"
4772                   "for (var p in obj)"
4773                   "   if (p == 'prop') return false;"
4774                   "return true;})()");
4775    CHECK(result->IsTrue());
4776  }
4777  env2.Dispose();
4778}
4779
4780
4781TEST(ContextDetachGlobal) {
4782  v8::HandleScope handle_scope;
4783  LocalContext env1;
4784  v8::Persistent<Context> env2 = Context::New();
4785
4786  Local<v8::Object> global1 = env1->Global();
4787
4788  Local<Value> foo = v8_str("foo");
4789
4790  // Set to the same domain.
4791  env1->SetSecurityToken(foo);
4792  env2->SetSecurityToken(foo);
4793
4794  // Enter env2
4795  env2->Enter();
4796
4797  // Create a function in env2 and add a reference to it in env1.
4798  Local<v8::Object> global2 = env2->Global();
4799  global2->Set(v8_str("prop"), v8::Integer::New(1));
4800  CompileRun("function getProp() {return prop;}");
4801
4802  env1->Global()->Set(v8_str("getProp"),
4803                      global2->Get(v8_str("getProp")));
4804
4805  // Detach env2's global, and reuse the global object of env2
4806  env2->Exit();
4807  env2->DetachGlobal();
4808  // env2 has a new global object.
4809  CHECK(!env2->Global()->Equals(global2));
4810
4811  v8::Persistent<Context> env3 =
4812      Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
4813  env3->SetSecurityToken(v8_str("bar"));
4814  env3->Enter();
4815
4816  Local<v8::Object> global3 = env3->Global();
4817  CHECK_EQ(global2, global3);
4818  CHECK(global3->Get(v8_str("prop"))->IsUndefined());
4819  CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
4820  global3->Set(v8_str("prop"), v8::Integer::New(-1));
4821  global3->Set(v8_str("prop2"), v8::Integer::New(2));
4822  env3->Exit();
4823
4824  // Call getProp in env1, and it should return the value 1
4825  {
4826    Local<Value> get_prop = global1->Get(v8_str("getProp"));
4827    CHECK(get_prop->IsFunction());
4828    v8::TryCatch try_catch;
4829    Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
4830    CHECK(!try_catch.HasCaught());
4831    CHECK_EQ(1, r->Int32Value());
4832  }
4833
4834  // Check that env3 is not accessible from env1
4835  {
4836    Local<Value> r = global3->Get(v8_str("prop2"));
4837    CHECK(r->IsUndefined());
4838  }
4839
4840  env2.Dispose();
4841  env3.Dispose();
4842}
4843
4844
4845TEST(DetachAndReattachGlobal) {
4846  v8::HandleScope scope;
4847  LocalContext env1;
4848
4849  // Create second environment.
4850  v8::Persistent<Context> env2 = Context::New();
4851
4852  Local<Value> foo = v8_str("foo");
4853
4854  // Set same security token for env1 and env2.
4855  env1->SetSecurityToken(foo);
4856  env2->SetSecurityToken(foo);
4857
4858  // Create a property on the global object in env2.
4859  {
4860    v8::Context::Scope scope(env2);
4861    env2->Global()->Set(v8_str("p"), v8::Integer::New(42));
4862  }
4863
4864  // Create a reference to env2 global from env1 global.
4865  env1->Global()->Set(v8_str("other"), env2->Global());
4866
4867  // Check that we have access to other.p in env2 from env1.
4868  Local<Value> result = CompileRun("other.p");
4869  CHECK(result->IsInt32());
4870  CHECK_EQ(42, result->Int32Value());
4871
4872  // Hold on to global from env2 and detach global from env2.
4873  Local<v8::Object> global2 = env2->Global();
4874  env2->DetachGlobal();
4875
4876  // Check that the global has been detached. No other.p property can
4877  // be found.
4878  result = CompileRun("other.p");
4879  CHECK(result->IsUndefined());
4880
4881  // Reuse global2 for env3.
4882  v8::Persistent<Context> env3 =
4883      Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
4884  CHECK_EQ(global2, env3->Global());
4885
4886  // Start by using the same security token for env3 as for env1 and env2.
4887  env3->SetSecurityToken(foo);
4888
4889  // Create a property on the global object in env3.
4890  {
4891    v8::Context::Scope scope(env3);
4892    env3->Global()->Set(v8_str("p"), v8::Integer::New(24));
4893  }
4894
4895  // Check that other.p is now the property in env3 and that we have access.
4896  result = CompileRun("other.p");
4897  CHECK(result->IsInt32());
4898  CHECK_EQ(24, result->Int32Value());
4899
4900  // Change security token for env3 to something different from env1 and env2.
4901  env3->SetSecurityToken(v8_str("bar"));
4902
4903  // Check that we do not have access to other.p in env1. |other| is now
4904  // the global object for env3 which has a different security token,
4905  // so access should be blocked.
4906  result = CompileRun("other.p");
4907  CHECK(result->IsUndefined());
4908
4909  // Detach the global for env3 and reattach it to env2.
4910  env3->DetachGlobal();
4911  env2->ReattachGlobal(global2);
4912
4913  // Check that we have access to other.p again in env1.  |other| is now
4914  // the global object for env2 which has the same security token as env1.
4915  result = CompileRun("other.p");
4916  CHECK(result->IsInt32());
4917  CHECK_EQ(42, result->Int32Value());
4918
4919  env2.Dispose();
4920  env3.Dispose();
4921}
4922
4923
4924static bool NamedAccessBlocker(Local<v8::Object> global,
4925                               Local<Value> name,
4926                               v8::AccessType type,
4927                               Local<Value> data) {
4928  return Context::GetCurrent()->Global()->Equals(global);
4929}
4930
4931
4932static bool IndexedAccessBlocker(Local<v8::Object> global,
4933                                 uint32_t key,
4934                                 v8::AccessType type,
4935                                 Local<Value> data) {
4936  return Context::GetCurrent()->Global()->Equals(global);
4937}
4938
4939
4940static int g_echo_value = -1;
4941static v8::Handle<Value> EchoGetter(Local<String> name,
4942                                    const AccessorInfo& info) {
4943  return v8_num(g_echo_value);
4944}
4945
4946
4947static void EchoSetter(Local<String> name,
4948                       Local<Value> value,
4949                       const AccessorInfo&) {
4950  if (value->IsNumber())
4951    g_echo_value = value->Int32Value();
4952}
4953
4954
4955static v8::Handle<Value> UnreachableGetter(Local<String> name,
4956                                           const AccessorInfo& info) {
4957  CHECK(false);  // This function should not be called..
4958  return v8::Undefined();
4959}
4960
4961
4962static void UnreachableSetter(Local<String>, Local<Value>,
4963                              const AccessorInfo&) {
4964  CHECK(false);  // This function should nto be called.
4965}
4966
4967
4968THREADED_TEST(AccessControl) {
4969  v8::HandleScope handle_scope;
4970  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
4971
4972  global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
4973                                           IndexedAccessBlocker);
4974
4975  // Add an accessor accessible by cross-domain JS code.
4976  global_template->SetAccessor(
4977      v8_str("accessible_prop"),
4978      EchoGetter, EchoSetter,
4979      v8::Handle<Value>(),
4980      v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
4981
4982  // Add an accessor that is not accessible by cross-domain JS code.
4983  global_template->SetAccessor(v8_str("blocked_prop"),
4984                               UnreachableGetter, UnreachableSetter,
4985                               v8::Handle<Value>(),
4986                               v8::DEFAULT);
4987
4988  // Create an environment
4989  v8::Persistent<Context> context0 = Context::New(NULL, global_template);
4990  context0->Enter();
4991
4992  v8::Handle<v8::Object> global0 = context0->Global();
4993
4994  v8::HandleScope scope1;
4995
4996  v8::Persistent<Context> context1 = Context::New();
4997  context1->Enter();
4998
4999  v8::Handle<v8::Object> global1 = context1->Global();
5000  global1->Set(v8_str("other"), global0);
5001
5002  v8::Handle<Value> value;
5003
5004  // Access blocked property
5005  value = v8_compile("other.blocked_prop = 1")->Run();
5006  value = v8_compile("other.blocked_prop")->Run();
5007  CHECK(value->IsUndefined());
5008
5009  value = v8_compile("propertyIsEnumerable.call(other, 'blocked_prop')")->Run();
5010  CHECK(value->IsFalse());
5011
5012  // Access accessible property
5013  value = v8_compile("other.accessible_prop = 3")->Run();
5014  CHECK(value->IsNumber());
5015  CHECK_EQ(3, value->Int32Value());
5016  CHECK_EQ(3, g_echo_value);
5017
5018  value = v8_compile("other.accessible_prop")->Run();
5019  CHECK(value->IsNumber());
5020  CHECK_EQ(3, value->Int32Value());
5021
5022  value =
5023    v8_compile("propertyIsEnumerable.call(other, 'accessible_prop')")->Run();
5024  CHECK(value->IsTrue());
5025
5026  // Enumeration doesn't enumerate accessors from inaccessible objects in
5027  // the prototype chain even if the accessors are in themselves accessible.
5028  Local<Value> result =
5029      CompileRun("(function(){var obj = {'__proto__':other};"
5030                 "for (var p in obj)"
5031                 "   if (p == 'accessible_prop' || p == 'blocked_prop') {"
5032                 "     return false;"
5033                 "   }"
5034                 "return true;})()");
5035  CHECK(result->IsTrue());
5036
5037  context1->Exit();
5038  context0->Exit();
5039  context1.Dispose();
5040  context0.Dispose();
5041}
5042
5043
5044static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
5045                                            Local<Value> name,
5046                                            v8::AccessType type,
5047                                            Local<Value> data) {
5048  return false;
5049}
5050
5051
5052static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
5053                                              uint32_t key,
5054                                              v8::AccessType type,
5055                                              Local<Value> data) {
5056  return false;
5057}
5058
5059
5060THREADED_TEST(AccessControlGetOwnPropertyNames) {
5061  v8::HandleScope handle_scope;
5062  v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
5063
5064  obj_template->Set(v8_str("x"), v8::Integer::New(42));
5065  obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
5066                                        GetOwnPropertyNamesIndexedBlocker);
5067
5068  // Create an environment
5069  v8::Persistent<Context> context0 = Context::New(NULL, obj_template);
5070  context0->Enter();
5071
5072  v8::Handle<v8::Object> global0 = context0->Global();
5073
5074  v8::HandleScope scope1;
5075
5076  v8::Persistent<Context> context1 = Context::New();
5077  context1->Enter();
5078
5079  v8::Handle<v8::Object> global1 = context1->Global();
5080  global1->Set(v8_str("other"), global0);
5081  global1->Set(v8_str("object"), obj_template->NewInstance());
5082
5083  v8::Handle<Value> value;
5084
5085  // Attempt to get the property names of the other global object and
5086  // of an object that requires access checks.  Accessing the other
5087  // global object should be blocked by access checks on the global
5088  // proxy object.  Accessing the object that requires access checks
5089  // is blocked by the access checks on the object itself.
5090  value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
5091  CHECK(value->IsTrue());
5092
5093  value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
5094  CHECK(value->IsTrue());
5095
5096  context1->Exit();
5097  context0->Exit();
5098  context1.Dispose();
5099  context0.Dispose();
5100}
5101
5102
5103static v8::Handle<v8::Array> NamedPropertyEnumerator(const AccessorInfo& info) {
5104  v8::Handle<v8::Array> result = v8::Array::New(1);
5105  result->Set(0, v8_str("x"));
5106  return result;
5107}
5108
5109
5110THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
5111  v8::HandleScope handle_scope;
5112  v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
5113
5114  obj_template->Set(v8_str("x"), v8::Integer::New(42));
5115  obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
5116                                        NamedPropertyEnumerator);
5117
5118  LocalContext context;
5119  v8::Handle<v8::Object> global = context->Global();
5120  global->Set(v8_str("object"), obj_template->NewInstance());
5121
5122  v8::Handle<Value> value =
5123      CompileRun("Object.getOwnPropertyNames(object).join(',')");
5124  CHECK_EQ(v8_str("x"), value);
5125}
5126
5127
5128static v8::Handle<Value> ConstTenGetter(Local<String> name,
5129                                        const AccessorInfo& info) {
5130  return v8_num(10);
5131}
5132
5133
5134THREADED_TEST(CrossDomainAccessors) {
5135  v8::HandleScope handle_scope;
5136
5137  v8::Handle<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
5138
5139  v8::Handle<v8::ObjectTemplate> global_template =
5140      func_template->InstanceTemplate();
5141
5142  v8::Handle<v8::ObjectTemplate> proto_template =
5143      func_template->PrototypeTemplate();
5144
5145  // Add an accessor to proto that's accessible by cross-domain JS code.
5146  proto_template->SetAccessor(v8_str("accessible"),
5147                              ConstTenGetter, 0,
5148                              v8::Handle<Value>(),
5149                              v8::ALL_CAN_READ);
5150
5151  // Add an accessor that is not accessible by cross-domain JS code.
5152  global_template->SetAccessor(v8_str("unreachable"),
5153                               UnreachableGetter, 0,
5154                               v8::Handle<Value>(),
5155                               v8::DEFAULT);
5156
5157  v8::Persistent<Context> context0 = Context::New(NULL, global_template);
5158  context0->Enter();
5159
5160  Local<v8::Object> global = context0->Global();
5161  // Add a normal property that shadows 'accessible'
5162  global->Set(v8_str("accessible"), v8_num(11));
5163
5164  // Enter a new context.
5165  v8::HandleScope scope1;
5166  v8::Persistent<Context> context1 = Context::New();
5167  context1->Enter();
5168
5169  v8::Handle<v8::Object> global1 = context1->Global();
5170  global1->Set(v8_str("other"), global);
5171
5172  // Should return 10, instead of 11
5173  v8::Handle<Value> value = v8_compile("other.accessible")->Run();
5174  CHECK(value->IsNumber());
5175  CHECK_EQ(10, value->Int32Value());
5176
5177  value = v8_compile("other.unreachable")->Run();
5178  CHECK(value->IsUndefined());
5179
5180  context1->Exit();
5181  context0->Exit();
5182  context1.Dispose();
5183  context0.Dispose();
5184}
5185
5186
5187static int named_access_count = 0;
5188static int indexed_access_count = 0;
5189
5190static bool NamedAccessCounter(Local<v8::Object> global,
5191                               Local<Value> name,
5192                               v8::AccessType type,
5193                               Local<Value> data) {
5194  named_access_count++;
5195  return true;
5196}
5197
5198
5199static bool IndexedAccessCounter(Local<v8::Object> global,
5200                                 uint32_t key,
5201                                 v8::AccessType type,
5202                                 Local<Value> data) {
5203  indexed_access_count++;
5204  return true;
5205}
5206
5207
5208// This one is too easily disturbed by other tests.
5209TEST(AccessControlIC) {
5210  named_access_count = 0;
5211  indexed_access_count = 0;
5212
5213  v8::HandleScope handle_scope;
5214
5215  // Create an environment.
5216  v8::Persistent<Context> context0 = Context::New();
5217  context0->Enter();
5218
5219  // Create an object that requires access-check functions to be
5220  // called for cross-domain access.
5221  v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
5222  object_template->SetAccessCheckCallbacks(NamedAccessCounter,
5223                                           IndexedAccessCounter);
5224  Local<v8::Object> object = object_template->NewInstance();
5225
5226  v8::HandleScope scope1;
5227
5228  // Create another environment.
5229  v8::Persistent<Context> context1 = Context::New();
5230  context1->Enter();
5231
5232  // Make easy access to the object from the other environment.
5233  v8::Handle<v8::Object> global1 = context1->Global();
5234  global1->Set(v8_str("obj"), object);
5235
5236  v8::Handle<Value> value;
5237
5238  // Check that the named access-control function is called every time.
5239  CompileRun("function testProp(obj) {"
5240             "  for (var i = 0; i < 10; i++) obj.prop = 1;"
5241             "  for (var j = 0; j < 10; j++) obj.prop;"
5242             "  return obj.prop"
5243             "}");
5244  value = CompileRun("testProp(obj)");
5245  CHECK(value->IsNumber());
5246  CHECK_EQ(1, value->Int32Value());
5247  CHECK_EQ(21, named_access_count);
5248
5249  // Check that the named access-control function is called every time.
5250  CompileRun("var p = 'prop';"
5251             "function testKeyed(obj) {"
5252             "  for (var i = 0; i < 10; i++) obj[p] = 1;"
5253             "  for (var j = 0; j < 10; j++) obj[p];"
5254             "  return obj[p];"
5255             "}");
5256  // Use obj which requires access checks.  No inline caching is used
5257  // in that case.
5258  value = CompileRun("testKeyed(obj)");
5259  CHECK(value->IsNumber());
5260  CHECK_EQ(1, value->Int32Value());
5261  CHECK_EQ(42, named_access_count);
5262  // Force the inline caches into generic state and try again.
5263  CompileRun("testKeyed({ a: 0 })");
5264  CompileRun("testKeyed({ b: 0 })");
5265  value = CompileRun("testKeyed(obj)");
5266  CHECK(value->IsNumber());
5267  CHECK_EQ(1, value->Int32Value());
5268  CHECK_EQ(63, named_access_count);
5269
5270  // Check that the indexed access-control function is called every time.
5271  CompileRun("function testIndexed(obj) {"
5272             "  for (var i = 0; i < 10; i++) obj[0] = 1;"
5273             "  for (var j = 0; j < 10; j++) obj[0];"
5274             "  return obj[0]"
5275             "}");
5276  value = CompileRun("testIndexed(obj)");
5277  CHECK(value->IsNumber());
5278  CHECK_EQ(1, value->Int32Value());
5279  CHECK_EQ(21, indexed_access_count);
5280  // Force the inline caches into generic state.
5281  CompileRun("testIndexed(new Array(1))");
5282  // Test that the indexed access check is called.
5283  value = CompileRun("testIndexed(obj)");
5284  CHECK(value->IsNumber());
5285  CHECK_EQ(1, value->Int32Value());
5286  CHECK_EQ(42, indexed_access_count);
5287
5288  // Check that the named access check is called when invoking
5289  // functions on an object that requires access checks.
5290  CompileRun("obj.f = function() {}");
5291  CompileRun("function testCallNormal(obj) {"
5292             "  for (var i = 0; i < 10; i++) obj.f();"
5293             "}");
5294  CompileRun("testCallNormal(obj)");
5295  CHECK_EQ(74, named_access_count);
5296
5297  // Force obj into slow case.
5298  value = CompileRun("delete obj.prop");
5299  CHECK(value->BooleanValue());
5300  // Force inline caches into dictionary probing mode.
5301  CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
5302  // Test that the named access check is called.
5303  value = CompileRun("testProp(obj);");
5304  CHECK(value->IsNumber());
5305  CHECK_EQ(1, value->Int32Value());
5306  CHECK_EQ(96, named_access_count);
5307
5308  // Force the call inline cache into dictionary probing mode.
5309  CompileRun("o.f = function() {}; testCallNormal(o)");
5310  // Test that the named access check is still called for each
5311  // invocation of the function.
5312  value = CompileRun("testCallNormal(obj)");
5313  CHECK_EQ(106, named_access_count);
5314
5315  context1->Exit();
5316  context0->Exit();
5317  context1.Dispose();
5318  context0.Dispose();
5319}
5320
5321
5322static bool NamedAccessFlatten(Local<v8::Object> global,
5323                               Local<Value> name,
5324                               v8::AccessType type,
5325                               Local<Value> data) {
5326  char buf[100];
5327  int len;
5328
5329  CHECK(name->IsString());
5330
5331  memset(buf, 0x1, sizeof(buf));
5332  len = name.As<String>()->WriteAscii(buf);
5333  CHECK_EQ(4, len);
5334
5335  uint16_t buf2[100];
5336
5337  memset(buf, 0x1, sizeof(buf));
5338  len = name.As<String>()->Write(buf2);
5339  CHECK_EQ(4, len);
5340
5341  return true;
5342}
5343
5344
5345static bool IndexedAccessFlatten(Local<v8::Object> global,
5346                                 uint32_t key,
5347                                 v8::AccessType type,
5348                                 Local<Value> data) {
5349  return true;
5350}
5351
5352
5353// Regression test.  In access checks, operations that may cause
5354// garbage collection are not allowed.  It used to be the case that
5355// using the Write operation on a string could cause a garbage
5356// collection due to flattening of the string.  This is no longer the
5357// case.
5358THREADED_TEST(AccessControlFlatten) {
5359  named_access_count = 0;
5360  indexed_access_count = 0;
5361
5362  v8::HandleScope handle_scope;
5363
5364  // Create an environment.
5365  v8::Persistent<Context> context0 = Context::New();
5366  context0->Enter();
5367
5368  // Create an object that requires access-check functions to be
5369  // called for cross-domain access.
5370  v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
5371  object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
5372                                           IndexedAccessFlatten);
5373  Local<v8::Object> object = object_template->NewInstance();
5374
5375  v8::HandleScope scope1;
5376
5377  // Create another environment.
5378  v8::Persistent<Context> context1 = Context::New();
5379  context1->Enter();
5380
5381  // Make easy access to the object from the other environment.
5382  v8::Handle<v8::Object> global1 = context1->Global();
5383  global1->Set(v8_str("obj"), object);
5384
5385  v8::Handle<Value> value;
5386
5387  value = v8_compile("var p = 'as' + 'df';")->Run();
5388  value = v8_compile("obj[p];")->Run();
5389
5390  context1->Exit();
5391  context0->Exit();
5392  context1.Dispose();
5393  context0.Dispose();
5394}
5395
5396
5397static v8::Handle<Value> AccessControlNamedGetter(
5398    Local<String>, const AccessorInfo&) {
5399  return v8::Integer::New(42);
5400}
5401
5402
5403static v8::Handle<Value> AccessControlNamedSetter(
5404    Local<String>, Local<Value> value, const AccessorInfo&) {
5405  return value;
5406}
5407
5408
5409static v8::Handle<Value> AccessControlIndexedGetter(
5410      uint32_t index,
5411      const AccessorInfo& info) {
5412  return v8_num(42);
5413}
5414
5415
5416static v8::Handle<Value> AccessControlIndexedSetter(
5417    uint32_t, Local<Value> value, const AccessorInfo&) {
5418  return value;
5419}
5420
5421
5422THREADED_TEST(AccessControlInterceptorIC) {
5423  named_access_count = 0;
5424  indexed_access_count = 0;
5425
5426  v8::HandleScope handle_scope;
5427
5428  // Create an environment.
5429  v8::Persistent<Context> context0 = Context::New();
5430  context0->Enter();
5431
5432  // Create an object that requires access-check functions to be
5433  // called for cross-domain access.  The object also has interceptors
5434  // interceptor.
5435  v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
5436  object_template->SetAccessCheckCallbacks(NamedAccessCounter,
5437                                           IndexedAccessCounter);
5438  object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
5439                                           AccessControlNamedSetter);
5440  object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
5441                                             AccessControlIndexedSetter);
5442  Local<v8::Object> object = object_template->NewInstance();
5443
5444  v8::HandleScope scope1;
5445
5446  // Create another environment.
5447  v8::Persistent<Context> context1 = Context::New();
5448  context1->Enter();
5449
5450  // Make easy access to the object from the other environment.
5451  v8::Handle<v8::Object> global1 = context1->Global();
5452  global1->Set(v8_str("obj"), object);
5453
5454  v8::Handle<Value> value;
5455
5456  // Check that the named access-control function is called every time
5457  // eventhough there is an interceptor on the object.
5458  value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
5459  value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
5460                     "obj.x")->Run();
5461  CHECK(value->IsNumber());
5462  CHECK_EQ(42, value->Int32Value());
5463  CHECK_EQ(21, named_access_count);
5464
5465  value = v8_compile("var p = 'x';")->Run();
5466  value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
5467  value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
5468                     "obj[p]")->Run();
5469  CHECK(value->IsNumber());
5470  CHECK_EQ(42, value->Int32Value());
5471  CHECK_EQ(42, named_access_count);
5472
5473  // Check that the indexed access-control function is called every
5474  // time eventhough there is an interceptor on the object.
5475  value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
5476  value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
5477                     "obj[0]")->Run();
5478  CHECK(value->IsNumber());
5479  CHECK_EQ(42, value->Int32Value());
5480  CHECK_EQ(21, indexed_access_count);
5481
5482  context1->Exit();
5483  context0->Exit();
5484  context1.Dispose();
5485  context0.Dispose();
5486}
5487
5488
5489THREADED_TEST(Version) {
5490  v8::V8::GetVersion();
5491}
5492
5493
5494static v8::Handle<Value> InstanceFunctionCallback(const v8::Arguments& args) {
5495  ApiTestFuzzer::Fuzz();
5496  return v8_num(12);
5497}
5498
5499
5500THREADED_TEST(InstanceProperties) {
5501  v8::HandleScope handle_scope;
5502  LocalContext context;
5503
5504  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
5505  Local<ObjectTemplate> instance = t->InstanceTemplate();
5506
5507  instance->Set(v8_str("x"), v8_num(42));
5508  instance->Set(v8_str("f"),
5509                v8::FunctionTemplate::New(InstanceFunctionCallback));
5510
5511  Local<Value> o = t->GetFunction()->NewInstance();
5512
5513  context->Global()->Set(v8_str("i"), o);
5514  Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
5515  CHECK_EQ(42, value->Int32Value());
5516
5517  value = Script::Compile(v8_str("i.f()"))->Run();
5518  CHECK_EQ(12, value->Int32Value());
5519}
5520
5521
5522static v8::Handle<Value>
5523GlobalObjectInstancePropertiesGet(Local<String> key, const AccessorInfo&) {
5524  ApiTestFuzzer::Fuzz();
5525  return v8::Handle<Value>();
5526}
5527
5528
5529THREADED_TEST(GlobalObjectInstanceProperties) {
5530  v8::HandleScope handle_scope;
5531
5532  Local<Value> global_object;
5533
5534  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
5535  t->InstanceTemplate()->SetNamedPropertyHandler(
5536      GlobalObjectInstancePropertiesGet);
5537  Local<ObjectTemplate> instance_template = t->InstanceTemplate();
5538  instance_template->Set(v8_str("x"), v8_num(42));
5539  instance_template->Set(v8_str("f"),
5540                         v8::FunctionTemplate::New(InstanceFunctionCallback));
5541
5542  {
5543    LocalContext env(NULL, instance_template);
5544    // Hold on to the global object so it can be used again in another
5545    // environment initialization.
5546    global_object = env->Global();
5547
5548    Local<Value> value = Script::Compile(v8_str("x"))->Run();
5549    CHECK_EQ(42, value->Int32Value());
5550    value = Script::Compile(v8_str("f()"))->Run();
5551    CHECK_EQ(12, value->Int32Value());
5552  }
5553
5554  {
5555    // Create new environment reusing the global object.
5556    LocalContext env(NULL, instance_template, global_object);
5557    Local<Value> value = Script::Compile(v8_str("x"))->Run();
5558    CHECK_EQ(42, value->Int32Value());
5559    value = Script::Compile(v8_str("f()"))->Run();
5560    CHECK_EQ(12, value->Int32Value());
5561  }
5562}
5563
5564
5565static v8::Handle<Value> ShadowFunctionCallback(const v8::Arguments& args) {
5566  ApiTestFuzzer::Fuzz();
5567  return v8_num(42);
5568}
5569
5570
5571static int shadow_y;
5572static int shadow_y_setter_call_count;
5573static int shadow_y_getter_call_count;
5574
5575
5576static void ShadowYSetter(Local<String>, Local<Value>, const AccessorInfo&) {
5577  shadow_y_setter_call_count++;
5578  shadow_y = 42;
5579}
5580
5581
5582static v8::Handle<Value> ShadowYGetter(Local<String> name,
5583                                       const AccessorInfo& info) {
5584  ApiTestFuzzer::Fuzz();
5585  shadow_y_getter_call_count++;
5586  return v8_num(shadow_y);
5587}
5588
5589
5590static v8::Handle<Value> ShadowIndexedGet(uint32_t index,
5591                                          const AccessorInfo& info) {
5592  return v8::Handle<Value>();
5593}
5594
5595
5596static v8::Handle<Value> ShadowNamedGet(Local<String> key,
5597                                        const AccessorInfo&) {
5598  return v8::Handle<Value>();
5599}
5600
5601
5602THREADED_TEST(ShadowObject) {
5603  shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
5604  v8::HandleScope handle_scope;
5605
5606  Local<ObjectTemplate> global_template = v8::ObjectTemplate::New();
5607  LocalContext context(NULL, global_template);
5608
5609  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
5610  t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
5611  t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
5612  Local<ObjectTemplate> proto = t->PrototypeTemplate();
5613  Local<ObjectTemplate> instance = t->InstanceTemplate();
5614
5615  // Only allow calls of f on instances of t.
5616  Local<v8::Signature> signature = v8::Signature::New(t);
5617  proto->Set(v8_str("f"),
5618             v8::FunctionTemplate::New(ShadowFunctionCallback,
5619                                       Local<Value>(),
5620                                       signature));
5621  proto->Set(v8_str("x"), v8_num(12));
5622
5623  instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
5624
5625  Local<Value> o = t->GetFunction()->NewInstance();
5626  context->Global()->Set(v8_str("__proto__"), o);
5627
5628  Local<Value> value =
5629      Script::Compile(v8_str("propertyIsEnumerable(0)"))->Run();
5630  CHECK(value->IsBoolean());
5631  CHECK(!value->BooleanValue());
5632
5633  value = Script::Compile(v8_str("x"))->Run();
5634  CHECK_EQ(12, value->Int32Value());
5635
5636  value = Script::Compile(v8_str("f()"))->Run();
5637  CHECK_EQ(42, value->Int32Value());
5638
5639  Script::Compile(v8_str("y = 42"))->Run();
5640  CHECK_EQ(1, shadow_y_setter_call_count);
5641  value = Script::Compile(v8_str("y"))->Run();
5642  CHECK_EQ(1, shadow_y_getter_call_count);
5643  CHECK_EQ(42, value->Int32Value());
5644}
5645
5646
5647THREADED_TEST(HiddenPrototype) {
5648  v8::HandleScope handle_scope;
5649  LocalContext context;
5650
5651  Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
5652  t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
5653  Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
5654  t1->SetHiddenPrototype(true);
5655  t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
5656  Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
5657  t2->SetHiddenPrototype(true);
5658  t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
5659  Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
5660  t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
5661
5662  Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
5663  Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
5664  Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
5665  Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
5666
5667  // Setting the prototype on an object skips hidden prototypes.
5668  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5669  o0->Set(v8_str("__proto__"), o1);
5670  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5671  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
5672  o0->Set(v8_str("__proto__"), o2);
5673  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5674  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
5675  CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
5676  o0->Set(v8_str("__proto__"), o3);
5677  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5678  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
5679  CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
5680  CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
5681
5682  // Getting the prototype of o0 should get the first visible one
5683  // which is o3.  Therefore, z should not be defined on the prototype
5684  // object.
5685  Local<Value> proto = o0->Get(v8_str("__proto__"));
5686  CHECK(proto->IsObject());
5687  CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
5688}
5689
5690
5691THREADED_TEST(SetPrototype) {
5692  v8::HandleScope handle_scope;
5693  LocalContext context;
5694
5695  Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
5696  t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
5697  Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
5698  t1->SetHiddenPrototype(true);
5699  t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
5700  Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
5701  t2->SetHiddenPrototype(true);
5702  t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
5703  Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
5704  t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
5705
5706  Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
5707  Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
5708  Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
5709  Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
5710
5711  // Setting the prototype on an object does not skip hidden prototypes.
5712  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5713  CHECK(o0->SetPrototype(o1));
5714  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5715  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
5716  CHECK(o1->SetPrototype(o2));
5717  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5718  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
5719  CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
5720  CHECK(o2->SetPrototype(o3));
5721  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5722  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
5723  CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
5724  CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
5725
5726  // Getting the prototype of o0 should get the first visible one
5727  // which is o3.  Therefore, z should not be defined on the prototype
5728  // object.
5729  Local<Value> proto = o0->Get(v8_str("__proto__"));
5730  CHECK(proto->IsObject());
5731  CHECK_EQ(proto.As<v8::Object>(), o3);
5732
5733  // However, Object::GetPrototype ignores hidden prototype.
5734  Local<Value> proto0 = o0->GetPrototype();
5735  CHECK(proto0->IsObject());
5736  CHECK_EQ(proto0.As<v8::Object>(), o1);
5737
5738  Local<Value> proto1 = o1->GetPrototype();
5739  CHECK(proto1->IsObject());
5740  CHECK_EQ(proto1.As<v8::Object>(), o2);
5741
5742  Local<Value> proto2 = o2->GetPrototype();
5743  CHECK(proto2->IsObject());
5744  CHECK_EQ(proto2.As<v8::Object>(), o3);
5745}
5746
5747
5748THREADED_TEST(SetPrototypeThrows) {
5749  v8::HandleScope handle_scope;
5750  LocalContext context;
5751
5752  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
5753
5754  Local<v8::Object> o0 = t->GetFunction()->NewInstance();
5755  Local<v8::Object> o1 = t->GetFunction()->NewInstance();
5756
5757  CHECK(o0->SetPrototype(o1));
5758  // If setting the prototype leads to the cycle, SetPrototype should
5759  // return false and keep VM in sane state.
5760  v8::TryCatch try_catch;
5761  CHECK(!o1->SetPrototype(o0));
5762  CHECK(!try_catch.HasCaught());
5763  ASSERT(!i::Top::has_pending_exception());
5764
5765  CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
5766}
5767
5768
5769THREADED_TEST(GetterSetterExceptions) {
5770  v8::HandleScope handle_scope;
5771  LocalContext context;
5772  CompileRun(
5773    "function Foo() { };"
5774    "function Throw() { throw 5; };"
5775    "var x = { };"
5776    "x.__defineSetter__('set', Throw);"
5777    "x.__defineGetter__('get', Throw);");
5778  Local<v8::Object> x =
5779      Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
5780  v8::TryCatch try_catch;
5781  x->Set(v8_str("set"), v8::Integer::New(8));
5782  x->Get(v8_str("get"));
5783  x->Set(v8_str("set"), v8::Integer::New(8));
5784  x->Get(v8_str("get"));
5785  x->Set(v8_str("set"), v8::Integer::New(8));
5786  x->Get(v8_str("get"));
5787  x->Set(v8_str("set"), v8::Integer::New(8));
5788  x->Get(v8_str("get"));
5789}
5790
5791
5792THREADED_TEST(Constructor) {
5793  v8::HandleScope handle_scope;
5794  LocalContext context;
5795  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
5796  templ->SetClassName(v8_str("Fun"));
5797  Local<Function> cons = templ->GetFunction();
5798  context->Global()->Set(v8_str("Fun"), cons);
5799  Local<v8::Object> inst = cons->NewInstance();
5800  i::Handle<i::JSObject> obj = v8::Utils::OpenHandle(*inst);
5801  Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
5802  CHECK(value->BooleanValue());
5803}
5804
5805THREADED_TEST(FunctionDescriptorException) {
5806  v8::HandleScope handle_scope;
5807  LocalContext context;
5808  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
5809  templ->SetClassName(v8_str("Fun"));
5810  Local<Function> cons = templ->GetFunction();
5811  context->Global()->Set(v8_str("Fun"), cons);
5812  Local<Value> value = CompileRun(
5813    "function test() {"
5814    "  try {"
5815    "    (new Fun()).blah()"
5816    "  } catch (e) {"
5817    "    var str = String(e);"
5818    "    if (str.indexOf('TypeError') == -1) return 1;"
5819    "    if (str.indexOf('[object Fun]') != -1) return 2;"
5820    "    if (str.indexOf('#<a Fun>') == -1) return 3;"
5821    "    return 0;"
5822    "  }"
5823    "  return 4;"
5824    "}"
5825    "test();");
5826  CHECK_EQ(0, value->Int32Value());
5827}
5828
5829
5830THREADED_TEST(EvalAliasedDynamic) {
5831  v8::HandleScope scope;
5832  LocalContext current;
5833
5834  // Tests where aliased eval can only be resolved dynamically.
5835  Local<Script> script =
5836      Script::Compile(v8_str("function f(x) { "
5837                             "  var foo = 2;"
5838                             "  with (x) { return eval('foo'); }"
5839                             "}"
5840                             "foo = 0;"
5841                             "result1 = f(new Object());"
5842                             "result2 = f(this);"
5843                             "var x = new Object();"
5844                             "x.eval = function(x) { return 1; };"
5845                             "result3 = f(x);"));
5846  script->Run();
5847  CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
5848  CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
5849  CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
5850
5851  v8::TryCatch try_catch;
5852  script =
5853    Script::Compile(v8_str("function f(x) { "
5854                           "  var bar = 2;"
5855                           "  with (x) { return eval('bar'); }"
5856                           "}"
5857                           "f(this)"));
5858  script->Run();
5859  CHECK(try_catch.HasCaught());
5860  try_catch.Reset();
5861}
5862
5863
5864THREADED_TEST(CrossEval) {
5865  v8::HandleScope scope;
5866  LocalContext other;
5867  LocalContext current;
5868
5869  Local<String> token = v8_str("<security token>");
5870  other->SetSecurityToken(token);
5871  current->SetSecurityToken(token);
5872
5873  // Setup reference from current to other.
5874  current->Global()->Set(v8_str("other"), other->Global());
5875
5876  // Check that new variables are introduced in other context.
5877  Local<Script> script =
5878      Script::Compile(v8_str("other.eval('var foo = 1234')"));
5879  script->Run();
5880  Local<Value> foo = other->Global()->Get(v8_str("foo"));
5881  CHECK_EQ(1234, foo->Int32Value());
5882  CHECK(!current->Global()->Has(v8_str("foo")));
5883
5884  // Check that writing to non-existing properties introduces them in
5885  // the other context.
5886  script =
5887      Script::Compile(v8_str("other.eval('na = 1234')"));
5888  script->Run();
5889  CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
5890  CHECK(!current->Global()->Has(v8_str("na")));
5891
5892  // Check that global variables in current context are not visible in other
5893  // context.
5894  v8::TryCatch try_catch;
5895  script =
5896      Script::Compile(v8_str("var bar = 42; other.eval('bar');"));
5897  Local<Value> result = script->Run();
5898  CHECK(try_catch.HasCaught());
5899  try_catch.Reset();
5900
5901  // Check that local variables in current context are not visible in other
5902  // context.
5903  script =
5904      Script::Compile(v8_str("(function() { "
5905                             "  var baz = 87;"
5906                             "  return other.eval('baz');"
5907                             "})();"));
5908  result = script->Run();
5909  CHECK(try_catch.HasCaught());
5910  try_catch.Reset();
5911
5912  // Check that global variables in the other environment are visible
5913  // when evaluting code.
5914  other->Global()->Set(v8_str("bis"), v8_num(1234));
5915  script = Script::Compile(v8_str("other.eval('bis')"));
5916  CHECK_EQ(1234, script->Run()->Int32Value());
5917  CHECK(!try_catch.HasCaught());
5918
5919  // Check that the 'this' pointer points to the global object evaluating
5920  // code.
5921  other->Global()->Set(v8_str("t"), other->Global());
5922  script = Script::Compile(v8_str("other.eval('this == t')"));
5923  result = script->Run();
5924  CHECK(result->IsTrue());
5925  CHECK(!try_catch.HasCaught());
5926
5927  // Check that variables introduced in with-statement are not visible in
5928  // other context.
5929  script =
5930      Script::Compile(v8_str("with({x:2}){other.eval('x')}"));
5931  result = script->Run();
5932  CHECK(try_catch.HasCaught());
5933  try_catch.Reset();
5934
5935  // Check that you cannot use 'eval.call' with another object than the
5936  // current global object.
5937  script =
5938      Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')"));
5939  result = script->Run();
5940  CHECK(try_catch.HasCaught());
5941}
5942
5943
5944// Test that calling eval in a context which has been detached from
5945// its global throws an exception.  This behavior is consistent with
5946// other JavaScript implementations.
5947THREADED_TEST(EvalInDetachedGlobal) {
5948  v8::HandleScope scope;
5949
5950  v8::Persistent<Context> context0 = Context::New();
5951  v8::Persistent<Context> context1 = Context::New();
5952
5953  // Setup function in context0 that uses eval from context0.
5954  context0->Enter();
5955  v8::Handle<v8::Value> fun =
5956      CompileRun("var x = 42;"
5957                 "(function() {"
5958                 "  var e = eval;"
5959                 "  return function(s) { return e(s); }"
5960                 "})()");
5961  context0->Exit();
5962
5963  // Put the function into context1 and call it before and after
5964  // detaching the global.  Before detaching, the call succeeds and
5965  // after detaching and exception is thrown.
5966  context1->Enter();
5967  context1->Global()->Set(v8_str("fun"), fun);
5968  v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
5969  CHECK_EQ(42, x_value->Int32Value());
5970  context0->DetachGlobal();
5971  v8::TryCatch catcher;
5972  x_value = CompileRun("fun('x')");
5973  CHECK(x_value.IsEmpty());
5974  CHECK(catcher.HasCaught());
5975  context1->Exit();
5976
5977  context1.Dispose();
5978  context0.Dispose();
5979}
5980
5981
5982THREADED_TEST(CrossLazyLoad) {
5983  v8::HandleScope scope;
5984  LocalContext other;
5985  LocalContext current;
5986
5987  Local<String> token = v8_str("<security token>");
5988  other->SetSecurityToken(token);
5989  current->SetSecurityToken(token);
5990
5991  // Setup reference from current to other.
5992  current->Global()->Set(v8_str("other"), other->Global());
5993
5994  // Trigger lazy loading in other context.
5995  Local<Script> script =
5996      Script::Compile(v8_str("other.eval('new Date(42)')"));
5997  Local<Value> value = script->Run();
5998  CHECK_EQ(42.0, value->NumberValue());
5999}
6000
6001
6002static v8::Handle<Value> call_as_function(const v8::Arguments& args) {
6003  ApiTestFuzzer::Fuzz();
6004  if (args.IsConstructCall()) {
6005    if (args[0]->IsInt32()) {
6006       return v8_num(-args[0]->Int32Value());
6007    }
6008  }
6009
6010  return args[0];
6011}
6012
6013
6014// Test that a call handler can be set for objects which will allow
6015// non-function objects created through the API to be called as
6016// functions.
6017THREADED_TEST(CallAsFunction) {
6018  v8::HandleScope scope;
6019  LocalContext context;
6020
6021  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6022  Local<ObjectTemplate> instance_template = t->InstanceTemplate();
6023  instance_template->SetCallAsFunctionHandler(call_as_function);
6024  Local<v8::Object> instance = t->GetFunction()->NewInstance();
6025  context->Global()->Set(v8_str("obj"), instance);
6026  v8::TryCatch try_catch;
6027  Local<Value> value;
6028  CHECK(!try_catch.HasCaught());
6029
6030  value = CompileRun("obj(42)");
6031  CHECK(!try_catch.HasCaught());
6032  CHECK_EQ(42, value->Int32Value());
6033
6034  value = CompileRun("(function(o){return o(49)})(obj)");
6035  CHECK(!try_catch.HasCaught());
6036  CHECK_EQ(49, value->Int32Value());
6037
6038  // test special case of call as function
6039  value = CompileRun("[obj]['0'](45)");
6040  CHECK(!try_catch.HasCaught());
6041  CHECK_EQ(45, value->Int32Value());
6042
6043  value = CompileRun("obj.call = Function.prototype.call;"
6044                     "obj.call(null, 87)");
6045  CHECK(!try_catch.HasCaught());
6046  CHECK_EQ(87, value->Int32Value());
6047
6048  // Regression tests for bug #1116356: Calling call through call/apply
6049  // must work for non-function receivers.
6050  const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
6051  value = CompileRun(apply_99);
6052  CHECK(!try_catch.HasCaught());
6053  CHECK_EQ(99, value->Int32Value());
6054
6055  const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
6056  value = CompileRun(call_17);
6057  CHECK(!try_catch.HasCaught());
6058  CHECK_EQ(17, value->Int32Value());
6059
6060  // Check that the call-as-function handler can be called through
6061  // new.
6062  value = CompileRun("new obj(43)");
6063  CHECK(!try_catch.HasCaught());
6064  CHECK_EQ(-43, value->Int32Value());
6065}
6066
6067
6068static int CountHandles() {
6069  return v8::HandleScope::NumberOfHandles();
6070}
6071
6072
6073static int Recurse(int depth, int iterations) {
6074  v8::HandleScope scope;
6075  if (depth == 0) return CountHandles();
6076  for (int i = 0; i < iterations; i++) {
6077    Local<v8::Number> n = v8::Integer::New(42);
6078  }
6079  return Recurse(depth - 1, iterations);
6080}
6081
6082
6083THREADED_TEST(HandleIteration) {
6084  static const int kIterations = 500;
6085  static const int kNesting = 200;
6086  CHECK_EQ(0, CountHandles());
6087  {
6088    v8::HandleScope scope1;
6089    CHECK_EQ(0, CountHandles());
6090    for (int i = 0; i < kIterations; i++) {
6091      Local<v8::Number> n = v8::Integer::New(42);
6092      CHECK_EQ(i + 1, CountHandles());
6093    }
6094
6095    CHECK_EQ(kIterations, CountHandles());
6096    {
6097      v8::HandleScope scope2;
6098      for (int j = 0; j < kIterations; j++) {
6099        Local<v8::Number> n = v8::Integer::New(42);
6100        CHECK_EQ(j + 1 + kIterations, CountHandles());
6101      }
6102    }
6103    CHECK_EQ(kIterations, CountHandles());
6104  }
6105  CHECK_EQ(0, CountHandles());
6106  CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations));
6107}
6108
6109
6110static v8::Handle<Value> InterceptorHasOwnPropertyGetter(
6111    Local<String> name,
6112    const AccessorInfo& info) {
6113  ApiTestFuzzer::Fuzz();
6114  return v8::Handle<Value>();
6115}
6116
6117
6118THREADED_TEST(InterceptorHasOwnProperty) {
6119  v8::HandleScope scope;
6120  LocalContext context;
6121  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6122  Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
6123  instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
6124  Local<Function> function = fun_templ->GetFunction();
6125  context->Global()->Set(v8_str("constructor"), function);
6126  v8::Handle<Value> value = CompileRun(
6127      "var o = new constructor();"
6128      "o.hasOwnProperty('ostehaps');");
6129  CHECK_EQ(false, value->BooleanValue());
6130  value = CompileRun(
6131      "o.ostehaps = 42;"
6132      "o.hasOwnProperty('ostehaps');");
6133  CHECK_EQ(true, value->BooleanValue());
6134  value = CompileRun(
6135      "var p = new constructor();"
6136      "p.hasOwnProperty('ostehaps');");
6137  CHECK_EQ(false, value->BooleanValue());
6138}
6139
6140
6141static v8::Handle<Value> InterceptorHasOwnPropertyGetterGC(
6142    Local<String> name,
6143    const AccessorInfo& info) {
6144  ApiTestFuzzer::Fuzz();
6145  i::Heap::CollectAllGarbage(false);
6146  return v8::Handle<Value>();
6147}
6148
6149
6150THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
6151  v8::HandleScope scope;
6152  LocalContext context;
6153  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6154  Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
6155  instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
6156  Local<Function> function = fun_templ->GetFunction();
6157  context->Global()->Set(v8_str("constructor"), function);
6158  // Let's first make some stuff so we can be sure to get a good GC.
6159  CompileRun(
6160      "function makestr(size) {"
6161      "  switch (size) {"
6162      "    case 1: return 'f';"
6163      "    case 2: return 'fo';"
6164      "    case 3: return 'foo';"
6165      "  }"
6166      "  return makestr(size >> 1) + makestr((size + 1) >> 1);"
6167      "}"
6168      "var x = makestr(12345);"
6169      "x = makestr(31415);"
6170      "x = makestr(23456);");
6171  v8::Handle<Value> value = CompileRun(
6172      "var o = new constructor();"
6173      "o.__proto__ = new String(x);"
6174      "o.hasOwnProperty('ostehaps');");
6175  CHECK_EQ(false, value->BooleanValue());
6176}
6177
6178
6179typedef v8::Handle<Value> (*NamedPropertyGetter)(Local<String> property,
6180                                                 const AccessorInfo& info);
6181
6182
6183static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
6184                                   const char* source,
6185                                   int expected) {
6186  v8::HandleScope scope;
6187  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6188  templ->SetNamedPropertyHandler(getter);
6189  LocalContext context;
6190  context->Global()->Set(v8_str("o"), templ->NewInstance());
6191  v8::Handle<Value> value = CompileRun(source);
6192  CHECK_EQ(expected, value->Int32Value());
6193}
6194
6195
6196static v8::Handle<Value> InterceptorLoadICGetter(Local<String> name,
6197                                                 const AccessorInfo& info) {
6198  ApiTestFuzzer::Fuzz();
6199  CHECK(v8_str("x")->Equals(name));
6200  return v8::Integer::New(42);
6201}
6202
6203
6204// This test should hit the load IC for the interceptor case.
6205THREADED_TEST(InterceptorLoadIC) {
6206  CheckInterceptorLoadIC(InterceptorLoadICGetter,
6207    "var result = 0;"
6208    "for (var i = 0; i < 1000; i++) {"
6209    "  result = o.x;"
6210    "}",
6211    42);
6212}
6213
6214
6215// Below go several tests which verify that JITing for various
6216// configurations of interceptor and explicit fields works fine
6217// (those cases are special cased to get better performance).
6218
6219static v8::Handle<Value> InterceptorLoadXICGetter(Local<String> name,
6220                                                 const AccessorInfo& info) {
6221  ApiTestFuzzer::Fuzz();
6222  return v8_str("x")->Equals(name)
6223      ? v8::Integer::New(42) : v8::Handle<v8::Value>();
6224}
6225
6226
6227THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
6228  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6229    "var result = 0;"
6230    "o.y = 239;"
6231    "for (var i = 0; i < 1000; i++) {"
6232    "  result = o.y;"
6233    "}",
6234    239);
6235}
6236
6237
6238THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
6239  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6240    "var result = 0;"
6241    "o.__proto__ = { 'y': 239 };"
6242    "for (var i = 0; i < 1000; i++) {"
6243    "  result = o.y + o.x;"
6244    "}",
6245    239 + 42);
6246}
6247
6248
6249THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
6250  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6251    "var result = 0;"
6252    "o.__proto__.y = 239;"
6253    "for (var i = 0; i < 1000; i++) {"
6254    "  result = o.y + o.x;"
6255    "}",
6256    239 + 42);
6257}
6258
6259
6260THREADED_TEST(InterceptorLoadICUndefined) {
6261  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6262    "var result = 0;"
6263    "for (var i = 0; i < 1000; i++) {"
6264    "  result = (o.y == undefined) ? 239 : 42;"
6265    "}",
6266    239);
6267}
6268
6269
6270THREADED_TEST(InterceptorLoadICWithOverride) {
6271  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6272    "fst = new Object();  fst.__proto__ = o;"
6273    "snd = new Object();  snd.__proto__ = fst;"
6274    "var result1 = 0;"
6275    "for (var i = 0; i < 1000;  i++) {"
6276    "  result1 = snd.x;"
6277    "}"
6278    "fst.x = 239;"
6279    "var result = 0;"
6280    "for (var i = 0; i < 1000; i++) {"
6281    "  result = snd.x;"
6282    "}"
6283    "result + result1",
6284    239 + 42);
6285}
6286
6287
6288// Test the case when we stored field into
6289// a stub, but interceptor produced value on its own.
6290THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
6291  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6292    "proto = new Object();"
6293    "o.__proto__ = proto;"
6294    "proto.x = 239;"
6295    "for (var i = 0; i < 1000; i++) {"
6296    "  o.x;"
6297    // Now it should be ICed and keep a reference to x defined on proto
6298    "}"
6299    "var result = 0;"
6300    "for (var i = 0; i < 1000; i++) {"
6301    "  result += o.x;"
6302    "}"
6303    "result;",
6304    42 * 1000);
6305}
6306
6307
6308// Test the case when we stored field into
6309// a stub, but it got invalidated later on.
6310THREADED_TEST(InterceptorLoadICInvalidatedField) {
6311  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6312    "proto1 = new Object();"
6313    "proto2 = new Object();"
6314    "o.__proto__ = proto1;"
6315    "proto1.__proto__ = proto2;"
6316    "proto2.y = 239;"
6317    "for (var i = 0; i < 1000; i++) {"
6318    "  o.y;"
6319    // Now it should be ICed and keep a reference to y defined on proto2
6320    "}"
6321    "proto1.y = 42;"
6322    "var result = 0;"
6323    "for (var i = 0; i < 1000; i++) {"
6324    "  result += o.y;"
6325    "}"
6326    "result;",
6327    42 * 1000);
6328}
6329
6330
6331static int interceptor_load_not_handled_calls = 0;
6332static v8::Handle<Value> InterceptorLoadNotHandled(Local<String> name,
6333                                                   const AccessorInfo& info) {
6334  ++interceptor_load_not_handled_calls;
6335  return v8::Handle<v8::Value>();
6336}
6337
6338
6339// Test how post-interceptor lookups are done in the non-cacheable
6340// case: the interceptor should not be invoked during this lookup.
6341THREADED_TEST(InterceptorLoadICPostInterceptor) {
6342  interceptor_load_not_handled_calls = 0;
6343  CheckInterceptorLoadIC(InterceptorLoadNotHandled,
6344    "receiver = new Object();"
6345    "receiver.__proto__ = o;"
6346    "proto = new Object();"
6347    "/* Make proto a slow-case object. */"
6348    "for (var i = 0; i < 1000; i++) {"
6349    "  proto[\"xxxxxxxx\" + i] = [];"
6350    "}"
6351    "proto.x = 17;"
6352    "o.__proto__ = proto;"
6353    "var result = 0;"
6354    "for (var i = 0; i < 1000; i++) {"
6355    "  result += receiver.x;"
6356    "}"
6357    "result;",
6358    17 * 1000);
6359  CHECK_EQ(1000, interceptor_load_not_handled_calls);
6360}
6361
6362
6363// Test the case when we stored field into
6364// a stub, but it got invalidated later on due to override on
6365// global object which is between interceptor and fields' holders.
6366THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
6367  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6368    "o.__proto__ = this;"  // set a global to be a proto of o.
6369    "this.__proto__.y = 239;"
6370    "for (var i = 0; i < 10; i++) {"
6371    "  if (o.y != 239) throw 'oops: ' + o.y;"
6372    // Now it should be ICed and keep a reference to y defined on field_holder.
6373    "}"
6374    "this.y = 42;"  // Assign on a global.
6375    "var result = 0;"
6376    "for (var i = 0; i < 10; i++) {"
6377    "  result += o.y;"
6378    "}"
6379    "result;",
6380    42 * 10);
6381}
6382
6383
6384static v8::Handle<Value> Return239(Local<String> name, const AccessorInfo&) {
6385  ApiTestFuzzer::Fuzz();
6386  return v8_num(239);
6387}
6388
6389
6390static void SetOnThis(Local<String> name,
6391                      Local<Value> value,
6392                      const AccessorInfo& info) {
6393  info.This()->ForceSet(name, value);
6394}
6395
6396
6397THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
6398  v8::HandleScope scope;
6399  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6400  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6401  templ->SetAccessor(v8_str("y"), Return239);
6402  LocalContext context;
6403  context->Global()->Set(v8_str("o"), templ->NewInstance());
6404
6405  // Check the case when receiver and interceptor's holder
6406  // are the same objects.
6407  v8::Handle<Value> value = CompileRun(
6408      "var result = 0;"
6409      "for (var i = 0; i < 7; i++) {"
6410      "  result = o.y;"
6411      "}");
6412  CHECK_EQ(239, value->Int32Value());
6413
6414  // Check the case when interceptor's holder is in proto chain
6415  // of receiver.
6416  value = CompileRun(
6417      "r = { __proto__: o };"
6418      "var result = 0;"
6419      "for (var i = 0; i < 7; i++) {"
6420      "  result = r.y;"
6421      "}");
6422  CHECK_EQ(239, value->Int32Value());
6423}
6424
6425
6426THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
6427  v8::HandleScope scope;
6428  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6429  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6430  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
6431  templ_p->SetAccessor(v8_str("y"), Return239);
6432
6433  LocalContext context;
6434  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6435  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
6436
6437  // Check the case when receiver and interceptor's holder
6438  // are the same objects.
6439  v8::Handle<Value> value = CompileRun(
6440      "o.__proto__ = p;"
6441      "var result = 0;"
6442      "for (var i = 0; i < 7; i++) {"
6443      "  result = o.x + o.y;"
6444      "}");
6445  CHECK_EQ(239 + 42, value->Int32Value());
6446
6447  // Check the case when interceptor's holder is in proto chain
6448  // of receiver.
6449  value = CompileRun(
6450      "r = { __proto__: o };"
6451      "var result = 0;"
6452      "for (var i = 0; i < 7; i++) {"
6453      "  result = r.x + r.y;"
6454      "}");
6455  CHECK_EQ(239 + 42, value->Int32Value());
6456}
6457
6458
6459THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
6460  v8::HandleScope scope;
6461  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6462  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6463  templ->SetAccessor(v8_str("y"), Return239);
6464
6465  LocalContext context;
6466  context->Global()->Set(v8_str("o"), templ->NewInstance());
6467
6468  v8::Handle<Value> value = CompileRun(
6469    "fst = new Object();  fst.__proto__ = o;"
6470    "snd = new Object();  snd.__proto__ = fst;"
6471    "var result1 = 0;"
6472    "for (var i = 0; i < 7;  i++) {"
6473    "  result1 = snd.x;"
6474    "}"
6475    "fst.x = 239;"
6476    "var result = 0;"
6477    "for (var i = 0; i < 7; i++) {"
6478    "  result = snd.x;"
6479    "}"
6480    "result + result1");
6481  CHECK_EQ(239 + 42, value->Int32Value());
6482}
6483
6484
6485// Test the case when we stored callback into
6486// a stub, but interceptor produced value on its own.
6487THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
6488  v8::HandleScope scope;
6489  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6490  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6491  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
6492  templ_p->SetAccessor(v8_str("y"), Return239);
6493
6494  LocalContext context;
6495  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6496  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
6497
6498  v8::Handle<Value> value = CompileRun(
6499    "o.__proto__ = p;"
6500    "for (var i = 0; i < 7; i++) {"
6501    "  o.x;"
6502    // Now it should be ICed and keep a reference to x defined on p
6503    "}"
6504    "var result = 0;"
6505    "for (var i = 0; i < 7; i++) {"
6506    "  result += o.x;"
6507    "}"
6508    "result");
6509  CHECK_EQ(42 * 7, value->Int32Value());
6510}
6511
6512
6513// Test the case when we stored callback into
6514// a stub, but it got invalidated later on.
6515THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
6516  v8::HandleScope scope;
6517  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6518  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6519  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
6520  templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
6521
6522  LocalContext context;
6523  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6524  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
6525
6526  v8::Handle<Value> value = CompileRun(
6527    "inbetween = new Object();"
6528    "o.__proto__ = inbetween;"
6529    "inbetween.__proto__ = p;"
6530    "for (var i = 0; i < 10; i++) {"
6531    "  o.y;"
6532    // Now it should be ICed and keep a reference to y defined on p
6533    "}"
6534    "inbetween.y = 42;"
6535    "var result = 0;"
6536    "for (var i = 0; i < 10; i++) {"
6537    "  result += o.y;"
6538    "}"
6539    "result");
6540  CHECK_EQ(42 * 10, value->Int32Value());
6541}
6542
6543
6544// Test the case when we stored callback into
6545// a stub, but it got invalidated later on due to override on
6546// global object which is between interceptor and callbacks' holders.
6547THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
6548  v8::HandleScope scope;
6549  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6550  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6551  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
6552  templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
6553
6554  LocalContext context;
6555  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6556  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
6557
6558  v8::Handle<Value> value = CompileRun(
6559    "o.__proto__ = this;"
6560    "this.__proto__ = p;"
6561    "for (var i = 0; i < 10; i++) {"
6562    "  if (o.y != 239) throw 'oops: ' + o.y;"
6563    // Now it should be ICed and keep a reference to y defined on p
6564    "}"
6565    "this.y = 42;"
6566    "var result = 0;"
6567    "for (var i = 0; i < 10; i++) {"
6568    "  result += o.y;"
6569    "}"
6570    "result");
6571  CHECK_EQ(42 * 10, value->Int32Value());
6572}
6573
6574
6575static v8::Handle<Value> InterceptorLoadICGetter0(Local<String> name,
6576                                                  const AccessorInfo& info) {
6577  ApiTestFuzzer::Fuzz();
6578  CHECK(v8_str("x")->Equals(name));
6579  return v8::Integer::New(0);
6580}
6581
6582
6583THREADED_TEST(InterceptorReturningZero) {
6584  CheckInterceptorLoadIC(InterceptorLoadICGetter0,
6585     "o.x == undefined ? 1 : 0",
6586     0);
6587}
6588
6589
6590static v8::Handle<Value> InterceptorStoreICSetter(
6591    Local<String> key, Local<Value> value, const AccessorInfo&) {
6592  CHECK(v8_str("x")->Equals(key));
6593  CHECK_EQ(42, value->Int32Value());
6594  return value;
6595}
6596
6597
6598// This test should hit the store IC for the interceptor case.
6599THREADED_TEST(InterceptorStoreIC) {
6600  v8::HandleScope scope;
6601  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6602  templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
6603                                 InterceptorStoreICSetter);
6604  LocalContext context;
6605  context->Global()->Set(v8_str("o"), templ->NewInstance());
6606  v8::Handle<Value> value = CompileRun(
6607    "for (var i = 0; i < 1000; i++) {"
6608    "  o.x = 42;"
6609    "}");
6610}
6611
6612
6613THREADED_TEST(InterceptorStoreICWithNoSetter) {
6614  v8::HandleScope scope;
6615  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6616  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6617  LocalContext context;
6618  context->Global()->Set(v8_str("o"), templ->NewInstance());
6619  v8::Handle<Value> value = CompileRun(
6620    "for (var i = 0; i < 1000; i++) {"
6621    "  o.y = 239;"
6622    "}"
6623    "42 + o.y");
6624  CHECK_EQ(239 + 42, value->Int32Value());
6625}
6626
6627
6628
6629
6630v8::Handle<Value> call_ic_function;
6631v8::Handle<Value> call_ic_function2;
6632v8::Handle<Value> call_ic_function3;
6633
6634static v8::Handle<Value> InterceptorCallICGetter(Local<String> name,
6635                                                 const AccessorInfo& info) {
6636  ApiTestFuzzer::Fuzz();
6637  CHECK(v8_str("x")->Equals(name));
6638  return call_ic_function;
6639}
6640
6641
6642// This test should hit the call IC for the interceptor case.
6643THREADED_TEST(InterceptorCallIC) {
6644  v8::HandleScope scope;
6645  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6646  templ->SetNamedPropertyHandler(InterceptorCallICGetter);
6647  LocalContext context;
6648  context->Global()->Set(v8_str("o"), templ->NewInstance());
6649  call_ic_function =
6650      v8_compile("function f(x) { return x + 1; }; f")->Run();
6651  v8::Handle<Value> value = CompileRun(
6652    "var result = 0;"
6653    "for (var i = 0; i < 1000; i++) {"
6654    "  result = o.x(41);"
6655    "}");
6656  CHECK_EQ(42, value->Int32Value());
6657}
6658
6659
6660// This test checks that if interceptor doesn't provide
6661// a value, we can fetch regular value.
6662THREADED_TEST(InterceptorCallICSeesOthers) {
6663  v8::HandleScope scope;
6664  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6665  templ->SetNamedPropertyHandler(NoBlockGetterX);
6666  LocalContext context;
6667  context->Global()->Set(v8_str("o"), templ->NewInstance());
6668  v8::Handle<Value> value = CompileRun(
6669    "o.x = function f(x) { return x + 1; };"
6670    "var result = 0;"
6671    "for (var i = 0; i < 7; i++) {"
6672    "  result = o.x(41);"
6673    "}");
6674  CHECK_EQ(42, value->Int32Value());
6675}
6676
6677
6678static v8::Handle<Value> call_ic_function4;
6679static v8::Handle<Value> InterceptorCallICGetter4(Local<String> name,
6680                                                  const AccessorInfo& info) {
6681  ApiTestFuzzer::Fuzz();
6682  CHECK(v8_str("x")->Equals(name));
6683  return call_ic_function4;
6684}
6685
6686
6687// This test checks that if interceptor provides a function,
6688// even if we cached shadowed variant, interceptor's function
6689// is invoked
6690THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
6691  v8::HandleScope scope;
6692  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6693  templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
6694  LocalContext context;
6695  context->Global()->Set(v8_str("o"), templ->NewInstance());
6696  call_ic_function4 =
6697      v8_compile("function f(x) { return x - 1; }; f")->Run();
6698  v8::Handle<Value> value = CompileRun(
6699    "o.__proto__.x = function(x) { return x + 1; };"
6700    "var result = 0;"
6701    "for (var i = 0; i < 1000; i++) {"
6702    "  result = o.x(42);"
6703    "}");
6704  CHECK_EQ(41, value->Int32Value());
6705}
6706
6707
6708// Test the case when we stored cacheable lookup into
6709// a stub, but it got invalidated later on
6710THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
6711  v8::HandleScope scope;
6712  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6713  templ->SetNamedPropertyHandler(NoBlockGetterX);
6714  LocalContext context;
6715  context->Global()->Set(v8_str("o"), templ->NewInstance());
6716  v8::Handle<Value> value = CompileRun(
6717    "proto1 = new Object();"
6718    "proto2 = new Object();"
6719    "o.__proto__ = proto1;"
6720    "proto1.__proto__ = proto2;"
6721    "proto2.y = function(x) { return x + 1; };"
6722    // Invoke it many times to compile a stub
6723    "for (var i = 0; i < 7; i++) {"
6724    "  o.y(42);"
6725    "}"
6726    "proto1.y = function(x) { return x - 1; };"
6727    "var result = 0;"
6728    "for (var i = 0; i < 7; i++) {"
6729    "  result += o.y(42);"
6730    "}");
6731  CHECK_EQ(41 * 7, value->Int32Value());
6732}
6733
6734
6735static v8::Handle<Value> call_ic_function5;
6736static v8::Handle<Value> InterceptorCallICGetter5(Local<String> name,
6737                                                  const AccessorInfo& info) {
6738  ApiTestFuzzer::Fuzz();
6739  if (v8_str("x")->Equals(name))
6740    return call_ic_function5;
6741  else
6742    return Local<Value>();
6743}
6744
6745
6746// This test checks that if interceptor doesn't provide a function,
6747// cached constant function is used
6748THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
6749  v8::HandleScope scope;
6750  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6751  templ->SetNamedPropertyHandler(NoBlockGetterX);
6752  LocalContext context;
6753  context->Global()->Set(v8_str("o"), templ->NewInstance());
6754  v8::Handle<Value> value = CompileRun(
6755    "function inc(x) { return x + 1; };"
6756    "inc(1);"
6757    "o.x = inc;"
6758    "var result = 0;"
6759    "for (var i = 0; i < 1000; i++) {"
6760    "  result = o.x(42);"
6761    "}");
6762  CHECK_EQ(43, value->Int32Value());
6763}
6764
6765
6766// This test checks that if interceptor provides a function,
6767// even if we cached constant function, interceptor's function
6768// is invoked
6769THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
6770  v8::HandleScope scope;
6771  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6772  templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
6773  LocalContext context;
6774  context->Global()->Set(v8_str("o"), templ->NewInstance());
6775  call_ic_function5 =
6776      v8_compile("function f(x) { return x - 1; }; f")->Run();
6777  v8::Handle<Value> value = CompileRun(
6778    "function inc(x) { return x + 1; };"
6779    "inc(1);"
6780    "o.x = inc;"
6781    "var result = 0;"
6782    "for (var i = 0; i < 1000; i++) {"
6783    "  result = o.x(42);"
6784    "}");
6785  CHECK_EQ(41, value->Int32Value());
6786}
6787
6788
6789// Test the case when we stored constant function into
6790// a stub, but it got invalidated later on
6791THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
6792  v8::HandleScope scope;
6793  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6794  templ->SetNamedPropertyHandler(NoBlockGetterX);
6795  LocalContext context;
6796  context->Global()->Set(v8_str("o"), templ->NewInstance());
6797  v8::Handle<Value> value = CompileRun(
6798    "function inc(x) { return x + 1; };"
6799    "inc(1);"
6800    "proto1 = new Object();"
6801    "proto2 = new Object();"
6802    "o.__proto__ = proto1;"
6803    "proto1.__proto__ = proto2;"
6804    "proto2.y = inc;"
6805    // Invoke it many times to compile a stub
6806    "for (var i = 0; i < 7; i++) {"
6807    "  o.y(42);"
6808    "}"
6809    "proto1.y = function(x) { return x - 1; };"
6810    "var result = 0;"
6811    "for (var i = 0; i < 7; i++) {"
6812    "  result += o.y(42);"
6813    "}");
6814  CHECK_EQ(41 * 7, value->Int32Value());
6815}
6816
6817
6818// Test the case when we stored constant function into
6819// a stub, but it got invalidated later on due to override on
6820// global object which is between interceptor and constant function' holders.
6821THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
6822  v8::HandleScope scope;
6823  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6824  templ->SetNamedPropertyHandler(NoBlockGetterX);
6825  LocalContext context;
6826  context->Global()->Set(v8_str("o"), templ->NewInstance());
6827  v8::Handle<Value> value = CompileRun(
6828    "function inc(x) { return x + 1; };"
6829    "inc(1);"
6830    "o.__proto__ = this;"
6831    "this.__proto__.y = inc;"
6832    // Invoke it many times to compile a stub
6833    "for (var i = 0; i < 7; i++) {"
6834    "  if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
6835    "}"
6836    "this.y = function(x) { return x - 1; };"
6837    "var result = 0;"
6838    "for (var i = 0; i < 7; i++) {"
6839    "  result += o.y(42);"
6840    "}");
6841  CHECK_EQ(41 * 7, value->Int32Value());
6842}
6843
6844
6845// Test the case when actual function to call sits on global object.
6846THREADED_TEST(InterceptorCallICCachedFromGlobal) {
6847  v8::HandleScope scope;
6848  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6849  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
6850
6851  LocalContext context;
6852  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6853
6854  v8::Handle<Value> value = CompileRun(
6855    "try {"
6856    "  o.__proto__ = this;"
6857    "  for (var i = 0; i < 10; i++) {"
6858    "    var v = o.parseFloat('239');"
6859    "    if (v != 239) throw v;"
6860      // Now it should be ICed and keep a reference to parseFloat.
6861    "  }"
6862    "  var result = 0;"
6863    "  for (var i = 0; i < 10; i++) {"
6864    "    result += o.parseFloat('239');"
6865    "  }"
6866    "  result"
6867    "} catch(e) {"
6868    "  e"
6869    "};");
6870  CHECK_EQ(239 * 10, value->Int32Value());
6871}
6872
6873static v8::Handle<Value> InterceptorCallICFastApi(Local<String> name,
6874                                                  const AccessorInfo& info) {
6875  ApiTestFuzzer::Fuzz();
6876  int* call_count = reinterpret_cast<int*>(v8::External::Unwrap(info.Data()));
6877  ++(*call_count);
6878  if ((*call_count) % 20 == 0) {
6879    i::Heap::CollectAllGarbage(true);
6880  }
6881  return v8::Handle<Value>();
6882}
6883
6884static v8::Handle<Value> FastApiCallback_TrivialSignature(
6885    const v8::Arguments& args) {
6886  ApiTestFuzzer::Fuzz();
6887  CHECK_EQ(args.This(), args.Holder());
6888  CHECK(args.Data()->Equals(v8_str("method_data")));
6889  return v8::Integer::New(args[0]->Int32Value() + 1);
6890}
6891
6892static v8::Handle<Value> FastApiCallback_SimpleSignature(
6893    const v8::Arguments& args) {
6894  ApiTestFuzzer::Fuzz();
6895  CHECK_EQ(args.This()->GetPrototype(), args.Holder());
6896  CHECK(args.Data()->Equals(v8_str("method_data")));
6897  // Note, we're using HasRealNamedProperty instead of Has to avoid
6898  // invoking the interceptor again.
6899  CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
6900  return v8::Integer::New(args[0]->Int32Value() + 1);
6901}
6902
6903// Helper to maximize the odds of object moving.
6904static void GenerateSomeGarbage() {
6905  CompileRun(
6906      "var garbage;"
6907      "for (var i = 0; i < 1000; i++) {"
6908      "  garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
6909      "}"
6910      "garbage = undefined;");
6911}
6912
6913THREADED_TEST(InterceptorCallICFastApi_TrivialSignature) {
6914  int interceptor_call_count = 0;
6915  v8::HandleScope scope;
6916  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6917  v8::Handle<v8::FunctionTemplate> method_templ =
6918      v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
6919                                v8_str("method_data"),
6920                                v8::Handle<v8::Signature>());
6921  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
6922  proto_templ->Set(v8_str("method"), method_templ);
6923  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
6924  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
6925                                 NULL, NULL, NULL, NULL,
6926                                 v8::External::Wrap(&interceptor_call_count));
6927  LocalContext context;
6928  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
6929  GenerateSomeGarbage();
6930  context->Global()->Set(v8_str("o"), fun->NewInstance());
6931  v8::Handle<Value> value = CompileRun(
6932      "var result = 0;"
6933      "for (var i = 0; i < 100; i++) {"
6934      "  result = o.method(41);"
6935      "}");
6936  CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
6937  CHECK_EQ(100, interceptor_call_count);
6938}
6939
6940THREADED_TEST(InterceptorCallICFastApi_SimpleSignature) {
6941  int interceptor_call_count = 0;
6942  v8::HandleScope scope;
6943  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6944  v8::Handle<v8::FunctionTemplate> method_templ =
6945      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
6946                                v8_str("method_data"),
6947                                v8::Signature::New(fun_templ));
6948  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
6949  proto_templ->Set(v8_str("method"), method_templ);
6950  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
6951  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
6952                                 NULL, NULL, NULL, NULL,
6953                                 v8::External::Wrap(&interceptor_call_count));
6954  LocalContext context;
6955  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
6956  GenerateSomeGarbage();
6957  context->Global()->Set(v8_str("o"), fun->NewInstance());
6958  v8::Handle<Value> value = CompileRun(
6959      "o.foo = 17;"
6960      "var receiver = {};"
6961      "receiver.__proto__ = o;"
6962      "var result = 0;"
6963      "for (var i = 0; i < 100; i++) {"
6964      "  result = receiver.method(41);"
6965      "}");
6966  CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
6967  CHECK_EQ(100, interceptor_call_count);
6968}
6969
6970THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
6971  int interceptor_call_count = 0;
6972  v8::HandleScope scope;
6973  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6974  v8::Handle<v8::FunctionTemplate> method_templ =
6975      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
6976                                v8_str("method_data"),
6977                                v8::Signature::New(fun_templ));
6978  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
6979  proto_templ->Set(v8_str("method"), method_templ);
6980  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
6981  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
6982                                 NULL, NULL, NULL, NULL,
6983                                 v8::External::Wrap(&interceptor_call_count));
6984  LocalContext context;
6985  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
6986  GenerateSomeGarbage();
6987  context->Global()->Set(v8_str("o"), fun->NewInstance());
6988  v8::Handle<Value> value = CompileRun(
6989      "o.foo = 17;"
6990      "var receiver = {};"
6991      "receiver.__proto__ = o;"
6992      "var result = 0;"
6993      "var saved_result = 0;"
6994      "for (var i = 0; i < 100; i++) {"
6995      "  result = receiver.method(41);"
6996      "  if (i == 50) {"
6997      "    saved_result = result;"
6998      "    receiver = {method: function(x) { return x - 1 }};"
6999      "  }"
7000      "}");
7001  CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
7002  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7003  CHECK_GE(interceptor_call_count, 50);
7004}
7005
7006THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
7007  int interceptor_call_count = 0;
7008  v8::HandleScope scope;
7009  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7010  v8::Handle<v8::FunctionTemplate> method_templ =
7011      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7012                                v8_str("method_data"),
7013                                v8::Signature::New(fun_templ));
7014  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7015  proto_templ->Set(v8_str("method"), method_templ);
7016  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7017  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
7018                                 NULL, NULL, NULL, NULL,
7019                                 v8::External::Wrap(&interceptor_call_count));
7020  LocalContext context;
7021  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7022  GenerateSomeGarbage();
7023  context->Global()->Set(v8_str("o"), fun->NewInstance());
7024  v8::Handle<Value> value = CompileRun(
7025      "o.foo = 17;"
7026      "var receiver = {};"
7027      "receiver.__proto__ = o;"
7028      "var result = 0;"
7029      "var saved_result = 0;"
7030      "for (var i = 0; i < 100; i++) {"
7031      "  result = receiver.method(41);"
7032      "  if (i == 50) {"
7033      "    saved_result = result;"
7034      "    o.method = function(x) { return x - 1 };"
7035      "  }"
7036      "}");
7037  CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
7038  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7039  CHECK_GE(interceptor_call_count, 50);
7040}
7041
7042THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
7043  int interceptor_call_count = 0;
7044  v8::HandleScope scope;
7045  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7046  v8::Handle<v8::FunctionTemplate> method_templ =
7047      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7048                                v8_str("method_data"),
7049                                v8::Signature::New(fun_templ));
7050  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7051  proto_templ->Set(v8_str("method"), method_templ);
7052  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7053  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
7054                                 NULL, NULL, NULL, NULL,
7055                                 v8::External::Wrap(&interceptor_call_count));
7056  LocalContext context;
7057  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7058  GenerateSomeGarbage();
7059  context->Global()->Set(v8_str("o"), fun->NewInstance());
7060  v8::TryCatch try_catch;
7061  v8::Handle<Value> value = CompileRun(
7062      "o.foo = 17;"
7063      "var receiver = {};"
7064      "receiver.__proto__ = o;"
7065      "var result = 0;"
7066      "var saved_result = 0;"
7067      "for (var i = 0; i < 100; i++) {"
7068      "  result = receiver.method(41);"
7069      "  if (i == 50) {"
7070      "    saved_result = result;"
7071      "    receiver = 333;"
7072      "  }"
7073      "}");
7074  CHECK(try_catch.HasCaught());
7075  CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
7076           try_catch.Exception()->ToString());
7077  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7078  CHECK_GE(interceptor_call_count, 50);
7079}
7080
7081THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
7082  int interceptor_call_count = 0;
7083  v8::HandleScope scope;
7084  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7085  v8::Handle<v8::FunctionTemplate> method_templ =
7086      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7087                                v8_str("method_data"),
7088                                v8::Signature::New(fun_templ));
7089  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7090  proto_templ->Set(v8_str("method"), method_templ);
7091  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7092  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
7093                                 NULL, NULL, NULL, NULL,
7094                                 v8::External::Wrap(&interceptor_call_count));
7095  LocalContext context;
7096  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7097  GenerateSomeGarbage();
7098  context->Global()->Set(v8_str("o"), fun->NewInstance());
7099  v8::TryCatch try_catch;
7100  v8::Handle<Value> value = CompileRun(
7101      "o.foo = 17;"
7102      "var receiver = {};"
7103      "receiver.__proto__ = o;"
7104      "var result = 0;"
7105      "var saved_result = 0;"
7106      "for (var i = 0; i < 100; i++) {"
7107      "  result = receiver.method(41);"
7108      "  if (i == 50) {"
7109      "    saved_result = result;"
7110      "    receiver = {method: receiver.method};"
7111      "  }"
7112      "}");
7113  CHECK(try_catch.HasCaught());
7114  CHECK_EQ(v8_str("TypeError: Illegal invocation"),
7115           try_catch.Exception()->ToString());
7116  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7117  CHECK_GE(interceptor_call_count, 50);
7118}
7119
7120THREADED_TEST(CallICFastApi_TrivialSignature) {
7121  v8::HandleScope scope;
7122  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7123  v8::Handle<v8::FunctionTemplate> method_templ =
7124      v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
7125                                v8_str("method_data"),
7126                                v8::Handle<v8::Signature>());
7127  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7128  proto_templ->Set(v8_str("method"), method_templ);
7129  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7130  LocalContext context;
7131  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7132  GenerateSomeGarbage();
7133  context->Global()->Set(v8_str("o"), fun->NewInstance());
7134  v8::Handle<Value> value = CompileRun(
7135      "var result = 0;"
7136      "for (var i = 0; i < 100; i++) {"
7137      "  result = o.method(41);"
7138      "}");
7139
7140  CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
7141}
7142
7143THREADED_TEST(CallICFastApi_SimpleSignature) {
7144  v8::HandleScope scope;
7145  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7146  v8::Handle<v8::FunctionTemplate> method_templ =
7147      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7148                                v8_str("method_data"),
7149                                v8::Signature::New(fun_templ));
7150  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7151  proto_templ->Set(v8_str("method"), method_templ);
7152  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7153  LocalContext context;
7154  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7155  GenerateSomeGarbage();
7156  context->Global()->Set(v8_str("o"), fun->NewInstance());
7157  v8::Handle<Value> value = CompileRun(
7158      "o.foo = 17;"
7159      "var receiver = {};"
7160      "receiver.__proto__ = o;"
7161      "var result = 0;"
7162      "for (var i = 0; i < 100; i++) {"
7163      "  result = receiver.method(41);"
7164      "}");
7165
7166  CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
7167}
7168
7169THREADED_TEST(CallICFastApi_SimpleSignature_Miss1) {
7170  v8::HandleScope scope;
7171  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7172  v8::Handle<v8::FunctionTemplate> method_templ =
7173      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7174                                v8_str("method_data"),
7175                                v8::Signature::New(fun_templ));
7176  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7177  proto_templ->Set(v8_str("method"), method_templ);
7178  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7179  LocalContext context;
7180  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7181  GenerateSomeGarbage();
7182  context->Global()->Set(v8_str("o"), fun->NewInstance());
7183  v8::Handle<Value> value = CompileRun(
7184      "o.foo = 17;"
7185      "var receiver = {};"
7186      "receiver.__proto__ = o;"
7187      "var result = 0;"
7188      "var saved_result = 0;"
7189      "for (var i = 0; i < 100; i++) {"
7190      "  result = receiver.method(41);"
7191      "  if (i == 50) {"
7192      "    saved_result = result;"
7193      "    receiver = {method: function(x) { return x - 1 }};"
7194      "  }"
7195      "}");
7196  CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
7197  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7198}
7199
7200THREADED_TEST(CallICFastApi_SimpleSignature_Miss2) {
7201  v8::HandleScope scope;
7202  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7203  v8::Handle<v8::FunctionTemplate> method_templ =
7204      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7205                                v8_str("method_data"),
7206                                v8::Signature::New(fun_templ));
7207  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7208  proto_templ->Set(v8_str("method"), method_templ);
7209  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7210  LocalContext context;
7211  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7212  GenerateSomeGarbage();
7213  context->Global()->Set(v8_str("o"), fun->NewInstance());
7214  v8::TryCatch try_catch;
7215  v8::Handle<Value> value = CompileRun(
7216      "o.foo = 17;"
7217      "var receiver = {};"
7218      "receiver.__proto__ = o;"
7219      "var result = 0;"
7220      "var saved_result = 0;"
7221      "for (var i = 0; i < 100; i++) {"
7222      "  result = receiver.method(41);"
7223      "  if (i == 50) {"
7224      "    saved_result = result;"
7225      "    receiver = 333;"
7226      "  }"
7227      "}");
7228  CHECK(try_catch.HasCaught());
7229  CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
7230           try_catch.Exception()->ToString());
7231  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7232}
7233
7234
7235v8::Handle<Value> keyed_call_ic_function;
7236
7237static v8::Handle<Value> InterceptorKeyedCallICGetter(
7238    Local<String> name, const AccessorInfo& info) {
7239  ApiTestFuzzer::Fuzz();
7240  if (v8_str("x")->Equals(name)) {
7241    return keyed_call_ic_function;
7242  }
7243  return v8::Handle<Value>();
7244}
7245
7246
7247// Test the case when we stored cacheable lookup into
7248// a stub, but the function name changed (to another cacheable function).
7249THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
7250  v8::HandleScope scope;
7251  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7252  templ->SetNamedPropertyHandler(NoBlockGetterX);
7253  LocalContext context;
7254  context->Global()->Set(v8_str("o"), templ->NewInstance());
7255  v8::Handle<Value> value = CompileRun(
7256    "proto = new Object();"
7257    "proto.y = function(x) { return x + 1; };"
7258    "proto.z = function(x) { return x - 1; };"
7259    "o.__proto__ = proto;"
7260    "var result = 0;"
7261    "var method = 'y';"
7262    "for (var i = 0; i < 10; i++) {"
7263    "  if (i == 5) { method = 'z'; };"
7264    "  result += o[method](41);"
7265    "}");
7266  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
7267}
7268
7269
7270// Test the case when we stored cacheable lookup into
7271// a stub, but the function name changed (and the new function is present
7272// both before and after the interceptor in the prototype chain).
7273THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
7274  v8::HandleScope scope;
7275  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7276  templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
7277  LocalContext context;
7278  context->Global()->Set(v8_str("proto1"), templ->NewInstance());
7279  keyed_call_ic_function =
7280      v8_compile("function f(x) { return x - 1; }; f")->Run();
7281  v8::Handle<Value> value = CompileRun(
7282    "o = new Object();"
7283    "proto2 = new Object();"
7284    "o.y = function(x) { return x + 1; };"
7285    "proto2.y = function(x) { return x + 2; };"
7286    "o.__proto__ = proto1;"
7287    "proto1.__proto__ = proto2;"
7288    "var result = 0;"
7289    "var method = 'x';"
7290    "for (var i = 0; i < 10; i++) {"
7291    "  if (i == 5) { method = 'y'; };"
7292    "  result += o[method](41);"
7293    "}");
7294  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
7295}
7296
7297
7298// Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
7299// on the global object.
7300THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
7301  v8::HandleScope scope;
7302  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7303  templ->SetNamedPropertyHandler(NoBlockGetterX);
7304  LocalContext context;
7305  context->Global()->Set(v8_str("o"), templ->NewInstance());
7306  v8::Handle<Value> value = CompileRun(
7307    "function inc(x) { return x + 1; };"
7308    "inc(1);"
7309    "function dec(x) { return x - 1; };"
7310    "dec(1);"
7311    "o.__proto__ = this;"
7312    "this.__proto__.x = inc;"
7313    "this.__proto__.y = dec;"
7314    "var result = 0;"
7315    "var method = 'x';"
7316    "for (var i = 0; i < 10; i++) {"
7317    "  if (i == 5) { method = 'y'; };"
7318    "  result += o[method](41);"
7319    "}");
7320  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
7321}
7322
7323
7324// Test the case when actual function to call sits on global object.
7325THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
7326  v8::HandleScope scope;
7327  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7328  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
7329  LocalContext context;
7330  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
7331
7332  v8::Handle<Value> value = CompileRun(
7333    "function len(x) { return x.length; };"
7334    "o.__proto__ = this;"
7335    "var m = 'parseFloat';"
7336    "var result = 0;"
7337    "for (var i = 0; i < 10; i++) {"
7338    "  if (i == 5) {"
7339    "    m = 'len';"
7340    "    saved_result = result;"
7341    "  };"
7342    "  result = o[m]('239');"
7343    "}");
7344  CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
7345  CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7346}
7347
7348// Test the map transition before the interceptor.
7349THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
7350  v8::HandleScope scope;
7351  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7352  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
7353  LocalContext context;
7354  context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
7355
7356  v8::Handle<Value> value = CompileRun(
7357    "var o = new Object();"
7358    "o.__proto__ = proto;"
7359    "o.method = function(x) { return x + 1; };"
7360    "var m = 'method';"
7361    "var result = 0;"
7362    "for (var i = 0; i < 10; i++) {"
7363    "  if (i == 5) { o.method = function(x) { return x - 1; }; };"
7364    "  result += o[m](41);"
7365    "}");
7366  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
7367}
7368
7369
7370// Test the map transition after the interceptor.
7371THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
7372  v8::HandleScope scope;
7373  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7374  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
7375  LocalContext context;
7376  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
7377
7378  v8::Handle<Value> value = CompileRun(
7379    "var proto = new Object();"
7380    "o.__proto__ = proto;"
7381    "proto.method = function(x) { return x + 1; };"
7382    "var m = 'method';"
7383    "var result = 0;"
7384    "for (var i = 0; i < 10; i++) {"
7385    "  if (i == 5) { proto.method = function(x) { return x - 1; }; };"
7386    "  result += o[m](41);"
7387    "}");
7388  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
7389}
7390
7391
7392static int interceptor_call_count = 0;
7393
7394static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name,
7395                                                     const AccessorInfo& info) {
7396  ApiTestFuzzer::Fuzz();
7397  if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
7398    return call_ic_function2;
7399  }
7400  return v8::Handle<Value>();
7401}
7402
7403
7404// This test should hit load and call ICs for the interceptor case.
7405// Once in a while, the interceptor will reply that a property was not
7406// found in which case we should get a reference error.
7407THREADED_TEST(InterceptorICReferenceErrors) {
7408  v8::HandleScope scope;
7409  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7410  templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
7411  LocalContext context(0, templ, v8::Handle<Value>());
7412  call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
7413  v8::Handle<Value> value = CompileRun(
7414    "function f() {"
7415    "  for (var i = 0; i < 1000; i++) {"
7416    "    try { x; } catch(e) { return true; }"
7417    "  }"
7418    "  return false;"
7419    "};"
7420    "f();");
7421  CHECK_EQ(true, value->BooleanValue());
7422  interceptor_call_count = 0;
7423  value = CompileRun(
7424    "function g() {"
7425    "  for (var i = 0; i < 1000; i++) {"
7426    "    try { x(42); } catch(e) { return true; }"
7427    "  }"
7428    "  return false;"
7429    "};"
7430    "g();");
7431  CHECK_EQ(true, value->BooleanValue());
7432}
7433
7434
7435static int interceptor_ic_exception_get_count = 0;
7436
7437static v8::Handle<Value> InterceptorICExceptionGetter(
7438    Local<String> name,
7439    const AccessorInfo& info) {
7440  ApiTestFuzzer::Fuzz();
7441  if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
7442    return call_ic_function3;
7443  }
7444  if (interceptor_ic_exception_get_count == 20) {
7445    return v8::ThrowException(v8_num(42));
7446  }
7447  // Do not handle get for properties other than x.
7448  return v8::Handle<Value>();
7449}
7450
7451// Test interceptor load/call IC where the interceptor throws an
7452// exception once in a while.
7453THREADED_TEST(InterceptorICGetterExceptions) {
7454  interceptor_ic_exception_get_count = 0;
7455  v8::HandleScope scope;
7456  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7457  templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
7458  LocalContext context(0, templ, v8::Handle<Value>());
7459  call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
7460  v8::Handle<Value> value = CompileRun(
7461    "function f() {"
7462    "  for (var i = 0; i < 100; i++) {"
7463    "    try { x; } catch(e) { return true; }"
7464    "  }"
7465    "  return false;"
7466    "};"
7467    "f();");
7468  CHECK_EQ(true, value->BooleanValue());
7469  interceptor_ic_exception_get_count = 0;
7470  value = CompileRun(
7471    "function f() {"
7472    "  for (var i = 0; i < 100; i++) {"
7473    "    try { x(42); } catch(e) { return true; }"
7474    "  }"
7475    "  return false;"
7476    "};"
7477    "f();");
7478  CHECK_EQ(true, value->BooleanValue());
7479}
7480
7481
7482static int interceptor_ic_exception_set_count = 0;
7483
7484static v8::Handle<Value> InterceptorICExceptionSetter(
7485      Local<String> key, Local<Value> value, const AccessorInfo&) {
7486  ApiTestFuzzer::Fuzz();
7487  if (++interceptor_ic_exception_set_count > 20) {
7488    return v8::ThrowException(v8_num(42));
7489  }
7490  // Do not actually handle setting.
7491  return v8::Handle<Value>();
7492}
7493
7494// Test interceptor store IC where the interceptor throws an exception
7495// once in a while.
7496THREADED_TEST(InterceptorICSetterExceptions) {
7497  interceptor_ic_exception_set_count = 0;
7498  v8::HandleScope scope;
7499  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7500  templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
7501  LocalContext context(0, templ, v8::Handle<Value>());
7502  v8::Handle<Value> value = CompileRun(
7503    "function f() {"
7504    "  for (var i = 0; i < 100; i++) {"
7505    "    try { x = 42; } catch(e) { return true; }"
7506    "  }"
7507    "  return false;"
7508    "};"
7509    "f();");
7510  CHECK_EQ(true, value->BooleanValue());
7511}
7512
7513
7514// Test that we ignore null interceptors.
7515THREADED_TEST(NullNamedInterceptor) {
7516  v8::HandleScope scope;
7517  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7518  templ->SetNamedPropertyHandler(0);
7519  LocalContext context;
7520  templ->Set("x", v8_num(42));
7521  v8::Handle<v8::Object> obj = templ->NewInstance();
7522  context->Global()->Set(v8_str("obj"), obj);
7523  v8::Handle<Value> value = CompileRun("obj.x");
7524  CHECK(value->IsInt32());
7525  CHECK_EQ(42, value->Int32Value());
7526}
7527
7528
7529// Test that we ignore null interceptors.
7530THREADED_TEST(NullIndexedInterceptor) {
7531  v8::HandleScope scope;
7532  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7533  templ->SetIndexedPropertyHandler(0);
7534  LocalContext context;
7535  templ->Set("42", v8_num(42));
7536  v8::Handle<v8::Object> obj = templ->NewInstance();
7537  context->Global()->Set(v8_str("obj"), obj);
7538  v8::Handle<Value> value = CompileRun("obj[42]");
7539  CHECK(value->IsInt32());
7540  CHECK_EQ(42, value->Int32Value());
7541}
7542
7543
7544THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
7545  v8::HandleScope scope;
7546  v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
7547  templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
7548  LocalContext env;
7549  env->Global()->Set(v8_str("obj"),
7550                     templ->GetFunction()->NewInstance());
7551  ExpectTrue("obj.x === 42");
7552  ExpectTrue("!obj.propertyIsEnumerable('x')");
7553}
7554
7555
7556static v8::Handle<Value> ParentGetter(Local<String> name,
7557                                      const AccessorInfo& info) {
7558  ApiTestFuzzer::Fuzz();
7559  return v8_num(1);
7560}
7561
7562
7563static v8::Handle<Value> ChildGetter(Local<String> name,
7564                                     const AccessorInfo& info) {
7565  ApiTestFuzzer::Fuzz();
7566  return v8_num(42);
7567}
7568
7569
7570THREADED_TEST(Overriding) {
7571  v8::HandleScope scope;
7572  LocalContext context;
7573
7574  // Parent template.
7575  Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New();
7576  Local<ObjectTemplate> parent_instance_templ =
7577      parent_templ->InstanceTemplate();
7578  parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
7579
7580  // Template that inherits from the parent template.
7581  Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New();
7582  Local<ObjectTemplate> child_instance_templ =
7583      child_templ->InstanceTemplate();
7584  child_templ->Inherit(parent_templ);
7585  // Override 'f'.  The child version of 'f' should get called for child
7586  // instances.
7587  child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
7588  // Add 'g' twice.  The 'g' added last should get called for instances.
7589  child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
7590  child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
7591
7592  // Add 'h' as an accessor to the proto template with ReadOnly attributes
7593  // so 'h' can be shadowed on the instance object.
7594  Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
7595  child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
7596      v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
7597
7598  // Add 'i' as an accessor to the instance template with ReadOnly attributes
7599  // but the attribute does not have effect because it is duplicated with
7600  // NULL setter.
7601  child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
7602      v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
7603
7604
7605
7606  // Instantiate the child template.
7607  Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
7608
7609  // Check that the child function overrides the parent one.
7610  context->Global()->Set(v8_str("o"), instance);
7611  Local<Value> value = v8_compile("o.f")->Run();
7612  // Check that the 'g' that was added last is hit.
7613  CHECK_EQ(42, value->Int32Value());
7614  value = v8_compile("o.g")->Run();
7615  CHECK_EQ(42, value->Int32Value());
7616
7617  // Check 'h' can be shadowed.
7618  value = v8_compile("o.h = 3; o.h")->Run();
7619  CHECK_EQ(3, value->Int32Value());
7620
7621  // Check 'i' is cannot be shadowed or changed.
7622  value = v8_compile("o.i = 3; o.i")->Run();
7623  CHECK_EQ(42, value->Int32Value());
7624}
7625
7626
7627static v8::Handle<Value> IsConstructHandler(const v8::Arguments& args) {
7628  ApiTestFuzzer::Fuzz();
7629  if (args.IsConstructCall()) {
7630    return v8::Boolean::New(true);
7631  }
7632  return v8::Boolean::New(false);
7633}
7634
7635
7636THREADED_TEST(IsConstructCall) {
7637  v8::HandleScope scope;
7638
7639  // Function template with call handler.
7640  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
7641  templ->SetCallHandler(IsConstructHandler);
7642
7643  LocalContext context;
7644
7645  context->Global()->Set(v8_str("f"), templ->GetFunction());
7646  Local<Value> value = v8_compile("f()")->Run();
7647  CHECK(!value->BooleanValue());
7648  value = v8_compile("new f()")->Run();
7649  CHECK(value->BooleanValue());
7650}
7651
7652
7653THREADED_TEST(ObjectProtoToString) {
7654  v8::HandleScope scope;
7655  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
7656  templ->SetClassName(v8_str("MyClass"));
7657
7658  LocalContext context;
7659
7660  Local<String> customized_tostring = v8_str("customized toString");
7661
7662  // Replace Object.prototype.toString
7663  v8_compile("Object.prototype.toString = function() {"
7664                  "  return 'customized toString';"
7665                  "}")->Run();
7666
7667  // Normal ToString call should call replaced Object.prototype.toString
7668  Local<v8::Object> instance = templ->GetFunction()->NewInstance();
7669  Local<String> value = instance->ToString();
7670  CHECK(value->IsString() && value->Equals(customized_tostring));
7671
7672  // ObjectProtoToString should not call replace toString function.
7673  value = instance->ObjectProtoToString();
7674  CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
7675
7676  // Check global
7677  value = context->Global()->ObjectProtoToString();
7678  CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
7679
7680  // Check ordinary object
7681  Local<Value> object = v8_compile("new Object()")->Run();
7682  value = object.As<v8::Object>()->ObjectProtoToString();
7683  CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
7684}
7685
7686
7687bool ApiTestFuzzer::fuzzing_ = false;
7688i::Semaphore* ApiTestFuzzer::all_tests_done_=
7689  i::OS::CreateSemaphore(0);
7690int ApiTestFuzzer::active_tests_;
7691int ApiTestFuzzer::tests_being_run_;
7692int ApiTestFuzzer::current_;
7693
7694
7695// We are in a callback and want to switch to another thread (if we
7696// are currently running the thread fuzzing test).
7697void ApiTestFuzzer::Fuzz() {
7698  if (!fuzzing_) return;
7699  ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
7700  test->ContextSwitch();
7701}
7702
7703
7704// Let the next thread go.  Since it is also waiting on the V8 lock it may
7705// not start immediately.
7706bool ApiTestFuzzer::NextThread() {
7707  int test_position = GetNextTestNumber();
7708  const char* test_name = RegisterThreadedTest::nth(current_)->name();
7709  if (test_position == current_) {
7710    if (kLogThreading)
7711      printf("Stay with %s\n", test_name);
7712    return false;
7713  }
7714  if (kLogThreading) {
7715    printf("Switch from %s to %s\n",
7716           test_name,
7717           RegisterThreadedTest::nth(test_position)->name());
7718  }
7719  current_ = test_position;
7720  RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal();
7721  return true;
7722}
7723
7724
7725void ApiTestFuzzer::Run() {
7726  // When it is our turn...
7727  gate_->Wait();
7728  {
7729    // ... get the V8 lock and start running the test.
7730    v8::Locker locker;
7731    CallTest();
7732  }
7733  // This test finished.
7734  active_ = false;
7735  active_tests_--;
7736  // If it was the last then signal that fact.
7737  if (active_tests_ == 0) {
7738    all_tests_done_->Signal();
7739  } else {
7740    // Otherwise select a new test and start that.
7741    NextThread();
7742  }
7743}
7744
7745
7746static unsigned linear_congruential_generator;
7747
7748
7749void ApiTestFuzzer::Setup(PartOfTest part) {
7750  linear_congruential_generator = i::FLAG_testing_prng_seed;
7751  fuzzing_ = true;
7752  int start = (part == FIRST_PART) ? 0 : (RegisterThreadedTest::count() >> 1);
7753  int end = (part == FIRST_PART)
7754      ? (RegisterThreadedTest::count() >> 1)
7755      : RegisterThreadedTest::count();
7756  active_tests_ = tests_being_run_ = end - start;
7757  for (int i = 0; i < tests_being_run_; i++) {
7758    RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
7759  }
7760  for (int i = 0; i < active_tests_; i++) {
7761    RegisterThreadedTest::nth(i)->fuzzer_->Start();
7762  }
7763}
7764
7765
7766static void CallTestNumber(int test_number) {
7767  (RegisterThreadedTest::nth(test_number)->callback())();
7768}
7769
7770
7771void ApiTestFuzzer::RunAllTests() {
7772  // Set off the first test.
7773  current_ = -1;
7774  NextThread();
7775  // Wait till they are all done.
7776  all_tests_done_->Wait();
7777}
7778
7779
7780int ApiTestFuzzer::GetNextTestNumber() {
7781  int next_test;
7782  do {
7783    next_test = (linear_congruential_generator >> 16) % tests_being_run_;
7784    linear_congruential_generator *= 1664525u;
7785    linear_congruential_generator += 1013904223u;
7786  } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
7787  return next_test;
7788}
7789
7790
7791void ApiTestFuzzer::ContextSwitch() {
7792  // If the new thread is the same as the current thread there is nothing to do.
7793  if (NextThread()) {
7794    // Now it can start.
7795    v8::Unlocker unlocker;
7796    // Wait till someone starts us again.
7797    gate_->Wait();
7798    // And we're off.
7799  }
7800}
7801
7802
7803void ApiTestFuzzer::TearDown() {
7804  fuzzing_ = false;
7805  for (int i = 0; i < RegisterThreadedTest::count(); i++) {
7806    ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
7807    if (fuzzer != NULL) fuzzer->Join();
7808  }
7809}
7810
7811
7812// Lets not be needlessly self-referential.
7813TEST(Threading) {
7814  ApiTestFuzzer::Setup(ApiTestFuzzer::FIRST_PART);
7815  ApiTestFuzzer::RunAllTests();
7816  ApiTestFuzzer::TearDown();
7817}
7818
7819TEST(Threading2) {
7820  ApiTestFuzzer::Setup(ApiTestFuzzer::SECOND_PART);
7821  ApiTestFuzzer::RunAllTests();
7822  ApiTestFuzzer::TearDown();
7823}
7824
7825
7826void ApiTestFuzzer::CallTest() {
7827  if (kLogThreading)
7828    printf("Start test %d\n", test_number_);
7829  CallTestNumber(test_number_);
7830  if (kLogThreading)
7831    printf("End test %d\n", test_number_);
7832}
7833
7834
7835static v8::Handle<Value> ThrowInJS(const v8::Arguments& args) {
7836  CHECK(v8::Locker::IsLocked());
7837  ApiTestFuzzer::Fuzz();
7838  v8::Unlocker unlocker;
7839  const char* code = "throw 7;";
7840  {
7841    v8::Locker nested_locker;
7842    v8::HandleScope scope;
7843    v8::Handle<Value> exception;
7844    { v8::TryCatch try_catch;
7845      v8::Handle<Value> value = CompileRun(code);
7846      CHECK(value.IsEmpty());
7847      CHECK(try_catch.HasCaught());
7848      // Make sure to wrap the exception in a new handle because
7849      // the handle returned from the TryCatch is destroyed
7850      // when the TryCatch is destroyed.
7851      exception = Local<Value>::New(try_catch.Exception());
7852    }
7853    return v8::ThrowException(exception);
7854  }
7855}
7856
7857
7858static v8::Handle<Value> ThrowInJSNoCatch(const v8::Arguments& args) {
7859  CHECK(v8::Locker::IsLocked());
7860  ApiTestFuzzer::Fuzz();
7861  v8::Unlocker unlocker;
7862  const char* code = "throw 7;";
7863  {
7864    v8::Locker nested_locker;
7865    v8::HandleScope scope;
7866    v8::Handle<Value> value = CompileRun(code);
7867    CHECK(value.IsEmpty());
7868    return v8_str("foo");
7869  }
7870}
7871
7872
7873// These are locking tests that don't need to be run again
7874// as part of the locking aggregation tests.
7875TEST(NestedLockers) {
7876  v8::Locker locker;
7877  CHECK(v8::Locker::IsLocked());
7878  v8::HandleScope scope;
7879  LocalContext env;
7880  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS);
7881  Local<Function> fun = fun_templ->GetFunction();
7882  env->Global()->Set(v8_str("throw_in_js"), fun);
7883  Local<Script> script = v8_compile("(function () {"
7884                                    "  try {"
7885                                    "    throw_in_js();"
7886                                    "    return 42;"
7887                                    "  } catch (e) {"
7888                                    "    return e * 13;"
7889                                    "  }"
7890                                    "})();");
7891  CHECK_EQ(91, script->Run()->Int32Value());
7892}
7893
7894
7895// These are locking tests that don't need to be run again
7896// as part of the locking aggregation tests.
7897TEST(NestedLockersNoTryCatch) {
7898  v8::Locker locker;
7899  v8::HandleScope scope;
7900  LocalContext env;
7901  Local<v8::FunctionTemplate> fun_templ =
7902      v8::FunctionTemplate::New(ThrowInJSNoCatch);
7903  Local<Function> fun = fun_templ->GetFunction();
7904  env->Global()->Set(v8_str("throw_in_js"), fun);
7905  Local<Script> script = v8_compile("(function () {"
7906                                    "  try {"
7907                                    "    throw_in_js();"
7908                                    "    return 42;"
7909                                    "  } catch (e) {"
7910                                    "    return e * 13;"
7911                                    "  }"
7912                                    "})();");
7913  CHECK_EQ(91, script->Run()->Int32Value());
7914}
7915
7916
7917THREADED_TEST(RecursiveLocking) {
7918  v8::Locker locker;
7919  {
7920    v8::Locker locker2;
7921    CHECK(v8::Locker::IsLocked());
7922  }
7923}
7924
7925
7926static v8::Handle<Value> UnlockForAMoment(const v8::Arguments& args) {
7927  ApiTestFuzzer::Fuzz();
7928  v8::Unlocker unlocker;
7929  return v8::Undefined();
7930}
7931
7932
7933THREADED_TEST(LockUnlockLock) {
7934  {
7935    v8::Locker locker;
7936    v8::HandleScope scope;
7937    LocalContext env;
7938    Local<v8::FunctionTemplate> fun_templ =
7939        v8::FunctionTemplate::New(UnlockForAMoment);
7940    Local<Function> fun = fun_templ->GetFunction();
7941    env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
7942    Local<Script> script = v8_compile("(function () {"
7943                                      "  unlock_for_a_moment();"
7944                                      "  return 42;"
7945                                      "})();");
7946    CHECK_EQ(42, script->Run()->Int32Value());
7947  }
7948  {
7949    v8::Locker locker;
7950    v8::HandleScope scope;
7951    LocalContext env;
7952    Local<v8::FunctionTemplate> fun_templ =
7953        v8::FunctionTemplate::New(UnlockForAMoment);
7954    Local<Function> fun = fun_templ->GetFunction();
7955    env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
7956    Local<Script> script = v8_compile("(function () {"
7957                                      "  unlock_for_a_moment();"
7958                                      "  return 42;"
7959                                      "})();");
7960    CHECK_EQ(42, script->Run()->Int32Value());
7961  }
7962}
7963
7964
7965static int GetGlobalObjectsCount() {
7966  int count = 0;
7967  i::HeapIterator it;
7968  for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
7969    if (object->IsJSGlobalObject()) count++;
7970  return count;
7971}
7972
7973
7974static int GetSurvivingGlobalObjectsCount() {
7975  // We need to collect all garbage twice to be sure that everything
7976  // has been collected.  This is because inline caches are cleared in
7977  // the first garbage collection but some of the maps have already
7978  // been marked at that point.  Therefore some of the maps are not
7979  // collected until the second garbage collection.
7980  i::Heap::CollectAllGarbage(false);
7981  i::Heap::CollectAllGarbage(false);
7982  int count = GetGlobalObjectsCount();
7983#ifdef DEBUG
7984  if (count > 0) i::Heap::TracePathToGlobal();
7985#endif
7986  return count;
7987}
7988
7989
7990TEST(DontLeakGlobalObjects) {
7991  // Regression test for issues 1139850 and 1174891.
7992
7993  v8::V8::Initialize();
7994
7995  int count = GetSurvivingGlobalObjectsCount();
7996
7997  for (int i = 0; i < 5; i++) {
7998    { v8::HandleScope scope;
7999      LocalContext context;
8000    }
8001    CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
8002
8003    { v8::HandleScope scope;
8004      LocalContext context;
8005      v8_compile("Date")->Run();
8006    }
8007    CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
8008
8009    { v8::HandleScope scope;
8010      LocalContext context;
8011      v8_compile("/aaa/")->Run();
8012    }
8013    CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
8014
8015    { v8::HandleScope scope;
8016      const char* extension_list[] = { "v8/gc" };
8017      v8::ExtensionConfiguration extensions(1, extension_list);
8018      LocalContext context(&extensions);
8019      v8_compile("gc();")->Run();
8020    }
8021    CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
8022  }
8023}
8024
8025
8026v8::Persistent<v8::Object> some_object;
8027v8::Persistent<v8::Object> bad_handle;
8028
8029void NewPersistentHandleCallback(v8::Persistent<v8::Value> handle, void*) {
8030  v8::HandleScope scope;
8031  bad_handle = v8::Persistent<v8::Object>::New(some_object);
8032  handle.Dispose();
8033}
8034
8035
8036THREADED_TEST(NewPersistentHandleFromWeakCallback) {
8037  LocalContext context;
8038
8039  v8::Persistent<v8::Object> handle1, handle2;
8040  {
8041    v8::HandleScope scope;
8042    some_object = v8::Persistent<v8::Object>::New(v8::Object::New());
8043    handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
8044    handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
8045  }
8046  // Note: order is implementation dependent alas: currently
8047  // global handle nodes are processed by PostGarbageCollectionProcessing
8048  // in reverse allocation order, so if second allocated handle is deleted,
8049  // weak callback of the first handle would be able to 'reallocate' it.
8050  handle1.MakeWeak(NULL, NewPersistentHandleCallback);
8051  handle2.Dispose();
8052  i::Heap::CollectAllGarbage(false);
8053}
8054
8055
8056v8::Persistent<v8::Object> to_be_disposed;
8057
8058void DisposeAndForceGcCallback(v8::Persistent<v8::Value> handle, void*) {
8059  to_be_disposed.Dispose();
8060  i::Heap::CollectAllGarbage(false);
8061  handle.Dispose();
8062}
8063
8064
8065THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
8066  LocalContext context;
8067
8068  v8::Persistent<v8::Object> handle1, handle2;
8069  {
8070    v8::HandleScope scope;
8071    handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
8072    handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
8073  }
8074  handle1.MakeWeak(NULL, DisposeAndForceGcCallback);
8075  to_be_disposed = handle2;
8076  i::Heap::CollectAllGarbage(false);
8077}
8078
8079void DisposingCallback(v8::Persistent<v8::Value> handle, void*) {
8080  handle.Dispose();
8081}
8082
8083void HandleCreatingCallback(v8::Persistent<v8::Value> handle, void*) {
8084  v8::HandleScope scope;
8085  v8::Persistent<v8::Object>::New(v8::Object::New());
8086  handle.Dispose();
8087}
8088
8089
8090THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
8091  LocalContext context;
8092
8093  v8::Persistent<v8::Object> handle1, handle2, handle3;
8094  {
8095    v8::HandleScope scope;
8096    handle3 = v8::Persistent<v8::Object>::New(v8::Object::New());
8097    handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
8098    handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
8099  }
8100  handle2.MakeWeak(NULL, DisposingCallback);
8101  handle3.MakeWeak(NULL, HandleCreatingCallback);
8102  i::Heap::CollectAllGarbage(false);
8103}
8104
8105
8106THREADED_TEST(CheckForCrossContextObjectLiterals) {
8107  v8::V8::Initialize();
8108
8109  const int nof = 2;
8110  const char* sources[nof] = {
8111    "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
8112    "Object()"
8113  };
8114
8115  for (int i = 0; i < nof; i++) {
8116    const char* source = sources[i];
8117    { v8::HandleScope scope;
8118      LocalContext context;
8119      CompileRun(source);
8120    }
8121    { v8::HandleScope scope;
8122      LocalContext context;
8123      CompileRun(source);
8124    }
8125  }
8126}
8127
8128
8129static v8::Handle<Value> NestedScope(v8::Persistent<Context> env) {
8130  v8::HandleScope inner;
8131  env->Enter();
8132  v8::Handle<Value> three = v8_num(3);
8133  v8::Handle<Value> value = inner.Close(three);
8134  env->Exit();
8135  return value;
8136}
8137
8138
8139THREADED_TEST(NestedHandleScopeAndContexts) {
8140  v8::HandleScope outer;
8141  v8::Persistent<Context> env = Context::New();
8142  env->Enter();
8143  v8::Handle<Value> value = NestedScope(env);
8144  v8::Handle<String> str = value->ToString();
8145  env->Exit();
8146  env.Dispose();
8147}
8148
8149
8150THREADED_TEST(ExternalAllocatedMemory) {
8151  v8::HandleScope outer;
8152  v8::Persistent<Context> env = Context::New();
8153  const int kSize = 1024*1024;
8154  CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize), kSize);
8155  CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize), 0);
8156}
8157
8158
8159THREADED_TEST(DisposeEnteredContext) {
8160  v8::HandleScope scope;
8161  LocalContext outer;
8162  { v8::Persistent<v8::Context> inner = v8::Context::New();
8163    inner->Enter();
8164    inner.Dispose();
8165    inner.Clear();
8166    inner->Exit();
8167  }
8168}
8169
8170
8171// Regression test for issue 54, object templates with internal fields
8172// but no accessors or interceptors did not get their internal field
8173// count set on instances.
8174THREADED_TEST(Regress54) {
8175  v8::HandleScope outer;
8176  LocalContext context;
8177  static v8::Persistent<v8::ObjectTemplate> templ;
8178  if (templ.IsEmpty()) {
8179    v8::HandleScope inner;
8180    v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New();
8181    local->SetInternalFieldCount(1);
8182    templ = v8::Persistent<v8::ObjectTemplate>::New(inner.Close(local));
8183  }
8184  v8::Handle<v8::Object> result = templ->NewInstance();
8185  CHECK_EQ(1, result->InternalFieldCount());
8186}
8187
8188
8189// If part of the threaded tests, this test makes ThreadingTest fail
8190// on mac.
8191TEST(CatchStackOverflow) {
8192  v8::HandleScope scope;
8193  LocalContext context;
8194  v8::TryCatch try_catch;
8195  v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(
8196    "function f() {"
8197    "  return f();"
8198    "}"
8199    ""
8200    "f();"));
8201  v8::Handle<v8::Value> result = script->Run();
8202  CHECK(result.IsEmpty());
8203}
8204
8205
8206static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
8207                                    const char* resource_name,
8208                                    int line_offset) {
8209  v8::HandleScope scope;
8210  v8::TryCatch try_catch;
8211  v8::Handle<v8::Value> result = script->Run();
8212  CHECK(result.IsEmpty());
8213  CHECK(try_catch.HasCaught());
8214  v8::Handle<v8::Message> message = try_catch.Message();
8215  CHECK(!message.IsEmpty());
8216  CHECK_EQ(10 + line_offset, message->GetLineNumber());
8217  CHECK_EQ(91, message->GetStartPosition());
8218  CHECK_EQ(92, message->GetEndPosition());
8219  CHECK_EQ(2, message->GetStartColumn());
8220  CHECK_EQ(3, message->GetEndColumn());
8221  v8::String::AsciiValue line(message->GetSourceLine());
8222  CHECK_EQ("  throw 'nirk';", *line);
8223  v8::String::AsciiValue name(message->GetScriptResourceName());
8224  CHECK_EQ(resource_name, *name);
8225}
8226
8227
8228THREADED_TEST(TryCatchSourceInfo) {
8229  v8::HandleScope scope;
8230  LocalContext context;
8231  v8::Handle<v8::String> source = v8::String::New(
8232      "function Foo() {\n"
8233      "  return Bar();\n"
8234      "}\n"
8235      "\n"
8236      "function Bar() {\n"
8237      "  return Baz();\n"
8238      "}\n"
8239      "\n"
8240      "function Baz() {\n"
8241      "  throw 'nirk';\n"
8242      "}\n"
8243      "\n"
8244      "Foo();\n");
8245
8246  const char* resource_name;
8247  v8::Handle<v8::Script> script;
8248  resource_name = "test.js";
8249  script = v8::Script::Compile(source, v8::String::New(resource_name));
8250  CheckTryCatchSourceInfo(script, resource_name, 0);
8251
8252  resource_name = "test1.js";
8253  v8::ScriptOrigin origin1(v8::String::New(resource_name));
8254  script = v8::Script::Compile(source, &origin1);
8255  CheckTryCatchSourceInfo(script, resource_name, 0);
8256
8257  resource_name = "test2.js";
8258  v8::ScriptOrigin origin2(v8::String::New(resource_name), v8::Integer::New(7));
8259  script = v8::Script::Compile(source, &origin2);
8260  CheckTryCatchSourceInfo(script, resource_name, 7);
8261}
8262
8263
8264THREADED_TEST(CompilationCache) {
8265  v8::HandleScope scope;
8266  LocalContext context;
8267  v8::Handle<v8::String> source0 = v8::String::New("1234");
8268  v8::Handle<v8::String> source1 = v8::String::New("1234");
8269  v8::Handle<v8::Script> script0 =
8270      v8::Script::Compile(source0, v8::String::New("test.js"));
8271  v8::Handle<v8::Script> script1 =
8272      v8::Script::Compile(source1, v8::String::New("test.js"));
8273  v8::Handle<v8::Script> script2 =
8274      v8::Script::Compile(source0);  // different origin
8275  CHECK_EQ(1234, script0->Run()->Int32Value());
8276  CHECK_EQ(1234, script1->Run()->Int32Value());
8277  CHECK_EQ(1234, script2->Run()->Int32Value());
8278}
8279
8280
8281static v8::Handle<Value> FunctionNameCallback(const v8::Arguments& args) {
8282  ApiTestFuzzer::Fuzz();
8283  return v8_num(42);
8284}
8285
8286
8287THREADED_TEST(CallbackFunctionName) {
8288  v8::HandleScope scope;
8289  LocalContext context;
8290  Local<ObjectTemplate> t = ObjectTemplate::New();
8291  t->Set(v8_str("asdf"), v8::FunctionTemplate::New(FunctionNameCallback));
8292  context->Global()->Set(v8_str("obj"), t->NewInstance());
8293  v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
8294  CHECK(value->IsString());
8295  v8::String::AsciiValue name(value);
8296  CHECK_EQ("asdf", *name);
8297}
8298
8299
8300THREADED_TEST(DateAccess) {
8301  v8::HandleScope scope;
8302  LocalContext context;
8303  v8::Handle<v8::Value> date = v8::Date::New(1224744689038.0);
8304  CHECK(date->IsDate());
8305  CHECK_EQ(1224744689038.0, date.As<v8::Date>()->NumberValue());
8306}
8307
8308
8309void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) {
8310  v8::Handle<v8::Object> obj = val.As<v8::Object>();
8311  v8::Handle<v8::Array> props = obj->GetPropertyNames();
8312  CHECK_EQ(elmc, props->Length());
8313  for (int i = 0; i < elmc; i++) {
8314    v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
8315    CHECK_EQ(elmv[i], *elm);
8316  }
8317}
8318
8319
8320THREADED_TEST(PropertyEnumeration) {
8321  v8::HandleScope scope;
8322  LocalContext context;
8323  v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
8324      "var result = [];"
8325      "result[0] = {};"
8326      "result[1] = {a: 1, b: 2};"
8327      "result[2] = [1, 2, 3];"
8328      "var proto = {x: 1, y: 2, z: 3};"
8329      "var x = { __proto__: proto, w: 0, z: 1 };"
8330      "result[3] = x;"
8331      "result;"))->Run();
8332  v8::Handle<v8::Array> elms = obj.As<v8::Array>();
8333  CHECK_EQ(4, elms->Length());
8334  int elmc0 = 0;
8335  const char** elmv0 = NULL;
8336  CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
8337  int elmc1 = 2;
8338  const char* elmv1[] = {"a", "b"};
8339  CheckProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
8340  int elmc2 = 3;
8341  const char* elmv2[] = {"0", "1", "2"};
8342  CheckProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
8343  int elmc3 = 4;
8344  const char* elmv3[] = {"w", "z", "x", "y"};
8345  CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3);
8346}
8347
8348
8349static bool NamedSetAccessBlocker(Local<v8::Object> obj,
8350                                  Local<Value> name,
8351                                  v8::AccessType type,
8352                                  Local<Value> data) {
8353  return type != v8::ACCESS_SET;
8354}
8355
8356
8357static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
8358                                    uint32_t key,
8359                                    v8::AccessType type,
8360                                    Local<Value> data) {
8361  return type != v8::ACCESS_SET;
8362}
8363
8364
8365THREADED_TEST(DisableAccessChecksWhileConfiguring) {
8366  v8::HandleScope scope;
8367  LocalContext context;
8368  Local<ObjectTemplate> templ = ObjectTemplate::New();
8369  templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
8370                                 IndexedSetAccessBlocker);
8371  templ->Set(v8_str("x"), v8::True());
8372  Local<v8::Object> instance = templ->NewInstance();
8373  context->Global()->Set(v8_str("obj"), instance);
8374  Local<Value> value = CompileRun("obj.x");
8375  CHECK(value->BooleanValue());
8376}
8377
8378
8379static bool NamedGetAccessBlocker(Local<v8::Object> obj,
8380                                  Local<Value> name,
8381                                  v8::AccessType type,
8382                                  Local<Value> data) {
8383  return false;
8384}
8385
8386
8387static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
8388                                    uint32_t key,
8389                                    v8::AccessType type,
8390                                    Local<Value> data) {
8391  return false;
8392}
8393
8394
8395
8396THREADED_TEST(AccessChecksReenabledCorrectly) {
8397  v8::HandleScope scope;
8398  LocalContext context;
8399  Local<ObjectTemplate> templ = ObjectTemplate::New();
8400  templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
8401                                 IndexedGetAccessBlocker);
8402  templ->Set(v8_str("a"), v8_str("a"));
8403  // Add more than 8 (see kMaxFastProperties) properties
8404  // so that the constructor will force copying map.
8405  // Cannot sprintf, gcc complains unsafety.
8406  char buf[4];
8407  for (char i = '0'; i <= '9' ; i++) {
8408    buf[0] = i;
8409    for (char j = '0'; j <= '9'; j++) {
8410      buf[1] = j;
8411      for (char k = '0'; k <= '9'; k++) {
8412        buf[2] = k;
8413        buf[3] = 0;
8414        templ->Set(v8_str(buf), v8::Number::New(k));
8415      }
8416    }
8417  }
8418
8419  Local<v8::Object> instance_1 = templ->NewInstance();
8420  context->Global()->Set(v8_str("obj_1"), instance_1);
8421
8422  Local<Value> value_1 = CompileRun("obj_1.a");
8423  CHECK(value_1->IsUndefined());
8424
8425  Local<v8::Object> instance_2 = templ->NewInstance();
8426  context->Global()->Set(v8_str("obj_2"), instance_2);
8427
8428  Local<Value> value_2 = CompileRun("obj_2.a");
8429  CHECK(value_2->IsUndefined());
8430}
8431
8432
8433// This tests that access check information remains on the global
8434// object template when creating contexts.
8435THREADED_TEST(AccessControlRepeatedContextCreation) {
8436  v8::HandleScope handle_scope;
8437  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
8438  global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
8439                                           IndexedSetAccessBlocker);
8440  i::Handle<i::ObjectTemplateInfo> internal_template =
8441      v8::Utils::OpenHandle(*global_template);
8442  CHECK(!internal_template->constructor()->IsUndefined());
8443  i::Handle<i::FunctionTemplateInfo> constructor(
8444      i::FunctionTemplateInfo::cast(internal_template->constructor()));
8445  CHECK(!constructor->access_check_info()->IsUndefined());
8446  v8::Persistent<Context> context0 = Context::New(NULL, global_template);
8447  CHECK(!constructor->access_check_info()->IsUndefined());
8448}
8449
8450
8451THREADED_TEST(TurnOnAccessCheck) {
8452  v8::HandleScope handle_scope;
8453
8454  // Create an environment with access check to the global object disabled by
8455  // default.
8456  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
8457  global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
8458                                           IndexedGetAccessBlocker,
8459                                           v8::Handle<v8::Value>(),
8460                                           false);
8461  v8::Persistent<Context> context = Context::New(NULL, global_template);
8462  Context::Scope context_scope(context);
8463
8464  // Set up a property and a number of functions.
8465  context->Global()->Set(v8_str("a"), v8_num(1));
8466  CompileRun("function f1() {return a;}"
8467             "function f2() {return a;}"
8468             "function g1() {return h();}"
8469             "function g2() {return h();}"
8470             "function h() {return 1;}");
8471  Local<Function> f1 =
8472      Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
8473  Local<Function> f2 =
8474      Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
8475  Local<Function> g1 =
8476      Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
8477  Local<Function> g2 =
8478      Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
8479  Local<Function> h =
8480      Local<Function>::Cast(context->Global()->Get(v8_str("h")));
8481
8482  // Get the global object.
8483  v8::Handle<v8::Object> global = context->Global();
8484
8485  // Call f1 one time and f2 a number of times. This will ensure that f1 still
8486  // uses the runtime system to retreive property a whereas f2 uses global load
8487  // inline cache.
8488  CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
8489  for (int i = 0; i < 4; i++) {
8490    CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
8491  }
8492
8493  // Same for g1 and g2.
8494  CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
8495  for (int i = 0; i < 4; i++) {
8496    CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
8497  }
8498
8499  // Detach the global and turn on access check.
8500  context->DetachGlobal();
8501  context->Global()->TurnOnAccessCheck();
8502
8503  // Failing access check to property get results in undefined.
8504  CHECK(f1->Call(global, 0, NULL)->IsUndefined());
8505  CHECK(f2->Call(global, 0, NULL)->IsUndefined());
8506
8507  // Failing access check to function call results in exception.
8508  CHECK(g1->Call(global, 0, NULL).IsEmpty());
8509  CHECK(g2->Call(global, 0, NULL).IsEmpty());
8510
8511  // No failing access check when just returning a constant.
8512  CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
8513}
8514
8515
8516// This test verifies that pre-compilation (aka preparsing) can be called
8517// without initializing the whole VM. Thus we cannot run this test in a
8518// multi-threaded setup.
8519TEST(PreCompile) {
8520  // TODO(155): This test would break without the initialization of V8. This is
8521  // a workaround for now to make this test not fail.
8522  v8::V8::Initialize();
8523  const char* script = "function foo(a) { return a+1; }";
8524  v8::ScriptData* sd =
8525      v8::ScriptData::PreCompile(script, i::StrLength(script));
8526  CHECK_NE(sd->Length(), 0);
8527  CHECK_NE(sd->Data(), NULL);
8528  CHECK(!sd->HasError());
8529  delete sd;
8530}
8531
8532
8533TEST(PreCompileWithError) {
8534  v8::V8::Initialize();
8535  const char* script = "function foo(a) { return 1 * * 2; }";
8536  v8::ScriptData* sd =
8537      v8::ScriptData::PreCompile(script, i::StrLength(script));
8538  CHECK(sd->HasError());
8539  delete sd;
8540}
8541
8542
8543TEST(Regress31661) {
8544  v8::V8::Initialize();
8545  const char* script = " The Definintive Guide";
8546  v8::ScriptData* sd =
8547      v8::ScriptData::PreCompile(script, i::StrLength(script));
8548  CHECK(sd->HasError());
8549  delete sd;
8550}
8551
8552
8553// Tests that ScriptData can be serialized and deserialized.
8554TEST(PreCompileSerialization) {
8555  v8::V8::Initialize();
8556  const char* script = "function foo(a) { return a+1; }";
8557  v8::ScriptData* sd =
8558      v8::ScriptData::PreCompile(script, i::StrLength(script));
8559
8560  // Serialize.
8561  int serialized_data_length = sd->Length();
8562  char* serialized_data = i::NewArray<char>(serialized_data_length);
8563  memcpy(serialized_data, sd->Data(), serialized_data_length);
8564
8565  // Deserialize.
8566  v8::ScriptData* deserialized_sd =
8567      v8::ScriptData::New(serialized_data, serialized_data_length);
8568
8569  // Verify that the original is the same as the deserialized.
8570  CHECK_EQ(sd->Length(), deserialized_sd->Length());
8571  CHECK_EQ(0, memcmp(sd->Data(), deserialized_sd->Data(), sd->Length()));
8572  CHECK_EQ(sd->HasError(), deserialized_sd->HasError());
8573
8574  delete sd;
8575  delete deserialized_sd;
8576}
8577
8578
8579// Attempts to deserialize bad data.
8580TEST(PreCompileDeserializationError) {
8581  v8::V8::Initialize();
8582  const char* data = "DONT CARE";
8583  int invalid_size = 3;
8584  v8::ScriptData* sd = v8::ScriptData::New(data, invalid_size);
8585
8586  CHECK_EQ(0, sd->Length());
8587
8588  delete sd;
8589}
8590
8591
8592// Attempts to deserialize bad data.
8593TEST(PreCompileInvalidPreparseDataError) {
8594  v8::V8::Initialize();
8595  v8::HandleScope scope;
8596  LocalContext context;
8597
8598  const char* script = "function foo(){ return 5;}\n"
8599      "function bar(){ return 6 + 7;}  foo();";
8600  v8::ScriptData* sd =
8601      v8::ScriptData::PreCompile(script, i::StrLength(script));
8602  CHECK(!sd->HasError());
8603  // ScriptDataImpl private implementation details
8604  const int kUnsignedSize = sizeof(unsigned);
8605  const int kHeaderSize = 4;
8606  const int kFunctionEntrySize = 5;
8607  const int kFunctionEntryStartOffset = 0;
8608  const int kFunctionEntryEndOffset = 1;
8609  unsigned* sd_data =
8610      reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
8611  CHECK_EQ(sd->Length(),
8612           (kHeaderSize + 2 * kFunctionEntrySize) * kUnsignedSize);
8613
8614  // Overwrite function bar's end position with 0.
8615  sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
8616  v8::TryCatch try_catch;
8617
8618  Local<String> source = String::New(script);
8619  Local<Script> compiled_script = Script::New(source, NULL, sd);
8620  CHECK(try_catch.HasCaught());
8621  String::AsciiValue exception_value(try_catch.Message()->Get());
8622  CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
8623           *exception_value);
8624
8625  try_catch.Reset();
8626  // Overwrite function bar's start position with 200.  The function entry
8627  // will not be found when searching for it by position.
8628  sd = v8::ScriptData::PreCompile(script, i::StrLength(script));
8629  sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
8630  sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
8631      200;
8632  compiled_script = Script::New(source, NULL, sd);
8633  CHECK(try_catch.HasCaught());
8634  String::AsciiValue second_exception_value(try_catch.Message()->Get());
8635  CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
8636           *second_exception_value);
8637
8638  delete sd;
8639}
8640
8641
8642// Verifies that the Handle<String> and const char* versions of the API produce
8643// the same results (at least for one trivial case).
8644TEST(PreCompileAPIVariationsAreSame) {
8645  v8::V8::Initialize();
8646  v8::HandleScope scope;
8647
8648  const char* cstring = "function foo(a) { return a+1; }";
8649
8650  v8::ScriptData* sd_from_cstring =
8651      v8::ScriptData::PreCompile(cstring, i::StrLength(cstring));
8652
8653  TestAsciiResource* resource = new TestAsciiResource(cstring);
8654  v8::ScriptData* sd_from_external_string = v8::ScriptData::PreCompile(
8655      v8::String::NewExternal(resource));
8656
8657  v8::ScriptData* sd_from_string = v8::ScriptData::PreCompile(
8658      v8::String::New(cstring));
8659
8660  CHECK_EQ(sd_from_cstring->Length(), sd_from_external_string->Length());
8661  CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
8662                     sd_from_external_string->Data(),
8663                     sd_from_cstring->Length()));
8664
8665  CHECK_EQ(sd_from_cstring->Length(), sd_from_string->Length());
8666  CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
8667                     sd_from_string->Data(),
8668                     sd_from_cstring->Length()));
8669
8670
8671  delete sd_from_cstring;
8672  delete sd_from_external_string;
8673  delete sd_from_string;
8674}
8675
8676
8677// This tests that we do not allow dictionary load/call inline caches
8678// to use functions that have not yet been compiled.  The potential
8679// problem of loading a function that has not yet been compiled can
8680// arise because we share code between contexts via the compilation
8681// cache.
8682THREADED_TEST(DictionaryICLoadedFunction) {
8683  v8::HandleScope scope;
8684  // Test LoadIC.
8685  for (int i = 0; i < 2; i++) {
8686    LocalContext context;
8687    context->Global()->Set(v8_str("tmp"), v8::True());
8688    context->Global()->Delete(v8_str("tmp"));
8689    CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
8690  }
8691  // Test CallIC.
8692  for (int i = 0; i < 2; i++) {
8693    LocalContext context;
8694    context->Global()->Set(v8_str("tmp"), v8::True());
8695    context->Global()->Delete(v8_str("tmp"));
8696    CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
8697  }
8698}
8699
8700
8701// Test that cross-context new calls use the context of the callee to
8702// create the new JavaScript object.
8703THREADED_TEST(CrossContextNew) {
8704  v8::HandleScope scope;
8705  v8::Persistent<Context> context0 = Context::New();
8706  v8::Persistent<Context> context1 = Context::New();
8707
8708  // Allow cross-domain access.
8709  Local<String> token = v8_str("<security token>");
8710  context0->SetSecurityToken(token);
8711  context1->SetSecurityToken(token);
8712
8713  // Set an 'x' property on the Object prototype and define a
8714  // constructor function in context0.
8715  context0->Enter();
8716  CompileRun("Object.prototype.x = 42; function C() {};");
8717  context0->Exit();
8718
8719  // Call the constructor function from context0 and check that the
8720  // result has the 'x' property.
8721  context1->Enter();
8722  context1->Global()->Set(v8_str("other"), context0->Global());
8723  Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
8724  CHECK(value->IsInt32());
8725  CHECK_EQ(42, value->Int32Value());
8726  context1->Exit();
8727
8728  // Dispose the contexts to allow them to be garbage collected.
8729  context0.Dispose();
8730  context1.Dispose();
8731}
8732
8733
8734class RegExpInterruptTest {
8735 public:
8736  RegExpInterruptTest() : block_(NULL) {}
8737  ~RegExpInterruptTest() { delete block_; }
8738  void RunTest() {
8739    block_ = i::OS::CreateSemaphore(0);
8740    gc_count_ = 0;
8741    gc_during_regexp_ = 0;
8742    regexp_success_ = false;
8743    gc_success_ = false;
8744    GCThread gc_thread(this);
8745    gc_thread.Start();
8746    v8::Locker::StartPreemption(1);
8747
8748    LongRunningRegExp();
8749    {
8750      v8::Unlocker unlock;
8751      gc_thread.Join();
8752    }
8753    v8::Locker::StopPreemption();
8754    CHECK(regexp_success_);
8755    CHECK(gc_success_);
8756  }
8757 private:
8758  // Number of garbage collections required.
8759  static const int kRequiredGCs = 5;
8760
8761  class GCThread : public i::Thread {
8762   public:
8763    explicit GCThread(RegExpInterruptTest* test)
8764        : test_(test) {}
8765    virtual void Run() {
8766      test_->CollectGarbage();
8767    }
8768   private:
8769     RegExpInterruptTest* test_;
8770  };
8771
8772  void CollectGarbage() {
8773    block_->Wait();
8774    while (gc_during_regexp_ < kRequiredGCs) {
8775      {
8776        v8::Locker lock;
8777        // TODO(lrn): Perhaps create some garbage before collecting.
8778        i::Heap::CollectAllGarbage(false);
8779        gc_count_++;
8780      }
8781      i::OS::Sleep(1);
8782    }
8783    gc_success_ = true;
8784  }
8785
8786  void LongRunningRegExp() {
8787    block_->Signal();  // Enable garbage collection thread on next preemption.
8788    int rounds = 0;
8789    while (gc_during_regexp_ < kRequiredGCs) {
8790      int gc_before = gc_count_;
8791      {
8792        // Match 15-30 "a"'s against 14 and a "b".
8793        const char* c_source =
8794            "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
8795            ".exec('aaaaaaaaaaaaaaab') === null";
8796        Local<String> source = String::New(c_source);
8797        Local<Script> script = Script::Compile(source);
8798        Local<Value> result = script->Run();
8799        if (!result->BooleanValue()) {
8800          gc_during_regexp_ = kRequiredGCs;  // Allow gc thread to exit.
8801          return;
8802        }
8803      }
8804      {
8805        // Match 15-30 "a"'s against 15 and a "b".
8806        const char* c_source =
8807            "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
8808            ".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'";
8809        Local<String> source = String::New(c_source);
8810        Local<Script> script = Script::Compile(source);
8811        Local<Value> result = script->Run();
8812        if (!result->BooleanValue()) {
8813          gc_during_regexp_ = kRequiredGCs;
8814          return;
8815        }
8816      }
8817      int gc_after = gc_count_;
8818      gc_during_regexp_ += gc_after - gc_before;
8819      rounds++;
8820      i::OS::Sleep(1);
8821    }
8822    regexp_success_ = true;
8823  }
8824
8825  i::Semaphore* block_;
8826  int gc_count_;
8827  int gc_during_regexp_;
8828  bool regexp_success_;
8829  bool gc_success_;
8830};
8831
8832
8833// Test that a regular expression execution can be interrupted and
8834// survive a garbage collection.
8835TEST(RegExpInterruption) {
8836  v8::Locker lock;
8837  v8::V8::Initialize();
8838  v8::HandleScope scope;
8839  Local<Context> local_env;
8840  {
8841    LocalContext env;
8842    local_env = env.local();
8843  }
8844
8845  // Local context should still be live.
8846  CHECK(!local_env.IsEmpty());
8847  local_env->Enter();
8848
8849  // Should complete without problems.
8850  RegExpInterruptTest().RunTest();
8851
8852  local_env->Exit();
8853}
8854
8855
8856class ApplyInterruptTest {
8857 public:
8858  ApplyInterruptTest() : block_(NULL) {}
8859  ~ApplyInterruptTest() { delete block_; }
8860  void RunTest() {
8861    block_ = i::OS::CreateSemaphore(0);
8862    gc_count_ = 0;
8863    gc_during_apply_ = 0;
8864    apply_success_ = false;
8865    gc_success_ = false;
8866    GCThread gc_thread(this);
8867    gc_thread.Start();
8868    v8::Locker::StartPreemption(1);
8869
8870    LongRunningApply();
8871    {
8872      v8::Unlocker unlock;
8873      gc_thread.Join();
8874    }
8875    v8::Locker::StopPreemption();
8876    CHECK(apply_success_);
8877    CHECK(gc_success_);
8878  }
8879 private:
8880  // Number of garbage collections required.
8881  static const int kRequiredGCs = 2;
8882
8883  class GCThread : public i::Thread {
8884   public:
8885    explicit GCThread(ApplyInterruptTest* test)
8886        : test_(test) {}
8887    virtual void Run() {
8888      test_->CollectGarbage();
8889    }
8890   private:
8891     ApplyInterruptTest* test_;
8892  };
8893
8894  void CollectGarbage() {
8895    block_->Wait();
8896    while (gc_during_apply_ < kRequiredGCs) {
8897      {
8898        v8::Locker lock;
8899        i::Heap::CollectAllGarbage(false);
8900        gc_count_++;
8901      }
8902      i::OS::Sleep(1);
8903    }
8904    gc_success_ = true;
8905  }
8906
8907  void LongRunningApply() {
8908    block_->Signal();
8909    int rounds = 0;
8910    while (gc_during_apply_ < kRequiredGCs) {
8911      int gc_before = gc_count_;
8912      {
8913        const char* c_source =
8914            "function do_very_little(bar) {"
8915            "  this.foo = bar;"
8916            "}"
8917            "for (var i = 0; i < 100000; i++) {"
8918            "  do_very_little.apply(this, ['bar']);"
8919            "}";
8920        Local<String> source = String::New(c_source);
8921        Local<Script> script = Script::Compile(source);
8922        Local<Value> result = script->Run();
8923        // Check that no exception was thrown.
8924        CHECK(!result.IsEmpty());
8925      }
8926      int gc_after = gc_count_;
8927      gc_during_apply_ += gc_after - gc_before;
8928      rounds++;
8929    }
8930    apply_success_ = true;
8931  }
8932
8933  i::Semaphore* block_;
8934  int gc_count_;
8935  int gc_during_apply_;
8936  bool apply_success_;
8937  bool gc_success_;
8938};
8939
8940
8941// Test that nothing bad happens if we get a preemption just when we were
8942// about to do an apply().
8943TEST(ApplyInterruption) {
8944  v8::Locker lock;
8945  v8::V8::Initialize();
8946  v8::HandleScope scope;
8947  Local<Context> local_env;
8948  {
8949    LocalContext env;
8950    local_env = env.local();
8951  }
8952
8953  // Local context should still be live.
8954  CHECK(!local_env.IsEmpty());
8955  local_env->Enter();
8956
8957  // Should complete without problems.
8958  ApplyInterruptTest().RunTest();
8959
8960  local_env->Exit();
8961}
8962
8963
8964// Verify that we can clone an object
8965TEST(ObjectClone) {
8966  v8::HandleScope scope;
8967  LocalContext env;
8968
8969  const char* sample =
8970    "var rv = {};"      \
8971    "rv.alpha = 'hello';" \
8972    "rv.beta = 123;"     \
8973    "rv;";
8974
8975  // Create an object, verify basics.
8976  Local<Value> val = CompileRun(sample);
8977  CHECK(val->IsObject());
8978  Local<v8::Object> obj = val.As<v8::Object>();
8979  obj->Set(v8_str("gamma"), v8_str("cloneme"));
8980
8981  CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
8982  CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
8983  CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
8984
8985  // Clone it.
8986  Local<v8::Object> clone = obj->Clone();
8987  CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
8988  CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta")));
8989  CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
8990
8991  // Set a property on the clone, verify each object.
8992  clone->Set(v8_str("beta"), v8::Integer::New(456));
8993  CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
8994  CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta")));
8995}
8996
8997
8998class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
8999 public:
9000  explicit AsciiVectorResource(i::Vector<const char> vector)
9001      : data_(vector) {}
9002  virtual ~AsciiVectorResource() {}
9003  virtual size_t length() const { return data_.length(); }
9004  virtual const char* data() const { return data_.start(); }
9005 private:
9006  i::Vector<const char> data_;
9007};
9008
9009
9010class UC16VectorResource : public v8::String::ExternalStringResource {
9011 public:
9012  explicit UC16VectorResource(i::Vector<const i::uc16> vector)
9013      : data_(vector) {}
9014  virtual ~UC16VectorResource() {}
9015  virtual size_t length() const { return data_.length(); }
9016  virtual const i::uc16* data() const { return data_.start(); }
9017 private:
9018  i::Vector<const i::uc16> data_;
9019};
9020
9021
9022static void MorphAString(i::String* string,
9023                         AsciiVectorResource* ascii_resource,
9024                         UC16VectorResource* uc16_resource) {
9025  CHECK(i::StringShape(string).IsExternal());
9026  if (string->IsAsciiRepresentation()) {
9027    // Check old map is not symbol or long.
9028    CHECK(string->map() == i::Heap::external_ascii_string_map());
9029    // Morph external string to be TwoByte string.
9030    string->set_map(i::Heap::external_string_map());
9031    i::ExternalTwoByteString* morphed =
9032         i::ExternalTwoByteString::cast(string);
9033    morphed->set_resource(uc16_resource);
9034  } else {
9035    // Check old map is not symbol or long.
9036    CHECK(string->map() == i::Heap::external_string_map());
9037    // Morph external string to be ASCII string.
9038    string->set_map(i::Heap::external_ascii_string_map());
9039    i::ExternalAsciiString* morphed =
9040         i::ExternalAsciiString::cast(string);
9041    morphed->set_resource(ascii_resource);
9042  }
9043}
9044
9045
9046// Test that we can still flatten a string if the components it is built up
9047// from have been turned into 16 bit strings in the mean time.
9048THREADED_TEST(MorphCompositeStringTest) {
9049  const char* c_string = "Now is the time for all good men"
9050                         " to come to the aid of the party";
9051  uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
9052  {
9053    v8::HandleScope scope;
9054    LocalContext env;
9055    AsciiVectorResource ascii_resource(
9056        i::Vector<const char>(c_string, i::StrLength(c_string)));
9057    UC16VectorResource uc16_resource(
9058        i::Vector<const uint16_t>(two_byte_string,
9059                                  i::StrLength(c_string)));
9060
9061    Local<String> lhs(v8::Utils::ToLocal(
9062        i::Factory::NewExternalStringFromAscii(&ascii_resource)));
9063    Local<String> rhs(v8::Utils::ToLocal(
9064        i::Factory::NewExternalStringFromAscii(&ascii_resource)));
9065
9066    env->Global()->Set(v8_str("lhs"), lhs);
9067    env->Global()->Set(v8_str("rhs"), rhs);
9068
9069    CompileRun(
9070        "var cons = lhs + rhs;"
9071        "var slice = lhs.substring(1, lhs.length - 1);"
9072        "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
9073
9074    MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
9075    MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
9076
9077    // Now do some stuff to make sure the strings are flattened, etc.
9078    CompileRun(
9079        "/[^a-z]/.test(cons);"
9080        "/[^a-z]/.test(slice);"
9081        "/[^a-z]/.test(slice_on_cons);");
9082    const char* expected_cons =
9083        "Now is the time for all good men to come to the aid of the party"
9084        "Now is the time for all good men to come to the aid of the party";
9085    const char* expected_slice =
9086        "ow is the time for all good men to come to the aid of the part";
9087    const char* expected_slice_on_cons =
9088        "ow is the time for all good men to come to the aid of the party"
9089        "Now is the time for all good men to come to the aid of the part";
9090    CHECK_EQ(String::New(expected_cons),
9091             env->Global()->Get(v8_str("cons")));
9092    CHECK_EQ(String::New(expected_slice),
9093             env->Global()->Get(v8_str("slice")));
9094    CHECK_EQ(String::New(expected_slice_on_cons),
9095             env->Global()->Get(v8_str("slice_on_cons")));
9096  }
9097  i::DeleteArray(two_byte_string);
9098}
9099
9100
9101TEST(CompileExternalTwoByteSource) {
9102  v8::HandleScope scope;
9103  LocalContext context;
9104
9105  // This is a very short list of sources, which currently is to check for a
9106  // regression caused by r2703.
9107  const char* ascii_sources[] = {
9108    "0.5",
9109    "-0.5",   // This mainly testes PushBack in the Scanner.
9110    "--0.5",  // This mainly testes PushBack in the Scanner.
9111    NULL
9112  };
9113
9114  // Compile the sources as external two byte strings.
9115  for (int i = 0; ascii_sources[i] != NULL; i++) {
9116    uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
9117    UC16VectorResource uc16_resource(
9118        i::Vector<const uint16_t>(two_byte_string,
9119                                  i::StrLength(ascii_sources[i])));
9120    v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource);
9121    v8::Script::Compile(source);
9122    i::DeleteArray(two_byte_string);
9123  }
9124}
9125
9126
9127class RegExpStringModificationTest {
9128 public:
9129  RegExpStringModificationTest()
9130      : block_(i::OS::CreateSemaphore(0)),
9131        morphs_(0),
9132        morphs_during_regexp_(0),
9133        ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)),
9134        uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {}
9135  ~RegExpStringModificationTest() { delete block_; }
9136  void RunTest() {
9137    regexp_success_ = false;
9138    morph_success_ = false;
9139
9140    // Initialize the contents of two_byte_content_ to be a uc16 representation
9141    // of "aaaaaaaaaaaaaab".
9142    for (int i = 0; i < 14; i++) {
9143      two_byte_content_[i] = 'a';
9144    }
9145    two_byte_content_[14] = 'b';
9146
9147    // Create the input string for the regexp - the one we are going to change
9148    // properties of.
9149    input_ = i::Factory::NewExternalStringFromAscii(&ascii_resource_);
9150
9151    // Inject the input as a global variable.
9152    i::Handle<i::String> input_name =
9153        i::Factory::NewStringFromAscii(i::Vector<const char>("input", 5));
9154    i::Top::global_context()->global()->SetProperty(*input_name, *input_, NONE);
9155
9156
9157    MorphThread morph_thread(this);
9158    morph_thread.Start();
9159    v8::Locker::StartPreemption(1);
9160    LongRunningRegExp();
9161    {
9162      v8::Unlocker unlock;
9163      morph_thread.Join();
9164    }
9165    v8::Locker::StopPreemption();
9166    CHECK(regexp_success_);
9167    CHECK(morph_success_);
9168  }
9169 private:
9170
9171  // Number of string modifications required.
9172  static const int kRequiredModifications = 5;
9173  static const int kMaxModifications = 100;
9174
9175  class MorphThread : public i::Thread {
9176   public:
9177    explicit MorphThread(RegExpStringModificationTest* test)
9178        : test_(test) {}
9179    virtual void Run() {
9180      test_->MorphString();
9181    }
9182   private:
9183     RegExpStringModificationTest* test_;
9184  };
9185
9186  void MorphString() {
9187    block_->Wait();
9188    while (morphs_during_regexp_ < kRequiredModifications &&
9189           morphs_ < kMaxModifications) {
9190      {
9191        v8::Locker lock;
9192        // Swap string between ascii and two-byte representation.
9193        i::String* string = *input_;
9194        MorphAString(string, &ascii_resource_, &uc16_resource_);
9195        morphs_++;
9196      }
9197      i::OS::Sleep(1);
9198    }
9199    morph_success_ = true;
9200  }
9201
9202  void LongRunningRegExp() {
9203    block_->Signal();  // Enable morphing thread on next preemption.
9204    while (morphs_during_regexp_ < kRequiredModifications &&
9205           morphs_ < kMaxModifications) {
9206      int morphs_before = morphs_;
9207      {
9208        v8::HandleScope scope;
9209        // Match 15-30 "a"'s against 14 and a "b".
9210        const char* c_source =
9211            "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
9212            ".exec(input) === null";
9213        Local<String> source = String::New(c_source);
9214        Local<Script> script = Script::Compile(source);
9215        Local<Value> result = script->Run();
9216        CHECK(result->IsTrue());
9217      }
9218      int morphs_after = morphs_;
9219      morphs_during_regexp_ += morphs_after - morphs_before;
9220    }
9221    regexp_success_ = true;
9222  }
9223
9224  i::uc16 two_byte_content_[15];
9225  i::Semaphore* block_;
9226  int morphs_;
9227  int morphs_during_regexp_;
9228  bool regexp_success_;
9229  bool morph_success_;
9230  i::Handle<i::String> input_;
9231  AsciiVectorResource ascii_resource_;
9232  UC16VectorResource uc16_resource_;
9233};
9234
9235
9236// Test that a regular expression execution can be interrupted and
9237// the string changed without failing.
9238TEST(RegExpStringModification) {
9239  v8::Locker lock;
9240  v8::V8::Initialize();
9241  v8::HandleScope scope;
9242  Local<Context> local_env;
9243  {
9244    LocalContext env;
9245    local_env = env.local();
9246  }
9247
9248  // Local context should still be live.
9249  CHECK(!local_env.IsEmpty());
9250  local_env->Enter();
9251
9252  // Should complete without problems.
9253  RegExpStringModificationTest().RunTest();
9254
9255  local_env->Exit();
9256}
9257
9258
9259// Test that we can set a property on the global object even if there
9260// is a read-only property in the prototype chain.
9261TEST(ReadOnlyPropertyInGlobalProto) {
9262  v8::HandleScope scope;
9263  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
9264  LocalContext context(0, templ);
9265  v8::Handle<v8::Object> global = context->Global();
9266  v8::Handle<v8::Object> global_proto =
9267      v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
9268  global_proto->Set(v8_str("x"), v8::Integer::New(0), v8::ReadOnly);
9269  global_proto->Set(v8_str("y"), v8::Integer::New(0), v8::ReadOnly);
9270  // Check without 'eval' or 'with'.
9271  v8::Handle<v8::Value> res =
9272      CompileRun("function f() { x = 42; return x; }; f()");
9273  // Check with 'eval'.
9274  res = CompileRun("function f() { eval('1'); y = 42; return y; }; f()");
9275  CHECK_EQ(v8::Integer::New(42), res);
9276  // Check with 'with'.
9277  res = CompileRun("function f() { with (this) { y = 42 }; return y; }; f()");
9278  CHECK_EQ(v8::Integer::New(42), res);
9279}
9280
9281static int force_set_set_count = 0;
9282static int force_set_get_count = 0;
9283bool pass_on_get = false;
9284
9285static v8::Handle<v8::Value> ForceSetGetter(v8::Local<v8::String> name,
9286                                            const v8::AccessorInfo& info) {
9287  force_set_get_count++;
9288  if (pass_on_get) {
9289    return v8::Handle<v8::Value>();
9290  } else {
9291    return v8::Int32::New(3);
9292  }
9293}
9294
9295static void ForceSetSetter(v8::Local<v8::String> name,
9296                           v8::Local<v8::Value> value,
9297                           const v8::AccessorInfo& info) {
9298  force_set_set_count++;
9299}
9300
9301static v8::Handle<v8::Value> ForceSetInterceptSetter(
9302    v8::Local<v8::String> name,
9303    v8::Local<v8::Value> value,
9304    const v8::AccessorInfo& info) {
9305  force_set_set_count++;
9306  return v8::Undefined();
9307}
9308
9309TEST(ForceSet) {
9310  force_set_get_count = 0;
9311  force_set_set_count = 0;
9312  pass_on_get = false;
9313
9314  v8::HandleScope scope;
9315  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
9316  v8::Handle<v8::String> access_property = v8::String::New("a");
9317  templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
9318  LocalContext context(NULL, templ);
9319  v8::Handle<v8::Object> global = context->Global();
9320
9321  // Ordinary properties
9322  v8::Handle<v8::String> simple_property = v8::String::New("p");
9323  global->Set(simple_property, v8::Int32::New(4), v8::ReadOnly);
9324  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
9325  // This should fail because the property is read-only
9326  global->Set(simple_property, v8::Int32::New(5));
9327  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
9328  // This should succeed even though the property is read-only
9329  global->ForceSet(simple_property, v8::Int32::New(6));
9330  CHECK_EQ(6, global->Get(simple_property)->Int32Value());
9331
9332  // Accessors
9333  CHECK_EQ(0, force_set_set_count);
9334  CHECK_EQ(0, force_set_get_count);
9335  CHECK_EQ(3, global->Get(access_property)->Int32Value());
9336  // CHECK_EQ the property shouldn't override it, just call the setter
9337  // which in this case does nothing.
9338  global->Set(access_property, v8::Int32::New(7));
9339  CHECK_EQ(3, global->Get(access_property)->Int32Value());
9340  CHECK_EQ(1, force_set_set_count);
9341  CHECK_EQ(2, force_set_get_count);
9342  // Forcing the property to be set should override the accessor without
9343  // calling it
9344  global->ForceSet(access_property, v8::Int32::New(8));
9345  CHECK_EQ(8, global->Get(access_property)->Int32Value());
9346  CHECK_EQ(1, force_set_set_count);
9347  CHECK_EQ(2, force_set_get_count);
9348}
9349
9350TEST(ForceSetWithInterceptor) {
9351  force_set_get_count = 0;
9352  force_set_set_count = 0;
9353  pass_on_get = false;
9354
9355  v8::HandleScope scope;
9356  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
9357  templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
9358  LocalContext context(NULL, templ);
9359  v8::Handle<v8::Object> global = context->Global();
9360
9361  v8::Handle<v8::String> some_property = v8::String::New("a");
9362  CHECK_EQ(0, force_set_set_count);
9363  CHECK_EQ(0, force_set_get_count);
9364  CHECK_EQ(3, global->Get(some_property)->Int32Value());
9365  // Setting the property shouldn't override it, just call the setter
9366  // which in this case does nothing.
9367  global->Set(some_property, v8::Int32::New(7));
9368  CHECK_EQ(3, global->Get(some_property)->Int32Value());
9369  CHECK_EQ(1, force_set_set_count);
9370  CHECK_EQ(2, force_set_get_count);
9371  // Getting the property when the interceptor returns an empty handle
9372  // should yield undefined, since the property isn't present on the
9373  // object itself yet.
9374  pass_on_get = true;
9375  CHECK(global->Get(some_property)->IsUndefined());
9376  CHECK_EQ(1, force_set_set_count);
9377  CHECK_EQ(3, force_set_get_count);
9378  // Forcing the property to be set should cause the value to be
9379  // set locally without calling the interceptor.
9380  global->ForceSet(some_property, v8::Int32::New(8));
9381  CHECK_EQ(8, global->Get(some_property)->Int32Value());
9382  CHECK_EQ(1, force_set_set_count);
9383  CHECK_EQ(4, force_set_get_count);
9384  // Reenabling the interceptor should cause it to take precedence over
9385  // the property
9386  pass_on_get = false;
9387  CHECK_EQ(3, global->Get(some_property)->Int32Value());
9388  CHECK_EQ(1, force_set_set_count);
9389  CHECK_EQ(5, force_set_get_count);
9390  // The interceptor should also work for other properties
9391  CHECK_EQ(3, global->Get(v8::String::New("b"))->Int32Value());
9392  CHECK_EQ(1, force_set_set_count);
9393  CHECK_EQ(6, force_set_get_count);
9394}
9395
9396
9397THREADED_TEST(ForceDelete) {
9398  v8::HandleScope scope;
9399  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
9400  LocalContext context(NULL, templ);
9401  v8::Handle<v8::Object> global = context->Global();
9402
9403  // Ordinary properties
9404  v8::Handle<v8::String> simple_property = v8::String::New("p");
9405  global->Set(simple_property, v8::Int32::New(4), v8::DontDelete);
9406  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
9407  // This should fail because the property is dont-delete.
9408  CHECK(!global->Delete(simple_property));
9409  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
9410  // This should succeed even though the property is dont-delete.
9411  CHECK(global->ForceDelete(simple_property));
9412  CHECK(global->Get(simple_property)->IsUndefined());
9413}
9414
9415
9416static int force_delete_interceptor_count = 0;
9417static bool pass_on_delete = false;
9418
9419
9420static v8::Handle<v8::Boolean> ForceDeleteDeleter(
9421    v8::Local<v8::String> name,
9422    const v8::AccessorInfo& info) {
9423  force_delete_interceptor_count++;
9424  if (pass_on_delete) {
9425    return v8::Handle<v8::Boolean>();
9426  } else {
9427    return v8::True();
9428  }
9429}
9430
9431
9432THREADED_TEST(ForceDeleteWithInterceptor) {
9433  force_delete_interceptor_count = 0;
9434  pass_on_delete = false;
9435
9436  v8::HandleScope scope;
9437  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
9438  templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
9439  LocalContext context(NULL, templ);
9440  v8::Handle<v8::Object> global = context->Global();
9441
9442  v8::Handle<v8::String> some_property = v8::String::New("a");
9443  global->Set(some_property, v8::Integer::New(42), v8::DontDelete);
9444
9445  // Deleting a property should get intercepted and nothing should
9446  // happen.
9447  CHECK_EQ(0, force_delete_interceptor_count);
9448  CHECK(global->Delete(some_property));
9449  CHECK_EQ(1, force_delete_interceptor_count);
9450  CHECK_EQ(42, global->Get(some_property)->Int32Value());
9451  // Deleting the property when the interceptor returns an empty
9452  // handle should not delete the property since it is DontDelete.
9453  pass_on_delete = true;
9454  CHECK(!global->Delete(some_property));
9455  CHECK_EQ(2, force_delete_interceptor_count);
9456  CHECK_EQ(42, global->Get(some_property)->Int32Value());
9457  // Forcing the property to be deleted should delete the value
9458  // without calling the interceptor.
9459  CHECK(global->ForceDelete(some_property));
9460  CHECK(global->Get(some_property)->IsUndefined());
9461  CHECK_EQ(2, force_delete_interceptor_count);
9462}
9463
9464
9465// Make sure that forcing a delete invalidates any IC stubs, so we
9466// don't read the hole value.
9467THREADED_TEST(ForceDeleteIC) {
9468  v8::HandleScope scope;
9469  LocalContext context;
9470  // Create a DontDelete variable on the global object.
9471  CompileRun("this.__proto__ = { foo: 'horse' };"
9472             "var foo = 'fish';"
9473             "function f() { return foo.length; }");
9474  // Initialize the IC for foo in f.
9475  CompileRun("for (var i = 0; i < 4; i++) f();");
9476  // Make sure the value of foo is correct before the deletion.
9477  CHECK_EQ(4, CompileRun("f()")->Int32Value());
9478  // Force the deletion of foo.
9479  CHECK(context->Global()->ForceDelete(v8_str("foo")));
9480  // Make sure the value for foo is read from the prototype, and that
9481  // we don't get in trouble with reading the deleted cell value
9482  // sentinel.
9483  CHECK_EQ(5, CompileRun("f()")->Int32Value());
9484}
9485
9486
9487v8::Persistent<Context> calling_context0;
9488v8::Persistent<Context> calling_context1;
9489v8::Persistent<Context> calling_context2;
9490
9491
9492// Check that the call to the callback is initiated in
9493// calling_context2, the directly calling context is calling_context1
9494// and the callback itself is in calling_context0.
9495static v8::Handle<Value> GetCallingContextCallback(const v8::Arguments& args) {
9496  ApiTestFuzzer::Fuzz();
9497  CHECK(Context::GetCurrent() == calling_context0);
9498  CHECK(Context::GetCalling() == calling_context1);
9499  CHECK(Context::GetEntered() == calling_context2);
9500  return v8::Integer::New(42);
9501}
9502
9503
9504THREADED_TEST(GetCallingContext) {
9505  v8::HandleScope scope;
9506
9507  calling_context0 = Context::New();
9508  calling_context1 = Context::New();
9509  calling_context2 = Context::New();
9510
9511  // Allow cross-domain access.
9512  Local<String> token = v8_str("<security token>");
9513  calling_context0->SetSecurityToken(token);
9514  calling_context1->SetSecurityToken(token);
9515  calling_context2->SetSecurityToken(token);
9516
9517  // Create an object with a C++ callback in context0.
9518  calling_context0->Enter();
9519  Local<v8::FunctionTemplate> callback_templ =
9520      v8::FunctionTemplate::New(GetCallingContextCallback);
9521  calling_context0->Global()->Set(v8_str("callback"),
9522                                  callback_templ->GetFunction());
9523  calling_context0->Exit();
9524
9525  // Expose context0 in context1 and setup a function that calls the
9526  // callback function.
9527  calling_context1->Enter();
9528  calling_context1->Global()->Set(v8_str("context0"),
9529                                  calling_context0->Global());
9530  CompileRun("function f() { context0.callback() }");
9531  calling_context1->Exit();
9532
9533  // Expose context1 in context2 and call the callback function in
9534  // context0 indirectly through f in context1.
9535  calling_context2->Enter();
9536  calling_context2->Global()->Set(v8_str("context1"),
9537                                  calling_context1->Global());
9538  CompileRun("context1.f()");
9539  calling_context2->Exit();
9540
9541  // Dispose the contexts to allow them to be garbage collected.
9542  calling_context0.Dispose();
9543  calling_context1.Dispose();
9544  calling_context2.Dispose();
9545  calling_context0.Clear();
9546  calling_context1.Clear();
9547  calling_context2.Clear();
9548}
9549
9550
9551// Check that a variable declaration with no explicit initialization
9552// value does not shadow an existing property in the prototype chain.
9553//
9554// This is consistent with Firefox and Safari.
9555//
9556// See http://crbug.com/12548.
9557THREADED_TEST(InitGlobalVarInProtoChain) {
9558  v8::HandleScope scope;
9559  LocalContext context;
9560  // Introduce a variable in the prototype chain.
9561  CompileRun("__proto__.x = 42");
9562  v8::Handle<v8::Value> result = CompileRun("var x; x");
9563  CHECK(!result->IsUndefined());
9564  CHECK_EQ(42, result->Int32Value());
9565}
9566
9567
9568// Regression test for issue 398.
9569// If a function is added to an object, creating a constant function
9570// field, and the result is cloned, replacing the constant function on the
9571// original should not affect the clone.
9572// See http://code.google.com/p/v8/issues/detail?id=398
9573THREADED_TEST(ReplaceConstantFunction) {
9574  v8::HandleScope scope;
9575  LocalContext context;
9576  v8::Handle<v8::Object> obj = v8::Object::New();
9577  v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
9578  v8::Handle<v8::String> foo_string = v8::String::New("foo");
9579  obj->Set(foo_string, func_templ->GetFunction());
9580  v8::Handle<v8::Object> obj_clone = obj->Clone();
9581  obj_clone->Set(foo_string, v8::String::New("Hello"));
9582  CHECK(!obj->Get(foo_string)->IsUndefined());
9583}
9584
9585
9586// Regression test for http://crbug.com/16276.
9587THREADED_TEST(Regress16276) {
9588  v8::HandleScope scope;
9589  LocalContext context;
9590  // Force the IC in f to be a dictionary load IC.
9591  CompileRun("function f(obj) { return obj.x; }\n"
9592             "var obj = { x: { foo: 42 }, y: 87 };\n"
9593             "var x = obj.x;\n"
9594             "delete obj.y;\n"
9595             "for (var i = 0; i < 5; i++) f(obj);");
9596  // Detach the global object to make 'this' refer directly to the
9597  // global object (not the proxy), and make sure that the dictionary
9598  // load IC doesn't mess up loading directly from the global object.
9599  context->DetachGlobal();
9600  CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value());
9601}
9602
9603
9604THREADED_TEST(PixelArray) {
9605  v8::HandleScope scope;
9606  LocalContext context;
9607  const int kElementCount = 260;
9608  uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
9609  i::Handle<i::PixelArray> pixels = i::Factory::NewPixelArray(kElementCount,
9610                                                              pixel_data);
9611  i::Heap::CollectAllGarbage(false);  // Force GC to trigger verification.
9612  for (int i = 0; i < kElementCount; i++) {
9613    pixels->set(i, i % 256);
9614  }
9615  i::Heap::CollectAllGarbage(false);  // Force GC to trigger verification.
9616  for (int i = 0; i < kElementCount; i++) {
9617    CHECK_EQ(i % 256, pixels->get(i));
9618    CHECK_EQ(i % 256, pixel_data[i]);
9619  }
9620
9621  v8::Handle<v8::Object> obj = v8::Object::New();
9622  i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
9623  // Set the elements to be the pixels.
9624  // jsobj->set_elements(*pixels);
9625  obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
9626  CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1))->value());
9627  obj->Set(v8_str("field"), v8::Int32::New(1503));
9628  context->Global()->Set(v8_str("pixels"), obj);
9629  v8::Handle<v8::Value> result = CompileRun("pixels.field");
9630  CHECK_EQ(1503, result->Int32Value());
9631  result = CompileRun("pixels[1]");
9632  CHECK_EQ(1, result->Int32Value());
9633
9634  result = CompileRun("var sum = 0;"
9635                      "for (var i = 0; i < 8; i++) {"
9636                      "  sum += pixels[i] = pixels[i] = -i;"
9637                      "}"
9638                      "sum;");
9639  CHECK_EQ(-28, result->Int32Value());
9640
9641  result = CompileRun("var sum = 0;"
9642                      "for (var i = 0; i < 8; i++) {"
9643                      "  sum += pixels[i] = pixels[i] = 0;"
9644                      "}"
9645                      "sum;");
9646  CHECK_EQ(0, result->Int32Value());
9647
9648  result = CompileRun("var sum = 0;"
9649                      "for (var i = 0; i < 8; i++) {"
9650                      "  sum += pixels[i] = pixels[i] = 255;"
9651                      "}"
9652                      "sum;");
9653  CHECK_EQ(8 * 255, result->Int32Value());
9654
9655  result = CompileRun("var sum = 0;"
9656                      "for (var i = 0; i < 8; i++) {"
9657                      "  sum += pixels[i] = pixels[i] = 256 + i;"
9658                      "}"
9659                      "sum;");
9660  CHECK_EQ(2076, result->Int32Value());
9661
9662  result = CompileRun("var sum = 0;"
9663                      "for (var i = 0; i < 8; i++) {"
9664                      "  sum += pixels[i] = pixels[i] = i;"
9665                      "}"
9666                      "sum;");
9667  CHECK_EQ(28, result->Int32Value());
9668
9669  result = CompileRun("var sum = 0;"
9670                      "for (var i = 0; i < 8; i++) {"
9671                      "  sum += pixels[i];"
9672                      "}"
9673                      "sum;");
9674  CHECK_EQ(28, result->Int32Value());
9675
9676  i::Handle<i::Smi> value(i::Smi::FromInt(2));
9677  i::SetElement(jsobj, 1, value);
9678  CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(1))->value());
9679  *value.location() = i::Smi::FromInt(256);
9680  i::SetElement(jsobj, 1, value);
9681  CHECK_EQ(255, i::Smi::cast(jsobj->GetElement(1))->value());
9682  *value.location() = i::Smi::FromInt(-1);
9683  i::SetElement(jsobj, 1, value);
9684  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1))->value());
9685
9686  result = CompileRun("for (var i = 0; i < 8; i++) {"
9687                      "  pixels[i] = (i * 65) - 109;"
9688                      "}"
9689                      "pixels[1] + pixels[6];");
9690  CHECK_EQ(255, result->Int32Value());
9691  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0))->value());
9692  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1))->value());
9693  CHECK_EQ(21, i::Smi::cast(jsobj->GetElement(2))->value());
9694  CHECK_EQ(86, i::Smi::cast(jsobj->GetElement(3))->value());
9695  CHECK_EQ(151, i::Smi::cast(jsobj->GetElement(4))->value());
9696  CHECK_EQ(216, i::Smi::cast(jsobj->GetElement(5))->value());
9697  CHECK_EQ(255, i::Smi::cast(jsobj->GetElement(6))->value());
9698  CHECK_EQ(255, i::Smi::cast(jsobj->GetElement(7))->value());
9699  result = CompileRun("var sum = 0;"
9700                      "for (var i = 0; i < 8; i++) {"
9701                      "  sum += pixels[i];"
9702                      "}"
9703                      "sum;");
9704  CHECK_EQ(984, result->Int32Value());
9705
9706  result = CompileRun("for (var i = 0; i < 8; i++) {"
9707                      "  pixels[i] = (i * 1.1);"
9708                      "}"
9709                      "pixels[1] + pixels[6];");
9710  CHECK_EQ(8, result->Int32Value());
9711  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0))->value());
9712  CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1))->value());
9713  CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(2))->value());
9714  CHECK_EQ(3, i::Smi::cast(jsobj->GetElement(3))->value());
9715  CHECK_EQ(4, i::Smi::cast(jsobj->GetElement(4))->value());
9716  CHECK_EQ(6, i::Smi::cast(jsobj->GetElement(5))->value());
9717  CHECK_EQ(7, i::Smi::cast(jsobj->GetElement(6))->value());
9718  CHECK_EQ(8, i::Smi::cast(jsobj->GetElement(7))->value());
9719
9720  result = CompileRun("for (var i = 0; i < 8; i++) {"
9721                      "  pixels[7] = undefined;"
9722                      "}"
9723                      "pixels[7];");
9724  CHECK_EQ(0, result->Int32Value());
9725  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(7))->value());
9726
9727  result = CompileRun("for (var i = 0; i < 8; i++) {"
9728                      "  pixels[6] = '2.3';"
9729                      "}"
9730                      "pixels[6];");
9731  CHECK_EQ(2, result->Int32Value());
9732  CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(6))->value());
9733
9734  result = CompileRun("for (var i = 0; i < 8; i++) {"
9735                      "  pixels[5] = NaN;"
9736                      "}"
9737                      "pixels[5];");
9738  CHECK_EQ(0, result->Int32Value());
9739  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5))->value());
9740
9741  result = CompileRun("for (var i = 0; i < 8; i++) {"
9742                      "  pixels[8] = Infinity;"
9743                      "}"
9744                      "pixels[8];");
9745  CHECK_EQ(255, result->Int32Value());
9746  CHECK_EQ(255, i::Smi::cast(jsobj->GetElement(8))->value());
9747
9748  result = CompileRun("for (var i = 0; i < 8; i++) {"
9749                      "  pixels[9] = -Infinity;"
9750                      "}"
9751                      "pixels[9];");
9752  CHECK_EQ(0, result->Int32Value());
9753  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(9))->value());
9754
9755  result = CompileRun("pixels[3] = 33;"
9756                      "delete pixels[3];"
9757                      "pixels[3];");
9758  CHECK_EQ(33, result->Int32Value());
9759
9760  result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
9761                      "pixels[2] = 12; pixels[3] = 13;"
9762                      "pixels.__defineGetter__('2',"
9763                      "function() { return 120; });"
9764                      "pixels[2];");
9765  CHECK_EQ(12, result->Int32Value());
9766
9767  result = CompileRun("var js_array = new Array(40);"
9768                      "js_array[0] = 77;"
9769                      "js_array;");
9770  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
9771
9772  result = CompileRun("pixels[1] = 23;"
9773                      "pixels.__proto__ = [];"
9774                      "js_array.__proto__ = pixels;"
9775                      "js_array.concat(pixels);");
9776  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
9777  CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
9778
9779  result = CompileRun("pixels[1] = 23;");
9780  CHECK_EQ(23, result->Int32Value());
9781
9782  // Test for index greater than 255.  Regression test for:
9783  // http://code.google.com/p/chromium/issues/detail?id=26337.
9784  result = CompileRun("pixels[256] = 255;");
9785  CHECK_EQ(255, result->Int32Value());
9786  result = CompileRun("var i = 0;"
9787                      "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
9788                      "i");
9789  CHECK_EQ(255, result->Int32Value());
9790
9791  free(pixel_data);
9792}
9793
9794
9795THREADED_TEST(PixelArrayInfo) {
9796  v8::HandleScope scope;
9797  LocalContext context;
9798  for (int size = 0; size < 100; size += 10) {
9799    uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
9800    v8::Handle<v8::Object> obj = v8::Object::New();
9801    obj->SetIndexedPropertiesToPixelData(pixel_data, size);
9802    CHECK(obj->HasIndexedPropertiesInPixelData());
9803    CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
9804    CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
9805    free(pixel_data);
9806  }
9807}
9808
9809
9810static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
9811  switch (array_type) {
9812    case v8::kExternalByteArray:
9813    case v8::kExternalUnsignedByteArray:
9814      return 1;
9815      break;
9816    case v8::kExternalShortArray:
9817    case v8::kExternalUnsignedShortArray:
9818      return 2;
9819      break;
9820    case v8::kExternalIntArray:
9821    case v8::kExternalUnsignedIntArray:
9822    case v8::kExternalFloatArray:
9823      return 4;
9824      break;
9825    default:
9826      UNREACHABLE();
9827      return -1;
9828  }
9829  UNREACHABLE();
9830  return -1;
9831}
9832
9833
9834template <class ExternalArrayClass, class ElementType>
9835static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
9836                                    int64_t low,
9837                                    int64_t high) {
9838  v8::HandleScope scope;
9839  LocalContext context;
9840  const int kElementCount = 40;
9841  int element_size = ExternalArrayElementSize(array_type);
9842  ElementType* array_data =
9843      static_cast<ElementType*>(malloc(kElementCount * element_size));
9844  i::Handle<ExternalArrayClass> array =
9845      i::Handle<ExternalArrayClass>::cast(
9846          i::Factory::NewExternalArray(kElementCount, array_type, array_data));
9847  i::Heap::CollectAllGarbage(false);  // Force GC to trigger verification.
9848  for (int i = 0; i < kElementCount; i++) {
9849    array->set(i, static_cast<ElementType>(i));
9850  }
9851  i::Heap::CollectAllGarbage(false);  // Force GC to trigger verification.
9852  for (int i = 0; i < kElementCount; i++) {
9853    CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array->get(i)));
9854    CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
9855  }
9856
9857  v8::Handle<v8::Object> obj = v8::Object::New();
9858  i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
9859  // Set the elements to be the external array.
9860  obj->SetIndexedPropertiesToExternalArrayData(array_data,
9861                                               array_type,
9862                                               kElementCount);
9863  CHECK_EQ(1, static_cast<int>(jsobj->GetElement(1)->Number()));
9864  obj->Set(v8_str("field"), v8::Int32::New(1503));
9865  context->Global()->Set(v8_str("ext_array"), obj);
9866  v8::Handle<v8::Value> result = CompileRun("ext_array.field");
9867  CHECK_EQ(1503, result->Int32Value());
9868  result = CompileRun("ext_array[1]");
9869  CHECK_EQ(1, result->Int32Value());
9870
9871  // Check pass through of assigned smis
9872  result = CompileRun("var sum = 0;"
9873                      "for (var i = 0; i < 8; i++) {"
9874                      "  sum += ext_array[i] = ext_array[i] = -i;"
9875                      "}"
9876                      "sum;");
9877  CHECK_EQ(-28, result->Int32Value());
9878
9879  // Check assigned smis
9880  result = CompileRun("for (var i = 0; i < 8; i++) {"
9881                      "  ext_array[i] = i;"
9882                      "}"
9883                      "var sum = 0;"
9884                      "for (var i = 0; i < 8; i++) {"
9885                      "  sum += ext_array[i];"
9886                      "}"
9887                      "sum;");
9888  CHECK_EQ(28, result->Int32Value());
9889
9890  // Check assigned smis in reverse order
9891  result = CompileRun("for (var i = 8; --i >= 0; ) {"
9892                      "  ext_array[i] = i;"
9893                      "}"
9894                      "var sum = 0;"
9895                      "for (var i = 0; i < 8; i++) {"
9896                      "  sum += ext_array[i];"
9897                      "}"
9898                      "sum;");
9899  CHECK_EQ(28, result->Int32Value());
9900
9901  // Check pass through of assigned HeapNumbers
9902  result = CompileRun("var sum = 0;"
9903                      "for (var i = 0; i < 16; i+=2) {"
9904                      "  sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
9905                      "}"
9906                      "sum;");
9907  CHECK_EQ(-28, result->Int32Value());
9908
9909  // Check assigned HeapNumbers
9910  result = CompileRun("for (var i = 0; i < 16; i+=2) {"
9911                      "  ext_array[i] = (i * 0.5);"
9912                      "}"
9913                      "var sum = 0;"
9914                      "for (var i = 0; i < 16; i+=2) {"
9915                      "  sum += ext_array[i];"
9916                      "}"
9917                      "sum;");
9918  CHECK_EQ(28, result->Int32Value());
9919
9920  // Check assigned HeapNumbers in reverse order
9921  result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
9922                      "  ext_array[i] = (i * 0.5);"
9923                      "}"
9924                      "var sum = 0;"
9925                      "for (var i = 0; i < 16; i+=2) {"
9926                      "  sum += ext_array[i];"
9927                      "}"
9928                      "sum;");
9929  CHECK_EQ(28, result->Int32Value());
9930
9931  i::ScopedVector<char> test_buf(1024);
9932
9933  // Check legal boundary conditions.
9934  // The repeated loads and stores ensure the ICs are exercised.
9935  const char* boundary_program =
9936      "var res = 0;"
9937      "for (var i = 0; i < 16; i++) {"
9938      "  ext_array[i] = %lld;"
9939      "  if (i > 8) {"
9940      "    res = ext_array[i];"
9941      "  }"
9942      "}"
9943      "res;";
9944  i::OS::SNPrintF(test_buf,
9945                  boundary_program,
9946                  low);
9947  result = CompileRun(test_buf.start());
9948  CHECK_EQ(low, result->IntegerValue());
9949
9950  i::OS::SNPrintF(test_buf,
9951                  boundary_program,
9952                  high);
9953  result = CompileRun(test_buf.start());
9954  CHECK_EQ(high, result->IntegerValue());
9955
9956  // Check misprediction of type in IC.
9957  result = CompileRun("var tmp_array = ext_array;"
9958                      "var sum = 0;"
9959                      "for (var i = 0; i < 8; i++) {"
9960                      "  tmp_array[i] = i;"
9961                      "  sum += tmp_array[i];"
9962                      "  if (i == 4) {"
9963                      "    tmp_array = {};"
9964                      "  }"
9965                      "}"
9966                      "sum;");
9967  i::Heap::CollectAllGarbage(false);  // Force GC to trigger verification.
9968  CHECK_EQ(28, result->Int32Value());
9969
9970  // Make sure out-of-range loads do not throw.
9971  i::OS::SNPrintF(test_buf,
9972                  "var caught_exception = false;"
9973                  "try {"
9974                  "  ext_array[%d];"
9975                  "} catch (e) {"
9976                  "  caught_exception = true;"
9977                  "}"
9978                  "caught_exception;",
9979                  kElementCount);
9980  result = CompileRun(test_buf.start());
9981  CHECK_EQ(false, result->BooleanValue());
9982
9983  // Make sure out-of-range stores do not throw.
9984  i::OS::SNPrintF(test_buf,
9985                  "var caught_exception = false;"
9986                  "try {"
9987                  "  ext_array[%d] = 1;"
9988                  "} catch (e) {"
9989                  "  caught_exception = true;"
9990                  "}"
9991                  "caught_exception;",
9992                  kElementCount);
9993  result = CompileRun(test_buf.start());
9994  CHECK_EQ(false, result->BooleanValue());
9995
9996  // Check other boundary conditions, values and operations.
9997  result = CompileRun("for (var i = 0; i < 8; i++) {"
9998                      "  ext_array[7] = undefined;"
9999                      "}"
10000                      "ext_array[7];");
10001  CHECK_EQ(0, result->Int32Value());
10002  CHECK_EQ(0, static_cast<int>(jsobj->GetElement(7)->Number()));
10003
10004  result = CompileRun("for (var i = 0; i < 8; i++) {"
10005                      "  ext_array[6] = '2.3';"
10006                      "}"
10007                      "ext_array[6];");
10008  CHECK_EQ(2, result->Int32Value());
10009  CHECK_EQ(2, static_cast<int>(jsobj->GetElement(6)->Number()));
10010
10011  if (array_type != v8::kExternalFloatArray) {
10012    // Though the specification doesn't state it, be explicit about
10013    // converting NaNs and +/-Infinity to zero.
10014    result = CompileRun("for (var i = 0; i < 8; i++) {"
10015                        "  ext_array[i] = 5;"
10016                        "}"
10017                        "for (var i = 0; i < 8; i++) {"
10018                        "  ext_array[i] = NaN;"
10019                        "}"
10020                        "ext_array[5];");
10021    CHECK_EQ(0, result->Int32Value());
10022    CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5))->value());
10023
10024    result = CompileRun("for (var i = 0; i < 8; i++) {"
10025                        "  ext_array[i] = 5;"
10026                        "}"
10027                        "for (var i = 0; i < 8; i++) {"
10028                        "  ext_array[i] = Infinity;"
10029                        "}"
10030                        "ext_array[5];");
10031    CHECK_EQ(0, result->Int32Value());
10032    CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5))->value());
10033
10034    result = CompileRun("for (var i = 0; i < 8; i++) {"
10035                        "  ext_array[i] = 5;"
10036                        "}"
10037                        "for (var i = 0; i < 8; i++) {"
10038                        "  ext_array[i] = -Infinity;"
10039                        "}"
10040                        "ext_array[5];");
10041    CHECK_EQ(0, result->Int32Value());
10042    CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5))->value());
10043  }
10044
10045  result = CompileRun("ext_array[3] = 33;"
10046                      "delete ext_array[3];"
10047                      "ext_array[3];");
10048  CHECK_EQ(33, result->Int32Value());
10049
10050  result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
10051                      "ext_array[2] = 12; ext_array[3] = 13;"
10052                      "ext_array.__defineGetter__('2',"
10053                      "function() { return 120; });"
10054                      "ext_array[2];");
10055  CHECK_EQ(12, result->Int32Value());
10056
10057  result = CompileRun("var js_array = new Array(40);"
10058                      "js_array[0] = 77;"
10059                      "js_array;");
10060  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
10061
10062  result = CompileRun("ext_array[1] = 23;"
10063                      "ext_array.__proto__ = [];"
10064                      "js_array.__proto__ = ext_array;"
10065                      "js_array.concat(ext_array);");
10066  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
10067  CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
10068
10069  result = CompileRun("ext_array[1] = 23;");
10070  CHECK_EQ(23, result->Int32Value());
10071
10072  // Test more complex manipulations which cause eax to contain values
10073  // that won't be completely overwritten by loads from the arrays.
10074  // This catches bugs in the instructions used for the KeyedLoadIC
10075  // for byte and word types.
10076  {
10077    const int kXSize = 300;
10078    const int kYSize = 300;
10079    const int kLargeElementCount = kXSize * kYSize * 4;
10080    ElementType* large_array_data =
10081        static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
10082    i::Handle<ExternalArrayClass> large_array =
10083        i::Handle<ExternalArrayClass>::cast(
10084            i::Factory::NewExternalArray(kLargeElementCount,
10085                                         array_type,
10086                                         array_data));
10087    v8::Handle<v8::Object> large_obj = v8::Object::New();
10088    // Set the elements to be the external array.
10089    large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
10090                                                       array_type,
10091                                                       kLargeElementCount);
10092    context->Global()->Set(v8_str("large_array"), large_obj);
10093    // Initialize contents of a few rows.
10094    for (int x = 0; x < 300; x++) {
10095      int row = 0;
10096      int offset = row * 300 * 4;
10097      large_array_data[offset + 4 * x + 0] = (ElementType) 127;
10098      large_array_data[offset + 4 * x + 1] = (ElementType) 0;
10099      large_array_data[offset + 4 * x + 2] = (ElementType) 0;
10100      large_array_data[offset + 4 * x + 3] = (ElementType) 127;
10101      row = 150;
10102      offset = row * 300 * 4;
10103      large_array_data[offset + 4 * x + 0] = (ElementType) 127;
10104      large_array_data[offset + 4 * x + 1] = (ElementType) 0;
10105      large_array_data[offset + 4 * x + 2] = (ElementType) 0;
10106      large_array_data[offset + 4 * x + 3] = (ElementType) 127;
10107      row = 298;
10108      offset = row * 300 * 4;
10109      large_array_data[offset + 4 * x + 0] = (ElementType) 127;
10110      large_array_data[offset + 4 * x + 1] = (ElementType) 0;
10111      large_array_data[offset + 4 * x + 2] = (ElementType) 0;
10112      large_array_data[offset + 4 * x + 3] = (ElementType) 127;
10113    }
10114    // The goal of the code below is to make "offset" large enough
10115    // that the computation of the index (which goes into eax) has
10116    // high bits set which will not be overwritten by a byte or short
10117    // load.
10118    result = CompileRun("var failed = false;"
10119                        "var offset = 0;"
10120                        "for (var i = 0; i < 300; i++) {"
10121                        "  if (large_array[4 * i] != 127 ||"
10122                        "      large_array[4 * i + 1] != 0 ||"
10123                        "      large_array[4 * i + 2] != 0 ||"
10124                        "      large_array[4 * i + 3] != 127) {"
10125                        "    failed = true;"
10126                        "  }"
10127                        "}"
10128                        "offset = 150 * 300 * 4;"
10129                        "for (var i = 0; i < 300; i++) {"
10130                        "  if (large_array[offset + 4 * i] != 127 ||"
10131                        "      large_array[offset + 4 * i + 1] != 0 ||"
10132                        "      large_array[offset + 4 * i + 2] != 0 ||"
10133                        "      large_array[offset + 4 * i + 3] != 127) {"
10134                        "    failed = true;"
10135                        "  }"
10136                        "}"
10137                        "offset = 298 * 300 * 4;"
10138                        "for (var i = 0; i < 300; i++) {"
10139                        "  if (large_array[offset + 4 * i] != 127 ||"
10140                        "      large_array[offset + 4 * i + 1] != 0 ||"
10141                        "      large_array[offset + 4 * i + 2] != 0 ||"
10142                        "      large_array[offset + 4 * i + 3] != 127) {"
10143                        "    failed = true;"
10144                        "  }"
10145                        "}"
10146                        "!failed;");
10147    CHECK_EQ(true, result->BooleanValue());
10148    free(large_array_data);
10149  }
10150
10151  free(array_data);
10152}
10153
10154
10155THREADED_TEST(ExternalByteArray) {
10156  ExternalArrayTestHelper<i::ExternalByteArray, int8_t>(
10157      v8::kExternalByteArray,
10158      -128,
10159      127);
10160}
10161
10162
10163THREADED_TEST(ExternalUnsignedByteArray) {
10164  ExternalArrayTestHelper<i::ExternalUnsignedByteArray, uint8_t>(
10165      v8::kExternalUnsignedByteArray,
10166      0,
10167      255);
10168}
10169
10170
10171THREADED_TEST(ExternalShortArray) {
10172  ExternalArrayTestHelper<i::ExternalShortArray, int16_t>(
10173      v8::kExternalShortArray,
10174      -32768,
10175      32767);
10176}
10177
10178
10179THREADED_TEST(ExternalUnsignedShortArray) {
10180  ExternalArrayTestHelper<i::ExternalUnsignedShortArray, uint16_t>(
10181      v8::kExternalUnsignedShortArray,
10182      0,
10183      65535);
10184}
10185
10186
10187THREADED_TEST(ExternalIntArray) {
10188  ExternalArrayTestHelper<i::ExternalIntArray, int32_t>(
10189      v8::kExternalIntArray,
10190      INT_MIN,   // -2147483648
10191      INT_MAX);  //  2147483647
10192}
10193
10194
10195THREADED_TEST(ExternalUnsignedIntArray) {
10196  ExternalArrayTestHelper<i::ExternalUnsignedIntArray, uint32_t>(
10197      v8::kExternalUnsignedIntArray,
10198      0,
10199      UINT_MAX);  // 4294967295
10200}
10201
10202
10203THREADED_TEST(ExternalFloatArray) {
10204  ExternalArrayTestHelper<i::ExternalFloatArray, float>(
10205      v8::kExternalFloatArray,
10206      -500,
10207      500);
10208}
10209
10210
10211THREADED_TEST(ExternalArrays) {
10212  TestExternalByteArray();
10213  TestExternalUnsignedByteArray();
10214  TestExternalShortArray();
10215  TestExternalUnsignedShortArray();
10216  TestExternalIntArray();
10217  TestExternalUnsignedIntArray();
10218  TestExternalFloatArray();
10219}
10220
10221
10222void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
10223  v8::HandleScope scope;
10224  LocalContext context;
10225  for (int size = 0; size < 100; size += 10) {
10226    int element_size = ExternalArrayElementSize(array_type);
10227    void* external_data = malloc(size * element_size);
10228    v8::Handle<v8::Object> obj = v8::Object::New();
10229    obj->SetIndexedPropertiesToExternalArrayData(
10230        external_data, array_type, size);
10231    CHECK(obj->HasIndexedPropertiesInExternalArrayData());
10232    CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
10233    CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
10234    CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
10235    free(external_data);
10236  }
10237}
10238
10239
10240THREADED_TEST(ExternalArrayInfo) {
10241  ExternalArrayInfoTestHelper(v8::kExternalByteArray);
10242  ExternalArrayInfoTestHelper(v8::kExternalUnsignedByteArray);
10243  ExternalArrayInfoTestHelper(v8::kExternalShortArray);
10244  ExternalArrayInfoTestHelper(v8::kExternalUnsignedShortArray);
10245  ExternalArrayInfoTestHelper(v8::kExternalIntArray);
10246  ExternalArrayInfoTestHelper(v8::kExternalUnsignedIntArray);
10247  ExternalArrayInfoTestHelper(v8::kExternalFloatArray);
10248}
10249
10250
10251THREADED_TEST(ScriptContextDependence) {
10252  v8::HandleScope scope;
10253  LocalContext c1;
10254  const char *source = "foo";
10255  v8::Handle<v8::Script> dep = v8::Script::Compile(v8::String::New(source));
10256  v8::Handle<v8::Script> indep = v8::Script::New(v8::String::New(source));
10257  c1->Global()->Set(v8::String::New("foo"), v8::Integer::New(100));
10258  CHECK_EQ(dep->Run()->Int32Value(), 100);
10259  CHECK_EQ(indep->Run()->Int32Value(), 100);
10260  LocalContext c2;
10261  c2->Global()->Set(v8::String::New("foo"), v8::Integer::New(101));
10262  CHECK_EQ(dep->Run()->Int32Value(), 100);
10263  CHECK_EQ(indep->Run()->Int32Value(), 101);
10264}
10265
10266
10267THREADED_TEST(StackTrace) {
10268  v8::HandleScope scope;
10269  LocalContext context;
10270  v8::TryCatch try_catch;
10271  const char *source = "function foo() { FAIL.FAIL; }; foo();";
10272  v8::Handle<v8::String> src = v8::String::New(source);
10273  v8::Handle<v8::String> origin = v8::String::New("stack-trace-test");
10274  v8::Script::New(src, origin)->Run();
10275  CHECK(try_catch.HasCaught());
10276  v8::String::Utf8Value stack(try_catch.StackTrace());
10277  CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
10278}
10279
10280
10281// Checks that a StackFrame has certain expected values.
10282void checkStackFrame(const char* expected_script_name,
10283    const char* expected_func_name, int expected_line_number,
10284    int expected_column, bool is_eval, bool is_constructor,
10285    v8::Handle<v8::StackFrame> frame) {
10286  v8::HandleScope scope;
10287  v8::String::Utf8Value func_name(frame->GetFunctionName());
10288  v8::String::Utf8Value script_name(frame->GetScriptName());
10289  if (*script_name == NULL) {
10290    // The situation where there is no associated script, like for evals.
10291    CHECK(expected_script_name == NULL);
10292  } else {
10293    CHECK(strstr(*script_name, expected_script_name) != NULL);
10294  }
10295  CHECK(strstr(*func_name, expected_func_name) != NULL);
10296  CHECK_EQ(expected_line_number, frame->GetLineNumber());
10297  CHECK_EQ(expected_column, frame->GetColumn());
10298  CHECK_EQ(is_eval, frame->IsEval());
10299  CHECK_EQ(is_constructor, frame->IsConstructor());
10300}
10301
10302
10303v8::Handle<Value> AnalyzeStackInNativeCode(const v8::Arguments& args) {
10304  v8::HandleScope scope;
10305  const char* origin = "capture-stack-trace-test";
10306  const int kOverviewTest = 1;
10307  const int kDetailedTest = 2;
10308
10309  ASSERT(args.Length() == 1);
10310
10311  int testGroup = args[0]->Int32Value();
10312  if (testGroup == kOverviewTest) {
10313    v8::Handle<v8::StackTrace> stackTrace =
10314        v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kOverview);
10315    CHECK_EQ(4, stackTrace->GetFrameCount());
10316    checkStackFrame(origin, "bar", 2, 10, false, false,
10317                    stackTrace->GetFrame(0));
10318    checkStackFrame(origin, "foo", 6, 3, false, false,
10319                    stackTrace->GetFrame(1));
10320    checkStackFrame(NULL, "", 1, 1, false, false,
10321                    stackTrace->GetFrame(2));
10322    // The last frame is an anonymous function that has the initial call.
10323    checkStackFrame(origin, "", 8, 7, false, false,
10324                    stackTrace->GetFrame(3));
10325
10326    CHECK(stackTrace->AsArray()->IsArray());
10327  } else if (testGroup == kDetailedTest) {
10328    v8::Handle<v8::StackTrace> stackTrace =
10329        v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
10330    CHECK_EQ(4, stackTrace->GetFrameCount());
10331    checkStackFrame(origin, "bat", 4, 22, false, false,
10332                    stackTrace->GetFrame(0));
10333    checkStackFrame(origin, "baz", 8, 3, false, true,
10334                    stackTrace->GetFrame(1));
10335#ifdef ENABLE_DEBUGGER_SUPPORT
10336    bool is_eval = true;
10337#else  // ENABLE_DEBUGGER_SUPPORT
10338    bool is_eval = false;
10339#endif  // ENABLE_DEBUGGER_SUPPORT
10340
10341    checkStackFrame(NULL, "", 1, 1, is_eval, false,
10342                    stackTrace->GetFrame(2));
10343    // The last frame is an anonymous function that has the initial call to foo.
10344    checkStackFrame(origin, "", 10, 1, false, false,
10345                    stackTrace->GetFrame(3));
10346
10347    CHECK(stackTrace->AsArray()->IsArray());
10348  }
10349  return v8::Undefined();
10350}
10351
10352
10353// Tests the C++ StackTrace API.
10354THREADED_TEST(CaptureStackTrace) {
10355  v8::HandleScope scope;
10356  v8::Handle<v8::String> origin = v8::String::New("capture-stack-trace-test");
10357  Local<ObjectTemplate> templ = ObjectTemplate::New();
10358  templ->Set(v8_str("AnalyzeStackInNativeCode"),
10359             v8::FunctionTemplate::New(AnalyzeStackInNativeCode));
10360  LocalContext context(0, templ);
10361
10362  // Test getting OVERVIEW information. Should ignore information that is not
10363  // script name, function name, line number, and column offset.
10364  const char *overview_source =
10365    "function bar() {\n"
10366    "  var y; AnalyzeStackInNativeCode(1);\n"
10367    "}\n"
10368    "function foo() {\n"
10369    "\n"
10370    "  bar();\n"
10371    "}\n"
10372    "var x;eval('new foo();');";
10373  v8::Handle<v8::String> overview_src = v8::String::New(overview_source);
10374  v8::Handle<Value> overview_result =
10375      v8::Script::New(overview_src, origin)->Run();
10376  ASSERT(!overview_result.IsEmpty());
10377  ASSERT(overview_result->IsObject());
10378
10379  // Test getting DETAILED information.
10380  const char *detailed_source =
10381    "function bat() {AnalyzeStackInNativeCode(2);\n"
10382    "}\n"
10383    "\n"
10384    "function baz() {\n"
10385    "  bat();\n"
10386    "}\n"
10387    "eval('new baz();');";
10388  v8::Handle<v8::String> detailed_src = v8::String::New(detailed_source);
10389  // Make the script using a non-zero line and column offset.
10390  v8::Handle<v8::Integer> line_offset = v8::Integer::New(3);
10391  v8::Handle<v8::Integer> column_offset = v8::Integer::New(5);
10392  v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
10393  v8::Handle<v8::Script> detailed_script(
10394      v8::Script::New(detailed_src, &detailed_origin));
10395  v8::Handle<Value> detailed_result = detailed_script->Run();
10396  ASSERT(!detailed_result.IsEmpty());
10397  ASSERT(detailed_result->IsObject());
10398}
10399
10400
10401static void StackTraceForUncaughtExceptionListener(
10402    v8::Handle<v8::Message> message,
10403    v8::Handle<Value>) {
10404  v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
10405  CHECK_EQ(2, stack_trace->GetFrameCount());
10406  checkStackFrame("origin", "foo", 2, 3, false, false,
10407                  stack_trace->GetFrame(0));
10408  checkStackFrame("origin", "bar", 5, 3, false, false,
10409                  stack_trace->GetFrame(1));
10410}
10411
10412TEST(CaptureStackTraceForUncaughtException) {
10413  report_count = 0;
10414  v8::HandleScope scope;
10415  LocalContext env;
10416  v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
10417  v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
10418
10419  Script::Compile(v8_str("function foo() {\n"
10420                         "  throw 1;\n"
10421                         "};\n"
10422                         "function bar() {\n"
10423                         "  foo();\n"
10424                         "};"),
10425                  v8_str("origin"))->Run();
10426  v8::Local<v8::Object> global = env->Global();
10427  Local<Value> trouble = global->Get(v8_str("bar"));
10428  CHECK(trouble->IsFunction());
10429  Function::Cast(*trouble)->Call(global, 0, NULL);
10430  v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
10431  v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
10432}
10433
10434
10435// Test that idle notification can be handled and eventually returns true.
10436THREADED_TEST(IdleNotification) {
10437  bool rv = false;
10438  for (int i = 0; i < 100; i++) {
10439    rv = v8::V8::IdleNotification();
10440    if (rv)
10441      break;
10442  }
10443  CHECK(rv == true);
10444}
10445
10446
10447static uint32_t* stack_limit;
10448
10449static v8::Handle<Value> GetStackLimitCallback(const v8::Arguments& args) {
10450  stack_limit = reinterpret_cast<uint32_t*>(i::StackGuard::climit());
10451  return v8::Undefined();
10452}
10453
10454
10455// Uses the address of a local variable to determine the stack top now.
10456// Given a size, returns an address that is that far from the current
10457// top of stack.
10458static uint32_t* ComputeStackLimit(uint32_t size) {
10459  uint32_t* answer = &size - (size / sizeof(size));
10460  // If the size is very large and the stack is very near the bottom of
10461  // memory then the calculation above may wrap around and give an address
10462  // that is above the (downwards-growing) stack.  In that case we return
10463  // a very low address.
10464  if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
10465  return answer;
10466}
10467
10468
10469TEST(SetResourceConstraints) {
10470  static const int K = 1024;
10471  uint32_t* set_limit = ComputeStackLimit(128 * K);
10472
10473  // Set stack limit.
10474  v8::ResourceConstraints constraints;
10475  constraints.set_stack_limit(set_limit);
10476  CHECK(v8::SetResourceConstraints(&constraints));
10477
10478  // Execute a script.
10479  v8::HandleScope scope;
10480  LocalContext env;
10481  Local<v8::FunctionTemplate> fun_templ =
10482      v8::FunctionTemplate::New(GetStackLimitCallback);
10483  Local<Function> fun = fun_templ->GetFunction();
10484  env->Global()->Set(v8_str("get_stack_limit"), fun);
10485  CompileRun("get_stack_limit();");
10486
10487  CHECK(stack_limit == set_limit);
10488}
10489
10490
10491TEST(SetResourceConstraintsInThread) {
10492  uint32_t* set_limit;
10493  {
10494    v8::Locker locker;
10495    static const int K = 1024;
10496    set_limit = ComputeStackLimit(128 * K);
10497
10498    // Set stack limit.
10499    v8::ResourceConstraints constraints;
10500    constraints.set_stack_limit(set_limit);
10501    CHECK(v8::SetResourceConstraints(&constraints));
10502
10503    // Execute a script.
10504    v8::HandleScope scope;
10505    LocalContext env;
10506    Local<v8::FunctionTemplate> fun_templ =
10507        v8::FunctionTemplate::New(GetStackLimitCallback);
10508    Local<Function> fun = fun_templ->GetFunction();
10509    env->Global()->Set(v8_str("get_stack_limit"), fun);
10510    CompileRun("get_stack_limit();");
10511
10512    CHECK(stack_limit == set_limit);
10513  }
10514  {
10515    v8::Locker locker;
10516    CHECK(stack_limit == set_limit);
10517  }
10518}
10519
10520
10521THREADED_TEST(GetHeapStatistics) {
10522  v8::HandleScope scope;
10523  LocalContext c1;
10524  v8::HeapStatistics heap_statistics;
10525  CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
10526  CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
10527  v8::V8::GetHeapStatistics(&heap_statistics);
10528  CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
10529  CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
10530}
10531
10532
10533static double DoubleFromBits(uint64_t value) {
10534  double target;
10535#ifdef BIG_ENDIAN_FLOATING_POINT
10536  const int kIntSize = 4;
10537  // Somebody swapped the lower and higher half of doubles.
10538  memcpy(&target, reinterpret_cast<char*>(&value) + kIntSize, kIntSize);
10539  memcpy(reinterpret_cast<char*>(&target) + kIntSize, &value, kIntSize);
10540#else
10541  memcpy(&target, &value, sizeof(target));
10542#endif
10543  return target;
10544}
10545
10546
10547static uint64_t DoubleToBits(double value) {
10548  uint64_t target;
10549#ifdef BIG_ENDIAN_FLOATING_POINT
10550  const int kIntSize = 4;
10551  // Somebody swapped the lower and higher half of doubles.
10552  memcpy(&target, reinterpret_cast<char*>(&value) + kIntSize, kIntSize);
10553  memcpy(reinterpret_cast<char*>(&target) + kIntSize, &value, kIntSize);
10554#else
10555  memcpy(&target, &value, sizeof(target));
10556#endif
10557  return target;
10558}
10559
10560
10561static double DoubleToDateTime(double input) {
10562  double date_limit = 864e13;
10563  if (IsNaN(input) || input < -date_limit || input > date_limit) {
10564    return i::OS::nan_value();
10565  }
10566  return (input < 0) ? -(floor(-input)) : floor(input);
10567}
10568
10569// We don't have a consistent way to write 64-bit constants syntactically, so we
10570// split them into two 32-bit constants and combine them programmatically.
10571static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
10572  return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
10573}
10574
10575
10576THREADED_TEST(QuietSignalingNaNs) {
10577  v8::HandleScope scope;
10578  LocalContext context;
10579  v8::TryCatch try_catch;
10580
10581  // Special double values.
10582  double snan = DoubleFromBits(0x7ff00000, 0x00000001);
10583  double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
10584  double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
10585  double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
10586  double min_normal = DoubleFromBits(0x00100000, 0x00000000);
10587  double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
10588  double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
10589
10590  // Date values are capped at +/-100000000 days (times 864e5 ms per day)
10591  // on either side of the epoch.
10592  double date_limit = 864e13;
10593
10594  double test_values[] = {
10595      snan,
10596      qnan,
10597      infinity,
10598      max_normal,
10599      date_limit + 1,
10600      date_limit,
10601      min_normal,
10602      max_denormal,
10603      min_denormal,
10604      0,
10605      -0,
10606      -min_denormal,
10607      -max_denormal,
10608      -min_normal,
10609      -date_limit,
10610      -date_limit - 1,
10611      -max_normal,
10612      -infinity,
10613      -qnan,
10614      -snan
10615  };
10616  int num_test_values = 20;
10617
10618  for (int i = 0; i < num_test_values; i++) {
10619    double test_value = test_values[i];
10620
10621    // Check that Number::New preserves non-NaNs and quiets SNaNs.
10622    v8::Handle<v8::Value> number = v8::Number::New(test_value);
10623    double stored_number = number->NumberValue();
10624    if (!IsNaN(test_value)) {
10625      CHECK_EQ(test_value, stored_number);
10626    } else {
10627      uint64_t stored_bits = DoubleToBits(stored_number);
10628      // Check if quiet nan (bits 51..62 all set).
10629      CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
10630    }
10631
10632    // Check that Date::New preserves non-NaNs in the date range and
10633    // quiets SNaNs.
10634    v8::Handle<v8::Value> date = v8::Date::New(test_value);
10635    double expected_stored_date = DoubleToDateTime(test_value);
10636    double stored_date = date->NumberValue();
10637    if (!IsNaN(expected_stored_date)) {
10638      CHECK_EQ(expected_stored_date, stored_date);
10639    } else {
10640      uint64_t stored_bits = DoubleToBits(stored_date);
10641      // Check if quiet nan (bits 51..62 all set).
10642      CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
10643    }
10644  }
10645}
10646
10647
10648static v8::Handle<Value> SpaghettiIncident(const v8::Arguments& args) {
10649  v8::HandleScope scope;
10650  v8::TryCatch tc;
10651  v8::Handle<v8::String> str = args[0]->ToString();
10652  if (tc.HasCaught())
10653    return tc.ReThrow();
10654  return v8::Undefined();
10655}
10656
10657
10658// Test that an exception can be propagated down through a spaghetti
10659// stack using ReThrow.
10660THREADED_TEST(SpaghettiStackReThrow) {
10661  v8::HandleScope scope;
10662  LocalContext context;
10663  context->Global()->Set(
10664      v8::String::New("s"),
10665      v8::FunctionTemplate::New(SpaghettiIncident)->GetFunction());
10666  v8::TryCatch try_catch;
10667  CompileRun(
10668      "var i = 0;"
10669      "var o = {"
10670      "  toString: function () {"
10671      "    if (i == 10) {"
10672      "      throw 'Hey!';"
10673      "    } else {"
10674      "      i++;"
10675      "      return s(o);"
10676      "    }"
10677      "  }"
10678      "};"
10679      "s(o);");
10680  CHECK(try_catch.HasCaught());
10681  v8::String::Utf8Value value(try_catch.Exception());
10682  CHECK_EQ(0, strcmp(*value, "Hey!"));
10683}
10684
10685
10686TEST(Regress528) {
10687  v8::V8::Initialize();
10688
10689  v8::HandleScope scope;
10690  v8::Persistent<Context> context;
10691  v8::Persistent<Context> other_context;
10692  int gc_count;
10693
10694  // Create a context used to keep the code from aging in the compilation
10695  // cache.
10696  other_context = Context::New();
10697
10698  // Context-dependent context data creates reference from the compilation
10699  // cache to the global object.
10700  const char* source_simple = "1";
10701  context = Context::New();
10702  {
10703    v8::HandleScope scope;
10704
10705    context->Enter();
10706    Local<v8::String> obj = v8::String::New("");
10707    context->SetData(obj);
10708    CompileRun(source_simple);
10709    context->Exit();
10710  }
10711  context.Dispose();
10712  for (gc_count = 1; gc_count < 10; gc_count++) {
10713    other_context->Enter();
10714    CompileRun(source_simple);
10715    other_context->Exit();
10716    i::Heap::CollectAllGarbage(false);
10717    if (GetGlobalObjectsCount() == 1) break;
10718  }
10719  CHECK_GE(2, gc_count);
10720  CHECK_EQ(1, GetGlobalObjectsCount());
10721
10722  // Eval in a function creates reference from the compilation cache to the
10723  // global object.
10724  const char* source_eval = "function f(){eval('1')}; f()";
10725  context = Context::New();
10726  {
10727    v8::HandleScope scope;
10728
10729    context->Enter();
10730    CompileRun(source_eval);
10731    context->Exit();
10732  }
10733  context.Dispose();
10734  for (gc_count = 1; gc_count < 10; gc_count++) {
10735    other_context->Enter();
10736    CompileRun(source_eval);
10737    other_context->Exit();
10738    i::Heap::CollectAllGarbage(false);
10739    if (GetGlobalObjectsCount() == 1) break;
10740  }
10741  CHECK_GE(2, gc_count);
10742  CHECK_EQ(1, GetGlobalObjectsCount());
10743
10744  // Looking up the line number for an exception creates reference from the
10745  // compilation cache to the global object.
10746  const char* source_exception = "function f(){throw 1;} f()";
10747  context = Context::New();
10748  {
10749    v8::HandleScope scope;
10750
10751    context->Enter();
10752    v8::TryCatch try_catch;
10753    CompileRun(source_exception);
10754    CHECK(try_catch.HasCaught());
10755    v8::Handle<v8::Message> message = try_catch.Message();
10756    CHECK(!message.IsEmpty());
10757    CHECK_EQ(1, message->GetLineNumber());
10758    context->Exit();
10759  }
10760  context.Dispose();
10761  for (gc_count = 1; gc_count < 10; gc_count++) {
10762    other_context->Enter();
10763    CompileRun(source_exception);
10764    other_context->Exit();
10765    i::Heap::CollectAllGarbage(false);
10766    if (GetGlobalObjectsCount() == 1) break;
10767  }
10768  CHECK_GE(2, gc_count);
10769  CHECK_EQ(1, GetGlobalObjectsCount());
10770
10771  other_context.Dispose();
10772}
10773
10774
10775THREADED_TEST(ScriptOrigin) {
10776  v8::HandleScope scope;
10777  LocalContext env;
10778  v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
10779  v8::Handle<v8::String> script = v8::String::New(
10780      "function f() {}\n\nfunction g() {}");
10781  v8::Script::Compile(script, &origin)->Run();
10782  v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
10783      env->Global()->Get(v8::String::New("f")));
10784  v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
10785      env->Global()->Get(v8::String::New("g")));
10786
10787  v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
10788  CHECK_EQ("test", *v8::String::AsciiValue(script_origin_f.ResourceName()));
10789  CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
10790
10791  v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
10792  CHECK_EQ("test", *v8::String::AsciiValue(script_origin_g.ResourceName()));
10793  CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
10794}
10795
10796
10797THREADED_TEST(ScriptLineNumber) {
10798  v8::HandleScope scope;
10799  LocalContext env;
10800  v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
10801  v8::Handle<v8::String> script = v8::String::New(
10802      "function f() {}\n\nfunction g() {}");
10803  v8::Script::Compile(script, &origin)->Run();
10804  v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
10805      env->Global()->Get(v8::String::New("f")));
10806  v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
10807      env->Global()->Get(v8::String::New("g")));
10808  CHECK_EQ(0, f->GetScriptLineNumber());
10809  CHECK_EQ(2, g->GetScriptLineNumber());
10810}
10811
10812
10813static v8::Handle<Value> GetterWhichReturns42(Local<String> name,
10814                                              const AccessorInfo& info) {
10815  return v8_num(42);
10816}
10817
10818
10819static void SetterWhichSetsYOnThisTo23(Local<String> name,
10820                                       Local<Value> value,
10821                                       const AccessorInfo& info) {
10822  info.This()->Set(v8_str("y"), v8_num(23));
10823}
10824
10825
10826TEST(SetterOnConstructorPrototype) {
10827  v8::HandleScope scope;
10828  Local<ObjectTemplate> templ = ObjectTemplate::New();
10829  templ->SetAccessor(v8_str("x"),
10830                     GetterWhichReturns42,
10831                     SetterWhichSetsYOnThisTo23);
10832  LocalContext context;
10833  context->Global()->Set(v8_str("P"), templ->NewInstance());
10834  CompileRun("function C1() {"
10835             "  this.x = 23;"
10836             "};"
10837             "C1.prototype = P;"
10838             "function C2() {"
10839             "  this.x = 23"
10840             "};"
10841             "C2.prototype = { };"
10842             "C2.prototype.__proto__ = P;");
10843
10844  v8::Local<v8::Script> script;
10845  script = v8::Script::Compile(v8_str("new C1();"));
10846  for (int i = 0; i < 10; i++) {
10847    v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
10848    CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
10849    CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
10850  }
10851
10852  script = v8::Script::Compile(v8_str("new C2();"));
10853  for (int i = 0; i < 10; i++) {
10854    v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
10855    CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
10856    CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
10857  }
10858}
10859
10860
10861static v8::Handle<Value> NamedPropertyGetterWhichReturns42(
10862    Local<String> name, const AccessorInfo& info) {
10863  return v8_num(42);
10864}
10865
10866
10867static v8::Handle<Value> NamedPropertySetterWhichSetsYOnThisTo23(
10868    Local<String> name, Local<Value> value, const AccessorInfo& info) {
10869  if (name->Equals(v8_str("x"))) {
10870    info.This()->Set(v8_str("y"), v8_num(23));
10871  }
10872  return v8::Handle<Value>();
10873}
10874
10875
10876THREADED_TEST(InterceptorOnConstructorPrototype) {
10877  v8::HandleScope scope;
10878  Local<ObjectTemplate> templ = ObjectTemplate::New();
10879  templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
10880                                 NamedPropertySetterWhichSetsYOnThisTo23);
10881  LocalContext context;
10882  context->Global()->Set(v8_str("P"), templ->NewInstance());
10883  CompileRun("function C1() {"
10884             "  this.x = 23;"
10885             "};"
10886             "C1.prototype = P;"
10887             "function C2() {"
10888             "  this.x = 23"
10889             "};"
10890             "C2.prototype = { };"
10891             "C2.prototype.__proto__ = P;");
10892
10893  v8::Local<v8::Script> script;
10894  script = v8::Script::Compile(v8_str("new C1();"));
10895  for (int i = 0; i < 10; i++) {
10896    v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
10897    CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
10898    CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
10899  }
10900
10901  script = v8::Script::Compile(v8_str("new C2();"));
10902  for (int i = 0; i < 10; i++) {
10903    v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
10904    CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
10905    CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
10906  }
10907}
10908
10909
10910TEST(Bug618) {
10911  const char* source = "function C1() {"
10912                       "  this.x = 23;"
10913                       "};"
10914                       "C1.prototype = P;";
10915
10916  v8::HandleScope scope;
10917  LocalContext context;
10918  v8::Local<v8::Script> script;
10919
10920  // Use a simple object as prototype.
10921  v8::Local<v8::Object> prototype = v8::Object::New();
10922  prototype->Set(v8_str("y"), v8_num(42));
10923  context->Global()->Set(v8_str("P"), prototype);
10924
10925  // This compile will add the code to the compilation cache.
10926  CompileRun(source);
10927
10928  script = v8::Script::Compile(v8_str("new C1();"));
10929  for (int i = 0; i < 10; i++) {
10930    v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
10931    CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
10932    CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
10933  }
10934
10935  // Use an API object with accessors as prototype.
10936  Local<ObjectTemplate> templ = ObjectTemplate::New();
10937  templ->SetAccessor(v8_str("x"),
10938                     GetterWhichReturns42,
10939                     SetterWhichSetsYOnThisTo23);
10940  context->Global()->Set(v8_str("P"), templ->NewInstance());
10941
10942  // This compile will get the code from the compilation cache.
10943  CompileRun(source);
10944
10945  script = v8::Script::Compile(v8_str("new C1();"));
10946  for (int i = 0; i < 10; i++) {
10947    v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
10948    CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
10949    CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
10950  }
10951}
10952
10953int prologue_call_count = 0;
10954int epilogue_call_count = 0;
10955int prologue_call_count_second = 0;
10956int epilogue_call_count_second = 0;
10957
10958void PrologueCallback(v8::GCType, v8::GCCallbackFlags) {
10959  ++prologue_call_count;
10960}
10961
10962void EpilogueCallback(v8::GCType, v8::GCCallbackFlags) {
10963  ++epilogue_call_count;
10964}
10965
10966void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
10967  ++prologue_call_count_second;
10968}
10969
10970void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
10971  ++epilogue_call_count_second;
10972}
10973
10974TEST(GCCallbacks) {
10975  LocalContext context;
10976
10977  v8::V8::AddGCPrologueCallback(PrologueCallback);
10978  v8::V8::AddGCEpilogueCallback(EpilogueCallback);
10979  CHECK_EQ(0, prologue_call_count);
10980  CHECK_EQ(0, epilogue_call_count);
10981  i::Heap::CollectAllGarbage(false);
10982  CHECK_EQ(1, prologue_call_count);
10983  CHECK_EQ(1, epilogue_call_count);
10984  v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
10985  v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
10986  i::Heap::CollectAllGarbage(false);
10987  CHECK_EQ(2, prologue_call_count);
10988  CHECK_EQ(2, epilogue_call_count);
10989  CHECK_EQ(1, prologue_call_count_second);
10990  CHECK_EQ(1, epilogue_call_count_second);
10991  v8::V8::RemoveGCPrologueCallback(PrologueCallback);
10992  v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
10993  i::Heap::CollectAllGarbage(false);
10994  CHECK_EQ(2, prologue_call_count);
10995  CHECK_EQ(2, epilogue_call_count);
10996  CHECK_EQ(2, prologue_call_count_second);
10997  CHECK_EQ(2, epilogue_call_count_second);
10998  v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
10999  v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
11000  i::Heap::CollectAllGarbage(false);
11001  CHECK_EQ(2, prologue_call_count);
11002  CHECK_EQ(2, epilogue_call_count);
11003  CHECK_EQ(2, prologue_call_count_second);
11004  CHECK_EQ(2, epilogue_call_count_second);
11005}
11006
11007
11008THREADED_TEST(AddToJSFunctionResultCache) {
11009  i::FLAG_allow_natives_syntax = true;
11010  v8::HandleScope scope;
11011
11012  LocalContext context;
11013
11014  const char* code =
11015      "(function() {"
11016      "  var key0 = 'a';"
11017      "  var key1 = 'b';"
11018      "  var r0 = %_GetFromCache(0, key0);"
11019      "  var r1 = %_GetFromCache(0, key1);"
11020      "  var r0_ = %_GetFromCache(0, key0);"
11021      "  if (r0 !== r0_)"
11022      "    return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
11023      "  var r1_ = %_GetFromCache(0, key1);"
11024      "  if (r1 !== r1_)"
11025      "    return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
11026      "  return 'PASSED';"
11027      "})()";
11028  i::Heap::ClearJSFunctionResultCaches();
11029  ExpectString(code, "PASSED");
11030}
11031
11032
11033static const int k0CacheSize = 16;
11034
11035THREADED_TEST(FillJSFunctionResultCache) {
11036  i::FLAG_allow_natives_syntax = true;
11037  v8::HandleScope scope;
11038
11039  LocalContext context;
11040
11041  const char* code =
11042      "(function() {"
11043      "  var k = 'a';"
11044      "  var r = %_GetFromCache(0, k);"
11045      "  for (var i = 0; i < 16; i++) {"
11046      "    %_GetFromCache(0, 'a' + i);"
11047      "  };"
11048      "  if (r === %_GetFromCache(0, k))"
11049      "    return 'FAILED: k0CacheSize is too small';"
11050      "  return 'PASSED';"
11051      "})()";
11052  i::Heap::ClearJSFunctionResultCaches();
11053  ExpectString(code, "PASSED");
11054}
11055
11056
11057THREADED_TEST(RoundRobinGetFromCache) {
11058  i::FLAG_allow_natives_syntax = true;
11059  v8::HandleScope scope;
11060
11061  LocalContext context;
11062
11063  const char* code =
11064      "(function() {"
11065      "  var keys = [];"
11066      "  for (var i = 0; i < 16; i++) keys.push(i);"
11067      "  var values = [];"
11068      "  for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
11069      "  for (var i = 0; i < 16; i++) {"
11070      "    var v = %_GetFromCache(0, keys[i]);"
11071      "    if (v !== values[i])"
11072      "      return 'Wrong value for ' + "
11073      "          keys[i] + ': ' + v + ' vs. ' + values[i];"
11074      "  };"
11075      "  return 'PASSED';"
11076      "})()";
11077  i::Heap::ClearJSFunctionResultCaches();
11078  ExpectString(code, "PASSED");
11079}
11080
11081
11082THREADED_TEST(ReverseGetFromCache) {
11083  i::FLAG_allow_natives_syntax = true;
11084  v8::HandleScope scope;
11085
11086  LocalContext context;
11087
11088  const char* code =
11089      "(function() {"
11090      "  var keys = [];"
11091      "  for (var i = 0; i < 16; i++) keys.push(i);"
11092      "  var values = [];"
11093      "  for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
11094      "  for (var i = 15; i >= 16; i--) {"
11095      "    var v = %_GetFromCache(0, keys[i]);"
11096      "    if (v !== values[i])"
11097      "      return 'Wrong value for ' + "
11098      "          keys[i] + ': ' + v + ' vs. ' + values[i];"
11099      "  };"
11100      "  return 'PASSED';"
11101      "})()";
11102  i::Heap::ClearJSFunctionResultCaches();
11103  ExpectString(code, "PASSED");
11104}
11105
11106
11107THREADED_TEST(TestEviction) {
11108  i::FLAG_allow_natives_syntax = true;
11109  v8::HandleScope scope;
11110
11111  LocalContext context;
11112
11113  const char* code =
11114      "(function() {"
11115      "  for (var i = 0; i < 2*16; i++) {"
11116      "    %_GetFromCache(0, 'a' + i);"
11117      "  };"
11118      "  return 'PASSED';"
11119      "})()";
11120  i::Heap::ClearJSFunctionResultCaches();
11121  ExpectString(code, "PASSED");
11122}
11123
11124
11125THREADED_TEST(TwoByteStringInAsciiCons) {
11126  // See Chromium issue 47824.
11127  v8::HandleScope scope;
11128
11129  LocalContext context;
11130  const char* init_code =
11131      "var str1 = 'abelspendabel';"
11132      "var str2 = str1 + str1 + str1;"
11133      "str2;";
11134  Local<Value> result = CompileRun(init_code);
11135
11136  CHECK(result->IsString());
11137  i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
11138  int length = string->length();
11139  CHECK(string->IsAsciiRepresentation());
11140
11141  FlattenString(string);
11142  i::Handle<i::String> flat_string = FlattenGetString(string);
11143
11144  CHECK(string->IsAsciiRepresentation());
11145  CHECK(flat_string->IsAsciiRepresentation());
11146
11147  // Create external resource.
11148  uint16_t* uc16_buffer = new uint16_t[length + 1];
11149
11150  i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
11151  uc16_buffer[length] = 0;
11152
11153  TestResource resource(uc16_buffer);
11154
11155  flat_string->MakeExternal(&resource);
11156
11157  CHECK(flat_string->IsTwoByteRepresentation());
11158
11159  // At this point, we should have a Cons string which is flat and ASCII,
11160  // with a first half that is a two-byte string (although it only contains
11161  // ASCII characters). This is a valid sequence of steps, and it can happen
11162  // in real pages.
11163
11164  CHECK(string->IsAsciiRepresentation());
11165  i::ConsString* cons = i::ConsString::cast(*string);
11166  CHECK_EQ(0, cons->second()->length());
11167  CHECK(cons->first()->IsTwoByteRepresentation());
11168
11169  // Check that some string operations work.
11170
11171  // Atom RegExp.
11172  Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
11173  CHECK_EQ(6, reresult->Int32Value());
11174
11175  // Nonatom RegExp.
11176  reresult = CompileRun("str2.match(/abe./g).length;");
11177  CHECK_EQ(6, reresult->Int32Value());
11178
11179  reresult = CompileRun("str2.search(/bel/g);");
11180  CHECK_EQ(1, reresult->Int32Value());
11181
11182  reresult = CompileRun("str2.search(/be./g);");
11183  CHECK_EQ(1, reresult->Int32Value());
11184
11185  ExpectTrue("/bel/g.test(str2);");
11186
11187  ExpectTrue("/be./g.test(str2);");
11188
11189  reresult = CompileRun("/bel/g.exec(str2);");
11190  CHECK(!reresult->IsNull());
11191
11192  reresult = CompileRun("/be./g.exec(str2);");
11193  CHECK(!reresult->IsNull());
11194
11195  ExpectString("str2.substring(2, 10);", "elspenda");
11196
11197  ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
11198
11199  ExpectString("str2.charAt(2);", "e");
11200
11201  reresult = CompileRun("str2.charCodeAt(2);");
11202  CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
11203}
11204
11205
11206// Failed access check callback that performs a GC on each invocation.
11207void FailedAccessCheckCallbackGC(Local<v8::Object> target,
11208                                 v8::AccessType type,
11209                                 Local<v8::Value> data) {
11210  i::Heap::CollectAllGarbage(true);
11211}
11212
11213
11214TEST(GCInFailedAccessCheckCallback) {
11215  // Install a failed access check callback that performs a GC on each
11216  // invocation. Then force the callback to be called from va
11217
11218  v8::V8::Initialize();
11219  v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
11220
11221  v8::HandleScope scope;
11222
11223  // Create an ObjectTemplate for global objects and install access
11224  // check callbacks that will block access.
11225  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
11226  global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
11227                                           IndexedGetAccessBlocker,
11228                                           v8::Handle<v8::Value>(),
11229                                           false);
11230
11231  // Create a context and set an x property on it's global object.
11232  LocalContext context0(NULL, global_template);
11233  context0->Global()->Set(v8_str("x"), v8_num(42));
11234  v8::Handle<v8::Object> global0 = context0->Global();
11235
11236  // Create a context with a different security token so that the
11237  // failed access check callback will be called on each access.
11238  LocalContext context1(NULL, global_template);
11239  context1->Global()->Set(v8_str("other"), global0);
11240
11241  // Get property with failed access check.
11242  ExpectUndefined("other.x");
11243
11244  // Get element with failed access check.
11245  ExpectUndefined("other[0]");
11246
11247  // Set property with failed access check.
11248  v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
11249  CHECK(result->IsObject());
11250
11251  // Set element with failed access check.
11252  result = CompileRun("other[0] = new Object()");
11253  CHECK(result->IsObject());
11254
11255  // Get property attribute with failed access check.
11256  ExpectFalse("\'x\' in other");
11257
11258  // Get property attribute for element with failed access check.
11259  ExpectFalse("0 in other");
11260
11261  // Delete property.
11262  ExpectFalse("delete other.x");
11263
11264  // Delete element.
11265  CHECK_EQ(false, global0->Delete(0));
11266
11267  // DefineAccessor.
11268  CHECK_EQ(false,
11269           global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
11270
11271  // Define JavaScript accessor.
11272  ExpectUndefined("Object.prototype.__defineGetter__.call("
11273                  "    other, \'x\', function() { return 42; })");
11274
11275  // LookupAccessor.
11276  ExpectUndefined("Object.prototype.__lookupGetter__.call("
11277                  "    other, \'x\')");
11278
11279  // HasLocalElement.
11280  ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
11281
11282  CHECK_EQ(false, global0->HasRealIndexedProperty(0));
11283  CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
11284  CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
11285
11286  // Reset the failed access check callback so it does not influence
11287  // the other tests.
11288  v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
11289}
11290