test-api.cc revision b8e0da25ee8efac3bb05cd6b2730aafbd96119f4
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#include "parser.h"
41#include "unicode-inl.h"
42
43static const bool kLogThreading = true;
44
45static bool IsNaN(double x) {
46#ifdef WIN32
47  return _isnan(x);
48#else
49  return isnan(x);
50#endif
51}
52
53using ::v8::ObjectTemplate;
54using ::v8::Value;
55using ::v8::Context;
56using ::v8::Local;
57using ::v8::String;
58using ::v8::Script;
59using ::v8::Function;
60using ::v8::AccessorInfo;
61using ::v8::Extension;
62
63namespace i = ::i;
64
65
66static void ExpectString(const char* code, const char* expected) {
67  Local<Value> result = CompileRun(code);
68  CHECK(result->IsString());
69  String::AsciiValue ascii(result);
70  CHECK_EQ(expected, *ascii);
71}
72
73
74static void ExpectBoolean(const char* code, bool expected) {
75  Local<Value> result = CompileRun(code);
76  CHECK(result->IsBoolean());
77  CHECK_EQ(expected, result->BooleanValue());
78}
79
80
81static void ExpectTrue(const char* code) {
82  ExpectBoolean(code, true);
83}
84
85
86static void ExpectFalse(const char* code) {
87  ExpectBoolean(code, false);
88}
89
90
91static void ExpectObject(const char* code, Local<Value> expected) {
92  Local<Value> result = CompileRun(code);
93  CHECK(result->Equals(expected));
94}
95
96
97static void ExpectUndefined(const char* code) {
98  Local<Value> result = CompileRun(code);
99  CHECK(result->IsUndefined());
100}
101
102
103static int signature_callback_count;
104static v8::Handle<Value> IncrementingSignatureCallback(
105    const v8::Arguments& args) {
106  ApiTestFuzzer::Fuzz();
107  signature_callback_count++;
108  v8::Handle<v8::Array> result = v8::Array::New(args.Length());
109  for (int i = 0; i < args.Length(); i++)
110    result->Set(v8::Integer::New(i), args[i]);
111  return result;
112}
113
114
115static v8::Handle<Value> SignatureCallback(const v8::Arguments& args) {
116  ApiTestFuzzer::Fuzz();
117  v8::Handle<v8::Array> result = v8::Array::New(args.Length());
118  for (int i = 0; i < args.Length(); i++) {
119    result->Set(v8::Integer::New(i), args[i]);
120  }
121  return result;
122}
123
124
125THREADED_TEST(Handles) {
126  v8::HandleScope scope;
127  Local<Context> local_env;
128  {
129    LocalContext env;
130    local_env = env.local();
131  }
132
133  // Local context should still be live.
134  CHECK(!local_env.IsEmpty());
135  local_env->Enter();
136
137  v8::Handle<v8::Primitive> undef = v8::Undefined();
138  CHECK(!undef.IsEmpty());
139  CHECK(undef->IsUndefined());
140
141  const char* c_source = "1 + 2 + 3";
142  Local<String> source = String::New(c_source);
143  Local<Script> script = Script::Compile(source);
144  CHECK_EQ(6, script->Run()->Int32Value());
145
146  local_env->Exit();
147}
148
149
150THREADED_TEST(ReceiverSignature) {
151  v8::HandleScope scope;
152  LocalContext env;
153  v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
154  v8::Handle<v8::Signature> sig = v8::Signature::New(fun);
155  fun->PrototypeTemplate()->Set(
156      v8_str("m"),
157      v8::FunctionTemplate::New(IncrementingSignatureCallback,
158                                v8::Handle<Value>(),
159                                sig));
160  env->Global()->Set(v8_str("Fun"), fun->GetFunction());
161  signature_callback_count = 0;
162  CompileRun(
163      "var o = new Fun();"
164      "o.m();");
165  CHECK_EQ(1, signature_callback_count);
166  v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New();
167  sub_fun->Inherit(fun);
168  env->Global()->Set(v8_str("SubFun"), sub_fun->GetFunction());
169  CompileRun(
170      "var o = new SubFun();"
171      "o.m();");
172  CHECK_EQ(2, signature_callback_count);
173
174  v8::TryCatch try_catch;
175  CompileRun(
176      "var o = { };"
177      "o.m = Fun.prototype.m;"
178      "o.m();");
179  CHECK_EQ(2, signature_callback_count);
180  CHECK(try_catch.HasCaught());
181  try_catch.Reset();
182  v8::Handle<v8::FunctionTemplate> unrel_fun = v8::FunctionTemplate::New();
183  sub_fun->Inherit(fun);
184  env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
185  CompileRun(
186      "var o = new UnrelFun();"
187      "o.m = Fun.prototype.m;"
188      "o.m();");
189  CHECK_EQ(2, signature_callback_count);
190  CHECK(try_catch.HasCaught());
191}
192
193
194
195
196THREADED_TEST(ArgumentSignature) {
197  v8::HandleScope scope;
198  LocalContext env;
199  v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New();
200  cons->SetClassName(v8_str("Cons"));
201  v8::Handle<v8::Signature> sig =
202      v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 1, &cons);
203  v8::Handle<v8::FunctionTemplate> fun =
204      v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), sig);
205  env->Global()->Set(v8_str("Cons"), cons->GetFunction());
206  env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
207
208  v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
209  CHECK(value1->IsTrue());
210
211  v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
212  CHECK(value2->IsTrue());
213
214  v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
215  CHECK(value3->IsTrue());
216
217  v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New();
218  cons1->SetClassName(v8_str("Cons1"));
219  v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New();
220  cons2->SetClassName(v8_str("Cons2"));
221  v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New();
222  cons3->SetClassName(v8_str("Cons3"));
223
224  v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
225  v8::Handle<v8::Signature> wsig =
226      v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 3, args);
227  v8::Handle<v8::FunctionTemplate> fun2 =
228      v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), wsig);
229
230  env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
231  env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
232  env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
233  env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
234  v8::Handle<Value> value4 = CompileRun(
235      "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
236      "'[object Cons1],[object Cons2],[object Cons3]'");
237  CHECK(value4->IsTrue());
238
239  v8::Handle<Value> value5 = CompileRun(
240      "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
241  CHECK(value5->IsTrue());
242
243  v8::Handle<Value> value6 = CompileRun(
244      "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
245  CHECK(value6->IsTrue());
246
247  v8::Handle<Value> value7 = CompileRun(
248      "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
249      "'[object Cons1],[object Cons2],[object Cons3],d';");
250  CHECK(value7->IsTrue());
251
252  v8::Handle<Value> value8 = CompileRun(
253      "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
254  CHECK(value8->IsTrue());
255}
256
257
258THREADED_TEST(HulIgennem) {
259  v8::HandleScope scope;
260  LocalContext env;
261  v8::Handle<v8::Primitive> undef = v8::Undefined();
262  Local<String> undef_str = undef->ToString();
263  char* value = i::NewArray<char>(undef_str->Length() + 1);
264  undef_str->WriteAscii(value);
265  CHECK_EQ(0, strcmp(value, "undefined"));
266  i::DeleteArray(value);
267}
268
269
270THREADED_TEST(Access) {
271  v8::HandleScope scope;
272  LocalContext env;
273  Local<v8::Object> obj = v8::Object::New();
274  Local<Value> foo_before = obj->Get(v8_str("foo"));
275  CHECK(foo_before->IsUndefined());
276  Local<String> bar_str = v8_str("bar");
277  obj->Set(v8_str("foo"), bar_str);
278  Local<Value> foo_after = obj->Get(v8_str("foo"));
279  CHECK(!foo_after->IsUndefined());
280  CHECK(foo_after->IsString());
281  CHECK_EQ(bar_str, foo_after);
282}
283
284
285THREADED_TEST(AccessElement) {
286  v8::HandleScope scope;
287  LocalContext env;
288  Local<v8::Object> obj = v8::Object::New();
289  Local<Value> before = obj->Get(1);
290  CHECK(before->IsUndefined());
291  Local<String> bar_str = v8_str("bar");
292  obj->Set(1, bar_str);
293  Local<Value> after = obj->Get(1);
294  CHECK(!after->IsUndefined());
295  CHECK(after->IsString());
296  CHECK_EQ(bar_str, after);
297
298  Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
299  CHECK_EQ(v8_str("a"), value->Get(0));
300  CHECK_EQ(v8_str("b"), value->Get(1));
301}
302
303
304THREADED_TEST(Script) {
305  v8::HandleScope scope;
306  LocalContext env;
307  const char* c_source = "1 + 2 + 3";
308  Local<String> source = String::New(c_source);
309  Local<Script> script = Script::Compile(source);
310  CHECK_EQ(6, script->Run()->Int32Value());
311}
312
313
314static uint16_t* AsciiToTwoByteString(const char* source) {
315  int array_length = i::StrLength(source) + 1;
316  uint16_t* converted = i::NewArray<uint16_t>(array_length);
317  for (int i = 0; i < array_length; i++) converted[i] = source[i];
318  return converted;
319}
320
321
322class TestResource: public String::ExternalStringResource {
323 public:
324  static int dispose_count;
325
326  explicit TestResource(uint16_t* data)
327      : data_(data), length_(0) {
328    while (data[length_]) ++length_;
329  }
330
331  ~TestResource() {
332    i::DeleteArray(data_);
333    ++dispose_count;
334  }
335
336  const uint16_t* data() const {
337    return data_;
338  }
339
340  size_t length() const {
341    return length_;
342  }
343 private:
344  uint16_t* data_;
345  size_t length_;
346};
347
348
349int TestResource::dispose_count = 0;
350
351
352class TestAsciiResource: public String::ExternalAsciiStringResource {
353 public:
354  static int dispose_count;
355
356  explicit TestAsciiResource(const char* data)
357      : data_(data),
358        length_(strlen(data)) { }
359
360  ~TestAsciiResource() {
361    i::DeleteArray(data_);
362    ++dispose_count;
363  }
364
365  const char* data() const {
366    return data_;
367  }
368
369  size_t length() const {
370    return length_;
371  }
372 private:
373  const char* data_;
374  size_t length_;
375};
376
377
378int TestAsciiResource::dispose_count = 0;
379
380
381THREADED_TEST(ScriptUsingStringResource) {
382  TestResource::dispose_count = 0;
383  const char* c_source = "1 + 2 * 3";
384  uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
385  {
386    v8::HandleScope scope;
387    LocalContext env;
388    TestResource* resource = new TestResource(two_byte_source);
389    Local<String> source = String::NewExternal(resource);
390    Local<Script> script = Script::Compile(source);
391    Local<Value> value = script->Run();
392    CHECK(value->IsNumber());
393    CHECK_EQ(7, value->Int32Value());
394    CHECK(source->IsExternal());
395    CHECK_EQ(resource,
396             static_cast<TestResource*>(source->GetExternalStringResource()));
397    i::Heap::CollectAllGarbage(false);
398    CHECK_EQ(0, TestResource::dispose_count);
399  }
400  i::CompilationCache::Clear();
401  i::Heap::CollectAllGarbage(false);
402  CHECK_EQ(1, TestResource::dispose_count);
403}
404
405
406THREADED_TEST(ScriptUsingAsciiStringResource) {
407  TestAsciiResource::dispose_count = 0;
408  const char* c_source = "1 + 2 * 3";
409  {
410    v8::HandleScope scope;
411    LocalContext env;
412    Local<String> source =
413        String::NewExternal(new TestAsciiResource(i::StrDup(c_source)));
414    Local<Script> script = Script::Compile(source);
415    Local<Value> value = script->Run();
416    CHECK(value->IsNumber());
417    CHECK_EQ(7, value->Int32Value());
418    i::Heap::CollectAllGarbage(false);
419    CHECK_EQ(0, TestAsciiResource::dispose_count);
420  }
421  i::CompilationCache::Clear();
422  i::Heap::CollectAllGarbage(false);
423  CHECK_EQ(1, TestAsciiResource::dispose_count);
424}
425
426
427THREADED_TEST(ScriptMakingExternalString) {
428  TestResource::dispose_count = 0;
429  uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
430  {
431    v8::HandleScope scope;
432    LocalContext env;
433    Local<String> source = String::New(two_byte_source);
434    // Trigger GCs so that the newly allocated string moves to old gen.
435    i::Heap::CollectGarbage(i::NEW_SPACE);  // in survivor space now
436    i::Heap::CollectGarbage(i::NEW_SPACE);  // in old gen now
437    bool success = source->MakeExternal(new TestResource(two_byte_source));
438    CHECK(success);
439    Local<Script> script = Script::Compile(source);
440    Local<Value> value = script->Run();
441    CHECK(value->IsNumber());
442    CHECK_EQ(7, value->Int32Value());
443    i::Heap::CollectAllGarbage(false);
444    CHECK_EQ(0, TestResource::dispose_count);
445  }
446  i::CompilationCache::Clear();
447  i::Heap::CollectAllGarbage(false);
448  CHECK_EQ(1, TestResource::dispose_count);
449}
450
451
452THREADED_TEST(ScriptMakingExternalAsciiString) {
453  TestAsciiResource::dispose_count = 0;
454  const char* c_source = "1 + 2 * 3";
455  {
456    v8::HandleScope scope;
457    LocalContext env;
458    Local<String> source = v8_str(c_source);
459    // Trigger GCs so that the newly allocated string moves to old gen.
460    i::Heap::CollectGarbage(i::NEW_SPACE);  // in survivor space now
461    i::Heap::CollectGarbage(i::NEW_SPACE);  // in old gen now
462    bool success = source->MakeExternal(
463        new TestAsciiResource(i::StrDup(c_source)));
464    CHECK(success);
465    Local<Script> script = Script::Compile(source);
466    Local<Value> value = script->Run();
467    CHECK(value->IsNumber());
468    CHECK_EQ(7, value->Int32Value());
469    i::Heap::CollectAllGarbage(false);
470    CHECK_EQ(0, TestAsciiResource::dispose_count);
471  }
472  i::CompilationCache::Clear();
473  i::Heap::CollectAllGarbage(false);
474  CHECK_EQ(1, TestAsciiResource::dispose_count);
475}
476
477
478TEST(MakingExternalStringConditions) {
479  v8::HandleScope scope;
480  LocalContext env;
481
482  // Free some space in the new space so that we can check freshness.
483  i::Heap::CollectGarbage(i::NEW_SPACE);
484  i::Heap::CollectGarbage(i::NEW_SPACE);
485
486  uint16_t* two_byte_string = AsciiToTwoByteString("small");
487  Local<String> small_string = String::New(two_byte_string);
488  i::DeleteArray(two_byte_string);
489
490  // We should refuse to externalize newly created small string.
491  CHECK(!small_string->CanMakeExternal());
492  // Trigger GCs so that the newly allocated string moves to old gen.
493  i::Heap::CollectGarbage(i::NEW_SPACE);  // in survivor space now
494  i::Heap::CollectGarbage(i::NEW_SPACE);  // in old gen now
495  // Old space strings should be accepted.
496  CHECK(small_string->CanMakeExternal());
497
498  two_byte_string = AsciiToTwoByteString("small 2");
499  small_string = String::New(two_byte_string);
500  i::DeleteArray(two_byte_string);
501
502  // We should refuse externalizing newly created small string.
503  CHECK(!small_string->CanMakeExternal());
504  for (int i = 0; i < 100; i++) {
505    String::Value value(small_string);
506  }
507  // Frequently used strings should be accepted.
508  CHECK(small_string->CanMakeExternal());
509
510  const int buf_size = 10 * 1024;
511  char* buf = i::NewArray<char>(buf_size);
512  memset(buf, 'a', buf_size);
513  buf[buf_size - 1] = '\0';
514
515  two_byte_string = AsciiToTwoByteString(buf);
516  Local<String> large_string = String::New(two_byte_string);
517  i::DeleteArray(buf);
518  i::DeleteArray(two_byte_string);
519  // Large strings should be immediately accepted.
520  CHECK(large_string->CanMakeExternal());
521}
522
523
524TEST(MakingExternalAsciiStringConditions) {
525  v8::HandleScope scope;
526  LocalContext env;
527
528  // Free some space in the new space so that we can check freshness.
529  i::Heap::CollectGarbage(i::NEW_SPACE);
530  i::Heap::CollectGarbage(i::NEW_SPACE);
531
532  Local<String> small_string = String::New("small");
533  // We should refuse to externalize newly created small string.
534  CHECK(!small_string->CanMakeExternal());
535  // Trigger GCs so that the newly allocated string moves to old gen.
536  i::Heap::CollectGarbage(i::NEW_SPACE);  // in survivor space now
537  i::Heap::CollectGarbage(i::NEW_SPACE);  // in old gen now
538  // Old space strings should be accepted.
539  CHECK(small_string->CanMakeExternal());
540
541  small_string = String::New("small 2");
542  // We should refuse externalizing newly created small string.
543  CHECK(!small_string->CanMakeExternal());
544  for (int i = 0; i < 100; i++) {
545    String::Value value(small_string);
546  }
547  // Frequently used strings should be accepted.
548  CHECK(small_string->CanMakeExternal());
549
550  const int buf_size = 10 * 1024;
551  char* buf = i::NewArray<char>(buf_size);
552  memset(buf, 'a', buf_size);
553  buf[buf_size - 1] = '\0';
554  Local<String> large_string = String::New(buf);
555  i::DeleteArray(buf);
556  // Large strings should be immediately accepted.
557  CHECK(large_string->CanMakeExternal());
558}
559
560
561THREADED_TEST(UsingExternalString) {
562  {
563    v8::HandleScope scope;
564    uint16_t* two_byte_string = AsciiToTwoByteString("test string");
565    Local<String> string =
566        String::NewExternal(new TestResource(two_byte_string));
567    i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
568    // Trigger GCs so that the newly allocated string moves to old gen.
569    i::Heap::CollectGarbage(i::NEW_SPACE);  // in survivor space now
570    i::Heap::CollectGarbage(i::NEW_SPACE);  // in old gen now
571    i::Handle<i::String> isymbol = i::Factory::SymbolFromString(istring);
572    CHECK(isymbol->IsSymbol());
573  }
574  i::Heap::CollectAllGarbage(false);
575  i::Heap::CollectAllGarbage(false);
576}
577
578
579THREADED_TEST(UsingExternalAsciiString) {
580  {
581    v8::HandleScope scope;
582    const char* one_byte_string = "test string";
583    Local<String> string = String::NewExternal(
584        new TestAsciiResource(i::StrDup(one_byte_string)));
585    i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
586    // Trigger GCs so that the newly allocated string moves to old gen.
587    i::Heap::CollectGarbage(i::NEW_SPACE);  // in survivor space now
588    i::Heap::CollectGarbage(i::NEW_SPACE);  // in old gen now
589    i::Handle<i::String> isymbol = i::Factory::SymbolFromString(istring);
590    CHECK(isymbol->IsSymbol());
591  }
592  i::Heap::CollectAllGarbage(false);
593  i::Heap::CollectAllGarbage(false);
594}
595
596
597THREADED_TEST(ScavengeExternalString) {
598  TestResource::dispose_count = 0;
599  bool in_new_space = false;
600  {
601    v8::HandleScope scope;
602    uint16_t* two_byte_string = AsciiToTwoByteString("test string");
603    Local<String> string =
604        String::NewExternal(new TestResource(two_byte_string));
605    i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
606    i::Heap::CollectGarbage(i::NEW_SPACE);
607    in_new_space = i::Heap::InNewSpace(*istring);
608    CHECK(in_new_space || i::Heap::old_data_space()->Contains(*istring));
609    CHECK_EQ(0, TestResource::dispose_count);
610  }
611  i::Heap::CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
612  CHECK_EQ(1, TestResource::dispose_count);
613}
614
615
616THREADED_TEST(ScavengeExternalAsciiString) {
617  TestAsciiResource::dispose_count = 0;
618  bool in_new_space = false;
619  {
620    v8::HandleScope scope;
621    const char* one_byte_string = "test string";
622    Local<String> string = String::NewExternal(
623        new TestAsciiResource(i::StrDup(one_byte_string)));
624    i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
625    i::Heap::CollectGarbage(i::NEW_SPACE);
626    in_new_space = i::Heap::InNewSpace(*istring);
627    CHECK(in_new_space || i::Heap::old_data_space()->Contains(*istring));
628    CHECK_EQ(0, TestAsciiResource::dispose_count);
629  }
630  i::Heap::CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
631  CHECK_EQ(1, TestAsciiResource::dispose_count);
632}
633
634
635class TestAsciiResourceWithDisposeControl: public TestAsciiResource {
636 public:
637  static int dispose_calls;
638
639  TestAsciiResourceWithDisposeControl(const char* data, bool dispose)
640      : TestAsciiResource(data),
641        dispose_(dispose) { }
642
643  void Dispose() {
644    ++dispose_calls;
645    if (dispose_) delete this;
646  }
647 private:
648  bool dispose_;
649};
650
651
652int TestAsciiResourceWithDisposeControl::dispose_calls = 0;
653
654
655TEST(ExternalStringWithDisposeHandling) {
656  const char* c_source = "1 + 2 * 3";
657
658  // Use a stack allocated external string resource allocated object.
659  TestAsciiResource::dispose_count = 0;
660  TestAsciiResourceWithDisposeControl::dispose_calls = 0;
661  TestAsciiResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
662  {
663    v8::HandleScope scope;
664    LocalContext env;
665    Local<String> source =  String::NewExternal(&res_stack);
666    Local<Script> script = Script::Compile(source);
667    Local<Value> value = script->Run();
668    CHECK(value->IsNumber());
669    CHECK_EQ(7, value->Int32Value());
670    i::Heap::CollectAllGarbage(false);
671    CHECK_EQ(0, TestAsciiResource::dispose_count);
672  }
673  i::CompilationCache::Clear();
674  i::Heap::CollectAllGarbage(false);
675  CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
676  CHECK_EQ(0, TestAsciiResource::dispose_count);
677
678  // Use a heap allocated external string resource allocated object.
679  TestAsciiResource::dispose_count = 0;
680  TestAsciiResourceWithDisposeControl::dispose_calls = 0;
681  TestAsciiResource* res_heap =
682      new TestAsciiResourceWithDisposeControl(i::StrDup(c_source), true);
683  {
684    v8::HandleScope scope;
685    LocalContext env;
686    Local<String> source =  String::NewExternal(res_heap);
687    Local<Script> script = Script::Compile(source);
688    Local<Value> value = script->Run();
689    CHECK(value->IsNumber());
690    CHECK_EQ(7, value->Int32Value());
691    i::Heap::CollectAllGarbage(false);
692    CHECK_EQ(0, TestAsciiResource::dispose_count);
693  }
694  i::CompilationCache::Clear();
695  i::Heap::CollectAllGarbage(false);
696  CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
697  CHECK_EQ(1, TestAsciiResource::dispose_count);
698}
699
700
701THREADED_TEST(StringConcat) {
702  {
703    v8::HandleScope scope;
704    LocalContext env;
705    const char* one_byte_string_1 = "function a_times_t";
706    const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
707    const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
708    const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
709    const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
710    const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
711    const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
712    Local<String> left = v8_str(one_byte_string_1);
713
714    uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
715    Local<String> right = String::New(two_byte_source);
716    i::DeleteArray(two_byte_source);
717
718    Local<String> source = String::Concat(left, right);
719    right = String::NewExternal(
720        new TestAsciiResource(i::StrDup(one_byte_extern_1)));
721    source = String::Concat(source, right);
722    right = String::NewExternal(
723        new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
724    source = String::Concat(source, right);
725    right = v8_str(one_byte_string_2);
726    source = String::Concat(source, right);
727
728    two_byte_source = AsciiToTwoByteString(two_byte_string_2);
729    right = String::New(two_byte_source);
730    i::DeleteArray(two_byte_source);
731
732    source = String::Concat(source, right);
733    right = String::NewExternal(
734        new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
735    source = String::Concat(source, right);
736    Local<Script> script = Script::Compile(source);
737    Local<Value> value = script->Run();
738    CHECK(value->IsNumber());
739    CHECK_EQ(68, value->Int32Value());
740  }
741  i::CompilationCache::Clear();
742  i::Heap::CollectAllGarbage(false);
743  i::Heap::CollectAllGarbage(false);
744}
745
746
747THREADED_TEST(GlobalProperties) {
748  v8::HandleScope scope;
749  LocalContext env;
750  v8::Handle<v8::Object> global = env->Global();
751  global->Set(v8_str("pi"), v8_num(3.1415926));
752  Local<Value> pi = global->Get(v8_str("pi"));
753  CHECK_EQ(3.1415926, pi->NumberValue());
754}
755
756
757static v8::Handle<Value> handle_call(const v8::Arguments& args) {
758  ApiTestFuzzer::Fuzz();
759  return v8_num(102);
760}
761
762
763static v8::Handle<Value> construct_call(const v8::Arguments& args) {
764  ApiTestFuzzer::Fuzz();
765  args.This()->Set(v8_str("x"), v8_num(1));
766  args.This()->Set(v8_str("y"), v8_num(2));
767  return args.This();
768}
769
770static v8::Handle<Value> Return239(Local<String> name, const AccessorInfo&) {
771  ApiTestFuzzer::Fuzz();
772  return v8_num(239);
773}
774
775
776THREADED_TEST(FunctionTemplate) {
777  v8::HandleScope scope;
778  LocalContext env;
779  {
780    Local<v8::FunctionTemplate> fun_templ =
781        v8::FunctionTemplate::New(handle_call);
782    Local<Function> fun = fun_templ->GetFunction();
783    env->Global()->Set(v8_str("obj"), fun);
784    Local<Script> script = v8_compile("obj()");
785    CHECK_EQ(102, script->Run()->Int32Value());
786  }
787  // Use SetCallHandler to initialize a function template, should work like the
788  // previous one.
789  {
790    Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
791    fun_templ->SetCallHandler(handle_call);
792    Local<Function> fun = fun_templ->GetFunction();
793    env->Global()->Set(v8_str("obj"), fun);
794    Local<Script> script = v8_compile("obj()");
795    CHECK_EQ(102, script->Run()->Int32Value());
796  }
797  // Test constructor calls.
798  {
799    Local<v8::FunctionTemplate> fun_templ =
800        v8::FunctionTemplate::New(construct_call);
801    fun_templ->SetClassName(v8_str("funky"));
802    fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), Return239);
803    Local<Function> fun = fun_templ->GetFunction();
804    env->Global()->Set(v8_str("obj"), fun);
805    Local<Script> script = v8_compile("var s = new obj(); s.x");
806    CHECK_EQ(1, script->Run()->Int32Value());
807
808    Local<Value> result = v8_compile("(new obj()).toString()")->Run();
809    CHECK_EQ(v8_str("[object funky]"), result);
810
811    result = v8_compile("(new obj()).m")->Run();
812    CHECK_EQ(239, result->Int32Value());
813  }
814}
815
816
817static void* expected_ptr;
818static v8::Handle<v8::Value> callback(const v8::Arguments& args) {
819  void* ptr = v8::External::Unwrap(args.Data());
820  CHECK_EQ(expected_ptr, ptr);
821  return v8::Boolean::New(true);
822}
823
824
825static void TestExternalPointerWrapping() {
826  v8::HandleScope scope;
827  LocalContext env;
828
829  v8::Handle<v8::Value> data = v8::External::Wrap(expected_ptr);
830
831  v8::Handle<v8::Object> obj = v8::Object::New();
832  obj->Set(v8_str("func"),
833           v8::FunctionTemplate::New(callback, data)->GetFunction());
834  env->Global()->Set(v8_str("obj"), obj);
835
836  CHECK(CompileRun(
837        "function foo() {\n"
838        "  for (var i = 0; i < 13; i++) obj.func();\n"
839        "}\n"
840        "foo(), true")->BooleanValue());
841}
842
843
844THREADED_TEST(ExternalWrap) {
845  // Check heap allocated object.
846  int* ptr = new int;
847  expected_ptr = ptr;
848  TestExternalPointerWrapping();
849  delete ptr;
850
851  // Check stack allocated object.
852  int foo;
853  expected_ptr = &foo;
854  TestExternalPointerWrapping();
855
856  // Check not aligned addresses.
857  const int n = 100;
858  char* s = new char[n];
859  for (int i = 0; i < n; i++) {
860    expected_ptr = s + i;
861    TestExternalPointerWrapping();
862  }
863
864  delete[] s;
865
866  // Check several invalid addresses.
867  expected_ptr = reinterpret_cast<void*>(1);
868  TestExternalPointerWrapping();
869
870  expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
871  TestExternalPointerWrapping();
872
873  expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
874  TestExternalPointerWrapping();
875
876#if defined(V8_HOST_ARCH_X64)
877  expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
878  TestExternalPointerWrapping();
879
880  expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
881  TestExternalPointerWrapping();
882#endif
883}
884
885
886THREADED_TEST(FindInstanceInPrototypeChain) {
887  v8::HandleScope scope;
888  LocalContext env;
889
890  Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New();
891  Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New();
892  Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New();
893  derived->Inherit(base);
894
895  Local<v8::Function> base_function = base->GetFunction();
896  Local<v8::Function> derived_function = derived->GetFunction();
897  Local<v8::Function> other_function = other->GetFunction();
898
899  Local<v8::Object> base_instance = base_function->NewInstance();
900  Local<v8::Object> derived_instance = derived_function->NewInstance();
901  Local<v8::Object> derived_instance2 = derived_function->NewInstance();
902  Local<v8::Object> other_instance = other_function->NewInstance();
903  derived_instance2->Set(v8_str("__proto__"), derived_instance);
904  other_instance->Set(v8_str("__proto__"), derived_instance2);
905
906  // base_instance is only an instance of base.
907  CHECK_EQ(base_instance,
908           base_instance->FindInstanceInPrototypeChain(base));
909  CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
910  CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
911
912  // derived_instance is an instance of base and derived.
913  CHECK_EQ(derived_instance,
914           derived_instance->FindInstanceInPrototypeChain(base));
915  CHECK_EQ(derived_instance,
916           derived_instance->FindInstanceInPrototypeChain(derived));
917  CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
918
919  // other_instance is an instance of other and its immediate
920  // prototype derived_instance2 is an instance of base and derived.
921  // Note, derived_instance is an instance of base and derived too,
922  // but it comes after derived_instance2 in the prototype chain of
923  // other_instance.
924  CHECK_EQ(derived_instance2,
925           other_instance->FindInstanceInPrototypeChain(base));
926  CHECK_EQ(derived_instance2,
927           other_instance->FindInstanceInPrototypeChain(derived));
928  CHECK_EQ(other_instance,
929           other_instance->FindInstanceInPrototypeChain(other));
930}
931
932
933THREADED_TEST(TinyInteger) {
934  v8::HandleScope scope;
935  LocalContext env;
936  int32_t value = 239;
937  Local<v8::Integer> value_obj = v8::Integer::New(value);
938  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
939}
940
941
942THREADED_TEST(BigSmiInteger) {
943  v8::HandleScope scope;
944  LocalContext env;
945  int32_t value = i::Smi::kMaxValue;
946  // We cannot add one to a Smi::kMaxValue without wrapping.
947  if (i::kSmiValueSize < 32) {
948    CHECK(i::Smi::IsValid(value));
949    CHECK(!i::Smi::IsValid(value + 1));
950    Local<v8::Integer> value_obj = v8::Integer::New(value);
951    CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
952  }
953}
954
955
956THREADED_TEST(BigInteger) {
957  v8::HandleScope scope;
958  LocalContext env;
959  // We cannot add one to a Smi::kMaxValue without wrapping.
960  if (i::kSmiValueSize < 32) {
961    // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
962    // The code will not be run in that case, due to the "if" guard.
963    int32_t value =
964        static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
965    CHECK(value > i::Smi::kMaxValue);
966    CHECK(!i::Smi::IsValid(value));
967    Local<v8::Integer> value_obj = v8::Integer::New(value);
968    CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
969  }
970}
971
972
973THREADED_TEST(TinyUnsignedInteger) {
974  v8::HandleScope scope;
975  LocalContext env;
976  uint32_t value = 239;
977  Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
978  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
979}
980
981
982THREADED_TEST(BigUnsignedSmiInteger) {
983  v8::HandleScope scope;
984  LocalContext env;
985  uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
986  CHECK(i::Smi::IsValid(value));
987  CHECK(!i::Smi::IsValid(value + 1));
988  Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
989  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
990}
991
992
993THREADED_TEST(BigUnsignedInteger) {
994  v8::HandleScope scope;
995  LocalContext env;
996  uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
997  CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
998  CHECK(!i::Smi::IsValid(value));
999  Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1000  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1001}
1002
1003
1004THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1005  v8::HandleScope scope;
1006  LocalContext env;
1007  uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1008  uint32_t value = INT32_MAX_AS_UINT + 1;
1009  CHECK(value > INT32_MAX_AS_UINT);  // No overflow.
1010  Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1011  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1012}
1013
1014
1015THREADED_TEST(Number) {
1016  v8::HandleScope scope;
1017  LocalContext env;
1018  double PI = 3.1415926;
1019  Local<v8::Number> pi_obj = v8::Number::New(PI);
1020  CHECK_EQ(PI, pi_obj->NumberValue());
1021}
1022
1023
1024THREADED_TEST(ToNumber) {
1025  v8::HandleScope scope;
1026  LocalContext env;
1027  Local<String> str = v8_str("3.1415926");
1028  CHECK_EQ(3.1415926, str->NumberValue());
1029  v8::Handle<v8::Boolean> t = v8::True();
1030  CHECK_EQ(1.0, t->NumberValue());
1031  v8::Handle<v8::Boolean> f = v8::False();
1032  CHECK_EQ(0.0, f->NumberValue());
1033}
1034
1035
1036THREADED_TEST(Date) {
1037  v8::HandleScope scope;
1038  LocalContext env;
1039  double PI = 3.1415926;
1040  Local<Value> date_obj = v8::Date::New(PI);
1041  CHECK_EQ(3.0, date_obj->NumberValue());
1042}
1043
1044
1045THREADED_TEST(Boolean) {
1046  v8::HandleScope scope;
1047  LocalContext env;
1048  v8::Handle<v8::Boolean> t = v8::True();
1049  CHECK(t->Value());
1050  v8::Handle<v8::Boolean> f = v8::False();
1051  CHECK(!f->Value());
1052  v8::Handle<v8::Primitive> u = v8::Undefined();
1053  CHECK(!u->BooleanValue());
1054  v8::Handle<v8::Primitive> n = v8::Null();
1055  CHECK(!n->BooleanValue());
1056  v8::Handle<String> str1 = v8_str("");
1057  CHECK(!str1->BooleanValue());
1058  v8::Handle<String> str2 = v8_str("x");
1059  CHECK(str2->BooleanValue());
1060  CHECK(!v8::Number::New(0)->BooleanValue());
1061  CHECK(v8::Number::New(-1)->BooleanValue());
1062  CHECK(v8::Number::New(1)->BooleanValue());
1063  CHECK(v8::Number::New(42)->BooleanValue());
1064  CHECK(!v8_compile("NaN")->Run()->BooleanValue());
1065}
1066
1067
1068static v8::Handle<Value> DummyCallHandler(const v8::Arguments& args) {
1069  ApiTestFuzzer::Fuzz();
1070  return v8_num(13.4);
1071}
1072
1073
1074static v8::Handle<Value> GetM(Local<String> name, const AccessorInfo&) {
1075  ApiTestFuzzer::Fuzz();
1076  return v8_num(876);
1077}
1078
1079
1080THREADED_TEST(GlobalPrototype) {
1081  v8::HandleScope scope;
1082  v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
1083  func_templ->PrototypeTemplate()->Set(
1084      "dummy",
1085      v8::FunctionTemplate::New(DummyCallHandler));
1086  v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1087  templ->Set("x", v8_num(200));
1088  templ->SetAccessor(v8_str("m"), GetM);
1089  LocalContext env(0, templ);
1090  v8::Handle<v8::Object> obj = env->Global();
1091  v8::Handle<Script> script = v8_compile("dummy()");
1092  v8::Handle<Value> result = script->Run();
1093  CHECK_EQ(13.4, result->NumberValue());
1094  CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1095  CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1096}
1097
1098
1099THREADED_TEST(ObjectTemplate) {
1100  v8::HandleScope scope;
1101  Local<ObjectTemplate> templ1 = ObjectTemplate::New();
1102  templ1->Set("x", v8_num(10));
1103  templ1->Set("y", v8_num(13));
1104  LocalContext env;
1105  Local<v8::Object> instance1 = templ1->NewInstance();
1106  env->Global()->Set(v8_str("p"), instance1);
1107  CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1108  CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1109  Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
1110  fun->PrototypeTemplate()->Set("nirk", v8_num(123));
1111  Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1112  templ2->Set("a", v8_num(12));
1113  templ2->Set("b", templ1);
1114  Local<v8::Object> instance2 = templ2->NewInstance();
1115  env->Global()->Set(v8_str("q"), instance2);
1116  CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1117  CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1118  CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1119  CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1120}
1121
1122
1123static v8::Handle<Value> GetFlabby(const v8::Arguments& args) {
1124  ApiTestFuzzer::Fuzz();
1125  return v8_num(17.2);
1126}
1127
1128
1129static v8::Handle<Value> GetKnurd(Local<String> property, const AccessorInfo&) {
1130  ApiTestFuzzer::Fuzz();
1131  return v8_num(15.2);
1132}
1133
1134
1135THREADED_TEST(DescriptorInheritance) {
1136  v8::HandleScope scope;
1137  v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New();
1138  super->PrototypeTemplate()->Set("flabby",
1139                                  v8::FunctionTemplate::New(GetFlabby));
1140  super->PrototypeTemplate()->Set("PI", v8_num(3.14));
1141
1142  super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1143
1144  v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New();
1145  base1->Inherit(super);
1146  base1->PrototypeTemplate()->Set("v1", v8_num(20.1));
1147
1148  v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New();
1149  base2->Inherit(super);
1150  base2->PrototypeTemplate()->Set("v2", v8_num(10.1));
1151
1152  LocalContext env;
1153
1154  env->Global()->Set(v8_str("s"), super->GetFunction());
1155  env->Global()->Set(v8_str("base1"), base1->GetFunction());
1156  env->Global()->Set(v8_str("base2"), base2->GetFunction());
1157
1158  // Checks right __proto__ chain.
1159  CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1160  CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1161
1162  CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1163
1164  // Instance accessor should not be visible on function object or its prototype
1165  CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1166  CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1167  CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1168
1169  env->Global()->Set(v8_str("obj"),
1170                     base1->GetFunction()->NewInstance());
1171  CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1172  CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1173  CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1174  CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1175  CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1176
1177  env->Global()->Set(v8_str("obj2"),
1178                     base2->GetFunction()->NewInstance());
1179  CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1180  CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1181  CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1182  CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1183  CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1184
1185  // base1 and base2 cannot cross reference to each's prototype
1186  CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1187  CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1188}
1189
1190
1191int echo_named_call_count;
1192
1193
1194static v8::Handle<Value> EchoNamedProperty(Local<String> name,
1195                                           const AccessorInfo& info) {
1196  ApiTestFuzzer::Fuzz();
1197  CHECK_EQ(v8_str("data"), info.Data());
1198  echo_named_call_count++;
1199  return name;
1200}
1201
1202
1203THREADED_TEST(NamedPropertyHandlerGetter) {
1204  echo_named_call_count = 0;
1205  v8::HandleScope scope;
1206  v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1207  templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
1208                                                     0, 0, 0, 0,
1209                                                     v8_str("data"));
1210  LocalContext env;
1211  env->Global()->Set(v8_str("obj"),
1212                     templ->GetFunction()->NewInstance());
1213  CHECK_EQ(echo_named_call_count, 0);
1214  v8_compile("obj.x")->Run();
1215  CHECK_EQ(echo_named_call_count, 1);
1216  const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
1217  v8::Handle<Value> str = CompileRun(code);
1218  String::AsciiValue value(str);
1219  CHECK_EQ(*value, "oddlepoddle");
1220  // Check default behavior
1221  CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
1222  CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
1223  CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
1224}
1225
1226
1227int echo_indexed_call_count = 0;
1228
1229
1230static v8::Handle<Value> EchoIndexedProperty(uint32_t index,
1231                                             const AccessorInfo& info) {
1232  ApiTestFuzzer::Fuzz();
1233  CHECK_EQ(v8_num(637), info.Data());
1234  echo_indexed_call_count++;
1235  return v8_num(index);
1236}
1237
1238
1239THREADED_TEST(IndexedPropertyHandlerGetter) {
1240  v8::HandleScope scope;
1241  v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1242  templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
1243                                                       0, 0, 0, 0,
1244                                                       v8_num(637));
1245  LocalContext env;
1246  env->Global()->Set(v8_str("obj"),
1247                     templ->GetFunction()->NewInstance());
1248  Local<Script> script = v8_compile("obj[900]");
1249  CHECK_EQ(script->Run()->Int32Value(), 900);
1250}
1251
1252
1253v8::Handle<v8::Object> bottom;
1254
1255static v8::Handle<Value> CheckThisIndexedPropertyHandler(
1256    uint32_t index,
1257    const AccessorInfo& info) {
1258  ApiTestFuzzer::Fuzz();
1259  CHECK(info.This()->Equals(bottom));
1260  return v8::Handle<Value>();
1261}
1262
1263static v8::Handle<Value> CheckThisNamedPropertyHandler(
1264    Local<String> name,
1265    const AccessorInfo& info) {
1266  ApiTestFuzzer::Fuzz();
1267  CHECK(info.This()->Equals(bottom));
1268  return v8::Handle<Value>();
1269}
1270
1271
1272v8::Handle<Value> CheckThisIndexedPropertySetter(uint32_t index,
1273                                                 Local<Value> value,
1274                                                 const AccessorInfo& info) {
1275  ApiTestFuzzer::Fuzz();
1276  CHECK(info.This()->Equals(bottom));
1277  return v8::Handle<Value>();
1278}
1279
1280
1281v8::Handle<Value> CheckThisNamedPropertySetter(Local<String> property,
1282                                               Local<Value> value,
1283                                               const AccessorInfo& info) {
1284  ApiTestFuzzer::Fuzz();
1285  CHECK(info.This()->Equals(bottom));
1286  return v8::Handle<Value>();
1287}
1288
1289v8::Handle<v8::Integer> CheckThisIndexedPropertyQuery(
1290    uint32_t index,
1291    const AccessorInfo& info) {
1292  ApiTestFuzzer::Fuzz();
1293  CHECK(info.This()->Equals(bottom));
1294  return v8::Handle<v8::Integer>();
1295}
1296
1297
1298v8::Handle<v8::Integer> CheckThisNamedPropertyQuery(Local<String> property,
1299                                                    const AccessorInfo& info) {
1300  ApiTestFuzzer::Fuzz();
1301  CHECK(info.This()->Equals(bottom));
1302  return v8::Handle<v8::Integer>();
1303}
1304
1305
1306v8::Handle<v8::Boolean> CheckThisIndexedPropertyDeleter(
1307    uint32_t index,
1308    const AccessorInfo& info) {
1309  ApiTestFuzzer::Fuzz();
1310  CHECK(info.This()->Equals(bottom));
1311  return v8::Handle<v8::Boolean>();
1312}
1313
1314
1315v8::Handle<v8::Boolean> CheckThisNamedPropertyDeleter(
1316    Local<String> property,
1317    const AccessorInfo& info) {
1318  ApiTestFuzzer::Fuzz();
1319  CHECK(info.This()->Equals(bottom));
1320  return v8::Handle<v8::Boolean>();
1321}
1322
1323
1324v8::Handle<v8::Array> CheckThisIndexedPropertyEnumerator(
1325    const AccessorInfo& info) {
1326  ApiTestFuzzer::Fuzz();
1327  CHECK(info.This()->Equals(bottom));
1328  return v8::Handle<v8::Array>();
1329}
1330
1331
1332v8::Handle<v8::Array> CheckThisNamedPropertyEnumerator(
1333    const AccessorInfo& info) {
1334  ApiTestFuzzer::Fuzz();
1335  CHECK(info.This()->Equals(bottom));
1336  return v8::Handle<v8::Array>();
1337}
1338
1339
1340THREADED_TEST(PropertyHandlerInPrototype) {
1341  v8::HandleScope scope;
1342  LocalContext env;
1343
1344  // Set up a prototype chain with three interceptors.
1345  v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1346  templ->InstanceTemplate()->SetIndexedPropertyHandler(
1347      CheckThisIndexedPropertyHandler,
1348      CheckThisIndexedPropertySetter,
1349      CheckThisIndexedPropertyQuery,
1350      CheckThisIndexedPropertyDeleter,
1351      CheckThisIndexedPropertyEnumerator);
1352
1353  templ->InstanceTemplate()->SetNamedPropertyHandler(
1354      CheckThisNamedPropertyHandler,
1355      CheckThisNamedPropertySetter,
1356      CheckThisNamedPropertyQuery,
1357      CheckThisNamedPropertyDeleter,
1358      CheckThisNamedPropertyEnumerator);
1359
1360  bottom = templ->GetFunction()->NewInstance();
1361  Local<v8::Object> top = templ->GetFunction()->NewInstance();
1362  Local<v8::Object> middle = templ->GetFunction()->NewInstance();
1363
1364  bottom->Set(v8_str("__proto__"), middle);
1365  middle->Set(v8_str("__proto__"), top);
1366  env->Global()->Set(v8_str("obj"), bottom);
1367
1368  // Indexed and named get.
1369  Script::Compile(v8_str("obj[0]"))->Run();
1370  Script::Compile(v8_str("obj.x"))->Run();
1371
1372  // Indexed and named set.
1373  Script::Compile(v8_str("obj[1] = 42"))->Run();
1374  Script::Compile(v8_str("obj.y = 42"))->Run();
1375
1376  // Indexed and named query.
1377  Script::Compile(v8_str("0 in obj"))->Run();
1378  Script::Compile(v8_str("'x' in obj"))->Run();
1379
1380  // Indexed and named deleter.
1381  Script::Compile(v8_str("delete obj[0]"))->Run();
1382  Script::Compile(v8_str("delete obj.x"))->Run();
1383
1384  // Enumerators.
1385  Script::Compile(v8_str("for (var p in obj) ;"))->Run();
1386}
1387
1388
1389static v8::Handle<Value> PrePropertyHandlerGet(Local<String> key,
1390                                               const AccessorInfo& info) {
1391  ApiTestFuzzer::Fuzz();
1392  if (v8_str("pre")->Equals(key)) {
1393    return v8_str("PrePropertyHandler: pre");
1394  }
1395  return v8::Handle<String>();
1396}
1397
1398
1399static v8::Handle<v8::Integer> PrePropertyHandlerQuery(Local<String> key,
1400                                                       const AccessorInfo&) {
1401  if (v8_str("pre")->Equals(key)) {
1402    return v8::Integer::New(v8::None);
1403  }
1404
1405  return v8::Handle<v8::Integer>();  // do not intercept the call
1406}
1407
1408
1409THREADED_TEST(PrePropertyHandler) {
1410  v8::HandleScope scope;
1411  v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
1412  desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
1413                                                    0,
1414                                                    PrePropertyHandlerQuery);
1415  LocalContext env(NULL, desc->InstanceTemplate());
1416  Script::Compile(v8_str(
1417      "var pre = 'Object: pre'; var on = 'Object: on';"))->Run();
1418  v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run();
1419  CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
1420  v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run();
1421  CHECK_EQ(v8_str("Object: on"), result_on);
1422  v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run();
1423  CHECK(result_post.IsEmpty());
1424}
1425
1426
1427THREADED_TEST(UndefinedIsNotEnumerable) {
1428  v8::HandleScope scope;
1429  LocalContext env;
1430  v8::Handle<Value> result = Script::Compile(v8_str(
1431      "this.propertyIsEnumerable(undefined)"))->Run();
1432  CHECK(result->IsFalse());
1433}
1434
1435
1436v8::Handle<Script> call_recursively_script;
1437static const int kTargetRecursionDepth = 200;  // near maximum
1438
1439
1440static v8::Handle<Value> CallScriptRecursivelyCall(const v8::Arguments& args) {
1441  ApiTestFuzzer::Fuzz();
1442  int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1443  if (depth == kTargetRecursionDepth) return v8::Undefined();
1444  args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1445  return call_recursively_script->Run();
1446}
1447
1448
1449static v8::Handle<Value> CallFunctionRecursivelyCall(
1450    const v8::Arguments& args) {
1451  ApiTestFuzzer::Fuzz();
1452  int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1453  if (depth == kTargetRecursionDepth) {
1454    printf("[depth = %d]\n", depth);
1455    return v8::Undefined();
1456  }
1457  args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1458  v8::Handle<Value> function =
1459      args.This()->Get(v8_str("callFunctionRecursively"));
1460  return function.As<Function>()->Call(args.This(), 0, NULL);
1461}
1462
1463
1464THREADED_TEST(DeepCrossLanguageRecursion) {
1465  v8::HandleScope scope;
1466  v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
1467  global->Set(v8_str("callScriptRecursively"),
1468              v8::FunctionTemplate::New(CallScriptRecursivelyCall));
1469  global->Set(v8_str("callFunctionRecursively"),
1470              v8::FunctionTemplate::New(CallFunctionRecursivelyCall));
1471  LocalContext env(NULL, global);
1472
1473  env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1474  call_recursively_script = v8_compile("callScriptRecursively()");
1475  v8::Handle<Value> result = call_recursively_script->Run();
1476  call_recursively_script = v8::Handle<Script>();
1477
1478  env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1479  Script::Compile(v8_str("callFunctionRecursively()"))->Run();
1480}
1481
1482
1483static v8::Handle<Value>
1484    ThrowingPropertyHandlerGet(Local<String> key, const AccessorInfo&) {
1485  ApiTestFuzzer::Fuzz();
1486  return v8::ThrowException(key);
1487}
1488
1489
1490static v8::Handle<Value> ThrowingPropertyHandlerSet(Local<String> key,
1491                                                    Local<Value>,
1492                                                    const AccessorInfo&) {
1493  v8::ThrowException(key);
1494  return v8::Undefined();  // not the same as v8::Handle<v8::Value>()
1495}
1496
1497
1498THREADED_TEST(CallbackExceptionRegression) {
1499  v8::HandleScope scope;
1500  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
1501  obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
1502                               ThrowingPropertyHandlerSet);
1503  LocalContext env;
1504  env->Global()->Set(v8_str("obj"), obj->NewInstance());
1505  v8::Handle<Value> otto = Script::Compile(v8_str(
1506      "try { with (obj) { otto; } } catch (e) { e; }"))->Run();
1507  CHECK_EQ(v8_str("otto"), otto);
1508  v8::Handle<Value> netto = Script::Compile(v8_str(
1509      "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run();
1510  CHECK_EQ(v8_str("netto"), netto);
1511}
1512
1513
1514THREADED_TEST(FunctionPrototype) {
1515  v8::HandleScope scope;
1516  Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New();
1517  Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
1518  LocalContext env;
1519  env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
1520  Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak"));
1521  CHECK_EQ(script->Run()->Int32Value(), 321);
1522}
1523
1524
1525THREADED_TEST(InternalFields) {
1526  v8::HandleScope scope;
1527  LocalContext env;
1528
1529  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1530  Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1531  instance_templ->SetInternalFieldCount(1);
1532  Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1533  CHECK_EQ(1, obj->InternalFieldCount());
1534  CHECK(obj->GetInternalField(0)->IsUndefined());
1535  obj->SetInternalField(0, v8_num(17));
1536  CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
1537}
1538
1539
1540THREADED_TEST(GlobalObjectInternalFields) {
1541  v8::HandleScope scope;
1542  Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
1543  global_template->SetInternalFieldCount(1);
1544  LocalContext env(NULL, global_template);
1545  v8::Handle<v8::Object> global_proxy = env->Global();
1546  v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
1547  CHECK_EQ(1, global->InternalFieldCount());
1548  CHECK(global->GetInternalField(0)->IsUndefined());
1549  global->SetInternalField(0, v8_num(17));
1550  CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
1551}
1552
1553
1554THREADED_TEST(InternalFieldsNativePointers) {
1555  v8::HandleScope scope;
1556  LocalContext env;
1557
1558  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1559  Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1560  instance_templ->SetInternalFieldCount(1);
1561  Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1562  CHECK_EQ(1, obj->InternalFieldCount());
1563  CHECK(obj->GetPointerFromInternalField(0) == NULL);
1564
1565  char* data = new char[100];
1566
1567  void* aligned = data;
1568  CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
1569  void* unaligned = data + 1;
1570  CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
1571
1572  // Check reading and writing aligned pointers.
1573  obj->SetPointerInInternalField(0, aligned);
1574  i::Heap::CollectAllGarbage(false);
1575  CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1576
1577  // Check reading and writing unaligned pointers.
1578  obj->SetPointerInInternalField(0, unaligned);
1579  i::Heap::CollectAllGarbage(false);
1580  CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1581
1582  delete[] data;
1583}
1584
1585
1586THREADED_TEST(InternalFieldsNativePointersAndExternal) {
1587  v8::HandleScope scope;
1588  LocalContext env;
1589
1590  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1591  Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1592  instance_templ->SetInternalFieldCount(1);
1593  Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1594  CHECK_EQ(1, obj->InternalFieldCount());
1595  CHECK(obj->GetPointerFromInternalField(0) == NULL);
1596
1597  char* data = new char[100];
1598
1599  void* aligned = data;
1600  CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
1601  void* unaligned = data + 1;
1602  CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
1603
1604  obj->SetPointerInInternalField(0, aligned);
1605  i::Heap::CollectAllGarbage(false);
1606  CHECK_EQ(aligned, v8::External::Unwrap(obj->GetInternalField(0)));
1607
1608  obj->SetPointerInInternalField(0, unaligned);
1609  i::Heap::CollectAllGarbage(false);
1610  CHECK_EQ(unaligned, v8::External::Unwrap(obj->GetInternalField(0)));
1611
1612  obj->SetInternalField(0, v8::External::Wrap(aligned));
1613  i::Heap::CollectAllGarbage(false);
1614  CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1615
1616  obj->SetInternalField(0, v8::External::Wrap(unaligned));
1617  i::Heap::CollectAllGarbage(false);
1618  CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1619
1620  delete[] data;
1621}
1622
1623
1624THREADED_TEST(IdentityHash) {
1625  v8::HandleScope scope;
1626  LocalContext env;
1627
1628  // Ensure that the test starts with an fresh heap to test whether the hash
1629  // code is based on the address.
1630  i::Heap::CollectAllGarbage(false);
1631  Local<v8::Object> obj = v8::Object::New();
1632  int hash = obj->GetIdentityHash();
1633  int hash1 = obj->GetIdentityHash();
1634  CHECK_EQ(hash, hash1);
1635  int hash2 = v8::Object::New()->GetIdentityHash();
1636  // Since the identity hash is essentially a random number two consecutive
1637  // objects should not be assigned the same hash code. If the test below fails
1638  // the random number generator should be evaluated.
1639  CHECK_NE(hash, hash2);
1640  i::Heap::CollectAllGarbage(false);
1641  int hash3 = v8::Object::New()->GetIdentityHash();
1642  // Make sure that the identity hash is not based on the initial address of
1643  // the object alone. If the test below fails the random number generator
1644  // should be evaluated.
1645  CHECK_NE(hash, hash3);
1646  int hash4 = obj->GetIdentityHash();
1647  CHECK_EQ(hash, hash4);
1648}
1649
1650
1651THREADED_TEST(HiddenProperties) {
1652  v8::HandleScope scope;
1653  LocalContext env;
1654
1655  v8::Local<v8::Object> obj = v8::Object::New();
1656  v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1657  v8::Local<v8::String> empty = v8_str("");
1658  v8::Local<v8::String> prop_name = v8_str("prop_name");
1659
1660  i::Heap::CollectAllGarbage(false);
1661
1662  // Make sure delete of a non-existent hidden value works
1663  CHECK(obj->DeleteHiddenValue(key));
1664
1665  CHECK(obj->SetHiddenValue(key, v8::Integer::New(1503)));
1666  CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
1667  CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
1668  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1669
1670  i::Heap::CollectAllGarbage(false);
1671
1672  // Make sure we do not find the hidden property.
1673  CHECK(!obj->Has(empty));
1674  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1675  CHECK(obj->Get(empty)->IsUndefined());
1676  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1677  CHECK(obj->Set(empty, v8::Integer::New(2003)));
1678  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1679  CHECK_EQ(2003, obj->Get(empty)->Int32Value());
1680
1681  i::Heap::CollectAllGarbage(false);
1682
1683  // Add another property and delete it afterwards to force the object in
1684  // slow case.
1685  CHECK(obj->Set(prop_name, v8::Integer::New(2008)));
1686  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1687  CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
1688  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1689  CHECK(obj->Delete(prop_name));
1690  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1691
1692  i::Heap::CollectAllGarbage(false);
1693
1694  CHECK(obj->DeleteHiddenValue(key));
1695  CHECK(obj->GetHiddenValue(key).IsEmpty());
1696}
1697
1698
1699static bool interceptor_for_hidden_properties_called;
1700static v8::Handle<Value> InterceptorForHiddenProperties(
1701    Local<String> name, const AccessorInfo& info) {
1702  interceptor_for_hidden_properties_called = true;
1703  return v8::Handle<Value>();
1704}
1705
1706
1707THREADED_TEST(HiddenPropertiesWithInterceptors) {
1708  v8::HandleScope scope;
1709  LocalContext context;
1710
1711  interceptor_for_hidden_properties_called = false;
1712
1713  v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1714
1715  // Associate an interceptor with an object and start setting hidden values.
1716  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
1717  Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
1718  instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
1719  Local<v8::Function> function = fun_templ->GetFunction();
1720  Local<v8::Object> obj = function->NewInstance();
1721  CHECK(obj->SetHiddenValue(key, v8::Integer::New(2302)));
1722  CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
1723  CHECK(!interceptor_for_hidden_properties_called);
1724}
1725
1726
1727THREADED_TEST(External) {
1728  v8::HandleScope scope;
1729  int x = 3;
1730  Local<v8::External> ext = v8::External::New(&x);
1731  LocalContext env;
1732  env->Global()->Set(v8_str("ext"), ext);
1733  Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
1734  v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
1735  int* ptr = static_cast<int*>(reext->Value());
1736  CHECK_EQ(x, 3);
1737  *ptr = 10;
1738  CHECK_EQ(x, 10);
1739
1740  // Make sure unaligned pointers are wrapped properly.
1741  char* data = i::StrDup("0123456789");
1742  Local<v8::Value> zero = v8::External::Wrap(&data[0]);
1743  Local<v8::Value> one = v8::External::Wrap(&data[1]);
1744  Local<v8::Value> two = v8::External::Wrap(&data[2]);
1745  Local<v8::Value> three = v8::External::Wrap(&data[3]);
1746
1747  char* char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(zero));
1748  CHECK_EQ('0', *char_ptr);
1749  char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(one));
1750  CHECK_EQ('1', *char_ptr);
1751  char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(two));
1752  CHECK_EQ('2', *char_ptr);
1753  char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(three));
1754  CHECK_EQ('3', *char_ptr);
1755  i::DeleteArray(data);
1756}
1757
1758
1759THREADED_TEST(GlobalHandle) {
1760  v8::Persistent<String> global;
1761  {
1762    v8::HandleScope scope;
1763    Local<String> str = v8_str("str");
1764    global = v8::Persistent<String>::New(str);
1765  }
1766  CHECK_EQ(global->Length(), 3);
1767  global.Dispose();
1768}
1769
1770
1771THREADED_TEST(ScriptException) {
1772  v8::HandleScope scope;
1773  LocalContext env;
1774  Local<Script> script = Script::Compile(v8_str("throw 'panama!';"));
1775  v8::TryCatch try_catch;
1776  Local<Value> result = script->Run();
1777  CHECK(result.IsEmpty());
1778  CHECK(try_catch.HasCaught());
1779  String::AsciiValue exception_value(try_catch.Exception());
1780  CHECK_EQ(*exception_value, "panama!");
1781}
1782
1783
1784bool message_received;
1785
1786
1787static void check_message(v8::Handle<v8::Message> message,
1788                          v8::Handle<Value> data) {
1789  CHECK_EQ(5.76, data->NumberValue());
1790  CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
1791  CHECK_EQ(7.56, message->GetScriptData()->NumberValue());
1792  message_received = true;
1793}
1794
1795
1796THREADED_TEST(MessageHandlerData) {
1797  message_received = false;
1798  v8::HandleScope scope;
1799  CHECK(!message_received);
1800  v8::V8::AddMessageListener(check_message, v8_num(5.76));
1801  LocalContext context;
1802  v8::ScriptOrigin origin =
1803      v8::ScriptOrigin(v8_str("6.75"));
1804  v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
1805                                                  &origin);
1806  script->SetData(v8_str("7.56"));
1807  script->Run();
1808  CHECK(message_received);
1809  // clear out the message listener
1810  v8::V8::RemoveMessageListeners(check_message);
1811}
1812
1813
1814THREADED_TEST(GetSetProperty) {
1815  v8::HandleScope scope;
1816  LocalContext context;
1817  context->Global()->Set(v8_str("foo"), v8_num(14));
1818  context->Global()->Set(v8_str("12"), v8_num(92));
1819  context->Global()->Set(v8::Integer::New(16), v8_num(32));
1820  context->Global()->Set(v8_num(13), v8_num(56));
1821  Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run();
1822  CHECK_EQ(14, foo->Int32Value());
1823  Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run();
1824  CHECK_EQ(92, twelve->Int32Value());
1825  Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run();
1826  CHECK_EQ(32, sixteen->Int32Value());
1827  Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run();
1828  CHECK_EQ(56, thirteen->Int32Value());
1829  CHECK_EQ(92, context->Global()->Get(v8::Integer::New(12))->Int32Value());
1830  CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
1831  CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
1832  CHECK_EQ(32, context->Global()->Get(v8::Integer::New(16))->Int32Value());
1833  CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
1834  CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
1835  CHECK_EQ(56, context->Global()->Get(v8::Integer::New(13))->Int32Value());
1836  CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
1837  CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
1838}
1839
1840
1841THREADED_TEST(PropertyAttributes) {
1842  v8::HandleScope scope;
1843  LocalContext context;
1844  // read-only
1845  Local<String> prop = v8_str("read_only");
1846  context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
1847  CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
1848  Script::Compile(v8_str("read_only = 9"))->Run();
1849  CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
1850  context->Global()->Set(prop, v8_num(10));
1851  CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
1852  // dont-delete
1853  prop = v8_str("dont_delete");
1854  context->Global()->Set(prop, v8_num(13), v8::DontDelete);
1855  CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
1856  Script::Compile(v8_str("delete dont_delete"))->Run();
1857  CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
1858}
1859
1860
1861THREADED_TEST(Array) {
1862  v8::HandleScope scope;
1863  LocalContext context;
1864  Local<v8::Array> array = v8::Array::New();
1865  CHECK_EQ(0, array->Length());
1866  CHECK(array->Get(0)->IsUndefined());
1867  CHECK(!array->Has(0));
1868  CHECK(array->Get(100)->IsUndefined());
1869  CHECK(!array->Has(100));
1870  array->Set(2, v8_num(7));
1871  CHECK_EQ(3, array->Length());
1872  CHECK(!array->Has(0));
1873  CHECK(!array->Has(1));
1874  CHECK(array->Has(2));
1875  CHECK_EQ(7, array->Get(2)->Int32Value());
1876  Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
1877  Local<v8::Array> arr = obj.As<v8::Array>();
1878  CHECK_EQ(3, arr->Length());
1879  CHECK_EQ(1, arr->Get(0)->Int32Value());
1880  CHECK_EQ(2, arr->Get(1)->Int32Value());
1881  CHECK_EQ(3, arr->Get(2)->Int32Value());
1882}
1883
1884
1885v8::Handle<Value> HandleF(const v8::Arguments& args) {
1886  v8::HandleScope scope;
1887  ApiTestFuzzer::Fuzz();
1888  Local<v8::Array> result = v8::Array::New(args.Length());
1889  for (int i = 0; i < args.Length(); i++)
1890    result->Set(i, args[i]);
1891  return scope.Close(result);
1892}
1893
1894
1895THREADED_TEST(Vector) {
1896  v8::HandleScope scope;
1897  Local<ObjectTemplate> global = ObjectTemplate::New();
1898  global->Set(v8_str("f"), v8::FunctionTemplate::New(HandleF));
1899  LocalContext context(0, global);
1900
1901  const char* fun = "f()";
1902  Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
1903  CHECK_EQ(0, a0->Length());
1904
1905  const char* fun2 = "f(11)";
1906  Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
1907  CHECK_EQ(1, a1->Length());
1908  CHECK_EQ(11, a1->Get(0)->Int32Value());
1909
1910  const char* fun3 = "f(12, 13)";
1911  Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
1912  CHECK_EQ(2, a2->Length());
1913  CHECK_EQ(12, a2->Get(0)->Int32Value());
1914  CHECK_EQ(13, a2->Get(1)->Int32Value());
1915
1916  const char* fun4 = "f(14, 15, 16)";
1917  Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
1918  CHECK_EQ(3, a3->Length());
1919  CHECK_EQ(14, a3->Get(0)->Int32Value());
1920  CHECK_EQ(15, a3->Get(1)->Int32Value());
1921  CHECK_EQ(16, a3->Get(2)->Int32Value());
1922
1923  const char* fun5 = "f(17, 18, 19, 20)";
1924  Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
1925  CHECK_EQ(4, a4->Length());
1926  CHECK_EQ(17, a4->Get(0)->Int32Value());
1927  CHECK_EQ(18, a4->Get(1)->Int32Value());
1928  CHECK_EQ(19, a4->Get(2)->Int32Value());
1929  CHECK_EQ(20, a4->Get(3)->Int32Value());
1930}
1931
1932
1933THREADED_TEST(FunctionCall) {
1934  v8::HandleScope scope;
1935  LocalContext context;
1936  CompileRun(
1937    "function Foo() {"
1938    "  var result = [];"
1939    "  for (var i = 0; i < arguments.length; i++) {"
1940    "    result.push(arguments[i]);"
1941    "  }"
1942    "  return result;"
1943    "}");
1944  Local<Function> Foo =
1945      Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
1946
1947  v8::Handle<Value>* args0 = NULL;
1948  Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
1949  CHECK_EQ(0, a0->Length());
1950
1951  v8::Handle<Value> args1[] = { v8_num(1.1) };
1952  Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
1953  CHECK_EQ(1, a1->Length());
1954  CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
1955
1956  v8::Handle<Value> args2[] = { v8_num(2.2),
1957                                v8_num(3.3) };
1958  Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
1959  CHECK_EQ(2, a2->Length());
1960  CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
1961  CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
1962
1963  v8::Handle<Value> args3[] = { v8_num(4.4),
1964                                v8_num(5.5),
1965                                v8_num(6.6) };
1966  Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
1967  CHECK_EQ(3, a3->Length());
1968  CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
1969  CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
1970  CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
1971
1972  v8::Handle<Value> args4[] = { v8_num(7.7),
1973                                v8_num(8.8),
1974                                v8_num(9.9),
1975                                v8_num(10.11) };
1976  Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
1977  CHECK_EQ(4, a4->Length());
1978  CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
1979  CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
1980  CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
1981  CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
1982}
1983
1984
1985static const char* js_code_causing_out_of_memory =
1986    "var a = new Array(); while(true) a.push(a);";
1987
1988
1989// These tests run for a long time and prevent us from running tests
1990// that come after them so they cannot run in parallel.
1991TEST(OutOfMemory) {
1992  // It's not possible to read a snapshot into a heap with different dimensions.
1993  if (i::Snapshot::IsEnabled()) return;
1994  // Set heap limits.
1995  static const int K = 1024;
1996  v8::ResourceConstraints constraints;
1997  constraints.set_max_young_space_size(256 * K);
1998  constraints.set_max_old_space_size(4 * K * K);
1999  v8::SetResourceConstraints(&constraints);
2000
2001  // Execute a script that causes out of memory.
2002  v8::HandleScope scope;
2003  LocalContext context;
2004  v8::V8::IgnoreOutOfMemoryException();
2005  Local<Script> script =
2006      Script::Compile(String::New(js_code_causing_out_of_memory));
2007  Local<Value> result = script->Run();
2008
2009  // Check for out of memory state.
2010  CHECK(result.IsEmpty());
2011  CHECK(context->HasOutOfMemoryException());
2012}
2013
2014
2015v8::Handle<Value> ProvokeOutOfMemory(const v8::Arguments& args) {
2016  ApiTestFuzzer::Fuzz();
2017
2018  v8::HandleScope scope;
2019  LocalContext context;
2020  Local<Script> script =
2021      Script::Compile(String::New(js_code_causing_out_of_memory));
2022  Local<Value> result = script->Run();
2023
2024  // Check for out of memory state.
2025  CHECK(result.IsEmpty());
2026  CHECK(context->HasOutOfMemoryException());
2027
2028  return result;
2029}
2030
2031
2032TEST(OutOfMemoryNested) {
2033  // It's not possible to read a snapshot into a heap with different dimensions.
2034  if (i::Snapshot::IsEnabled()) return;
2035  // Set heap limits.
2036  static const int K = 1024;
2037  v8::ResourceConstraints constraints;
2038  constraints.set_max_young_space_size(256 * K);
2039  constraints.set_max_old_space_size(4 * K * K);
2040  v8::SetResourceConstraints(&constraints);
2041
2042  v8::HandleScope scope;
2043  Local<ObjectTemplate> templ = ObjectTemplate::New();
2044  templ->Set(v8_str("ProvokeOutOfMemory"),
2045             v8::FunctionTemplate::New(ProvokeOutOfMemory));
2046  LocalContext context(0, templ);
2047  v8::V8::IgnoreOutOfMemoryException();
2048  Local<Value> result = CompileRun(
2049    "var thrown = false;"
2050    "try {"
2051    "  ProvokeOutOfMemory();"
2052    "} catch (e) {"
2053    "  thrown = true;"
2054    "}");
2055  // Check for out of memory state.
2056  CHECK(result.IsEmpty());
2057  CHECK(context->HasOutOfMemoryException());
2058}
2059
2060
2061TEST(HugeConsStringOutOfMemory) {
2062  // It's not possible to read a snapshot into a heap with different dimensions.
2063  if (i::Snapshot::IsEnabled()) return;
2064  v8::HandleScope scope;
2065  LocalContext context;
2066  // Set heap limits.
2067  static const int K = 1024;
2068  v8::ResourceConstraints constraints;
2069  constraints.set_max_young_space_size(256 * K);
2070  constraints.set_max_old_space_size(2 * K * K);
2071  v8::SetResourceConstraints(&constraints);
2072
2073  // Execute a script that causes out of memory.
2074  v8::V8::IgnoreOutOfMemoryException();
2075
2076  // Build huge string. This should fail with out of memory exception.
2077  Local<Value> result = CompileRun(
2078    "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();"
2079    "for (var i = 0; i < 22; i++) { str = str + str; }");
2080
2081  // Check for out of memory state.
2082  CHECK(result.IsEmpty());
2083  CHECK(context->HasOutOfMemoryException());
2084}
2085
2086
2087THREADED_TEST(ConstructCall) {
2088  v8::HandleScope scope;
2089  LocalContext context;
2090  CompileRun(
2091    "function Foo() {"
2092    "  var result = [];"
2093    "  for (var i = 0; i < arguments.length; i++) {"
2094    "    result.push(arguments[i]);"
2095    "  }"
2096    "  return result;"
2097    "}");
2098  Local<Function> Foo =
2099      Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
2100
2101  v8::Handle<Value>* args0 = NULL;
2102  Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
2103  CHECK_EQ(0, a0->Length());
2104
2105  v8::Handle<Value> args1[] = { v8_num(1.1) };
2106  Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
2107  CHECK_EQ(1, a1->Length());
2108  CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
2109
2110  v8::Handle<Value> args2[] = { v8_num(2.2),
2111                                v8_num(3.3) };
2112  Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
2113  CHECK_EQ(2, a2->Length());
2114  CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
2115  CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
2116
2117  v8::Handle<Value> args3[] = { v8_num(4.4),
2118                                v8_num(5.5),
2119                                v8_num(6.6) };
2120  Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
2121  CHECK_EQ(3, a3->Length());
2122  CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
2123  CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
2124  CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
2125
2126  v8::Handle<Value> args4[] = { v8_num(7.7),
2127                                v8_num(8.8),
2128                                v8_num(9.9),
2129                                v8_num(10.11) };
2130  Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
2131  CHECK_EQ(4, a4->Length());
2132  CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
2133  CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
2134  CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
2135  CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
2136}
2137
2138
2139static void CheckUncle(v8::TryCatch* try_catch) {
2140  CHECK(try_catch->HasCaught());
2141  String::AsciiValue str_value(try_catch->Exception());
2142  CHECK_EQ(*str_value, "uncle?");
2143  try_catch->Reset();
2144}
2145
2146
2147THREADED_TEST(ConversionNumber) {
2148  v8::HandleScope scope;
2149  LocalContext env;
2150  // Very large number.
2151  CompileRun("var obj = Math.pow(2,32) * 1237;");
2152  Local<Value> obj = env->Global()->Get(v8_str("obj"));
2153  CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
2154  CHECK_EQ(0, obj->ToInt32()->Value());
2155  CHECK(0u == obj->ToUint32()->Value());  // NOLINT - no CHECK_EQ for unsigned.
2156  // Large number.
2157  CompileRun("var obj = -1234567890123;");
2158  obj = env->Global()->Get(v8_str("obj"));
2159  CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
2160  CHECK_EQ(-1912276171, obj->ToInt32()->Value());
2161  CHECK(2382691125u == obj->ToUint32()->Value());  // NOLINT
2162  // Small positive integer.
2163  CompileRun("var obj = 42;");
2164  obj = env->Global()->Get(v8_str("obj"));
2165  CHECK_EQ(42.0, obj->ToNumber()->Value());
2166  CHECK_EQ(42, obj->ToInt32()->Value());
2167  CHECK(42u == obj->ToUint32()->Value());  // NOLINT
2168  // Negative integer.
2169  CompileRun("var obj = -37;");
2170  obj = env->Global()->Get(v8_str("obj"));
2171  CHECK_EQ(-37.0, obj->ToNumber()->Value());
2172  CHECK_EQ(-37, obj->ToInt32()->Value());
2173  CHECK(4294967259u == obj->ToUint32()->Value());  // NOLINT
2174  // Positive non-int32 integer.
2175  CompileRun("var obj = 0x81234567;");
2176  obj = env->Global()->Get(v8_str("obj"));
2177  CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
2178  CHECK_EQ(-2128394905, obj->ToInt32()->Value());
2179  CHECK(2166572391u == obj->ToUint32()->Value());  // NOLINT
2180  // Fraction.
2181  CompileRun("var obj = 42.3;");
2182  obj = env->Global()->Get(v8_str("obj"));
2183  CHECK_EQ(42.3, obj->ToNumber()->Value());
2184  CHECK_EQ(42, obj->ToInt32()->Value());
2185  CHECK(42u == obj->ToUint32()->Value());  // NOLINT
2186  // Large negative fraction.
2187  CompileRun("var obj = -5726623061.75;");
2188  obj = env->Global()->Get(v8_str("obj"));
2189  CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
2190  CHECK_EQ(-1431655765, obj->ToInt32()->Value());
2191  CHECK(2863311531u == obj->ToUint32()->Value());  // NOLINT
2192}
2193
2194
2195THREADED_TEST(isNumberType) {
2196  v8::HandleScope scope;
2197  LocalContext env;
2198  // Very large number.
2199  CompileRun("var obj = Math.pow(2,32) * 1237;");
2200  Local<Value> obj = env->Global()->Get(v8_str("obj"));
2201  CHECK(!obj->IsInt32());
2202  CHECK(!obj->IsUint32());
2203  // Large negative number.
2204  CompileRun("var obj = -1234567890123;");
2205  obj = env->Global()->Get(v8_str("obj"));
2206  CHECK(!obj->IsInt32());
2207  CHECK(!obj->IsUint32());
2208  // Small positive integer.
2209  CompileRun("var obj = 42;");
2210  obj = env->Global()->Get(v8_str("obj"));
2211  CHECK(obj->IsInt32());
2212  CHECK(obj->IsUint32());
2213  // Negative integer.
2214  CompileRun("var obj = -37;");
2215  obj = env->Global()->Get(v8_str("obj"));
2216  CHECK(obj->IsInt32());
2217  CHECK(!obj->IsUint32());
2218  // Positive non-int32 integer.
2219  CompileRun("var obj = 0x81234567;");
2220  obj = env->Global()->Get(v8_str("obj"));
2221  CHECK(!obj->IsInt32());
2222  CHECK(obj->IsUint32());
2223  // Fraction.
2224  CompileRun("var obj = 42.3;");
2225  obj = env->Global()->Get(v8_str("obj"));
2226  CHECK(!obj->IsInt32());
2227  CHECK(!obj->IsUint32());
2228  // Large negative fraction.
2229  CompileRun("var obj = -5726623061.75;");
2230  obj = env->Global()->Get(v8_str("obj"));
2231  CHECK(!obj->IsInt32());
2232  CHECK(!obj->IsUint32());
2233}
2234
2235
2236THREADED_TEST(ConversionException) {
2237  v8::HandleScope scope;
2238  LocalContext env;
2239  CompileRun(
2240    "function TestClass() { };"
2241    "TestClass.prototype.toString = function () { throw 'uncle?'; };"
2242    "var obj = new TestClass();");
2243  Local<Value> obj = env->Global()->Get(v8_str("obj"));
2244
2245  v8::TryCatch try_catch;
2246
2247  Local<Value> to_string_result = obj->ToString();
2248  CHECK(to_string_result.IsEmpty());
2249  CheckUncle(&try_catch);
2250
2251  Local<Value> to_number_result = obj->ToNumber();
2252  CHECK(to_number_result.IsEmpty());
2253  CheckUncle(&try_catch);
2254
2255  Local<Value> to_integer_result = obj->ToInteger();
2256  CHECK(to_integer_result.IsEmpty());
2257  CheckUncle(&try_catch);
2258
2259  Local<Value> to_uint32_result = obj->ToUint32();
2260  CHECK(to_uint32_result.IsEmpty());
2261  CheckUncle(&try_catch);
2262
2263  Local<Value> to_int32_result = obj->ToInt32();
2264  CHECK(to_int32_result.IsEmpty());
2265  CheckUncle(&try_catch);
2266
2267  Local<Value> to_object_result = v8::Undefined()->ToObject();
2268  CHECK(to_object_result.IsEmpty());
2269  CHECK(try_catch.HasCaught());
2270  try_catch.Reset();
2271
2272  int32_t int32_value = obj->Int32Value();
2273  CHECK_EQ(0, int32_value);
2274  CheckUncle(&try_catch);
2275
2276  uint32_t uint32_value = obj->Uint32Value();
2277  CHECK_EQ(0, uint32_value);
2278  CheckUncle(&try_catch);
2279
2280  double number_value = obj->NumberValue();
2281  CHECK_NE(0, IsNaN(number_value));
2282  CheckUncle(&try_catch);
2283
2284  int64_t integer_value = obj->IntegerValue();
2285  CHECK_EQ(0.0, static_cast<double>(integer_value));
2286  CheckUncle(&try_catch);
2287}
2288
2289
2290v8::Handle<Value> ThrowFromC(const v8::Arguments& args) {
2291  ApiTestFuzzer::Fuzz();
2292  return v8::ThrowException(v8_str("konto"));
2293}
2294
2295
2296v8::Handle<Value> CCatcher(const v8::Arguments& args) {
2297  if (args.Length() < 1) return v8::Boolean::New(false);
2298  v8::HandleScope scope;
2299  v8::TryCatch try_catch;
2300  Local<Value> result = v8::Script::Compile(args[0]->ToString())->Run();
2301  CHECK(!try_catch.HasCaught() || result.IsEmpty());
2302  return v8::Boolean::New(try_catch.HasCaught());
2303}
2304
2305
2306THREADED_TEST(APICatch) {
2307  v8::HandleScope scope;
2308  Local<ObjectTemplate> templ = ObjectTemplate::New();
2309  templ->Set(v8_str("ThrowFromC"),
2310             v8::FunctionTemplate::New(ThrowFromC));
2311  LocalContext context(0, templ);
2312  CompileRun(
2313    "var thrown = false;"
2314    "try {"
2315    "  ThrowFromC();"
2316    "} catch (e) {"
2317    "  thrown = true;"
2318    "}");
2319  Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
2320  CHECK(thrown->BooleanValue());
2321}
2322
2323
2324THREADED_TEST(APIThrowTryCatch) {
2325  v8::HandleScope scope;
2326  Local<ObjectTemplate> templ = ObjectTemplate::New();
2327  templ->Set(v8_str("ThrowFromC"),
2328             v8::FunctionTemplate::New(ThrowFromC));
2329  LocalContext context(0, templ);
2330  v8::TryCatch try_catch;
2331  CompileRun("ThrowFromC();");
2332  CHECK(try_catch.HasCaught());
2333}
2334
2335
2336// Test that a try-finally block doesn't shadow a try-catch block
2337// when setting up an external handler.
2338//
2339// BUG(271): Some of the exception propagation does not work on the
2340// ARM simulator because the simulator separates the C++ stack and the
2341// JS stack.  This test therefore fails on the simulator.  The test is
2342// not threaded to allow the threading tests to run on the simulator.
2343TEST(TryCatchInTryFinally) {
2344  v8::HandleScope scope;
2345  Local<ObjectTemplate> templ = ObjectTemplate::New();
2346  templ->Set(v8_str("CCatcher"),
2347             v8::FunctionTemplate::New(CCatcher));
2348  LocalContext context(0, templ);
2349  Local<Value> result = CompileRun("try {"
2350                                   "  try {"
2351                                   "    CCatcher('throw 7;');"
2352                                   "  } finally {"
2353                                   "  }"
2354                                   "} catch (e) {"
2355                                   "}");
2356  CHECK(result->IsTrue());
2357}
2358
2359
2360static void check_reference_error_message(
2361    v8::Handle<v8::Message> message,
2362    v8::Handle<v8::Value> data) {
2363  const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
2364  CHECK(message->Get()->Equals(v8_str(reference_error)));
2365}
2366
2367
2368// Test that overwritten toString methods are not invoked on uncaught
2369// exception formatting. However, they are invoked when performing
2370// normal error string conversions.
2371TEST(APIThrowMessageOverwrittenToString) {
2372  v8::HandleScope scope;
2373  v8::V8::AddMessageListener(check_reference_error_message);
2374  LocalContext context;
2375  CompileRun("ReferenceError.prototype.toString ="
2376             "  function() { return 'Whoops' }");
2377  CompileRun("asdf;");
2378  v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
2379  CHECK(string->Equals(v8_str("Whoops")));
2380  v8::V8::RemoveMessageListeners(check_message);
2381}
2382
2383
2384static void receive_message(v8::Handle<v8::Message> message,
2385                            v8::Handle<v8::Value> data) {
2386  message->Get();
2387  message_received = true;
2388}
2389
2390
2391TEST(APIThrowMessage) {
2392  message_received = false;
2393  v8::HandleScope scope;
2394  v8::V8::AddMessageListener(receive_message);
2395  Local<ObjectTemplate> templ = ObjectTemplate::New();
2396  templ->Set(v8_str("ThrowFromC"),
2397             v8::FunctionTemplate::New(ThrowFromC));
2398  LocalContext context(0, templ);
2399  CompileRun("ThrowFromC();");
2400  CHECK(message_received);
2401  v8::V8::RemoveMessageListeners(check_message);
2402}
2403
2404
2405TEST(APIThrowMessageAndVerboseTryCatch) {
2406  message_received = false;
2407  v8::HandleScope scope;
2408  v8::V8::AddMessageListener(receive_message);
2409  Local<ObjectTemplate> templ = ObjectTemplate::New();
2410  templ->Set(v8_str("ThrowFromC"),
2411             v8::FunctionTemplate::New(ThrowFromC));
2412  LocalContext context(0, templ);
2413  v8::TryCatch try_catch;
2414  try_catch.SetVerbose(true);
2415  Local<Value> result = CompileRun("ThrowFromC();");
2416  CHECK(try_catch.HasCaught());
2417  CHECK(result.IsEmpty());
2418  CHECK(message_received);
2419  v8::V8::RemoveMessageListeners(check_message);
2420}
2421
2422
2423THREADED_TEST(ExternalScriptException) {
2424  v8::HandleScope scope;
2425  Local<ObjectTemplate> templ = ObjectTemplate::New();
2426  templ->Set(v8_str("ThrowFromC"),
2427             v8::FunctionTemplate::New(ThrowFromC));
2428  LocalContext context(0, templ);
2429
2430  v8::TryCatch try_catch;
2431  Local<Script> script
2432      = Script::Compile(v8_str("ThrowFromC(); throw 'panama';"));
2433  Local<Value> result = script->Run();
2434  CHECK(result.IsEmpty());
2435  CHECK(try_catch.HasCaught());
2436  String::AsciiValue exception_value(try_catch.Exception());
2437  CHECK_EQ("konto", *exception_value);
2438}
2439
2440
2441
2442v8::Handle<Value> CThrowCountDown(const v8::Arguments& args) {
2443  ApiTestFuzzer::Fuzz();
2444  CHECK_EQ(4, args.Length());
2445  int count = args[0]->Int32Value();
2446  int cInterval = args[2]->Int32Value();
2447  if (count == 0) {
2448    return v8::ThrowException(v8_str("FromC"));
2449  } else {
2450    Local<v8::Object> global = Context::GetCurrent()->Global();
2451    Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
2452    v8::Handle<Value> argv[] = { v8_num(count - 1),
2453                                 args[1],
2454                                 args[2],
2455                                 args[3] };
2456    if (count % cInterval == 0) {
2457      v8::TryCatch try_catch;
2458      Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
2459      int expected = args[3]->Int32Value();
2460      if (try_catch.HasCaught()) {
2461        CHECK_EQ(expected, count);
2462        CHECK(result.IsEmpty());
2463        CHECK(!i::Top::has_scheduled_exception());
2464      } else {
2465        CHECK_NE(expected, count);
2466      }
2467      return result;
2468    } else {
2469      return fun.As<Function>()->Call(global, 4, argv);
2470    }
2471  }
2472}
2473
2474
2475v8::Handle<Value> JSCheck(const v8::Arguments& args) {
2476  ApiTestFuzzer::Fuzz();
2477  CHECK_EQ(3, args.Length());
2478  bool equality = args[0]->BooleanValue();
2479  int count = args[1]->Int32Value();
2480  int expected = args[2]->Int32Value();
2481  if (equality) {
2482    CHECK_EQ(count, expected);
2483  } else {
2484    CHECK_NE(count, expected);
2485  }
2486  return v8::Undefined();
2487}
2488
2489
2490THREADED_TEST(EvalInTryFinally) {
2491  v8::HandleScope scope;
2492  LocalContext context;
2493  v8::TryCatch try_catch;
2494  CompileRun("(function() {"
2495             "  try {"
2496             "    eval('asldkf (*&^&*^');"
2497             "  } finally {"
2498             "    return;"
2499             "  }"
2500             "})()");
2501  CHECK(!try_catch.HasCaught());
2502}
2503
2504
2505// This test works by making a stack of alternating JavaScript and C
2506// activations.  These activations set up exception handlers with regular
2507// intervals, one interval for C activations and another for JavaScript
2508// activations.  When enough activations have been created an exception is
2509// thrown and we check that the right activation catches the exception and that
2510// no other activations do.  The right activation is always the topmost one with
2511// a handler, regardless of whether it is in JavaScript or C.
2512//
2513// The notation used to describe a test case looks like this:
2514//
2515//    *JS[4] *C[3] @JS[2] C[1] JS[0]
2516//
2517// Each entry is an activation, either JS or C.  The index is the count at that
2518// level.  Stars identify activations with exception handlers, the @ identifies
2519// the exception handler that should catch the exception.
2520//
2521// BUG(271): Some of the exception propagation does not work on the
2522// ARM simulator because the simulator separates the C++ stack and the
2523// JS stack.  This test therefore fails on the simulator.  The test is
2524// not threaded to allow the threading tests to run on the simulator.
2525TEST(ExceptionOrder) {
2526  v8::HandleScope scope;
2527  Local<ObjectTemplate> templ = ObjectTemplate::New();
2528  templ->Set(v8_str("check"), v8::FunctionTemplate::New(JSCheck));
2529  templ->Set(v8_str("CThrowCountDown"),
2530             v8::FunctionTemplate::New(CThrowCountDown));
2531  LocalContext context(0, templ);
2532  CompileRun(
2533    "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
2534    "  if (count == 0) throw 'FromJS';"
2535    "  if (count % jsInterval == 0) {"
2536    "    try {"
2537    "      var value = CThrowCountDown(count - 1,"
2538    "                                  jsInterval,"
2539    "                                  cInterval,"
2540    "                                  expected);"
2541    "      check(false, count, expected);"
2542    "      return value;"
2543    "    } catch (e) {"
2544    "      check(true, count, expected);"
2545    "    }"
2546    "  } else {"
2547    "    return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
2548    "  }"
2549    "}");
2550  Local<Function> fun =
2551      Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
2552
2553  const int argc = 4;
2554  //                             count      jsInterval cInterval  expected
2555
2556  // *JS[4] *C[3] @JS[2] C[1] JS[0]
2557  v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
2558  fun->Call(fun, argc, a0);
2559
2560  // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
2561  v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
2562  fun->Call(fun, argc, a1);
2563
2564  // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
2565  v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
2566  fun->Call(fun, argc, a2);
2567
2568  // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
2569  v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
2570  fun->Call(fun, argc, a3);
2571
2572  // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
2573  v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
2574  fun->Call(fun, argc, a4);
2575
2576  // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
2577  v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
2578  fun->Call(fun, argc, a5);
2579}
2580
2581
2582v8::Handle<Value> ThrowValue(const v8::Arguments& args) {
2583  ApiTestFuzzer::Fuzz();
2584  CHECK_EQ(1, args.Length());
2585  return v8::ThrowException(args[0]);
2586}
2587
2588
2589THREADED_TEST(ThrowValues) {
2590  v8::HandleScope scope;
2591  Local<ObjectTemplate> templ = ObjectTemplate::New();
2592  templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(ThrowValue));
2593  LocalContext context(0, templ);
2594  v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
2595    "function Run(obj) {"
2596    "  try {"
2597    "    Throw(obj);"
2598    "  } catch (e) {"
2599    "    return e;"
2600    "  }"
2601    "  return 'no exception';"
2602    "}"
2603    "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
2604  CHECK_EQ(5, result->Length());
2605  CHECK(result->Get(v8::Integer::New(0))->IsString());
2606  CHECK(result->Get(v8::Integer::New(1))->IsNumber());
2607  CHECK_EQ(1, result->Get(v8::Integer::New(1))->Int32Value());
2608  CHECK(result->Get(v8::Integer::New(2))->IsNumber());
2609  CHECK_EQ(0, result->Get(v8::Integer::New(2))->Int32Value());
2610  CHECK(result->Get(v8::Integer::New(3))->IsNull());
2611  CHECK(result->Get(v8::Integer::New(4))->IsUndefined());
2612}
2613
2614
2615THREADED_TEST(CatchZero) {
2616  v8::HandleScope scope;
2617  LocalContext context;
2618  v8::TryCatch try_catch;
2619  CHECK(!try_catch.HasCaught());
2620  Script::Compile(v8_str("throw 10"))->Run();
2621  CHECK(try_catch.HasCaught());
2622  CHECK_EQ(10, try_catch.Exception()->Int32Value());
2623  try_catch.Reset();
2624  CHECK(!try_catch.HasCaught());
2625  Script::Compile(v8_str("throw 0"))->Run();
2626  CHECK(try_catch.HasCaught());
2627  CHECK_EQ(0, try_catch.Exception()->Int32Value());
2628}
2629
2630
2631THREADED_TEST(CatchExceptionFromWith) {
2632  v8::HandleScope scope;
2633  LocalContext context;
2634  v8::TryCatch try_catch;
2635  CHECK(!try_catch.HasCaught());
2636  Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run();
2637  CHECK(try_catch.HasCaught());
2638}
2639
2640
2641THREADED_TEST(Equality) {
2642  v8::HandleScope scope;
2643  LocalContext context;
2644  // Check that equality works at all before relying on CHECK_EQ
2645  CHECK(v8_str("a")->Equals(v8_str("a")));
2646  CHECK(!v8_str("a")->Equals(v8_str("b")));
2647
2648  CHECK_EQ(v8_str("a"), v8_str("a"));
2649  CHECK_NE(v8_str("a"), v8_str("b"));
2650  CHECK_EQ(v8_num(1), v8_num(1));
2651  CHECK_EQ(v8_num(1.00), v8_num(1));
2652  CHECK_NE(v8_num(1), v8_num(2));
2653
2654  // Assume String is not symbol.
2655  CHECK(v8_str("a")->StrictEquals(v8_str("a")));
2656  CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
2657  CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
2658  CHECK(v8_num(1)->StrictEquals(v8_num(1)));
2659  CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
2660  CHECK(v8_num(0)->StrictEquals(v8_num(-0)));
2661  Local<Value> not_a_number = v8_num(i::OS::nan_value());
2662  CHECK(!not_a_number->StrictEquals(not_a_number));
2663  CHECK(v8::False()->StrictEquals(v8::False()));
2664  CHECK(!v8::False()->StrictEquals(v8::Undefined()));
2665
2666  v8::Handle<v8::Object> obj = v8::Object::New();
2667  v8::Persistent<v8::Object> alias = v8::Persistent<v8::Object>::New(obj);
2668  CHECK(alias->StrictEquals(obj));
2669  alias.Dispose();
2670}
2671
2672
2673THREADED_TEST(MultiRun) {
2674  v8::HandleScope scope;
2675  LocalContext context;
2676  Local<Script> script = Script::Compile(v8_str("x"));
2677  for (int i = 0; i < 10; i++)
2678    script->Run();
2679}
2680
2681
2682static v8::Handle<Value> GetXValue(Local<String> name,
2683                                   const AccessorInfo& info) {
2684  ApiTestFuzzer::Fuzz();
2685  CHECK_EQ(info.Data(), v8_str("donut"));
2686  CHECK_EQ(name, v8_str("x"));
2687  return name;
2688}
2689
2690
2691THREADED_TEST(SimplePropertyRead) {
2692  v8::HandleScope scope;
2693  Local<ObjectTemplate> templ = ObjectTemplate::New();
2694  templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
2695  LocalContext context;
2696  context->Global()->Set(v8_str("obj"), templ->NewInstance());
2697  Local<Script> script = Script::Compile(v8_str("obj.x"));
2698  for (int i = 0; i < 10; i++) {
2699    Local<Value> result = script->Run();
2700    CHECK_EQ(result, v8_str("x"));
2701  }
2702}
2703
2704THREADED_TEST(DefinePropertyOnAPIAccessor) {
2705  v8::HandleScope scope;
2706  Local<ObjectTemplate> templ = ObjectTemplate::New();
2707  templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
2708  LocalContext context;
2709  context->Global()->Set(v8_str("obj"), templ->NewInstance());
2710
2711  // Uses getOwnPropertyDescriptor to check the configurable status
2712  Local<Script> script_desc
2713    = Script::Compile(v8_str("var prop = Object.getOwnPropertyDescriptor( "
2714                             "obj, 'x');"
2715                             "prop.configurable;"));
2716  Local<Value> result = script_desc->Run();
2717  CHECK_EQ(result->BooleanValue(), true);
2718
2719  // Redefine get - but still configurable
2720  Local<Script> script_define
2721    = Script::Compile(v8_str("var desc = { get: function(){return 42; },"
2722                             "            configurable: true };"
2723                             "Object.defineProperty(obj, 'x', desc);"
2724                             "obj.x"));
2725  result = script_define->Run();
2726  CHECK_EQ(result, v8_num(42));
2727
2728  // Check that the accessor is still configurable
2729  result = script_desc->Run();
2730  CHECK_EQ(result->BooleanValue(), true);
2731
2732  // Redefine to a non-configurable
2733  script_define
2734    = Script::Compile(v8_str("var desc = { get: function(){return 43; },"
2735                             "             configurable: false };"
2736                             "Object.defineProperty(obj, 'x', desc);"
2737                             "obj.x"));
2738  result = script_define->Run();
2739  CHECK_EQ(result, v8_num(43));
2740  result = script_desc->Run();
2741  CHECK_EQ(result->BooleanValue(), false);
2742
2743  // Make sure that it is not possible to redefine again
2744  v8::TryCatch try_catch;
2745  result = script_define->Run();
2746  CHECK(try_catch.HasCaught());
2747  String::AsciiValue exception_value(try_catch.Exception());
2748  CHECK_EQ(*exception_value,
2749           "TypeError: Cannot redefine property: defineProperty");
2750}
2751
2752THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
2753  v8::HandleScope scope;
2754  Local<ObjectTemplate> templ = ObjectTemplate::New();
2755  templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
2756  LocalContext context;
2757  context->Global()->Set(v8_str("obj"), templ->NewInstance());
2758
2759  Local<Script> script_desc = Script::Compile(v8_str("var prop ="
2760                                    "Object.getOwnPropertyDescriptor( "
2761                                    "obj, 'x');"
2762                                    "prop.configurable;"));
2763  Local<Value> result = script_desc->Run();
2764  CHECK_EQ(result->BooleanValue(), true);
2765
2766  Local<Script> script_define =
2767    Script::Compile(v8_str("var desc = {get: function(){return 42; },"
2768                           "            configurable: true };"
2769                           "Object.defineProperty(obj, 'x', desc);"
2770                           "obj.x"));
2771  result = script_define->Run();
2772  CHECK_EQ(result, v8_num(42));
2773
2774
2775  result = script_desc->Run();
2776  CHECK_EQ(result->BooleanValue(), true);
2777
2778
2779  script_define =
2780    Script::Compile(v8_str("var desc = {get: function(){return 43; },"
2781                           "            configurable: false };"
2782                           "Object.defineProperty(obj, 'x', desc);"
2783                           "obj.x"));
2784  result = script_define->Run();
2785  CHECK_EQ(result, v8_num(43));
2786  result = script_desc->Run();
2787
2788  CHECK_EQ(result->BooleanValue(), false);
2789
2790  v8::TryCatch try_catch;
2791  result = script_define->Run();
2792  CHECK(try_catch.HasCaught());
2793  String::AsciiValue exception_value(try_catch.Exception());
2794  CHECK_EQ(*exception_value,
2795           "TypeError: Cannot redefine property: defineProperty");
2796}
2797
2798
2799static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
2800                                                char const* name) {
2801  return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
2802}
2803
2804
2805THREADED_TEST(DefineAPIAccessorOnObject) {
2806  v8::HandleScope scope;
2807  Local<ObjectTemplate> templ = ObjectTemplate::New();
2808  LocalContext context;
2809
2810  context->Global()->Set(v8_str("obj1"), templ->NewInstance());
2811  CompileRun("var obj2 = {};");
2812
2813  CHECK(CompileRun("obj1.x")->IsUndefined());
2814  CHECK(CompileRun("obj2.x")->IsUndefined());
2815
2816  CHECK(GetGlobalProperty(&context, "obj1")->
2817      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2818
2819  ExpectString("obj1.x", "x");
2820  CHECK(CompileRun("obj2.x")->IsUndefined());
2821
2822  CHECK(GetGlobalProperty(&context, "obj2")->
2823      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2824
2825  ExpectString("obj1.x", "x");
2826  ExpectString("obj2.x", "x");
2827
2828  ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
2829  ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
2830
2831  CompileRun("Object.defineProperty(obj1, 'x',"
2832             "{ get: function() { return 'y'; }, configurable: true })");
2833
2834  ExpectString("obj1.x", "y");
2835  ExpectString("obj2.x", "x");
2836
2837  CompileRun("Object.defineProperty(obj2, 'x',"
2838             "{ get: function() { return 'y'; }, configurable: true })");
2839
2840  ExpectString("obj1.x", "y");
2841  ExpectString("obj2.x", "y");
2842
2843  ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
2844  ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
2845
2846  CHECK(GetGlobalProperty(&context, "obj1")->
2847      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2848  CHECK(GetGlobalProperty(&context, "obj2")->
2849      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2850
2851  ExpectString("obj1.x", "x");
2852  ExpectString("obj2.x", "x");
2853
2854  ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
2855  ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
2856
2857  // Define getters/setters, but now make them not configurable.
2858  CompileRun("Object.defineProperty(obj1, 'x',"
2859             "{ get: function() { return 'z'; }, configurable: false })");
2860  CompileRun("Object.defineProperty(obj2, 'x',"
2861             "{ get: function() { return 'z'; }, configurable: false })");
2862
2863  ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
2864  ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
2865
2866  ExpectString("obj1.x", "z");
2867  ExpectString("obj2.x", "z");
2868
2869  CHECK(!GetGlobalProperty(&context, "obj1")->
2870      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2871  CHECK(!GetGlobalProperty(&context, "obj2")->
2872      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2873
2874  ExpectString("obj1.x", "z");
2875  ExpectString("obj2.x", "z");
2876}
2877
2878
2879THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
2880  v8::HandleScope scope;
2881  Local<ObjectTemplate> templ = ObjectTemplate::New();
2882  LocalContext context;
2883
2884  context->Global()->Set(v8_str("obj1"), templ->NewInstance());
2885  CompileRun("var obj2 = {};");
2886
2887  CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
2888        v8_str("x"),
2889        GetXValue, NULL,
2890        v8_str("donut"), v8::DEFAULT, v8::DontDelete));
2891  CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
2892        v8_str("x"),
2893        GetXValue, NULL,
2894        v8_str("donut"), v8::DEFAULT, v8::DontDelete));
2895
2896  ExpectString("obj1.x", "x");
2897  ExpectString("obj2.x", "x");
2898
2899  ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
2900  ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
2901
2902  CHECK(!GetGlobalProperty(&context, "obj1")->
2903      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2904  CHECK(!GetGlobalProperty(&context, "obj2")->
2905      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2906
2907  {
2908    v8::TryCatch try_catch;
2909    CompileRun("Object.defineProperty(obj1, 'x',"
2910        "{get: function() { return 'func'; }})");
2911    CHECK(try_catch.HasCaught());
2912    String::AsciiValue exception_value(try_catch.Exception());
2913    CHECK_EQ(*exception_value,
2914            "TypeError: Cannot redefine property: defineProperty");
2915  }
2916  {
2917    v8::TryCatch try_catch;
2918    CompileRun("Object.defineProperty(obj2, 'x',"
2919        "{get: function() { return 'func'; }})");
2920    CHECK(try_catch.HasCaught());
2921    String::AsciiValue exception_value(try_catch.Exception());
2922    CHECK_EQ(*exception_value,
2923            "TypeError: Cannot redefine property: defineProperty");
2924  }
2925}
2926
2927
2928static v8::Handle<Value> Get239Value(Local<String> name,
2929                                     const AccessorInfo& info) {
2930  ApiTestFuzzer::Fuzz();
2931  CHECK_EQ(info.Data(), v8_str("donut"));
2932  CHECK_EQ(name, v8_str("239"));
2933  return name;
2934}
2935
2936
2937THREADED_TEST(ElementAPIAccessor) {
2938  v8::HandleScope scope;
2939  Local<ObjectTemplate> templ = ObjectTemplate::New();
2940  LocalContext context;
2941
2942  context->Global()->Set(v8_str("obj1"), templ->NewInstance());
2943  CompileRun("var obj2 = {};");
2944
2945  CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
2946        v8_str("239"),
2947        Get239Value, NULL,
2948        v8_str("donut")));
2949  CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
2950        v8_str("239"),
2951        Get239Value, NULL,
2952        v8_str("donut")));
2953
2954  ExpectString("obj1[239]", "239");
2955  ExpectString("obj2[239]", "239");
2956  ExpectString("obj1['239']", "239");
2957  ExpectString("obj2['239']", "239");
2958}
2959
2960
2961v8::Persistent<Value> xValue;
2962
2963
2964static void SetXValue(Local<String> name,
2965                      Local<Value> value,
2966                      const AccessorInfo& info) {
2967  CHECK_EQ(value, v8_num(4));
2968  CHECK_EQ(info.Data(), v8_str("donut"));
2969  CHECK_EQ(name, v8_str("x"));
2970  CHECK(xValue.IsEmpty());
2971  xValue = v8::Persistent<Value>::New(value);
2972}
2973
2974
2975THREADED_TEST(SimplePropertyWrite) {
2976  v8::HandleScope scope;
2977  Local<ObjectTemplate> templ = ObjectTemplate::New();
2978  templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
2979  LocalContext context;
2980  context->Global()->Set(v8_str("obj"), templ->NewInstance());
2981  Local<Script> script = Script::Compile(v8_str("obj.x = 4"));
2982  for (int i = 0; i < 10; i++) {
2983    CHECK(xValue.IsEmpty());
2984    script->Run();
2985    CHECK_EQ(v8_num(4), xValue);
2986    xValue.Dispose();
2987    xValue = v8::Persistent<Value>();
2988  }
2989}
2990
2991
2992static v8::Handle<Value> XPropertyGetter(Local<String> property,
2993                                         const AccessorInfo& info) {
2994  ApiTestFuzzer::Fuzz();
2995  CHECK(info.Data()->IsUndefined());
2996  return property;
2997}
2998
2999
3000THREADED_TEST(NamedInterceptorPropertyRead) {
3001  v8::HandleScope scope;
3002  Local<ObjectTemplate> templ = ObjectTemplate::New();
3003  templ->SetNamedPropertyHandler(XPropertyGetter);
3004  LocalContext context;
3005  context->Global()->Set(v8_str("obj"), templ->NewInstance());
3006  Local<Script> script = Script::Compile(v8_str("obj.x"));
3007  for (int i = 0; i < 10; i++) {
3008    Local<Value> result = script->Run();
3009    CHECK_EQ(result, v8_str("x"));
3010  }
3011}
3012
3013
3014THREADED_TEST(NamedInterceptorDictionaryIC) {
3015  v8::HandleScope scope;
3016  Local<ObjectTemplate> templ = ObjectTemplate::New();
3017  templ->SetNamedPropertyHandler(XPropertyGetter);
3018  LocalContext context;
3019  // Create an object with a named interceptor.
3020  context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
3021  Local<Script> script = Script::Compile(v8_str("interceptor_obj.x"));
3022  for (int i = 0; i < 10; i++) {
3023    Local<Value> result = script->Run();
3024    CHECK_EQ(result, v8_str("x"));
3025  }
3026  // Create a slow case object and a function accessing a property in
3027  // that slow case object (with dictionary probing in generated
3028  // code). Then force object with a named interceptor into slow-case,
3029  // pass it to the function, and check that the interceptor is called
3030  // instead of accessing the local property.
3031  Local<Value> result =
3032      CompileRun("function get_x(o) { return o.x; };"
3033                 "var obj = { x : 42, y : 0 };"
3034                 "delete obj.y;"
3035                 "for (var i = 0; i < 10; i++) get_x(obj);"
3036                 "interceptor_obj.x = 42;"
3037                 "interceptor_obj.y = 10;"
3038                 "delete interceptor_obj.y;"
3039                 "get_x(interceptor_obj)");
3040  CHECK_EQ(result, v8_str("x"));
3041}
3042
3043
3044THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
3045  v8::HandleScope scope;
3046
3047  v8::Persistent<Context> context1 = Context::New();
3048
3049  context1->Enter();
3050  Local<ObjectTemplate> templ = ObjectTemplate::New();
3051  templ->SetNamedPropertyHandler(XPropertyGetter);
3052  // Create an object with a named interceptor.
3053  v8::Local<v8::Object> object = templ->NewInstance();
3054  context1->Global()->Set(v8_str("interceptor_obj"), object);
3055
3056  // Force the object into the slow case.
3057  CompileRun("interceptor_obj.y = 0;"
3058             "delete interceptor_obj.y;");
3059  context1->Exit();
3060
3061  {
3062    // Introduce the object into a different context.
3063    // Repeat named loads to exercise ICs.
3064    LocalContext context2;
3065    context2->Global()->Set(v8_str("interceptor_obj"), object);
3066    Local<Value> result =
3067      CompileRun("function get_x(o) { return o.x; }"
3068                 "interceptor_obj.x = 42;"
3069                 "for (var i=0; i != 10; i++) {"
3070                 "  get_x(interceptor_obj);"
3071                 "}"
3072                 "get_x(interceptor_obj)");
3073    // Check that the interceptor was actually invoked.
3074    CHECK_EQ(result, v8_str("x"));
3075  }
3076
3077  // Return to the original context and force some object to the slow case
3078  // to cause the NormalizedMapCache to verify.
3079  context1->Enter();
3080  CompileRun("var obj = { x : 0 }; delete obj.x;");
3081  context1->Exit();
3082
3083  context1.Dispose();
3084}
3085
3086
3087static v8::Handle<Value> SetXOnPrototypeGetter(Local<String> property,
3088                                               const AccessorInfo& info) {
3089  // Set x on the prototype object and do not handle the get request.
3090  v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
3091  proto.As<v8::Object>()->Set(v8_str("x"), v8::Integer::New(23));
3092  return v8::Handle<Value>();
3093}
3094
3095
3096// This is a regression test for http://crbug.com/20104. Map
3097// transitions should not interfere with post interceptor lookup.
3098THREADED_TEST(NamedInterceptorMapTransitionRead) {
3099  v8::HandleScope scope;
3100  Local<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New();
3101  Local<v8::ObjectTemplate> instance_template
3102      = function_template->InstanceTemplate();
3103  instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
3104  LocalContext context;
3105  context->Global()->Set(v8_str("F"), function_template->GetFunction());
3106  // Create an instance of F and introduce a map transition for x.
3107  CompileRun("var o = new F(); o.x = 23;");
3108  // Create an instance of F and invoke the getter. The result should be 23.
3109  Local<Value> result = CompileRun("o = new F(); o.x");
3110  CHECK_EQ(result->Int32Value(), 23);
3111}
3112
3113
3114static v8::Handle<Value> IndexedPropertyGetter(uint32_t index,
3115                                               const AccessorInfo& info) {
3116  ApiTestFuzzer::Fuzz();
3117  if (index == 37) {
3118    return v8::Handle<Value>(v8_num(625));
3119  }
3120  return v8::Handle<Value>();
3121}
3122
3123
3124static v8::Handle<Value> IndexedPropertySetter(uint32_t index,
3125                                               Local<Value> value,
3126                                               const AccessorInfo& info) {
3127  ApiTestFuzzer::Fuzz();
3128  if (index == 39) {
3129    return value;
3130  }
3131  return v8::Handle<Value>();
3132}
3133
3134
3135THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
3136  v8::HandleScope scope;
3137  Local<ObjectTemplate> templ = ObjectTemplate::New();
3138  templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
3139                                   IndexedPropertySetter);
3140  LocalContext context;
3141  context->Global()->Set(v8_str("obj"), templ->NewInstance());
3142  Local<Script> getter_script = Script::Compile(v8_str(
3143      "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];"));
3144  Local<Script> setter_script = Script::Compile(v8_str(
3145      "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
3146      "obj[17] = 23;"
3147      "obj.foo;"));
3148  Local<Script> interceptor_setter_script = Script::Compile(v8_str(
3149      "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
3150      "obj[39] = 47;"
3151      "obj.foo;"));  // This setter should not run, due to the interceptor.
3152  Local<Script> interceptor_getter_script = Script::Compile(v8_str(
3153      "obj[37];"));
3154  Local<Value> result = getter_script->Run();
3155  CHECK_EQ(v8_num(5), result);
3156  result = setter_script->Run();
3157  CHECK_EQ(v8_num(23), result);
3158  result = interceptor_setter_script->Run();
3159  CHECK_EQ(v8_num(23), result);
3160  result = interceptor_getter_script->Run();
3161  CHECK_EQ(v8_num(625), result);
3162}
3163
3164
3165static v8::Handle<Value> IdentityIndexedPropertyGetter(
3166    uint32_t index,
3167    const AccessorInfo& info) {
3168  return v8::Integer::NewFromUnsigned(index);
3169}
3170
3171
3172THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
3173  v8::HandleScope scope;
3174  Local<ObjectTemplate> templ = ObjectTemplate::New();
3175  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3176
3177  LocalContext context;
3178  context->Global()->Set(v8_str("obj"), templ->NewInstance());
3179
3180  // Check fast object case.
3181  const char* fast_case_code =
3182      "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
3183  ExpectString(fast_case_code, "0");
3184
3185  // Check slow case.
3186  const char* slow_case_code =
3187      "obj.x = 1; delete obj.x;"
3188      "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
3189  ExpectString(slow_case_code, "1");
3190}
3191
3192
3193THREADED_TEST(IndexedInterceptorWithNoSetter) {
3194  v8::HandleScope scope;
3195  Local<ObjectTemplate> templ = ObjectTemplate::New();
3196  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3197
3198  LocalContext context;
3199  context->Global()->Set(v8_str("obj"), templ->NewInstance());
3200
3201  const char* code =
3202      "try {"
3203      "  obj[0] = 239;"
3204      "  for (var i = 0; i < 100; i++) {"
3205      "    var v = obj[0];"
3206      "    if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
3207      "  }"
3208      "  'PASSED'"
3209      "} catch(e) {"
3210      "  e"
3211      "}";
3212  ExpectString(code, "PASSED");
3213}
3214
3215
3216THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
3217  v8::HandleScope scope;
3218  Local<ObjectTemplate> templ = ObjectTemplate::New();
3219  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3220
3221  LocalContext context;
3222  Local<v8::Object> obj = templ->NewInstance();
3223  obj->TurnOnAccessCheck();
3224  context->Global()->Set(v8_str("obj"), obj);
3225
3226  const char* code =
3227      "try {"
3228      "  for (var i = 0; i < 100; i++) {"
3229      "    var v = obj[0];"
3230      "    if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
3231      "  }"
3232      "  'PASSED'"
3233      "} catch(e) {"
3234      "  e"
3235      "}";
3236  ExpectString(code, "PASSED");
3237}
3238
3239
3240THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
3241  i::FLAG_allow_natives_syntax = true;
3242  v8::HandleScope scope;
3243  Local<ObjectTemplate> templ = ObjectTemplate::New();
3244  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3245
3246  LocalContext context;
3247  Local<v8::Object> obj = templ->NewInstance();
3248  context->Global()->Set(v8_str("obj"), obj);
3249
3250  const char* code =
3251      "try {"
3252      "  for (var i = 0; i < 100; i++) {"
3253      "    var expected = i;"
3254      "    if (i == 5) {"
3255      "      %EnableAccessChecks(obj);"
3256      "      expected = undefined;"
3257      "    }"
3258      "    var v = obj[i];"
3259      "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3260      "    if (i == 5) %DisableAccessChecks(obj);"
3261      "  }"
3262      "  'PASSED'"
3263      "} catch(e) {"
3264      "  e"
3265      "}";
3266  ExpectString(code, "PASSED");
3267}
3268
3269
3270THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
3271  v8::HandleScope scope;
3272  Local<ObjectTemplate> templ = ObjectTemplate::New();
3273  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3274
3275  LocalContext context;
3276  Local<v8::Object> obj = templ->NewInstance();
3277  context->Global()->Set(v8_str("obj"), obj);
3278
3279  const char* code =
3280      "try {"
3281      "  for (var i = 0; i < 100; i++) {"
3282      "    var v = obj[i];"
3283      "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
3284      "  }"
3285      "  'PASSED'"
3286      "} catch(e) {"
3287      "  e"
3288      "}";
3289  ExpectString(code, "PASSED");
3290}
3291
3292
3293THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
3294  v8::HandleScope scope;
3295  Local<ObjectTemplate> templ = ObjectTemplate::New();
3296  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3297
3298  LocalContext context;
3299  Local<v8::Object> obj = templ->NewInstance();
3300  context->Global()->Set(v8_str("obj"), obj);
3301
3302  const char* code =
3303      "try {"
3304      "  for (var i = 0; i < 100; i++) {"
3305      "    var expected = i;"
3306      "    var key = i;"
3307      "    if (i == 25) {"
3308      "       key = -1;"
3309      "       expected = undefined;"
3310      "    }"
3311      "    if (i == 50) {"
3312      "       /* probe minimal Smi number on 32-bit platforms */"
3313      "       key = -(1 << 30);"
3314      "       expected = undefined;"
3315      "    }"
3316      "    if (i == 75) {"
3317      "       /* probe minimal Smi number on 64-bit platforms */"
3318      "       key = 1 << 31;"
3319      "       expected = undefined;"
3320      "    }"
3321      "    var v = obj[key];"
3322      "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3323      "  }"
3324      "  'PASSED'"
3325      "} catch(e) {"
3326      "  e"
3327      "}";
3328  ExpectString(code, "PASSED");
3329}
3330
3331
3332THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
3333  v8::HandleScope scope;
3334  Local<ObjectTemplate> templ = ObjectTemplate::New();
3335  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3336
3337  LocalContext context;
3338  Local<v8::Object> obj = templ->NewInstance();
3339  context->Global()->Set(v8_str("obj"), obj);
3340
3341  const char* code =
3342      "try {"
3343      "  for (var i = 0; i < 100; i++) {"
3344      "    var expected = i;"
3345      "    var key = i;"
3346      "    if (i == 50) {"
3347      "       key = 'foobar';"
3348      "       expected = undefined;"
3349      "    }"
3350      "    var v = obj[key];"
3351      "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3352      "  }"
3353      "  'PASSED'"
3354      "} catch(e) {"
3355      "  e"
3356      "}";
3357  ExpectString(code, "PASSED");
3358}
3359
3360
3361THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
3362  v8::HandleScope scope;
3363  Local<ObjectTemplate> templ = ObjectTemplate::New();
3364  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3365
3366  LocalContext context;
3367  Local<v8::Object> obj = templ->NewInstance();
3368  context->Global()->Set(v8_str("obj"), obj);
3369
3370  const char* code =
3371      "var original = obj;"
3372      "try {"
3373      "  for (var i = 0; i < 100; i++) {"
3374      "    var expected = i;"
3375      "    if (i == 50) {"
3376      "       obj = {50: 'foobar'};"
3377      "       expected = 'foobar';"
3378      "    }"
3379      "    var v = obj[i];"
3380      "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3381      "    if (i == 50) obj = original;"
3382      "  }"
3383      "  'PASSED'"
3384      "} catch(e) {"
3385      "  e"
3386      "}";
3387  ExpectString(code, "PASSED");
3388}
3389
3390
3391THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
3392  v8::HandleScope scope;
3393  Local<ObjectTemplate> templ = ObjectTemplate::New();
3394  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3395
3396  LocalContext context;
3397  Local<v8::Object> obj = templ->NewInstance();
3398  context->Global()->Set(v8_str("obj"), obj);
3399
3400  const char* code =
3401      "var original = obj;"
3402      "try {"
3403      "  for (var i = 0; i < 100; i++) {"
3404      "    var expected = i;"
3405      "    if (i == 5) {"
3406      "       obj = 239;"
3407      "       expected = undefined;"
3408      "    }"
3409      "    var v = obj[i];"
3410      "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3411      "    if (i == 5) obj = original;"
3412      "  }"
3413      "  'PASSED'"
3414      "} catch(e) {"
3415      "  e"
3416      "}";
3417  ExpectString(code, "PASSED");
3418}
3419
3420
3421THREADED_TEST(IndexedInterceptorOnProto) {
3422  v8::HandleScope scope;
3423  Local<ObjectTemplate> templ = ObjectTemplate::New();
3424  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3425
3426  LocalContext context;
3427  Local<v8::Object> obj = templ->NewInstance();
3428  context->Global()->Set(v8_str("obj"), obj);
3429
3430  const char* code =
3431      "var o = {__proto__: obj};"
3432      "try {"
3433      "  for (var i = 0; i < 100; i++) {"
3434      "    var v = o[i];"
3435      "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
3436      "  }"
3437      "  'PASSED'"
3438      "} catch(e) {"
3439      "  e"
3440      "}";
3441  ExpectString(code, "PASSED");
3442}
3443
3444
3445THREADED_TEST(MultiContexts) {
3446  v8::HandleScope scope;
3447  v8::Handle<ObjectTemplate> templ = ObjectTemplate::New();
3448  templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(DummyCallHandler));
3449
3450  Local<String> password = v8_str("Password");
3451
3452  // Create an environment
3453  LocalContext context0(0, templ);
3454  context0->SetSecurityToken(password);
3455  v8::Handle<v8::Object> global0 = context0->Global();
3456  global0->Set(v8_str("custom"), v8_num(1234));
3457  CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
3458
3459  // Create an independent environment
3460  LocalContext context1(0, templ);
3461  context1->SetSecurityToken(password);
3462  v8::Handle<v8::Object> global1 = context1->Global();
3463  global1->Set(v8_str("custom"), v8_num(1234));
3464  CHECK_NE(global0, global1);
3465  CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
3466  CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
3467
3468  // Now create a new context with the old global
3469  LocalContext context2(0, templ, global1);
3470  context2->SetSecurityToken(password);
3471  v8::Handle<v8::Object> global2 = context2->Global();
3472  CHECK_EQ(global1, global2);
3473  CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
3474  CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
3475}
3476
3477
3478THREADED_TEST(FunctionPrototypeAcrossContexts) {
3479  // Make sure that functions created by cloning boilerplates cannot
3480  // communicate through their __proto__ field.
3481
3482  v8::HandleScope scope;
3483
3484  LocalContext env0;
3485  v8::Handle<v8::Object> global0 =
3486      env0->Global();
3487  v8::Handle<v8::Object> object0 =
3488      global0->Get(v8_str("Object")).As<v8::Object>();
3489  v8::Handle<v8::Object> tostring0 =
3490      object0->Get(v8_str("toString")).As<v8::Object>();
3491  v8::Handle<v8::Object> proto0 =
3492      tostring0->Get(v8_str("__proto__")).As<v8::Object>();
3493  proto0->Set(v8_str("custom"), v8_num(1234));
3494
3495  LocalContext env1;
3496  v8::Handle<v8::Object> global1 =
3497      env1->Global();
3498  v8::Handle<v8::Object> object1 =
3499      global1->Get(v8_str("Object")).As<v8::Object>();
3500  v8::Handle<v8::Object> tostring1 =
3501      object1->Get(v8_str("toString")).As<v8::Object>();
3502  v8::Handle<v8::Object> proto1 =
3503      tostring1->Get(v8_str("__proto__")).As<v8::Object>();
3504  CHECK(!proto1->Has(v8_str("custom")));
3505}
3506
3507
3508THREADED_TEST(Regress892105) {
3509  // Make sure that object and array literals created by cloning
3510  // boilerplates cannot communicate through their __proto__
3511  // field. This is rather difficult to check, but we try to add stuff
3512  // to Object.prototype and Array.prototype and create a new
3513  // environment. This should succeed.
3514
3515  v8::HandleScope scope;
3516
3517  Local<String> source = v8_str("Object.prototype.obj = 1234;"
3518                                "Array.prototype.arr = 4567;"
3519                                "8901");
3520
3521  LocalContext env0;
3522  Local<Script> script0 = Script::Compile(source);
3523  CHECK_EQ(8901.0, script0->Run()->NumberValue());
3524
3525  LocalContext env1;
3526  Local<Script> script1 = Script::Compile(source);
3527  CHECK_EQ(8901.0, script1->Run()->NumberValue());
3528}
3529
3530
3531THREADED_TEST(UndetectableObject) {
3532  v8::HandleScope scope;
3533  LocalContext env;
3534
3535  Local<v8::FunctionTemplate> desc =
3536      v8::FunctionTemplate::New(0, v8::Handle<Value>());
3537  desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
3538
3539  Local<v8::Object> obj = desc->GetFunction()->NewInstance();
3540  env->Global()->Set(v8_str("undetectable"), obj);
3541
3542  ExpectString("undetectable.toString()", "[object Object]");
3543  ExpectString("typeof undetectable", "undefined");
3544  ExpectString("typeof(undetectable)", "undefined");
3545  ExpectBoolean("typeof undetectable == 'undefined'", true);
3546  ExpectBoolean("typeof undetectable == 'object'", false);
3547  ExpectBoolean("if (undetectable) { true; } else { false; }", false);
3548  ExpectBoolean("!undetectable", true);
3549
3550  ExpectObject("true&&undetectable", obj);
3551  ExpectBoolean("false&&undetectable", false);
3552  ExpectBoolean("true||undetectable", true);
3553  ExpectObject("false||undetectable", obj);
3554
3555  ExpectObject("undetectable&&true", obj);
3556  ExpectObject("undetectable&&false", obj);
3557  ExpectBoolean("undetectable||true", true);
3558  ExpectBoolean("undetectable||false", false);
3559
3560  ExpectBoolean("undetectable==null", true);
3561  ExpectBoolean("null==undetectable", true);
3562  ExpectBoolean("undetectable==undefined", true);
3563  ExpectBoolean("undefined==undetectable", true);
3564  ExpectBoolean("undetectable==undetectable", true);
3565
3566
3567  ExpectBoolean("undetectable===null", false);
3568  ExpectBoolean("null===undetectable", false);
3569  ExpectBoolean("undetectable===undefined", false);
3570  ExpectBoolean("undefined===undetectable", false);
3571  ExpectBoolean("undetectable===undetectable", true);
3572}
3573
3574
3575
3576THREADED_TEST(ExtensibleOnUndetectable) {
3577  v8::HandleScope scope;
3578  LocalContext env;
3579
3580  Local<v8::FunctionTemplate> desc =
3581      v8::FunctionTemplate::New(0, v8::Handle<Value>());
3582  desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
3583
3584  Local<v8::Object> obj = desc->GetFunction()->NewInstance();
3585  env->Global()->Set(v8_str("undetectable"), obj);
3586
3587  Local<String> source = v8_str("undetectable.x = 42;"
3588                                "undetectable.x");
3589
3590  Local<Script> script = Script::Compile(source);
3591
3592  CHECK_EQ(v8::Integer::New(42), script->Run());
3593
3594  ExpectBoolean("Object.isExtensible(undetectable)", true);
3595
3596  source = v8_str("Object.preventExtensions(undetectable);");
3597  script = Script::Compile(source);
3598  script->Run();
3599  ExpectBoolean("Object.isExtensible(undetectable)", false);
3600
3601  source = v8_str("undetectable.y = 2000;");
3602  script = Script::Compile(source);
3603  v8::TryCatch try_catch;
3604  Local<Value> result = script->Run();
3605  CHECK(result.IsEmpty());
3606  CHECK(try_catch.HasCaught());
3607}
3608
3609
3610
3611THREADED_TEST(UndetectableString) {
3612  v8::HandleScope scope;
3613  LocalContext env;
3614
3615  Local<String> obj = String::NewUndetectable("foo");
3616  env->Global()->Set(v8_str("undetectable"), obj);
3617
3618  ExpectString("undetectable", "foo");
3619  ExpectString("typeof undetectable", "undefined");
3620  ExpectString("typeof(undetectable)", "undefined");
3621  ExpectBoolean("typeof undetectable == 'undefined'", true);
3622  ExpectBoolean("typeof undetectable == 'string'", false);
3623  ExpectBoolean("if (undetectable) { true; } else { false; }", false);
3624  ExpectBoolean("!undetectable", true);
3625
3626  ExpectObject("true&&undetectable", obj);
3627  ExpectBoolean("false&&undetectable", false);
3628  ExpectBoolean("true||undetectable", true);
3629  ExpectObject("false||undetectable", obj);
3630
3631  ExpectObject("undetectable&&true", obj);
3632  ExpectObject("undetectable&&false", obj);
3633  ExpectBoolean("undetectable||true", true);
3634  ExpectBoolean("undetectable||false", false);
3635
3636  ExpectBoolean("undetectable==null", true);
3637  ExpectBoolean("null==undetectable", true);
3638  ExpectBoolean("undetectable==undefined", true);
3639  ExpectBoolean("undefined==undetectable", true);
3640  ExpectBoolean("undetectable==undetectable", true);
3641
3642
3643  ExpectBoolean("undetectable===null", false);
3644  ExpectBoolean("null===undetectable", false);
3645  ExpectBoolean("undetectable===undefined", false);
3646  ExpectBoolean("undefined===undetectable", false);
3647  ExpectBoolean("undetectable===undetectable", true);
3648}
3649
3650
3651template <typename T> static void USE(T) { }
3652
3653
3654// This test is not intended to be run, just type checked.
3655static void PersistentHandles() {
3656  USE(PersistentHandles);
3657  Local<String> str = v8_str("foo");
3658  v8::Persistent<String> p_str = v8::Persistent<String>::New(str);
3659  USE(p_str);
3660  Local<Script> scr = Script::Compile(v8_str(""));
3661  v8::Persistent<Script> p_scr = v8::Persistent<Script>::New(scr);
3662  USE(p_scr);
3663  Local<ObjectTemplate> templ = ObjectTemplate::New();
3664  v8::Persistent<ObjectTemplate> p_templ =
3665    v8::Persistent<ObjectTemplate>::New(templ);
3666  USE(p_templ);
3667}
3668
3669
3670static v8::Handle<Value> HandleLogDelegator(const v8::Arguments& args) {
3671  ApiTestFuzzer::Fuzz();
3672  return v8::Undefined();
3673}
3674
3675
3676THREADED_TEST(GlobalObjectTemplate) {
3677  v8::HandleScope handle_scope;
3678  Local<ObjectTemplate> global_template = ObjectTemplate::New();
3679  global_template->Set(v8_str("JSNI_Log"),
3680                       v8::FunctionTemplate::New(HandleLogDelegator));
3681  v8::Persistent<Context> context = Context::New(0, global_template);
3682  Context::Scope context_scope(context);
3683  Script::Compile(v8_str("JSNI_Log('LOG')"))->Run();
3684  context.Dispose();
3685}
3686
3687
3688static const char* kSimpleExtensionSource =
3689  "function Foo() {"
3690  "  return 4;"
3691  "}";
3692
3693
3694THREADED_TEST(SimpleExtensions) {
3695  v8::HandleScope handle_scope;
3696  v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
3697  const char* extension_names[] = { "simpletest" };
3698  v8::ExtensionConfiguration extensions(1, extension_names);
3699  v8::Handle<Context> context = Context::New(&extensions);
3700  Context::Scope lock(context);
3701  v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
3702  CHECK_EQ(result, v8::Integer::New(4));
3703}
3704
3705
3706static const char* kEvalExtensionSource1 =
3707  "function UseEval1() {"
3708  "  var x = 42;"
3709  "  return eval('x');"
3710  "}";
3711
3712
3713static const char* kEvalExtensionSource2 =
3714  "(function() {"
3715  "  var x = 42;"
3716  "  function e() {"
3717  "    return eval('x');"
3718  "  }"
3719  "  this.UseEval2 = e;"
3720  "})()";
3721
3722
3723THREADED_TEST(UseEvalFromExtension) {
3724  v8::HandleScope handle_scope;
3725  v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
3726  v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
3727  const char* extension_names[] = { "evaltest1", "evaltest2" };
3728  v8::ExtensionConfiguration extensions(2, extension_names);
3729  v8::Handle<Context> context = Context::New(&extensions);
3730  Context::Scope lock(context);
3731  v8::Handle<Value> result = Script::Compile(v8_str("UseEval1()"))->Run();
3732  CHECK_EQ(result, v8::Integer::New(42));
3733  result = Script::Compile(v8_str("UseEval2()"))->Run();
3734  CHECK_EQ(result, v8::Integer::New(42));
3735}
3736
3737
3738static const char* kWithExtensionSource1 =
3739  "function UseWith1() {"
3740  "  var x = 42;"
3741  "  with({x:87}) { return x; }"
3742  "}";
3743
3744
3745
3746static const char* kWithExtensionSource2 =
3747  "(function() {"
3748  "  var x = 42;"
3749  "  function e() {"
3750  "    with ({x:87}) { return x; }"
3751  "  }"
3752  "  this.UseWith2 = e;"
3753  "})()";
3754
3755
3756THREADED_TEST(UseWithFromExtension) {
3757  v8::HandleScope handle_scope;
3758  v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
3759  v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
3760  const char* extension_names[] = { "withtest1", "withtest2" };
3761  v8::ExtensionConfiguration extensions(2, extension_names);
3762  v8::Handle<Context> context = Context::New(&extensions);
3763  Context::Scope lock(context);
3764  v8::Handle<Value> result = Script::Compile(v8_str("UseWith1()"))->Run();
3765  CHECK_EQ(result, v8::Integer::New(87));
3766  result = Script::Compile(v8_str("UseWith2()"))->Run();
3767  CHECK_EQ(result, v8::Integer::New(87));
3768}
3769
3770
3771THREADED_TEST(AutoExtensions) {
3772  v8::HandleScope handle_scope;
3773  Extension* extension = new Extension("autotest", kSimpleExtensionSource);
3774  extension->set_auto_enable(true);
3775  v8::RegisterExtension(extension);
3776  v8::Handle<Context> context = Context::New();
3777  Context::Scope lock(context);
3778  v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
3779  CHECK_EQ(result, v8::Integer::New(4));
3780}
3781
3782
3783static const char* kSyntaxErrorInExtensionSource =
3784    "[";
3785
3786
3787// Test that a syntax error in an extension does not cause a fatal
3788// error but results in an empty context.
3789THREADED_TEST(SyntaxErrorExtensions) {
3790  v8::HandleScope handle_scope;
3791  v8::RegisterExtension(new Extension("syntaxerror",
3792                                      kSyntaxErrorInExtensionSource));
3793  const char* extension_names[] = { "syntaxerror" };
3794  v8::ExtensionConfiguration extensions(1, extension_names);
3795  v8::Handle<Context> context = Context::New(&extensions);
3796  CHECK(context.IsEmpty());
3797}
3798
3799
3800static const char* kExceptionInExtensionSource =
3801    "throw 42";
3802
3803
3804// Test that an exception when installing an extension does not cause
3805// a fatal error but results in an empty context.
3806THREADED_TEST(ExceptionExtensions) {
3807  v8::HandleScope handle_scope;
3808  v8::RegisterExtension(new Extension("exception",
3809                                      kExceptionInExtensionSource));
3810  const char* extension_names[] = { "exception" };
3811  v8::ExtensionConfiguration extensions(1, extension_names);
3812  v8::Handle<Context> context = Context::New(&extensions);
3813  CHECK(context.IsEmpty());
3814}
3815
3816
3817static const char* kNativeCallInExtensionSource =
3818    "function call_runtime_last_index_of(x) {"
3819    "  return %StringLastIndexOf(x, 'bob', 10);"
3820    "}";
3821
3822
3823static const char* kNativeCallTest =
3824    "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
3825
3826// Test that a native runtime calls are supported in extensions.
3827THREADED_TEST(NativeCallInExtensions) {
3828  v8::HandleScope handle_scope;
3829  v8::RegisterExtension(new Extension("nativecall",
3830                                      kNativeCallInExtensionSource));
3831  const char* extension_names[] = { "nativecall" };
3832  v8::ExtensionConfiguration extensions(1, extension_names);
3833  v8::Handle<Context> context = Context::New(&extensions);
3834  Context::Scope lock(context);
3835  v8::Handle<Value> result = Script::Compile(v8_str(kNativeCallTest))->Run();
3836  CHECK_EQ(result, v8::Integer::New(3));
3837}
3838
3839
3840static void CheckDependencies(const char* name, const char* expected) {
3841  v8::HandleScope handle_scope;
3842  v8::ExtensionConfiguration config(1, &name);
3843  LocalContext context(&config);
3844  CHECK_EQ(String::New(expected), context->Global()->Get(v8_str("loaded")));
3845}
3846
3847
3848/*
3849 * Configuration:
3850 *
3851 *     /-- B <--\
3852 * A <-          -- D <-- E
3853 *     \-- C <--/
3854 */
3855THREADED_TEST(ExtensionDependency) {
3856  static const char* kEDeps[] = { "D" };
3857  v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
3858  static const char* kDDeps[] = { "B", "C" };
3859  v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
3860  static const char* kBCDeps[] = { "A" };
3861  v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
3862  v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
3863  v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
3864  CheckDependencies("A", "undefinedA");
3865  CheckDependencies("B", "undefinedAB");
3866  CheckDependencies("C", "undefinedAC");
3867  CheckDependencies("D", "undefinedABCD");
3868  CheckDependencies("E", "undefinedABCDE");
3869  v8::HandleScope handle_scope;
3870  static const char* exts[2] = { "C", "E" };
3871  v8::ExtensionConfiguration config(2, exts);
3872  LocalContext context(&config);
3873  CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
3874}
3875
3876
3877static const char* kExtensionTestScript =
3878  "native function A();"
3879  "native function B();"
3880  "native function C();"
3881  "function Foo(i) {"
3882  "  if (i == 0) return A();"
3883  "  if (i == 1) return B();"
3884  "  if (i == 2) return C();"
3885  "}";
3886
3887
3888static v8::Handle<Value> CallFun(const v8::Arguments& args) {
3889  ApiTestFuzzer::Fuzz();
3890  if (args.IsConstructCall()) {
3891    args.This()->Set(v8_str("data"), args.Data());
3892    return v8::Null();
3893  }
3894  return args.Data();
3895}
3896
3897
3898class FunctionExtension : public Extension {
3899 public:
3900  FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
3901  virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
3902      v8::Handle<String> name);
3903};
3904
3905
3906static int lookup_count = 0;
3907v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunction(
3908      v8::Handle<String> name) {
3909  lookup_count++;
3910  if (name->Equals(v8_str("A"))) {
3911    return v8::FunctionTemplate::New(CallFun, v8::Integer::New(8));
3912  } else if (name->Equals(v8_str("B"))) {
3913    return v8::FunctionTemplate::New(CallFun, v8::Integer::New(7));
3914  } else if (name->Equals(v8_str("C"))) {
3915    return v8::FunctionTemplate::New(CallFun, v8::Integer::New(6));
3916  } else {
3917    return v8::Handle<v8::FunctionTemplate>();
3918  }
3919}
3920
3921
3922THREADED_TEST(FunctionLookup) {
3923  v8::RegisterExtension(new FunctionExtension());
3924  v8::HandleScope handle_scope;
3925  static const char* exts[1] = { "functiontest" };
3926  v8::ExtensionConfiguration config(1, exts);
3927  LocalContext context(&config);
3928  CHECK_EQ(3, lookup_count);
3929  CHECK_EQ(v8::Integer::New(8), Script::Compile(v8_str("Foo(0)"))->Run());
3930  CHECK_EQ(v8::Integer::New(7), Script::Compile(v8_str("Foo(1)"))->Run());
3931  CHECK_EQ(v8::Integer::New(6), Script::Compile(v8_str("Foo(2)"))->Run());
3932}
3933
3934
3935THREADED_TEST(NativeFunctionConstructCall) {
3936  v8::RegisterExtension(new FunctionExtension());
3937  v8::HandleScope handle_scope;
3938  static const char* exts[1] = { "functiontest" };
3939  v8::ExtensionConfiguration config(1, exts);
3940  LocalContext context(&config);
3941  for (int i = 0; i < 10; i++) {
3942    // Run a few times to ensure that allocation of objects doesn't
3943    // change behavior of a constructor function.
3944    CHECK_EQ(v8::Integer::New(8),
3945             Script::Compile(v8_str("(new A()).data"))->Run());
3946    CHECK_EQ(v8::Integer::New(7),
3947             Script::Compile(v8_str("(new B()).data"))->Run());
3948    CHECK_EQ(v8::Integer::New(6),
3949             Script::Compile(v8_str("(new C()).data"))->Run());
3950  }
3951}
3952
3953
3954static const char* last_location;
3955static const char* last_message;
3956void StoringErrorCallback(const char* location, const char* message) {
3957  if (last_location == NULL) {
3958    last_location = location;
3959    last_message = message;
3960  }
3961}
3962
3963
3964// ErrorReporting creates a circular extensions configuration and
3965// tests that the fatal error handler gets called.  This renders V8
3966// unusable and therefore this test cannot be run in parallel.
3967TEST(ErrorReporting) {
3968  v8::V8::SetFatalErrorHandler(StoringErrorCallback);
3969  static const char* aDeps[] = { "B" };
3970  v8::RegisterExtension(new Extension("A", "", 1, aDeps));
3971  static const char* bDeps[] = { "A" };
3972  v8::RegisterExtension(new Extension("B", "", 1, bDeps));
3973  last_location = NULL;
3974  v8::ExtensionConfiguration config(1, bDeps);
3975  v8::Handle<Context> context = Context::New(&config);
3976  CHECK(context.IsEmpty());
3977  CHECK_NE(last_location, NULL);
3978}
3979
3980
3981static const char* js_code_causing_huge_string_flattening =
3982    "var str = 'X';"
3983    "for (var i = 0; i < 30; i++) {"
3984    "  str = str + str;"
3985    "}"
3986    "str.match(/X/);";
3987
3988
3989void OOMCallback(const char* location, const char* message) {
3990  exit(0);
3991}
3992
3993
3994TEST(RegexpOutOfMemory) {
3995  // Execute a script that causes out of memory when flattening a string.
3996  v8::HandleScope scope;
3997  v8::V8::SetFatalErrorHandler(OOMCallback);
3998  LocalContext context;
3999  Local<Script> script =
4000      Script::Compile(String::New(js_code_causing_huge_string_flattening));
4001  last_location = NULL;
4002  Local<Value> result = script->Run();
4003
4004  CHECK(false);  // Should not return.
4005}
4006
4007
4008static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
4009                                             v8::Handle<Value> data) {
4010  CHECK_EQ(v8::Undefined(), data);
4011  CHECK(message->GetScriptResourceName()->IsUndefined());
4012  CHECK_EQ(v8::Undefined(), message->GetScriptResourceName());
4013  message->GetLineNumber();
4014  message->GetSourceLine();
4015}
4016
4017
4018THREADED_TEST(ErrorWithMissingScriptInfo) {
4019  v8::HandleScope scope;
4020  LocalContext context;
4021  v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
4022  Script::Compile(v8_str("throw Error()"))->Run();
4023  v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
4024}
4025
4026
4027int global_index = 0;
4028
4029class Snorkel {
4030 public:
4031  Snorkel() { index_ = global_index++; }
4032  int index_;
4033};
4034
4035class Whammy {
4036 public:
4037  Whammy() {
4038    cursor_ = 0;
4039  }
4040  ~Whammy() {
4041    script_.Dispose();
4042  }
4043  v8::Handle<Script> getScript() {
4044    if (script_.IsEmpty())
4045      script_ = v8::Persistent<Script>::New(v8_compile("({}).blammo"));
4046    return Local<Script>(*script_);
4047  }
4048
4049 public:
4050  static const int kObjectCount = 256;
4051  int cursor_;
4052  v8::Persistent<v8::Object> objects_[kObjectCount];
4053  v8::Persistent<Script> script_;
4054};
4055
4056static void HandleWeakReference(v8::Persistent<v8::Value> obj, void* data) {
4057  Snorkel* snorkel = reinterpret_cast<Snorkel*>(data);
4058  delete snorkel;
4059  obj.ClearWeak();
4060}
4061
4062v8::Handle<Value> WhammyPropertyGetter(Local<String> name,
4063                                       const AccessorInfo& info) {
4064  Whammy* whammy =
4065    static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
4066
4067  v8::Persistent<v8::Object> prev = whammy->objects_[whammy->cursor_];
4068
4069  v8::Handle<v8::Object> obj = v8::Object::New();
4070  v8::Persistent<v8::Object> global = v8::Persistent<v8::Object>::New(obj);
4071  if (!prev.IsEmpty()) {
4072    prev->Set(v8_str("next"), obj);
4073    prev.MakeWeak(new Snorkel(), &HandleWeakReference);
4074    whammy->objects_[whammy->cursor_].Clear();
4075  }
4076  whammy->objects_[whammy->cursor_] = global;
4077  whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount;
4078  return whammy->getScript()->Run();
4079}
4080
4081THREADED_TEST(WeakReference) {
4082  v8::HandleScope handle_scope;
4083  v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New();
4084  Whammy* whammy = new Whammy();
4085  templ->SetNamedPropertyHandler(WhammyPropertyGetter,
4086                                 0, 0, 0, 0,
4087                                 v8::External::New(whammy));
4088  const char* extension_list[] = { "v8/gc" };
4089  v8::ExtensionConfiguration extensions(1, extension_list);
4090  v8::Persistent<Context> context = Context::New(&extensions);
4091  Context::Scope context_scope(context);
4092
4093  v8::Handle<v8::Object> interceptor = templ->NewInstance();
4094  context->Global()->Set(v8_str("whammy"), interceptor);
4095  const char* code =
4096      "var last;"
4097      "for (var i = 0; i < 10000; i++) {"
4098      "  var obj = whammy.length;"
4099      "  if (last) last.next = obj;"
4100      "  last = obj;"
4101      "}"
4102      "gc();"
4103      "4";
4104  v8::Handle<Value> result = CompileRun(code);
4105  CHECK_EQ(4.0, result->NumberValue());
4106  delete whammy;
4107  context.Dispose();
4108}
4109
4110
4111static bool in_scavenge = false;
4112static int last = -1;
4113
4114static void ForceScavenge(v8::Persistent<v8::Value> obj, void* data) {
4115  CHECK_EQ(-1, last);
4116  last = 0;
4117  obj.Dispose();
4118  obj.Clear();
4119  in_scavenge = true;
4120  i::Heap::PerformScavenge();
4121  in_scavenge = false;
4122  *(reinterpret_cast<bool*>(data)) = true;
4123}
4124
4125static void CheckIsNotInvokedInScavenge(v8::Persistent<v8::Value> obj,
4126                                        void* data) {
4127  CHECK_EQ(0, last);
4128  last = 1;
4129  *(reinterpret_cast<bool*>(data)) = in_scavenge;
4130  obj.Dispose();
4131  obj.Clear();
4132}
4133
4134THREADED_TEST(NoWeakRefCallbacksInScavenge) {
4135  // Test verifies that scavenge cannot invoke WeakReferenceCallbacks.
4136  // Calling callbacks from scavenges is unsafe as objects held by those
4137  // handlers might have become strongly reachable, but scavenge doesn't
4138  // check that.
4139  v8::Persistent<Context> context = Context::New();
4140  Context::Scope context_scope(context);
4141
4142  v8::Persistent<v8::Object> object_a;
4143  v8::Persistent<v8::Object> object_b;
4144
4145  {
4146    v8::HandleScope handle_scope;
4147    object_b = v8::Persistent<v8::Object>::New(v8::Object::New());
4148    object_a = v8::Persistent<v8::Object>::New(v8::Object::New());
4149  }
4150
4151  bool object_a_disposed = false;
4152  object_a.MakeWeak(&object_a_disposed, &ForceScavenge);
4153  bool released_in_scavenge = false;
4154  object_b.MakeWeak(&released_in_scavenge, &CheckIsNotInvokedInScavenge);
4155
4156  while (!object_a_disposed) {
4157    i::Heap::CollectAllGarbage(false);
4158  }
4159  CHECK(!released_in_scavenge);
4160}
4161
4162
4163v8::Handle<Function> args_fun;
4164
4165
4166static v8::Handle<Value> ArgumentsTestCallback(const v8::Arguments& args) {
4167  ApiTestFuzzer::Fuzz();
4168  CHECK_EQ(args_fun, args.Callee());
4169  CHECK_EQ(3, args.Length());
4170  CHECK_EQ(v8::Integer::New(1), args[0]);
4171  CHECK_EQ(v8::Integer::New(2), args[1]);
4172  CHECK_EQ(v8::Integer::New(3), args[2]);
4173  CHECK_EQ(v8::Undefined(), args[3]);
4174  v8::HandleScope scope;
4175  i::Heap::CollectAllGarbage(false);
4176  return v8::Undefined();
4177}
4178
4179
4180THREADED_TEST(Arguments) {
4181  v8::HandleScope scope;
4182  v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
4183  global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback));
4184  LocalContext context(NULL, global);
4185  args_fun = context->Global()->Get(v8_str("f")).As<Function>();
4186  v8_compile("f(1, 2, 3)")->Run();
4187}
4188
4189
4190static v8::Handle<Value> NoBlockGetterX(Local<String> name,
4191                                        const AccessorInfo&) {
4192  return v8::Handle<Value>();
4193}
4194
4195
4196static v8::Handle<Value> NoBlockGetterI(uint32_t index,
4197                                        const AccessorInfo&) {
4198  return v8::Handle<Value>();
4199}
4200
4201
4202static v8::Handle<v8::Boolean> PDeleter(Local<String> name,
4203                                        const AccessorInfo&) {
4204  if (!name->Equals(v8_str("foo"))) {
4205    return v8::Handle<v8::Boolean>();  // not intercepted
4206  }
4207
4208  return v8::False();  // intercepted, and don't delete the property
4209}
4210
4211
4212static v8::Handle<v8::Boolean> IDeleter(uint32_t index, const AccessorInfo&) {
4213  if (index != 2) {
4214    return v8::Handle<v8::Boolean>();  // not intercepted
4215  }
4216
4217  return v8::False();  // intercepted, and don't delete the property
4218}
4219
4220
4221THREADED_TEST(Deleter) {
4222  v8::HandleScope scope;
4223  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4224  obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
4225  obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
4226  LocalContext context;
4227  context->Global()->Set(v8_str("k"), obj->NewInstance());
4228  CompileRun(
4229    "k.foo = 'foo';"
4230    "k.bar = 'bar';"
4231    "k[2] = 2;"
4232    "k[4] = 4;");
4233  CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
4234  CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
4235
4236  CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
4237  CHECK(v8_compile("k.bar")->Run()->IsUndefined());
4238
4239  CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
4240  CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
4241
4242  CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
4243  CHECK(v8_compile("k[4]")->Run()->IsUndefined());
4244}
4245
4246
4247static v8::Handle<Value> GetK(Local<String> name, const AccessorInfo&) {
4248  ApiTestFuzzer::Fuzz();
4249  if (name->Equals(v8_str("foo")) ||
4250      name->Equals(v8_str("bar")) ||
4251      name->Equals(v8_str("baz"))) {
4252    return v8::Undefined();
4253  }
4254  return v8::Handle<Value>();
4255}
4256
4257
4258static v8::Handle<Value> IndexedGetK(uint32_t index, const AccessorInfo&) {
4259  ApiTestFuzzer::Fuzz();
4260  if (index == 0 || index == 1) return v8::Undefined();
4261  return v8::Handle<Value>();
4262}
4263
4264
4265static v8::Handle<v8::Array> NamedEnum(const AccessorInfo&) {
4266  ApiTestFuzzer::Fuzz();
4267  v8::Handle<v8::Array> result = v8::Array::New(3);
4268  result->Set(v8::Integer::New(0), v8_str("foo"));
4269  result->Set(v8::Integer::New(1), v8_str("bar"));
4270  result->Set(v8::Integer::New(2), v8_str("baz"));
4271  return result;
4272}
4273
4274
4275static v8::Handle<v8::Array> IndexedEnum(const AccessorInfo&) {
4276  ApiTestFuzzer::Fuzz();
4277  v8::Handle<v8::Array> result = v8::Array::New(2);
4278  result->Set(v8::Integer::New(0), v8_str("0"));
4279  result->Set(v8::Integer::New(1), v8_str("1"));
4280  return result;
4281}
4282
4283
4284THREADED_TEST(Enumerators) {
4285  v8::HandleScope scope;
4286  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4287  obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
4288  obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
4289  LocalContext context;
4290  context->Global()->Set(v8_str("k"), obj->NewInstance());
4291  v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
4292    "k[10] = 0;"
4293    "k.a = 0;"
4294    "k[5] = 0;"
4295    "k.b = 0;"
4296    "k[4294967295] = 0;"
4297    "k.c = 0;"
4298    "k[4294967296] = 0;"
4299    "k.d = 0;"
4300    "k[140000] = 0;"
4301    "k.e = 0;"
4302    "k[30000000000] = 0;"
4303    "k.f = 0;"
4304    "var result = [];"
4305    "for (var prop in k) {"
4306    "  result.push(prop);"
4307    "}"
4308    "result"));
4309  // Check that we get all the property names returned including the
4310  // ones from the enumerators in the right order: indexed properties
4311  // in numerical order, indexed interceptor properties, named
4312  // properties in insertion order, named interceptor properties.
4313  // This order is not mandated by the spec, so this test is just
4314  // documenting our behavior.
4315  CHECK_EQ(17, result->Length());
4316  // Indexed properties in numerical order.
4317  CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(0)));
4318  CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(1)));
4319  CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(2)));
4320  CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(3)));
4321  // Indexed interceptor properties in the order they are returned
4322  // from the enumerator interceptor.
4323  CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(4)));
4324  CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(5)));
4325  // Named properties in insertion order.
4326  CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(6)));
4327  CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(7)));
4328  CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(8)));
4329  CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(9)));
4330  CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(10)));
4331  CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(11)));
4332  CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(12)));
4333  CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(13)));
4334  // Named interceptor properties.
4335  CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(14)));
4336  CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(15)));
4337  CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(16)));
4338}
4339
4340
4341int p_getter_count;
4342int p_getter_count2;
4343
4344
4345static v8::Handle<Value> PGetter(Local<String> name, const AccessorInfo& info) {
4346  ApiTestFuzzer::Fuzz();
4347  p_getter_count++;
4348  v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
4349  CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
4350  if (name->Equals(v8_str("p1"))) {
4351    CHECK_EQ(info.This(), global->Get(v8_str("o1")));
4352  } else if (name->Equals(v8_str("p2"))) {
4353    CHECK_EQ(info.This(), global->Get(v8_str("o2")));
4354  } else if (name->Equals(v8_str("p3"))) {
4355    CHECK_EQ(info.This(), global->Get(v8_str("o3")));
4356  } else if (name->Equals(v8_str("p4"))) {
4357    CHECK_EQ(info.This(), global->Get(v8_str("o4")));
4358  }
4359  return v8::Undefined();
4360}
4361
4362
4363static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
4364  ApiTestFuzzer::Fuzz();
4365  LocalContext context;
4366  context->Global()->Set(v8_str("o1"), obj->NewInstance());
4367  CompileRun(
4368    "o1.__proto__ = { };"
4369    "var o2 = { __proto__: o1 };"
4370    "var o3 = { __proto__: o2 };"
4371    "var o4 = { __proto__: o3 };"
4372    "for (var i = 0; i < 10; i++) o4.p4;"
4373    "for (var i = 0; i < 10; i++) o3.p3;"
4374    "for (var i = 0; i < 10; i++) o2.p2;"
4375    "for (var i = 0; i < 10; i++) o1.p1;");
4376}
4377
4378
4379static v8::Handle<Value> PGetter2(Local<String> name,
4380                                  const AccessorInfo& info) {
4381  ApiTestFuzzer::Fuzz();
4382  p_getter_count2++;
4383  v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
4384  CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
4385  if (name->Equals(v8_str("p1"))) {
4386    CHECK_EQ(info.This(), global->Get(v8_str("o1")));
4387  } else if (name->Equals(v8_str("p2"))) {
4388    CHECK_EQ(info.This(), global->Get(v8_str("o2")));
4389  } else if (name->Equals(v8_str("p3"))) {
4390    CHECK_EQ(info.This(), global->Get(v8_str("o3")));
4391  } else if (name->Equals(v8_str("p4"))) {
4392    CHECK_EQ(info.This(), global->Get(v8_str("o4")));
4393  }
4394  return v8::Undefined();
4395}
4396
4397
4398THREADED_TEST(GetterHolders) {
4399  v8::HandleScope scope;
4400  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4401  obj->SetAccessor(v8_str("p1"), PGetter);
4402  obj->SetAccessor(v8_str("p2"), PGetter);
4403  obj->SetAccessor(v8_str("p3"), PGetter);
4404  obj->SetAccessor(v8_str("p4"), PGetter);
4405  p_getter_count = 0;
4406  RunHolderTest(obj);
4407  CHECK_EQ(40, p_getter_count);
4408}
4409
4410
4411THREADED_TEST(PreInterceptorHolders) {
4412  v8::HandleScope scope;
4413  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4414  obj->SetNamedPropertyHandler(PGetter2);
4415  p_getter_count2 = 0;
4416  RunHolderTest(obj);
4417  CHECK_EQ(40, p_getter_count2);
4418}
4419
4420
4421THREADED_TEST(ObjectInstantiation) {
4422  v8::HandleScope scope;
4423  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
4424  templ->SetAccessor(v8_str("t"), PGetter2);
4425  LocalContext context;
4426  context->Global()->Set(v8_str("o"), templ->NewInstance());
4427  for (int i = 0; i < 100; i++) {
4428    v8::HandleScope inner_scope;
4429    v8::Handle<v8::Object> obj = templ->NewInstance();
4430    CHECK_NE(obj, context->Global()->Get(v8_str("o")));
4431    context->Global()->Set(v8_str("o2"), obj);
4432    v8::Handle<Value> value =
4433        Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run();
4434    CHECK_EQ(v8::True(), value);
4435    context->Global()->Set(v8_str("o"), obj);
4436  }
4437}
4438
4439
4440static int StrCmp16(uint16_t* a, uint16_t* b) {
4441  while (true) {
4442    if (*a == 0 && *b == 0) return 0;
4443    if (*a != *b) return 0 + *a - *b;
4444    a++;
4445    b++;
4446  }
4447}
4448
4449
4450static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
4451  while (true) {
4452    if (n-- == 0) return 0;
4453    if (*a == 0 && *b == 0) return 0;
4454    if (*a != *b) return 0 + *a - *b;
4455    a++;
4456    b++;
4457  }
4458}
4459
4460
4461THREADED_TEST(StringWrite) {
4462  v8::HandleScope scope;
4463  v8::Handle<String> str = v8_str("abcde");
4464  // abc<Icelandic eth><Unicode snowman>.
4465  v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
4466
4467  CHECK_EQ(5, str2->Length());
4468
4469  char buf[100];
4470  char utf8buf[100];
4471  uint16_t wbuf[100];
4472  int len;
4473  int charlen;
4474
4475  memset(utf8buf, 0x1, sizeof(utf8buf));
4476  len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
4477  CHECK_EQ(len, 9);
4478  CHECK_EQ(charlen, 5);
4479  CHECK_EQ(strcmp(utf8buf, "abc\303\260\342\230\203"), 0);
4480
4481  memset(utf8buf, 0x1, sizeof(utf8buf));
4482  len = str2->WriteUtf8(utf8buf, 8, &charlen);
4483  CHECK_EQ(len, 8);
4484  CHECK_EQ(charlen, 5);
4485  CHECK_EQ(strncmp(utf8buf, "abc\303\260\342\230\203\1", 9), 0);
4486
4487  memset(utf8buf, 0x1, sizeof(utf8buf));
4488  len = str2->WriteUtf8(utf8buf, 7, &charlen);
4489  CHECK_EQ(len, 5);
4490  CHECK_EQ(charlen, 4);
4491  CHECK_EQ(strncmp(utf8buf, "abc\303\260\1", 5), 0);
4492
4493  memset(utf8buf, 0x1, sizeof(utf8buf));
4494  len = str2->WriteUtf8(utf8buf, 6, &charlen);
4495  CHECK_EQ(len, 5);
4496  CHECK_EQ(charlen, 4);
4497  CHECK_EQ(strncmp(utf8buf, "abc\303\260\1", 5), 0);
4498
4499  memset(utf8buf, 0x1, sizeof(utf8buf));
4500  len = str2->WriteUtf8(utf8buf, 5, &charlen);
4501  CHECK_EQ(len, 5);
4502  CHECK_EQ(charlen, 4);
4503  CHECK_EQ(strncmp(utf8buf, "abc\303\260\1", 5), 0);
4504
4505  memset(utf8buf, 0x1, sizeof(utf8buf));
4506  len = str2->WriteUtf8(utf8buf, 4, &charlen);
4507  CHECK_EQ(len, 3);
4508  CHECK_EQ(charlen, 3);
4509  CHECK_EQ(strncmp(utf8buf, "abc\1", 4), 0);
4510
4511  memset(utf8buf, 0x1, sizeof(utf8buf));
4512  len = str2->WriteUtf8(utf8buf, 3, &charlen);
4513  CHECK_EQ(len, 3);
4514  CHECK_EQ(charlen, 3);
4515  CHECK_EQ(strncmp(utf8buf, "abc\1", 4), 0);
4516
4517  memset(utf8buf, 0x1, sizeof(utf8buf));
4518  len = str2->WriteUtf8(utf8buf, 2, &charlen);
4519  CHECK_EQ(len, 2);
4520  CHECK_EQ(charlen, 2);
4521  CHECK_EQ(strncmp(utf8buf, "ab\1", 3), 0);
4522
4523  memset(buf, 0x1, sizeof(buf));
4524  memset(wbuf, 0x1, sizeof(wbuf));
4525  len = str->WriteAscii(buf);
4526  CHECK_EQ(len, 5);
4527  len = str->Write(wbuf);
4528  CHECK_EQ(len, 5);
4529  CHECK_EQ(strcmp("abcde", buf), 0);
4530  uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
4531  CHECK_EQ(StrCmp16(answer1, wbuf), 0);
4532
4533  memset(buf, 0x1, sizeof(buf));
4534  memset(wbuf, 0x1, sizeof(wbuf));
4535  len = str->WriteAscii(buf, 0, 4);
4536  CHECK_EQ(len, 4);
4537  len = str->Write(wbuf, 0, 4);
4538  CHECK_EQ(len, 4);
4539  CHECK_EQ(strncmp("abcd\1", buf, 5), 0);
4540  uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
4541  CHECK_EQ(StrNCmp16(answer2, wbuf, 5), 0);
4542
4543  memset(buf, 0x1, sizeof(buf));
4544  memset(wbuf, 0x1, sizeof(wbuf));
4545  len = str->WriteAscii(buf, 0, 5);
4546  CHECK_EQ(len, 5);
4547  len = str->Write(wbuf, 0, 5);
4548  CHECK_EQ(len, 5);
4549  CHECK_EQ(strncmp("abcde\1", buf, 6), 0);
4550  uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
4551  CHECK_EQ(StrNCmp16(answer3, wbuf, 6), 0);
4552
4553  memset(buf, 0x1, sizeof(buf));
4554  memset(wbuf, 0x1, sizeof(wbuf));
4555  len = str->WriteAscii(buf, 0, 6);
4556  CHECK_EQ(len, 5);
4557  len = str->Write(wbuf, 0, 6);
4558  CHECK_EQ(len, 5);
4559  CHECK_EQ(strcmp("abcde", buf), 0);
4560  uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
4561  CHECK_EQ(StrCmp16(answer4, wbuf), 0);
4562
4563  memset(buf, 0x1, sizeof(buf));
4564  memset(wbuf, 0x1, sizeof(wbuf));
4565  len = str->WriteAscii(buf, 4, -1);
4566  CHECK_EQ(len, 1);
4567  len = str->Write(wbuf, 4, -1);
4568  CHECK_EQ(len, 1);
4569  CHECK_EQ(strcmp("e", buf), 0);
4570  uint16_t answer5[] = {'e', '\0'};
4571  CHECK_EQ(StrCmp16(answer5, wbuf), 0);
4572
4573  memset(buf, 0x1, sizeof(buf));
4574  memset(wbuf, 0x1, sizeof(wbuf));
4575  len = str->WriteAscii(buf, 4, 6);
4576  CHECK_EQ(len, 1);
4577  len = str->Write(wbuf, 4, 6);
4578  CHECK_EQ(len, 1);
4579  CHECK_EQ(strcmp("e", buf), 0);
4580  CHECK_EQ(StrCmp16(answer5, wbuf), 0);
4581
4582  memset(buf, 0x1, sizeof(buf));
4583  memset(wbuf, 0x1, sizeof(wbuf));
4584  len = str->WriteAscii(buf, 4, 1);
4585  CHECK_EQ(len, 1);
4586  len = str->Write(wbuf, 4, 1);
4587  CHECK_EQ(len, 1);
4588  CHECK_EQ(strncmp("e\1", buf, 2), 0);
4589  uint16_t answer6[] = {'e', 0x101};
4590  CHECK_EQ(StrNCmp16(answer6, wbuf, 2), 0);
4591
4592  memset(buf, 0x1, sizeof(buf));
4593  memset(wbuf, 0x1, sizeof(wbuf));
4594  len = str->WriteAscii(buf, 3, 1);
4595  CHECK_EQ(len, 1);
4596  len = str->Write(wbuf, 3, 1);
4597  CHECK_EQ(len, 1);
4598  CHECK_EQ(strncmp("d\1", buf, 2), 0);
4599  uint16_t answer7[] = {'d', 0x101};
4600  CHECK_EQ(StrNCmp16(answer7, wbuf, 2), 0);
4601}
4602
4603
4604THREADED_TEST(ToArrayIndex) {
4605  v8::HandleScope scope;
4606  LocalContext context;
4607
4608  v8::Handle<String> str = v8_str("42");
4609  v8::Handle<v8::Uint32> index = str->ToArrayIndex();
4610  CHECK(!index.IsEmpty());
4611  CHECK_EQ(42.0, index->Uint32Value());
4612  str = v8_str("42asdf");
4613  index = str->ToArrayIndex();
4614  CHECK(index.IsEmpty());
4615  str = v8_str("-42");
4616  index = str->ToArrayIndex();
4617  CHECK(index.IsEmpty());
4618  str = v8_str("4294967295");
4619  index = str->ToArrayIndex();
4620  CHECK(!index.IsEmpty());
4621  CHECK_EQ(4294967295.0, index->Uint32Value());
4622  v8::Handle<v8::Number> num = v8::Number::New(1);
4623  index = num->ToArrayIndex();
4624  CHECK(!index.IsEmpty());
4625  CHECK_EQ(1.0, index->Uint32Value());
4626  num = v8::Number::New(-1);
4627  index = num->ToArrayIndex();
4628  CHECK(index.IsEmpty());
4629  v8::Handle<v8::Object> obj = v8::Object::New();
4630  index = obj->ToArrayIndex();
4631  CHECK(index.IsEmpty());
4632}
4633
4634
4635THREADED_TEST(ErrorConstruction) {
4636  v8::HandleScope scope;
4637  LocalContext context;
4638
4639  v8::Handle<String> foo = v8_str("foo");
4640  v8::Handle<String> message = v8_str("message");
4641  v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
4642  CHECK(range_error->IsObject());
4643  v8::Handle<v8::Object> range_obj = range_error.As<v8::Object>();
4644  CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
4645  v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
4646  CHECK(reference_error->IsObject());
4647  CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
4648  v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
4649  CHECK(syntax_error->IsObject());
4650  CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
4651  v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
4652  CHECK(type_error->IsObject());
4653  CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
4654  v8::Handle<Value> error = v8::Exception::Error(foo);
4655  CHECK(error->IsObject());
4656  CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
4657}
4658
4659
4660static v8::Handle<Value> YGetter(Local<String> name, const AccessorInfo& info) {
4661  ApiTestFuzzer::Fuzz();
4662  return v8_num(10);
4663}
4664
4665
4666static void YSetter(Local<String> name,
4667                    Local<Value> value,
4668                    const AccessorInfo& info) {
4669  if (info.This()->Has(name)) {
4670    info.This()->Delete(name);
4671  }
4672  info.This()->Set(name, value);
4673}
4674
4675
4676THREADED_TEST(DeleteAccessor) {
4677  v8::HandleScope scope;
4678  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4679  obj->SetAccessor(v8_str("y"), YGetter, YSetter);
4680  LocalContext context;
4681  v8::Handle<v8::Object> holder = obj->NewInstance();
4682  context->Global()->Set(v8_str("holder"), holder);
4683  v8::Handle<Value> result = CompileRun(
4684      "holder.y = 11; holder.y = 12; holder.y");
4685  CHECK_EQ(12, result->Uint32Value());
4686}
4687
4688
4689THREADED_TEST(TypeSwitch) {
4690  v8::HandleScope scope;
4691  v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New();
4692  v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New();
4693  v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New();
4694  v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
4695  v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
4696  LocalContext context;
4697  v8::Handle<v8::Object> obj0 = v8::Object::New();
4698  v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
4699  v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
4700  v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
4701  for (int i = 0; i < 10; i++) {
4702    CHECK_EQ(0, type_switch->match(obj0));
4703    CHECK_EQ(1, type_switch->match(obj1));
4704    CHECK_EQ(2, type_switch->match(obj2));
4705    CHECK_EQ(3, type_switch->match(obj3));
4706    CHECK_EQ(3, type_switch->match(obj3));
4707    CHECK_EQ(2, type_switch->match(obj2));
4708    CHECK_EQ(1, type_switch->match(obj1));
4709    CHECK_EQ(0, type_switch->match(obj0));
4710  }
4711}
4712
4713
4714// For use within the TestSecurityHandler() test.
4715static bool g_security_callback_result = false;
4716static bool NamedSecurityTestCallback(Local<v8::Object> global,
4717                                      Local<Value> name,
4718                                      v8::AccessType type,
4719                                      Local<Value> data) {
4720  // Always allow read access.
4721  if (type == v8::ACCESS_GET)
4722    return true;
4723
4724  // Sometimes allow other access.
4725  return g_security_callback_result;
4726}
4727
4728
4729static bool IndexedSecurityTestCallback(Local<v8::Object> global,
4730                                        uint32_t key,
4731                                        v8::AccessType type,
4732                                        Local<Value> data) {
4733  // Always allow read access.
4734  if (type == v8::ACCESS_GET)
4735    return true;
4736
4737  // Sometimes allow other access.
4738  return g_security_callback_result;
4739}
4740
4741
4742static int trouble_nesting = 0;
4743static v8::Handle<Value> TroubleCallback(const v8::Arguments& args) {
4744  ApiTestFuzzer::Fuzz();
4745  trouble_nesting++;
4746
4747  // Call a JS function that throws an uncaught exception.
4748  Local<v8::Object> arg_this = Context::GetCurrent()->Global();
4749  Local<Value> trouble_callee = (trouble_nesting == 3) ?
4750    arg_this->Get(v8_str("trouble_callee")) :
4751    arg_this->Get(v8_str("trouble_caller"));
4752  CHECK(trouble_callee->IsFunction());
4753  return Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL);
4754}
4755
4756
4757static int report_count = 0;
4758static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
4759                                             v8::Handle<Value>) {
4760  report_count++;
4761}
4762
4763
4764// Counts uncaught exceptions, but other tests running in parallel
4765// also have uncaught exceptions.
4766TEST(ApiUncaughtException) {
4767  report_count = 0;
4768  v8::HandleScope scope;
4769  LocalContext env;
4770  v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
4771
4772  Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
4773  v8::Local<v8::Object> global = env->Global();
4774  global->Set(v8_str("trouble"), fun->GetFunction());
4775
4776  Script::Compile(v8_str("function trouble_callee() {"
4777                         "  var x = null;"
4778                         "  return x.foo;"
4779                         "};"
4780                         "function trouble_caller() {"
4781                         "  trouble();"
4782                         "};"))->Run();
4783  Local<Value> trouble = global->Get(v8_str("trouble"));
4784  CHECK(trouble->IsFunction());
4785  Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
4786  CHECK(trouble_callee->IsFunction());
4787  Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
4788  CHECK(trouble_caller->IsFunction());
4789  Function::Cast(*trouble_caller)->Call(global, 0, NULL);
4790  CHECK_EQ(1, report_count);
4791  v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
4792}
4793
4794static const char* script_resource_name = "ExceptionInNativeScript.js";
4795static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
4796                                                v8::Handle<Value>) {
4797  v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
4798  CHECK(!name_val.IsEmpty() && name_val->IsString());
4799  v8::String::AsciiValue name(message->GetScriptResourceName());
4800  CHECK_EQ(script_resource_name, *name);
4801  CHECK_EQ(3, message->GetLineNumber());
4802  v8::String::AsciiValue source_line(message->GetSourceLine());
4803  CHECK_EQ("  new o.foo();", *source_line);
4804}
4805
4806TEST(ExceptionInNativeScript) {
4807  v8::HandleScope scope;
4808  LocalContext env;
4809  v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
4810
4811  Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
4812  v8::Local<v8::Object> global = env->Global();
4813  global->Set(v8_str("trouble"), fun->GetFunction());
4814
4815  Script::Compile(v8_str("function trouble() {\n"
4816                         "  var o = {};\n"
4817                         "  new o.foo();\n"
4818                         "};"), v8::String::New(script_resource_name))->Run();
4819  Local<Value> trouble = global->Get(v8_str("trouble"));
4820  CHECK(trouble->IsFunction());
4821  Function::Cast(*trouble)->Call(global, 0, NULL);
4822  v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
4823}
4824
4825
4826TEST(CompilationErrorUsingTryCatchHandler) {
4827  v8::HandleScope scope;
4828  LocalContext env;
4829  v8::TryCatch try_catch;
4830  Script::Compile(v8_str("This doesn't &*&@#$&*^ compile."));
4831  CHECK_NE(NULL, *try_catch.Exception());
4832  CHECK(try_catch.HasCaught());
4833}
4834
4835
4836TEST(TryCatchFinallyUsingTryCatchHandler) {
4837  v8::HandleScope scope;
4838  LocalContext env;
4839  v8::TryCatch try_catch;
4840  Script::Compile(v8_str("try { throw ''; } catch (e) {}"))->Run();
4841  CHECK(!try_catch.HasCaught());
4842  Script::Compile(v8_str("try { throw ''; } finally {}"))->Run();
4843  CHECK(try_catch.HasCaught());
4844  try_catch.Reset();
4845  Script::Compile(v8_str("(function() {"
4846                         "try { throw ''; } finally { return; }"
4847                         "})()"))->Run();
4848  CHECK(!try_catch.HasCaught());
4849  Script::Compile(v8_str("(function()"
4850                         "  { try { throw ''; } finally { throw 0; }"
4851                         "})()"))->Run();
4852  CHECK(try_catch.HasCaught());
4853}
4854
4855
4856// SecurityHandler can't be run twice
4857TEST(SecurityHandler) {
4858  v8::HandleScope scope0;
4859  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
4860  global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
4861                                           IndexedSecurityTestCallback);
4862  // Create an environment
4863  v8::Persistent<Context> context0 =
4864    Context::New(NULL, global_template);
4865  context0->Enter();
4866
4867  v8::Handle<v8::Object> global0 = context0->Global();
4868  v8::Handle<Script> script0 = v8_compile("foo = 111");
4869  script0->Run();
4870  global0->Set(v8_str("0"), v8_num(999));
4871  v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
4872  CHECK_EQ(111, foo0->Int32Value());
4873  v8::Handle<Value> z0 = global0->Get(v8_str("0"));
4874  CHECK_EQ(999, z0->Int32Value());
4875
4876  // Create another environment, should fail security checks.
4877  v8::HandleScope scope1;
4878
4879  v8::Persistent<Context> context1 =
4880    Context::New(NULL, global_template);
4881  context1->Enter();
4882
4883  v8::Handle<v8::Object> global1 = context1->Global();
4884  global1->Set(v8_str("othercontext"), global0);
4885  // This set will fail the security check.
4886  v8::Handle<Script> script1 =
4887    v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
4888  script1->Run();
4889  // This read will pass the security check.
4890  v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
4891  CHECK_EQ(111, foo1->Int32Value());
4892  // This read will pass the security check.
4893  v8::Handle<Value> z1 = global0->Get(v8_str("0"));
4894  CHECK_EQ(999, z1->Int32Value());
4895
4896  // Create another environment, should pass security checks.
4897  { g_security_callback_result = true;  // allow security handler to pass.
4898    v8::HandleScope scope2;
4899    LocalContext context2;
4900    v8::Handle<v8::Object> global2 = context2->Global();
4901    global2->Set(v8_str("othercontext"), global0);
4902    v8::Handle<Script> script2 =
4903        v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
4904    script2->Run();
4905    v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
4906    CHECK_EQ(333, foo2->Int32Value());
4907    v8::Handle<Value> z2 = global0->Get(v8_str("0"));
4908    CHECK_EQ(888, z2->Int32Value());
4909  }
4910
4911  context1->Exit();
4912  context1.Dispose();
4913
4914  context0->Exit();
4915  context0.Dispose();
4916}
4917
4918
4919THREADED_TEST(SecurityChecks) {
4920  v8::HandleScope handle_scope;
4921  LocalContext env1;
4922  v8::Persistent<Context> env2 = Context::New();
4923
4924  Local<Value> foo = v8_str("foo");
4925  Local<Value> bar = v8_str("bar");
4926
4927  // Set to the same domain.
4928  env1->SetSecurityToken(foo);
4929
4930  // Create a function in env1.
4931  Script::Compile(v8_str("spy=function(){return spy;}"))->Run();
4932  Local<Value> spy = env1->Global()->Get(v8_str("spy"));
4933  CHECK(spy->IsFunction());
4934
4935  // Create another function accessing global objects.
4936  Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run();
4937  Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
4938  CHECK(spy2->IsFunction());
4939
4940  // Switch to env2 in the same domain and invoke spy on env2.
4941  {
4942    env2->SetSecurityToken(foo);
4943    // Enter env2
4944    Context::Scope scope_env2(env2);
4945    Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
4946    CHECK(result->IsFunction());
4947  }
4948
4949  {
4950    env2->SetSecurityToken(bar);
4951    Context::Scope scope_env2(env2);
4952
4953    // Call cross_domain_call, it should throw an exception
4954    v8::TryCatch try_catch;
4955    Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
4956    CHECK(try_catch.HasCaught());
4957  }
4958
4959  env2.Dispose();
4960}
4961
4962
4963// Regression test case for issue 1183439.
4964THREADED_TEST(SecurityChecksForPrototypeChain) {
4965  v8::HandleScope scope;
4966  LocalContext current;
4967  v8::Persistent<Context> other = Context::New();
4968
4969  // Change context to be able to get to the Object function in the
4970  // other context without hitting the security checks.
4971  v8::Local<Value> other_object;
4972  { Context::Scope scope(other);
4973    other_object = other->Global()->Get(v8_str("Object"));
4974    other->Global()->Set(v8_num(42), v8_num(87));
4975  }
4976
4977  current->Global()->Set(v8_str("other"), other->Global());
4978  CHECK(v8_compile("other")->Run()->Equals(other->Global()));
4979
4980  // Make sure the security check fails here and we get an undefined
4981  // result instead of getting the Object function. Repeat in a loop
4982  // to make sure to exercise the IC code.
4983  v8::Local<Script> access_other0 = v8_compile("other.Object");
4984  v8::Local<Script> access_other1 = v8_compile("other[42]");
4985  for (int i = 0; i < 5; i++) {
4986    CHECK(!access_other0->Run()->Equals(other_object));
4987    CHECK(access_other0->Run()->IsUndefined());
4988    CHECK(!access_other1->Run()->Equals(v8_num(87)));
4989    CHECK(access_other1->Run()->IsUndefined());
4990  }
4991
4992  // Create an object that has 'other' in its prototype chain and make
4993  // sure we cannot access the Object function indirectly through
4994  // that. Repeat in a loop to make sure to exercise the IC code.
4995  v8_compile("function F() { };"
4996             "F.prototype = other;"
4997             "var f = new F();")->Run();
4998  v8::Local<Script> access_f0 = v8_compile("f.Object");
4999  v8::Local<Script> access_f1 = v8_compile("f[42]");
5000  for (int j = 0; j < 5; j++) {
5001    CHECK(!access_f0->Run()->Equals(other_object));
5002    CHECK(access_f0->Run()->IsUndefined());
5003    CHECK(!access_f1->Run()->Equals(v8_num(87)));
5004    CHECK(access_f1->Run()->IsUndefined());
5005  }
5006
5007  // Now it gets hairy: Set the prototype for the other global object
5008  // to be the current global object. The prototype chain for 'f' now
5009  // goes through 'other' but ends up in the current global object.
5010  { Context::Scope scope(other);
5011    other->Global()->Set(v8_str("__proto__"), current->Global());
5012  }
5013  // Set a named and an index property on the current global
5014  // object. To force the lookup to go through the other global object,
5015  // the properties must not exist in the other global object.
5016  current->Global()->Set(v8_str("foo"), v8_num(100));
5017  current->Global()->Set(v8_num(99), v8_num(101));
5018  // Try to read the properties from f and make sure that the access
5019  // gets stopped by the security checks on the other global object.
5020  Local<Script> access_f2 = v8_compile("f.foo");
5021  Local<Script> access_f3 = v8_compile("f[99]");
5022  for (int k = 0; k < 5; k++) {
5023    CHECK(!access_f2->Run()->Equals(v8_num(100)));
5024    CHECK(access_f2->Run()->IsUndefined());
5025    CHECK(!access_f3->Run()->Equals(v8_num(101)));
5026    CHECK(access_f3->Run()->IsUndefined());
5027  }
5028  other.Dispose();
5029}
5030
5031
5032THREADED_TEST(CrossDomainDelete) {
5033  v8::HandleScope handle_scope;
5034  LocalContext env1;
5035  v8::Persistent<Context> env2 = Context::New();
5036
5037  Local<Value> foo = v8_str("foo");
5038  Local<Value> bar = v8_str("bar");
5039
5040  // Set to the same domain.
5041  env1->SetSecurityToken(foo);
5042  env2->SetSecurityToken(foo);
5043
5044  env1->Global()->Set(v8_str("prop"), v8_num(3));
5045  env2->Global()->Set(v8_str("env1"), env1->Global());
5046
5047  // Change env2 to a different domain and delete env1.prop.
5048  env2->SetSecurityToken(bar);
5049  {
5050    Context::Scope scope_env2(env2);
5051    Local<Value> result =
5052        Script::Compile(v8_str("delete env1.prop"))->Run();
5053    CHECK(result->IsFalse());
5054  }
5055
5056  // Check that env1.prop still exists.
5057  Local<Value> v = env1->Global()->Get(v8_str("prop"));
5058  CHECK(v->IsNumber());
5059  CHECK_EQ(3, v->Int32Value());
5060
5061  env2.Dispose();
5062}
5063
5064
5065THREADED_TEST(CrossDomainIsPropertyEnumerable) {
5066  v8::HandleScope handle_scope;
5067  LocalContext env1;
5068  v8::Persistent<Context> env2 = Context::New();
5069
5070  Local<Value> foo = v8_str("foo");
5071  Local<Value> bar = v8_str("bar");
5072
5073  // Set to the same domain.
5074  env1->SetSecurityToken(foo);
5075  env2->SetSecurityToken(foo);
5076
5077  env1->Global()->Set(v8_str("prop"), v8_num(3));
5078  env2->Global()->Set(v8_str("env1"), env1->Global());
5079
5080  // env1.prop is enumerable in env2.
5081  Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
5082  {
5083    Context::Scope scope_env2(env2);
5084    Local<Value> result = Script::Compile(test)->Run();
5085    CHECK(result->IsTrue());
5086  }
5087
5088  // Change env2 to a different domain and test again.
5089  env2->SetSecurityToken(bar);
5090  {
5091    Context::Scope scope_env2(env2);
5092    Local<Value> result = Script::Compile(test)->Run();
5093    CHECK(result->IsFalse());
5094  }
5095
5096  env2.Dispose();
5097}
5098
5099
5100THREADED_TEST(CrossDomainForIn) {
5101  v8::HandleScope handle_scope;
5102  LocalContext env1;
5103  v8::Persistent<Context> env2 = Context::New();
5104
5105  Local<Value> foo = v8_str("foo");
5106  Local<Value> bar = v8_str("bar");
5107
5108  // Set to the same domain.
5109  env1->SetSecurityToken(foo);
5110  env2->SetSecurityToken(foo);
5111
5112  env1->Global()->Set(v8_str("prop"), v8_num(3));
5113  env2->Global()->Set(v8_str("env1"), env1->Global());
5114
5115  // Change env2 to a different domain and set env1's global object
5116  // as the __proto__ of an object in env2 and enumerate properties
5117  // in for-in. It shouldn't enumerate properties on env1's global
5118  // object.
5119  env2->SetSecurityToken(bar);
5120  {
5121    Context::Scope scope_env2(env2);
5122    Local<Value> result =
5123        CompileRun("(function(){var obj = {'__proto__':env1};"
5124                   "for (var p in obj)"
5125                   "   if (p == 'prop') return false;"
5126                   "return true;})()");
5127    CHECK(result->IsTrue());
5128  }
5129  env2.Dispose();
5130}
5131
5132
5133TEST(ContextDetachGlobal) {
5134  v8::HandleScope handle_scope;
5135  LocalContext env1;
5136  v8::Persistent<Context> env2 = Context::New();
5137
5138  Local<v8::Object> global1 = env1->Global();
5139
5140  Local<Value> foo = v8_str("foo");
5141
5142  // Set to the same domain.
5143  env1->SetSecurityToken(foo);
5144  env2->SetSecurityToken(foo);
5145
5146  // Enter env2
5147  env2->Enter();
5148
5149  // Create a function in env2 and add a reference to it in env1.
5150  Local<v8::Object> global2 = env2->Global();
5151  global2->Set(v8_str("prop"), v8::Integer::New(1));
5152  CompileRun("function getProp() {return prop;}");
5153
5154  env1->Global()->Set(v8_str("getProp"),
5155                      global2->Get(v8_str("getProp")));
5156
5157  // Detach env2's global, and reuse the global object of env2
5158  env2->Exit();
5159  env2->DetachGlobal();
5160  // env2 has a new global object.
5161  CHECK(!env2->Global()->Equals(global2));
5162
5163  v8::Persistent<Context> env3 =
5164      Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
5165  env3->SetSecurityToken(v8_str("bar"));
5166  env3->Enter();
5167
5168  Local<v8::Object> global3 = env3->Global();
5169  CHECK_EQ(global2, global3);
5170  CHECK(global3->Get(v8_str("prop"))->IsUndefined());
5171  CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
5172  global3->Set(v8_str("prop"), v8::Integer::New(-1));
5173  global3->Set(v8_str("prop2"), v8::Integer::New(2));
5174  env3->Exit();
5175
5176  // Call getProp in env1, and it should return the value 1
5177  {
5178    Local<Value> get_prop = global1->Get(v8_str("getProp"));
5179    CHECK(get_prop->IsFunction());
5180    v8::TryCatch try_catch;
5181    Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
5182    CHECK(!try_catch.HasCaught());
5183    CHECK_EQ(1, r->Int32Value());
5184  }
5185
5186  // Check that env3 is not accessible from env1
5187  {
5188    Local<Value> r = global3->Get(v8_str("prop2"));
5189    CHECK(r->IsUndefined());
5190  }
5191
5192  env2.Dispose();
5193  env3.Dispose();
5194}
5195
5196
5197TEST(DetachAndReattachGlobal) {
5198  v8::HandleScope scope;
5199  LocalContext env1;
5200
5201  // Create second environment.
5202  v8::Persistent<Context> env2 = Context::New();
5203
5204  Local<Value> foo = v8_str("foo");
5205
5206  // Set same security token for env1 and env2.
5207  env1->SetSecurityToken(foo);
5208  env2->SetSecurityToken(foo);
5209
5210  // Create a property on the global object in env2.
5211  {
5212    v8::Context::Scope scope(env2);
5213    env2->Global()->Set(v8_str("p"), v8::Integer::New(42));
5214  }
5215
5216  // Create a reference to env2 global from env1 global.
5217  env1->Global()->Set(v8_str("other"), env2->Global());
5218
5219  // Check that we have access to other.p in env2 from env1.
5220  Local<Value> result = CompileRun("other.p");
5221  CHECK(result->IsInt32());
5222  CHECK_EQ(42, result->Int32Value());
5223
5224  // Hold on to global from env2 and detach global from env2.
5225  Local<v8::Object> global2 = env2->Global();
5226  env2->DetachGlobal();
5227
5228  // Check that the global has been detached. No other.p property can
5229  // be found.
5230  result = CompileRun("other.p");
5231  CHECK(result->IsUndefined());
5232
5233  // Reuse global2 for env3.
5234  v8::Persistent<Context> env3 =
5235      Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
5236  CHECK_EQ(global2, env3->Global());
5237
5238  // Start by using the same security token for env3 as for env1 and env2.
5239  env3->SetSecurityToken(foo);
5240
5241  // Create a property on the global object in env3.
5242  {
5243    v8::Context::Scope scope(env3);
5244    env3->Global()->Set(v8_str("p"), v8::Integer::New(24));
5245  }
5246
5247  // Check that other.p is now the property in env3 and that we have access.
5248  result = CompileRun("other.p");
5249  CHECK(result->IsInt32());
5250  CHECK_EQ(24, result->Int32Value());
5251
5252  // Change security token for env3 to something different from env1 and env2.
5253  env3->SetSecurityToken(v8_str("bar"));
5254
5255  // Check that we do not have access to other.p in env1. |other| is now
5256  // the global object for env3 which has a different security token,
5257  // so access should be blocked.
5258  result = CompileRun("other.p");
5259  CHECK(result->IsUndefined());
5260
5261  // Detach the global for env3 and reattach it to env2.
5262  env3->DetachGlobal();
5263  env2->ReattachGlobal(global2);
5264
5265  // Check that we have access to other.p again in env1.  |other| is now
5266  // the global object for env2 which has the same security token as env1.
5267  result = CompileRun("other.p");
5268  CHECK(result->IsInt32());
5269  CHECK_EQ(42, result->Int32Value());
5270
5271  env2.Dispose();
5272  env3.Dispose();
5273}
5274
5275
5276static bool NamedAccessBlocker(Local<v8::Object> global,
5277                               Local<Value> name,
5278                               v8::AccessType type,
5279                               Local<Value> data) {
5280  return Context::GetCurrent()->Global()->Equals(global);
5281}
5282
5283
5284static bool IndexedAccessBlocker(Local<v8::Object> global,
5285                                 uint32_t key,
5286                                 v8::AccessType type,
5287                                 Local<Value> data) {
5288  return Context::GetCurrent()->Global()->Equals(global);
5289}
5290
5291
5292static int g_echo_value = -1;
5293static v8::Handle<Value> EchoGetter(Local<String> name,
5294                                    const AccessorInfo& info) {
5295  return v8_num(g_echo_value);
5296}
5297
5298
5299static void EchoSetter(Local<String> name,
5300                       Local<Value> value,
5301                       const AccessorInfo&) {
5302  if (value->IsNumber())
5303    g_echo_value = value->Int32Value();
5304}
5305
5306
5307static v8::Handle<Value> UnreachableGetter(Local<String> name,
5308                                           const AccessorInfo& info) {
5309  CHECK(false);  // This function should not be called..
5310  return v8::Undefined();
5311}
5312
5313
5314static void UnreachableSetter(Local<String>, Local<Value>,
5315                              const AccessorInfo&) {
5316  CHECK(false);  // This function should nto be called.
5317}
5318
5319
5320THREADED_TEST(AccessControl) {
5321  v8::HandleScope handle_scope;
5322  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
5323
5324  global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
5325                                           IndexedAccessBlocker);
5326
5327  // Add an accessor accessible by cross-domain JS code.
5328  global_template->SetAccessor(
5329      v8_str("accessible_prop"),
5330      EchoGetter, EchoSetter,
5331      v8::Handle<Value>(),
5332      v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
5333
5334  // Add an accessor that is not accessible by cross-domain JS code.
5335  global_template->SetAccessor(v8_str("blocked_prop"),
5336                               UnreachableGetter, UnreachableSetter,
5337                               v8::Handle<Value>(),
5338                               v8::DEFAULT);
5339
5340  // Create an environment
5341  v8::Persistent<Context> context0 = Context::New(NULL, global_template);
5342  context0->Enter();
5343
5344  v8::Handle<v8::Object> global0 = context0->Global();
5345
5346  v8::HandleScope scope1;
5347
5348  v8::Persistent<Context> context1 = Context::New();
5349  context1->Enter();
5350
5351  v8::Handle<v8::Object> global1 = context1->Global();
5352  global1->Set(v8_str("other"), global0);
5353
5354  v8::Handle<Value> value;
5355
5356  // Access blocked property
5357  value = v8_compile("other.blocked_prop = 1")->Run();
5358  value = v8_compile("other.blocked_prop")->Run();
5359  CHECK(value->IsUndefined());
5360
5361  value = v8_compile("propertyIsEnumerable.call(other, 'blocked_prop')")->Run();
5362  CHECK(value->IsFalse());
5363
5364  // Access accessible property
5365  value = v8_compile("other.accessible_prop = 3")->Run();
5366  CHECK(value->IsNumber());
5367  CHECK_EQ(3, value->Int32Value());
5368  CHECK_EQ(3, g_echo_value);
5369
5370  value = v8_compile("other.accessible_prop")->Run();
5371  CHECK(value->IsNumber());
5372  CHECK_EQ(3, value->Int32Value());
5373
5374  value =
5375    v8_compile("propertyIsEnumerable.call(other, 'accessible_prop')")->Run();
5376  CHECK(value->IsTrue());
5377
5378  // Enumeration doesn't enumerate accessors from inaccessible objects in
5379  // the prototype chain even if the accessors are in themselves accessible.
5380  Local<Value> result =
5381      CompileRun("(function(){var obj = {'__proto__':other};"
5382                 "for (var p in obj)"
5383                 "   if (p == 'accessible_prop' || p == 'blocked_prop') {"
5384                 "     return false;"
5385                 "   }"
5386                 "return true;})()");
5387  CHECK(result->IsTrue());
5388
5389  context1->Exit();
5390  context0->Exit();
5391  context1.Dispose();
5392  context0.Dispose();
5393}
5394
5395
5396static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
5397                                            Local<Value> name,
5398                                            v8::AccessType type,
5399                                            Local<Value> data) {
5400  return false;
5401}
5402
5403
5404static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
5405                                              uint32_t key,
5406                                              v8::AccessType type,
5407                                              Local<Value> data) {
5408  return false;
5409}
5410
5411
5412THREADED_TEST(AccessControlGetOwnPropertyNames) {
5413  v8::HandleScope handle_scope;
5414  v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
5415
5416  obj_template->Set(v8_str("x"), v8::Integer::New(42));
5417  obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
5418                                        GetOwnPropertyNamesIndexedBlocker);
5419
5420  // Create an environment
5421  v8::Persistent<Context> context0 = Context::New(NULL, obj_template);
5422  context0->Enter();
5423
5424  v8::Handle<v8::Object> global0 = context0->Global();
5425
5426  v8::HandleScope scope1;
5427
5428  v8::Persistent<Context> context1 = Context::New();
5429  context1->Enter();
5430
5431  v8::Handle<v8::Object> global1 = context1->Global();
5432  global1->Set(v8_str("other"), global0);
5433  global1->Set(v8_str("object"), obj_template->NewInstance());
5434
5435  v8::Handle<Value> value;
5436
5437  // Attempt to get the property names of the other global object and
5438  // of an object that requires access checks.  Accessing the other
5439  // global object should be blocked by access checks on the global
5440  // proxy object.  Accessing the object that requires access checks
5441  // is blocked by the access checks on the object itself.
5442  value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
5443  CHECK(value->IsTrue());
5444
5445  value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
5446  CHECK(value->IsTrue());
5447
5448  context1->Exit();
5449  context0->Exit();
5450  context1.Dispose();
5451  context0.Dispose();
5452}
5453
5454
5455static v8::Handle<v8::Array> NamedPropertyEnumerator(const AccessorInfo& info) {
5456  v8::Handle<v8::Array> result = v8::Array::New(1);
5457  result->Set(0, v8_str("x"));
5458  return result;
5459}
5460
5461
5462THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
5463  v8::HandleScope handle_scope;
5464  v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
5465
5466  obj_template->Set(v8_str("x"), v8::Integer::New(42));
5467  obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
5468                                        NamedPropertyEnumerator);
5469
5470  LocalContext context;
5471  v8::Handle<v8::Object> global = context->Global();
5472  global->Set(v8_str("object"), obj_template->NewInstance());
5473
5474  v8::Handle<Value> value =
5475      CompileRun("Object.getOwnPropertyNames(object).join(',')");
5476  CHECK_EQ(v8_str("x"), value);
5477}
5478
5479
5480static v8::Handle<Value> ConstTenGetter(Local<String> name,
5481                                        const AccessorInfo& info) {
5482  return v8_num(10);
5483}
5484
5485
5486THREADED_TEST(CrossDomainAccessors) {
5487  v8::HandleScope handle_scope;
5488
5489  v8::Handle<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
5490
5491  v8::Handle<v8::ObjectTemplate> global_template =
5492      func_template->InstanceTemplate();
5493
5494  v8::Handle<v8::ObjectTemplate> proto_template =
5495      func_template->PrototypeTemplate();
5496
5497  // Add an accessor to proto that's accessible by cross-domain JS code.
5498  proto_template->SetAccessor(v8_str("accessible"),
5499                              ConstTenGetter, 0,
5500                              v8::Handle<Value>(),
5501                              v8::ALL_CAN_READ);
5502
5503  // Add an accessor that is not accessible by cross-domain JS code.
5504  global_template->SetAccessor(v8_str("unreachable"),
5505                               UnreachableGetter, 0,
5506                               v8::Handle<Value>(),
5507                               v8::DEFAULT);
5508
5509  v8::Persistent<Context> context0 = Context::New(NULL, global_template);
5510  context0->Enter();
5511
5512  Local<v8::Object> global = context0->Global();
5513  // Add a normal property that shadows 'accessible'
5514  global->Set(v8_str("accessible"), v8_num(11));
5515
5516  // Enter a new context.
5517  v8::HandleScope scope1;
5518  v8::Persistent<Context> context1 = Context::New();
5519  context1->Enter();
5520
5521  v8::Handle<v8::Object> global1 = context1->Global();
5522  global1->Set(v8_str("other"), global);
5523
5524  // Should return 10, instead of 11
5525  v8::Handle<Value> value = v8_compile("other.accessible")->Run();
5526  CHECK(value->IsNumber());
5527  CHECK_EQ(10, value->Int32Value());
5528
5529  value = v8_compile("other.unreachable")->Run();
5530  CHECK(value->IsUndefined());
5531
5532  context1->Exit();
5533  context0->Exit();
5534  context1.Dispose();
5535  context0.Dispose();
5536}
5537
5538
5539static int named_access_count = 0;
5540static int indexed_access_count = 0;
5541
5542static bool NamedAccessCounter(Local<v8::Object> global,
5543                               Local<Value> name,
5544                               v8::AccessType type,
5545                               Local<Value> data) {
5546  named_access_count++;
5547  return true;
5548}
5549
5550
5551static bool IndexedAccessCounter(Local<v8::Object> global,
5552                                 uint32_t key,
5553                                 v8::AccessType type,
5554                                 Local<Value> data) {
5555  indexed_access_count++;
5556  return true;
5557}
5558
5559
5560// This one is too easily disturbed by other tests.
5561TEST(AccessControlIC) {
5562  named_access_count = 0;
5563  indexed_access_count = 0;
5564
5565  v8::HandleScope handle_scope;
5566
5567  // Create an environment.
5568  v8::Persistent<Context> context0 = Context::New();
5569  context0->Enter();
5570
5571  // Create an object that requires access-check functions to be
5572  // called for cross-domain access.
5573  v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
5574  object_template->SetAccessCheckCallbacks(NamedAccessCounter,
5575                                           IndexedAccessCounter);
5576  Local<v8::Object> object = object_template->NewInstance();
5577
5578  v8::HandleScope scope1;
5579
5580  // Create another environment.
5581  v8::Persistent<Context> context1 = Context::New();
5582  context1->Enter();
5583
5584  // Make easy access to the object from the other environment.
5585  v8::Handle<v8::Object> global1 = context1->Global();
5586  global1->Set(v8_str("obj"), object);
5587
5588  v8::Handle<Value> value;
5589
5590  // Check that the named access-control function is called every time.
5591  CompileRun("function testProp(obj) {"
5592             "  for (var i = 0; i < 10; i++) obj.prop = 1;"
5593             "  for (var j = 0; j < 10; j++) obj.prop;"
5594             "  return obj.prop"
5595             "}");
5596  value = CompileRun("testProp(obj)");
5597  CHECK(value->IsNumber());
5598  CHECK_EQ(1, value->Int32Value());
5599  CHECK_EQ(21, named_access_count);
5600
5601  // Check that the named access-control function is called every time.
5602  CompileRun("var p = 'prop';"
5603             "function testKeyed(obj) {"
5604             "  for (var i = 0; i < 10; i++) obj[p] = 1;"
5605             "  for (var j = 0; j < 10; j++) obj[p];"
5606             "  return obj[p];"
5607             "}");
5608  // Use obj which requires access checks.  No inline caching is used
5609  // in that case.
5610  value = CompileRun("testKeyed(obj)");
5611  CHECK(value->IsNumber());
5612  CHECK_EQ(1, value->Int32Value());
5613  CHECK_EQ(42, named_access_count);
5614  // Force the inline caches into generic state and try again.
5615  CompileRun("testKeyed({ a: 0 })");
5616  CompileRun("testKeyed({ b: 0 })");
5617  value = CompileRun("testKeyed(obj)");
5618  CHECK(value->IsNumber());
5619  CHECK_EQ(1, value->Int32Value());
5620  CHECK_EQ(63, named_access_count);
5621
5622  // Check that the indexed access-control function is called every time.
5623  CompileRun("function testIndexed(obj) {"
5624             "  for (var i = 0; i < 10; i++) obj[0] = 1;"
5625             "  for (var j = 0; j < 10; j++) obj[0];"
5626             "  return obj[0]"
5627             "}");
5628  value = CompileRun("testIndexed(obj)");
5629  CHECK(value->IsNumber());
5630  CHECK_EQ(1, value->Int32Value());
5631  CHECK_EQ(21, indexed_access_count);
5632  // Force the inline caches into generic state.
5633  CompileRun("testIndexed(new Array(1))");
5634  // Test that the indexed access check is called.
5635  value = CompileRun("testIndexed(obj)");
5636  CHECK(value->IsNumber());
5637  CHECK_EQ(1, value->Int32Value());
5638  CHECK_EQ(42, indexed_access_count);
5639
5640  // Check that the named access check is called when invoking
5641  // functions on an object that requires access checks.
5642  CompileRun("obj.f = function() {}");
5643  CompileRun("function testCallNormal(obj) {"
5644             "  for (var i = 0; i < 10; i++) obj.f();"
5645             "}");
5646  CompileRun("testCallNormal(obj)");
5647  CHECK_EQ(74, named_access_count);
5648
5649  // Force obj into slow case.
5650  value = CompileRun("delete obj.prop");
5651  CHECK(value->BooleanValue());
5652  // Force inline caches into dictionary probing mode.
5653  CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
5654  // Test that the named access check is called.
5655  value = CompileRun("testProp(obj);");
5656  CHECK(value->IsNumber());
5657  CHECK_EQ(1, value->Int32Value());
5658  CHECK_EQ(96, named_access_count);
5659
5660  // Force the call inline cache into dictionary probing mode.
5661  CompileRun("o.f = function() {}; testCallNormal(o)");
5662  // Test that the named access check is still called for each
5663  // invocation of the function.
5664  value = CompileRun("testCallNormal(obj)");
5665  CHECK_EQ(106, named_access_count);
5666
5667  context1->Exit();
5668  context0->Exit();
5669  context1.Dispose();
5670  context0.Dispose();
5671}
5672
5673
5674static bool NamedAccessFlatten(Local<v8::Object> global,
5675                               Local<Value> name,
5676                               v8::AccessType type,
5677                               Local<Value> data) {
5678  char buf[100];
5679  int len;
5680
5681  CHECK(name->IsString());
5682
5683  memset(buf, 0x1, sizeof(buf));
5684  len = name.As<String>()->WriteAscii(buf);
5685  CHECK_EQ(4, len);
5686
5687  uint16_t buf2[100];
5688
5689  memset(buf, 0x1, sizeof(buf));
5690  len = name.As<String>()->Write(buf2);
5691  CHECK_EQ(4, len);
5692
5693  return true;
5694}
5695
5696
5697static bool IndexedAccessFlatten(Local<v8::Object> global,
5698                                 uint32_t key,
5699                                 v8::AccessType type,
5700                                 Local<Value> data) {
5701  return true;
5702}
5703
5704
5705// Regression test.  In access checks, operations that may cause
5706// garbage collection are not allowed.  It used to be the case that
5707// using the Write operation on a string could cause a garbage
5708// collection due to flattening of the string.  This is no longer the
5709// case.
5710THREADED_TEST(AccessControlFlatten) {
5711  named_access_count = 0;
5712  indexed_access_count = 0;
5713
5714  v8::HandleScope handle_scope;
5715
5716  // Create an environment.
5717  v8::Persistent<Context> context0 = Context::New();
5718  context0->Enter();
5719
5720  // Create an object that requires access-check functions to be
5721  // called for cross-domain access.
5722  v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
5723  object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
5724                                           IndexedAccessFlatten);
5725  Local<v8::Object> object = object_template->NewInstance();
5726
5727  v8::HandleScope scope1;
5728
5729  // Create another environment.
5730  v8::Persistent<Context> context1 = Context::New();
5731  context1->Enter();
5732
5733  // Make easy access to the object from the other environment.
5734  v8::Handle<v8::Object> global1 = context1->Global();
5735  global1->Set(v8_str("obj"), object);
5736
5737  v8::Handle<Value> value;
5738
5739  value = v8_compile("var p = 'as' + 'df';")->Run();
5740  value = v8_compile("obj[p];")->Run();
5741
5742  context1->Exit();
5743  context0->Exit();
5744  context1.Dispose();
5745  context0.Dispose();
5746}
5747
5748
5749static v8::Handle<Value> AccessControlNamedGetter(
5750    Local<String>, const AccessorInfo&) {
5751  return v8::Integer::New(42);
5752}
5753
5754
5755static v8::Handle<Value> AccessControlNamedSetter(
5756    Local<String>, Local<Value> value, const AccessorInfo&) {
5757  return value;
5758}
5759
5760
5761static v8::Handle<Value> AccessControlIndexedGetter(
5762      uint32_t index,
5763      const AccessorInfo& info) {
5764  return v8_num(42);
5765}
5766
5767
5768static v8::Handle<Value> AccessControlIndexedSetter(
5769    uint32_t, Local<Value> value, const AccessorInfo&) {
5770  return value;
5771}
5772
5773
5774THREADED_TEST(AccessControlInterceptorIC) {
5775  named_access_count = 0;
5776  indexed_access_count = 0;
5777
5778  v8::HandleScope handle_scope;
5779
5780  // Create an environment.
5781  v8::Persistent<Context> context0 = Context::New();
5782  context0->Enter();
5783
5784  // Create an object that requires access-check functions to be
5785  // called for cross-domain access.  The object also has interceptors
5786  // interceptor.
5787  v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
5788  object_template->SetAccessCheckCallbacks(NamedAccessCounter,
5789                                           IndexedAccessCounter);
5790  object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
5791                                           AccessControlNamedSetter);
5792  object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
5793                                             AccessControlIndexedSetter);
5794  Local<v8::Object> object = object_template->NewInstance();
5795
5796  v8::HandleScope scope1;
5797
5798  // Create another environment.
5799  v8::Persistent<Context> context1 = Context::New();
5800  context1->Enter();
5801
5802  // Make easy access to the object from the other environment.
5803  v8::Handle<v8::Object> global1 = context1->Global();
5804  global1->Set(v8_str("obj"), object);
5805
5806  v8::Handle<Value> value;
5807
5808  // Check that the named access-control function is called every time
5809  // eventhough there is an interceptor on the object.
5810  value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
5811  value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
5812                     "obj.x")->Run();
5813  CHECK(value->IsNumber());
5814  CHECK_EQ(42, value->Int32Value());
5815  CHECK_EQ(21, named_access_count);
5816
5817  value = v8_compile("var p = 'x';")->Run();
5818  value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
5819  value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
5820                     "obj[p]")->Run();
5821  CHECK(value->IsNumber());
5822  CHECK_EQ(42, value->Int32Value());
5823  CHECK_EQ(42, named_access_count);
5824
5825  // Check that the indexed access-control function is called every
5826  // time eventhough there is an interceptor on the object.
5827  value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
5828  value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
5829                     "obj[0]")->Run();
5830  CHECK(value->IsNumber());
5831  CHECK_EQ(42, value->Int32Value());
5832  CHECK_EQ(21, indexed_access_count);
5833
5834  context1->Exit();
5835  context0->Exit();
5836  context1.Dispose();
5837  context0.Dispose();
5838}
5839
5840
5841THREADED_TEST(Version) {
5842  v8::V8::GetVersion();
5843}
5844
5845
5846static v8::Handle<Value> InstanceFunctionCallback(const v8::Arguments& args) {
5847  ApiTestFuzzer::Fuzz();
5848  return v8_num(12);
5849}
5850
5851
5852THREADED_TEST(InstanceProperties) {
5853  v8::HandleScope handle_scope;
5854  LocalContext context;
5855
5856  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
5857  Local<ObjectTemplate> instance = t->InstanceTemplate();
5858
5859  instance->Set(v8_str("x"), v8_num(42));
5860  instance->Set(v8_str("f"),
5861                v8::FunctionTemplate::New(InstanceFunctionCallback));
5862
5863  Local<Value> o = t->GetFunction()->NewInstance();
5864
5865  context->Global()->Set(v8_str("i"), o);
5866  Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
5867  CHECK_EQ(42, value->Int32Value());
5868
5869  value = Script::Compile(v8_str("i.f()"))->Run();
5870  CHECK_EQ(12, value->Int32Value());
5871}
5872
5873
5874static v8::Handle<Value>
5875GlobalObjectInstancePropertiesGet(Local<String> key, const AccessorInfo&) {
5876  ApiTestFuzzer::Fuzz();
5877  return v8::Handle<Value>();
5878}
5879
5880
5881THREADED_TEST(GlobalObjectInstanceProperties) {
5882  v8::HandleScope handle_scope;
5883
5884  Local<Value> global_object;
5885
5886  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
5887  t->InstanceTemplate()->SetNamedPropertyHandler(
5888      GlobalObjectInstancePropertiesGet);
5889  Local<ObjectTemplate> instance_template = t->InstanceTemplate();
5890  instance_template->Set(v8_str("x"), v8_num(42));
5891  instance_template->Set(v8_str("f"),
5892                         v8::FunctionTemplate::New(InstanceFunctionCallback));
5893
5894  // The script to check how Crankshaft compiles missing global function
5895  // invocations.  function g is not defined and should throw on call.
5896  const char* script =
5897      "function wrapper(call) {"
5898      "  var x = 0, y = 1;"
5899      "  for (var i = 0; i < 1000; i++) {"
5900      "    x += i * 100;"
5901      "    y += i * 100;"
5902      "  }"
5903      "  if (call) g();"
5904      "}"
5905      "for (var i = 0; i < 17; i++) wrapper(false);"
5906      "var thrown = 0;"
5907      "try { wrapper(true); } catch (e) { thrown = 1; };"
5908      "thrown";
5909
5910  {
5911    LocalContext env(NULL, instance_template);
5912    // Hold on to the global object so it can be used again in another
5913    // environment initialization.
5914    global_object = env->Global();
5915
5916    Local<Value> value = Script::Compile(v8_str("x"))->Run();
5917    CHECK_EQ(42, value->Int32Value());
5918    value = Script::Compile(v8_str("f()"))->Run();
5919    CHECK_EQ(12, value->Int32Value());
5920    value = Script::Compile(v8_str(script))->Run();
5921    CHECK_EQ(1, value->Int32Value());
5922  }
5923
5924  {
5925    // Create new environment reusing the global object.
5926    LocalContext env(NULL, instance_template, global_object);
5927    Local<Value> value = Script::Compile(v8_str("x"))->Run();
5928    CHECK_EQ(42, value->Int32Value());
5929    value = Script::Compile(v8_str("f()"))->Run();
5930    CHECK_EQ(12, value->Int32Value());
5931    value = Script::Compile(v8_str(script))->Run();
5932    CHECK_EQ(1, value->Int32Value());
5933  }
5934}
5935
5936
5937THREADED_TEST(CallKnownGlobalReceiver) {
5938  v8::HandleScope handle_scope;
5939
5940  Local<Value> global_object;
5941
5942  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
5943  Local<ObjectTemplate> instance_template = t->InstanceTemplate();
5944
5945  // The script to check that we leave global object not
5946  // global object proxy on stack when we deoptimize from inside
5947  // arguments evaluation.
5948  // To provoke error we need to both force deoptimization
5949  // from arguments evaluation and to force CallIC to take
5950  // CallIC_Miss code path that can't cope with global proxy.
5951  const char* script =
5952      "function bar(x, y) { try { } finally { } }"
5953      "function baz(x) { try { } finally { } }"
5954      "function bom(x) { try { } finally { } }"
5955      "function foo(x) { bar([x], bom(2)); }"
5956      "for (var i = 0; i < 10000; i++) foo(1);"
5957      "foo";
5958
5959  Local<Value> foo;
5960  {
5961    LocalContext env(NULL, instance_template);
5962    // Hold on to the global object so it can be used again in another
5963    // environment initialization.
5964    global_object = env->Global();
5965    foo = Script::Compile(v8_str(script))->Run();
5966  }
5967
5968  {
5969    // Create new environment reusing the global object.
5970    LocalContext env(NULL, instance_template, global_object);
5971    env->Global()->Set(v8_str("foo"), foo);
5972    Local<Value> value = Script::Compile(v8_str("foo()"))->Run();
5973  }
5974}
5975
5976
5977static v8::Handle<Value> ShadowFunctionCallback(const v8::Arguments& args) {
5978  ApiTestFuzzer::Fuzz();
5979  return v8_num(42);
5980}
5981
5982
5983static int shadow_y;
5984static int shadow_y_setter_call_count;
5985static int shadow_y_getter_call_count;
5986
5987
5988static void ShadowYSetter(Local<String>, Local<Value>, const AccessorInfo&) {
5989  shadow_y_setter_call_count++;
5990  shadow_y = 42;
5991}
5992
5993
5994static v8::Handle<Value> ShadowYGetter(Local<String> name,
5995                                       const AccessorInfo& info) {
5996  ApiTestFuzzer::Fuzz();
5997  shadow_y_getter_call_count++;
5998  return v8_num(shadow_y);
5999}
6000
6001
6002static v8::Handle<Value> ShadowIndexedGet(uint32_t index,
6003                                          const AccessorInfo& info) {
6004  return v8::Handle<Value>();
6005}
6006
6007
6008static v8::Handle<Value> ShadowNamedGet(Local<String> key,
6009                                        const AccessorInfo&) {
6010  return v8::Handle<Value>();
6011}
6012
6013
6014THREADED_TEST(ShadowObject) {
6015  shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
6016  v8::HandleScope handle_scope;
6017
6018  Local<ObjectTemplate> global_template = v8::ObjectTemplate::New();
6019  LocalContext context(NULL, global_template);
6020
6021  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6022  t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
6023  t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
6024  Local<ObjectTemplate> proto = t->PrototypeTemplate();
6025  Local<ObjectTemplate> instance = t->InstanceTemplate();
6026
6027  // Only allow calls of f on instances of t.
6028  Local<v8::Signature> signature = v8::Signature::New(t);
6029  proto->Set(v8_str("f"),
6030             v8::FunctionTemplate::New(ShadowFunctionCallback,
6031                                       Local<Value>(),
6032                                       signature));
6033  proto->Set(v8_str("x"), v8_num(12));
6034
6035  instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
6036
6037  Local<Value> o = t->GetFunction()->NewInstance();
6038  context->Global()->Set(v8_str("__proto__"), o);
6039
6040  Local<Value> value =
6041      Script::Compile(v8_str("propertyIsEnumerable(0)"))->Run();
6042  CHECK(value->IsBoolean());
6043  CHECK(!value->BooleanValue());
6044
6045  value = Script::Compile(v8_str("x"))->Run();
6046  CHECK_EQ(12, value->Int32Value());
6047
6048  value = Script::Compile(v8_str("f()"))->Run();
6049  CHECK_EQ(42, value->Int32Value());
6050
6051  Script::Compile(v8_str("y = 42"))->Run();
6052  CHECK_EQ(1, shadow_y_setter_call_count);
6053  value = Script::Compile(v8_str("y"))->Run();
6054  CHECK_EQ(1, shadow_y_getter_call_count);
6055  CHECK_EQ(42, value->Int32Value());
6056}
6057
6058
6059THREADED_TEST(HiddenPrototype) {
6060  v8::HandleScope handle_scope;
6061  LocalContext context;
6062
6063  Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
6064  t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
6065  Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
6066  t1->SetHiddenPrototype(true);
6067  t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
6068  Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
6069  t2->SetHiddenPrototype(true);
6070  t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
6071  Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
6072  t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
6073
6074  Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
6075  Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
6076  Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
6077  Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
6078
6079  // Setting the prototype on an object skips hidden prototypes.
6080  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6081  o0->Set(v8_str("__proto__"), o1);
6082  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6083  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6084  o0->Set(v8_str("__proto__"), o2);
6085  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6086  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6087  CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
6088  o0->Set(v8_str("__proto__"), o3);
6089  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6090  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6091  CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
6092  CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
6093
6094  // Getting the prototype of o0 should get the first visible one
6095  // which is o3.  Therefore, z should not be defined on the prototype
6096  // object.
6097  Local<Value> proto = o0->Get(v8_str("__proto__"));
6098  CHECK(proto->IsObject());
6099  CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
6100}
6101
6102
6103THREADED_TEST(SetPrototype) {
6104  v8::HandleScope handle_scope;
6105  LocalContext context;
6106
6107  Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
6108  t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
6109  Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
6110  t1->SetHiddenPrototype(true);
6111  t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
6112  Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
6113  t2->SetHiddenPrototype(true);
6114  t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
6115  Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
6116  t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
6117
6118  Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
6119  Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
6120  Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
6121  Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
6122
6123  // Setting the prototype on an object does not skip hidden prototypes.
6124  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6125  CHECK(o0->SetPrototype(o1));
6126  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6127  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6128  CHECK(o1->SetPrototype(o2));
6129  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6130  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6131  CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
6132  CHECK(o2->SetPrototype(o3));
6133  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6134  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6135  CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
6136  CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
6137
6138  // Getting the prototype of o0 should get the first visible one
6139  // which is o3.  Therefore, z should not be defined on the prototype
6140  // object.
6141  Local<Value> proto = o0->Get(v8_str("__proto__"));
6142  CHECK(proto->IsObject());
6143  CHECK_EQ(proto.As<v8::Object>(), o3);
6144
6145  // However, Object::GetPrototype ignores hidden prototype.
6146  Local<Value> proto0 = o0->GetPrototype();
6147  CHECK(proto0->IsObject());
6148  CHECK_EQ(proto0.As<v8::Object>(), o1);
6149
6150  Local<Value> proto1 = o1->GetPrototype();
6151  CHECK(proto1->IsObject());
6152  CHECK_EQ(proto1.As<v8::Object>(), o2);
6153
6154  Local<Value> proto2 = o2->GetPrototype();
6155  CHECK(proto2->IsObject());
6156  CHECK_EQ(proto2.As<v8::Object>(), o3);
6157}
6158
6159
6160THREADED_TEST(SetPrototypeThrows) {
6161  v8::HandleScope handle_scope;
6162  LocalContext context;
6163
6164  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6165
6166  Local<v8::Object> o0 = t->GetFunction()->NewInstance();
6167  Local<v8::Object> o1 = t->GetFunction()->NewInstance();
6168
6169  CHECK(o0->SetPrototype(o1));
6170  // If setting the prototype leads to the cycle, SetPrototype should
6171  // return false and keep VM in sane state.
6172  v8::TryCatch try_catch;
6173  CHECK(!o1->SetPrototype(o0));
6174  CHECK(!try_catch.HasCaught());
6175  ASSERT(!i::Top::has_pending_exception());
6176
6177  CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
6178}
6179
6180
6181THREADED_TEST(GetterSetterExceptions) {
6182  v8::HandleScope handle_scope;
6183  LocalContext context;
6184  CompileRun(
6185    "function Foo() { };"
6186    "function Throw() { throw 5; };"
6187    "var x = { };"
6188    "x.__defineSetter__('set', Throw);"
6189    "x.__defineGetter__('get', Throw);");
6190  Local<v8::Object> x =
6191      Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
6192  v8::TryCatch try_catch;
6193  x->Set(v8_str("set"), v8::Integer::New(8));
6194  x->Get(v8_str("get"));
6195  x->Set(v8_str("set"), v8::Integer::New(8));
6196  x->Get(v8_str("get"));
6197  x->Set(v8_str("set"), v8::Integer::New(8));
6198  x->Get(v8_str("get"));
6199  x->Set(v8_str("set"), v8::Integer::New(8));
6200  x->Get(v8_str("get"));
6201}
6202
6203
6204THREADED_TEST(Constructor) {
6205  v8::HandleScope handle_scope;
6206  LocalContext context;
6207  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
6208  templ->SetClassName(v8_str("Fun"));
6209  Local<Function> cons = templ->GetFunction();
6210  context->Global()->Set(v8_str("Fun"), cons);
6211  Local<v8::Object> inst = cons->NewInstance();
6212  i::Handle<i::JSObject> obj = v8::Utils::OpenHandle(*inst);
6213  Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
6214  CHECK(value->BooleanValue());
6215}
6216
6217THREADED_TEST(FunctionDescriptorException) {
6218  v8::HandleScope handle_scope;
6219  LocalContext context;
6220  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
6221  templ->SetClassName(v8_str("Fun"));
6222  Local<Function> cons = templ->GetFunction();
6223  context->Global()->Set(v8_str("Fun"), cons);
6224  Local<Value> value = CompileRun(
6225    "function test() {"
6226    "  try {"
6227    "    (new Fun()).blah()"
6228    "  } catch (e) {"
6229    "    var str = String(e);"
6230    "    if (str.indexOf('TypeError') == -1) return 1;"
6231    "    if (str.indexOf('[object Fun]') != -1) return 2;"
6232    "    if (str.indexOf('#<a Fun>') == -1) return 3;"
6233    "    return 0;"
6234    "  }"
6235    "  return 4;"
6236    "}"
6237    "test();");
6238  CHECK_EQ(0, value->Int32Value());
6239}
6240
6241
6242THREADED_TEST(EvalAliasedDynamic) {
6243  v8::HandleScope scope;
6244  LocalContext current;
6245
6246  // Tests where aliased eval can only be resolved dynamically.
6247  Local<Script> script =
6248      Script::Compile(v8_str("function f(x) { "
6249                             "  var foo = 2;"
6250                             "  with (x) { return eval('foo'); }"
6251                             "}"
6252                             "foo = 0;"
6253                             "result1 = f(new Object());"
6254                             "result2 = f(this);"
6255                             "var x = new Object();"
6256                             "x.eval = function(x) { return 1; };"
6257                             "result3 = f(x);"));
6258  script->Run();
6259  CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
6260  CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
6261  CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
6262
6263  v8::TryCatch try_catch;
6264  script =
6265    Script::Compile(v8_str("function f(x) { "
6266                           "  var bar = 2;"
6267                           "  with (x) { return eval('bar'); }"
6268                           "}"
6269                           "f(this)"));
6270  script->Run();
6271  CHECK(try_catch.HasCaught());
6272  try_catch.Reset();
6273}
6274
6275
6276THREADED_TEST(CrossEval) {
6277  v8::HandleScope scope;
6278  LocalContext other;
6279  LocalContext current;
6280
6281  Local<String> token = v8_str("<security token>");
6282  other->SetSecurityToken(token);
6283  current->SetSecurityToken(token);
6284
6285  // Setup reference from current to other.
6286  current->Global()->Set(v8_str("other"), other->Global());
6287
6288  // Check that new variables are introduced in other context.
6289  Local<Script> script =
6290      Script::Compile(v8_str("other.eval('var foo = 1234')"));
6291  script->Run();
6292  Local<Value> foo = other->Global()->Get(v8_str("foo"));
6293  CHECK_EQ(1234, foo->Int32Value());
6294  CHECK(!current->Global()->Has(v8_str("foo")));
6295
6296  // Check that writing to non-existing properties introduces them in
6297  // the other context.
6298  script =
6299      Script::Compile(v8_str("other.eval('na = 1234')"));
6300  script->Run();
6301  CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
6302  CHECK(!current->Global()->Has(v8_str("na")));
6303
6304  // Check that global variables in current context are not visible in other
6305  // context.
6306  v8::TryCatch try_catch;
6307  script =
6308      Script::Compile(v8_str("var bar = 42; other.eval('bar');"));
6309  Local<Value> result = script->Run();
6310  CHECK(try_catch.HasCaught());
6311  try_catch.Reset();
6312
6313  // Check that local variables in current context are not visible in other
6314  // context.
6315  script =
6316      Script::Compile(v8_str("(function() { "
6317                             "  var baz = 87;"
6318                             "  return other.eval('baz');"
6319                             "})();"));
6320  result = script->Run();
6321  CHECK(try_catch.HasCaught());
6322  try_catch.Reset();
6323
6324  // Check that global variables in the other environment are visible
6325  // when evaluting code.
6326  other->Global()->Set(v8_str("bis"), v8_num(1234));
6327  script = Script::Compile(v8_str("other.eval('bis')"));
6328  CHECK_EQ(1234, script->Run()->Int32Value());
6329  CHECK(!try_catch.HasCaught());
6330
6331  // Check that the 'this' pointer points to the global object evaluating
6332  // code.
6333  other->Global()->Set(v8_str("t"), other->Global());
6334  script = Script::Compile(v8_str("other.eval('this == t')"));
6335  result = script->Run();
6336  CHECK(result->IsTrue());
6337  CHECK(!try_catch.HasCaught());
6338
6339  // Check that variables introduced in with-statement are not visible in
6340  // other context.
6341  script =
6342      Script::Compile(v8_str("with({x:2}){other.eval('x')}"));
6343  result = script->Run();
6344  CHECK(try_catch.HasCaught());
6345  try_catch.Reset();
6346
6347  // Check that you cannot use 'eval.call' with another object than the
6348  // current global object.
6349  script =
6350      Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')"));
6351  result = script->Run();
6352  CHECK(try_catch.HasCaught());
6353}
6354
6355
6356// Test that calling eval in a context which has been detached from
6357// its global throws an exception.  This behavior is consistent with
6358// other JavaScript implementations.
6359THREADED_TEST(EvalInDetachedGlobal) {
6360  v8::HandleScope scope;
6361
6362  v8::Persistent<Context> context0 = Context::New();
6363  v8::Persistent<Context> context1 = Context::New();
6364
6365  // Setup function in context0 that uses eval from context0.
6366  context0->Enter();
6367  v8::Handle<v8::Value> fun =
6368      CompileRun("var x = 42;"
6369                 "(function() {"
6370                 "  var e = eval;"
6371                 "  return function(s) { return e(s); }"
6372                 "})()");
6373  context0->Exit();
6374
6375  // Put the function into context1 and call it before and after
6376  // detaching the global.  Before detaching, the call succeeds and
6377  // after detaching and exception is thrown.
6378  context1->Enter();
6379  context1->Global()->Set(v8_str("fun"), fun);
6380  v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
6381  CHECK_EQ(42, x_value->Int32Value());
6382  context0->DetachGlobal();
6383  v8::TryCatch catcher;
6384  x_value = CompileRun("fun('x')");
6385  CHECK(x_value.IsEmpty());
6386  CHECK(catcher.HasCaught());
6387  context1->Exit();
6388
6389  context1.Dispose();
6390  context0.Dispose();
6391}
6392
6393
6394THREADED_TEST(CrossLazyLoad) {
6395  v8::HandleScope scope;
6396  LocalContext other;
6397  LocalContext current;
6398
6399  Local<String> token = v8_str("<security token>");
6400  other->SetSecurityToken(token);
6401  current->SetSecurityToken(token);
6402
6403  // Setup reference from current to other.
6404  current->Global()->Set(v8_str("other"), other->Global());
6405
6406  // Trigger lazy loading in other context.
6407  Local<Script> script =
6408      Script::Compile(v8_str("other.eval('new Date(42)')"));
6409  Local<Value> value = script->Run();
6410  CHECK_EQ(42.0, value->NumberValue());
6411}
6412
6413
6414static v8::Handle<Value> call_as_function(const v8::Arguments& args) {
6415  ApiTestFuzzer::Fuzz();
6416  if (args.IsConstructCall()) {
6417    if (args[0]->IsInt32()) {
6418       return v8_num(-args[0]->Int32Value());
6419    }
6420  }
6421
6422  return args[0];
6423}
6424
6425
6426// Test that a call handler can be set for objects which will allow
6427// non-function objects created through the API to be called as
6428// functions.
6429THREADED_TEST(CallAsFunction) {
6430  v8::HandleScope scope;
6431  LocalContext context;
6432
6433  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6434  Local<ObjectTemplate> instance_template = t->InstanceTemplate();
6435  instance_template->SetCallAsFunctionHandler(call_as_function);
6436  Local<v8::Object> instance = t->GetFunction()->NewInstance();
6437  context->Global()->Set(v8_str("obj"), instance);
6438  v8::TryCatch try_catch;
6439  Local<Value> value;
6440  CHECK(!try_catch.HasCaught());
6441
6442  value = CompileRun("obj(42)");
6443  CHECK(!try_catch.HasCaught());
6444  CHECK_EQ(42, value->Int32Value());
6445
6446  value = CompileRun("(function(o){return o(49)})(obj)");
6447  CHECK(!try_catch.HasCaught());
6448  CHECK_EQ(49, value->Int32Value());
6449
6450  // test special case of call as function
6451  value = CompileRun("[obj]['0'](45)");
6452  CHECK(!try_catch.HasCaught());
6453  CHECK_EQ(45, value->Int32Value());
6454
6455  value = CompileRun("obj.call = Function.prototype.call;"
6456                     "obj.call(null, 87)");
6457  CHECK(!try_catch.HasCaught());
6458  CHECK_EQ(87, value->Int32Value());
6459
6460  // Regression tests for bug #1116356: Calling call through call/apply
6461  // must work for non-function receivers.
6462  const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
6463  value = CompileRun(apply_99);
6464  CHECK(!try_catch.HasCaught());
6465  CHECK_EQ(99, value->Int32Value());
6466
6467  const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
6468  value = CompileRun(call_17);
6469  CHECK(!try_catch.HasCaught());
6470  CHECK_EQ(17, value->Int32Value());
6471
6472  // Check that the call-as-function handler can be called through
6473  // new.
6474  value = CompileRun("new obj(43)");
6475  CHECK(!try_catch.HasCaught());
6476  CHECK_EQ(-43, value->Int32Value());
6477}
6478
6479
6480static int CountHandles() {
6481  return v8::HandleScope::NumberOfHandles();
6482}
6483
6484
6485static int Recurse(int depth, int iterations) {
6486  v8::HandleScope scope;
6487  if (depth == 0) return CountHandles();
6488  for (int i = 0; i < iterations; i++) {
6489    Local<v8::Number> n = v8::Integer::New(42);
6490  }
6491  return Recurse(depth - 1, iterations);
6492}
6493
6494
6495THREADED_TEST(HandleIteration) {
6496  static const int kIterations = 500;
6497  static const int kNesting = 200;
6498  CHECK_EQ(0, CountHandles());
6499  {
6500    v8::HandleScope scope1;
6501    CHECK_EQ(0, CountHandles());
6502    for (int i = 0; i < kIterations; i++) {
6503      Local<v8::Number> n = v8::Integer::New(42);
6504      CHECK_EQ(i + 1, CountHandles());
6505    }
6506
6507    CHECK_EQ(kIterations, CountHandles());
6508    {
6509      v8::HandleScope scope2;
6510      for (int j = 0; j < kIterations; j++) {
6511        Local<v8::Number> n = v8::Integer::New(42);
6512        CHECK_EQ(j + 1 + kIterations, CountHandles());
6513      }
6514    }
6515    CHECK_EQ(kIterations, CountHandles());
6516  }
6517  CHECK_EQ(0, CountHandles());
6518  CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations));
6519}
6520
6521
6522static v8::Handle<Value> InterceptorHasOwnPropertyGetter(
6523    Local<String> name,
6524    const AccessorInfo& info) {
6525  ApiTestFuzzer::Fuzz();
6526  return v8::Handle<Value>();
6527}
6528
6529
6530THREADED_TEST(InterceptorHasOwnProperty) {
6531  v8::HandleScope scope;
6532  LocalContext context;
6533  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6534  Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
6535  instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
6536  Local<Function> function = fun_templ->GetFunction();
6537  context->Global()->Set(v8_str("constructor"), function);
6538  v8::Handle<Value> value = CompileRun(
6539      "var o = new constructor();"
6540      "o.hasOwnProperty('ostehaps');");
6541  CHECK_EQ(false, value->BooleanValue());
6542  value = CompileRun(
6543      "o.ostehaps = 42;"
6544      "o.hasOwnProperty('ostehaps');");
6545  CHECK_EQ(true, value->BooleanValue());
6546  value = CompileRun(
6547      "var p = new constructor();"
6548      "p.hasOwnProperty('ostehaps');");
6549  CHECK_EQ(false, value->BooleanValue());
6550}
6551
6552
6553static v8::Handle<Value> InterceptorHasOwnPropertyGetterGC(
6554    Local<String> name,
6555    const AccessorInfo& info) {
6556  ApiTestFuzzer::Fuzz();
6557  i::Heap::CollectAllGarbage(false);
6558  return v8::Handle<Value>();
6559}
6560
6561
6562THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
6563  v8::HandleScope scope;
6564  LocalContext context;
6565  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6566  Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
6567  instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
6568  Local<Function> function = fun_templ->GetFunction();
6569  context->Global()->Set(v8_str("constructor"), function);
6570  // Let's first make some stuff so we can be sure to get a good GC.
6571  CompileRun(
6572      "function makestr(size) {"
6573      "  switch (size) {"
6574      "    case 1: return 'f';"
6575      "    case 2: return 'fo';"
6576      "    case 3: return 'foo';"
6577      "  }"
6578      "  return makestr(size >> 1) + makestr((size + 1) >> 1);"
6579      "}"
6580      "var x = makestr(12345);"
6581      "x = makestr(31415);"
6582      "x = makestr(23456);");
6583  v8::Handle<Value> value = CompileRun(
6584      "var o = new constructor();"
6585      "o.__proto__ = new String(x);"
6586      "o.hasOwnProperty('ostehaps');");
6587  CHECK_EQ(false, value->BooleanValue());
6588}
6589
6590
6591typedef v8::Handle<Value> (*NamedPropertyGetter)(Local<String> property,
6592                                                 const AccessorInfo& info);
6593
6594
6595static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
6596                                   const char* source,
6597                                   int expected) {
6598  v8::HandleScope scope;
6599  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6600  templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
6601  LocalContext context;
6602  context->Global()->Set(v8_str("o"), templ->NewInstance());
6603  v8::Handle<Value> value = CompileRun(source);
6604  CHECK_EQ(expected, value->Int32Value());
6605}
6606
6607
6608static v8::Handle<Value> InterceptorLoadICGetter(Local<String> name,
6609                                                 const AccessorInfo& info) {
6610  ApiTestFuzzer::Fuzz();
6611  CHECK_EQ(v8_str("data"), info.Data());
6612  CHECK_EQ(v8_str("x"), name);
6613  return v8::Integer::New(42);
6614}
6615
6616
6617// This test should hit the load IC for the interceptor case.
6618THREADED_TEST(InterceptorLoadIC) {
6619  CheckInterceptorLoadIC(InterceptorLoadICGetter,
6620    "var result = 0;"
6621    "for (var i = 0; i < 1000; i++) {"
6622    "  result = o.x;"
6623    "}",
6624    42);
6625}
6626
6627
6628// Below go several tests which verify that JITing for various
6629// configurations of interceptor and explicit fields works fine
6630// (those cases are special cased to get better performance).
6631
6632static v8::Handle<Value> InterceptorLoadXICGetter(Local<String> name,
6633                                                 const AccessorInfo& info) {
6634  ApiTestFuzzer::Fuzz();
6635  return v8_str("x")->Equals(name)
6636      ? v8::Integer::New(42) : v8::Handle<v8::Value>();
6637}
6638
6639
6640THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
6641  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6642    "var result = 0;"
6643    "o.y = 239;"
6644    "for (var i = 0; i < 1000; i++) {"
6645    "  result = o.y;"
6646    "}",
6647    239);
6648}
6649
6650
6651THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
6652  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6653    "var result = 0;"
6654    "o.__proto__ = { 'y': 239 };"
6655    "for (var i = 0; i < 1000; i++) {"
6656    "  result = o.y + o.x;"
6657    "}",
6658    239 + 42);
6659}
6660
6661
6662THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
6663  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6664    "var result = 0;"
6665    "o.__proto__.y = 239;"
6666    "for (var i = 0; i < 1000; i++) {"
6667    "  result = o.y + o.x;"
6668    "}",
6669    239 + 42);
6670}
6671
6672
6673THREADED_TEST(InterceptorLoadICUndefined) {
6674  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6675    "var result = 0;"
6676    "for (var i = 0; i < 1000; i++) {"
6677    "  result = (o.y == undefined) ? 239 : 42;"
6678    "}",
6679    239);
6680}
6681
6682
6683THREADED_TEST(InterceptorLoadICWithOverride) {
6684  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6685    "fst = new Object();  fst.__proto__ = o;"
6686    "snd = new Object();  snd.__proto__ = fst;"
6687    "var result1 = 0;"
6688    "for (var i = 0; i < 1000;  i++) {"
6689    "  result1 = snd.x;"
6690    "}"
6691    "fst.x = 239;"
6692    "var result = 0;"
6693    "for (var i = 0; i < 1000; i++) {"
6694    "  result = snd.x;"
6695    "}"
6696    "result + result1",
6697    239 + 42);
6698}
6699
6700
6701// Test the case when we stored field into
6702// a stub, but interceptor produced value on its own.
6703THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
6704  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6705    "proto = new Object();"
6706    "o.__proto__ = proto;"
6707    "proto.x = 239;"
6708    "for (var i = 0; i < 1000; i++) {"
6709    "  o.x;"
6710    // Now it should be ICed and keep a reference to x defined on proto
6711    "}"
6712    "var result = 0;"
6713    "for (var i = 0; i < 1000; i++) {"
6714    "  result += o.x;"
6715    "}"
6716    "result;",
6717    42 * 1000);
6718}
6719
6720
6721// Test the case when we stored field into
6722// a stub, but it got invalidated later on.
6723THREADED_TEST(InterceptorLoadICInvalidatedField) {
6724  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6725    "proto1 = new Object();"
6726    "proto2 = new Object();"
6727    "o.__proto__ = proto1;"
6728    "proto1.__proto__ = proto2;"
6729    "proto2.y = 239;"
6730    "for (var i = 0; i < 1000; i++) {"
6731    "  o.y;"
6732    // Now it should be ICed and keep a reference to y defined on proto2
6733    "}"
6734    "proto1.y = 42;"
6735    "var result = 0;"
6736    "for (var i = 0; i < 1000; i++) {"
6737    "  result += o.y;"
6738    "}"
6739    "result;",
6740    42 * 1000);
6741}
6742
6743
6744static int interceptor_load_not_handled_calls = 0;
6745static v8::Handle<Value> InterceptorLoadNotHandled(Local<String> name,
6746                                                   const AccessorInfo& info) {
6747  ++interceptor_load_not_handled_calls;
6748  return v8::Handle<v8::Value>();
6749}
6750
6751
6752// Test how post-interceptor lookups are done in the non-cacheable
6753// case: the interceptor should not be invoked during this lookup.
6754THREADED_TEST(InterceptorLoadICPostInterceptor) {
6755  interceptor_load_not_handled_calls = 0;
6756  CheckInterceptorLoadIC(InterceptorLoadNotHandled,
6757    "receiver = new Object();"
6758    "receiver.__proto__ = o;"
6759    "proto = new Object();"
6760    "/* Make proto a slow-case object. */"
6761    "for (var i = 0; i < 1000; i++) {"
6762    "  proto[\"xxxxxxxx\" + i] = [];"
6763    "}"
6764    "proto.x = 17;"
6765    "o.__proto__ = proto;"
6766    "var result = 0;"
6767    "for (var i = 0; i < 1000; i++) {"
6768    "  result += receiver.x;"
6769    "}"
6770    "result;",
6771    17 * 1000);
6772  CHECK_EQ(1000, interceptor_load_not_handled_calls);
6773}
6774
6775
6776// Test the case when we stored field into
6777// a stub, but it got invalidated later on due to override on
6778// global object which is between interceptor and fields' holders.
6779THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
6780  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6781    "o.__proto__ = this;"  // set a global to be a proto of o.
6782    "this.__proto__.y = 239;"
6783    "for (var i = 0; i < 10; i++) {"
6784    "  if (o.y != 239) throw 'oops: ' + o.y;"
6785    // Now it should be ICed and keep a reference to y defined on field_holder.
6786    "}"
6787    "this.y = 42;"  // Assign on a global.
6788    "var result = 0;"
6789    "for (var i = 0; i < 10; i++) {"
6790    "  result += o.y;"
6791    "}"
6792    "result;",
6793    42 * 10);
6794}
6795
6796
6797static void SetOnThis(Local<String> name,
6798                      Local<Value> value,
6799                      const AccessorInfo& info) {
6800  info.This()->ForceSet(name, value);
6801}
6802
6803
6804THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
6805  v8::HandleScope scope;
6806  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6807  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6808  templ->SetAccessor(v8_str("y"), Return239);
6809  LocalContext context;
6810  context->Global()->Set(v8_str("o"), templ->NewInstance());
6811
6812  // Check the case when receiver and interceptor's holder
6813  // are the same objects.
6814  v8::Handle<Value> value = CompileRun(
6815      "var result = 0;"
6816      "for (var i = 0; i < 7; i++) {"
6817      "  result = o.y;"
6818      "}");
6819  CHECK_EQ(239, value->Int32Value());
6820
6821  // Check the case when interceptor's holder is in proto chain
6822  // of receiver.
6823  value = CompileRun(
6824      "r = { __proto__: o };"
6825      "var result = 0;"
6826      "for (var i = 0; i < 7; i++) {"
6827      "  result = r.y;"
6828      "}");
6829  CHECK_EQ(239, value->Int32Value());
6830}
6831
6832
6833THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
6834  v8::HandleScope scope;
6835  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6836  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6837  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
6838  templ_p->SetAccessor(v8_str("y"), Return239);
6839
6840  LocalContext context;
6841  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6842  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
6843
6844  // Check the case when receiver and interceptor's holder
6845  // are the same objects.
6846  v8::Handle<Value> value = CompileRun(
6847      "o.__proto__ = p;"
6848      "var result = 0;"
6849      "for (var i = 0; i < 7; i++) {"
6850      "  result = o.x + o.y;"
6851      "}");
6852  CHECK_EQ(239 + 42, value->Int32Value());
6853
6854  // Check the case when interceptor's holder is in proto chain
6855  // of receiver.
6856  value = CompileRun(
6857      "r = { __proto__: o };"
6858      "var result = 0;"
6859      "for (var i = 0; i < 7; i++) {"
6860      "  result = r.x + r.y;"
6861      "}");
6862  CHECK_EQ(239 + 42, value->Int32Value());
6863}
6864
6865
6866THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
6867  v8::HandleScope scope;
6868  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6869  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6870  templ->SetAccessor(v8_str("y"), Return239);
6871
6872  LocalContext context;
6873  context->Global()->Set(v8_str("o"), templ->NewInstance());
6874
6875  v8::Handle<Value> value = CompileRun(
6876    "fst = new Object();  fst.__proto__ = o;"
6877    "snd = new Object();  snd.__proto__ = fst;"
6878    "var result1 = 0;"
6879    "for (var i = 0; i < 7;  i++) {"
6880    "  result1 = snd.x;"
6881    "}"
6882    "fst.x = 239;"
6883    "var result = 0;"
6884    "for (var i = 0; i < 7; i++) {"
6885    "  result = snd.x;"
6886    "}"
6887    "result + result1");
6888  CHECK_EQ(239 + 42, value->Int32Value());
6889}
6890
6891
6892// Test the case when we stored callback into
6893// a stub, but interceptor produced value on its own.
6894THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
6895  v8::HandleScope scope;
6896  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6897  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6898  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
6899  templ_p->SetAccessor(v8_str("y"), Return239);
6900
6901  LocalContext context;
6902  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6903  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
6904
6905  v8::Handle<Value> value = CompileRun(
6906    "o.__proto__ = p;"
6907    "for (var i = 0; i < 7; i++) {"
6908    "  o.x;"
6909    // Now it should be ICed and keep a reference to x defined on p
6910    "}"
6911    "var result = 0;"
6912    "for (var i = 0; i < 7; i++) {"
6913    "  result += o.x;"
6914    "}"
6915    "result");
6916  CHECK_EQ(42 * 7, value->Int32Value());
6917}
6918
6919
6920// Test the case when we stored callback into
6921// a stub, but it got invalidated later on.
6922THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
6923  v8::HandleScope scope;
6924  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6925  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6926  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
6927  templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
6928
6929  LocalContext context;
6930  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6931  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
6932
6933  v8::Handle<Value> value = CompileRun(
6934    "inbetween = new Object();"
6935    "o.__proto__ = inbetween;"
6936    "inbetween.__proto__ = p;"
6937    "for (var i = 0; i < 10; i++) {"
6938    "  o.y;"
6939    // Now it should be ICed and keep a reference to y defined on p
6940    "}"
6941    "inbetween.y = 42;"
6942    "var result = 0;"
6943    "for (var i = 0; i < 10; i++) {"
6944    "  result += o.y;"
6945    "}"
6946    "result");
6947  CHECK_EQ(42 * 10, value->Int32Value());
6948}
6949
6950
6951// Test the case when we stored callback into
6952// a stub, but it got invalidated later on due to override on
6953// global object which is between interceptor and callbacks' holders.
6954THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
6955  v8::HandleScope scope;
6956  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6957  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6958  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
6959  templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
6960
6961  LocalContext context;
6962  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6963  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
6964
6965  v8::Handle<Value> value = CompileRun(
6966    "o.__proto__ = this;"
6967    "this.__proto__ = p;"
6968    "for (var i = 0; i < 10; i++) {"
6969    "  if (o.y != 239) throw 'oops: ' + o.y;"
6970    // Now it should be ICed and keep a reference to y defined on p
6971    "}"
6972    "this.y = 42;"
6973    "var result = 0;"
6974    "for (var i = 0; i < 10; i++) {"
6975    "  result += o.y;"
6976    "}"
6977    "result");
6978  CHECK_EQ(42 * 10, value->Int32Value());
6979}
6980
6981
6982static v8::Handle<Value> InterceptorLoadICGetter0(Local<String> name,
6983                                                  const AccessorInfo& info) {
6984  ApiTestFuzzer::Fuzz();
6985  CHECK(v8_str("x")->Equals(name));
6986  return v8::Integer::New(0);
6987}
6988
6989
6990THREADED_TEST(InterceptorReturningZero) {
6991  CheckInterceptorLoadIC(InterceptorLoadICGetter0,
6992     "o.x == undefined ? 1 : 0",
6993     0);
6994}
6995
6996
6997static v8::Handle<Value> InterceptorStoreICSetter(
6998    Local<String> key, Local<Value> value, const AccessorInfo&) {
6999  CHECK(v8_str("x")->Equals(key));
7000  CHECK_EQ(42, value->Int32Value());
7001  return value;
7002}
7003
7004
7005// This test should hit the store IC for the interceptor case.
7006THREADED_TEST(InterceptorStoreIC) {
7007  v8::HandleScope scope;
7008  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7009  templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
7010                                 InterceptorStoreICSetter,
7011                                 0, 0, 0, v8_str("data"));
7012  LocalContext context;
7013  context->Global()->Set(v8_str("o"), templ->NewInstance());
7014  v8::Handle<Value> value = CompileRun(
7015    "for (var i = 0; i < 1000; i++) {"
7016    "  o.x = 42;"
7017    "}");
7018}
7019
7020
7021THREADED_TEST(InterceptorStoreICWithNoSetter) {
7022  v8::HandleScope scope;
7023  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7024  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
7025  LocalContext context;
7026  context->Global()->Set(v8_str("o"), templ->NewInstance());
7027  v8::Handle<Value> value = CompileRun(
7028    "for (var i = 0; i < 1000; i++) {"
7029    "  o.y = 239;"
7030    "}"
7031    "42 + o.y");
7032  CHECK_EQ(239 + 42, value->Int32Value());
7033}
7034
7035
7036
7037
7038v8::Handle<Value> call_ic_function;
7039v8::Handle<Value> call_ic_function2;
7040v8::Handle<Value> call_ic_function3;
7041
7042static v8::Handle<Value> InterceptorCallICGetter(Local<String> name,
7043                                                 const AccessorInfo& info) {
7044  ApiTestFuzzer::Fuzz();
7045  CHECK(v8_str("x")->Equals(name));
7046  return call_ic_function;
7047}
7048
7049
7050// This test should hit the call IC for the interceptor case.
7051THREADED_TEST(InterceptorCallIC) {
7052  v8::HandleScope scope;
7053  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7054  templ->SetNamedPropertyHandler(InterceptorCallICGetter);
7055  LocalContext context;
7056  context->Global()->Set(v8_str("o"), templ->NewInstance());
7057  call_ic_function =
7058      v8_compile("function f(x) { return x + 1; }; f")->Run();
7059  v8::Handle<Value> value = CompileRun(
7060    "var result = 0;"
7061    "for (var i = 0; i < 1000; i++) {"
7062    "  result = o.x(41);"
7063    "}");
7064  CHECK_EQ(42, value->Int32Value());
7065}
7066
7067
7068// This test checks that if interceptor doesn't provide
7069// a value, we can fetch regular value.
7070THREADED_TEST(InterceptorCallICSeesOthers) {
7071  v8::HandleScope scope;
7072  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7073  templ->SetNamedPropertyHandler(NoBlockGetterX);
7074  LocalContext context;
7075  context->Global()->Set(v8_str("o"), templ->NewInstance());
7076  v8::Handle<Value> value = CompileRun(
7077    "o.x = function f(x) { return x + 1; };"
7078    "var result = 0;"
7079    "for (var i = 0; i < 7; i++) {"
7080    "  result = o.x(41);"
7081    "}");
7082  CHECK_EQ(42, value->Int32Value());
7083}
7084
7085
7086static v8::Handle<Value> call_ic_function4;
7087static v8::Handle<Value> InterceptorCallICGetter4(Local<String> name,
7088                                                  const AccessorInfo& info) {
7089  ApiTestFuzzer::Fuzz();
7090  CHECK(v8_str("x")->Equals(name));
7091  return call_ic_function4;
7092}
7093
7094
7095// This test checks that if interceptor provides a function,
7096// even if we cached shadowed variant, interceptor's function
7097// is invoked
7098THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
7099  v8::HandleScope scope;
7100  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7101  templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
7102  LocalContext context;
7103  context->Global()->Set(v8_str("o"), templ->NewInstance());
7104  call_ic_function4 =
7105      v8_compile("function f(x) { return x - 1; }; f")->Run();
7106  v8::Handle<Value> value = CompileRun(
7107    "o.__proto__.x = function(x) { return x + 1; };"
7108    "var result = 0;"
7109    "for (var i = 0; i < 1000; i++) {"
7110    "  result = o.x(42);"
7111    "}");
7112  CHECK_EQ(41, value->Int32Value());
7113}
7114
7115
7116// Test the case when we stored cacheable lookup into
7117// a stub, but it got invalidated later on
7118THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
7119  v8::HandleScope scope;
7120  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7121  templ->SetNamedPropertyHandler(NoBlockGetterX);
7122  LocalContext context;
7123  context->Global()->Set(v8_str("o"), templ->NewInstance());
7124  v8::Handle<Value> value = CompileRun(
7125    "proto1 = new Object();"
7126    "proto2 = new Object();"
7127    "o.__proto__ = proto1;"
7128    "proto1.__proto__ = proto2;"
7129    "proto2.y = function(x) { return x + 1; };"
7130    // Invoke it many times to compile a stub
7131    "for (var i = 0; i < 7; i++) {"
7132    "  o.y(42);"
7133    "}"
7134    "proto1.y = function(x) { return x - 1; };"
7135    "var result = 0;"
7136    "for (var i = 0; i < 7; i++) {"
7137    "  result += o.y(42);"
7138    "}");
7139  CHECK_EQ(41 * 7, value->Int32Value());
7140}
7141
7142
7143static v8::Handle<Value> call_ic_function5;
7144static v8::Handle<Value> InterceptorCallICGetter5(Local<String> name,
7145                                                  const AccessorInfo& info) {
7146  ApiTestFuzzer::Fuzz();
7147  if (v8_str("x")->Equals(name))
7148    return call_ic_function5;
7149  else
7150    return Local<Value>();
7151}
7152
7153
7154// This test checks that if interceptor doesn't provide a function,
7155// cached constant function is used
7156THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
7157  v8::HandleScope scope;
7158  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7159  templ->SetNamedPropertyHandler(NoBlockGetterX);
7160  LocalContext context;
7161  context->Global()->Set(v8_str("o"), templ->NewInstance());
7162  v8::Handle<Value> value = CompileRun(
7163    "function inc(x) { return x + 1; };"
7164    "inc(1);"
7165    "o.x = inc;"
7166    "var result = 0;"
7167    "for (var i = 0; i < 1000; i++) {"
7168    "  result = o.x(42);"
7169    "}");
7170  CHECK_EQ(43, value->Int32Value());
7171}
7172
7173
7174// This test checks that if interceptor provides a function,
7175// even if we cached constant function, interceptor's function
7176// is invoked
7177THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
7178  v8::HandleScope scope;
7179  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7180  templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
7181  LocalContext context;
7182  context->Global()->Set(v8_str("o"), templ->NewInstance());
7183  call_ic_function5 =
7184      v8_compile("function f(x) { return x - 1; }; f")->Run();
7185  v8::Handle<Value> value = CompileRun(
7186    "function inc(x) { return x + 1; };"
7187    "inc(1);"
7188    "o.x = inc;"
7189    "var result = 0;"
7190    "for (var i = 0; i < 1000; i++) {"
7191    "  result = o.x(42);"
7192    "}");
7193  CHECK_EQ(41, value->Int32Value());
7194}
7195
7196
7197// Test the case when we stored constant function into
7198// a stub, but it got invalidated later on
7199THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
7200  v8::HandleScope scope;
7201  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7202  templ->SetNamedPropertyHandler(NoBlockGetterX);
7203  LocalContext context;
7204  context->Global()->Set(v8_str("o"), templ->NewInstance());
7205  v8::Handle<Value> value = CompileRun(
7206    "function inc(x) { return x + 1; };"
7207    "inc(1);"
7208    "proto1 = new Object();"
7209    "proto2 = new Object();"
7210    "o.__proto__ = proto1;"
7211    "proto1.__proto__ = proto2;"
7212    "proto2.y = inc;"
7213    // Invoke it many times to compile a stub
7214    "for (var i = 0; i < 7; i++) {"
7215    "  o.y(42);"
7216    "}"
7217    "proto1.y = function(x) { return x - 1; };"
7218    "var result = 0;"
7219    "for (var i = 0; i < 7; i++) {"
7220    "  result += o.y(42);"
7221    "}");
7222  CHECK_EQ(41 * 7, value->Int32Value());
7223}
7224
7225
7226// Test the case when we stored constant function into
7227// a stub, but it got invalidated later on due to override on
7228// global object which is between interceptor and constant function' holders.
7229THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
7230  v8::HandleScope scope;
7231  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7232  templ->SetNamedPropertyHandler(NoBlockGetterX);
7233  LocalContext context;
7234  context->Global()->Set(v8_str("o"), templ->NewInstance());
7235  v8::Handle<Value> value = CompileRun(
7236    "function inc(x) { return x + 1; };"
7237    "inc(1);"
7238    "o.__proto__ = this;"
7239    "this.__proto__.y = inc;"
7240    // Invoke it many times to compile a stub
7241    "for (var i = 0; i < 7; i++) {"
7242    "  if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
7243    "}"
7244    "this.y = function(x) { return x - 1; };"
7245    "var result = 0;"
7246    "for (var i = 0; i < 7; i++) {"
7247    "  result += o.y(42);"
7248    "}");
7249  CHECK_EQ(41 * 7, value->Int32Value());
7250}
7251
7252
7253// Test the case when actual function to call sits on global object.
7254THREADED_TEST(InterceptorCallICCachedFromGlobal) {
7255  v8::HandleScope scope;
7256  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7257  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
7258
7259  LocalContext context;
7260  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
7261
7262  v8::Handle<Value> value = CompileRun(
7263    "try {"
7264    "  o.__proto__ = this;"
7265    "  for (var i = 0; i < 10; i++) {"
7266    "    var v = o.parseFloat('239');"
7267    "    if (v != 239) throw v;"
7268      // Now it should be ICed and keep a reference to parseFloat.
7269    "  }"
7270    "  var result = 0;"
7271    "  for (var i = 0; i < 10; i++) {"
7272    "    result += o.parseFloat('239');"
7273    "  }"
7274    "  result"
7275    "} catch(e) {"
7276    "  e"
7277    "};");
7278  CHECK_EQ(239 * 10, value->Int32Value());
7279}
7280
7281static v8::Handle<Value> InterceptorCallICFastApi(Local<String> name,
7282                                                  const AccessorInfo& info) {
7283  ApiTestFuzzer::Fuzz();
7284  int* call_count = reinterpret_cast<int*>(v8::External::Unwrap(info.Data()));
7285  ++(*call_count);
7286  if ((*call_count) % 20 == 0) {
7287    i::Heap::CollectAllGarbage(true);
7288  }
7289  return v8::Handle<Value>();
7290}
7291
7292static v8::Handle<Value> FastApiCallback_TrivialSignature(
7293    const v8::Arguments& args) {
7294  ApiTestFuzzer::Fuzz();
7295  CHECK_EQ(args.This(), args.Holder());
7296  CHECK(args.Data()->Equals(v8_str("method_data")));
7297  return v8::Integer::New(args[0]->Int32Value() + 1);
7298}
7299
7300static v8::Handle<Value> FastApiCallback_SimpleSignature(
7301    const v8::Arguments& args) {
7302  ApiTestFuzzer::Fuzz();
7303  CHECK_EQ(args.This()->GetPrototype(), args.Holder());
7304  CHECK(args.Data()->Equals(v8_str("method_data")));
7305  // Note, we're using HasRealNamedProperty instead of Has to avoid
7306  // invoking the interceptor again.
7307  CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
7308  return v8::Integer::New(args[0]->Int32Value() + 1);
7309}
7310
7311// Helper to maximize the odds of object moving.
7312static void GenerateSomeGarbage() {
7313  CompileRun(
7314      "var garbage;"
7315      "for (var i = 0; i < 1000; i++) {"
7316      "  garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
7317      "}"
7318      "garbage = undefined;");
7319}
7320
7321THREADED_TEST(InterceptorCallICFastApi_TrivialSignature) {
7322  int interceptor_call_count = 0;
7323  v8::HandleScope scope;
7324  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7325  v8::Handle<v8::FunctionTemplate> method_templ =
7326      v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
7327                                v8_str("method_data"),
7328                                v8::Handle<v8::Signature>());
7329  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7330  proto_templ->Set(v8_str("method"), method_templ);
7331  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7332  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
7333                                 NULL, NULL, NULL, NULL,
7334                                 v8::External::Wrap(&interceptor_call_count));
7335  LocalContext context;
7336  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7337  GenerateSomeGarbage();
7338  context->Global()->Set(v8_str("o"), fun->NewInstance());
7339  v8::Handle<Value> value = CompileRun(
7340      "var result = 0;"
7341      "for (var i = 0; i < 100; i++) {"
7342      "  result = o.method(41);"
7343      "}");
7344  CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
7345  CHECK_EQ(100, interceptor_call_count);
7346}
7347
7348THREADED_TEST(InterceptorCallICFastApi_SimpleSignature) {
7349  int interceptor_call_count = 0;
7350  v8::HandleScope scope;
7351  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7352  v8::Handle<v8::FunctionTemplate> method_templ =
7353      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7354                                v8_str("method_data"),
7355                                v8::Signature::New(fun_templ));
7356  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7357  proto_templ->Set(v8_str("method"), method_templ);
7358  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7359  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
7360                                 NULL, NULL, NULL, NULL,
7361                                 v8::External::Wrap(&interceptor_call_count));
7362  LocalContext context;
7363  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7364  GenerateSomeGarbage();
7365  context->Global()->Set(v8_str("o"), fun->NewInstance());
7366  v8::Handle<Value> value = CompileRun(
7367      "o.foo = 17;"
7368      "var receiver = {};"
7369      "receiver.__proto__ = o;"
7370      "var result = 0;"
7371      "for (var i = 0; i < 100; i++) {"
7372      "  result = receiver.method(41);"
7373      "}");
7374  CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
7375  CHECK_EQ(100, interceptor_call_count);
7376}
7377
7378THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
7379  int interceptor_call_count = 0;
7380  v8::HandleScope scope;
7381  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7382  v8::Handle<v8::FunctionTemplate> method_templ =
7383      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7384                                v8_str("method_data"),
7385                                v8::Signature::New(fun_templ));
7386  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7387  proto_templ->Set(v8_str("method"), method_templ);
7388  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7389  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
7390                                 NULL, NULL, NULL, NULL,
7391                                 v8::External::Wrap(&interceptor_call_count));
7392  LocalContext context;
7393  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7394  GenerateSomeGarbage();
7395  context->Global()->Set(v8_str("o"), fun->NewInstance());
7396  v8::Handle<Value> value = CompileRun(
7397      "o.foo = 17;"
7398      "var receiver = {};"
7399      "receiver.__proto__ = o;"
7400      "var result = 0;"
7401      "var saved_result = 0;"
7402      "for (var i = 0; i < 100; i++) {"
7403      "  result = receiver.method(41);"
7404      "  if (i == 50) {"
7405      "    saved_result = result;"
7406      "    receiver = {method: function(x) { return x - 1 }};"
7407      "  }"
7408      "}");
7409  CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
7410  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7411  CHECK_GE(interceptor_call_count, 50);
7412}
7413
7414THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
7415  int interceptor_call_count = 0;
7416  v8::HandleScope scope;
7417  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7418  v8::Handle<v8::FunctionTemplate> method_templ =
7419      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7420                                v8_str("method_data"),
7421                                v8::Signature::New(fun_templ));
7422  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7423  proto_templ->Set(v8_str("method"), method_templ);
7424  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7425  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
7426                                 NULL, NULL, NULL, NULL,
7427                                 v8::External::Wrap(&interceptor_call_count));
7428  LocalContext context;
7429  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7430  GenerateSomeGarbage();
7431  context->Global()->Set(v8_str("o"), fun->NewInstance());
7432  v8::Handle<Value> value = CompileRun(
7433      "o.foo = 17;"
7434      "var receiver = {};"
7435      "receiver.__proto__ = o;"
7436      "var result = 0;"
7437      "var saved_result = 0;"
7438      "for (var i = 0; i < 100; i++) {"
7439      "  result = receiver.method(41);"
7440      "  if (i == 50) {"
7441      "    saved_result = result;"
7442      "    o.method = function(x) { return x - 1 };"
7443      "  }"
7444      "}");
7445  CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
7446  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7447  CHECK_GE(interceptor_call_count, 50);
7448}
7449
7450THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
7451  int interceptor_call_count = 0;
7452  v8::HandleScope scope;
7453  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7454  v8::Handle<v8::FunctionTemplate> method_templ =
7455      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7456                                v8_str("method_data"),
7457                                v8::Signature::New(fun_templ));
7458  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7459  proto_templ->Set(v8_str("method"), method_templ);
7460  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7461  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
7462                                 NULL, NULL, NULL, NULL,
7463                                 v8::External::Wrap(&interceptor_call_count));
7464  LocalContext context;
7465  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7466  GenerateSomeGarbage();
7467  context->Global()->Set(v8_str("o"), fun->NewInstance());
7468  v8::TryCatch try_catch;
7469  v8::Handle<Value> value = CompileRun(
7470      "o.foo = 17;"
7471      "var receiver = {};"
7472      "receiver.__proto__ = o;"
7473      "var result = 0;"
7474      "var saved_result = 0;"
7475      "for (var i = 0; i < 100; i++) {"
7476      "  result = receiver.method(41);"
7477      "  if (i == 50) {"
7478      "    saved_result = result;"
7479      "    receiver = 333;"
7480      "  }"
7481      "}");
7482  CHECK(try_catch.HasCaught());
7483  CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
7484           try_catch.Exception()->ToString());
7485  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7486  CHECK_GE(interceptor_call_count, 50);
7487}
7488
7489THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
7490  int interceptor_call_count = 0;
7491  v8::HandleScope scope;
7492  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7493  v8::Handle<v8::FunctionTemplate> method_templ =
7494      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7495                                v8_str("method_data"),
7496                                v8::Signature::New(fun_templ));
7497  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7498  proto_templ->Set(v8_str("method"), method_templ);
7499  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7500  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
7501                                 NULL, NULL, NULL, NULL,
7502                                 v8::External::Wrap(&interceptor_call_count));
7503  LocalContext context;
7504  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7505  GenerateSomeGarbage();
7506  context->Global()->Set(v8_str("o"), fun->NewInstance());
7507  v8::TryCatch try_catch;
7508  v8::Handle<Value> value = CompileRun(
7509      "o.foo = 17;"
7510      "var receiver = {};"
7511      "receiver.__proto__ = o;"
7512      "var result = 0;"
7513      "var saved_result = 0;"
7514      "for (var i = 0; i < 100; i++) {"
7515      "  result = receiver.method(41);"
7516      "  if (i == 50) {"
7517      "    saved_result = result;"
7518      "    receiver = {method: receiver.method};"
7519      "  }"
7520      "}");
7521  CHECK(try_catch.HasCaught());
7522  CHECK_EQ(v8_str("TypeError: Illegal invocation"),
7523           try_catch.Exception()->ToString());
7524  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7525  CHECK_GE(interceptor_call_count, 50);
7526}
7527
7528THREADED_TEST(CallICFastApi_TrivialSignature) {
7529  v8::HandleScope scope;
7530  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7531  v8::Handle<v8::FunctionTemplate> method_templ =
7532      v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
7533                                v8_str("method_data"),
7534                                v8::Handle<v8::Signature>());
7535  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7536  proto_templ->Set(v8_str("method"), method_templ);
7537  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7538  LocalContext context;
7539  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7540  GenerateSomeGarbage();
7541  context->Global()->Set(v8_str("o"), fun->NewInstance());
7542  v8::Handle<Value> value = CompileRun(
7543      "var result = 0;"
7544      "for (var i = 0; i < 100; i++) {"
7545      "  result = o.method(41);"
7546      "}");
7547
7548  CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
7549}
7550
7551THREADED_TEST(CallICFastApi_SimpleSignature) {
7552  v8::HandleScope scope;
7553  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7554  v8::Handle<v8::FunctionTemplate> method_templ =
7555      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7556                                v8_str("method_data"),
7557                                v8::Signature::New(fun_templ));
7558  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7559  proto_templ->Set(v8_str("method"), method_templ);
7560  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7561  LocalContext context;
7562  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7563  GenerateSomeGarbage();
7564  context->Global()->Set(v8_str("o"), fun->NewInstance());
7565  v8::Handle<Value> value = CompileRun(
7566      "o.foo = 17;"
7567      "var receiver = {};"
7568      "receiver.__proto__ = o;"
7569      "var result = 0;"
7570      "for (var i = 0; i < 100; i++) {"
7571      "  result = receiver.method(41);"
7572      "}");
7573
7574  CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
7575}
7576
7577THREADED_TEST(CallICFastApi_SimpleSignature_Miss1) {
7578  v8::HandleScope scope;
7579  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7580  v8::Handle<v8::FunctionTemplate> method_templ =
7581      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7582                                v8_str("method_data"),
7583                                v8::Signature::New(fun_templ));
7584  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7585  proto_templ->Set(v8_str("method"), method_templ);
7586  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7587  LocalContext context;
7588  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7589  GenerateSomeGarbage();
7590  context->Global()->Set(v8_str("o"), fun->NewInstance());
7591  v8::Handle<Value> value = CompileRun(
7592      "o.foo = 17;"
7593      "var receiver = {};"
7594      "receiver.__proto__ = o;"
7595      "var result = 0;"
7596      "var saved_result = 0;"
7597      "for (var i = 0; i < 100; i++) {"
7598      "  result = receiver.method(41);"
7599      "  if (i == 50) {"
7600      "    saved_result = result;"
7601      "    receiver = {method: function(x) { return x - 1 }};"
7602      "  }"
7603      "}");
7604  CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
7605  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7606}
7607
7608THREADED_TEST(CallICFastApi_SimpleSignature_Miss2) {
7609  v8::HandleScope scope;
7610  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7611  v8::Handle<v8::FunctionTemplate> method_templ =
7612      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7613                                v8_str("method_data"),
7614                                v8::Signature::New(fun_templ));
7615  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7616  proto_templ->Set(v8_str("method"), method_templ);
7617  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7618  LocalContext context;
7619  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7620  GenerateSomeGarbage();
7621  context->Global()->Set(v8_str("o"), fun->NewInstance());
7622  v8::TryCatch try_catch;
7623  v8::Handle<Value> value = CompileRun(
7624      "o.foo = 17;"
7625      "var receiver = {};"
7626      "receiver.__proto__ = o;"
7627      "var result = 0;"
7628      "var saved_result = 0;"
7629      "for (var i = 0; i < 100; i++) {"
7630      "  result = receiver.method(41);"
7631      "  if (i == 50) {"
7632      "    saved_result = result;"
7633      "    receiver = 333;"
7634      "  }"
7635      "}");
7636  CHECK(try_catch.HasCaught());
7637  CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
7638           try_catch.Exception()->ToString());
7639  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7640}
7641
7642
7643v8::Handle<Value> keyed_call_ic_function;
7644
7645static v8::Handle<Value> InterceptorKeyedCallICGetter(
7646    Local<String> name, const AccessorInfo& info) {
7647  ApiTestFuzzer::Fuzz();
7648  if (v8_str("x")->Equals(name)) {
7649    return keyed_call_ic_function;
7650  }
7651  return v8::Handle<Value>();
7652}
7653
7654
7655// Test the case when we stored cacheable lookup into
7656// a stub, but the function name changed (to another cacheable function).
7657THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
7658  v8::HandleScope scope;
7659  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7660  templ->SetNamedPropertyHandler(NoBlockGetterX);
7661  LocalContext context;
7662  context->Global()->Set(v8_str("o"), templ->NewInstance());
7663  v8::Handle<Value> value = CompileRun(
7664    "proto = new Object();"
7665    "proto.y = function(x) { return x + 1; };"
7666    "proto.z = function(x) { return x - 1; };"
7667    "o.__proto__ = proto;"
7668    "var result = 0;"
7669    "var method = 'y';"
7670    "for (var i = 0; i < 10; i++) {"
7671    "  if (i == 5) { method = 'z'; };"
7672    "  result += o[method](41);"
7673    "}");
7674  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
7675}
7676
7677
7678// Test the case when we stored cacheable lookup into
7679// a stub, but the function name changed (and the new function is present
7680// both before and after the interceptor in the prototype chain).
7681THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
7682  v8::HandleScope scope;
7683  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7684  templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
7685  LocalContext context;
7686  context->Global()->Set(v8_str("proto1"), templ->NewInstance());
7687  keyed_call_ic_function =
7688      v8_compile("function f(x) { return x - 1; }; f")->Run();
7689  v8::Handle<Value> value = CompileRun(
7690    "o = new Object();"
7691    "proto2 = new Object();"
7692    "o.y = function(x) { return x + 1; };"
7693    "proto2.y = function(x) { return x + 2; };"
7694    "o.__proto__ = proto1;"
7695    "proto1.__proto__ = proto2;"
7696    "var result = 0;"
7697    "var method = 'x';"
7698    "for (var i = 0; i < 10; i++) {"
7699    "  if (i == 5) { method = 'y'; };"
7700    "  result += o[method](41);"
7701    "}");
7702  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
7703}
7704
7705
7706// Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
7707// on the global object.
7708THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
7709  v8::HandleScope scope;
7710  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7711  templ->SetNamedPropertyHandler(NoBlockGetterX);
7712  LocalContext context;
7713  context->Global()->Set(v8_str("o"), templ->NewInstance());
7714  v8::Handle<Value> value = CompileRun(
7715    "function inc(x) { return x + 1; };"
7716    "inc(1);"
7717    "function dec(x) { return x - 1; };"
7718    "dec(1);"
7719    "o.__proto__ = this;"
7720    "this.__proto__.x = inc;"
7721    "this.__proto__.y = dec;"
7722    "var result = 0;"
7723    "var method = 'x';"
7724    "for (var i = 0; i < 10; i++) {"
7725    "  if (i == 5) { method = 'y'; };"
7726    "  result += o[method](41);"
7727    "}");
7728  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
7729}
7730
7731
7732// Test the case when actual function to call sits on global object.
7733THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
7734  v8::HandleScope scope;
7735  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7736  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
7737  LocalContext context;
7738  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
7739
7740  v8::Handle<Value> value = CompileRun(
7741    "function len(x) { return x.length; };"
7742    "o.__proto__ = this;"
7743    "var m = 'parseFloat';"
7744    "var result = 0;"
7745    "for (var i = 0; i < 10; i++) {"
7746    "  if (i == 5) {"
7747    "    m = 'len';"
7748    "    saved_result = result;"
7749    "  };"
7750    "  result = o[m]('239');"
7751    "}");
7752  CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
7753  CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7754}
7755
7756// Test the map transition before the interceptor.
7757THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
7758  v8::HandleScope scope;
7759  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7760  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
7761  LocalContext context;
7762  context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
7763
7764  v8::Handle<Value> value = CompileRun(
7765    "var o = new Object();"
7766    "o.__proto__ = proto;"
7767    "o.method = function(x) { return x + 1; };"
7768    "var m = 'method';"
7769    "var result = 0;"
7770    "for (var i = 0; i < 10; i++) {"
7771    "  if (i == 5) { o.method = function(x) { return x - 1; }; };"
7772    "  result += o[m](41);"
7773    "}");
7774  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
7775}
7776
7777
7778// Test the map transition after the interceptor.
7779THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
7780  v8::HandleScope scope;
7781  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7782  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
7783  LocalContext context;
7784  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
7785
7786  v8::Handle<Value> value = CompileRun(
7787    "var proto = new Object();"
7788    "o.__proto__ = proto;"
7789    "proto.method = function(x) { return x + 1; };"
7790    "var m = 'method';"
7791    "var result = 0;"
7792    "for (var i = 0; i < 10; i++) {"
7793    "  if (i == 5) { proto.method = function(x) { return x - 1; }; };"
7794    "  result += o[m](41);"
7795    "}");
7796  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
7797}
7798
7799
7800static int interceptor_call_count = 0;
7801
7802static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name,
7803                                                     const AccessorInfo& info) {
7804  ApiTestFuzzer::Fuzz();
7805  if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
7806    return call_ic_function2;
7807  }
7808  return v8::Handle<Value>();
7809}
7810
7811
7812// This test should hit load and call ICs for the interceptor case.
7813// Once in a while, the interceptor will reply that a property was not
7814// found in which case we should get a reference error.
7815THREADED_TEST(InterceptorICReferenceErrors) {
7816  v8::HandleScope scope;
7817  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7818  templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
7819  LocalContext context(0, templ, v8::Handle<Value>());
7820  call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
7821  v8::Handle<Value> value = CompileRun(
7822    "function f() {"
7823    "  for (var i = 0; i < 1000; i++) {"
7824    "    try { x; } catch(e) { return true; }"
7825    "  }"
7826    "  return false;"
7827    "};"
7828    "f();");
7829  CHECK_EQ(true, value->BooleanValue());
7830  interceptor_call_count = 0;
7831  value = CompileRun(
7832    "function g() {"
7833    "  for (var i = 0; i < 1000; i++) {"
7834    "    try { x(42); } catch(e) { return true; }"
7835    "  }"
7836    "  return false;"
7837    "};"
7838    "g();");
7839  CHECK_EQ(true, value->BooleanValue());
7840}
7841
7842
7843static int interceptor_ic_exception_get_count = 0;
7844
7845static v8::Handle<Value> InterceptorICExceptionGetter(
7846    Local<String> name,
7847    const AccessorInfo& info) {
7848  ApiTestFuzzer::Fuzz();
7849  if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
7850    return call_ic_function3;
7851  }
7852  if (interceptor_ic_exception_get_count == 20) {
7853    return v8::ThrowException(v8_num(42));
7854  }
7855  // Do not handle get for properties other than x.
7856  return v8::Handle<Value>();
7857}
7858
7859// Test interceptor load/call IC where the interceptor throws an
7860// exception once in a while.
7861THREADED_TEST(InterceptorICGetterExceptions) {
7862  interceptor_ic_exception_get_count = 0;
7863  v8::HandleScope scope;
7864  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7865  templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
7866  LocalContext context(0, templ, v8::Handle<Value>());
7867  call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
7868  v8::Handle<Value> value = CompileRun(
7869    "function f() {"
7870    "  for (var i = 0; i < 100; i++) {"
7871    "    try { x; } catch(e) { return true; }"
7872    "  }"
7873    "  return false;"
7874    "};"
7875    "f();");
7876  CHECK_EQ(true, value->BooleanValue());
7877  interceptor_ic_exception_get_count = 0;
7878  value = CompileRun(
7879    "function f() {"
7880    "  for (var i = 0; i < 100; i++) {"
7881    "    try { x(42); } catch(e) { return true; }"
7882    "  }"
7883    "  return false;"
7884    "};"
7885    "f();");
7886  CHECK_EQ(true, value->BooleanValue());
7887}
7888
7889
7890static int interceptor_ic_exception_set_count = 0;
7891
7892static v8::Handle<Value> InterceptorICExceptionSetter(
7893      Local<String> key, Local<Value> value, const AccessorInfo&) {
7894  ApiTestFuzzer::Fuzz();
7895  if (++interceptor_ic_exception_set_count > 20) {
7896    return v8::ThrowException(v8_num(42));
7897  }
7898  // Do not actually handle setting.
7899  return v8::Handle<Value>();
7900}
7901
7902// Test interceptor store IC where the interceptor throws an exception
7903// once in a while.
7904THREADED_TEST(InterceptorICSetterExceptions) {
7905  interceptor_ic_exception_set_count = 0;
7906  v8::HandleScope scope;
7907  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7908  templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
7909  LocalContext context(0, templ, v8::Handle<Value>());
7910  v8::Handle<Value> value = CompileRun(
7911    "function f() {"
7912    "  for (var i = 0; i < 100; i++) {"
7913    "    try { x = 42; } catch(e) { return true; }"
7914    "  }"
7915    "  return false;"
7916    "};"
7917    "f();");
7918  CHECK_EQ(true, value->BooleanValue());
7919}
7920
7921
7922// Test that we ignore null interceptors.
7923THREADED_TEST(NullNamedInterceptor) {
7924  v8::HandleScope scope;
7925  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7926  templ->SetNamedPropertyHandler(0);
7927  LocalContext context;
7928  templ->Set("x", v8_num(42));
7929  v8::Handle<v8::Object> obj = templ->NewInstance();
7930  context->Global()->Set(v8_str("obj"), obj);
7931  v8::Handle<Value> value = CompileRun("obj.x");
7932  CHECK(value->IsInt32());
7933  CHECK_EQ(42, value->Int32Value());
7934}
7935
7936
7937// Test that we ignore null interceptors.
7938THREADED_TEST(NullIndexedInterceptor) {
7939  v8::HandleScope scope;
7940  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7941  templ->SetIndexedPropertyHandler(0);
7942  LocalContext context;
7943  templ->Set("42", v8_num(42));
7944  v8::Handle<v8::Object> obj = templ->NewInstance();
7945  context->Global()->Set(v8_str("obj"), obj);
7946  v8::Handle<Value> value = CompileRun("obj[42]");
7947  CHECK(value->IsInt32());
7948  CHECK_EQ(42, value->Int32Value());
7949}
7950
7951
7952THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
7953  v8::HandleScope scope;
7954  v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
7955  templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
7956  LocalContext env;
7957  env->Global()->Set(v8_str("obj"),
7958                     templ->GetFunction()->NewInstance());
7959  ExpectTrue("obj.x === 42");
7960  ExpectTrue("!obj.propertyIsEnumerable('x')");
7961}
7962
7963
7964static v8::Handle<Value> ParentGetter(Local<String> name,
7965                                      const AccessorInfo& info) {
7966  ApiTestFuzzer::Fuzz();
7967  return v8_num(1);
7968}
7969
7970
7971static v8::Handle<Value> ChildGetter(Local<String> name,
7972                                     const AccessorInfo& info) {
7973  ApiTestFuzzer::Fuzz();
7974  return v8_num(42);
7975}
7976
7977
7978THREADED_TEST(Overriding) {
7979  v8::HandleScope scope;
7980  LocalContext context;
7981
7982  // Parent template.
7983  Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New();
7984  Local<ObjectTemplate> parent_instance_templ =
7985      parent_templ->InstanceTemplate();
7986  parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
7987
7988  // Template that inherits from the parent template.
7989  Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New();
7990  Local<ObjectTemplate> child_instance_templ =
7991      child_templ->InstanceTemplate();
7992  child_templ->Inherit(parent_templ);
7993  // Override 'f'.  The child version of 'f' should get called for child
7994  // instances.
7995  child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
7996  // Add 'g' twice.  The 'g' added last should get called for instances.
7997  child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
7998  child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
7999
8000  // Add 'h' as an accessor to the proto template with ReadOnly attributes
8001  // so 'h' can be shadowed on the instance object.
8002  Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
8003  child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
8004      v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
8005
8006  // Add 'i' as an accessor to the instance template with ReadOnly attributes
8007  // but the attribute does not have effect because it is duplicated with
8008  // NULL setter.
8009  child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
8010      v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
8011
8012
8013
8014  // Instantiate the child template.
8015  Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
8016
8017  // Check that the child function overrides the parent one.
8018  context->Global()->Set(v8_str("o"), instance);
8019  Local<Value> value = v8_compile("o.f")->Run();
8020  // Check that the 'g' that was added last is hit.
8021  CHECK_EQ(42, value->Int32Value());
8022  value = v8_compile("o.g")->Run();
8023  CHECK_EQ(42, value->Int32Value());
8024
8025  // Check 'h' can be shadowed.
8026  value = v8_compile("o.h = 3; o.h")->Run();
8027  CHECK_EQ(3, value->Int32Value());
8028
8029  // Check 'i' is cannot be shadowed or changed.
8030  value = v8_compile("o.i = 3; o.i")->Run();
8031  CHECK_EQ(42, value->Int32Value());
8032}
8033
8034
8035static v8::Handle<Value> IsConstructHandler(const v8::Arguments& args) {
8036  ApiTestFuzzer::Fuzz();
8037  if (args.IsConstructCall()) {
8038    return v8::Boolean::New(true);
8039  }
8040  return v8::Boolean::New(false);
8041}
8042
8043
8044THREADED_TEST(IsConstructCall) {
8045  v8::HandleScope scope;
8046
8047  // Function template with call handler.
8048  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
8049  templ->SetCallHandler(IsConstructHandler);
8050
8051  LocalContext context;
8052
8053  context->Global()->Set(v8_str("f"), templ->GetFunction());
8054  Local<Value> value = v8_compile("f()")->Run();
8055  CHECK(!value->BooleanValue());
8056  value = v8_compile("new f()")->Run();
8057  CHECK(value->BooleanValue());
8058}
8059
8060
8061THREADED_TEST(ObjectProtoToString) {
8062  v8::HandleScope scope;
8063  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
8064  templ->SetClassName(v8_str("MyClass"));
8065
8066  LocalContext context;
8067
8068  Local<String> customized_tostring = v8_str("customized toString");
8069
8070  // Replace Object.prototype.toString
8071  v8_compile("Object.prototype.toString = function() {"
8072                  "  return 'customized toString';"
8073                  "}")->Run();
8074
8075  // Normal ToString call should call replaced Object.prototype.toString
8076  Local<v8::Object> instance = templ->GetFunction()->NewInstance();
8077  Local<String> value = instance->ToString();
8078  CHECK(value->IsString() && value->Equals(customized_tostring));
8079
8080  // ObjectProtoToString should not call replace toString function.
8081  value = instance->ObjectProtoToString();
8082  CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
8083
8084  // Check global
8085  value = context->Global()->ObjectProtoToString();
8086  CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
8087
8088  // Check ordinary object
8089  Local<Value> object = v8_compile("new Object()")->Run();
8090  value = object.As<v8::Object>()->ObjectProtoToString();
8091  CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
8092}
8093
8094
8095THREADED_TEST(ObjectGetConstructorName) {
8096  v8::HandleScope scope;
8097  LocalContext context;
8098  v8_compile("function Parent() {};"
8099             "function Child() {};"
8100             "Child.prototype = new Parent();"
8101             "var outer = { inner: function() { } };"
8102             "var p = new Parent();"
8103             "var c = new Child();"
8104             "var x = new outer.inner();")->Run();
8105
8106  Local<v8::Value> p = context->Global()->Get(v8_str("p"));
8107  CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
8108      v8_str("Parent")));
8109
8110  Local<v8::Value> c = context->Global()->Get(v8_str("c"));
8111  CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
8112      v8_str("Child")));
8113
8114  Local<v8::Value> x = context->Global()->Get(v8_str("x"));
8115  CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
8116      v8_str("outer.inner")));
8117}
8118
8119
8120bool ApiTestFuzzer::fuzzing_ = false;
8121i::Semaphore* ApiTestFuzzer::all_tests_done_=
8122  i::OS::CreateSemaphore(0);
8123int ApiTestFuzzer::active_tests_;
8124int ApiTestFuzzer::tests_being_run_;
8125int ApiTestFuzzer::current_;
8126
8127
8128// We are in a callback and want to switch to another thread (if we
8129// are currently running the thread fuzzing test).
8130void ApiTestFuzzer::Fuzz() {
8131  if (!fuzzing_) return;
8132  ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
8133  test->ContextSwitch();
8134}
8135
8136
8137// Let the next thread go.  Since it is also waiting on the V8 lock it may
8138// not start immediately.
8139bool ApiTestFuzzer::NextThread() {
8140  int test_position = GetNextTestNumber();
8141  const char* test_name = RegisterThreadedTest::nth(current_)->name();
8142  if (test_position == current_) {
8143    if (kLogThreading)
8144      printf("Stay with %s\n", test_name);
8145    return false;
8146  }
8147  if (kLogThreading) {
8148    printf("Switch from %s to %s\n",
8149           test_name,
8150           RegisterThreadedTest::nth(test_position)->name());
8151  }
8152  current_ = test_position;
8153  RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal();
8154  return true;
8155}
8156
8157
8158void ApiTestFuzzer::Run() {
8159  // When it is our turn...
8160  gate_->Wait();
8161  {
8162    // ... get the V8 lock and start running the test.
8163    v8::Locker locker;
8164    CallTest();
8165  }
8166  // This test finished.
8167  active_ = false;
8168  active_tests_--;
8169  // If it was the last then signal that fact.
8170  if (active_tests_ == 0) {
8171    all_tests_done_->Signal();
8172  } else {
8173    // Otherwise select a new test and start that.
8174    NextThread();
8175  }
8176}
8177
8178
8179static unsigned linear_congruential_generator;
8180
8181
8182void ApiTestFuzzer::Setup(PartOfTest part) {
8183  linear_congruential_generator = i::FLAG_testing_prng_seed;
8184  fuzzing_ = true;
8185  int start = (part == FIRST_PART) ? 0 : (RegisterThreadedTest::count() >> 1);
8186  int end = (part == FIRST_PART)
8187      ? (RegisterThreadedTest::count() >> 1)
8188      : RegisterThreadedTest::count();
8189  active_tests_ = tests_being_run_ = end - start;
8190  for (int i = 0; i < tests_being_run_; i++) {
8191    RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
8192  }
8193  for (int i = 0; i < active_tests_; i++) {
8194    RegisterThreadedTest::nth(i)->fuzzer_->Start();
8195  }
8196}
8197
8198
8199static void CallTestNumber(int test_number) {
8200  (RegisterThreadedTest::nth(test_number)->callback())();
8201}
8202
8203
8204void ApiTestFuzzer::RunAllTests() {
8205  // Set off the first test.
8206  current_ = -1;
8207  NextThread();
8208  // Wait till they are all done.
8209  all_tests_done_->Wait();
8210}
8211
8212
8213int ApiTestFuzzer::GetNextTestNumber() {
8214  int next_test;
8215  do {
8216    next_test = (linear_congruential_generator >> 16) % tests_being_run_;
8217    linear_congruential_generator *= 1664525u;
8218    linear_congruential_generator += 1013904223u;
8219  } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
8220  return next_test;
8221}
8222
8223
8224void ApiTestFuzzer::ContextSwitch() {
8225  // If the new thread is the same as the current thread there is nothing to do.
8226  if (NextThread()) {
8227    // Now it can start.
8228    v8::Unlocker unlocker;
8229    // Wait till someone starts us again.
8230    gate_->Wait();
8231    // And we're off.
8232  }
8233}
8234
8235
8236void ApiTestFuzzer::TearDown() {
8237  fuzzing_ = false;
8238  for (int i = 0; i < RegisterThreadedTest::count(); i++) {
8239    ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
8240    if (fuzzer != NULL) fuzzer->Join();
8241  }
8242}
8243
8244
8245// Lets not be needlessly self-referential.
8246TEST(Threading) {
8247  ApiTestFuzzer::Setup(ApiTestFuzzer::FIRST_PART);
8248  ApiTestFuzzer::RunAllTests();
8249  ApiTestFuzzer::TearDown();
8250}
8251
8252TEST(Threading2) {
8253  ApiTestFuzzer::Setup(ApiTestFuzzer::SECOND_PART);
8254  ApiTestFuzzer::RunAllTests();
8255  ApiTestFuzzer::TearDown();
8256}
8257
8258
8259void ApiTestFuzzer::CallTest() {
8260  if (kLogThreading)
8261    printf("Start test %d\n", test_number_);
8262  CallTestNumber(test_number_);
8263  if (kLogThreading)
8264    printf("End test %d\n", test_number_);
8265}
8266
8267
8268static v8::Handle<Value> ThrowInJS(const v8::Arguments& args) {
8269  CHECK(v8::Locker::IsLocked());
8270  ApiTestFuzzer::Fuzz();
8271  v8::Unlocker unlocker;
8272  const char* code = "throw 7;";
8273  {
8274    v8::Locker nested_locker;
8275    v8::HandleScope scope;
8276    v8::Handle<Value> exception;
8277    { v8::TryCatch try_catch;
8278      v8::Handle<Value> value = CompileRun(code);
8279      CHECK(value.IsEmpty());
8280      CHECK(try_catch.HasCaught());
8281      // Make sure to wrap the exception in a new handle because
8282      // the handle returned from the TryCatch is destroyed
8283      // when the TryCatch is destroyed.
8284      exception = Local<Value>::New(try_catch.Exception());
8285    }
8286    return v8::ThrowException(exception);
8287  }
8288}
8289
8290
8291static v8::Handle<Value> ThrowInJSNoCatch(const v8::Arguments& args) {
8292  CHECK(v8::Locker::IsLocked());
8293  ApiTestFuzzer::Fuzz();
8294  v8::Unlocker unlocker;
8295  const char* code = "throw 7;";
8296  {
8297    v8::Locker nested_locker;
8298    v8::HandleScope scope;
8299    v8::Handle<Value> value = CompileRun(code);
8300    CHECK(value.IsEmpty());
8301    return v8_str("foo");
8302  }
8303}
8304
8305
8306// These are locking tests that don't need to be run again
8307// as part of the locking aggregation tests.
8308TEST(NestedLockers) {
8309  v8::Locker locker;
8310  CHECK(v8::Locker::IsLocked());
8311  v8::HandleScope scope;
8312  LocalContext env;
8313  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS);
8314  Local<Function> fun = fun_templ->GetFunction();
8315  env->Global()->Set(v8_str("throw_in_js"), fun);
8316  Local<Script> script = v8_compile("(function () {"
8317                                    "  try {"
8318                                    "    throw_in_js();"
8319                                    "    return 42;"
8320                                    "  } catch (e) {"
8321                                    "    return e * 13;"
8322                                    "  }"
8323                                    "})();");
8324  CHECK_EQ(91, script->Run()->Int32Value());
8325}
8326
8327
8328// These are locking tests that don't need to be run again
8329// as part of the locking aggregation tests.
8330TEST(NestedLockersNoTryCatch) {
8331  v8::Locker locker;
8332  v8::HandleScope scope;
8333  LocalContext env;
8334  Local<v8::FunctionTemplate> fun_templ =
8335      v8::FunctionTemplate::New(ThrowInJSNoCatch);
8336  Local<Function> fun = fun_templ->GetFunction();
8337  env->Global()->Set(v8_str("throw_in_js"), fun);
8338  Local<Script> script = v8_compile("(function () {"
8339                                    "  try {"
8340                                    "    throw_in_js();"
8341                                    "    return 42;"
8342                                    "  } catch (e) {"
8343                                    "    return e * 13;"
8344                                    "  }"
8345                                    "})();");
8346  CHECK_EQ(91, script->Run()->Int32Value());
8347}
8348
8349
8350THREADED_TEST(RecursiveLocking) {
8351  v8::Locker locker;
8352  {
8353    v8::Locker locker2;
8354    CHECK(v8::Locker::IsLocked());
8355  }
8356}
8357
8358
8359static v8::Handle<Value> UnlockForAMoment(const v8::Arguments& args) {
8360  ApiTestFuzzer::Fuzz();
8361  v8::Unlocker unlocker;
8362  return v8::Undefined();
8363}
8364
8365
8366THREADED_TEST(LockUnlockLock) {
8367  {
8368    v8::Locker locker;
8369    v8::HandleScope scope;
8370    LocalContext env;
8371    Local<v8::FunctionTemplate> fun_templ =
8372        v8::FunctionTemplate::New(UnlockForAMoment);
8373    Local<Function> fun = fun_templ->GetFunction();
8374    env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
8375    Local<Script> script = v8_compile("(function () {"
8376                                      "  unlock_for_a_moment();"
8377                                      "  return 42;"
8378                                      "})();");
8379    CHECK_EQ(42, script->Run()->Int32Value());
8380  }
8381  {
8382    v8::Locker locker;
8383    v8::HandleScope scope;
8384    LocalContext env;
8385    Local<v8::FunctionTemplate> fun_templ =
8386        v8::FunctionTemplate::New(UnlockForAMoment);
8387    Local<Function> fun = fun_templ->GetFunction();
8388    env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
8389    Local<Script> script = v8_compile("(function () {"
8390                                      "  unlock_for_a_moment();"
8391                                      "  return 42;"
8392                                      "})();");
8393    CHECK_EQ(42, script->Run()->Int32Value());
8394  }
8395}
8396
8397
8398static int GetGlobalObjectsCount() {
8399  int count = 0;
8400  i::HeapIterator it;
8401  for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
8402    if (object->IsJSGlobalObject()) count++;
8403  return count;
8404}
8405
8406
8407static void CheckSurvivingGlobalObjectsCount(int expected) {
8408  // We need to collect all garbage twice to be sure that everything
8409  // has been collected.  This is because inline caches are cleared in
8410  // the first garbage collection but some of the maps have already
8411  // been marked at that point.  Therefore some of the maps are not
8412  // collected until the second garbage collection.
8413  i::Heap::CollectAllGarbage(false);
8414  i::Heap::CollectAllGarbage(false);
8415  int count = GetGlobalObjectsCount();
8416#ifdef DEBUG
8417  if (count != expected) i::Heap::TracePathToGlobal();
8418#endif
8419  CHECK_EQ(expected, count);
8420}
8421
8422
8423TEST(DontLeakGlobalObjects) {
8424  // Regression test for issues 1139850 and 1174891.
8425
8426  v8::V8::Initialize();
8427
8428  for (int i = 0; i < 5; i++) {
8429    { v8::HandleScope scope;
8430      LocalContext context;
8431    }
8432    CheckSurvivingGlobalObjectsCount(0);
8433
8434    { v8::HandleScope scope;
8435      LocalContext context;
8436      v8_compile("Date")->Run();
8437    }
8438    CheckSurvivingGlobalObjectsCount(0);
8439
8440    { v8::HandleScope scope;
8441      LocalContext context;
8442      v8_compile("/aaa/")->Run();
8443    }
8444    CheckSurvivingGlobalObjectsCount(0);
8445
8446    { v8::HandleScope scope;
8447      const char* extension_list[] = { "v8/gc" };
8448      v8::ExtensionConfiguration extensions(1, extension_list);
8449      LocalContext context(&extensions);
8450      v8_compile("gc();")->Run();
8451    }
8452    CheckSurvivingGlobalObjectsCount(0);
8453  }
8454}
8455
8456
8457v8::Persistent<v8::Object> some_object;
8458v8::Persistent<v8::Object> bad_handle;
8459
8460void NewPersistentHandleCallback(v8::Persistent<v8::Value> handle, void*) {
8461  v8::HandleScope scope;
8462  bad_handle = v8::Persistent<v8::Object>::New(some_object);
8463  handle.Dispose();
8464}
8465
8466
8467THREADED_TEST(NewPersistentHandleFromWeakCallback) {
8468  LocalContext context;
8469
8470  v8::Persistent<v8::Object> handle1, handle2;
8471  {
8472    v8::HandleScope scope;
8473    some_object = v8::Persistent<v8::Object>::New(v8::Object::New());
8474    handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
8475    handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
8476  }
8477  // Note: order is implementation dependent alas: currently
8478  // global handle nodes are processed by PostGarbageCollectionProcessing
8479  // in reverse allocation order, so if second allocated handle is deleted,
8480  // weak callback of the first handle would be able to 'reallocate' it.
8481  handle1.MakeWeak(NULL, NewPersistentHandleCallback);
8482  handle2.Dispose();
8483  i::Heap::CollectAllGarbage(false);
8484}
8485
8486
8487v8::Persistent<v8::Object> to_be_disposed;
8488
8489void DisposeAndForceGcCallback(v8::Persistent<v8::Value> handle, void*) {
8490  to_be_disposed.Dispose();
8491  i::Heap::CollectAllGarbage(false);
8492  handle.Dispose();
8493}
8494
8495
8496THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
8497  LocalContext context;
8498
8499  v8::Persistent<v8::Object> handle1, handle2;
8500  {
8501    v8::HandleScope scope;
8502    handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
8503    handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
8504  }
8505  handle1.MakeWeak(NULL, DisposeAndForceGcCallback);
8506  to_be_disposed = handle2;
8507  i::Heap::CollectAllGarbage(false);
8508}
8509
8510void DisposingCallback(v8::Persistent<v8::Value> handle, void*) {
8511  handle.Dispose();
8512}
8513
8514void HandleCreatingCallback(v8::Persistent<v8::Value> handle, void*) {
8515  v8::HandleScope scope;
8516  v8::Persistent<v8::Object>::New(v8::Object::New());
8517  handle.Dispose();
8518}
8519
8520
8521THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
8522  LocalContext context;
8523
8524  v8::Persistent<v8::Object> handle1, handle2, handle3;
8525  {
8526    v8::HandleScope scope;
8527    handle3 = v8::Persistent<v8::Object>::New(v8::Object::New());
8528    handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
8529    handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
8530  }
8531  handle2.MakeWeak(NULL, DisposingCallback);
8532  handle3.MakeWeak(NULL, HandleCreatingCallback);
8533  i::Heap::CollectAllGarbage(false);
8534}
8535
8536
8537THREADED_TEST(CheckForCrossContextObjectLiterals) {
8538  v8::V8::Initialize();
8539
8540  const int nof = 2;
8541  const char* sources[nof] = {
8542    "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
8543    "Object()"
8544  };
8545
8546  for (int i = 0; i < nof; i++) {
8547    const char* source = sources[i];
8548    { v8::HandleScope scope;
8549      LocalContext context;
8550      CompileRun(source);
8551    }
8552    { v8::HandleScope scope;
8553      LocalContext context;
8554      CompileRun(source);
8555    }
8556  }
8557}
8558
8559
8560static v8::Handle<Value> NestedScope(v8::Persistent<Context> env) {
8561  v8::HandleScope inner;
8562  env->Enter();
8563  v8::Handle<Value> three = v8_num(3);
8564  v8::Handle<Value> value = inner.Close(three);
8565  env->Exit();
8566  return value;
8567}
8568
8569
8570THREADED_TEST(NestedHandleScopeAndContexts) {
8571  v8::HandleScope outer;
8572  v8::Persistent<Context> env = Context::New();
8573  env->Enter();
8574  v8::Handle<Value> value = NestedScope(env);
8575  v8::Handle<String> str = value->ToString();
8576  env->Exit();
8577  env.Dispose();
8578}
8579
8580
8581THREADED_TEST(ExternalAllocatedMemory) {
8582  v8::HandleScope outer;
8583  v8::Persistent<Context> env = Context::New();
8584  const int kSize = 1024*1024;
8585  CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize), kSize);
8586  CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize), 0);
8587}
8588
8589
8590THREADED_TEST(DisposeEnteredContext) {
8591  v8::HandleScope scope;
8592  LocalContext outer;
8593  { v8::Persistent<v8::Context> inner = v8::Context::New();
8594    inner->Enter();
8595    inner.Dispose();
8596    inner.Clear();
8597    inner->Exit();
8598  }
8599}
8600
8601
8602// Regression test for issue 54, object templates with internal fields
8603// but no accessors or interceptors did not get their internal field
8604// count set on instances.
8605THREADED_TEST(Regress54) {
8606  v8::HandleScope outer;
8607  LocalContext context;
8608  static v8::Persistent<v8::ObjectTemplate> templ;
8609  if (templ.IsEmpty()) {
8610    v8::HandleScope inner;
8611    v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New();
8612    local->SetInternalFieldCount(1);
8613    templ = v8::Persistent<v8::ObjectTemplate>::New(inner.Close(local));
8614  }
8615  v8::Handle<v8::Object> result = templ->NewInstance();
8616  CHECK_EQ(1, result->InternalFieldCount());
8617}
8618
8619
8620// If part of the threaded tests, this test makes ThreadingTest fail
8621// on mac.
8622TEST(CatchStackOverflow) {
8623  v8::HandleScope scope;
8624  LocalContext context;
8625  v8::TryCatch try_catch;
8626  v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(
8627    "function f() {"
8628    "  return f();"
8629    "}"
8630    ""
8631    "f();"));
8632  v8::Handle<v8::Value> result = script->Run();
8633  CHECK(result.IsEmpty());
8634}
8635
8636
8637static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
8638                                    const char* resource_name,
8639                                    int line_offset) {
8640  v8::HandleScope scope;
8641  v8::TryCatch try_catch;
8642  v8::Handle<v8::Value> result = script->Run();
8643  CHECK(result.IsEmpty());
8644  CHECK(try_catch.HasCaught());
8645  v8::Handle<v8::Message> message = try_catch.Message();
8646  CHECK(!message.IsEmpty());
8647  CHECK_EQ(10 + line_offset, message->GetLineNumber());
8648  CHECK_EQ(91, message->GetStartPosition());
8649  CHECK_EQ(92, message->GetEndPosition());
8650  CHECK_EQ(2, message->GetStartColumn());
8651  CHECK_EQ(3, message->GetEndColumn());
8652  v8::String::AsciiValue line(message->GetSourceLine());
8653  CHECK_EQ("  throw 'nirk';", *line);
8654  v8::String::AsciiValue name(message->GetScriptResourceName());
8655  CHECK_EQ(resource_name, *name);
8656}
8657
8658
8659THREADED_TEST(TryCatchSourceInfo) {
8660  v8::HandleScope scope;
8661  LocalContext context;
8662  v8::Handle<v8::String> source = v8::String::New(
8663      "function Foo() {\n"
8664      "  return Bar();\n"
8665      "}\n"
8666      "\n"
8667      "function Bar() {\n"
8668      "  return Baz();\n"
8669      "}\n"
8670      "\n"
8671      "function Baz() {\n"
8672      "  throw 'nirk';\n"
8673      "}\n"
8674      "\n"
8675      "Foo();\n");
8676
8677  const char* resource_name;
8678  v8::Handle<v8::Script> script;
8679  resource_name = "test.js";
8680  script = v8::Script::Compile(source, v8::String::New(resource_name));
8681  CheckTryCatchSourceInfo(script, resource_name, 0);
8682
8683  resource_name = "test1.js";
8684  v8::ScriptOrigin origin1(v8::String::New(resource_name));
8685  script = v8::Script::Compile(source, &origin1);
8686  CheckTryCatchSourceInfo(script, resource_name, 0);
8687
8688  resource_name = "test2.js";
8689  v8::ScriptOrigin origin2(v8::String::New(resource_name), v8::Integer::New(7));
8690  script = v8::Script::Compile(source, &origin2);
8691  CheckTryCatchSourceInfo(script, resource_name, 7);
8692}
8693
8694
8695THREADED_TEST(CompilationCache) {
8696  v8::HandleScope scope;
8697  LocalContext context;
8698  v8::Handle<v8::String> source0 = v8::String::New("1234");
8699  v8::Handle<v8::String> source1 = v8::String::New("1234");
8700  v8::Handle<v8::Script> script0 =
8701      v8::Script::Compile(source0, v8::String::New("test.js"));
8702  v8::Handle<v8::Script> script1 =
8703      v8::Script::Compile(source1, v8::String::New("test.js"));
8704  v8::Handle<v8::Script> script2 =
8705      v8::Script::Compile(source0);  // different origin
8706  CHECK_EQ(1234, script0->Run()->Int32Value());
8707  CHECK_EQ(1234, script1->Run()->Int32Value());
8708  CHECK_EQ(1234, script2->Run()->Int32Value());
8709}
8710
8711
8712static v8::Handle<Value> FunctionNameCallback(const v8::Arguments& args) {
8713  ApiTestFuzzer::Fuzz();
8714  return v8_num(42);
8715}
8716
8717
8718THREADED_TEST(CallbackFunctionName) {
8719  v8::HandleScope scope;
8720  LocalContext context;
8721  Local<ObjectTemplate> t = ObjectTemplate::New();
8722  t->Set(v8_str("asdf"), v8::FunctionTemplate::New(FunctionNameCallback));
8723  context->Global()->Set(v8_str("obj"), t->NewInstance());
8724  v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
8725  CHECK(value->IsString());
8726  v8::String::AsciiValue name(value);
8727  CHECK_EQ("asdf", *name);
8728}
8729
8730
8731THREADED_TEST(DateAccess) {
8732  v8::HandleScope scope;
8733  LocalContext context;
8734  v8::Handle<v8::Value> date = v8::Date::New(1224744689038.0);
8735  CHECK(date->IsDate());
8736  CHECK_EQ(1224744689038.0, date.As<v8::Date>()->NumberValue());
8737}
8738
8739
8740void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) {
8741  v8::Handle<v8::Object> obj = val.As<v8::Object>();
8742  v8::Handle<v8::Array> props = obj->GetPropertyNames();
8743  CHECK_EQ(elmc, props->Length());
8744  for (int i = 0; i < elmc; i++) {
8745    v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
8746    CHECK_EQ(elmv[i], *elm);
8747  }
8748}
8749
8750
8751THREADED_TEST(PropertyEnumeration) {
8752  v8::HandleScope scope;
8753  LocalContext context;
8754  v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
8755      "var result = [];"
8756      "result[0] = {};"
8757      "result[1] = {a: 1, b: 2};"
8758      "result[2] = [1, 2, 3];"
8759      "var proto = {x: 1, y: 2, z: 3};"
8760      "var x = { __proto__: proto, w: 0, z: 1 };"
8761      "result[3] = x;"
8762      "result;"))->Run();
8763  v8::Handle<v8::Array> elms = obj.As<v8::Array>();
8764  CHECK_EQ(4, elms->Length());
8765  int elmc0 = 0;
8766  const char** elmv0 = NULL;
8767  CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
8768  int elmc1 = 2;
8769  const char* elmv1[] = {"a", "b"};
8770  CheckProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
8771  int elmc2 = 3;
8772  const char* elmv2[] = {"0", "1", "2"};
8773  CheckProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
8774  int elmc3 = 4;
8775  const char* elmv3[] = {"w", "z", "x", "y"};
8776  CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3);
8777}
8778
8779
8780static bool NamedSetAccessBlocker(Local<v8::Object> obj,
8781                                  Local<Value> name,
8782                                  v8::AccessType type,
8783                                  Local<Value> data) {
8784  return type != v8::ACCESS_SET;
8785}
8786
8787
8788static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
8789                                    uint32_t key,
8790                                    v8::AccessType type,
8791                                    Local<Value> data) {
8792  return type != v8::ACCESS_SET;
8793}
8794
8795
8796THREADED_TEST(DisableAccessChecksWhileConfiguring) {
8797  v8::HandleScope scope;
8798  LocalContext context;
8799  Local<ObjectTemplate> templ = ObjectTemplate::New();
8800  templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
8801                                 IndexedSetAccessBlocker);
8802  templ->Set(v8_str("x"), v8::True());
8803  Local<v8::Object> instance = templ->NewInstance();
8804  context->Global()->Set(v8_str("obj"), instance);
8805  Local<Value> value = CompileRun("obj.x");
8806  CHECK(value->BooleanValue());
8807}
8808
8809
8810static bool NamedGetAccessBlocker(Local<v8::Object> obj,
8811                                  Local<Value> name,
8812                                  v8::AccessType type,
8813                                  Local<Value> data) {
8814  return false;
8815}
8816
8817
8818static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
8819                                    uint32_t key,
8820                                    v8::AccessType type,
8821                                    Local<Value> data) {
8822  return false;
8823}
8824
8825
8826
8827THREADED_TEST(AccessChecksReenabledCorrectly) {
8828  v8::HandleScope scope;
8829  LocalContext context;
8830  Local<ObjectTemplate> templ = ObjectTemplate::New();
8831  templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
8832                                 IndexedGetAccessBlocker);
8833  templ->Set(v8_str("a"), v8_str("a"));
8834  // Add more than 8 (see kMaxFastProperties) properties
8835  // so that the constructor will force copying map.
8836  // Cannot sprintf, gcc complains unsafety.
8837  char buf[4];
8838  for (char i = '0'; i <= '9' ; i++) {
8839    buf[0] = i;
8840    for (char j = '0'; j <= '9'; j++) {
8841      buf[1] = j;
8842      for (char k = '0'; k <= '9'; k++) {
8843        buf[2] = k;
8844        buf[3] = 0;
8845        templ->Set(v8_str(buf), v8::Number::New(k));
8846      }
8847    }
8848  }
8849
8850  Local<v8::Object> instance_1 = templ->NewInstance();
8851  context->Global()->Set(v8_str("obj_1"), instance_1);
8852
8853  Local<Value> value_1 = CompileRun("obj_1.a");
8854  CHECK(value_1->IsUndefined());
8855
8856  Local<v8::Object> instance_2 = templ->NewInstance();
8857  context->Global()->Set(v8_str("obj_2"), instance_2);
8858
8859  Local<Value> value_2 = CompileRun("obj_2.a");
8860  CHECK(value_2->IsUndefined());
8861}
8862
8863
8864// This tests that access check information remains on the global
8865// object template when creating contexts.
8866THREADED_TEST(AccessControlRepeatedContextCreation) {
8867  v8::HandleScope handle_scope;
8868  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
8869  global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
8870                                           IndexedSetAccessBlocker);
8871  i::Handle<i::ObjectTemplateInfo> internal_template =
8872      v8::Utils::OpenHandle(*global_template);
8873  CHECK(!internal_template->constructor()->IsUndefined());
8874  i::Handle<i::FunctionTemplateInfo> constructor(
8875      i::FunctionTemplateInfo::cast(internal_template->constructor()));
8876  CHECK(!constructor->access_check_info()->IsUndefined());
8877  v8::Persistent<Context> context0 = Context::New(NULL, global_template);
8878  CHECK(!constructor->access_check_info()->IsUndefined());
8879}
8880
8881
8882THREADED_TEST(TurnOnAccessCheck) {
8883  v8::HandleScope handle_scope;
8884
8885  // Create an environment with access check to the global object disabled by
8886  // default.
8887  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
8888  global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
8889                                           IndexedGetAccessBlocker,
8890                                           v8::Handle<v8::Value>(),
8891                                           false);
8892  v8::Persistent<Context> context = Context::New(NULL, global_template);
8893  Context::Scope context_scope(context);
8894
8895  // Set up a property and a number of functions.
8896  context->Global()->Set(v8_str("a"), v8_num(1));
8897  CompileRun("function f1() {return a;}"
8898             "function f2() {return a;}"
8899             "function g1() {return h();}"
8900             "function g2() {return h();}"
8901             "function h() {return 1;}");
8902  Local<Function> f1 =
8903      Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
8904  Local<Function> f2 =
8905      Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
8906  Local<Function> g1 =
8907      Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
8908  Local<Function> g2 =
8909      Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
8910  Local<Function> h =
8911      Local<Function>::Cast(context->Global()->Get(v8_str("h")));
8912
8913  // Get the global object.
8914  v8::Handle<v8::Object> global = context->Global();
8915
8916  // Call f1 one time and f2 a number of times. This will ensure that f1 still
8917  // uses the runtime system to retreive property a whereas f2 uses global load
8918  // inline cache.
8919  CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
8920  for (int i = 0; i < 4; i++) {
8921    CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
8922  }
8923
8924  // Same for g1 and g2.
8925  CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
8926  for (int i = 0; i < 4; i++) {
8927    CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
8928  }
8929
8930  // Detach the global and turn on access check.
8931  context->DetachGlobal();
8932  context->Global()->TurnOnAccessCheck();
8933
8934  // Failing access check to property get results in undefined.
8935  CHECK(f1->Call(global, 0, NULL)->IsUndefined());
8936  CHECK(f2->Call(global, 0, NULL)->IsUndefined());
8937
8938  // Failing access check to function call results in exception.
8939  CHECK(g1->Call(global, 0, NULL).IsEmpty());
8940  CHECK(g2->Call(global, 0, NULL).IsEmpty());
8941
8942  // No failing access check when just returning a constant.
8943  CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
8944}
8945
8946
8947v8::Handle<v8::String> a;
8948v8::Handle<v8::String> h;
8949
8950static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
8951                                       Local<Value> name,
8952                                       v8::AccessType type,
8953                                       Local<Value> data) {
8954  return !(name->Equals(a) || name->Equals(h));
8955}
8956
8957
8958THREADED_TEST(TurnOnAccessCheckAndRecompile) {
8959  v8::HandleScope handle_scope;
8960
8961  // Create an environment with access check to the global object disabled by
8962  // default. When the registered access checker will block access to properties
8963  // a and h
8964  a = v8_str("a");
8965  h = v8_str("h");
8966  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
8967  global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
8968                                           IndexedGetAccessBlocker,
8969                                           v8::Handle<v8::Value>(),
8970                                           false);
8971  v8::Persistent<Context> context = Context::New(NULL, global_template);
8972  Context::Scope context_scope(context);
8973
8974  // Set up a property and a number of functions.
8975  context->Global()->Set(v8_str("a"), v8_num(1));
8976  static const char* source = "function f1() {return a;}"
8977                              "function f2() {return a;}"
8978                              "function g1() {return h();}"
8979                              "function g2() {return h();}"
8980                              "function h() {return 1;}";
8981
8982  CompileRun(source);
8983  Local<Function> f1;
8984  Local<Function> f2;
8985  Local<Function> g1;
8986  Local<Function> g2;
8987  Local<Function> h;
8988  f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
8989  f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
8990  g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
8991  g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
8992  h =  Local<Function>::Cast(context->Global()->Get(v8_str("h")));
8993
8994  // Get the global object.
8995  v8::Handle<v8::Object> global = context->Global();
8996
8997  // Call f1 one time and f2 a number of times. This will ensure that f1 still
8998  // uses the runtime system to retreive property a whereas f2 uses global load
8999  // inline cache.
9000  CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
9001  for (int i = 0; i < 4; i++) {
9002    CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
9003  }
9004
9005  // Same for g1 and g2.
9006  CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
9007  for (int i = 0; i < 4; i++) {
9008    CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
9009  }
9010
9011  // Detach the global and turn on access check now blocking access to property
9012  // a and function h.
9013  context->DetachGlobal();
9014  context->Global()->TurnOnAccessCheck();
9015
9016  // Failing access check to property get results in undefined.
9017  CHECK(f1->Call(global, 0, NULL)->IsUndefined());
9018  CHECK(f2->Call(global, 0, NULL)->IsUndefined());
9019
9020  // Failing access check to function call results in exception.
9021  CHECK(g1->Call(global, 0, NULL).IsEmpty());
9022  CHECK(g2->Call(global, 0, NULL).IsEmpty());
9023
9024  // No failing access check when just returning a constant.
9025  CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
9026
9027  // Now compile the source again. And get the newly compiled functions, except
9028  // for h for which access is blocked.
9029  CompileRun(source);
9030  f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
9031  f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
9032  g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
9033  g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
9034  CHECK(context->Global()->Get(v8_str("h"))->IsUndefined());
9035
9036  // Failing access check to property get results in undefined.
9037  CHECK(f1->Call(global, 0, NULL)->IsUndefined());
9038  CHECK(f2->Call(global, 0, NULL)->IsUndefined());
9039
9040  // Failing access check to function call results in exception.
9041  CHECK(g1->Call(global, 0, NULL).IsEmpty());
9042  CHECK(g2->Call(global, 0, NULL).IsEmpty());
9043}
9044
9045
9046// This test verifies that pre-compilation (aka preparsing) can be called
9047// without initializing the whole VM. Thus we cannot run this test in a
9048// multi-threaded setup.
9049TEST(PreCompile) {
9050  // TODO(155): This test would break without the initialization of V8. This is
9051  // a workaround for now to make this test not fail.
9052  v8::V8::Initialize();
9053  const char* script = "function foo(a) { return a+1; }";
9054  v8::ScriptData* sd =
9055      v8::ScriptData::PreCompile(script, i::StrLength(script));
9056  CHECK_NE(sd->Length(), 0);
9057  CHECK_NE(sd->Data(), NULL);
9058  CHECK(!sd->HasError());
9059  delete sd;
9060}
9061
9062
9063TEST(PreCompileWithError) {
9064  v8::V8::Initialize();
9065  const char* script = "function foo(a) { return 1 * * 2; }";
9066  v8::ScriptData* sd =
9067      v8::ScriptData::PreCompile(script, i::StrLength(script));
9068  CHECK(sd->HasError());
9069  delete sd;
9070}
9071
9072
9073TEST(Regress31661) {
9074  v8::V8::Initialize();
9075  const char* script = " The Definintive Guide";
9076  v8::ScriptData* sd =
9077      v8::ScriptData::PreCompile(script, i::StrLength(script));
9078  CHECK(sd->HasError());
9079  delete sd;
9080}
9081
9082
9083// Tests that ScriptData can be serialized and deserialized.
9084TEST(PreCompileSerialization) {
9085  v8::V8::Initialize();
9086  const char* script = "function foo(a) { return a+1; }";
9087  v8::ScriptData* sd =
9088      v8::ScriptData::PreCompile(script, i::StrLength(script));
9089
9090  // Serialize.
9091  int serialized_data_length = sd->Length();
9092  char* serialized_data = i::NewArray<char>(serialized_data_length);
9093  memcpy(serialized_data, sd->Data(), serialized_data_length);
9094
9095  // Deserialize.
9096  v8::ScriptData* deserialized_sd =
9097      v8::ScriptData::New(serialized_data, serialized_data_length);
9098
9099  // Verify that the original is the same as the deserialized.
9100  CHECK_EQ(sd->Length(), deserialized_sd->Length());
9101  CHECK_EQ(0, memcmp(sd->Data(), deserialized_sd->Data(), sd->Length()));
9102  CHECK_EQ(sd->HasError(), deserialized_sd->HasError());
9103
9104  delete sd;
9105  delete deserialized_sd;
9106}
9107
9108
9109// Attempts to deserialize bad data.
9110TEST(PreCompileDeserializationError) {
9111  v8::V8::Initialize();
9112  const char* data = "DONT CARE";
9113  int invalid_size = 3;
9114  v8::ScriptData* sd = v8::ScriptData::New(data, invalid_size);
9115
9116  CHECK_EQ(0, sd->Length());
9117
9118  delete sd;
9119}
9120
9121
9122// Attempts to deserialize bad data.
9123TEST(PreCompileInvalidPreparseDataError) {
9124  v8::V8::Initialize();
9125  v8::HandleScope scope;
9126  LocalContext context;
9127
9128  const char* script = "function foo(){ return 5;}\n"
9129      "function bar(){ return 6 + 7;}  foo();";
9130  v8::ScriptData* sd =
9131      v8::ScriptData::PreCompile(script, i::StrLength(script));
9132  CHECK(!sd->HasError());
9133  // ScriptDataImpl private implementation details
9134  const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
9135  const int kFunctionEntrySize = i::FunctionEntry::kSize;
9136  const int kFunctionEntryStartOffset = 0;
9137  const int kFunctionEntryEndOffset = 1;
9138  unsigned* sd_data =
9139      reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
9140
9141  // Overwrite function bar's end position with 0.
9142  sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
9143  v8::TryCatch try_catch;
9144
9145  Local<String> source = String::New(script);
9146  Local<Script> compiled_script = Script::New(source, NULL, sd);
9147  CHECK(try_catch.HasCaught());
9148  String::AsciiValue exception_value(try_catch.Message()->Get());
9149  CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
9150           *exception_value);
9151
9152  try_catch.Reset();
9153  // Overwrite function bar's start position with 200.  The function entry
9154  // will not be found when searching for it by position.
9155  sd = v8::ScriptData::PreCompile(script, i::StrLength(script));
9156  sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
9157  sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
9158      200;
9159  compiled_script = Script::New(source, NULL, sd);
9160  CHECK(try_catch.HasCaught());
9161  String::AsciiValue second_exception_value(try_catch.Message()->Get());
9162  CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
9163           *second_exception_value);
9164
9165  delete sd;
9166}
9167
9168
9169// Verifies that the Handle<String> and const char* versions of the API produce
9170// the same results (at least for one trivial case).
9171TEST(PreCompileAPIVariationsAreSame) {
9172  v8::V8::Initialize();
9173  v8::HandleScope scope;
9174
9175  const char* cstring = "function foo(a) { return a+1; }";
9176
9177  v8::ScriptData* sd_from_cstring =
9178      v8::ScriptData::PreCompile(cstring, i::StrLength(cstring));
9179
9180  TestAsciiResource* resource = new TestAsciiResource(cstring);
9181  v8::ScriptData* sd_from_external_string = v8::ScriptData::PreCompile(
9182      v8::String::NewExternal(resource));
9183
9184  v8::ScriptData* sd_from_string = v8::ScriptData::PreCompile(
9185      v8::String::New(cstring));
9186
9187  CHECK_EQ(sd_from_cstring->Length(), sd_from_external_string->Length());
9188  CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
9189                     sd_from_external_string->Data(),
9190                     sd_from_cstring->Length()));
9191
9192  CHECK_EQ(sd_from_cstring->Length(), sd_from_string->Length());
9193  CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
9194                     sd_from_string->Data(),
9195                     sd_from_cstring->Length()));
9196
9197
9198  delete sd_from_cstring;
9199  delete sd_from_external_string;
9200  delete sd_from_string;
9201}
9202
9203
9204// This tests that we do not allow dictionary load/call inline caches
9205// to use functions that have not yet been compiled.  The potential
9206// problem of loading a function that has not yet been compiled can
9207// arise because we share code between contexts via the compilation
9208// cache.
9209THREADED_TEST(DictionaryICLoadedFunction) {
9210  v8::HandleScope scope;
9211  // Test LoadIC.
9212  for (int i = 0; i < 2; i++) {
9213    LocalContext context;
9214    context->Global()->Set(v8_str("tmp"), v8::True());
9215    context->Global()->Delete(v8_str("tmp"));
9216    CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
9217  }
9218  // Test CallIC.
9219  for (int i = 0; i < 2; i++) {
9220    LocalContext context;
9221    context->Global()->Set(v8_str("tmp"), v8::True());
9222    context->Global()->Delete(v8_str("tmp"));
9223    CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
9224  }
9225}
9226
9227
9228// Test that cross-context new calls use the context of the callee to
9229// create the new JavaScript object.
9230THREADED_TEST(CrossContextNew) {
9231  v8::HandleScope scope;
9232  v8::Persistent<Context> context0 = Context::New();
9233  v8::Persistent<Context> context1 = Context::New();
9234
9235  // Allow cross-domain access.
9236  Local<String> token = v8_str("<security token>");
9237  context0->SetSecurityToken(token);
9238  context1->SetSecurityToken(token);
9239
9240  // Set an 'x' property on the Object prototype and define a
9241  // constructor function in context0.
9242  context0->Enter();
9243  CompileRun("Object.prototype.x = 42; function C() {};");
9244  context0->Exit();
9245
9246  // Call the constructor function from context0 and check that the
9247  // result has the 'x' property.
9248  context1->Enter();
9249  context1->Global()->Set(v8_str("other"), context0->Global());
9250  Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
9251  CHECK(value->IsInt32());
9252  CHECK_EQ(42, value->Int32Value());
9253  context1->Exit();
9254
9255  // Dispose the contexts to allow them to be garbage collected.
9256  context0.Dispose();
9257  context1.Dispose();
9258}
9259
9260
9261class RegExpInterruptTest {
9262 public:
9263  RegExpInterruptTest() : block_(NULL) {}
9264  ~RegExpInterruptTest() { delete block_; }
9265  void RunTest() {
9266    block_ = i::OS::CreateSemaphore(0);
9267    gc_count_ = 0;
9268    gc_during_regexp_ = 0;
9269    regexp_success_ = false;
9270    gc_success_ = false;
9271    GCThread gc_thread(this);
9272    gc_thread.Start();
9273    v8::Locker::StartPreemption(1);
9274
9275    LongRunningRegExp();
9276    {
9277      v8::Unlocker unlock;
9278      gc_thread.Join();
9279    }
9280    v8::Locker::StopPreemption();
9281    CHECK(regexp_success_);
9282    CHECK(gc_success_);
9283  }
9284 private:
9285  // Number of garbage collections required.
9286  static const int kRequiredGCs = 5;
9287
9288  class GCThread : public i::Thread {
9289   public:
9290    explicit GCThread(RegExpInterruptTest* test)
9291        : test_(test) {}
9292    virtual void Run() {
9293      test_->CollectGarbage();
9294    }
9295   private:
9296     RegExpInterruptTest* test_;
9297  };
9298
9299  void CollectGarbage() {
9300    block_->Wait();
9301    while (gc_during_regexp_ < kRequiredGCs) {
9302      {
9303        v8::Locker lock;
9304        // TODO(lrn): Perhaps create some garbage before collecting.
9305        i::Heap::CollectAllGarbage(false);
9306        gc_count_++;
9307      }
9308      i::OS::Sleep(1);
9309    }
9310    gc_success_ = true;
9311  }
9312
9313  void LongRunningRegExp() {
9314    block_->Signal();  // Enable garbage collection thread on next preemption.
9315    int rounds = 0;
9316    while (gc_during_regexp_ < kRequiredGCs) {
9317      int gc_before = gc_count_;
9318      {
9319        // Match 15-30 "a"'s against 14 and a "b".
9320        const char* c_source =
9321            "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
9322            ".exec('aaaaaaaaaaaaaaab') === null";
9323        Local<String> source = String::New(c_source);
9324        Local<Script> script = Script::Compile(source);
9325        Local<Value> result = script->Run();
9326        if (!result->BooleanValue()) {
9327          gc_during_regexp_ = kRequiredGCs;  // Allow gc thread to exit.
9328          return;
9329        }
9330      }
9331      {
9332        // Match 15-30 "a"'s against 15 and a "b".
9333        const char* c_source =
9334            "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
9335            ".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'";
9336        Local<String> source = String::New(c_source);
9337        Local<Script> script = Script::Compile(source);
9338        Local<Value> result = script->Run();
9339        if (!result->BooleanValue()) {
9340          gc_during_regexp_ = kRequiredGCs;
9341          return;
9342        }
9343      }
9344      int gc_after = gc_count_;
9345      gc_during_regexp_ += gc_after - gc_before;
9346      rounds++;
9347      i::OS::Sleep(1);
9348    }
9349    regexp_success_ = true;
9350  }
9351
9352  i::Semaphore* block_;
9353  int gc_count_;
9354  int gc_during_regexp_;
9355  bool regexp_success_;
9356  bool gc_success_;
9357};
9358
9359
9360// Test that a regular expression execution can be interrupted and
9361// survive a garbage collection.
9362TEST(RegExpInterruption) {
9363  v8::Locker lock;
9364  v8::V8::Initialize();
9365  v8::HandleScope scope;
9366  Local<Context> local_env;
9367  {
9368    LocalContext env;
9369    local_env = env.local();
9370  }
9371
9372  // Local context should still be live.
9373  CHECK(!local_env.IsEmpty());
9374  local_env->Enter();
9375
9376  // Should complete without problems.
9377  RegExpInterruptTest().RunTest();
9378
9379  local_env->Exit();
9380}
9381
9382
9383class ApplyInterruptTest {
9384 public:
9385  ApplyInterruptTest() : block_(NULL) {}
9386  ~ApplyInterruptTest() { delete block_; }
9387  void RunTest() {
9388    block_ = i::OS::CreateSemaphore(0);
9389    gc_count_ = 0;
9390    gc_during_apply_ = 0;
9391    apply_success_ = false;
9392    gc_success_ = false;
9393    GCThread gc_thread(this);
9394    gc_thread.Start();
9395    v8::Locker::StartPreemption(1);
9396
9397    LongRunningApply();
9398    {
9399      v8::Unlocker unlock;
9400      gc_thread.Join();
9401    }
9402    v8::Locker::StopPreemption();
9403    CHECK(apply_success_);
9404    CHECK(gc_success_);
9405  }
9406 private:
9407  // Number of garbage collections required.
9408  static const int kRequiredGCs = 2;
9409
9410  class GCThread : public i::Thread {
9411   public:
9412    explicit GCThread(ApplyInterruptTest* test)
9413        : test_(test) {}
9414    virtual void Run() {
9415      test_->CollectGarbage();
9416    }
9417   private:
9418     ApplyInterruptTest* test_;
9419  };
9420
9421  void CollectGarbage() {
9422    block_->Wait();
9423    while (gc_during_apply_ < kRequiredGCs) {
9424      {
9425        v8::Locker lock;
9426        i::Heap::CollectAllGarbage(false);
9427        gc_count_++;
9428      }
9429      i::OS::Sleep(1);
9430    }
9431    gc_success_ = true;
9432  }
9433
9434  void LongRunningApply() {
9435    block_->Signal();
9436    int rounds = 0;
9437    while (gc_during_apply_ < kRequiredGCs) {
9438      int gc_before = gc_count_;
9439      {
9440        const char* c_source =
9441            "function do_very_little(bar) {"
9442            "  this.foo = bar;"
9443            "}"
9444            "for (var i = 0; i < 100000; i++) {"
9445            "  do_very_little.apply(this, ['bar']);"
9446            "}";
9447        Local<String> source = String::New(c_source);
9448        Local<Script> script = Script::Compile(source);
9449        Local<Value> result = script->Run();
9450        // Check that no exception was thrown.
9451        CHECK(!result.IsEmpty());
9452      }
9453      int gc_after = gc_count_;
9454      gc_during_apply_ += gc_after - gc_before;
9455      rounds++;
9456    }
9457    apply_success_ = true;
9458  }
9459
9460  i::Semaphore* block_;
9461  int gc_count_;
9462  int gc_during_apply_;
9463  bool apply_success_;
9464  bool gc_success_;
9465};
9466
9467
9468// Test that nothing bad happens if we get a preemption just when we were
9469// about to do an apply().
9470TEST(ApplyInterruption) {
9471  v8::Locker lock;
9472  v8::V8::Initialize();
9473  v8::HandleScope scope;
9474  Local<Context> local_env;
9475  {
9476    LocalContext env;
9477    local_env = env.local();
9478  }
9479
9480  // Local context should still be live.
9481  CHECK(!local_env.IsEmpty());
9482  local_env->Enter();
9483
9484  // Should complete without problems.
9485  ApplyInterruptTest().RunTest();
9486
9487  local_env->Exit();
9488}
9489
9490
9491// Verify that we can clone an object
9492TEST(ObjectClone) {
9493  v8::HandleScope scope;
9494  LocalContext env;
9495
9496  const char* sample =
9497    "var rv = {};"      \
9498    "rv.alpha = 'hello';" \
9499    "rv.beta = 123;"     \
9500    "rv;";
9501
9502  // Create an object, verify basics.
9503  Local<Value> val = CompileRun(sample);
9504  CHECK(val->IsObject());
9505  Local<v8::Object> obj = val.As<v8::Object>();
9506  obj->Set(v8_str("gamma"), v8_str("cloneme"));
9507
9508  CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
9509  CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
9510  CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
9511
9512  // Clone it.
9513  Local<v8::Object> clone = obj->Clone();
9514  CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
9515  CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta")));
9516  CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
9517
9518  // Set a property on the clone, verify each object.
9519  clone->Set(v8_str("beta"), v8::Integer::New(456));
9520  CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
9521  CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta")));
9522}
9523
9524
9525class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
9526 public:
9527  explicit AsciiVectorResource(i::Vector<const char> vector)
9528      : data_(vector) {}
9529  virtual ~AsciiVectorResource() {}
9530  virtual size_t length() const { return data_.length(); }
9531  virtual const char* data() const { return data_.start(); }
9532 private:
9533  i::Vector<const char> data_;
9534};
9535
9536
9537class UC16VectorResource : public v8::String::ExternalStringResource {
9538 public:
9539  explicit UC16VectorResource(i::Vector<const i::uc16> vector)
9540      : data_(vector) {}
9541  virtual ~UC16VectorResource() {}
9542  virtual size_t length() const { return data_.length(); }
9543  virtual const i::uc16* data() const { return data_.start(); }
9544 private:
9545  i::Vector<const i::uc16> data_;
9546};
9547
9548
9549static void MorphAString(i::String* string,
9550                         AsciiVectorResource* ascii_resource,
9551                         UC16VectorResource* uc16_resource) {
9552  CHECK(i::StringShape(string).IsExternal());
9553  if (string->IsAsciiRepresentation()) {
9554    // Check old map is not symbol or long.
9555    CHECK(string->map() == i::Heap::external_ascii_string_map());
9556    // Morph external string to be TwoByte string.
9557    string->set_map(i::Heap::external_string_map());
9558    i::ExternalTwoByteString* morphed =
9559         i::ExternalTwoByteString::cast(string);
9560    morphed->set_resource(uc16_resource);
9561  } else {
9562    // Check old map is not symbol or long.
9563    CHECK(string->map() == i::Heap::external_string_map());
9564    // Morph external string to be ASCII string.
9565    string->set_map(i::Heap::external_ascii_string_map());
9566    i::ExternalAsciiString* morphed =
9567         i::ExternalAsciiString::cast(string);
9568    morphed->set_resource(ascii_resource);
9569  }
9570}
9571
9572
9573// Test that we can still flatten a string if the components it is built up
9574// from have been turned into 16 bit strings in the mean time.
9575THREADED_TEST(MorphCompositeStringTest) {
9576  const char* c_string = "Now is the time for all good men"
9577                         " to come to the aid of the party";
9578  uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
9579  {
9580    v8::HandleScope scope;
9581    LocalContext env;
9582    AsciiVectorResource ascii_resource(
9583        i::Vector<const char>(c_string, i::StrLength(c_string)));
9584    UC16VectorResource uc16_resource(
9585        i::Vector<const uint16_t>(two_byte_string,
9586                                  i::StrLength(c_string)));
9587
9588    Local<String> lhs(v8::Utils::ToLocal(
9589        i::Factory::NewExternalStringFromAscii(&ascii_resource)));
9590    Local<String> rhs(v8::Utils::ToLocal(
9591        i::Factory::NewExternalStringFromAscii(&ascii_resource)));
9592
9593    env->Global()->Set(v8_str("lhs"), lhs);
9594    env->Global()->Set(v8_str("rhs"), rhs);
9595
9596    CompileRun(
9597        "var cons = lhs + rhs;"
9598        "var slice = lhs.substring(1, lhs.length - 1);"
9599        "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
9600
9601    MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
9602    MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
9603
9604    // Now do some stuff to make sure the strings are flattened, etc.
9605    CompileRun(
9606        "/[^a-z]/.test(cons);"
9607        "/[^a-z]/.test(slice);"
9608        "/[^a-z]/.test(slice_on_cons);");
9609    const char* expected_cons =
9610        "Now is the time for all good men to come to the aid of the party"
9611        "Now is the time for all good men to come to the aid of the party";
9612    const char* expected_slice =
9613        "ow is the time for all good men to come to the aid of the part";
9614    const char* expected_slice_on_cons =
9615        "ow is the time for all good men to come to the aid of the party"
9616        "Now is the time for all good men to come to the aid of the part";
9617    CHECK_EQ(String::New(expected_cons),
9618             env->Global()->Get(v8_str("cons")));
9619    CHECK_EQ(String::New(expected_slice),
9620             env->Global()->Get(v8_str("slice")));
9621    CHECK_EQ(String::New(expected_slice_on_cons),
9622             env->Global()->Get(v8_str("slice_on_cons")));
9623  }
9624  i::DeleteArray(two_byte_string);
9625}
9626
9627
9628TEST(CompileExternalTwoByteSource) {
9629  v8::HandleScope scope;
9630  LocalContext context;
9631
9632  // This is a very short list of sources, which currently is to check for a
9633  // regression caused by r2703.
9634  const char* ascii_sources[] = {
9635    "0.5",
9636    "-0.5",   // This mainly testes PushBack in the Scanner.
9637    "--0.5",  // This mainly testes PushBack in the Scanner.
9638    NULL
9639  };
9640
9641  // Compile the sources as external two byte strings.
9642  for (int i = 0; ascii_sources[i] != NULL; i++) {
9643    uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
9644    UC16VectorResource uc16_resource(
9645        i::Vector<const uint16_t>(two_byte_string,
9646                                  i::StrLength(ascii_sources[i])));
9647    v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource);
9648    v8::Script::Compile(source);
9649    i::DeleteArray(two_byte_string);
9650  }
9651}
9652
9653
9654class RegExpStringModificationTest {
9655 public:
9656  RegExpStringModificationTest()
9657      : block_(i::OS::CreateSemaphore(0)),
9658        morphs_(0),
9659        morphs_during_regexp_(0),
9660        ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)),
9661        uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {}
9662  ~RegExpStringModificationTest() { delete block_; }
9663  void RunTest() {
9664    regexp_success_ = false;
9665    morph_success_ = false;
9666
9667    // Initialize the contents of two_byte_content_ to be a uc16 representation
9668    // of "aaaaaaaaaaaaaab".
9669    for (int i = 0; i < 14; i++) {
9670      two_byte_content_[i] = 'a';
9671    }
9672    two_byte_content_[14] = 'b';
9673
9674    // Create the input string for the regexp - the one we are going to change
9675    // properties of.
9676    input_ = i::Factory::NewExternalStringFromAscii(&ascii_resource_);
9677
9678    // Inject the input as a global variable.
9679    i::Handle<i::String> input_name =
9680        i::Factory::NewStringFromAscii(i::Vector<const char>("input", 5));
9681    i::Top::global_context()->global()->SetProperty(*input_name,
9682                                                    *input_,
9683                                                    NONE)->ToObjectChecked();
9684
9685
9686    MorphThread morph_thread(this);
9687    morph_thread.Start();
9688    v8::Locker::StartPreemption(1);
9689    LongRunningRegExp();
9690    {
9691      v8::Unlocker unlock;
9692      morph_thread.Join();
9693    }
9694    v8::Locker::StopPreemption();
9695    CHECK(regexp_success_);
9696    CHECK(morph_success_);
9697  }
9698 private:
9699
9700  // Number of string modifications required.
9701  static const int kRequiredModifications = 5;
9702  static const int kMaxModifications = 100;
9703
9704  class MorphThread : public i::Thread {
9705   public:
9706    explicit MorphThread(RegExpStringModificationTest* test)
9707        : test_(test) {}
9708    virtual void Run() {
9709      test_->MorphString();
9710    }
9711   private:
9712     RegExpStringModificationTest* test_;
9713  };
9714
9715  void MorphString() {
9716    block_->Wait();
9717    while (morphs_during_regexp_ < kRequiredModifications &&
9718           morphs_ < kMaxModifications) {
9719      {
9720        v8::Locker lock;
9721        // Swap string between ascii and two-byte representation.
9722        i::String* string = *input_;
9723        MorphAString(string, &ascii_resource_, &uc16_resource_);
9724        morphs_++;
9725      }
9726      i::OS::Sleep(1);
9727    }
9728    morph_success_ = true;
9729  }
9730
9731  void LongRunningRegExp() {
9732    block_->Signal();  // Enable morphing thread on next preemption.
9733    while (morphs_during_regexp_ < kRequiredModifications &&
9734           morphs_ < kMaxModifications) {
9735      int morphs_before = morphs_;
9736      {
9737        v8::HandleScope scope;
9738        // Match 15-30 "a"'s against 14 and a "b".
9739        const char* c_source =
9740            "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
9741            ".exec(input) === null";
9742        Local<String> source = String::New(c_source);
9743        Local<Script> script = Script::Compile(source);
9744        Local<Value> result = script->Run();
9745        CHECK(result->IsTrue());
9746      }
9747      int morphs_after = morphs_;
9748      morphs_during_regexp_ += morphs_after - morphs_before;
9749    }
9750    regexp_success_ = true;
9751  }
9752
9753  i::uc16 two_byte_content_[15];
9754  i::Semaphore* block_;
9755  int morphs_;
9756  int morphs_during_regexp_;
9757  bool regexp_success_;
9758  bool morph_success_;
9759  i::Handle<i::String> input_;
9760  AsciiVectorResource ascii_resource_;
9761  UC16VectorResource uc16_resource_;
9762};
9763
9764
9765// Test that a regular expression execution can be interrupted and
9766// the string changed without failing.
9767TEST(RegExpStringModification) {
9768  v8::Locker lock;
9769  v8::V8::Initialize();
9770  v8::HandleScope scope;
9771  Local<Context> local_env;
9772  {
9773    LocalContext env;
9774    local_env = env.local();
9775  }
9776
9777  // Local context should still be live.
9778  CHECK(!local_env.IsEmpty());
9779  local_env->Enter();
9780
9781  // Should complete without problems.
9782  RegExpStringModificationTest().RunTest();
9783
9784  local_env->Exit();
9785}
9786
9787
9788// Test that we can set a property on the global object even if there
9789// is a read-only property in the prototype chain.
9790TEST(ReadOnlyPropertyInGlobalProto) {
9791  v8::HandleScope scope;
9792  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
9793  LocalContext context(0, templ);
9794  v8::Handle<v8::Object> global = context->Global();
9795  v8::Handle<v8::Object> global_proto =
9796      v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
9797  global_proto->Set(v8_str("x"), v8::Integer::New(0), v8::ReadOnly);
9798  global_proto->Set(v8_str("y"), v8::Integer::New(0), v8::ReadOnly);
9799  // Check without 'eval' or 'with'.
9800  v8::Handle<v8::Value> res =
9801      CompileRun("function f() { x = 42; return x; }; f()");
9802  // Check with 'eval'.
9803  res = CompileRun("function f() { eval('1'); y = 42; return y; }; f()");
9804  CHECK_EQ(v8::Integer::New(42), res);
9805  // Check with 'with'.
9806  res = CompileRun("function f() { with (this) { y = 42 }; return y; }; f()");
9807  CHECK_EQ(v8::Integer::New(42), res);
9808}
9809
9810static int force_set_set_count = 0;
9811static int force_set_get_count = 0;
9812bool pass_on_get = false;
9813
9814static v8::Handle<v8::Value> ForceSetGetter(v8::Local<v8::String> name,
9815                                            const v8::AccessorInfo& info) {
9816  force_set_get_count++;
9817  if (pass_on_get) {
9818    return v8::Handle<v8::Value>();
9819  } else {
9820    return v8::Int32::New(3);
9821  }
9822}
9823
9824static void ForceSetSetter(v8::Local<v8::String> name,
9825                           v8::Local<v8::Value> value,
9826                           const v8::AccessorInfo& info) {
9827  force_set_set_count++;
9828}
9829
9830static v8::Handle<v8::Value> ForceSetInterceptSetter(
9831    v8::Local<v8::String> name,
9832    v8::Local<v8::Value> value,
9833    const v8::AccessorInfo& info) {
9834  force_set_set_count++;
9835  return v8::Undefined();
9836}
9837
9838TEST(ForceSet) {
9839  force_set_get_count = 0;
9840  force_set_set_count = 0;
9841  pass_on_get = false;
9842
9843  v8::HandleScope scope;
9844  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
9845  v8::Handle<v8::String> access_property = v8::String::New("a");
9846  templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
9847  LocalContext context(NULL, templ);
9848  v8::Handle<v8::Object> global = context->Global();
9849
9850  // Ordinary properties
9851  v8::Handle<v8::String> simple_property = v8::String::New("p");
9852  global->Set(simple_property, v8::Int32::New(4), v8::ReadOnly);
9853  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
9854  // This should fail because the property is read-only
9855  global->Set(simple_property, v8::Int32::New(5));
9856  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
9857  // This should succeed even though the property is read-only
9858  global->ForceSet(simple_property, v8::Int32::New(6));
9859  CHECK_EQ(6, global->Get(simple_property)->Int32Value());
9860
9861  // Accessors
9862  CHECK_EQ(0, force_set_set_count);
9863  CHECK_EQ(0, force_set_get_count);
9864  CHECK_EQ(3, global->Get(access_property)->Int32Value());
9865  // CHECK_EQ the property shouldn't override it, just call the setter
9866  // which in this case does nothing.
9867  global->Set(access_property, v8::Int32::New(7));
9868  CHECK_EQ(3, global->Get(access_property)->Int32Value());
9869  CHECK_EQ(1, force_set_set_count);
9870  CHECK_EQ(2, force_set_get_count);
9871  // Forcing the property to be set should override the accessor without
9872  // calling it
9873  global->ForceSet(access_property, v8::Int32::New(8));
9874  CHECK_EQ(8, global->Get(access_property)->Int32Value());
9875  CHECK_EQ(1, force_set_set_count);
9876  CHECK_EQ(2, force_set_get_count);
9877}
9878
9879TEST(ForceSetWithInterceptor) {
9880  force_set_get_count = 0;
9881  force_set_set_count = 0;
9882  pass_on_get = false;
9883
9884  v8::HandleScope scope;
9885  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
9886  templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
9887  LocalContext context(NULL, templ);
9888  v8::Handle<v8::Object> global = context->Global();
9889
9890  v8::Handle<v8::String> some_property = v8::String::New("a");
9891  CHECK_EQ(0, force_set_set_count);
9892  CHECK_EQ(0, force_set_get_count);
9893  CHECK_EQ(3, global->Get(some_property)->Int32Value());
9894  // Setting the property shouldn't override it, just call the setter
9895  // which in this case does nothing.
9896  global->Set(some_property, v8::Int32::New(7));
9897  CHECK_EQ(3, global->Get(some_property)->Int32Value());
9898  CHECK_EQ(1, force_set_set_count);
9899  CHECK_EQ(2, force_set_get_count);
9900  // Getting the property when the interceptor returns an empty handle
9901  // should yield undefined, since the property isn't present on the
9902  // object itself yet.
9903  pass_on_get = true;
9904  CHECK(global->Get(some_property)->IsUndefined());
9905  CHECK_EQ(1, force_set_set_count);
9906  CHECK_EQ(3, force_set_get_count);
9907  // Forcing the property to be set should cause the value to be
9908  // set locally without calling the interceptor.
9909  global->ForceSet(some_property, v8::Int32::New(8));
9910  CHECK_EQ(8, global->Get(some_property)->Int32Value());
9911  CHECK_EQ(1, force_set_set_count);
9912  CHECK_EQ(4, force_set_get_count);
9913  // Reenabling the interceptor should cause it to take precedence over
9914  // the property
9915  pass_on_get = false;
9916  CHECK_EQ(3, global->Get(some_property)->Int32Value());
9917  CHECK_EQ(1, force_set_set_count);
9918  CHECK_EQ(5, force_set_get_count);
9919  // The interceptor should also work for other properties
9920  CHECK_EQ(3, global->Get(v8::String::New("b"))->Int32Value());
9921  CHECK_EQ(1, force_set_set_count);
9922  CHECK_EQ(6, force_set_get_count);
9923}
9924
9925
9926THREADED_TEST(ForceDelete) {
9927  v8::HandleScope scope;
9928  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
9929  LocalContext context(NULL, templ);
9930  v8::Handle<v8::Object> global = context->Global();
9931
9932  // Ordinary properties
9933  v8::Handle<v8::String> simple_property = v8::String::New("p");
9934  global->Set(simple_property, v8::Int32::New(4), v8::DontDelete);
9935  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
9936  // This should fail because the property is dont-delete.
9937  CHECK(!global->Delete(simple_property));
9938  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
9939  // This should succeed even though the property is dont-delete.
9940  CHECK(global->ForceDelete(simple_property));
9941  CHECK(global->Get(simple_property)->IsUndefined());
9942}
9943
9944
9945static int force_delete_interceptor_count = 0;
9946static bool pass_on_delete = false;
9947
9948
9949static v8::Handle<v8::Boolean> ForceDeleteDeleter(
9950    v8::Local<v8::String> name,
9951    const v8::AccessorInfo& info) {
9952  force_delete_interceptor_count++;
9953  if (pass_on_delete) {
9954    return v8::Handle<v8::Boolean>();
9955  } else {
9956    return v8::True();
9957  }
9958}
9959
9960
9961THREADED_TEST(ForceDeleteWithInterceptor) {
9962  force_delete_interceptor_count = 0;
9963  pass_on_delete = false;
9964
9965  v8::HandleScope scope;
9966  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
9967  templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
9968  LocalContext context(NULL, templ);
9969  v8::Handle<v8::Object> global = context->Global();
9970
9971  v8::Handle<v8::String> some_property = v8::String::New("a");
9972  global->Set(some_property, v8::Integer::New(42), v8::DontDelete);
9973
9974  // Deleting a property should get intercepted and nothing should
9975  // happen.
9976  CHECK_EQ(0, force_delete_interceptor_count);
9977  CHECK(global->Delete(some_property));
9978  CHECK_EQ(1, force_delete_interceptor_count);
9979  CHECK_EQ(42, global->Get(some_property)->Int32Value());
9980  // Deleting the property when the interceptor returns an empty
9981  // handle should not delete the property since it is DontDelete.
9982  pass_on_delete = true;
9983  CHECK(!global->Delete(some_property));
9984  CHECK_EQ(2, force_delete_interceptor_count);
9985  CHECK_EQ(42, global->Get(some_property)->Int32Value());
9986  // Forcing the property to be deleted should delete the value
9987  // without calling the interceptor.
9988  CHECK(global->ForceDelete(some_property));
9989  CHECK(global->Get(some_property)->IsUndefined());
9990  CHECK_EQ(2, force_delete_interceptor_count);
9991}
9992
9993
9994// Make sure that forcing a delete invalidates any IC stubs, so we
9995// don't read the hole value.
9996THREADED_TEST(ForceDeleteIC) {
9997  v8::HandleScope scope;
9998  LocalContext context;
9999  // Create a DontDelete variable on the global object.
10000  CompileRun("this.__proto__ = { foo: 'horse' };"
10001             "var foo = 'fish';"
10002             "function f() { return foo.length; }");
10003  // Initialize the IC for foo in f.
10004  CompileRun("for (var i = 0; i < 4; i++) f();");
10005  // Make sure the value of foo is correct before the deletion.
10006  CHECK_EQ(4, CompileRun("f()")->Int32Value());
10007  // Force the deletion of foo.
10008  CHECK(context->Global()->ForceDelete(v8_str("foo")));
10009  // Make sure the value for foo is read from the prototype, and that
10010  // we don't get in trouble with reading the deleted cell value
10011  // sentinel.
10012  CHECK_EQ(5, CompileRun("f()")->Int32Value());
10013}
10014
10015
10016v8::Persistent<Context> calling_context0;
10017v8::Persistent<Context> calling_context1;
10018v8::Persistent<Context> calling_context2;
10019
10020
10021// Check that the call to the callback is initiated in
10022// calling_context2, the directly calling context is calling_context1
10023// and the callback itself is in calling_context0.
10024static v8::Handle<Value> GetCallingContextCallback(const v8::Arguments& args) {
10025  ApiTestFuzzer::Fuzz();
10026  CHECK(Context::GetCurrent() == calling_context0);
10027  CHECK(Context::GetCalling() == calling_context1);
10028  CHECK(Context::GetEntered() == calling_context2);
10029  return v8::Integer::New(42);
10030}
10031
10032
10033THREADED_TEST(GetCallingContext) {
10034  v8::HandleScope scope;
10035
10036  calling_context0 = Context::New();
10037  calling_context1 = Context::New();
10038  calling_context2 = Context::New();
10039
10040  // Allow cross-domain access.
10041  Local<String> token = v8_str("<security token>");
10042  calling_context0->SetSecurityToken(token);
10043  calling_context1->SetSecurityToken(token);
10044  calling_context2->SetSecurityToken(token);
10045
10046  // Create an object with a C++ callback in context0.
10047  calling_context0->Enter();
10048  Local<v8::FunctionTemplate> callback_templ =
10049      v8::FunctionTemplate::New(GetCallingContextCallback);
10050  calling_context0->Global()->Set(v8_str("callback"),
10051                                  callback_templ->GetFunction());
10052  calling_context0->Exit();
10053
10054  // Expose context0 in context1 and setup a function that calls the
10055  // callback function.
10056  calling_context1->Enter();
10057  calling_context1->Global()->Set(v8_str("context0"),
10058                                  calling_context0->Global());
10059  CompileRun("function f() { context0.callback() }");
10060  calling_context1->Exit();
10061
10062  // Expose context1 in context2 and call the callback function in
10063  // context0 indirectly through f in context1.
10064  calling_context2->Enter();
10065  calling_context2->Global()->Set(v8_str("context1"),
10066                                  calling_context1->Global());
10067  CompileRun("context1.f()");
10068  calling_context2->Exit();
10069
10070  // Dispose the contexts to allow them to be garbage collected.
10071  calling_context0.Dispose();
10072  calling_context1.Dispose();
10073  calling_context2.Dispose();
10074  calling_context0.Clear();
10075  calling_context1.Clear();
10076  calling_context2.Clear();
10077}
10078
10079
10080// Check that a variable declaration with no explicit initialization
10081// value does not shadow an existing property in the prototype chain.
10082//
10083// This is consistent with Firefox and Safari.
10084//
10085// See http://crbug.com/12548.
10086THREADED_TEST(InitGlobalVarInProtoChain) {
10087  v8::HandleScope scope;
10088  LocalContext context;
10089  // Introduce a variable in the prototype chain.
10090  CompileRun("__proto__.x = 42");
10091  v8::Handle<v8::Value> result = CompileRun("var x; x");
10092  CHECK(!result->IsUndefined());
10093  CHECK_EQ(42, result->Int32Value());
10094}
10095
10096
10097// Regression test for issue 398.
10098// If a function is added to an object, creating a constant function
10099// field, and the result is cloned, replacing the constant function on the
10100// original should not affect the clone.
10101// See http://code.google.com/p/v8/issues/detail?id=398
10102THREADED_TEST(ReplaceConstantFunction) {
10103  v8::HandleScope scope;
10104  LocalContext context;
10105  v8::Handle<v8::Object> obj = v8::Object::New();
10106  v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
10107  v8::Handle<v8::String> foo_string = v8::String::New("foo");
10108  obj->Set(foo_string, func_templ->GetFunction());
10109  v8::Handle<v8::Object> obj_clone = obj->Clone();
10110  obj_clone->Set(foo_string, v8::String::New("Hello"));
10111  CHECK(!obj->Get(foo_string)->IsUndefined());
10112}
10113
10114
10115// Regression test for http://crbug.com/16276.
10116THREADED_TEST(Regress16276) {
10117  v8::HandleScope scope;
10118  LocalContext context;
10119  // Force the IC in f to be a dictionary load IC.
10120  CompileRun("function f(obj) { return obj.x; }\n"
10121             "var obj = { x: { foo: 42 }, y: 87 };\n"
10122             "var x = obj.x;\n"
10123             "delete obj.y;\n"
10124             "for (var i = 0; i < 5; i++) f(obj);");
10125  // Detach the global object to make 'this' refer directly to the
10126  // global object (not the proxy), and make sure that the dictionary
10127  // load IC doesn't mess up loading directly from the global object.
10128  context->DetachGlobal();
10129  CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value());
10130}
10131
10132
10133THREADED_TEST(PixelArray) {
10134  v8::HandleScope scope;
10135  LocalContext context;
10136  const int kElementCount = 260;
10137  uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
10138  i::Handle<i::PixelArray> pixels = i::Factory::NewPixelArray(kElementCount,
10139                                                              pixel_data);
10140  i::Heap::CollectAllGarbage(false);  // Force GC to trigger verification.
10141  for (int i = 0; i < kElementCount; i++) {
10142    pixels->set(i, i % 256);
10143  }
10144  i::Heap::CollectAllGarbage(false);  // Force GC to trigger verification.
10145  for (int i = 0; i < kElementCount; i++) {
10146    CHECK_EQ(i % 256, pixels->get(i));
10147    CHECK_EQ(i % 256, pixel_data[i]);
10148  }
10149
10150  v8::Handle<v8::Object> obj = v8::Object::New();
10151  i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
10152  // Set the elements to be the pixels.
10153  // jsobj->set_elements(*pixels);
10154  obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
10155  CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
10156  obj->Set(v8_str("field"), v8::Int32::New(1503));
10157  context->Global()->Set(v8_str("pixels"), obj);
10158  v8::Handle<v8::Value> result = CompileRun("pixels.field");
10159  CHECK_EQ(1503, result->Int32Value());
10160  result = CompileRun("pixels[1]");
10161  CHECK_EQ(1, result->Int32Value());
10162
10163  result = CompileRun("var sum = 0;"
10164                      "for (var i = 0; i < 8; i++) {"
10165                      "  sum += pixels[i] = pixels[i] = -i;"
10166                      "}"
10167                      "sum;");
10168  CHECK_EQ(-28, result->Int32Value());
10169
10170  result = CompileRun("var sum = 0;"
10171                      "for (var i = 0; i < 8; i++) {"
10172                      "  sum += pixels[i] = pixels[i] = 0;"
10173                      "}"
10174                      "sum;");
10175  CHECK_EQ(0, result->Int32Value());
10176
10177  result = CompileRun("var sum = 0;"
10178                      "for (var i = 0; i < 8; i++) {"
10179                      "  sum += pixels[i] = pixels[i] = 255;"
10180                      "}"
10181                      "sum;");
10182  CHECK_EQ(8 * 255, result->Int32Value());
10183
10184  result = CompileRun("var sum = 0;"
10185                      "for (var i = 0; i < 8; i++) {"
10186                      "  sum += pixels[i] = pixels[i] = 256 + i;"
10187                      "}"
10188                      "sum;");
10189  CHECK_EQ(2076, result->Int32Value());
10190
10191  result = CompileRun("var sum = 0;"
10192                      "for (var i = 0; i < 8; i++) {"
10193                      "  sum += pixels[i] = pixels[i] = i;"
10194                      "}"
10195                      "sum;");
10196  CHECK_EQ(28, result->Int32Value());
10197
10198  result = CompileRun("var sum = 0;"
10199                      "for (var i = 0; i < 8; i++) {"
10200                      "  sum += pixels[i];"
10201                      "}"
10202                      "sum;");
10203  CHECK_EQ(28, result->Int32Value());
10204
10205  i::Handle<i::Smi> value(i::Smi::FromInt(2));
10206  i::SetElement(jsobj, 1, value);
10207  CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
10208  *value.location() = i::Smi::FromInt(256);
10209  i::SetElement(jsobj, 1, value);
10210  CHECK_EQ(255,
10211           i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
10212  *value.location() = i::Smi::FromInt(-1);
10213  i::SetElement(jsobj, 1, value);
10214  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
10215
10216  result = CompileRun("for (var i = 0; i < 8; i++) {"
10217                      "  pixels[i] = (i * 65) - 109;"
10218                      "}"
10219                      "pixels[1] + pixels[6];");
10220  CHECK_EQ(255, result->Int32Value());
10221  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
10222  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
10223  CHECK_EQ(21,
10224           i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
10225  CHECK_EQ(86,
10226           i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
10227  CHECK_EQ(151,
10228           i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
10229  CHECK_EQ(216,
10230           i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
10231  CHECK_EQ(255,
10232           i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
10233  CHECK_EQ(255,
10234           i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
10235  result = CompileRun("var sum = 0;"
10236                      "for (var i = 0; i < 8; i++) {"
10237                      "  sum += pixels[i];"
10238                      "}"
10239                      "sum;");
10240  CHECK_EQ(984, result->Int32Value());
10241
10242  result = CompileRun("for (var i = 0; i < 8; i++) {"
10243                      "  pixels[i] = (i * 1.1);"
10244                      "}"
10245                      "pixels[1] + pixels[6];");
10246  CHECK_EQ(8, result->Int32Value());
10247  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
10248  CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
10249  CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
10250  CHECK_EQ(3, i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
10251  CHECK_EQ(4, i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
10252  CHECK_EQ(6, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
10253  CHECK_EQ(7, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
10254  CHECK_EQ(8, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
10255
10256  result = CompileRun("for (var i = 0; i < 8; i++) {"
10257                      "  pixels[7] = undefined;"
10258                      "}"
10259                      "pixels[7];");
10260  CHECK_EQ(0, result->Int32Value());
10261  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
10262
10263  result = CompileRun("for (var i = 0; i < 8; i++) {"
10264                      "  pixels[6] = '2.3';"
10265                      "}"
10266                      "pixels[6];");
10267  CHECK_EQ(2, result->Int32Value());
10268  CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
10269
10270  result = CompileRun("for (var i = 0; i < 8; i++) {"
10271                      "  pixels[5] = NaN;"
10272                      "}"
10273                      "pixels[5];");
10274  CHECK_EQ(0, result->Int32Value());
10275  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
10276
10277  result = CompileRun("for (var i = 0; i < 8; i++) {"
10278                      "  pixels[8] = Infinity;"
10279                      "}"
10280                      "pixels[8];");
10281  CHECK_EQ(255, result->Int32Value());
10282  CHECK_EQ(255,
10283           i::Smi::cast(jsobj->GetElement(8)->ToObjectChecked())->value());
10284
10285  result = CompileRun("for (var i = 0; i < 8; i++) {"
10286                      "  pixels[9] = -Infinity;"
10287                      "}"
10288                      "pixels[9];");
10289  CHECK_EQ(0, result->Int32Value());
10290  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(9)->ToObjectChecked())->value());
10291
10292  result = CompileRun("pixels[3] = 33;"
10293                      "delete pixels[3];"
10294                      "pixels[3];");
10295  CHECK_EQ(33, result->Int32Value());
10296
10297  result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
10298                      "pixels[2] = 12; pixels[3] = 13;"
10299                      "pixels.__defineGetter__('2',"
10300                      "function() { return 120; });"
10301                      "pixels[2];");
10302  CHECK_EQ(12, result->Int32Value());
10303
10304  result = CompileRun("var js_array = new Array(40);"
10305                      "js_array[0] = 77;"
10306                      "js_array;");
10307  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
10308
10309  result = CompileRun("pixels[1] = 23;"
10310                      "pixels.__proto__ = [];"
10311                      "js_array.__proto__ = pixels;"
10312                      "js_array.concat(pixels);");
10313  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
10314  CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
10315
10316  result = CompileRun("pixels[1] = 23;");
10317  CHECK_EQ(23, result->Int32Value());
10318
10319  // Test for index greater than 255.  Regression test for:
10320  // http://code.google.com/p/chromium/issues/detail?id=26337.
10321  result = CompileRun("pixels[256] = 255;");
10322  CHECK_EQ(255, result->Int32Value());
10323  result = CompileRun("var i = 0;"
10324                      "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
10325                      "i");
10326  CHECK_EQ(255, result->Int32Value());
10327
10328  free(pixel_data);
10329}
10330
10331
10332THREADED_TEST(PixelArrayInfo) {
10333  v8::HandleScope scope;
10334  LocalContext context;
10335  for (int size = 0; size < 100; size += 10) {
10336    uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
10337    v8::Handle<v8::Object> obj = v8::Object::New();
10338    obj->SetIndexedPropertiesToPixelData(pixel_data, size);
10339    CHECK(obj->HasIndexedPropertiesInPixelData());
10340    CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
10341    CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
10342    free(pixel_data);
10343  }
10344}
10345
10346
10347static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
10348  switch (array_type) {
10349    case v8::kExternalByteArray:
10350    case v8::kExternalUnsignedByteArray:
10351      return 1;
10352      break;
10353    case v8::kExternalShortArray:
10354    case v8::kExternalUnsignedShortArray:
10355      return 2;
10356      break;
10357    case v8::kExternalIntArray:
10358    case v8::kExternalUnsignedIntArray:
10359    case v8::kExternalFloatArray:
10360      return 4;
10361      break;
10362    default:
10363      UNREACHABLE();
10364      return -1;
10365  }
10366  UNREACHABLE();
10367  return -1;
10368}
10369
10370
10371template <class ExternalArrayClass, class ElementType>
10372static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
10373                                    int64_t low,
10374                                    int64_t high) {
10375  v8::HandleScope scope;
10376  LocalContext context;
10377  const int kElementCount = 40;
10378  int element_size = ExternalArrayElementSize(array_type);
10379  ElementType* array_data =
10380      static_cast<ElementType*>(malloc(kElementCount * element_size));
10381  i::Handle<ExternalArrayClass> array =
10382      i::Handle<ExternalArrayClass>::cast(
10383          i::Factory::NewExternalArray(kElementCount, array_type, array_data));
10384  i::Heap::CollectAllGarbage(false);  // Force GC to trigger verification.
10385  for (int i = 0; i < kElementCount; i++) {
10386    array->set(i, static_cast<ElementType>(i));
10387  }
10388  i::Heap::CollectAllGarbage(false);  // Force GC to trigger verification.
10389  for (int i = 0; i < kElementCount; i++) {
10390    CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array->get(i)));
10391    CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
10392  }
10393
10394  v8::Handle<v8::Object> obj = v8::Object::New();
10395  i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
10396  // Set the elements to be the external array.
10397  obj->SetIndexedPropertiesToExternalArrayData(array_data,
10398                                               array_type,
10399                                               kElementCount);
10400  CHECK_EQ(
10401      1, static_cast<int>(jsobj->GetElement(1)->ToObjectChecked()->Number()));
10402  obj->Set(v8_str("field"), v8::Int32::New(1503));
10403  context->Global()->Set(v8_str("ext_array"), obj);
10404  v8::Handle<v8::Value> result = CompileRun("ext_array.field");
10405  CHECK_EQ(1503, result->Int32Value());
10406  result = CompileRun("ext_array[1]");
10407  CHECK_EQ(1, result->Int32Value());
10408
10409  // Check pass through of assigned smis
10410  result = CompileRun("var sum = 0;"
10411                      "for (var i = 0; i < 8; i++) {"
10412                      "  sum += ext_array[i] = ext_array[i] = -i;"
10413                      "}"
10414                      "sum;");
10415  CHECK_EQ(-28, result->Int32Value());
10416
10417  // Check assigned smis
10418  result = CompileRun("for (var i = 0; i < 8; i++) {"
10419                      "  ext_array[i] = i;"
10420                      "}"
10421                      "var sum = 0;"
10422                      "for (var i = 0; i < 8; i++) {"
10423                      "  sum += ext_array[i];"
10424                      "}"
10425                      "sum;");
10426  CHECK_EQ(28, result->Int32Value());
10427
10428  // Check assigned smis in reverse order
10429  result = CompileRun("for (var i = 8; --i >= 0; ) {"
10430                      "  ext_array[i] = i;"
10431                      "}"
10432                      "var sum = 0;"
10433                      "for (var i = 0; i < 8; i++) {"
10434                      "  sum += ext_array[i];"
10435                      "}"
10436                      "sum;");
10437  CHECK_EQ(28, result->Int32Value());
10438
10439  // Check pass through of assigned HeapNumbers
10440  result = CompileRun("var sum = 0;"
10441                      "for (var i = 0; i < 16; i+=2) {"
10442                      "  sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
10443                      "}"
10444                      "sum;");
10445  CHECK_EQ(-28, result->Int32Value());
10446
10447  // Check assigned HeapNumbers
10448  result = CompileRun("for (var i = 0; i < 16; i+=2) {"
10449                      "  ext_array[i] = (i * 0.5);"
10450                      "}"
10451                      "var sum = 0;"
10452                      "for (var i = 0; i < 16; i+=2) {"
10453                      "  sum += ext_array[i];"
10454                      "}"
10455                      "sum;");
10456  CHECK_EQ(28, result->Int32Value());
10457
10458  // Check assigned HeapNumbers in reverse order
10459  result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
10460                      "  ext_array[i] = (i * 0.5);"
10461                      "}"
10462                      "var sum = 0;"
10463                      "for (var i = 0; i < 16; i+=2) {"
10464                      "  sum += ext_array[i];"
10465                      "}"
10466                      "sum;");
10467  CHECK_EQ(28, result->Int32Value());
10468
10469  i::ScopedVector<char> test_buf(1024);
10470
10471  // Check legal boundary conditions.
10472  // The repeated loads and stores ensure the ICs are exercised.
10473  const char* boundary_program =
10474      "var res = 0;"
10475      "for (var i = 0; i < 16; i++) {"
10476      "  ext_array[i] = %lld;"
10477      "  if (i > 8) {"
10478      "    res = ext_array[i];"
10479      "  }"
10480      "}"
10481      "res;";
10482  i::OS::SNPrintF(test_buf,
10483                  boundary_program,
10484                  low);
10485  result = CompileRun(test_buf.start());
10486  CHECK_EQ(low, result->IntegerValue());
10487
10488  i::OS::SNPrintF(test_buf,
10489                  boundary_program,
10490                  high);
10491  result = CompileRun(test_buf.start());
10492  CHECK_EQ(high, result->IntegerValue());
10493
10494  // Check misprediction of type in IC.
10495  result = CompileRun("var tmp_array = ext_array;"
10496                      "var sum = 0;"
10497                      "for (var i = 0; i < 8; i++) {"
10498                      "  tmp_array[i] = i;"
10499                      "  sum += tmp_array[i];"
10500                      "  if (i == 4) {"
10501                      "    tmp_array = {};"
10502                      "  }"
10503                      "}"
10504                      "sum;");
10505  i::Heap::CollectAllGarbage(false);  // Force GC to trigger verification.
10506  CHECK_EQ(28, result->Int32Value());
10507
10508  // Make sure out-of-range loads do not throw.
10509  i::OS::SNPrintF(test_buf,
10510                  "var caught_exception = false;"
10511                  "try {"
10512                  "  ext_array[%d];"
10513                  "} catch (e) {"
10514                  "  caught_exception = true;"
10515                  "}"
10516                  "caught_exception;",
10517                  kElementCount);
10518  result = CompileRun(test_buf.start());
10519  CHECK_EQ(false, result->BooleanValue());
10520
10521  // Make sure out-of-range stores do not throw.
10522  i::OS::SNPrintF(test_buf,
10523                  "var caught_exception = false;"
10524                  "try {"
10525                  "  ext_array[%d] = 1;"
10526                  "} catch (e) {"
10527                  "  caught_exception = true;"
10528                  "}"
10529                  "caught_exception;",
10530                  kElementCount);
10531  result = CompileRun(test_buf.start());
10532  CHECK_EQ(false, result->BooleanValue());
10533
10534  // Check other boundary conditions, values and operations.
10535  result = CompileRun("for (var i = 0; i < 8; i++) {"
10536                      "  ext_array[7] = undefined;"
10537                      "}"
10538                      "ext_array[7];");
10539  CHECK_EQ(0, result->Int32Value());
10540  CHECK_EQ(
10541      0, static_cast<int>(jsobj->GetElement(7)->ToObjectChecked()->Number()));
10542
10543  result = CompileRun("for (var i = 0; i < 8; i++) {"
10544                      "  ext_array[6] = '2.3';"
10545                      "}"
10546                      "ext_array[6];");
10547  CHECK_EQ(2, result->Int32Value());
10548  CHECK_EQ(
10549      2, static_cast<int>(jsobj->GetElement(6)->ToObjectChecked()->Number()));
10550
10551  if (array_type != v8::kExternalFloatArray) {
10552    // Though the specification doesn't state it, be explicit about
10553    // converting NaNs and +/-Infinity to zero.
10554    result = CompileRun("for (var i = 0; i < 8; i++) {"
10555                        "  ext_array[i] = 5;"
10556                        "}"
10557                        "for (var i = 0; i < 8; i++) {"
10558                        "  ext_array[i] = NaN;"
10559                        "}"
10560                        "ext_array[5];");
10561    CHECK_EQ(0, result->Int32Value());
10562    CHECK_EQ(0,
10563             i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
10564
10565    result = CompileRun("for (var i = 0; i < 8; i++) {"
10566                        "  ext_array[i] = 5;"
10567                        "}"
10568                        "for (var i = 0; i < 8; i++) {"
10569                        "  ext_array[i] = Infinity;"
10570                        "}"
10571                        "ext_array[5];");
10572    CHECK_EQ(0, result->Int32Value());
10573    CHECK_EQ(0,
10574             i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
10575
10576    result = CompileRun("for (var i = 0; i < 8; i++) {"
10577                        "  ext_array[i] = 5;"
10578                        "}"
10579                        "for (var i = 0; i < 8; i++) {"
10580                        "  ext_array[i] = -Infinity;"
10581                        "}"
10582                        "ext_array[5];");
10583    CHECK_EQ(0, result->Int32Value());
10584    CHECK_EQ(0,
10585             i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
10586  }
10587
10588  result = CompileRun("ext_array[3] = 33;"
10589                      "delete ext_array[3];"
10590                      "ext_array[3];");
10591  CHECK_EQ(33, result->Int32Value());
10592
10593  result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
10594                      "ext_array[2] = 12; ext_array[3] = 13;"
10595                      "ext_array.__defineGetter__('2',"
10596                      "function() { return 120; });"
10597                      "ext_array[2];");
10598  CHECK_EQ(12, result->Int32Value());
10599
10600  result = CompileRun("var js_array = new Array(40);"
10601                      "js_array[0] = 77;"
10602                      "js_array;");
10603  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
10604
10605  result = CompileRun("ext_array[1] = 23;"
10606                      "ext_array.__proto__ = [];"
10607                      "js_array.__proto__ = ext_array;"
10608                      "js_array.concat(ext_array);");
10609  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
10610  CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
10611
10612  result = CompileRun("ext_array[1] = 23;");
10613  CHECK_EQ(23, result->Int32Value());
10614
10615  // Test more complex manipulations which cause eax to contain values
10616  // that won't be completely overwritten by loads from the arrays.
10617  // This catches bugs in the instructions used for the KeyedLoadIC
10618  // for byte and word types.
10619  {
10620    const int kXSize = 300;
10621    const int kYSize = 300;
10622    const int kLargeElementCount = kXSize * kYSize * 4;
10623    ElementType* large_array_data =
10624        static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
10625    i::Handle<ExternalArrayClass> large_array =
10626        i::Handle<ExternalArrayClass>::cast(
10627            i::Factory::NewExternalArray(kLargeElementCount,
10628                                         array_type,
10629                                         array_data));
10630    v8::Handle<v8::Object> large_obj = v8::Object::New();
10631    // Set the elements to be the external array.
10632    large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
10633                                                       array_type,
10634                                                       kLargeElementCount);
10635    context->Global()->Set(v8_str("large_array"), large_obj);
10636    // Initialize contents of a few rows.
10637    for (int x = 0; x < 300; x++) {
10638      int row = 0;
10639      int offset = row * 300 * 4;
10640      large_array_data[offset + 4 * x + 0] = (ElementType) 127;
10641      large_array_data[offset + 4 * x + 1] = (ElementType) 0;
10642      large_array_data[offset + 4 * x + 2] = (ElementType) 0;
10643      large_array_data[offset + 4 * x + 3] = (ElementType) 127;
10644      row = 150;
10645      offset = row * 300 * 4;
10646      large_array_data[offset + 4 * x + 0] = (ElementType) 127;
10647      large_array_data[offset + 4 * x + 1] = (ElementType) 0;
10648      large_array_data[offset + 4 * x + 2] = (ElementType) 0;
10649      large_array_data[offset + 4 * x + 3] = (ElementType) 127;
10650      row = 298;
10651      offset = row * 300 * 4;
10652      large_array_data[offset + 4 * x + 0] = (ElementType) 127;
10653      large_array_data[offset + 4 * x + 1] = (ElementType) 0;
10654      large_array_data[offset + 4 * x + 2] = (ElementType) 0;
10655      large_array_data[offset + 4 * x + 3] = (ElementType) 127;
10656    }
10657    // The goal of the code below is to make "offset" large enough
10658    // that the computation of the index (which goes into eax) has
10659    // high bits set which will not be overwritten by a byte or short
10660    // load.
10661    result = CompileRun("var failed = false;"
10662                        "var offset = 0;"
10663                        "for (var i = 0; i < 300; i++) {"
10664                        "  if (large_array[4 * i] != 127 ||"
10665                        "      large_array[4 * i + 1] != 0 ||"
10666                        "      large_array[4 * i + 2] != 0 ||"
10667                        "      large_array[4 * i + 3] != 127) {"
10668                        "    failed = true;"
10669                        "  }"
10670                        "}"
10671                        "offset = 150 * 300 * 4;"
10672                        "for (var i = 0; i < 300; i++) {"
10673                        "  if (large_array[offset + 4 * i] != 127 ||"
10674                        "      large_array[offset + 4 * i + 1] != 0 ||"
10675                        "      large_array[offset + 4 * i + 2] != 0 ||"
10676                        "      large_array[offset + 4 * i + 3] != 127) {"
10677                        "    failed = true;"
10678                        "  }"
10679                        "}"
10680                        "offset = 298 * 300 * 4;"
10681                        "for (var i = 0; i < 300; i++) {"
10682                        "  if (large_array[offset + 4 * i] != 127 ||"
10683                        "      large_array[offset + 4 * i + 1] != 0 ||"
10684                        "      large_array[offset + 4 * i + 2] != 0 ||"
10685                        "      large_array[offset + 4 * i + 3] != 127) {"
10686                        "    failed = true;"
10687                        "  }"
10688                        "}"
10689                        "!failed;");
10690    CHECK_EQ(true, result->BooleanValue());
10691    free(large_array_data);
10692  }
10693
10694  free(array_data);
10695}
10696
10697
10698THREADED_TEST(ExternalByteArray) {
10699  ExternalArrayTestHelper<i::ExternalByteArray, int8_t>(
10700      v8::kExternalByteArray,
10701      -128,
10702      127);
10703}
10704
10705
10706THREADED_TEST(ExternalUnsignedByteArray) {
10707  ExternalArrayTestHelper<i::ExternalUnsignedByteArray, uint8_t>(
10708      v8::kExternalUnsignedByteArray,
10709      0,
10710      255);
10711}
10712
10713
10714THREADED_TEST(ExternalShortArray) {
10715  ExternalArrayTestHelper<i::ExternalShortArray, int16_t>(
10716      v8::kExternalShortArray,
10717      -32768,
10718      32767);
10719}
10720
10721
10722THREADED_TEST(ExternalUnsignedShortArray) {
10723  ExternalArrayTestHelper<i::ExternalUnsignedShortArray, uint16_t>(
10724      v8::kExternalUnsignedShortArray,
10725      0,
10726      65535);
10727}
10728
10729
10730THREADED_TEST(ExternalIntArray) {
10731  ExternalArrayTestHelper<i::ExternalIntArray, int32_t>(
10732      v8::kExternalIntArray,
10733      INT_MIN,   // -2147483648
10734      INT_MAX);  //  2147483647
10735}
10736
10737
10738THREADED_TEST(ExternalUnsignedIntArray) {
10739  ExternalArrayTestHelper<i::ExternalUnsignedIntArray, uint32_t>(
10740      v8::kExternalUnsignedIntArray,
10741      0,
10742      UINT_MAX);  // 4294967295
10743}
10744
10745
10746THREADED_TEST(ExternalFloatArray) {
10747  ExternalArrayTestHelper<i::ExternalFloatArray, float>(
10748      v8::kExternalFloatArray,
10749      -500,
10750      500);
10751}
10752
10753
10754THREADED_TEST(ExternalArrays) {
10755  TestExternalByteArray();
10756  TestExternalUnsignedByteArray();
10757  TestExternalShortArray();
10758  TestExternalUnsignedShortArray();
10759  TestExternalIntArray();
10760  TestExternalUnsignedIntArray();
10761  TestExternalFloatArray();
10762}
10763
10764
10765void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
10766  v8::HandleScope scope;
10767  LocalContext context;
10768  for (int size = 0; size < 100; size += 10) {
10769    int element_size = ExternalArrayElementSize(array_type);
10770    void* external_data = malloc(size * element_size);
10771    v8::Handle<v8::Object> obj = v8::Object::New();
10772    obj->SetIndexedPropertiesToExternalArrayData(
10773        external_data, array_type, size);
10774    CHECK(obj->HasIndexedPropertiesInExternalArrayData());
10775    CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
10776    CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
10777    CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
10778    free(external_data);
10779  }
10780}
10781
10782
10783THREADED_TEST(ExternalArrayInfo) {
10784  ExternalArrayInfoTestHelper(v8::kExternalByteArray);
10785  ExternalArrayInfoTestHelper(v8::kExternalUnsignedByteArray);
10786  ExternalArrayInfoTestHelper(v8::kExternalShortArray);
10787  ExternalArrayInfoTestHelper(v8::kExternalUnsignedShortArray);
10788  ExternalArrayInfoTestHelper(v8::kExternalIntArray);
10789  ExternalArrayInfoTestHelper(v8::kExternalUnsignedIntArray);
10790  ExternalArrayInfoTestHelper(v8::kExternalFloatArray);
10791}
10792
10793
10794THREADED_TEST(ScriptContextDependence) {
10795  v8::HandleScope scope;
10796  LocalContext c1;
10797  const char *source = "foo";
10798  v8::Handle<v8::Script> dep = v8::Script::Compile(v8::String::New(source));
10799  v8::Handle<v8::Script> indep = v8::Script::New(v8::String::New(source));
10800  c1->Global()->Set(v8::String::New("foo"), v8::Integer::New(100));
10801  CHECK_EQ(dep->Run()->Int32Value(), 100);
10802  CHECK_EQ(indep->Run()->Int32Value(), 100);
10803  LocalContext c2;
10804  c2->Global()->Set(v8::String::New("foo"), v8::Integer::New(101));
10805  CHECK_EQ(dep->Run()->Int32Value(), 100);
10806  CHECK_EQ(indep->Run()->Int32Value(), 101);
10807}
10808
10809
10810THREADED_TEST(StackTrace) {
10811  v8::HandleScope scope;
10812  LocalContext context;
10813  v8::TryCatch try_catch;
10814  const char *source = "function foo() { FAIL.FAIL; }; foo();";
10815  v8::Handle<v8::String> src = v8::String::New(source);
10816  v8::Handle<v8::String> origin = v8::String::New("stack-trace-test");
10817  v8::Script::New(src, origin)->Run();
10818  CHECK(try_catch.HasCaught());
10819  v8::String::Utf8Value stack(try_catch.StackTrace());
10820  CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
10821}
10822
10823
10824// Checks that a StackFrame has certain expected values.
10825void checkStackFrame(const char* expected_script_name,
10826    const char* expected_func_name, int expected_line_number,
10827    int expected_column, bool is_eval, bool is_constructor,
10828    v8::Handle<v8::StackFrame> frame) {
10829  v8::HandleScope scope;
10830  v8::String::Utf8Value func_name(frame->GetFunctionName());
10831  v8::String::Utf8Value script_name(frame->GetScriptName());
10832  if (*script_name == NULL) {
10833    // The situation where there is no associated script, like for evals.
10834    CHECK(expected_script_name == NULL);
10835  } else {
10836    CHECK(strstr(*script_name, expected_script_name) != NULL);
10837  }
10838  CHECK(strstr(*func_name, expected_func_name) != NULL);
10839  CHECK_EQ(expected_line_number, frame->GetLineNumber());
10840  CHECK_EQ(expected_column, frame->GetColumn());
10841  CHECK_EQ(is_eval, frame->IsEval());
10842  CHECK_EQ(is_constructor, frame->IsConstructor());
10843}
10844
10845
10846v8::Handle<Value> AnalyzeStackInNativeCode(const v8::Arguments& args) {
10847  v8::HandleScope scope;
10848  const char* origin = "capture-stack-trace-test";
10849  const int kOverviewTest = 1;
10850  const int kDetailedTest = 2;
10851
10852  ASSERT(args.Length() == 1);
10853
10854  int testGroup = args[0]->Int32Value();
10855  if (testGroup == kOverviewTest) {
10856    v8::Handle<v8::StackTrace> stackTrace =
10857        v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kOverview);
10858    CHECK_EQ(4, stackTrace->GetFrameCount());
10859    checkStackFrame(origin, "bar", 2, 10, false, false,
10860                    stackTrace->GetFrame(0));
10861    checkStackFrame(origin, "foo", 6, 3, false, false,
10862                    stackTrace->GetFrame(1));
10863    checkStackFrame(NULL, "", 1, 1, false, false,
10864                    stackTrace->GetFrame(2));
10865    // The last frame is an anonymous function that has the initial call.
10866    checkStackFrame(origin, "", 8, 7, false, false,
10867                    stackTrace->GetFrame(3));
10868
10869    CHECK(stackTrace->AsArray()->IsArray());
10870  } else if (testGroup == kDetailedTest) {
10871    v8::Handle<v8::StackTrace> stackTrace =
10872        v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
10873    CHECK_EQ(4, stackTrace->GetFrameCount());
10874    checkStackFrame(origin, "bat", 4, 22, false, false,
10875                    stackTrace->GetFrame(0));
10876    checkStackFrame(origin, "baz", 8, 3, false, true,
10877                    stackTrace->GetFrame(1));
10878#ifdef ENABLE_DEBUGGER_SUPPORT
10879    bool is_eval = true;
10880#else  // ENABLE_DEBUGGER_SUPPORT
10881    bool is_eval = false;
10882#endif  // ENABLE_DEBUGGER_SUPPORT
10883
10884    checkStackFrame(NULL, "", 1, 1, is_eval, false,
10885                    stackTrace->GetFrame(2));
10886    // The last frame is an anonymous function that has the initial call to foo.
10887    checkStackFrame(origin, "", 10, 1, false, false,
10888                    stackTrace->GetFrame(3));
10889
10890    CHECK(stackTrace->AsArray()->IsArray());
10891  }
10892  return v8::Undefined();
10893}
10894
10895
10896// Tests the C++ StackTrace API.
10897// TODO(3074796): Reenable this as a THREADED_TEST once it passes.
10898// THREADED_TEST(CaptureStackTrace) {
10899TEST(CaptureStackTrace) {
10900  v8::HandleScope scope;
10901  v8::Handle<v8::String> origin = v8::String::New("capture-stack-trace-test");
10902  Local<ObjectTemplate> templ = ObjectTemplate::New();
10903  templ->Set(v8_str("AnalyzeStackInNativeCode"),
10904             v8::FunctionTemplate::New(AnalyzeStackInNativeCode));
10905  LocalContext context(0, templ);
10906
10907  // Test getting OVERVIEW information. Should ignore information that is not
10908  // script name, function name, line number, and column offset.
10909  const char *overview_source =
10910    "function bar() {\n"
10911    "  var y; AnalyzeStackInNativeCode(1);\n"
10912    "}\n"
10913    "function foo() {\n"
10914    "\n"
10915    "  bar();\n"
10916    "}\n"
10917    "var x;eval('new foo();');";
10918  v8::Handle<v8::String> overview_src = v8::String::New(overview_source);
10919  v8::Handle<Value> overview_result =
10920      v8::Script::New(overview_src, origin)->Run();
10921  ASSERT(!overview_result.IsEmpty());
10922  ASSERT(overview_result->IsObject());
10923
10924  // Test getting DETAILED information.
10925  const char *detailed_source =
10926    "function bat() {AnalyzeStackInNativeCode(2);\n"
10927    "}\n"
10928    "\n"
10929    "function baz() {\n"
10930    "  bat();\n"
10931    "}\n"
10932    "eval('new baz();');";
10933  v8::Handle<v8::String> detailed_src = v8::String::New(detailed_source);
10934  // Make the script using a non-zero line and column offset.
10935  v8::Handle<v8::Integer> line_offset = v8::Integer::New(3);
10936  v8::Handle<v8::Integer> column_offset = v8::Integer::New(5);
10937  v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
10938  v8::Handle<v8::Script> detailed_script(
10939      v8::Script::New(detailed_src, &detailed_origin));
10940  v8::Handle<Value> detailed_result = detailed_script->Run();
10941  ASSERT(!detailed_result.IsEmpty());
10942  ASSERT(detailed_result->IsObject());
10943}
10944
10945
10946static void StackTraceForUncaughtExceptionListener(
10947    v8::Handle<v8::Message> message,
10948    v8::Handle<Value>) {
10949  v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
10950  CHECK_EQ(2, stack_trace->GetFrameCount());
10951  checkStackFrame("origin", "foo", 2, 3, false, false,
10952                  stack_trace->GetFrame(0));
10953  checkStackFrame("origin", "bar", 5, 3, false, false,
10954                  stack_trace->GetFrame(1));
10955}
10956
10957TEST(CaptureStackTraceForUncaughtException) {
10958  report_count = 0;
10959  v8::HandleScope scope;
10960  LocalContext env;
10961  v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
10962  v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
10963
10964  Script::Compile(v8_str("function foo() {\n"
10965                         "  throw 1;\n"
10966                         "};\n"
10967                         "function bar() {\n"
10968                         "  foo();\n"
10969                         "};"),
10970                  v8_str("origin"))->Run();
10971  v8::Local<v8::Object> global = env->Global();
10972  Local<Value> trouble = global->Get(v8_str("bar"));
10973  CHECK(trouble->IsFunction());
10974  Function::Cast(*trouble)->Call(global, 0, NULL);
10975  v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
10976  v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
10977}
10978
10979
10980v8::Handle<Value> AnalyzeStackOfEvalWithSourceURL(const v8::Arguments& args) {
10981  v8::HandleScope scope;
10982  v8::Handle<v8::StackTrace> stackTrace =
10983      v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
10984  CHECK_EQ(5, stackTrace->GetFrameCount());
10985  v8::Handle<v8::String> url = v8_str("eval_url");
10986  for (int i = 0; i < 3; i++) {
10987    v8::Handle<v8::String> name =
10988        stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
10989    CHECK(!name.IsEmpty());
10990    CHECK_EQ(url, name);
10991  }
10992  return v8::Undefined();
10993}
10994
10995
10996TEST(SourceURLInStackTrace) {
10997  v8::HandleScope scope;
10998  Local<ObjectTemplate> templ = ObjectTemplate::New();
10999  templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
11000             v8::FunctionTemplate::New(AnalyzeStackOfEvalWithSourceURL));
11001  LocalContext context(0, templ);
11002
11003  const char *source =
11004    "function outer() {\n"
11005    "function bar() {\n"
11006    "  AnalyzeStackOfEvalWithSourceURL();\n"
11007    "}\n"
11008    "function foo() {\n"
11009    "\n"
11010    "  bar();\n"
11011    "}\n"
11012    "foo();\n"
11013    "}\n"
11014    "eval('(' + outer +')()//@ sourceURL=eval_url');";
11015  CHECK(CompileRun(source)->IsUndefined());
11016}
11017
11018
11019// Test that idle notification can be handled and eventually returns true.
11020THREADED_TEST(IdleNotification) {
11021  bool rv = false;
11022  for (int i = 0; i < 100; i++) {
11023    rv = v8::V8::IdleNotification();
11024    if (rv)
11025      break;
11026  }
11027  CHECK(rv == true);
11028}
11029
11030
11031static uint32_t* stack_limit;
11032
11033static v8::Handle<Value> GetStackLimitCallback(const v8::Arguments& args) {
11034  stack_limit = reinterpret_cast<uint32_t*>(i::StackGuard::real_climit());
11035  return v8::Undefined();
11036}
11037
11038
11039// Uses the address of a local variable to determine the stack top now.
11040// Given a size, returns an address that is that far from the current
11041// top of stack.
11042static uint32_t* ComputeStackLimit(uint32_t size) {
11043  uint32_t* answer = &size - (size / sizeof(size));
11044  // If the size is very large and the stack is very near the bottom of
11045  // memory then the calculation above may wrap around and give an address
11046  // that is above the (downwards-growing) stack.  In that case we return
11047  // a very low address.
11048  if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
11049  return answer;
11050}
11051
11052
11053TEST(SetResourceConstraints) {
11054  static const int K = 1024;
11055  uint32_t* set_limit = ComputeStackLimit(128 * K);
11056
11057  // Set stack limit.
11058  v8::ResourceConstraints constraints;
11059  constraints.set_stack_limit(set_limit);
11060  CHECK(v8::SetResourceConstraints(&constraints));
11061
11062  // Execute a script.
11063  v8::HandleScope scope;
11064  LocalContext env;
11065  Local<v8::FunctionTemplate> fun_templ =
11066      v8::FunctionTemplate::New(GetStackLimitCallback);
11067  Local<Function> fun = fun_templ->GetFunction();
11068  env->Global()->Set(v8_str("get_stack_limit"), fun);
11069  CompileRun("get_stack_limit();");
11070
11071  CHECK(stack_limit == set_limit);
11072}
11073
11074
11075TEST(SetResourceConstraintsInThread) {
11076  uint32_t* set_limit;
11077  {
11078    v8::Locker locker;
11079    static const int K = 1024;
11080    set_limit = ComputeStackLimit(128 * K);
11081
11082    // Set stack limit.
11083    v8::ResourceConstraints constraints;
11084    constraints.set_stack_limit(set_limit);
11085    CHECK(v8::SetResourceConstraints(&constraints));
11086
11087    // Execute a script.
11088    v8::HandleScope scope;
11089    LocalContext env;
11090    Local<v8::FunctionTemplate> fun_templ =
11091        v8::FunctionTemplate::New(GetStackLimitCallback);
11092    Local<Function> fun = fun_templ->GetFunction();
11093    env->Global()->Set(v8_str("get_stack_limit"), fun);
11094    CompileRun("get_stack_limit();");
11095
11096    CHECK(stack_limit == set_limit);
11097  }
11098  {
11099    v8::Locker locker;
11100    CHECK(stack_limit == set_limit);
11101  }
11102}
11103
11104
11105THREADED_TEST(GetHeapStatistics) {
11106  v8::HandleScope scope;
11107  LocalContext c1;
11108  v8::HeapStatistics heap_statistics;
11109  CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
11110  CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
11111  v8::V8::GetHeapStatistics(&heap_statistics);
11112  CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
11113  CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
11114}
11115
11116
11117static double DoubleFromBits(uint64_t value) {
11118  double target;
11119#ifdef BIG_ENDIAN_FLOATING_POINT
11120  const int kIntSize = 4;
11121  // Somebody swapped the lower and higher half of doubles.
11122  memcpy(&target, reinterpret_cast<char*>(&value) + kIntSize, kIntSize);
11123  memcpy(reinterpret_cast<char*>(&target) + kIntSize, &value, kIntSize);
11124#else
11125  memcpy(&target, &value, sizeof(target));
11126#endif
11127  return target;
11128}
11129
11130
11131static uint64_t DoubleToBits(double value) {
11132  uint64_t target;
11133#ifdef BIG_ENDIAN_FLOATING_POINT
11134  const int kIntSize = 4;
11135  // Somebody swapped the lower and higher half of doubles.
11136  memcpy(&target, reinterpret_cast<char*>(&value) + kIntSize, kIntSize);
11137  memcpy(reinterpret_cast<char*>(&target) + kIntSize, &value, kIntSize);
11138#else
11139  memcpy(&target, &value, sizeof(target));
11140#endif
11141  return target;
11142}
11143
11144
11145static double DoubleToDateTime(double input) {
11146  double date_limit = 864e13;
11147  if (IsNaN(input) || input < -date_limit || input > date_limit) {
11148    return i::OS::nan_value();
11149  }
11150  return (input < 0) ? -(floor(-input)) : floor(input);
11151}
11152
11153// We don't have a consistent way to write 64-bit constants syntactically, so we
11154// split them into two 32-bit constants and combine them programmatically.
11155static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
11156  return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
11157}
11158
11159
11160THREADED_TEST(QuietSignalingNaNs) {
11161  v8::HandleScope scope;
11162  LocalContext context;
11163  v8::TryCatch try_catch;
11164
11165  // Special double values.
11166  double snan = DoubleFromBits(0x7ff00000, 0x00000001);
11167  double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
11168  double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
11169  double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
11170  double min_normal = DoubleFromBits(0x00100000, 0x00000000);
11171  double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
11172  double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
11173
11174  // Date values are capped at +/-100000000 days (times 864e5 ms per day)
11175  // on either side of the epoch.
11176  double date_limit = 864e13;
11177
11178  double test_values[] = {
11179      snan,
11180      qnan,
11181      infinity,
11182      max_normal,
11183      date_limit + 1,
11184      date_limit,
11185      min_normal,
11186      max_denormal,
11187      min_denormal,
11188      0,
11189      -0,
11190      -min_denormal,
11191      -max_denormal,
11192      -min_normal,
11193      -date_limit,
11194      -date_limit - 1,
11195      -max_normal,
11196      -infinity,
11197      -qnan,
11198      -snan
11199  };
11200  int num_test_values = 20;
11201
11202  for (int i = 0; i < num_test_values; i++) {
11203    double test_value = test_values[i];
11204
11205    // Check that Number::New preserves non-NaNs and quiets SNaNs.
11206    v8::Handle<v8::Value> number = v8::Number::New(test_value);
11207    double stored_number = number->NumberValue();
11208    if (!IsNaN(test_value)) {
11209      CHECK_EQ(test_value, stored_number);
11210    } else {
11211      uint64_t stored_bits = DoubleToBits(stored_number);
11212      // Check if quiet nan (bits 51..62 all set).
11213      CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
11214    }
11215
11216    // Check that Date::New preserves non-NaNs in the date range and
11217    // quiets SNaNs.
11218    v8::Handle<v8::Value> date = v8::Date::New(test_value);
11219    double expected_stored_date = DoubleToDateTime(test_value);
11220    double stored_date = date->NumberValue();
11221    if (!IsNaN(expected_stored_date)) {
11222      CHECK_EQ(expected_stored_date, stored_date);
11223    } else {
11224      uint64_t stored_bits = DoubleToBits(stored_date);
11225      // Check if quiet nan (bits 51..62 all set).
11226      CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
11227    }
11228  }
11229}
11230
11231
11232static v8::Handle<Value> SpaghettiIncident(const v8::Arguments& args) {
11233  v8::HandleScope scope;
11234  v8::TryCatch tc;
11235  v8::Handle<v8::String> str = args[0]->ToString();
11236  if (tc.HasCaught())
11237    return tc.ReThrow();
11238  return v8::Undefined();
11239}
11240
11241
11242// Test that an exception can be propagated down through a spaghetti
11243// stack using ReThrow.
11244THREADED_TEST(SpaghettiStackReThrow) {
11245  v8::HandleScope scope;
11246  LocalContext context;
11247  context->Global()->Set(
11248      v8::String::New("s"),
11249      v8::FunctionTemplate::New(SpaghettiIncident)->GetFunction());
11250  v8::TryCatch try_catch;
11251  CompileRun(
11252      "var i = 0;"
11253      "var o = {"
11254      "  toString: function () {"
11255      "    if (i == 10) {"
11256      "      throw 'Hey!';"
11257      "    } else {"
11258      "      i++;"
11259      "      return s(o);"
11260      "    }"
11261      "  }"
11262      "};"
11263      "s(o);");
11264  CHECK(try_catch.HasCaught());
11265  v8::String::Utf8Value value(try_catch.Exception());
11266  CHECK_EQ(0, strcmp(*value, "Hey!"));
11267}
11268
11269
11270TEST(Regress528) {
11271  v8::V8::Initialize();
11272
11273  v8::HandleScope scope;
11274  v8::Persistent<Context> context;
11275  v8::Persistent<Context> other_context;
11276  int gc_count;
11277
11278  // Create a context used to keep the code from aging in the compilation
11279  // cache.
11280  other_context = Context::New();
11281
11282  // Context-dependent context data creates reference from the compilation
11283  // cache to the global object.
11284  const char* source_simple = "1";
11285  context = Context::New();
11286  {
11287    v8::HandleScope scope;
11288
11289    context->Enter();
11290    Local<v8::String> obj = v8::String::New("");
11291    context->SetData(obj);
11292    CompileRun(source_simple);
11293    context->Exit();
11294  }
11295  context.Dispose();
11296  for (gc_count = 1; gc_count < 10; gc_count++) {
11297    other_context->Enter();
11298    CompileRun(source_simple);
11299    other_context->Exit();
11300    i::Heap::CollectAllGarbage(false);
11301    if (GetGlobalObjectsCount() == 1) break;
11302  }
11303  CHECK_GE(2, gc_count);
11304  CHECK_EQ(1, GetGlobalObjectsCount());
11305
11306  // Eval in a function creates reference from the compilation cache to the
11307  // global object.
11308  const char* source_eval = "function f(){eval('1')}; f()";
11309  context = Context::New();
11310  {
11311    v8::HandleScope scope;
11312
11313    context->Enter();
11314    CompileRun(source_eval);
11315    context->Exit();
11316  }
11317  context.Dispose();
11318  for (gc_count = 1; gc_count < 10; gc_count++) {
11319    other_context->Enter();
11320    CompileRun(source_eval);
11321    other_context->Exit();
11322    i::Heap::CollectAllGarbage(false);
11323    if (GetGlobalObjectsCount() == 1) break;
11324  }
11325  CHECK_GE(2, gc_count);
11326  CHECK_EQ(1, GetGlobalObjectsCount());
11327
11328  // Looking up the line number for an exception creates reference from the
11329  // compilation cache to the global object.
11330  const char* source_exception = "function f(){throw 1;} f()";
11331  context = Context::New();
11332  {
11333    v8::HandleScope scope;
11334
11335    context->Enter();
11336    v8::TryCatch try_catch;
11337    CompileRun(source_exception);
11338    CHECK(try_catch.HasCaught());
11339    v8::Handle<v8::Message> message = try_catch.Message();
11340    CHECK(!message.IsEmpty());
11341    CHECK_EQ(1, message->GetLineNumber());
11342    context->Exit();
11343  }
11344  context.Dispose();
11345  for (gc_count = 1; gc_count < 10; gc_count++) {
11346    other_context->Enter();
11347    CompileRun(source_exception);
11348    other_context->Exit();
11349    i::Heap::CollectAllGarbage(false);
11350    if (GetGlobalObjectsCount() == 1) break;
11351  }
11352  CHECK_GE(2, gc_count);
11353  CHECK_EQ(1, GetGlobalObjectsCount());
11354
11355  other_context.Dispose();
11356}
11357
11358
11359THREADED_TEST(ScriptOrigin) {
11360  v8::HandleScope scope;
11361  LocalContext env;
11362  v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
11363  v8::Handle<v8::String> script = v8::String::New(
11364      "function f() {}\n\nfunction g() {}");
11365  v8::Script::Compile(script, &origin)->Run();
11366  v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
11367      env->Global()->Get(v8::String::New("f")));
11368  v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
11369      env->Global()->Get(v8::String::New("g")));
11370
11371  v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
11372  CHECK_EQ("test", *v8::String::AsciiValue(script_origin_f.ResourceName()));
11373  CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
11374
11375  v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
11376  CHECK_EQ("test", *v8::String::AsciiValue(script_origin_g.ResourceName()));
11377  CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
11378}
11379
11380
11381THREADED_TEST(ScriptLineNumber) {
11382  v8::HandleScope scope;
11383  LocalContext env;
11384  v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
11385  v8::Handle<v8::String> script = v8::String::New(
11386      "function f() {}\n\nfunction g() {}");
11387  v8::Script::Compile(script, &origin)->Run();
11388  v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
11389      env->Global()->Get(v8::String::New("f")));
11390  v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
11391      env->Global()->Get(v8::String::New("g")));
11392  CHECK_EQ(0, f->GetScriptLineNumber());
11393  CHECK_EQ(2, g->GetScriptLineNumber());
11394}
11395
11396
11397static v8::Handle<Value> GetterWhichReturns42(Local<String> name,
11398                                              const AccessorInfo& info) {
11399  return v8_num(42);
11400}
11401
11402
11403static void SetterWhichSetsYOnThisTo23(Local<String> name,
11404                                       Local<Value> value,
11405                                       const AccessorInfo& info) {
11406  info.This()->Set(v8_str("y"), v8_num(23));
11407}
11408
11409
11410TEST(SetterOnConstructorPrototype) {
11411  v8::HandleScope scope;
11412  Local<ObjectTemplate> templ = ObjectTemplate::New();
11413  templ->SetAccessor(v8_str("x"),
11414                     GetterWhichReturns42,
11415                     SetterWhichSetsYOnThisTo23);
11416  LocalContext context;
11417  context->Global()->Set(v8_str("P"), templ->NewInstance());
11418  CompileRun("function C1() {"
11419             "  this.x = 23;"
11420             "};"
11421             "C1.prototype = P;"
11422             "function C2() {"
11423             "  this.x = 23"
11424             "};"
11425             "C2.prototype = { };"
11426             "C2.prototype.__proto__ = P;");
11427
11428  v8::Local<v8::Script> script;
11429  script = v8::Script::Compile(v8_str("new C1();"));
11430  for (int i = 0; i < 10; i++) {
11431    v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
11432    CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
11433    CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
11434  }
11435
11436  script = v8::Script::Compile(v8_str("new C2();"));
11437  for (int i = 0; i < 10; i++) {
11438    v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
11439    CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
11440    CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
11441  }
11442}
11443
11444
11445static v8::Handle<Value> NamedPropertyGetterWhichReturns42(
11446    Local<String> name, const AccessorInfo& info) {
11447  return v8_num(42);
11448}
11449
11450
11451static v8::Handle<Value> NamedPropertySetterWhichSetsYOnThisTo23(
11452    Local<String> name, Local<Value> value, const AccessorInfo& info) {
11453  if (name->Equals(v8_str("x"))) {
11454    info.This()->Set(v8_str("y"), v8_num(23));
11455  }
11456  return v8::Handle<Value>();
11457}
11458
11459
11460THREADED_TEST(InterceptorOnConstructorPrototype) {
11461  v8::HandleScope scope;
11462  Local<ObjectTemplate> templ = ObjectTemplate::New();
11463  templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
11464                                 NamedPropertySetterWhichSetsYOnThisTo23);
11465  LocalContext context;
11466  context->Global()->Set(v8_str("P"), templ->NewInstance());
11467  CompileRun("function C1() {"
11468             "  this.x = 23;"
11469             "};"
11470             "C1.prototype = P;"
11471             "function C2() {"
11472             "  this.x = 23"
11473             "};"
11474             "C2.prototype = { };"
11475             "C2.prototype.__proto__ = P;");
11476
11477  v8::Local<v8::Script> script;
11478  script = v8::Script::Compile(v8_str("new C1();"));
11479  for (int i = 0; i < 10; i++) {
11480    v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
11481    CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
11482    CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
11483  }
11484
11485  script = v8::Script::Compile(v8_str("new C2();"));
11486  for (int i = 0; i < 10; i++) {
11487    v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
11488    CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
11489    CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
11490  }
11491}
11492
11493
11494TEST(Bug618) {
11495  const char* source = "function C1() {"
11496                       "  this.x = 23;"
11497                       "};"
11498                       "C1.prototype = P;";
11499
11500  v8::HandleScope scope;
11501  LocalContext context;
11502  v8::Local<v8::Script> script;
11503
11504  // Use a simple object as prototype.
11505  v8::Local<v8::Object> prototype = v8::Object::New();
11506  prototype->Set(v8_str("y"), v8_num(42));
11507  context->Global()->Set(v8_str("P"), prototype);
11508
11509  // This compile will add the code to the compilation cache.
11510  CompileRun(source);
11511
11512  script = v8::Script::Compile(v8_str("new C1();"));
11513  // Allow enough iterations for the inobject slack tracking logic
11514  // to finalize instance size and install the fast construct stub.
11515  for (int i = 0; i < 256; i++) {
11516    v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
11517    CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
11518    CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
11519  }
11520
11521  // Use an API object with accessors as prototype.
11522  Local<ObjectTemplate> templ = ObjectTemplate::New();
11523  templ->SetAccessor(v8_str("x"),
11524                     GetterWhichReturns42,
11525                     SetterWhichSetsYOnThisTo23);
11526  context->Global()->Set(v8_str("P"), templ->NewInstance());
11527
11528  // This compile will get the code from the compilation cache.
11529  CompileRun(source);
11530
11531  script = v8::Script::Compile(v8_str("new C1();"));
11532  for (int i = 0; i < 10; i++) {
11533    v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
11534    CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
11535    CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
11536  }
11537}
11538
11539int prologue_call_count = 0;
11540int epilogue_call_count = 0;
11541int prologue_call_count_second = 0;
11542int epilogue_call_count_second = 0;
11543
11544void PrologueCallback(v8::GCType, v8::GCCallbackFlags) {
11545  ++prologue_call_count;
11546}
11547
11548void EpilogueCallback(v8::GCType, v8::GCCallbackFlags) {
11549  ++epilogue_call_count;
11550}
11551
11552void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
11553  ++prologue_call_count_second;
11554}
11555
11556void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
11557  ++epilogue_call_count_second;
11558}
11559
11560TEST(GCCallbacks) {
11561  LocalContext context;
11562
11563  v8::V8::AddGCPrologueCallback(PrologueCallback);
11564  v8::V8::AddGCEpilogueCallback(EpilogueCallback);
11565  CHECK_EQ(0, prologue_call_count);
11566  CHECK_EQ(0, epilogue_call_count);
11567  i::Heap::CollectAllGarbage(false);
11568  CHECK_EQ(1, prologue_call_count);
11569  CHECK_EQ(1, epilogue_call_count);
11570  v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
11571  v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
11572  i::Heap::CollectAllGarbage(false);
11573  CHECK_EQ(2, prologue_call_count);
11574  CHECK_EQ(2, epilogue_call_count);
11575  CHECK_EQ(1, prologue_call_count_second);
11576  CHECK_EQ(1, epilogue_call_count_second);
11577  v8::V8::RemoveGCPrologueCallback(PrologueCallback);
11578  v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
11579  i::Heap::CollectAllGarbage(false);
11580  CHECK_EQ(2, prologue_call_count);
11581  CHECK_EQ(2, epilogue_call_count);
11582  CHECK_EQ(2, prologue_call_count_second);
11583  CHECK_EQ(2, epilogue_call_count_second);
11584  v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
11585  v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
11586  i::Heap::CollectAllGarbage(false);
11587  CHECK_EQ(2, prologue_call_count);
11588  CHECK_EQ(2, epilogue_call_count);
11589  CHECK_EQ(2, prologue_call_count_second);
11590  CHECK_EQ(2, epilogue_call_count_second);
11591}
11592
11593
11594THREADED_TEST(AddToJSFunctionResultCache) {
11595  i::FLAG_allow_natives_syntax = true;
11596  v8::HandleScope scope;
11597
11598  LocalContext context;
11599
11600  const char* code =
11601      "(function() {"
11602      "  var key0 = 'a';"
11603      "  var key1 = 'b';"
11604      "  var r0 = %_GetFromCache(0, key0);"
11605      "  var r1 = %_GetFromCache(0, key1);"
11606      "  var r0_ = %_GetFromCache(0, key0);"
11607      "  if (r0 !== r0_)"
11608      "    return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
11609      "  var r1_ = %_GetFromCache(0, key1);"
11610      "  if (r1 !== r1_)"
11611      "    return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
11612      "  return 'PASSED';"
11613      "})()";
11614  i::Heap::ClearJSFunctionResultCaches();
11615  ExpectString(code, "PASSED");
11616}
11617
11618
11619static const int k0CacheSize = 16;
11620
11621THREADED_TEST(FillJSFunctionResultCache) {
11622  i::FLAG_allow_natives_syntax = true;
11623  v8::HandleScope scope;
11624
11625  LocalContext context;
11626
11627  const char* code =
11628      "(function() {"
11629      "  var k = 'a';"
11630      "  var r = %_GetFromCache(0, k);"
11631      "  for (var i = 0; i < 16; i++) {"
11632      "    %_GetFromCache(0, 'a' + i);"
11633      "  };"
11634      "  if (r === %_GetFromCache(0, k))"
11635      "    return 'FAILED: k0CacheSize is too small';"
11636      "  return 'PASSED';"
11637      "})()";
11638  i::Heap::ClearJSFunctionResultCaches();
11639  ExpectString(code, "PASSED");
11640}
11641
11642
11643THREADED_TEST(RoundRobinGetFromCache) {
11644  i::FLAG_allow_natives_syntax = true;
11645  v8::HandleScope scope;
11646
11647  LocalContext context;
11648
11649  const char* code =
11650      "(function() {"
11651      "  var keys = [];"
11652      "  for (var i = 0; i < 16; i++) keys.push(i);"
11653      "  var values = [];"
11654      "  for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
11655      "  for (var i = 0; i < 16; i++) {"
11656      "    var v = %_GetFromCache(0, keys[i]);"
11657      "    if (v !== values[i])"
11658      "      return 'Wrong value for ' + "
11659      "          keys[i] + ': ' + v + ' vs. ' + values[i];"
11660      "  };"
11661      "  return 'PASSED';"
11662      "})()";
11663  i::Heap::ClearJSFunctionResultCaches();
11664  ExpectString(code, "PASSED");
11665}
11666
11667
11668THREADED_TEST(ReverseGetFromCache) {
11669  i::FLAG_allow_natives_syntax = true;
11670  v8::HandleScope scope;
11671
11672  LocalContext context;
11673
11674  const char* code =
11675      "(function() {"
11676      "  var keys = [];"
11677      "  for (var i = 0; i < 16; i++) keys.push(i);"
11678      "  var values = [];"
11679      "  for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
11680      "  for (var i = 15; i >= 16; i--) {"
11681      "    var v = %_GetFromCache(0, keys[i]);"
11682      "    if (v !== values[i])"
11683      "      return 'Wrong value for ' + "
11684      "          keys[i] + ': ' + v + ' vs. ' + values[i];"
11685      "  };"
11686      "  return 'PASSED';"
11687      "})()";
11688  i::Heap::ClearJSFunctionResultCaches();
11689  ExpectString(code, "PASSED");
11690}
11691
11692
11693THREADED_TEST(TestEviction) {
11694  i::FLAG_allow_natives_syntax = true;
11695  v8::HandleScope scope;
11696
11697  LocalContext context;
11698
11699  const char* code =
11700      "(function() {"
11701      "  for (var i = 0; i < 2*16; i++) {"
11702      "    %_GetFromCache(0, 'a' + i);"
11703      "  };"
11704      "  return 'PASSED';"
11705      "})()";
11706  i::Heap::ClearJSFunctionResultCaches();
11707  ExpectString(code, "PASSED");
11708}
11709
11710
11711THREADED_TEST(TwoByteStringInAsciiCons) {
11712  // See Chromium issue 47824.
11713  v8::HandleScope scope;
11714
11715  LocalContext context;
11716  const char* init_code =
11717      "var str1 = 'abelspendabel';"
11718      "var str2 = str1 + str1 + str1;"
11719      "str2;";
11720  Local<Value> result = CompileRun(init_code);
11721
11722  CHECK(result->IsString());
11723  i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
11724  int length = string->length();
11725  CHECK(string->IsAsciiRepresentation());
11726
11727  FlattenString(string);
11728  i::Handle<i::String> flat_string = FlattenGetString(string);
11729
11730  CHECK(string->IsAsciiRepresentation());
11731  CHECK(flat_string->IsAsciiRepresentation());
11732
11733  // Create external resource.
11734  uint16_t* uc16_buffer = new uint16_t[length + 1];
11735
11736  i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
11737  uc16_buffer[length] = 0;
11738
11739  TestResource resource(uc16_buffer);
11740
11741  flat_string->MakeExternal(&resource);
11742
11743  CHECK(flat_string->IsTwoByteRepresentation());
11744
11745  // At this point, we should have a Cons string which is flat and ASCII,
11746  // with a first half that is a two-byte string (although it only contains
11747  // ASCII characters). This is a valid sequence of steps, and it can happen
11748  // in real pages.
11749
11750  CHECK(string->IsAsciiRepresentation());
11751  i::ConsString* cons = i::ConsString::cast(*string);
11752  CHECK_EQ(0, cons->second()->length());
11753  CHECK(cons->first()->IsTwoByteRepresentation());
11754
11755  // Check that some string operations work.
11756
11757  // Atom RegExp.
11758  Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
11759  CHECK_EQ(6, reresult->Int32Value());
11760
11761  // Nonatom RegExp.
11762  reresult = CompileRun("str2.match(/abe./g).length;");
11763  CHECK_EQ(6, reresult->Int32Value());
11764
11765  reresult = CompileRun("str2.search(/bel/g);");
11766  CHECK_EQ(1, reresult->Int32Value());
11767
11768  reresult = CompileRun("str2.search(/be./g);");
11769  CHECK_EQ(1, reresult->Int32Value());
11770
11771  ExpectTrue("/bel/g.test(str2);");
11772
11773  ExpectTrue("/be./g.test(str2);");
11774
11775  reresult = CompileRun("/bel/g.exec(str2);");
11776  CHECK(!reresult->IsNull());
11777
11778  reresult = CompileRun("/be./g.exec(str2);");
11779  CHECK(!reresult->IsNull());
11780
11781  ExpectString("str2.substring(2, 10);", "elspenda");
11782
11783  ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
11784
11785  ExpectString("str2.charAt(2);", "e");
11786
11787  reresult = CompileRun("str2.charCodeAt(2);");
11788  CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
11789}
11790
11791
11792// Failed access check callback that performs a GC on each invocation.
11793void FailedAccessCheckCallbackGC(Local<v8::Object> target,
11794                                 v8::AccessType type,
11795                                 Local<v8::Value> data) {
11796  i::Heap::CollectAllGarbage(true);
11797}
11798
11799
11800TEST(GCInFailedAccessCheckCallback) {
11801  // Install a failed access check callback that performs a GC on each
11802  // invocation. Then force the callback to be called from va
11803
11804  v8::V8::Initialize();
11805  v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
11806
11807  v8::HandleScope scope;
11808
11809  // Create an ObjectTemplate for global objects and install access
11810  // check callbacks that will block access.
11811  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
11812  global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
11813                                           IndexedGetAccessBlocker,
11814                                           v8::Handle<v8::Value>(),
11815                                           false);
11816
11817  // Create a context and set an x property on it's global object.
11818  LocalContext context0(NULL, global_template);
11819  context0->Global()->Set(v8_str("x"), v8_num(42));
11820  v8::Handle<v8::Object> global0 = context0->Global();
11821
11822  // Create a context with a different security token so that the
11823  // failed access check callback will be called on each access.
11824  LocalContext context1(NULL, global_template);
11825  context1->Global()->Set(v8_str("other"), global0);
11826
11827  // Get property with failed access check.
11828  ExpectUndefined("other.x");
11829
11830  // Get element with failed access check.
11831  ExpectUndefined("other[0]");
11832
11833  // Set property with failed access check.
11834  v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
11835  CHECK(result->IsObject());
11836
11837  // Set element with failed access check.
11838  result = CompileRun("other[0] = new Object()");
11839  CHECK(result->IsObject());
11840
11841  // Get property attribute with failed access check.
11842  ExpectFalse("\'x\' in other");
11843
11844  // Get property attribute for element with failed access check.
11845  ExpectFalse("0 in other");
11846
11847  // Delete property.
11848  ExpectFalse("delete other.x");
11849
11850  // Delete element.
11851  CHECK_EQ(false, global0->Delete(0));
11852
11853  // DefineAccessor.
11854  CHECK_EQ(false,
11855           global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
11856
11857  // Define JavaScript accessor.
11858  ExpectUndefined("Object.prototype.__defineGetter__.call("
11859                  "    other, \'x\', function() { return 42; })");
11860
11861  // LookupAccessor.
11862  ExpectUndefined("Object.prototype.__lookupGetter__.call("
11863                  "    other, \'x\')");
11864
11865  // HasLocalElement.
11866  ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
11867
11868  CHECK_EQ(false, global0->HasRealIndexedProperty(0));
11869  CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
11870  CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
11871
11872  // Reset the failed access check callback so it does not influence
11873  // the other tests.
11874  v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
11875}
11876
11877
11878TEST(StringCheckMultipleContexts) {
11879  const char* code =
11880      "(function() { return \"a\".charAt(0); })()";
11881
11882  {
11883    // Run the code twice in the first context to initialize the call IC.
11884    v8::HandleScope scope;
11885    LocalContext context1;
11886    ExpectString(code, "a");
11887    ExpectString(code, "a");
11888  }
11889
11890  {
11891    // Change the String.prototype in the second context and check
11892    // that the right function gets called.
11893    v8::HandleScope scope;
11894    LocalContext context2;
11895    CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
11896    ExpectString(code, "not a");
11897  }
11898}
11899
11900
11901TEST(NumberCheckMultipleContexts) {
11902  const char* code =
11903      "(function() { return (42).toString(); })()";
11904
11905  {
11906    // Run the code twice in the first context to initialize the call IC.
11907    v8::HandleScope scope;
11908    LocalContext context1;
11909    ExpectString(code, "42");
11910    ExpectString(code, "42");
11911  }
11912
11913  {
11914    // Change the Number.prototype in the second context and check
11915    // that the right function gets called.
11916    v8::HandleScope scope;
11917    LocalContext context2;
11918    CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
11919    ExpectString(code, "not 42");
11920  }
11921}
11922
11923
11924TEST(BooleanCheckMultipleContexts) {
11925  const char* code =
11926      "(function() { return true.toString(); })()";
11927
11928  {
11929    // Run the code twice in the first context to initialize the call IC.
11930    v8::HandleScope scope;
11931    LocalContext context1;
11932    ExpectString(code, "true");
11933    ExpectString(code, "true");
11934  }
11935
11936  {
11937    // Change the Boolean.prototype in the second context and check
11938    // that the right function gets called.
11939    v8::HandleScope scope;
11940    LocalContext context2;
11941    CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
11942    ExpectString(code, "");
11943  }
11944}
11945
11946
11947TEST(DontDeleteCellLoadIC) {
11948  const char* function_code =
11949      "function readCell() { while (true) { return cell; } }";
11950
11951  {
11952    // Run the code twice in the first context to initialize the load
11953    // IC for a don't delete cell.
11954    v8::HandleScope scope;
11955    LocalContext context1;
11956    CompileRun("var cell = \"first\";");
11957    ExpectBoolean("delete cell", false);
11958    CompileRun(function_code);
11959    ExpectString("readCell()", "first");
11960    ExpectString("readCell()", "first");
11961  }
11962
11963  {
11964    // Use a deletable cell in the second context.
11965    v8::HandleScope scope;
11966    LocalContext context2;
11967    CompileRun("cell = \"second\";");
11968    CompileRun(function_code);
11969    ExpectString("readCell()", "second");
11970    ExpectBoolean("delete cell", true);
11971    ExpectString("(function() {"
11972                 "  try {"
11973                 "    return readCell();"
11974                 "  } catch(e) {"
11975                 "    return e.toString();"
11976                 "  }"
11977                 "})()",
11978                 "ReferenceError: cell is not defined");
11979    CompileRun("cell = \"new_second\";");
11980    i::Heap::CollectAllGarbage(true);
11981    ExpectString("readCell()", "new_second");
11982    ExpectString("readCell()", "new_second");
11983  }
11984}
11985
11986
11987TEST(DontDeleteCellLoadICForceDelete) {
11988  const char* function_code =
11989      "function readCell() { while (true) { return cell; } }";
11990
11991  // Run the code twice to initialize the load IC for a don't delete
11992  // cell.
11993  v8::HandleScope scope;
11994  LocalContext context;
11995  CompileRun("var cell = \"value\";");
11996  ExpectBoolean("delete cell", false);
11997  CompileRun(function_code);
11998  ExpectString("readCell()", "value");
11999  ExpectString("readCell()", "value");
12000
12001  // Delete the cell using the API and check the inlined code works
12002  // correctly.
12003  CHECK(context->Global()->ForceDelete(v8_str("cell")));
12004  ExpectString("(function() {"
12005               "  try {"
12006               "    return readCell();"
12007               "  } catch(e) {"
12008               "    return e.toString();"
12009               "  }"
12010               "})()",
12011               "ReferenceError: cell is not defined");
12012}
12013
12014
12015TEST(DontDeleteCellLoadICAPI) {
12016  const char* function_code =
12017      "function readCell() { while (true) { return cell; } }";
12018
12019  // Run the code twice to initialize the load IC for a don't delete
12020  // cell created using the API.
12021  v8::HandleScope scope;
12022  LocalContext context;
12023  context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete);
12024  ExpectBoolean("delete cell", false);
12025  CompileRun(function_code);
12026  ExpectString("readCell()", "value");
12027  ExpectString("readCell()", "value");
12028
12029  // Delete the cell using the API and check the inlined code works
12030  // correctly.
12031  CHECK(context->Global()->ForceDelete(v8_str("cell")));
12032  ExpectString("(function() {"
12033               "  try {"
12034               "    return readCell();"
12035               "  } catch(e) {"
12036               "    return e.toString();"
12037               "  }"
12038               "})()",
12039               "ReferenceError: cell is not defined");
12040}
12041
12042
12043TEST(GlobalLoadICGC) {
12044  const char* function_code =
12045      "function readCell() { while (true) { return cell; } }";
12046
12047  // Check inline load code for a don't delete cell is cleared during
12048  // GC.
12049  {
12050    v8::HandleScope scope;
12051    LocalContext context;
12052    CompileRun("var cell = \"value\";");
12053    ExpectBoolean("delete cell", false);
12054    CompileRun(function_code);
12055    ExpectString("readCell()", "value");
12056    ExpectString("readCell()", "value");
12057  }
12058  {
12059    v8::HandleScope scope;
12060    LocalContext context2;
12061    // Hold the code object in the second context.
12062    CompileRun(function_code);
12063    CheckSurvivingGlobalObjectsCount(1);
12064  }
12065
12066  // Check inline load code for a deletable cell is cleared during GC.
12067  {
12068    v8::HandleScope scope;
12069    LocalContext context;
12070    CompileRun("cell = \"value\";");
12071    CompileRun(function_code);
12072    ExpectString("readCell()", "value");
12073    ExpectString("readCell()", "value");
12074  }
12075  {
12076    v8::HandleScope scope;
12077    LocalContext context2;
12078    // Hold the code object in the second context.
12079    CompileRun(function_code);
12080    CheckSurvivingGlobalObjectsCount(1);
12081  }
12082}
12083
12084
12085TEST(RegExp) {
12086  v8::HandleScope scope;
12087  LocalContext context;
12088
12089  v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
12090  CHECK(re->IsRegExp());
12091  CHECK(re->GetSource()->Equals(v8_str("foo")));
12092  CHECK_EQ(re->GetFlags(), v8::RegExp::kNone);
12093
12094  re = v8::RegExp::New(v8_str("bar"),
12095                       static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
12096                                                      v8::RegExp::kGlobal));
12097  CHECK(re->IsRegExp());
12098  CHECK(re->GetSource()->Equals(v8_str("bar")));
12099  CHECK_EQ(static_cast<int>(re->GetFlags()),
12100           v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal);
12101
12102  re = v8::RegExp::New(v8_str("baz"),
12103                       static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
12104                                                      v8::RegExp::kMultiline));
12105  CHECK(re->IsRegExp());
12106  CHECK(re->GetSource()->Equals(v8_str("baz")));
12107  CHECK_EQ(static_cast<int>(re->GetFlags()),
12108           v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline);
12109
12110  re = CompileRun("/quux/").As<v8::RegExp>();
12111  CHECK(re->IsRegExp());
12112  CHECK(re->GetSource()->Equals(v8_str("quux")));
12113  CHECK_EQ(re->GetFlags(), v8::RegExp::kNone);
12114
12115  re = CompileRun("/quux/gm").As<v8::RegExp>();
12116  CHECK(re->IsRegExp());
12117  CHECK(re->GetSource()->Equals(v8_str("quux")));
12118  CHECK_EQ(static_cast<int>(re->GetFlags()),
12119           v8::RegExp::kGlobal | v8::RegExp::kMultiline);
12120
12121  // Override the RegExp constructor and check the API constructor
12122  // still works.
12123  CompileRun("RegExp = function() {}");
12124
12125  re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
12126  CHECK(re->IsRegExp());
12127  CHECK(re->GetSource()->Equals(v8_str("foobar")));
12128  CHECK_EQ(re->GetFlags(), v8::RegExp::kNone);
12129
12130  re = v8::RegExp::New(v8_str("foobarbaz"),
12131                       static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
12132                                                      v8::RegExp::kMultiline));
12133  CHECK(re->IsRegExp());
12134  CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
12135  CHECK_EQ(static_cast<int>(re->GetFlags()),
12136           v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline);
12137
12138  context->Global()->Set(v8_str("re"), re);
12139  ExpectTrue("re.test('FoobarbaZ')");
12140
12141  v8::TryCatch try_catch;
12142  re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
12143  CHECK(re.IsEmpty());
12144  CHECK(try_catch.HasCaught());
12145  context->Global()->Set(v8_str("ex"), try_catch.Exception());
12146  ExpectTrue("ex instanceof SyntaxError");
12147}
12148
12149
12150static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
12151                                    const v8::AccessorInfo& info ) {
12152  return v8_str("42!");
12153}
12154
12155
12156static v8::Handle<v8::Array> Enumerator(const v8::AccessorInfo& info) {
12157  v8::Handle<v8::Array> result = v8::Array::New();
12158  result->Set(0, v8_str("universalAnswer"));
12159  return result;
12160}
12161
12162
12163TEST(NamedEnumeratorAndForIn) {
12164  v8::HandleScope handle_scope;
12165  LocalContext context;
12166  v8::Context::Scope context_scope(context.local());
12167
12168  v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New();
12169  tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
12170  context->Global()->Set(v8_str("o"), tmpl->NewInstance());
12171  v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
12172        "var result = []; for (var k in o) result.push(k); result"));
12173  CHECK_EQ(1, result->Length());
12174  CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
12175}
12176