test-api.cc revision 8a31eba00023874d4a1dcdc5f411cc4336776874
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
817THREADED_TEST(FindInstanceInPrototypeChain) {
818  v8::HandleScope scope;
819  LocalContext env;
820
821  Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New();
822  Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New();
823  Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New();
824  derived->Inherit(base);
825
826  Local<v8::Function> base_function = base->GetFunction();
827  Local<v8::Function> derived_function = derived->GetFunction();
828  Local<v8::Function> other_function = other->GetFunction();
829
830  Local<v8::Object> base_instance = base_function->NewInstance();
831  Local<v8::Object> derived_instance = derived_function->NewInstance();
832  Local<v8::Object> derived_instance2 = derived_function->NewInstance();
833  Local<v8::Object> other_instance = other_function->NewInstance();
834  derived_instance2->Set(v8_str("__proto__"), derived_instance);
835  other_instance->Set(v8_str("__proto__"), derived_instance2);
836
837  // base_instance is only an instance of base.
838  CHECK_EQ(base_instance,
839           base_instance->FindInstanceInPrototypeChain(base));
840  CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
841  CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
842
843  // derived_instance is an instance of base and derived.
844  CHECK_EQ(derived_instance,
845           derived_instance->FindInstanceInPrototypeChain(base));
846  CHECK_EQ(derived_instance,
847           derived_instance->FindInstanceInPrototypeChain(derived));
848  CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
849
850  // other_instance is an instance of other and its immediate
851  // prototype derived_instance2 is an instance of base and derived.
852  // Note, derived_instance is an instance of base and derived too,
853  // but it comes after derived_instance2 in the prototype chain of
854  // other_instance.
855  CHECK_EQ(derived_instance2,
856           other_instance->FindInstanceInPrototypeChain(base));
857  CHECK_EQ(derived_instance2,
858           other_instance->FindInstanceInPrototypeChain(derived));
859  CHECK_EQ(other_instance,
860           other_instance->FindInstanceInPrototypeChain(other));
861}
862
863
864THREADED_TEST(TinyInteger) {
865  v8::HandleScope scope;
866  LocalContext env;
867  int32_t value = 239;
868  Local<v8::Integer> value_obj = v8::Integer::New(value);
869  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
870}
871
872
873THREADED_TEST(BigSmiInteger) {
874  v8::HandleScope scope;
875  LocalContext env;
876  int32_t value = i::Smi::kMaxValue;
877  // We cannot add one to a Smi::kMaxValue without wrapping.
878  if (i::kSmiValueSize < 32) {
879    CHECK(i::Smi::IsValid(value));
880    CHECK(!i::Smi::IsValid(value + 1));
881    Local<v8::Integer> value_obj = v8::Integer::New(value);
882    CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
883  }
884}
885
886
887THREADED_TEST(BigInteger) {
888  v8::HandleScope scope;
889  LocalContext env;
890  // We cannot add one to a Smi::kMaxValue without wrapping.
891  if (i::kSmiValueSize < 32) {
892    // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
893    // The code will not be run in that case, due to the "if" guard.
894    int32_t value =
895        static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
896    CHECK(value > i::Smi::kMaxValue);
897    CHECK(!i::Smi::IsValid(value));
898    Local<v8::Integer> value_obj = v8::Integer::New(value);
899    CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
900  }
901}
902
903
904THREADED_TEST(TinyUnsignedInteger) {
905  v8::HandleScope scope;
906  LocalContext env;
907  uint32_t value = 239;
908  Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
909  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
910}
911
912
913THREADED_TEST(BigUnsignedSmiInteger) {
914  v8::HandleScope scope;
915  LocalContext env;
916  uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
917  CHECK(i::Smi::IsValid(value));
918  CHECK(!i::Smi::IsValid(value + 1));
919  Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
920  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
921}
922
923
924THREADED_TEST(BigUnsignedInteger) {
925  v8::HandleScope scope;
926  LocalContext env;
927  uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
928  CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
929  CHECK(!i::Smi::IsValid(value));
930  Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
931  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
932}
933
934
935THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
936  v8::HandleScope scope;
937  LocalContext env;
938  uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
939  uint32_t value = INT32_MAX_AS_UINT + 1;
940  CHECK(value > INT32_MAX_AS_UINT);  // No overflow.
941  Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
942  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
943}
944
945
946THREADED_TEST(Number) {
947  v8::HandleScope scope;
948  LocalContext env;
949  double PI = 3.1415926;
950  Local<v8::Number> pi_obj = v8::Number::New(PI);
951  CHECK_EQ(PI, pi_obj->NumberValue());
952}
953
954
955THREADED_TEST(ToNumber) {
956  v8::HandleScope scope;
957  LocalContext env;
958  Local<String> str = v8_str("3.1415926");
959  CHECK_EQ(3.1415926, str->NumberValue());
960  v8::Handle<v8::Boolean> t = v8::True();
961  CHECK_EQ(1.0, t->NumberValue());
962  v8::Handle<v8::Boolean> f = v8::False();
963  CHECK_EQ(0.0, f->NumberValue());
964}
965
966
967THREADED_TEST(Date) {
968  v8::HandleScope scope;
969  LocalContext env;
970  double PI = 3.1415926;
971  Local<Value> date_obj = v8::Date::New(PI);
972  CHECK_EQ(3.0, date_obj->NumberValue());
973}
974
975
976THREADED_TEST(Boolean) {
977  v8::HandleScope scope;
978  LocalContext env;
979  v8::Handle<v8::Boolean> t = v8::True();
980  CHECK(t->Value());
981  v8::Handle<v8::Boolean> f = v8::False();
982  CHECK(!f->Value());
983  v8::Handle<v8::Primitive> u = v8::Undefined();
984  CHECK(!u->BooleanValue());
985  v8::Handle<v8::Primitive> n = v8::Null();
986  CHECK(!n->BooleanValue());
987  v8::Handle<String> str1 = v8_str("");
988  CHECK(!str1->BooleanValue());
989  v8::Handle<String> str2 = v8_str("x");
990  CHECK(str2->BooleanValue());
991  CHECK(!v8::Number::New(0)->BooleanValue());
992  CHECK(v8::Number::New(-1)->BooleanValue());
993  CHECK(v8::Number::New(1)->BooleanValue());
994  CHECK(v8::Number::New(42)->BooleanValue());
995  CHECK(!v8_compile("NaN")->Run()->BooleanValue());
996}
997
998
999static v8::Handle<Value> DummyCallHandler(const v8::Arguments& args) {
1000  ApiTestFuzzer::Fuzz();
1001  return v8_num(13.4);
1002}
1003
1004
1005static v8::Handle<Value> GetM(Local<String> name, const AccessorInfo&) {
1006  ApiTestFuzzer::Fuzz();
1007  return v8_num(876);
1008}
1009
1010
1011THREADED_TEST(GlobalPrototype) {
1012  v8::HandleScope scope;
1013  v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
1014  func_templ->PrototypeTemplate()->Set(
1015      "dummy",
1016      v8::FunctionTemplate::New(DummyCallHandler));
1017  v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1018  templ->Set("x", v8_num(200));
1019  templ->SetAccessor(v8_str("m"), GetM);
1020  LocalContext env(0, templ);
1021  v8::Handle<v8::Object> obj = env->Global();
1022  v8::Handle<Script> script = v8_compile("dummy()");
1023  v8::Handle<Value> result = script->Run();
1024  CHECK_EQ(13.4, result->NumberValue());
1025  CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1026  CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1027}
1028
1029
1030THREADED_TEST(ObjectTemplate) {
1031  v8::HandleScope scope;
1032  Local<ObjectTemplate> templ1 = ObjectTemplate::New();
1033  templ1->Set("x", v8_num(10));
1034  templ1->Set("y", v8_num(13));
1035  LocalContext env;
1036  Local<v8::Object> instance1 = templ1->NewInstance();
1037  env->Global()->Set(v8_str("p"), instance1);
1038  CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1039  CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1040  Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
1041  fun->PrototypeTemplate()->Set("nirk", v8_num(123));
1042  Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1043  templ2->Set("a", v8_num(12));
1044  templ2->Set("b", templ1);
1045  Local<v8::Object> instance2 = templ2->NewInstance();
1046  env->Global()->Set(v8_str("q"), instance2);
1047  CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1048  CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1049  CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1050  CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1051}
1052
1053
1054static v8::Handle<Value> GetFlabby(const v8::Arguments& args) {
1055  ApiTestFuzzer::Fuzz();
1056  return v8_num(17.2);
1057}
1058
1059
1060static v8::Handle<Value> GetKnurd(Local<String> property, const AccessorInfo&) {
1061  ApiTestFuzzer::Fuzz();
1062  return v8_num(15.2);
1063}
1064
1065
1066THREADED_TEST(DescriptorInheritance) {
1067  v8::HandleScope scope;
1068  v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New();
1069  super->PrototypeTemplate()->Set("flabby",
1070                                  v8::FunctionTemplate::New(GetFlabby));
1071  super->PrototypeTemplate()->Set("PI", v8_num(3.14));
1072
1073  super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1074
1075  v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New();
1076  base1->Inherit(super);
1077  base1->PrototypeTemplate()->Set("v1", v8_num(20.1));
1078
1079  v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New();
1080  base2->Inherit(super);
1081  base2->PrototypeTemplate()->Set("v2", v8_num(10.1));
1082
1083  LocalContext env;
1084
1085  env->Global()->Set(v8_str("s"), super->GetFunction());
1086  env->Global()->Set(v8_str("base1"), base1->GetFunction());
1087  env->Global()->Set(v8_str("base2"), base2->GetFunction());
1088
1089  // Checks right __proto__ chain.
1090  CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1091  CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1092
1093  CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1094
1095  // Instance accessor should not be visible on function object or its prototype
1096  CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1097  CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1098  CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1099
1100  env->Global()->Set(v8_str("obj"),
1101                     base1->GetFunction()->NewInstance());
1102  CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1103  CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1104  CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1105  CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1106  CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1107
1108  env->Global()->Set(v8_str("obj2"),
1109                     base2->GetFunction()->NewInstance());
1110  CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1111  CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1112  CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1113  CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1114  CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1115
1116  // base1 and base2 cannot cross reference to each's prototype
1117  CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1118  CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1119}
1120
1121
1122int echo_named_call_count;
1123
1124
1125static v8::Handle<Value> EchoNamedProperty(Local<String> name,
1126                                           const AccessorInfo& info) {
1127  ApiTestFuzzer::Fuzz();
1128  CHECK_EQ(v8_str("data"), info.Data());
1129  echo_named_call_count++;
1130  return name;
1131}
1132
1133
1134THREADED_TEST(NamedPropertyHandlerGetter) {
1135  echo_named_call_count = 0;
1136  v8::HandleScope scope;
1137  v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1138  templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
1139                                                     0, 0, 0, 0,
1140                                                     v8_str("data"));
1141  LocalContext env;
1142  env->Global()->Set(v8_str("obj"),
1143                     templ->GetFunction()->NewInstance());
1144  CHECK_EQ(echo_named_call_count, 0);
1145  v8_compile("obj.x")->Run();
1146  CHECK_EQ(echo_named_call_count, 1);
1147  const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
1148  v8::Handle<Value> str = CompileRun(code);
1149  String::AsciiValue value(str);
1150  CHECK_EQ(*value, "oddlepoddle");
1151  // Check default behavior
1152  CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
1153  CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
1154  CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
1155}
1156
1157
1158int echo_indexed_call_count = 0;
1159
1160
1161static v8::Handle<Value> EchoIndexedProperty(uint32_t index,
1162                                             const AccessorInfo& info) {
1163  ApiTestFuzzer::Fuzz();
1164  CHECK_EQ(v8_num(637), info.Data());
1165  echo_indexed_call_count++;
1166  return v8_num(index);
1167}
1168
1169
1170THREADED_TEST(IndexedPropertyHandlerGetter) {
1171  v8::HandleScope scope;
1172  v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1173  templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
1174                                                       0, 0, 0, 0,
1175                                                       v8_num(637));
1176  LocalContext env;
1177  env->Global()->Set(v8_str("obj"),
1178                     templ->GetFunction()->NewInstance());
1179  Local<Script> script = v8_compile("obj[900]");
1180  CHECK_EQ(script->Run()->Int32Value(), 900);
1181}
1182
1183
1184v8::Handle<v8::Object> bottom;
1185
1186static v8::Handle<Value> CheckThisIndexedPropertyHandler(
1187    uint32_t index,
1188    const AccessorInfo& info) {
1189  ApiTestFuzzer::Fuzz();
1190  CHECK(info.This()->Equals(bottom));
1191  return v8::Handle<Value>();
1192}
1193
1194static v8::Handle<Value> CheckThisNamedPropertyHandler(
1195    Local<String> name,
1196    const AccessorInfo& info) {
1197  ApiTestFuzzer::Fuzz();
1198  CHECK(info.This()->Equals(bottom));
1199  return v8::Handle<Value>();
1200}
1201
1202
1203v8::Handle<Value> CheckThisIndexedPropertySetter(uint32_t index,
1204                                                 Local<Value> value,
1205                                                 const AccessorInfo& info) {
1206  ApiTestFuzzer::Fuzz();
1207  CHECK(info.This()->Equals(bottom));
1208  return v8::Handle<Value>();
1209}
1210
1211
1212v8::Handle<Value> CheckThisNamedPropertySetter(Local<String> property,
1213                                               Local<Value> value,
1214                                               const AccessorInfo& info) {
1215  ApiTestFuzzer::Fuzz();
1216  CHECK(info.This()->Equals(bottom));
1217  return v8::Handle<Value>();
1218}
1219
1220v8::Handle<v8::Integer> CheckThisIndexedPropertyQuery(
1221    uint32_t index,
1222    const AccessorInfo& info) {
1223  ApiTestFuzzer::Fuzz();
1224  CHECK(info.This()->Equals(bottom));
1225  return v8::Handle<v8::Integer>();
1226}
1227
1228
1229v8::Handle<v8::Integer> CheckThisNamedPropertyQuery(Local<String> property,
1230                                                    const AccessorInfo& info) {
1231  ApiTestFuzzer::Fuzz();
1232  CHECK(info.This()->Equals(bottom));
1233  return v8::Handle<v8::Integer>();
1234}
1235
1236
1237v8::Handle<v8::Boolean> CheckThisIndexedPropertyDeleter(
1238    uint32_t index,
1239    const AccessorInfo& info) {
1240  ApiTestFuzzer::Fuzz();
1241  CHECK(info.This()->Equals(bottom));
1242  return v8::Handle<v8::Boolean>();
1243}
1244
1245
1246v8::Handle<v8::Boolean> CheckThisNamedPropertyDeleter(
1247    Local<String> property,
1248    const AccessorInfo& info) {
1249  ApiTestFuzzer::Fuzz();
1250  CHECK(info.This()->Equals(bottom));
1251  return v8::Handle<v8::Boolean>();
1252}
1253
1254
1255v8::Handle<v8::Array> CheckThisIndexedPropertyEnumerator(
1256    const AccessorInfo& info) {
1257  ApiTestFuzzer::Fuzz();
1258  CHECK(info.This()->Equals(bottom));
1259  return v8::Handle<v8::Array>();
1260}
1261
1262
1263v8::Handle<v8::Array> CheckThisNamedPropertyEnumerator(
1264    const AccessorInfo& info) {
1265  ApiTestFuzzer::Fuzz();
1266  CHECK(info.This()->Equals(bottom));
1267  return v8::Handle<v8::Array>();
1268}
1269
1270
1271THREADED_TEST(PropertyHandlerInPrototype) {
1272  v8::HandleScope scope;
1273  LocalContext env;
1274
1275  // Set up a prototype chain with three interceptors.
1276  v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1277  templ->InstanceTemplate()->SetIndexedPropertyHandler(
1278      CheckThisIndexedPropertyHandler,
1279      CheckThisIndexedPropertySetter,
1280      CheckThisIndexedPropertyQuery,
1281      CheckThisIndexedPropertyDeleter,
1282      CheckThisIndexedPropertyEnumerator);
1283
1284  templ->InstanceTemplate()->SetNamedPropertyHandler(
1285      CheckThisNamedPropertyHandler,
1286      CheckThisNamedPropertySetter,
1287      CheckThisNamedPropertyQuery,
1288      CheckThisNamedPropertyDeleter,
1289      CheckThisNamedPropertyEnumerator);
1290
1291  bottom = templ->GetFunction()->NewInstance();
1292  Local<v8::Object> top = templ->GetFunction()->NewInstance();
1293  Local<v8::Object> middle = templ->GetFunction()->NewInstance();
1294
1295  bottom->Set(v8_str("__proto__"), middle);
1296  middle->Set(v8_str("__proto__"), top);
1297  env->Global()->Set(v8_str("obj"), bottom);
1298
1299  // Indexed and named get.
1300  Script::Compile(v8_str("obj[0]"))->Run();
1301  Script::Compile(v8_str("obj.x"))->Run();
1302
1303  // Indexed and named set.
1304  Script::Compile(v8_str("obj[1] = 42"))->Run();
1305  Script::Compile(v8_str("obj.y = 42"))->Run();
1306
1307  // Indexed and named query.
1308  Script::Compile(v8_str("0 in obj"))->Run();
1309  Script::Compile(v8_str("'x' in obj"))->Run();
1310
1311  // Indexed and named deleter.
1312  Script::Compile(v8_str("delete obj[0]"))->Run();
1313  Script::Compile(v8_str("delete obj.x"))->Run();
1314
1315  // Enumerators.
1316  Script::Compile(v8_str("for (var p in obj) ;"))->Run();
1317}
1318
1319
1320static v8::Handle<Value> PrePropertyHandlerGet(Local<String> key,
1321                                               const AccessorInfo& info) {
1322  ApiTestFuzzer::Fuzz();
1323  if (v8_str("pre")->Equals(key)) {
1324    return v8_str("PrePropertyHandler: pre");
1325  }
1326  return v8::Handle<String>();
1327}
1328
1329
1330static v8::Handle<v8::Integer> PrePropertyHandlerQuery(Local<String> key,
1331                                                       const AccessorInfo&) {
1332  if (v8_str("pre")->Equals(key)) {
1333    return v8::Integer::New(v8::None);
1334  }
1335
1336  return v8::Handle<v8::Integer>();  // do not intercept the call
1337}
1338
1339
1340THREADED_TEST(PrePropertyHandler) {
1341  v8::HandleScope scope;
1342  v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
1343  desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
1344                                                    0,
1345                                                    PrePropertyHandlerQuery);
1346  LocalContext env(NULL, desc->InstanceTemplate());
1347  Script::Compile(v8_str(
1348      "var pre = 'Object: pre'; var on = 'Object: on';"))->Run();
1349  v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run();
1350  CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
1351  v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run();
1352  CHECK_EQ(v8_str("Object: on"), result_on);
1353  v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run();
1354  CHECK(result_post.IsEmpty());
1355}
1356
1357
1358THREADED_TEST(UndefinedIsNotEnumerable) {
1359  v8::HandleScope scope;
1360  LocalContext env;
1361  v8::Handle<Value> result = Script::Compile(v8_str(
1362      "this.propertyIsEnumerable(undefined)"))->Run();
1363  CHECK(result->IsFalse());
1364}
1365
1366
1367v8::Handle<Script> call_recursively_script;
1368static const int kTargetRecursionDepth = 200;  // near maximum
1369
1370
1371static v8::Handle<Value> CallScriptRecursivelyCall(const v8::Arguments& args) {
1372  ApiTestFuzzer::Fuzz();
1373  int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1374  if (depth == kTargetRecursionDepth) return v8::Undefined();
1375  args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1376  return call_recursively_script->Run();
1377}
1378
1379
1380static v8::Handle<Value> CallFunctionRecursivelyCall(
1381    const v8::Arguments& args) {
1382  ApiTestFuzzer::Fuzz();
1383  int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1384  if (depth == kTargetRecursionDepth) {
1385    printf("[depth = %d]\n", depth);
1386    return v8::Undefined();
1387  }
1388  args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1389  v8::Handle<Value> function =
1390      args.This()->Get(v8_str("callFunctionRecursively"));
1391  return function.As<Function>()->Call(args.This(), 0, NULL);
1392}
1393
1394
1395THREADED_TEST(DeepCrossLanguageRecursion) {
1396  v8::HandleScope scope;
1397  v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
1398  global->Set(v8_str("callScriptRecursively"),
1399              v8::FunctionTemplate::New(CallScriptRecursivelyCall));
1400  global->Set(v8_str("callFunctionRecursively"),
1401              v8::FunctionTemplate::New(CallFunctionRecursivelyCall));
1402  LocalContext env(NULL, global);
1403
1404  env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1405  call_recursively_script = v8_compile("callScriptRecursively()");
1406  v8::Handle<Value> result = call_recursively_script->Run();
1407  call_recursively_script = v8::Handle<Script>();
1408
1409  env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1410  Script::Compile(v8_str("callFunctionRecursively()"))->Run();
1411}
1412
1413
1414static v8::Handle<Value>
1415    ThrowingPropertyHandlerGet(Local<String> key, const AccessorInfo&) {
1416  ApiTestFuzzer::Fuzz();
1417  return v8::ThrowException(key);
1418}
1419
1420
1421static v8::Handle<Value> ThrowingPropertyHandlerSet(Local<String> key,
1422                                                    Local<Value>,
1423                                                    const AccessorInfo&) {
1424  v8::ThrowException(key);
1425  return v8::Undefined();  // not the same as v8::Handle<v8::Value>()
1426}
1427
1428
1429THREADED_TEST(CallbackExceptionRegression) {
1430  v8::HandleScope scope;
1431  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
1432  obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
1433                               ThrowingPropertyHandlerSet);
1434  LocalContext env;
1435  env->Global()->Set(v8_str("obj"), obj->NewInstance());
1436  v8::Handle<Value> otto = Script::Compile(v8_str(
1437      "try { with (obj) { otto; } } catch (e) { e; }"))->Run();
1438  CHECK_EQ(v8_str("otto"), otto);
1439  v8::Handle<Value> netto = Script::Compile(v8_str(
1440      "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run();
1441  CHECK_EQ(v8_str("netto"), netto);
1442}
1443
1444
1445THREADED_TEST(FunctionPrototype) {
1446  v8::HandleScope scope;
1447  Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New();
1448  Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
1449  LocalContext env;
1450  env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
1451  Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak"));
1452  CHECK_EQ(script->Run()->Int32Value(), 321);
1453}
1454
1455
1456THREADED_TEST(InternalFields) {
1457  v8::HandleScope scope;
1458  LocalContext env;
1459
1460  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1461  Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1462  instance_templ->SetInternalFieldCount(1);
1463  Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1464  CHECK_EQ(1, obj->InternalFieldCount());
1465  CHECK(obj->GetInternalField(0)->IsUndefined());
1466  obj->SetInternalField(0, v8_num(17));
1467  CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
1468}
1469
1470
1471THREADED_TEST(GlobalObjectInternalFields) {
1472  v8::HandleScope scope;
1473  Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
1474  global_template->SetInternalFieldCount(1);
1475  LocalContext env(NULL, global_template);
1476  v8::Handle<v8::Object> global_proxy = env->Global();
1477  v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
1478  CHECK_EQ(1, global->InternalFieldCount());
1479  CHECK(global->GetInternalField(0)->IsUndefined());
1480  global->SetInternalField(0, v8_num(17));
1481  CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
1482}
1483
1484
1485THREADED_TEST(InternalFieldsNativePointers) {
1486  v8::HandleScope scope;
1487  LocalContext env;
1488
1489  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1490  Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1491  instance_templ->SetInternalFieldCount(1);
1492  Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1493  CHECK_EQ(1, obj->InternalFieldCount());
1494  CHECK(obj->GetPointerFromInternalField(0) == NULL);
1495
1496  char* data = new char[100];
1497
1498  void* aligned = data;
1499  CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
1500  void* unaligned = data + 1;
1501  CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
1502
1503  // Check reading and writing aligned pointers.
1504  obj->SetPointerInInternalField(0, aligned);
1505  i::Heap::CollectAllGarbage(false);
1506  CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1507
1508  // Check reading and writing unaligned pointers.
1509  obj->SetPointerInInternalField(0, unaligned);
1510  i::Heap::CollectAllGarbage(false);
1511  CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1512
1513  delete[] data;
1514}
1515
1516
1517THREADED_TEST(InternalFieldsNativePointersAndExternal) {
1518  v8::HandleScope scope;
1519  LocalContext env;
1520
1521  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1522  Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1523  instance_templ->SetInternalFieldCount(1);
1524  Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1525  CHECK_EQ(1, obj->InternalFieldCount());
1526  CHECK(obj->GetPointerFromInternalField(0) == NULL);
1527
1528  char* data = new char[100];
1529
1530  void* aligned = data;
1531  CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
1532  void* unaligned = data + 1;
1533  CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
1534
1535  obj->SetPointerInInternalField(0, aligned);
1536  i::Heap::CollectAllGarbage(false);
1537  CHECK_EQ(aligned, v8::External::Unwrap(obj->GetInternalField(0)));
1538
1539  obj->SetPointerInInternalField(0, unaligned);
1540  i::Heap::CollectAllGarbage(false);
1541  CHECK_EQ(unaligned, v8::External::Unwrap(obj->GetInternalField(0)));
1542
1543  obj->SetInternalField(0, v8::External::Wrap(aligned));
1544  i::Heap::CollectAllGarbage(false);
1545  CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1546
1547  obj->SetInternalField(0, v8::External::Wrap(unaligned));
1548  i::Heap::CollectAllGarbage(false);
1549  CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1550
1551  delete[] data;
1552}
1553
1554
1555THREADED_TEST(IdentityHash) {
1556  v8::HandleScope scope;
1557  LocalContext env;
1558
1559  // Ensure that the test starts with an fresh heap to test whether the hash
1560  // code is based on the address.
1561  i::Heap::CollectAllGarbage(false);
1562  Local<v8::Object> obj = v8::Object::New();
1563  int hash = obj->GetIdentityHash();
1564  int hash1 = obj->GetIdentityHash();
1565  CHECK_EQ(hash, hash1);
1566  int hash2 = v8::Object::New()->GetIdentityHash();
1567  // Since the identity hash is essentially a random number two consecutive
1568  // objects should not be assigned the same hash code. If the test below fails
1569  // the random number generator should be evaluated.
1570  CHECK_NE(hash, hash2);
1571  i::Heap::CollectAllGarbage(false);
1572  int hash3 = v8::Object::New()->GetIdentityHash();
1573  // Make sure that the identity hash is not based on the initial address of
1574  // the object alone. If the test below fails the random number generator
1575  // should be evaluated.
1576  CHECK_NE(hash, hash3);
1577  int hash4 = obj->GetIdentityHash();
1578  CHECK_EQ(hash, hash4);
1579}
1580
1581
1582THREADED_TEST(HiddenProperties) {
1583  v8::HandleScope scope;
1584  LocalContext env;
1585
1586  v8::Local<v8::Object> obj = v8::Object::New();
1587  v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1588  v8::Local<v8::String> empty = v8_str("");
1589  v8::Local<v8::String> prop_name = v8_str("prop_name");
1590
1591  i::Heap::CollectAllGarbage(false);
1592
1593  // Make sure delete of a non-existent hidden value works
1594  CHECK(obj->DeleteHiddenValue(key));
1595
1596  CHECK(obj->SetHiddenValue(key, v8::Integer::New(1503)));
1597  CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
1598  CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
1599  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1600
1601  i::Heap::CollectAllGarbage(false);
1602
1603  // Make sure we do not find the hidden property.
1604  CHECK(!obj->Has(empty));
1605  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1606  CHECK(obj->Get(empty)->IsUndefined());
1607  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1608  CHECK(obj->Set(empty, v8::Integer::New(2003)));
1609  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1610  CHECK_EQ(2003, obj->Get(empty)->Int32Value());
1611
1612  i::Heap::CollectAllGarbage(false);
1613
1614  // Add another property and delete it afterwards to force the object in
1615  // slow case.
1616  CHECK(obj->Set(prop_name, v8::Integer::New(2008)));
1617  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1618  CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
1619  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1620  CHECK(obj->Delete(prop_name));
1621  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1622
1623  i::Heap::CollectAllGarbage(false);
1624
1625  CHECK(obj->DeleteHiddenValue(key));
1626  CHECK(obj->GetHiddenValue(key).IsEmpty());
1627}
1628
1629
1630static bool interceptor_for_hidden_properties_called;
1631static v8::Handle<Value> InterceptorForHiddenProperties(
1632    Local<String> name, const AccessorInfo& info) {
1633  interceptor_for_hidden_properties_called = true;
1634  return v8::Handle<Value>();
1635}
1636
1637
1638THREADED_TEST(HiddenPropertiesWithInterceptors) {
1639  v8::HandleScope scope;
1640  LocalContext context;
1641
1642  interceptor_for_hidden_properties_called = false;
1643
1644  v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1645
1646  // Associate an interceptor with an object and start setting hidden values.
1647  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
1648  Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
1649  instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
1650  Local<v8::Function> function = fun_templ->GetFunction();
1651  Local<v8::Object> obj = function->NewInstance();
1652  CHECK(obj->SetHiddenValue(key, v8::Integer::New(2302)));
1653  CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
1654  CHECK(!interceptor_for_hidden_properties_called);
1655}
1656
1657
1658THREADED_TEST(External) {
1659  v8::HandleScope scope;
1660  int x = 3;
1661  Local<v8::External> ext = v8::External::New(&x);
1662  LocalContext env;
1663  env->Global()->Set(v8_str("ext"), ext);
1664  Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
1665  v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
1666  int* ptr = static_cast<int*>(reext->Value());
1667  CHECK_EQ(x, 3);
1668  *ptr = 10;
1669  CHECK_EQ(x, 10);
1670
1671  // Make sure unaligned pointers are wrapped properly.
1672  char* data = i::StrDup("0123456789");
1673  Local<v8::Value> zero = v8::External::Wrap(&data[0]);
1674  Local<v8::Value> one = v8::External::Wrap(&data[1]);
1675  Local<v8::Value> two = v8::External::Wrap(&data[2]);
1676  Local<v8::Value> three = v8::External::Wrap(&data[3]);
1677
1678  char* char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(zero));
1679  CHECK_EQ('0', *char_ptr);
1680  char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(one));
1681  CHECK_EQ('1', *char_ptr);
1682  char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(two));
1683  CHECK_EQ('2', *char_ptr);
1684  char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(three));
1685  CHECK_EQ('3', *char_ptr);
1686  i::DeleteArray(data);
1687}
1688
1689
1690THREADED_TEST(GlobalHandle) {
1691  v8::Persistent<String> global;
1692  {
1693    v8::HandleScope scope;
1694    Local<String> str = v8_str("str");
1695    global = v8::Persistent<String>::New(str);
1696  }
1697  CHECK_EQ(global->Length(), 3);
1698  global.Dispose();
1699}
1700
1701
1702THREADED_TEST(ScriptException) {
1703  v8::HandleScope scope;
1704  LocalContext env;
1705  Local<Script> script = Script::Compile(v8_str("throw 'panama!';"));
1706  v8::TryCatch try_catch;
1707  Local<Value> result = script->Run();
1708  CHECK(result.IsEmpty());
1709  CHECK(try_catch.HasCaught());
1710  String::AsciiValue exception_value(try_catch.Exception());
1711  CHECK_EQ(*exception_value, "panama!");
1712}
1713
1714
1715bool message_received;
1716
1717
1718static void check_message(v8::Handle<v8::Message> message,
1719                          v8::Handle<Value> data) {
1720  CHECK_EQ(5.76, data->NumberValue());
1721  CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
1722  CHECK_EQ(7.56, message->GetScriptData()->NumberValue());
1723  message_received = true;
1724}
1725
1726
1727THREADED_TEST(MessageHandlerData) {
1728  message_received = false;
1729  v8::HandleScope scope;
1730  CHECK(!message_received);
1731  v8::V8::AddMessageListener(check_message, v8_num(5.76));
1732  LocalContext context;
1733  v8::ScriptOrigin origin =
1734      v8::ScriptOrigin(v8_str("6.75"));
1735  v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
1736                                                  &origin);
1737  script->SetData(v8_str("7.56"));
1738  script->Run();
1739  CHECK(message_received);
1740  // clear out the message listener
1741  v8::V8::RemoveMessageListeners(check_message);
1742}
1743
1744
1745THREADED_TEST(GetSetProperty) {
1746  v8::HandleScope scope;
1747  LocalContext context;
1748  context->Global()->Set(v8_str("foo"), v8_num(14));
1749  context->Global()->Set(v8_str("12"), v8_num(92));
1750  context->Global()->Set(v8::Integer::New(16), v8_num(32));
1751  context->Global()->Set(v8_num(13), v8_num(56));
1752  Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run();
1753  CHECK_EQ(14, foo->Int32Value());
1754  Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run();
1755  CHECK_EQ(92, twelve->Int32Value());
1756  Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run();
1757  CHECK_EQ(32, sixteen->Int32Value());
1758  Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run();
1759  CHECK_EQ(56, thirteen->Int32Value());
1760  CHECK_EQ(92, context->Global()->Get(v8::Integer::New(12))->Int32Value());
1761  CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
1762  CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
1763  CHECK_EQ(32, context->Global()->Get(v8::Integer::New(16))->Int32Value());
1764  CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
1765  CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
1766  CHECK_EQ(56, context->Global()->Get(v8::Integer::New(13))->Int32Value());
1767  CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
1768  CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
1769}
1770
1771
1772THREADED_TEST(PropertyAttributes) {
1773  v8::HandleScope scope;
1774  LocalContext context;
1775  // read-only
1776  Local<String> prop = v8_str("read_only");
1777  context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
1778  CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
1779  Script::Compile(v8_str("read_only = 9"))->Run();
1780  CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
1781  context->Global()->Set(prop, v8_num(10));
1782  CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
1783  // dont-delete
1784  prop = v8_str("dont_delete");
1785  context->Global()->Set(prop, v8_num(13), v8::DontDelete);
1786  CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
1787  Script::Compile(v8_str("delete dont_delete"))->Run();
1788  CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
1789}
1790
1791
1792THREADED_TEST(Array) {
1793  v8::HandleScope scope;
1794  LocalContext context;
1795  Local<v8::Array> array = v8::Array::New();
1796  CHECK_EQ(0, array->Length());
1797  CHECK(array->Get(0)->IsUndefined());
1798  CHECK(!array->Has(0));
1799  CHECK(array->Get(100)->IsUndefined());
1800  CHECK(!array->Has(100));
1801  array->Set(2, v8_num(7));
1802  CHECK_EQ(3, array->Length());
1803  CHECK(!array->Has(0));
1804  CHECK(!array->Has(1));
1805  CHECK(array->Has(2));
1806  CHECK_EQ(7, array->Get(2)->Int32Value());
1807  Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
1808  Local<v8::Array> arr = obj.As<v8::Array>();
1809  CHECK_EQ(3, arr->Length());
1810  CHECK_EQ(1, arr->Get(0)->Int32Value());
1811  CHECK_EQ(2, arr->Get(1)->Int32Value());
1812  CHECK_EQ(3, arr->Get(2)->Int32Value());
1813}
1814
1815
1816v8::Handle<Value> HandleF(const v8::Arguments& args) {
1817  v8::HandleScope scope;
1818  ApiTestFuzzer::Fuzz();
1819  Local<v8::Array> result = v8::Array::New(args.Length());
1820  for (int i = 0; i < args.Length(); i++)
1821    result->Set(i, args[i]);
1822  return scope.Close(result);
1823}
1824
1825
1826THREADED_TEST(Vector) {
1827  v8::HandleScope scope;
1828  Local<ObjectTemplate> global = ObjectTemplate::New();
1829  global->Set(v8_str("f"), v8::FunctionTemplate::New(HandleF));
1830  LocalContext context(0, global);
1831
1832  const char* fun = "f()";
1833  Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
1834  CHECK_EQ(0, a0->Length());
1835
1836  const char* fun2 = "f(11)";
1837  Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
1838  CHECK_EQ(1, a1->Length());
1839  CHECK_EQ(11, a1->Get(0)->Int32Value());
1840
1841  const char* fun3 = "f(12, 13)";
1842  Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
1843  CHECK_EQ(2, a2->Length());
1844  CHECK_EQ(12, a2->Get(0)->Int32Value());
1845  CHECK_EQ(13, a2->Get(1)->Int32Value());
1846
1847  const char* fun4 = "f(14, 15, 16)";
1848  Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
1849  CHECK_EQ(3, a3->Length());
1850  CHECK_EQ(14, a3->Get(0)->Int32Value());
1851  CHECK_EQ(15, a3->Get(1)->Int32Value());
1852  CHECK_EQ(16, a3->Get(2)->Int32Value());
1853
1854  const char* fun5 = "f(17, 18, 19, 20)";
1855  Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
1856  CHECK_EQ(4, a4->Length());
1857  CHECK_EQ(17, a4->Get(0)->Int32Value());
1858  CHECK_EQ(18, a4->Get(1)->Int32Value());
1859  CHECK_EQ(19, a4->Get(2)->Int32Value());
1860  CHECK_EQ(20, a4->Get(3)->Int32Value());
1861}
1862
1863
1864THREADED_TEST(FunctionCall) {
1865  v8::HandleScope scope;
1866  LocalContext context;
1867  CompileRun(
1868    "function Foo() {"
1869    "  var result = [];"
1870    "  for (var i = 0; i < arguments.length; i++) {"
1871    "    result.push(arguments[i]);"
1872    "  }"
1873    "  return result;"
1874    "}");
1875  Local<Function> Foo =
1876      Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
1877
1878  v8::Handle<Value>* args0 = NULL;
1879  Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
1880  CHECK_EQ(0, a0->Length());
1881
1882  v8::Handle<Value> args1[] = { v8_num(1.1) };
1883  Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
1884  CHECK_EQ(1, a1->Length());
1885  CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
1886
1887  v8::Handle<Value> args2[] = { v8_num(2.2),
1888                                v8_num(3.3) };
1889  Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
1890  CHECK_EQ(2, a2->Length());
1891  CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
1892  CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
1893
1894  v8::Handle<Value> args3[] = { v8_num(4.4),
1895                                v8_num(5.5),
1896                                v8_num(6.6) };
1897  Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
1898  CHECK_EQ(3, a3->Length());
1899  CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
1900  CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
1901  CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
1902
1903  v8::Handle<Value> args4[] = { v8_num(7.7),
1904                                v8_num(8.8),
1905                                v8_num(9.9),
1906                                v8_num(10.11) };
1907  Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
1908  CHECK_EQ(4, a4->Length());
1909  CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
1910  CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
1911  CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
1912  CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
1913}
1914
1915
1916static const char* js_code_causing_out_of_memory =
1917    "var a = new Array(); while(true) a.push(a);";
1918
1919
1920// These tests run for a long time and prevent us from running tests
1921// that come after them so they cannot run in parallel.
1922TEST(OutOfMemory) {
1923  // It's not possible to read a snapshot into a heap with different dimensions.
1924  if (i::Snapshot::IsEnabled()) return;
1925  // Set heap limits.
1926  static const int K = 1024;
1927  v8::ResourceConstraints constraints;
1928  constraints.set_max_young_space_size(256 * K);
1929  constraints.set_max_old_space_size(4 * K * K);
1930  v8::SetResourceConstraints(&constraints);
1931
1932  // Execute a script that causes out of memory.
1933  v8::HandleScope scope;
1934  LocalContext context;
1935  v8::V8::IgnoreOutOfMemoryException();
1936  Local<Script> script =
1937      Script::Compile(String::New(js_code_causing_out_of_memory));
1938  Local<Value> result = script->Run();
1939
1940  // Check for out of memory state.
1941  CHECK(result.IsEmpty());
1942  CHECK(context->HasOutOfMemoryException());
1943}
1944
1945
1946v8::Handle<Value> ProvokeOutOfMemory(const v8::Arguments& args) {
1947  ApiTestFuzzer::Fuzz();
1948
1949  v8::HandleScope scope;
1950  LocalContext context;
1951  Local<Script> script =
1952      Script::Compile(String::New(js_code_causing_out_of_memory));
1953  Local<Value> result = script->Run();
1954
1955  // Check for out of memory state.
1956  CHECK(result.IsEmpty());
1957  CHECK(context->HasOutOfMemoryException());
1958
1959  return result;
1960}
1961
1962
1963TEST(OutOfMemoryNested) {
1964  // It's not possible to read a snapshot into a heap with different dimensions.
1965  if (i::Snapshot::IsEnabled()) return;
1966  // Set heap limits.
1967  static const int K = 1024;
1968  v8::ResourceConstraints constraints;
1969  constraints.set_max_young_space_size(256 * K);
1970  constraints.set_max_old_space_size(4 * K * K);
1971  v8::SetResourceConstraints(&constraints);
1972
1973  v8::HandleScope scope;
1974  Local<ObjectTemplate> templ = ObjectTemplate::New();
1975  templ->Set(v8_str("ProvokeOutOfMemory"),
1976             v8::FunctionTemplate::New(ProvokeOutOfMemory));
1977  LocalContext context(0, templ);
1978  v8::V8::IgnoreOutOfMemoryException();
1979  Local<Value> result = CompileRun(
1980    "var thrown = false;"
1981    "try {"
1982    "  ProvokeOutOfMemory();"
1983    "} catch (e) {"
1984    "  thrown = true;"
1985    "}");
1986  // Check for out of memory state.
1987  CHECK(result.IsEmpty());
1988  CHECK(context->HasOutOfMemoryException());
1989}
1990
1991
1992TEST(HugeConsStringOutOfMemory) {
1993  // It's not possible to read a snapshot into a heap with different dimensions.
1994  if (i::Snapshot::IsEnabled()) return;
1995  v8::HandleScope scope;
1996  LocalContext context;
1997  // Set heap limits.
1998  static const int K = 1024;
1999  v8::ResourceConstraints constraints;
2000  constraints.set_max_young_space_size(256 * K);
2001  constraints.set_max_old_space_size(2 * K * K);
2002  v8::SetResourceConstraints(&constraints);
2003
2004  // Execute a script that causes out of memory.
2005  v8::V8::IgnoreOutOfMemoryException();
2006
2007  // Build huge string. This should fail with out of memory exception.
2008  Local<Value> result = CompileRun(
2009    "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();"
2010    "for (var i = 0; i < 22; i++) { str = str + str; }");
2011
2012  // Check for out of memory state.
2013  CHECK(result.IsEmpty());
2014  CHECK(context->HasOutOfMemoryException());
2015}
2016
2017
2018THREADED_TEST(ConstructCall) {
2019  v8::HandleScope scope;
2020  LocalContext context;
2021  CompileRun(
2022    "function Foo() {"
2023    "  var result = [];"
2024    "  for (var i = 0; i < arguments.length; i++) {"
2025    "    result.push(arguments[i]);"
2026    "  }"
2027    "  return result;"
2028    "}");
2029  Local<Function> Foo =
2030      Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
2031
2032  v8::Handle<Value>* args0 = NULL;
2033  Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
2034  CHECK_EQ(0, a0->Length());
2035
2036  v8::Handle<Value> args1[] = { v8_num(1.1) };
2037  Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
2038  CHECK_EQ(1, a1->Length());
2039  CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
2040
2041  v8::Handle<Value> args2[] = { v8_num(2.2),
2042                                v8_num(3.3) };
2043  Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
2044  CHECK_EQ(2, a2->Length());
2045  CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
2046  CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
2047
2048  v8::Handle<Value> args3[] = { v8_num(4.4),
2049                                v8_num(5.5),
2050                                v8_num(6.6) };
2051  Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
2052  CHECK_EQ(3, a3->Length());
2053  CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
2054  CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
2055  CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
2056
2057  v8::Handle<Value> args4[] = { v8_num(7.7),
2058                                v8_num(8.8),
2059                                v8_num(9.9),
2060                                v8_num(10.11) };
2061  Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
2062  CHECK_EQ(4, a4->Length());
2063  CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
2064  CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
2065  CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
2066  CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
2067}
2068
2069
2070static void CheckUncle(v8::TryCatch* try_catch) {
2071  CHECK(try_catch->HasCaught());
2072  String::AsciiValue str_value(try_catch->Exception());
2073  CHECK_EQ(*str_value, "uncle?");
2074  try_catch->Reset();
2075}
2076
2077
2078THREADED_TEST(ConversionNumber) {
2079  v8::HandleScope scope;
2080  LocalContext env;
2081  // Very large number.
2082  CompileRun("var obj = Math.pow(2,32) * 1237;");
2083  Local<Value> obj = env->Global()->Get(v8_str("obj"));
2084  CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
2085  CHECK_EQ(0, obj->ToInt32()->Value());
2086  CHECK(0u == obj->ToUint32()->Value());  // NOLINT - no CHECK_EQ for unsigned.
2087  // Large number.
2088  CompileRun("var obj = -1234567890123;");
2089  obj = env->Global()->Get(v8_str("obj"));
2090  CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
2091  CHECK_EQ(-1912276171, obj->ToInt32()->Value());
2092  CHECK(2382691125u == obj->ToUint32()->Value());  // NOLINT
2093  // Small positive integer.
2094  CompileRun("var obj = 42;");
2095  obj = env->Global()->Get(v8_str("obj"));
2096  CHECK_EQ(42.0, obj->ToNumber()->Value());
2097  CHECK_EQ(42, obj->ToInt32()->Value());
2098  CHECK(42u == obj->ToUint32()->Value());  // NOLINT
2099  // Negative integer.
2100  CompileRun("var obj = -37;");
2101  obj = env->Global()->Get(v8_str("obj"));
2102  CHECK_EQ(-37.0, obj->ToNumber()->Value());
2103  CHECK_EQ(-37, obj->ToInt32()->Value());
2104  CHECK(4294967259u == obj->ToUint32()->Value());  // NOLINT
2105  // Positive non-int32 integer.
2106  CompileRun("var obj = 0x81234567;");
2107  obj = env->Global()->Get(v8_str("obj"));
2108  CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
2109  CHECK_EQ(-2128394905, obj->ToInt32()->Value());
2110  CHECK(2166572391u == obj->ToUint32()->Value());  // NOLINT
2111  // Fraction.
2112  CompileRun("var obj = 42.3;");
2113  obj = env->Global()->Get(v8_str("obj"));
2114  CHECK_EQ(42.3, obj->ToNumber()->Value());
2115  CHECK_EQ(42, obj->ToInt32()->Value());
2116  CHECK(42u == obj->ToUint32()->Value());  // NOLINT
2117  // Large negative fraction.
2118  CompileRun("var obj = -5726623061.75;");
2119  obj = env->Global()->Get(v8_str("obj"));
2120  CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
2121  CHECK_EQ(-1431655765, obj->ToInt32()->Value());
2122  CHECK(2863311531u == obj->ToUint32()->Value());  // NOLINT
2123}
2124
2125
2126THREADED_TEST(isNumberType) {
2127  v8::HandleScope scope;
2128  LocalContext env;
2129  // Very large number.
2130  CompileRun("var obj = Math.pow(2,32) * 1237;");
2131  Local<Value> obj = env->Global()->Get(v8_str("obj"));
2132  CHECK(!obj->IsInt32());
2133  CHECK(!obj->IsUint32());
2134  // Large negative number.
2135  CompileRun("var obj = -1234567890123;");
2136  obj = env->Global()->Get(v8_str("obj"));
2137  CHECK(!obj->IsInt32());
2138  CHECK(!obj->IsUint32());
2139  // Small positive integer.
2140  CompileRun("var obj = 42;");
2141  obj = env->Global()->Get(v8_str("obj"));
2142  CHECK(obj->IsInt32());
2143  CHECK(obj->IsUint32());
2144  // Negative integer.
2145  CompileRun("var obj = -37;");
2146  obj = env->Global()->Get(v8_str("obj"));
2147  CHECK(obj->IsInt32());
2148  CHECK(!obj->IsUint32());
2149  // Positive non-int32 integer.
2150  CompileRun("var obj = 0x81234567;");
2151  obj = env->Global()->Get(v8_str("obj"));
2152  CHECK(!obj->IsInt32());
2153  CHECK(obj->IsUint32());
2154  // Fraction.
2155  CompileRun("var obj = 42.3;");
2156  obj = env->Global()->Get(v8_str("obj"));
2157  CHECK(!obj->IsInt32());
2158  CHECK(!obj->IsUint32());
2159  // Large negative fraction.
2160  CompileRun("var obj = -5726623061.75;");
2161  obj = env->Global()->Get(v8_str("obj"));
2162  CHECK(!obj->IsInt32());
2163  CHECK(!obj->IsUint32());
2164}
2165
2166
2167THREADED_TEST(ConversionException) {
2168  v8::HandleScope scope;
2169  LocalContext env;
2170  CompileRun(
2171    "function TestClass() { };"
2172    "TestClass.prototype.toString = function () { throw 'uncle?'; };"
2173    "var obj = new TestClass();");
2174  Local<Value> obj = env->Global()->Get(v8_str("obj"));
2175
2176  v8::TryCatch try_catch;
2177
2178  Local<Value> to_string_result = obj->ToString();
2179  CHECK(to_string_result.IsEmpty());
2180  CheckUncle(&try_catch);
2181
2182  Local<Value> to_number_result = obj->ToNumber();
2183  CHECK(to_number_result.IsEmpty());
2184  CheckUncle(&try_catch);
2185
2186  Local<Value> to_integer_result = obj->ToInteger();
2187  CHECK(to_integer_result.IsEmpty());
2188  CheckUncle(&try_catch);
2189
2190  Local<Value> to_uint32_result = obj->ToUint32();
2191  CHECK(to_uint32_result.IsEmpty());
2192  CheckUncle(&try_catch);
2193
2194  Local<Value> to_int32_result = obj->ToInt32();
2195  CHECK(to_int32_result.IsEmpty());
2196  CheckUncle(&try_catch);
2197
2198  Local<Value> to_object_result = v8::Undefined()->ToObject();
2199  CHECK(to_object_result.IsEmpty());
2200  CHECK(try_catch.HasCaught());
2201  try_catch.Reset();
2202
2203  int32_t int32_value = obj->Int32Value();
2204  CHECK_EQ(0, int32_value);
2205  CheckUncle(&try_catch);
2206
2207  uint32_t uint32_value = obj->Uint32Value();
2208  CHECK_EQ(0, uint32_value);
2209  CheckUncle(&try_catch);
2210
2211  double number_value = obj->NumberValue();
2212  CHECK_NE(0, IsNaN(number_value));
2213  CheckUncle(&try_catch);
2214
2215  int64_t integer_value = obj->IntegerValue();
2216  CHECK_EQ(0.0, static_cast<double>(integer_value));
2217  CheckUncle(&try_catch);
2218}
2219
2220
2221v8::Handle<Value> ThrowFromC(const v8::Arguments& args) {
2222  ApiTestFuzzer::Fuzz();
2223  return v8::ThrowException(v8_str("konto"));
2224}
2225
2226
2227v8::Handle<Value> CCatcher(const v8::Arguments& args) {
2228  if (args.Length() < 1) return v8::Boolean::New(false);
2229  v8::HandleScope scope;
2230  v8::TryCatch try_catch;
2231  Local<Value> result = v8::Script::Compile(args[0]->ToString())->Run();
2232  CHECK(!try_catch.HasCaught() || result.IsEmpty());
2233  return v8::Boolean::New(try_catch.HasCaught());
2234}
2235
2236
2237THREADED_TEST(APICatch) {
2238  v8::HandleScope scope;
2239  Local<ObjectTemplate> templ = ObjectTemplate::New();
2240  templ->Set(v8_str("ThrowFromC"),
2241             v8::FunctionTemplate::New(ThrowFromC));
2242  LocalContext context(0, templ);
2243  CompileRun(
2244    "var thrown = false;"
2245    "try {"
2246    "  ThrowFromC();"
2247    "} catch (e) {"
2248    "  thrown = true;"
2249    "}");
2250  Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
2251  CHECK(thrown->BooleanValue());
2252}
2253
2254
2255THREADED_TEST(APIThrowTryCatch) {
2256  v8::HandleScope scope;
2257  Local<ObjectTemplate> templ = ObjectTemplate::New();
2258  templ->Set(v8_str("ThrowFromC"),
2259             v8::FunctionTemplate::New(ThrowFromC));
2260  LocalContext context(0, templ);
2261  v8::TryCatch try_catch;
2262  CompileRun("ThrowFromC();");
2263  CHECK(try_catch.HasCaught());
2264}
2265
2266
2267// Test that a try-finally block doesn't shadow a try-catch block
2268// when setting up an external handler.
2269//
2270// BUG(271): Some of the exception propagation does not work on the
2271// ARM simulator because the simulator separates the C++ stack and the
2272// JS stack.  This test therefore fails on the simulator.  The test is
2273// not threaded to allow the threading tests to run on the simulator.
2274TEST(TryCatchInTryFinally) {
2275  v8::HandleScope scope;
2276  Local<ObjectTemplate> templ = ObjectTemplate::New();
2277  templ->Set(v8_str("CCatcher"),
2278             v8::FunctionTemplate::New(CCatcher));
2279  LocalContext context(0, templ);
2280  Local<Value> result = CompileRun("try {"
2281                                   "  try {"
2282                                   "    CCatcher('throw 7;');"
2283                                   "  } finally {"
2284                                   "  }"
2285                                   "} catch (e) {"
2286                                   "}");
2287  CHECK(result->IsTrue());
2288}
2289
2290
2291static void receive_message(v8::Handle<v8::Message> message,
2292                            v8::Handle<v8::Value> data) {
2293  message->Get();
2294  message_received = true;
2295}
2296
2297
2298TEST(APIThrowMessage) {
2299  message_received = false;
2300  v8::HandleScope scope;
2301  v8::V8::AddMessageListener(receive_message);
2302  Local<ObjectTemplate> templ = ObjectTemplate::New();
2303  templ->Set(v8_str("ThrowFromC"),
2304             v8::FunctionTemplate::New(ThrowFromC));
2305  LocalContext context(0, templ);
2306  CompileRun("ThrowFromC();");
2307  CHECK(message_received);
2308  v8::V8::RemoveMessageListeners(check_message);
2309}
2310
2311
2312TEST(APIThrowMessageAndVerboseTryCatch) {
2313  message_received = false;
2314  v8::HandleScope scope;
2315  v8::V8::AddMessageListener(receive_message);
2316  Local<ObjectTemplate> templ = ObjectTemplate::New();
2317  templ->Set(v8_str("ThrowFromC"),
2318             v8::FunctionTemplate::New(ThrowFromC));
2319  LocalContext context(0, templ);
2320  v8::TryCatch try_catch;
2321  try_catch.SetVerbose(true);
2322  Local<Value> result = CompileRun("ThrowFromC();");
2323  CHECK(try_catch.HasCaught());
2324  CHECK(result.IsEmpty());
2325  CHECK(message_received);
2326  v8::V8::RemoveMessageListeners(check_message);
2327}
2328
2329
2330THREADED_TEST(ExternalScriptException) {
2331  v8::HandleScope scope;
2332  Local<ObjectTemplate> templ = ObjectTemplate::New();
2333  templ->Set(v8_str("ThrowFromC"),
2334             v8::FunctionTemplate::New(ThrowFromC));
2335  LocalContext context(0, templ);
2336
2337  v8::TryCatch try_catch;
2338  Local<Script> script
2339      = Script::Compile(v8_str("ThrowFromC(); throw 'panama';"));
2340  Local<Value> result = script->Run();
2341  CHECK(result.IsEmpty());
2342  CHECK(try_catch.HasCaught());
2343  String::AsciiValue exception_value(try_catch.Exception());
2344  CHECK_EQ("konto", *exception_value);
2345}
2346
2347
2348
2349v8::Handle<Value> CThrowCountDown(const v8::Arguments& args) {
2350  ApiTestFuzzer::Fuzz();
2351  CHECK_EQ(4, args.Length());
2352  int count = args[0]->Int32Value();
2353  int cInterval = args[2]->Int32Value();
2354  if (count == 0) {
2355    return v8::ThrowException(v8_str("FromC"));
2356  } else {
2357    Local<v8::Object> global = Context::GetCurrent()->Global();
2358    Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
2359    v8::Handle<Value> argv[] = { v8_num(count - 1),
2360                                 args[1],
2361                                 args[2],
2362                                 args[3] };
2363    if (count % cInterval == 0) {
2364      v8::TryCatch try_catch;
2365      Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
2366      int expected = args[3]->Int32Value();
2367      if (try_catch.HasCaught()) {
2368        CHECK_EQ(expected, count);
2369        CHECK(result.IsEmpty());
2370        CHECK(!i::Top::has_scheduled_exception());
2371      } else {
2372        CHECK_NE(expected, count);
2373      }
2374      return result;
2375    } else {
2376      return fun.As<Function>()->Call(global, 4, argv);
2377    }
2378  }
2379}
2380
2381
2382v8::Handle<Value> JSCheck(const v8::Arguments& args) {
2383  ApiTestFuzzer::Fuzz();
2384  CHECK_EQ(3, args.Length());
2385  bool equality = args[0]->BooleanValue();
2386  int count = args[1]->Int32Value();
2387  int expected = args[2]->Int32Value();
2388  if (equality) {
2389    CHECK_EQ(count, expected);
2390  } else {
2391    CHECK_NE(count, expected);
2392  }
2393  return v8::Undefined();
2394}
2395
2396
2397THREADED_TEST(EvalInTryFinally) {
2398  v8::HandleScope scope;
2399  LocalContext context;
2400  v8::TryCatch try_catch;
2401  CompileRun("(function() {"
2402             "  try {"
2403             "    eval('asldkf (*&^&*^');"
2404             "  } finally {"
2405             "    return;"
2406             "  }"
2407             "})()");
2408  CHECK(!try_catch.HasCaught());
2409}
2410
2411
2412// This test works by making a stack of alternating JavaScript and C
2413// activations.  These activations set up exception handlers with regular
2414// intervals, one interval for C activations and another for JavaScript
2415// activations.  When enough activations have been created an exception is
2416// thrown and we check that the right activation catches the exception and that
2417// no other activations do.  The right activation is always the topmost one with
2418// a handler, regardless of whether it is in JavaScript or C.
2419//
2420// The notation used to describe a test case looks like this:
2421//
2422//    *JS[4] *C[3] @JS[2] C[1] JS[0]
2423//
2424// Each entry is an activation, either JS or C.  The index is the count at that
2425// level.  Stars identify activations with exception handlers, the @ identifies
2426// the exception handler that should catch the exception.
2427//
2428// BUG(271): Some of the exception propagation does not work on the
2429// ARM simulator because the simulator separates the C++ stack and the
2430// JS stack.  This test therefore fails on the simulator.  The test is
2431// not threaded to allow the threading tests to run on the simulator.
2432TEST(ExceptionOrder) {
2433  v8::HandleScope scope;
2434  Local<ObjectTemplate> templ = ObjectTemplate::New();
2435  templ->Set(v8_str("check"), v8::FunctionTemplate::New(JSCheck));
2436  templ->Set(v8_str("CThrowCountDown"),
2437             v8::FunctionTemplate::New(CThrowCountDown));
2438  LocalContext context(0, templ);
2439  CompileRun(
2440    "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
2441    "  if (count == 0) throw 'FromJS';"
2442    "  if (count % jsInterval == 0) {"
2443    "    try {"
2444    "      var value = CThrowCountDown(count - 1,"
2445    "                                  jsInterval,"
2446    "                                  cInterval,"
2447    "                                  expected);"
2448    "      check(false, count, expected);"
2449    "      return value;"
2450    "    } catch (e) {"
2451    "      check(true, count, expected);"
2452    "    }"
2453    "  } else {"
2454    "    return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
2455    "  }"
2456    "}");
2457  Local<Function> fun =
2458      Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
2459
2460  const int argc = 4;
2461  //                             count      jsInterval cInterval  expected
2462
2463  // *JS[4] *C[3] @JS[2] C[1] JS[0]
2464  v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
2465  fun->Call(fun, argc, a0);
2466
2467  // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
2468  v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
2469  fun->Call(fun, argc, a1);
2470
2471  // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
2472  v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
2473  fun->Call(fun, argc, a2);
2474
2475  // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
2476  v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
2477  fun->Call(fun, argc, a3);
2478
2479  // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
2480  v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
2481  fun->Call(fun, argc, a4);
2482
2483  // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
2484  v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
2485  fun->Call(fun, argc, a5);
2486}
2487
2488
2489v8::Handle<Value> ThrowValue(const v8::Arguments& args) {
2490  ApiTestFuzzer::Fuzz();
2491  CHECK_EQ(1, args.Length());
2492  return v8::ThrowException(args[0]);
2493}
2494
2495
2496THREADED_TEST(ThrowValues) {
2497  v8::HandleScope scope;
2498  Local<ObjectTemplate> templ = ObjectTemplate::New();
2499  templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(ThrowValue));
2500  LocalContext context(0, templ);
2501  v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
2502    "function Run(obj) {"
2503    "  try {"
2504    "    Throw(obj);"
2505    "  } catch (e) {"
2506    "    return e;"
2507    "  }"
2508    "  return 'no exception';"
2509    "}"
2510    "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
2511  CHECK_EQ(5, result->Length());
2512  CHECK(result->Get(v8::Integer::New(0))->IsString());
2513  CHECK(result->Get(v8::Integer::New(1))->IsNumber());
2514  CHECK_EQ(1, result->Get(v8::Integer::New(1))->Int32Value());
2515  CHECK(result->Get(v8::Integer::New(2))->IsNumber());
2516  CHECK_EQ(0, result->Get(v8::Integer::New(2))->Int32Value());
2517  CHECK(result->Get(v8::Integer::New(3))->IsNull());
2518  CHECK(result->Get(v8::Integer::New(4))->IsUndefined());
2519}
2520
2521
2522THREADED_TEST(CatchZero) {
2523  v8::HandleScope scope;
2524  LocalContext context;
2525  v8::TryCatch try_catch;
2526  CHECK(!try_catch.HasCaught());
2527  Script::Compile(v8_str("throw 10"))->Run();
2528  CHECK(try_catch.HasCaught());
2529  CHECK_EQ(10, try_catch.Exception()->Int32Value());
2530  try_catch.Reset();
2531  CHECK(!try_catch.HasCaught());
2532  Script::Compile(v8_str("throw 0"))->Run();
2533  CHECK(try_catch.HasCaught());
2534  CHECK_EQ(0, try_catch.Exception()->Int32Value());
2535}
2536
2537
2538THREADED_TEST(CatchExceptionFromWith) {
2539  v8::HandleScope scope;
2540  LocalContext context;
2541  v8::TryCatch try_catch;
2542  CHECK(!try_catch.HasCaught());
2543  Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run();
2544  CHECK(try_catch.HasCaught());
2545}
2546
2547
2548THREADED_TEST(Equality) {
2549  v8::HandleScope scope;
2550  LocalContext context;
2551  // Check that equality works at all before relying on CHECK_EQ
2552  CHECK(v8_str("a")->Equals(v8_str("a")));
2553  CHECK(!v8_str("a")->Equals(v8_str("b")));
2554
2555  CHECK_EQ(v8_str("a"), v8_str("a"));
2556  CHECK_NE(v8_str("a"), v8_str("b"));
2557  CHECK_EQ(v8_num(1), v8_num(1));
2558  CHECK_EQ(v8_num(1.00), v8_num(1));
2559  CHECK_NE(v8_num(1), v8_num(2));
2560
2561  // Assume String is not symbol.
2562  CHECK(v8_str("a")->StrictEquals(v8_str("a")));
2563  CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
2564  CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
2565  CHECK(v8_num(1)->StrictEquals(v8_num(1)));
2566  CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
2567  CHECK(v8_num(0)->StrictEquals(v8_num(-0)));
2568  Local<Value> not_a_number = v8_num(i::OS::nan_value());
2569  CHECK(!not_a_number->StrictEquals(not_a_number));
2570  CHECK(v8::False()->StrictEquals(v8::False()));
2571  CHECK(!v8::False()->StrictEquals(v8::Undefined()));
2572
2573  v8::Handle<v8::Object> obj = v8::Object::New();
2574  v8::Persistent<v8::Object> alias = v8::Persistent<v8::Object>::New(obj);
2575  CHECK(alias->StrictEquals(obj));
2576  alias.Dispose();
2577}
2578
2579
2580THREADED_TEST(MultiRun) {
2581  v8::HandleScope scope;
2582  LocalContext context;
2583  Local<Script> script = Script::Compile(v8_str("x"));
2584  for (int i = 0; i < 10; i++)
2585    script->Run();
2586}
2587
2588
2589static v8::Handle<Value> GetXValue(Local<String> name,
2590                                   const AccessorInfo& info) {
2591  ApiTestFuzzer::Fuzz();
2592  CHECK_EQ(info.Data(), v8_str("donut"));
2593  CHECK_EQ(name, v8_str("x"));
2594  return name;
2595}
2596
2597
2598THREADED_TEST(SimplePropertyRead) {
2599  v8::HandleScope scope;
2600  Local<ObjectTemplate> templ = ObjectTemplate::New();
2601  templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
2602  LocalContext context;
2603  context->Global()->Set(v8_str("obj"), templ->NewInstance());
2604  Local<Script> script = Script::Compile(v8_str("obj.x"));
2605  for (int i = 0; i < 10; i++) {
2606    Local<Value> result = script->Run();
2607    CHECK_EQ(result, v8_str("x"));
2608  }
2609}
2610
2611THREADED_TEST(DefinePropertyOnAPIAccessor) {
2612  v8::HandleScope scope;
2613  Local<ObjectTemplate> templ = ObjectTemplate::New();
2614  templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
2615  LocalContext context;
2616  context->Global()->Set(v8_str("obj"), templ->NewInstance());
2617
2618  // Uses getOwnPropertyDescriptor to check the configurable status
2619  Local<Script> script_desc
2620    = Script::Compile(v8_str("var prop = Object.getOwnPropertyDescriptor( "
2621                             "obj, 'x');"
2622                             "prop.configurable;"));
2623  Local<Value> result = script_desc->Run();
2624  CHECK_EQ(result->BooleanValue(), true);
2625
2626  // Redefine get - but still configurable
2627  Local<Script> script_define
2628    = Script::Compile(v8_str("var desc = { get: function(){return 42; },"
2629                             "            configurable: true };"
2630                             "Object.defineProperty(obj, 'x', desc);"
2631                             "obj.x"));
2632  result = script_define->Run();
2633  CHECK_EQ(result, v8_num(42));
2634
2635  // Check that the accessor is still configurable
2636  result = script_desc->Run();
2637  CHECK_EQ(result->BooleanValue(), true);
2638
2639  // Redefine to a non-configurable
2640  script_define
2641    = Script::Compile(v8_str("var desc = { get: function(){return 43; },"
2642                             "             configurable: false };"
2643                             "Object.defineProperty(obj, 'x', desc);"
2644                             "obj.x"));
2645  result = script_define->Run();
2646  CHECK_EQ(result, v8_num(43));
2647  result = script_desc->Run();
2648  CHECK_EQ(result->BooleanValue(), false);
2649
2650  // Make sure that it is not possible to redefine again
2651  v8::TryCatch try_catch;
2652  result = script_define->Run();
2653  CHECK(try_catch.HasCaught());
2654  String::AsciiValue exception_value(try_catch.Exception());
2655  CHECK_EQ(*exception_value,
2656           "TypeError: Cannot redefine property: defineProperty");
2657}
2658
2659THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
2660  v8::HandleScope scope;
2661  Local<ObjectTemplate> templ = ObjectTemplate::New();
2662  templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
2663  LocalContext context;
2664  context->Global()->Set(v8_str("obj"), templ->NewInstance());
2665
2666  Local<Script> script_desc = Script::Compile(v8_str("var prop ="
2667                                    "Object.getOwnPropertyDescriptor( "
2668                                    "obj, 'x');"
2669                                    "prop.configurable;"));
2670  Local<Value> result = script_desc->Run();
2671  CHECK_EQ(result->BooleanValue(), true);
2672
2673  Local<Script> script_define =
2674    Script::Compile(v8_str("var desc = {get: function(){return 42; },"
2675                           "            configurable: true };"
2676                           "Object.defineProperty(obj, 'x', desc);"
2677                           "obj.x"));
2678  result = script_define->Run();
2679  CHECK_EQ(result, v8_num(42));
2680
2681
2682  result = script_desc->Run();
2683  CHECK_EQ(result->BooleanValue(), true);
2684
2685
2686  script_define =
2687    Script::Compile(v8_str("var desc = {get: function(){return 43; },"
2688                           "            configurable: false };"
2689                           "Object.defineProperty(obj, 'x', desc);"
2690                           "obj.x"));
2691  result = script_define->Run();
2692  CHECK_EQ(result, v8_num(43));
2693  result = script_desc->Run();
2694
2695  CHECK_EQ(result->BooleanValue(), false);
2696
2697  v8::TryCatch try_catch;
2698  result = script_define->Run();
2699  CHECK(try_catch.HasCaught());
2700  String::AsciiValue exception_value(try_catch.Exception());
2701  CHECK_EQ(*exception_value,
2702           "TypeError: Cannot redefine property: defineProperty");
2703}
2704
2705
2706static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
2707                                                char const* name) {
2708  return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
2709}
2710
2711
2712THREADED_TEST(DefineAPIAccessorOnObject) {
2713  v8::HandleScope scope;
2714  Local<ObjectTemplate> templ = ObjectTemplate::New();
2715  LocalContext context;
2716
2717  context->Global()->Set(v8_str("obj1"), templ->NewInstance());
2718  CompileRun("var obj2 = {};");
2719
2720  CHECK(CompileRun("obj1.x")->IsUndefined());
2721  CHECK(CompileRun("obj2.x")->IsUndefined());
2722
2723  CHECK(GetGlobalProperty(&context, "obj1")->
2724      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2725
2726  ExpectString("obj1.x", "x");
2727  CHECK(CompileRun("obj2.x")->IsUndefined());
2728
2729  CHECK(GetGlobalProperty(&context, "obj2")->
2730      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2731
2732  ExpectString("obj1.x", "x");
2733  ExpectString("obj2.x", "x");
2734
2735  ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
2736  ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
2737
2738  CompileRun("Object.defineProperty(obj1, 'x',"
2739             "{ get: function() { return 'y'; }, configurable: true })");
2740
2741  ExpectString("obj1.x", "y");
2742  ExpectString("obj2.x", "x");
2743
2744  CompileRun("Object.defineProperty(obj2, 'x',"
2745             "{ get: function() { return 'y'; }, configurable: true })");
2746
2747  ExpectString("obj1.x", "y");
2748  ExpectString("obj2.x", "y");
2749
2750  ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
2751  ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
2752
2753  CHECK(GetGlobalProperty(&context, "obj1")->
2754      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2755  CHECK(GetGlobalProperty(&context, "obj2")->
2756      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2757
2758  ExpectString("obj1.x", "x");
2759  ExpectString("obj2.x", "x");
2760
2761  ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
2762  ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
2763
2764  // Define getters/setters, but now make them not configurable.
2765  CompileRun("Object.defineProperty(obj1, 'x',"
2766             "{ get: function() { return 'z'; }, configurable: false })");
2767  CompileRun("Object.defineProperty(obj2, 'x',"
2768             "{ get: function() { return 'z'; }, configurable: false })");
2769
2770  ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
2771  ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
2772
2773  ExpectString("obj1.x", "z");
2774  ExpectString("obj2.x", "z");
2775
2776  CHECK(!GetGlobalProperty(&context, "obj1")->
2777      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2778  CHECK(!GetGlobalProperty(&context, "obj2")->
2779      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2780
2781  ExpectString("obj1.x", "z");
2782  ExpectString("obj2.x", "z");
2783}
2784
2785
2786THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
2787  v8::HandleScope scope;
2788  Local<ObjectTemplate> templ = ObjectTemplate::New();
2789  LocalContext context;
2790
2791  context->Global()->Set(v8_str("obj1"), templ->NewInstance());
2792  CompileRun("var obj2 = {};");
2793
2794  CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
2795        v8_str("x"),
2796        GetXValue, NULL,
2797        v8_str("donut"), v8::DEFAULT, v8::DontDelete));
2798  CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
2799        v8_str("x"),
2800        GetXValue, NULL,
2801        v8_str("donut"), v8::DEFAULT, v8::DontDelete));
2802
2803  ExpectString("obj1.x", "x");
2804  ExpectString("obj2.x", "x");
2805
2806  ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
2807  ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
2808
2809  CHECK(!GetGlobalProperty(&context, "obj1")->
2810      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2811  CHECK(!GetGlobalProperty(&context, "obj2")->
2812      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2813
2814  {
2815    v8::TryCatch try_catch;
2816    CompileRun("Object.defineProperty(obj1, 'x',"
2817        "{get: function() { return 'func'; }})");
2818    CHECK(try_catch.HasCaught());
2819    String::AsciiValue exception_value(try_catch.Exception());
2820    CHECK_EQ(*exception_value,
2821            "TypeError: Cannot redefine property: defineProperty");
2822  }
2823  {
2824    v8::TryCatch try_catch;
2825    CompileRun("Object.defineProperty(obj2, 'x',"
2826        "{get: function() { return 'func'; }})");
2827    CHECK(try_catch.HasCaught());
2828    String::AsciiValue exception_value(try_catch.Exception());
2829    CHECK_EQ(*exception_value,
2830            "TypeError: Cannot redefine property: defineProperty");
2831  }
2832}
2833
2834
2835static v8::Handle<Value> Get239Value(Local<String> name,
2836                                     const AccessorInfo& info) {
2837  ApiTestFuzzer::Fuzz();
2838  CHECK_EQ(info.Data(), v8_str("donut"));
2839  CHECK_EQ(name, v8_str("239"));
2840  return name;
2841}
2842
2843
2844THREADED_TEST(ElementAPIAccessor) {
2845  v8::HandleScope scope;
2846  Local<ObjectTemplate> templ = ObjectTemplate::New();
2847  LocalContext context;
2848
2849  context->Global()->Set(v8_str("obj1"), templ->NewInstance());
2850  CompileRun("var obj2 = {};");
2851
2852  CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
2853        v8_str("239"),
2854        Get239Value, NULL,
2855        v8_str("donut")));
2856  CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
2857        v8_str("239"),
2858        Get239Value, NULL,
2859        v8_str("donut")));
2860
2861  ExpectString("obj1[239]", "239");
2862  ExpectString("obj2[239]", "239");
2863  ExpectString("obj1['239']", "239");
2864  ExpectString("obj2['239']", "239");
2865}
2866
2867
2868v8::Persistent<Value> xValue;
2869
2870
2871static void SetXValue(Local<String> name,
2872                      Local<Value> value,
2873                      const AccessorInfo& info) {
2874  CHECK_EQ(value, v8_num(4));
2875  CHECK_EQ(info.Data(), v8_str("donut"));
2876  CHECK_EQ(name, v8_str("x"));
2877  CHECK(xValue.IsEmpty());
2878  xValue = v8::Persistent<Value>::New(value);
2879}
2880
2881
2882THREADED_TEST(SimplePropertyWrite) {
2883  v8::HandleScope scope;
2884  Local<ObjectTemplate> templ = ObjectTemplate::New();
2885  templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
2886  LocalContext context;
2887  context->Global()->Set(v8_str("obj"), templ->NewInstance());
2888  Local<Script> script = Script::Compile(v8_str("obj.x = 4"));
2889  for (int i = 0; i < 10; i++) {
2890    CHECK(xValue.IsEmpty());
2891    script->Run();
2892    CHECK_EQ(v8_num(4), xValue);
2893    xValue.Dispose();
2894    xValue = v8::Persistent<Value>();
2895  }
2896}
2897
2898
2899static v8::Handle<Value> XPropertyGetter(Local<String> property,
2900                                         const AccessorInfo& info) {
2901  ApiTestFuzzer::Fuzz();
2902  CHECK(info.Data()->IsUndefined());
2903  return property;
2904}
2905
2906
2907THREADED_TEST(NamedInterceptorPropertyRead) {
2908  v8::HandleScope scope;
2909  Local<ObjectTemplate> templ = ObjectTemplate::New();
2910  templ->SetNamedPropertyHandler(XPropertyGetter);
2911  LocalContext context;
2912  context->Global()->Set(v8_str("obj"), templ->NewInstance());
2913  Local<Script> script = Script::Compile(v8_str("obj.x"));
2914  for (int i = 0; i < 10; i++) {
2915    Local<Value> result = script->Run();
2916    CHECK_EQ(result, v8_str("x"));
2917  }
2918}
2919
2920
2921THREADED_TEST(NamedInterceptorDictionaryIC) {
2922  v8::HandleScope scope;
2923  Local<ObjectTemplate> templ = ObjectTemplate::New();
2924  templ->SetNamedPropertyHandler(XPropertyGetter);
2925  LocalContext context;
2926  // Create an object with a named interceptor.
2927  context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
2928  Local<Script> script = Script::Compile(v8_str("interceptor_obj.x"));
2929  for (int i = 0; i < 10; i++) {
2930    Local<Value> result = script->Run();
2931    CHECK_EQ(result, v8_str("x"));
2932  }
2933  // Create a slow case object and a function accessing a property in
2934  // that slow case object (with dictionary probing in generated
2935  // code). Then force object with a named interceptor into slow-case,
2936  // pass it to the function, and check that the interceptor is called
2937  // instead of accessing the local property.
2938  Local<Value> result =
2939      CompileRun("function get_x(o) { return o.x; };"
2940                 "var obj = { x : 42, y : 0 };"
2941                 "delete obj.y;"
2942                 "for (var i = 0; i < 10; i++) get_x(obj);"
2943                 "interceptor_obj.x = 42;"
2944                 "interceptor_obj.y = 10;"
2945                 "delete interceptor_obj.y;"
2946                 "get_x(interceptor_obj)");
2947  CHECK_EQ(result, v8_str("x"));
2948}
2949
2950
2951THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
2952  v8::HandleScope scope;
2953
2954  v8::Persistent<Context> context1 = Context::New();
2955
2956  context1->Enter();
2957  Local<ObjectTemplate> templ = ObjectTemplate::New();
2958  templ->SetNamedPropertyHandler(XPropertyGetter);
2959  // Create an object with a named interceptor.
2960  v8::Local<v8::Object> object = templ->NewInstance();
2961  context1->Global()->Set(v8_str("interceptor_obj"), object);
2962
2963  // Force the object into the slow case.
2964  CompileRun("interceptor_obj.y = 0;"
2965             "delete interceptor_obj.y;");
2966  context1->Exit();
2967
2968  {
2969    // Introduce the object into a different context.
2970    // Repeat named loads to exercise ICs.
2971    LocalContext context2;
2972    context2->Global()->Set(v8_str("interceptor_obj"), object);
2973    Local<Value> result =
2974      CompileRun("function get_x(o) { return o.x; }"
2975                 "interceptor_obj.x = 42;"
2976                 "for (var i=0; i != 10; i++) {"
2977                 "  get_x(interceptor_obj);"
2978                 "}"
2979                 "get_x(interceptor_obj)");
2980    // Check that the interceptor was actually invoked.
2981    CHECK_EQ(result, v8_str("x"));
2982  }
2983
2984  // Return to the original context and force some object to the slow case
2985  // to cause the NormalizedMapCache to verify.
2986  context1->Enter();
2987  CompileRun("var obj = { x : 0 }; delete obj.x;");
2988  context1->Exit();
2989
2990  context1.Dispose();
2991}
2992
2993
2994static v8::Handle<Value> SetXOnPrototypeGetter(Local<String> property,
2995                                               const AccessorInfo& info) {
2996  // Set x on the prototype object and do not handle the get request.
2997  v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
2998  proto.As<v8::Object>()->Set(v8_str("x"), v8::Integer::New(23));
2999  return v8::Handle<Value>();
3000}
3001
3002
3003// This is a regression test for http://crbug.com/20104. Map
3004// transitions should not interfere with post interceptor lookup.
3005THREADED_TEST(NamedInterceptorMapTransitionRead) {
3006  v8::HandleScope scope;
3007  Local<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New();
3008  Local<v8::ObjectTemplate> instance_template
3009      = function_template->InstanceTemplate();
3010  instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
3011  LocalContext context;
3012  context->Global()->Set(v8_str("F"), function_template->GetFunction());
3013  // Create an instance of F and introduce a map transition for x.
3014  CompileRun("var o = new F(); o.x = 23;");
3015  // Create an instance of F and invoke the getter. The result should be 23.
3016  Local<Value> result = CompileRun("o = new F(); o.x");
3017  CHECK_EQ(result->Int32Value(), 23);
3018}
3019
3020
3021static v8::Handle<Value> IndexedPropertyGetter(uint32_t index,
3022                                               const AccessorInfo& info) {
3023  ApiTestFuzzer::Fuzz();
3024  if (index == 37) {
3025    return v8::Handle<Value>(v8_num(625));
3026  }
3027  return v8::Handle<Value>();
3028}
3029
3030
3031static v8::Handle<Value> IndexedPropertySetter(uint32_t index,
3032                                               Local<Value> value,
3033                                               const AccessorInfo& info) {
3034  ApiTestFuzzer::Fuzz();
3035  if (index == 39) {
3036    return value;
3037  }
3038  return v8::Handle<Value>();
3039}
3040
3041
3042THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
3043  v8::HandleScope scope;
3044  Local<ObjectTemplate> templ = ObjectTemplate::New();
3045  templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
3046                                   IndexedPropertySetter);
3047  LocalContext context;
3048  context->Global()->Set(v8_str("obj"), templ->NewInstance());
3049  Local<Script> getter_script = Script::Compile(v8_str(
3050      "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];"));
3051  Local<Script> setter_script = Script::Compile(v8_str(
3052      "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
3053      "obj[17] = 23;"
3054      "obj.foo;"));
3055  Local<Script> interceptor_setter_script = Script::Compile(v8_str(
3056      "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
3057      "obj[39] = 47;"
3058      "obj.foo;"));  // This setter should not run, due to the interceptor.
3059  Local<Script> interceptor_getter_script = Script::Compile(v8_str(
3060      "obj[37];"));
3061  Local<Value> result = getter_script->Run();
3062  CHECK_EQ(v8_num(5), result);
3063  result = setter_script->Run();
3064  CHECK_EQ(v8_num(23), result);
3065  result = interceptor_setter_script->Run();
3066  CHECK_EQ(v8_num(23), result);
3067  result = interceptor_getter_script->Run();
3068  CHECK_EQ(v8_num(625), result);
3069}
3070
3071
3072static v8::Handle<Value> IdentityIndexedPropertyGetter(
3073    uint32_t index,
3074    const AccessorInfo& info) {
3075  return v8::Integer::NewFromUnsigned(index);
3076}
3077
3078
3079THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
3080  v8::HandleScope scope;
3081  Local<ObjectTemplate> templ = ObjectTemplate::New();
3082  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3083
3084  LocalContext context;
3085  context->Global()->Set(v8_str("obj"), templ->NewInstance());
3086
3087  // Check fast object case.
3088  const char* fast_case_code =
3089      "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
3090  ExpectString(fast_case_code, "0");
3091
3092  // Check slow case.
3093  const char* slow_case_code =
3094      "obj.x = 1; delete obj.x;"
3095      "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
3096  ExpectString(slow_case_code, "1");
3097}
3098
3099
3100THREADED_TEST(IndexedInterceptorWithNoSetter) {
3101  v8::HandleScope scope;
3102  Local<ObjectTemplate> templ = ObjectTemplate::New();
3103  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3104
3105  LocalContext context;
3106  context->Global()->Set(v8_str("obj"), templ->NewInstance());
3107
3108  const char* code =
3109      "try {"
3110      "  obj[0] = 239;"
3111      "  for (var i = 0; i < 100; i++) {"
3112      "    var v = obj[0];"
3113      "    if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
3114      "  }"
3115      "  'PASSED'"
3116      "} catch(e) {"
3117      "  e"
3118      "}";
3119  ExpectString(code, "PASSED");
3120}
3121
3122
3123THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
3124  v8::HandleScope scope;
3125  Local<ObjectTemplate> templ = ObjectTemplate::New();
3126  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3127
3128  LocalContext context;
3129  Local<v8::Object> obj = templ->NewInstance();
3130  obj->TurnOnAccessCheck();
3131  context->Global()->Set(v8_str("obj"), obj);
3132
3133  const char* code =
3134      "try {"
3135      "  for (var i = 0; i < 100; i++) {"
3136      "    var v = obj[0];"
3137      "    if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
3138      "  }"
3139      "  'PASSED'"
3140      "} catch(e) {"
3141      "  e"
3142      "}";
3143  ExpectString(code, "PASSED");
3144}
3145
3146
3147THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
3148  i::FLAG_allow_natives_syntax = true;
3149  v8::HandleScope scope;
3150  Local<ObjectTemplate> templ = ObjectTemplate::New();
3151  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3152
3153  LocalContext context;
3154  Local<v8::Object> obj = templ->NewInstance();
3155  context->Global()->Set(v8_str("obj"), obj);
3156
3157  const char* code =
3158      "try {"
3159      "  for (var i = 0; i < 100; i++) {"
3160      "    var expected = i;"
3161      "    if (i == 5) {"
3162      "      %EnableAccessChecks(obj);"
3163      "      expected = undefined;"
3164      "    }"
3165      "    var v = obj[i];"
3166      "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3167      "    if (i == 5) %DisableAccessChecks(obj);"
3168      "  }"
3169      "  'PASSED'"
3170      "} catch(e) {"
3171      "  e"
3172      "}";
3173  ExpectString(code, "PASSED");
3174}
3175
3176
3177THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
3178  v8::HandleScope scope;
3179  Local<ObjectTemplate> templ = ObjectTemplate::New();
3180  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3181
3182  LocalContext context;
3183  Local<v8::Object> obj = templ->NewInstance();
3184  context->Global()->Set(v8_str("obj"), obj);
3185
3186  const char* code =
3187      "try {"
3188      "  for (var i = 0; i < 100; i++) {"
3189      "    var v = obj[i];"
3190      "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
3191      "  }"
3192      "  'PASSED'"
3193      "} catch(e) {"
3194      "  e"
3195      "}";
3196  ExpectString(code, "PASSED");
3197}
3198
3199
3200THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
3201  v8::HandleScope scope;
3202  Local<ObjectTemplate> templ = ObjectTemplate::New();
3203  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3204
3205  LocalContext context;
3206  Local<v8::Object> obj = templ->NewInstance();
3207  context->Global()->Set(v8_str("obj"), obj);
3208
3209  const char* code =
3210      "try {"
3211      "  for (var i = 0; i < 100; i++) {"
3212      "    var expected = i;"
3213      "    var key = i;"
3214      "    if (i == 25) {"
3215      "       key = -1;"
3216      "       expected = undefined;"
3217      "    }"
3218      "    if (i == 50) {"
3219      "       /* probe minimal Smi number on 32-bit platforms */"
3220      "       key = -(1 << 30);"
3221      "       expected = undefined;"
3222      "    }"
3223      "    if (i == 75) {"
3224      "       /* probe minimal Smi number on 64-bit platforms */"
3225      "       key = 1 << 31;"
3226      "       expected = undefined;"
3227      "    }"
3228      "    var v = obj[key];"
3229      "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3230      "  }"
3231      "  'PASSED'"
3232      "} catch(e) {"
3233      "  e"
3234      "}";
3235  ExpectString(code, "PASSED");
3236}
3237
3238
3239THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
3240  v8::HandleScope scope;
3241  Local<ObjectTemplate> templ = ObjectTemplate::New();
3242  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3243
3244  LocalContext context;
3245  Local<v8::Object> obj = templ->NewInstance();
3246  context->Global()->Set(v8_str("obj"), obj);
3247
3248  const char* code =
3249      "try {"
3250      "  for (var i = 0; i < 100; i++) {"
3251      "    var expected = i;"
3252      "    var key = i;"
3253      "    if (i == 50) {"
3254      "       key = 'foobar';"
3255      "       expected = undefined;"
3256      "    }"
3257      "    var v = obj[key];"
3258      "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3259      "  }"
3260      "  'PASSED'"
3261      "} catch(e) {"
3262      "  e"
3263      "}";
3264  ExpectString(code, "PASSED");
3265}
3266
3267
3268THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
3269  v8::HandleScope scope;
3270  Local<ObjectTemplate> templ = ObjectTemplate::New();
3271  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3272
3273  LocalContext context;
3274  Local<v8::Object> obj = templ->NewInstance();
3275  context->Global()->Set(v8_str("obj"), obj);
3276
3277  const char* code =
3278      "var original = obj;"
3279      "try {"
3280      "  for (var i = 0; i < 100; i++) {"
3281      "    var expected = i;"
3282      "    if (i == 50) {"
3283      "       obj = {50: 'foobar'};"
3284      "       expected = 'foobar';"
3285      "    }"
3286      "    var v = obj[i];"
3287      "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3288      "    if (i == 50) obj = original;"
3289      "  }"
3290      "  'PASSED'"
3291      "} catch(e) {"
3292      "  e"
3293      "}";
3294  ExpectString(code, "PASSED");
3295}
3296
3297
3298THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
3299  v8::HandleScope scope;
3300  Local<ObjectTemplate> templ = ObjectTemplate::New();
3301  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3302
3303  LocalContext context;
3304  Local<v8::Object> obj = templ->NewInstance();
3305  context->Global()->Set(v8_str("obj"), obj);
3306
3307  const char* code =
3308      "var original = obj;"
3309      "try {"
3310      "  for (var i = 0; i < 100; i++) {"
3311      "    var expected = i;"
3312      "    if (i == 5) {"
3313      "       obj = 239;"
3314      "       expected = undefined;"
3315      "    }"
3316      "    var v = obj[i];"
3317      "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3318      "    if (i == 5) obj = original;"
3319      "  }"
3320      "  'PASSED'"
3321      "} catch(e) {"
3322      "  e"
3323      "}";
3324  ExpectString(code, "PASSED");
3325}
3326
3327
3328THREADED_TEST(IndexedInterceptorOnProto) {
3329  v8::HandleScope scope;
3330  Local<ObjectTemplate> templ = ObjectTemplate::New();
3331  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3332
3333  LocalContext context;
3334  Local<v8::Object> obj = templ->NewInstance();
3335  context->Global()->Set(v8_str("obj"), obj);
3336
3337  const char* code =
3338      "var o = {__proto__: obj};"
3339      "try {"
3340      "  for (var i = 0; i < 100; i++) {"
3341      "    var v = o[i];"
3342      "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
3343      "  }"
3344      "  'PASSED'"
3345      "} catch(e) {"
3346      "  e"
3347      "}";
3348  ExpectString(code, "PASSED");
3349}
3350
3351
3352THREADED_TEST(MultiContexts) {
3353  v8::HandleScope scope;
3354  v8::Handle<ObjectTemplate> templ = ObjectTemplate::New();
3355  templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(DummyCallHandler));
3356
3357  Local<String> password = v8_str("Password");
3358
3359  // Create an environment
3360  LocalContext context0(0, templ);
3361  context0->SetSecurityToken(password);
3362  v8::Handle<v8::Object> global0 = context0->Global();
3363  global0->Set(v8_str("custom"), v8_num(1234));
3364  CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
3365
3366  // Create an independent environment
3367  LocalContext context1(0, templ);
3368  context1->SetSecurityToken(password);
3369  v8::Handle<v8::Object> global1 = context1->Global();
3370  global1->Set(v8_str("custom"), v8_num(1234));
3371  CHECK_NE(global0, global1);
3372  CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
3373  CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
3374
3375  // Now create a new context with the old global
3376  LocalContext context2(0, templ, global1);
3377  context2->SetSecurityToken(password);
3378  v8::Handle<v8::Object> global2 = context2->Global();
3379  CHECK_EQ(global1, global2);
3380  CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
3381  CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
3382}
3383
3384
3385THREADED_TEST(FunctionPrototypeAcrossContexts) {
3386  // Make sure that functions created by cloning boilerplates cannot
3387  // communicate through their __proto__ field.
3388
3389  v8::HandleScope scope;
3390
3391  LocalContext env0;
3392  v8::Handle<v8::Object> global0 =
3393      env0->Global();
3394  v8::Handle<v8::Object> object0 =
3395      global0->Get(v8_str("Object")).As<v8::Object>();
3396  v8::Handle<v8::Object> tostring0 =
3397      object0->Get(v8_str("toString")).As<v8::Object>();
3398  v8::Handle<v8::Object> proto0 =
3399      tostring0->Get(v8_str("__proto__")).As<v8::Object>();
3400  proto0->Set(v8_str("custom"), v8_num(1234));
3401
3402  LocalContext env1;
3403  v8::Handle<v8::Object> global1 =
3404      env1->Global();
3405  v8::Handle<v8::Object> object1 =
3406      global1->Get(v8_str("Object")).As<v8::Object>();
3407  v8::Handle<v8::Object> tostring1 =
3408      object1->Get(v8_str("toString")).As<v8::Object>();
3409  v8::Handle<v8::Object> proto1 =
3410      tostring1->Get(v8_str("__proto__")).As<v8::Object>();
3411  CHECK(!proto1->Has(v8_str("custom")));
3412}
3413
3414
3415THREADED_TEST(Regress892105) {
3416  // Make sure that object and array literals created by cloning
3417  // boilerplates cannot communicate through their __proto__
3418  // field. This is rather difficult to check, but we try to add stuff
3419  // to Object.prototype and Array.prototype and create a new
3420  // environment. This should succeed.
3421
3422  v8::HandleScope scope;
3423
3424  Local<String> source = v8_str("Object.prototype.obj = 1234;"
3425                                "Array.prototype.arr = 4567;"
3426                                "8901");
3427
3428  LocalContext env0;
3429  Local<Script> script0 = Script::Compile(source);
3430  CHECK_EQ(8901.0, script0->Run()->NumberValue());
3431
3432  LocalContext env1;
3433  Local<Script> script1 = Script::Compile(source);
3434  CHECK_EQ(8901.0, script1->Run()->NumberValue());
3435}
3436
3437
3438THREADED_TEST(UndetectableObject) {
3439  v8::HandleScope scope;
3440  LocalContext env;
3441
3442  Local<v8::FunctionTemplate> desc =
3443      v8::FunctionTemplate::New(0, v8::Handle<Value>());
3444  desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
3445
3446  Local<v8::Object> obj = desc->GetFunction()->NewInstance();
3447  env->Global()->Set(v8_str("undetectable"), obj);
3448
3449  ExpectString("undetectable.toString()", "[object Object]");
3450  ExpectString("typeof undetectable", "undefined");
3451  ExpectString("typeof(undetectable)", "undefined");
3452  ExpectBoolean("typeof undetectable == 'undefined'", true);
3453  ExpectBoolean("typeof undetectable == 'object'", false);
3454  ExpectBoolean("if (undetectable) { true; } else { false; }", false);
3455  ExpectBoolean("!undetectable", true);
3456
3457  ExpectObject("true&&undetectable", obj);
3458  ExpectBoolean("false&&undetectable", false);
3459  ExpectBoolean("true||undetectable", true);
3460  ExpectObject("false||undetectable", obj);
3461
3462  ExpectObject("undetectable&&true", obj);
3463  ExpectObject("undetectable&&false", obj);
3464  ExpectBoolean("undetectable||true", true);
3465  ExpectBoolean("undetectable||false", false);
3466
3467  ExpectBoolean("undetectable==null", true);
3468  ExpectBoolean("null==undetectable", true);
3469  ExpectBoolean("undetectable==undefined", true);
3470  ExpectBoolean("undefined==undetectable", true);
3471  ExpectBoolean("undetectable==undetectable", true);
3472
3473
3474  ExpectBoolean("undetectable===null", false);
3475  ExpectBoolean("null===undetectable", false);
3476  ExpectBoolean("undetectable===undefined", false);
3477  ExpectBoolean("undefined===undetectable", false);
3478  ExpectBoolean("undetectable===undetectable", true);
3479}
3480
3481
3482
3483THREADED_TEST(ExtensibleOnUndetectable) {
3484  v8::HandleScope scope;
3485  LocalContext env;
3486
3487  Local<v8::FunctionTemplate> desc =
3488      v8::FunctionTemplate::New(0, v8::Handle<Value>());
3489  desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
3490
3491  Local<v8::Object> obj = desc->GetFunction()->NewInstance();
3492  env->Global()->Set(v8_str("undetectable"), obj);
3493
3494  Local<String> source = v8_str("undetectable.x = 42;"
3495                                "undetectable.x");
3496
3497  Local<Script> script = Script::Compile(source);
3498
3499  CHECK_EQ(v8::Integer::New(42), script->Run());
3500
3501  ExpectBoolean("Object.isExtensible(undetectable)", true);
3502
3503  source = v8_str("Object.preventExtensions(undetectable);");
3504  script = Script::Compile(source);
3505  script->Run();
3506  ExpectBoolean("Object.isExtensible(undetectable)", false);
3507
3508  source = v8_str("undetectable.y = 2000;");
3509  script = Script::Compile(source);
3510  v8::TryCatch try_catch;
3511  Local<Value> result = script->Run();
3512  CHECK(result.IsEmpty());
3513  CHECK(try_catch.HasCaught());
3514}
3515
3516
3517
3518THREADED_TEST(UndetectableString) {
3519  v8::HandleScope scope;
3520  LocalContext env;
3521
3522  Local<String> obj = String::NewUndetectable("foo");
3523  env->Global()->Set(v8_str("undetectable"), obj);
3524
3525  ExpectString("undetectable", "foo");
3526  ExpectString("typeof undetectable", "undefined");
3527  ExpectString("typeof(undetectable)", "undefined");
3528  ExpectBoolean("typeof undetectable == 'undefined'", true);
3529  ExpectBoolean("typeof undetectable == 'string'", false);
3530  ExpectBoolean("if (undetectable) { true; } else { false; }", false);
3531  ExpectBoolean("!undetectable", true);
3532
3533  ExpectObject("true&&undetectable", obj);
3534  ExpectBoolean("false&&undetectable", false);
3535  ExpectBoolean("true||undetectable", true);
3536  ExpectObject("false||undetectable", obj);
3537
3538  ExpectObject("undetectable&&true", obj);
3539  ExpectObject("undetectable&&false", obj);
3540  ExpectBoolean("undetectable||true", true);
3541  ExpectBoolean("undetectable||false", false);
3542
3543  ExpectBoolean("undetectable==null", true);
3544  ExpectBoolean("null==undetectable", true);
3545  ExpectBoolean("undetectable==undefined", true);
3546  ExpectBoolean("undefined==undetectable", true);
3547  ExpectBoolean("undetectable==undetectable", true);
3548
3549
3550  ExpectBoolean("undetectable===null", false);
3551  ExpectBoolean("null===undetectable", false);
3552  ExpectBoolean("undetectable===undefined", false);
3553  ExpectBoolean("undefined===undetectable", false);
3554  ExpectBoolean("undetectable===undetectable", true);
3555}
3556
3557
3558template <typename T> static void USE(T) { }
3559
3560
3561// This test is not intended to be run, just type checked.
3562static void PersistentHandles() {
3563  USE(PersistentHandles);
3564  Local<String> str = v8_str("foo");
3565  v8::Persistent<String> p_str = v8::Persistent<String>::New(str);
3566  USE(p_str);
3567  Local<Script> scr = Script::Compile(v8_str(""));
3568  v8::Persistent<Script> p_scr = v8::Persistent<Script>::New(scr);
3569  USE(p_scr);
3570  Local<ObjectTemplate> templ = ObjectTemplate::New();
3571  v8::Persistent<ObjectTemplate> p_templ =
3572    v8::Persistent<ObjectTemplate>::New(templ);
3573  USE(p_templ);
3574}
3575
3576
3577static v8::Handle<Value> HandleLogDelegator(const v8::Arguments& args) {
3578  ApiTestFuzzer::Fuzz();
3579  return v8::Undefined();
3580}
3581
3582
3583THREADED_TEST(GlobalObjectTemplate) {
3584  v8::HandleScope handle_scope;
3585  Local<ObjectTemplate> global_template = ObjectTemplate::New();
3586  global_template->Set(v8_str("JSNI_Log"),
3587                       v8::FunctionTemplate::New(HandleLogDelegator));
3588  v8::Persistent<Context> context = Context::New(0, global_template);
3589  Context::Scope context_scope(context);
3590  Script::Compile(v8_str("JSNI_Log('LOG')"))->Run();
3591  context.Dispose();
3592}
3593
3594
3595static const char* kSimpleExtensionSource =
3596  "function Foo() {"
3597  "  return 4;"
3598  "}";
3599
3600
3601THREADED_TEST(SimpleExtensions) {
3602  v8::HandleScope handle_scope;
3603  v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
3604  const char* extension_names[] = { "simpletest" };
3605  v8::ExtensionConfiguration extensions(1, extension_names);
3606  v8::Handle<Context> context = Context::New(&extensions);
3607  Context::Scope lock(context);
3608  v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
3609  CHECK_EQ(result, v8::Integer::New(4));
3610}
3611
3612
3613static const char* kEvalExtensionSource1 =
3614  "function UseEval1() {"
3615  "  var x = 42;"
3616  "  return eval('x');"
3617  "}";
3618
3619
3620static const char* kEvalExtensionSource2 =
3621  "(function() {"
3622  "  var x = 42;"
3623  "  function e() {"
3624  "    return eval('x');"
3625  "  }"
3626  "  this.UseEval2 = e;"
3627  "})()";
3628
3629
3630THREADED_TEST(UseEvalFromExtension) {
3631  v8::HandleScope handle_scope;
3632  v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
3633  v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
3634  const char* extension_names[] = { "evaltest1", "evaltest2" };
3635  v8::ExtensionConfiguration extensions(2, extension_names);
3636  v8::Handle<Context> context = Context::New(&extensions);
3637  Context::Scope lock(context);
3638  v8::Handle<Value> result = Script::Compile(v8_str("UseEval1()"))->Run();
3639  CHECK_EQ(result, v8::Integer::New(42));
3640  result = Script::Compile(v8_str("UseEval2()"))->Run();
3641  CHECK_EQ(result, v8::Integer::New(42));
3642}
3643
3644
3645static const char* kWithExtensionSource1 =
3646  "function UseWith1() {"
3647  "  var x = 42;"
3648  "  with({x:87}) { return x; }"
3649  "}";
3650
3651
3652
3653static const char* kWithExtensionSource2 =
3654  "(function() {"
3655  "  var x = 42;"
3656  "  function e() {"
3657  "    with ({x:87}) { return x; }"
3658  "  }"
3659  "  this.UseWith2 = e;"
3660  "})()";
3661
3662
3663THREADED_TEST(UseWithFromExtension) {
3664  v8::HandleScope handle_scope;
3665  v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
3666  v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
3667  const char* extension_names[] = { "withtest1", "withtest2" };
3668  v8::ExtensionConfiguration extensions(2, extension_names);
3669  v8::Handle<Context> context = Context::New(&extensions);
3670  Context::Scope lock(context);
3671  v8::Handle<Value> result = Script::Compile(v8_str("UseWith1()"))->Run();
3672  CHECK_EQ(result, v8::Integer::New(87));
3673  result = Script::Compile(v8_str("UseWith2()"))->Run();
3674  CHECK_EQ(result, v8::Integer::New(87));
3675}
3676
3677
3678THREADED_TEST(AutoExtensions) {
3679  v8::HandleScope handle_scope;
3680  Extension* extension = new Extension("autotest", kSimpleExtensionSource);
3681  extension->set_auto_enable(true);
3682  v8::RegisterExtension(extension);
3683  v8::Handle<Context> context = Context::New();
3684  Context::Scope lock(context);
3685  v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
3686  CHECK_EQ(result, v8::Integer::New(4));
3687}
3688
3689
3690static const char* kSyntaxErrorInExtensionSource =
3691    "[";
3692
3693
3694// Test that a syntax error in an extension does not cause a fatal
3695// error but results in an empty context.
3696THREADED_TEST(SyntaxErrorExtensions) {
3697  v8::HandleScope handle_scope;
3698  v8::RegisterExtension(new Extension("syntaxerror",
3699                                      kSyntaxErrorInExtensionSource));
3700  const char* extension_names[] = { "syntaxerror" };
3701  v8::ExtensionConfiguration extensions(1, extension_names);
3702  v8::Handle<Context> context = Context::New(&extensions);
3703  CHECK(context.IsEmpty());
3704}
3705
3706
3707static const char* kExceptionInExtensionSource =
3708    "throw 42";
3709
3710
3711// Test that an exception when installing an extension does not cause
3712// a fatal error but results in an empty context.
3713THREADED_TEST(ExceptionExtensions) {
3714  v8::HandleScope handle_scope;
3715  v8::RegisterExtension(new Extension("exception",
3716                                      kExceptionInExtensionSource));
3717  const char* extension_names[] = { "exception" };
3718  v8::ExtensionConfiguration extensions(1, extension_names);
3719  v8::Handle<Context> context = Context::New(&extensions);
3720  CHECK(context.IsEmpty());
3721}
3722
3723
3724static const char* kNativeCallInExtensionSource =
3725    "function call_runtime_last_index_of(x) {"
3726    "  return %StringLastIndexOf(x, 'bob', 10);"
3727    "}";
3728
3729
3730static const char* kNativeCallTest =
3731    "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
3732
3733// Test that a native runtime calls are supported in extensions.
3734THREADED_TEST(NativeCallInExtensions) {
3735  v8::HandleScope handle_scope;
3736  v8::RegisterExtension(new Extension("nativecall",
3737                                      kNativeCallInExtensionSource));
3738  const char* extension_names[] = { "nativecall" };
3739  v8::ExtensionConfiguration extensions(1, extension_names);
3740  v8::Handle<Context> context = Context::New(&extensions);
3741  Context::Scope lock(context);
3742  v8::Handle<Value> result = Script::Compile(v8_str(kNativeCallTest))->Run();
3743  CHECK_EQ(result, v8::Integer::New(3));
3744}
3745
3746
3747static void CheckDependencies(const char* name, const char* expected) {
3748  v8::HandleScope handle_scope;
3749  v8::ExtensionConfiguration config(1, &name);
3750  LocalContext context(&config);
3751  CHECK_EQ(String::New(expected), context->Global()->Get(v8_str("loaded")));
3752}
3753
3754
3755/*
3756 * Configuration:
3757 *
3758 *     /-- B <--\
3759 * A <-          -- D <-- E
3760 *     \-- C <--/
3761 */
3762THREADED_TEST(ExtensionDependency) {
3763  static const char* kEDeps[] = { "D" };
3764  v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
3765  static const char* kDDeps[] = { "B", "C" };
3766  v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
3767  static const char* kBCDeps[] = { "A" };
3768  v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
3769  v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
3770  v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
3771  CheckDependencies("A", "undefinedA");
3772  CheckDependencies("B", "undefinedAB");
3773  CheckDependencies("C", "undefinedAC");
3774  CheckDependencies("D", "undefinedABCD");
3775  CheckDependencies("E", "undefinedABCDE");
3776  v8::HandleScope handle_scope;
3777  static const char* exts[2] = { "C", "E" };
3778  v8::ExtensionConfiguration config(2, exts);
3779  LocalContext context(&config);
3780  CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
3781}
3782
3783
3784static const char* kExtensionTestScript =
3785  "native function A();"
3786  "native function B();"
3787  "native function C();"
3788  "function Foo(i) {"
3789  "  if (i == 0) return A();"
3790  "  if (i == 1) return B();"
3791  "  if (i == 2) return C();"
3792  "}";
3793
3794
3795static v8::Handle<Value> CallFun(const v8::Arguments& args) {
3796  ApiTestFuzzer::Fuzz();
3797  if (args.IsConstructCall()) {
3798    args.This()->Set(v8_str("data"), args.Data());
3799    return v8::Null();
3800  }
3801  return args.Data();
3802}
3803
3804
3805class FunctionExtension : public Extension {
3806 public:
3807  FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
3808  virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
3809      v8::Handle<String> name);
3810};
3811
3812
3813static int lookup_count = 0;
3814v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunction(
3815      v8::Handle<String> name) {
3816  lookup_count++;
3817  if (name->Equals(v8_str("A"))) {
3818    return v8::FunctionTemplate::New(CallFun, v8::Integer::New(8));
3819  } else if (name->Equals(v8_str("B"))) {
3820    return v8::FunctionTemplate::New(CallFun, v8::Integer::New(7));
3821  } else if (name->Equals(v8_str("C"))) {
3822    return v8::FunctionTemplate::New(CallFun, v8::Integer::New(6));
3823  } else {
3824    return v8::Handle<v8::FunctionTemplate>();
3825  }
3826}
3827
3828
3829THREADED_TEST(FunctionLookup) {
3830  v8::RegisterExtension(new FunctionExtension());
3831  v8::HandleScope handle_scope;
3832  static const char* exts[1] = { "functiontest" };
3833  v8::ExtensionConfiguration config(1, exts);
3834  LocalContext context(&config);
3835  CHECK_EQ(3, lookup_count);
3836  CHECK_EQ(v8::Integer::New(8), Script::Compile(v8_str("Foo(0)"))->Run());
3837  CHECK_EQ(v8::Integer::New(7), Script::Compile(v8_str("Foo(1)"))->Run());
3838  CHECK_EQ(v8::Integer::New(6), Script::Compile(v8_str("Foo(2)"))->Run());
3839}
3840
3841
3842THREADED_TEST(NativeFunctionConstructCall) {
3843  v8::RegisterExtension(new FunctionExtension());
3844  v8::HandleScope handle_scope;
3845  static const char* exts[1] = { "functiontest" };
3846  v8::ExtensionConfiguration config(1, exts);
3847  LocalContext context(&config);
3848  for (int i = 0; i < 10; i++) {
3849    // Run a few times to ensure that allocation of objects doesn't
3850    // change behavior of a constructor function.
3851    CHECK_EQ(v8::Integer::New(8),
3852             Script::Compile(v8_str("(new A()).data"))->Run());
3853    CHECK_EQ(v8::Integer::New(7),
3854             Script::Compile(v8_str("(new B()).data"))->Run());
3855    CHECK_EQ(v8::Integer::New(6),
3856             Script::Compile(v8_str("(new C()).data"))->Run());
3857  }
3858}
3859
3860
3861static const char* last_location;
3862static const char* last_message;
3863void StoringErrorCallback(const char* location, const char* message) {
3864  if (last_location == NULL) {
3865    last_location = location;
3866    last_message = message;
3867  }
3868}
3869
3870
3871// ErrorReporting creates a circular extensions configuration and
3872// tests that the fatal error handler gets called.  This renders V8
3873// unusable and therefore this test cannot be run in parallel.
3874TEST(ErrorReporting) {
3875  v8::V8::SetFatalErrorHandler(StoringErrorCallback);
3876  static const char* aDeps[] = { "B" };
3877  v8::RegisterExtension(new Extension("A", "", 1, aDeps));
3878  static const char* bDeps[] = { "A" };
3879  v8::RegisterExtension(new Extension("B", "", 1, bDeps));
3880  last_location = NULL;
3881  v8::ExtensionConfiguration config(1, bDeps);
3882  v8::Handle<Context> context = Context::New(&config);
3883  CHECK(context.IsEmpty());
3884  CHECK_NE(last_location, NULL);
3885}
3886
3887
3888static const char* js_code_causing_huge_string_flattening =
3889    "var str = 'X';"
3890    "for (var i = 0; i < 30; i++) {"
3891    "  str = str + str;"
3892    "}"
3893    "str.match(/X/);";
3894
3895
3896void OOMCallback(const char* location, const char* message) {
3897  exit(0);
3898}
3899
3900
3901TEST(RegexpOutOfMemory) {
3902  // Execute a script that causes out of memory when flattening a string.
3903  v8::HandleScope scope;
3904  v8::V8::SetFatalErrorHandler(OOMCallback);
3905  LocalContext context;
3906  Local<Script> script =
3907      Script::Compile(String::New(js_code_causing_huge_string_flattening));
3908  last_location = NULL;
3909  Local<Value> result = script->Run();
3910
3911  CHECK(false);  // Should not return.
3912}
3913
3914
3915static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
3916                                             v8::Handle<Value> data) {
3917  CHECK_EQ(v8::Undefined(), data);
3918  CHECK(message->GetScriptResourceName()->IsUndefined());
3919  CHECK_EQ(v8::Undefined(), message->GetScriptResourceName());
3920  message->GetLineNumber();
3921  message->GetSourceLine();
3922}
3923
3924
3925THREADED_TEST(ErrorWithMissingScriptInfo) {
3926  v8::HandleScope scope;
3927  LocalContext context;
3928  v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
3929  Script::Compile(v8_str("throw Error()"))->Run();
3930  v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
3931}
3932
3933
3934int global_index = 0;
3935
3936class Snorkel {
3937 public:
3938  Snorkel() { index_ = global_index++; }
3939  int index_;
3940};
3941
3942class Whammy {
3943 public:
3944  Whammy() {
3945    cursor_ = 0;
3946  }
3947  ~Whammy() {
3948    script_.Dispose();
3949  }
3950  v8::Handle<Script> getScript() {
3951    if (script_.IsEmpty())
3952      script_ = v8::Persistent<Script>::New(v8_compile("({}).blammo"));
3953    return Local<Script>(*script_);
3954  }
3955
3956 public:
3957  static const int kObjectCount = 256;
3958  int cursor_;
3959  v8::Persistent<v8::Object> objects_[kObjectCount];
3960  v8::Persistent<Script> script_;
3961};
3962
3963static void HandleWeakReference(v8::Persistent<v8::Value> obj, void* data) {
3964  Snorkel* snorkel = reinterpret_cast<Snorkel*>(data);
3965  delete snorkel;
3966  obj.ClearWeak();
3967}
3968
3969v8::Handle<Value> WhammyPropertyGetter(Local<String> name,
3970                                       const AccessorInfo& info) {
3971  Whammy* whammy =
3972    static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
3973
3974  v8::Persistent<v8::Object> prev = whammy->objects_[whammy->cursor_];
3975
3976  v8::Handle<v8::Object> obj = v8::Object::New();
3977  v8::Persistent<v8::Object> global = v8::Persistent<v8::Object>::New(obj);
3978  if (!prev.IsEmpty()) {
3979    prev->Set(v8_str("next"), obj);
3980    prev.MakeWeak(new Snorkel(), &HandleWeakReference);
3981    whammy->objects_[whammy->cursor_].Clear();
3982  }
3983  whammy->objects_[whammy->cursor_] = global;
3984  whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount;
3985  return whammy->getScript()->Run();
3986}
3987
3988THREADED_TEST(WeakReference) {
3989  v8::HandleScope handle_scope;
3990  v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New();
3991  Whammy* whammy = new Whammy();
3992  templ->SetNamedPropertyHandler(WhammyPropertyGetter,
3993                                 0, 0, 0, 0,
3994                                 v8::External::New(whammy));
3995  const char* extension_list[] = { "v8/gc" };
3996  v8::ExtensionConfiguration extensions(1, extension_list);
3997  v8::Persistent<Context> context = Context::New(&extensions);
3998  Context::Scope context_scope(context);
3999
4000  v8::Handle<v8::Object> interceptor = templ->NewInstance();
4001  context->Global()->Set(v8_str("whammy"), interceptor);
4002  const char* code =
4003      "var last;"
4004      "for (var i = 0; i < 10000; i++) {"
4005      "  var obj = whammy.length;"
4006      "  if (last) last.next = obj;"
4007      "  last = obj;"
4008      "}"
4009      "gc();"
4010      "4";
4011  v8::Handle<Value> result = CompileRun(code);
4012  CHECK_EQ(4.0, result->NumberValue());
4013  delete whammy;
4014  context.Dispose();
4015}
4016
4017
4018static bool in_scavenge = false;
4019static int last = -1;
4020
4021static void ForceScavenge(v8::Persistent<v8::Value> obj, void* data) {
4022  CHECK_EQ(-1, last);
4023  last = 0;
4024  obj.Dispose();
4025  obj.Clear();
4026  in_scavenge = true;
4027  i::Heap::PerformScavenge();
4028  in_scavenge = false;
4029  *(reinterpret_cast<bool*>(data)) = true;
4030}
4031
4032static void CheckIsNotInvokedInScavenge(v8::Persistent<v8::Value> obj,
4033                                        void* data) {
4034  CHECK_EQ(0, last);
4035  last = 1;
4036  *(reinterpret_cast<bool*>(data)) = in_scavenge;
4037  obj.Dispose();
4038  obj.Clear();
4039}
4040
4041THREADED_TEST(NoWeakRefCallbacksInScavenge) {
4042  // Test verifies that scavenge cannot invoke WeakReferenceCallbacks.
4043  // Calling callbacks from scavenges is unsafe as objects held by those
4044  // handlers might have become strongly reachable, but scavenge doesn't
4045  // check that.
4046  v8::Persistent<Context> context = Context::New();
4047  Context::Scope context_scope(context);
4048
4049  v8::Persistent<v8::Object> object_a;
4050  v8::Persistent<v8::Object> object_b;
4051
4052  {
4053    v8::HandleScope handle_scope;
4054    object_b = v8::Persistent<v8::Object>::New(v8::Object::New());
4055    object_a = v8::Persistent<v8::Object>::New(v8::Object::New());
4056  }
4057
4058  bool object_a_disposed = false;
4059  object_a.MakeWeak(&object_a_disposed, &ForceScavenge);
4060  bool released_in_scavenge = false;
4061  object_b.MakeWeak(&released_in_scavenge, &CheckIsNotInvokedInScavenge);
4062
4063  while (!object_a_disposed) {
4064    i::Heap::CollectAllGarbage(false);
4065  }
4066  CHECK(!released_in_scavenge);
4067}
4068
4069
4070v8::Handle<Function> args_fun;
4071
4072
4073static v8::Handle<Value> ArgumentsTestCallback(const v8::Arguments& args) {
4074  ApiTestFuzzer::Fuzz();
4075  CHECK_EQ(args_fun, args.Callee());
4076  CHECK_EQ(3, args.Length());
4077  CHECK_EQ(v8::Integer::New(1), args[0]);
4078  CHECK_EQ(v8::Integer::New(2), args[1]);
4079  CHECK_EQ(v8::Integer::New(3), args[2]);
4080  CHECK_EQ(v8::Undefined(), args[3]);
4081  v8::HandleScope scope;
4082  i::Heap::CollectAllGarbage(false);
4083  return v8::Undefined();
4084}
4085
4086
4087THREADED_TEST(Arguments) {
4088  v8::HandleScope scope;
4089  v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
4090  global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback));
4091  LocalContext context(NULL, global);
4092  args_fun = context->Global()->Get(v8_str("f")).As<Function>();
4093  v8_compile("f(1, 2, 3)")->Run();
4094}
4095
4096
4097static v8::Handle<Value> NoBlockGetterX(Local<String> name,
4098                                        const AccessorInfo&) {
4099  return v8::Handle<Value>();
4100}
4101
4102
4103static v8::Handle<Value> NoBlockGetterI(uint32_t index,
4104                                        const AccessorInfo&) {
4105  return v8::Handle<Value>();
4106}
4107
4108
4109static v8::Handle<v8::Boolean> PDeleter(Local<String> name,
4110                                        const AccessorInfo&) {
4111  if (!name->Equals(v8_str("foo"))) {
4112    return v8::Handle<v8::Boolean>();  // not intercepted
4113  }
4114
4115  return v8::False();  // intercepted, and don't delete the property
4116}
4117
4118
4119static v8::Handle<v8::Boolean> IDeleter(uint32_t index, const AccessorInfo&) {
4120  if (index != 2) {
4121    return v8::Handle<v8::Boolean>();  // not intercepted
4122  }
4123
4124  return v8::False();  // intercepted, and don't delete the property
4125}
4126
4127
4128THREADED_TEST(Deleter) {
4129  v8::HandleScope scope;
4130  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4131  obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
4132  obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
4133  LocalContext context;
4134  context->Global()->Set(v8_str("k"), obj->NewInstance());
4135  CompileRun(
4136    "k.foo = 'foo';"
4137    "k.bar = 'bar';"
4138    "k[2] = 2;"
4139    "k[4] = 4;");
4140  CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
4141  CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
4142
4143  CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
4144  CHECK(v8_compile("k.bar")->Run()->IsUndefined());
4145
4146  CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
4147  CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
4148
4149  CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
4150  CHECK(v8_compile("k[4]")->Run()->IsUndefined());
4151}
4152
4153
4154static v8::Handle<Value> GetK(Local<String> name, const AccessorInfo&) {
4155  ApiTestFuzzer::Fuzz();
4156  if (name->Equals(v8_str("foo")) ||
4157      name->Equals(v8_str("bar")) ||
4158      name->Equals(v8_str("baz"))) {
4159    return v8::Undefined();
4160  }
4161  return v8::Handle<Value>();
4162}
4163
4164
4165static v8::Handle<Value> IndexedGetK(uint32_t index, const AccessorInfo&) {
4166  ApiTestFuzzer::Fuzz();
4167  if (index == 0 || index == 1) return v8::Undefined();
4168  return v8::Handle<Value>();
4169}
4170
4171
4172static v8::Handle<v8::Array> NamedEnum(const AccessorInfo&) {
4173  ApiTestFuzzer::Fuzz();
4174  v8::Handle<v8::Array> result = v8::Array::New(3);
4175  result->Set(v8::Integer::New(0), v8_str("foo"));
4176  result->Set(v8::Integer::New(1), v8_str("bar"));
4177  result->Set(v8::Integer::New(2), v8_str("baz"));
4178  return result;
4179}
4180
4181
4182static v8::Handle<v8::Array> IndexedEnum(const AccessorInfo&) {
4183  ApiTestFuzzer::Fuzz();
4184  v8::Handle<v8::Array> result = v8::Array::New(2);
4185  result->Set(v8::Integer::New(0), v8_str("0"));
4186  result->Set(v8::Integer::New(1), v8_str("1"));
4187  return result;
4188}
4189
4190
4191THREADED_TEST(Enumerators) {
4192  v8::HandleScope scope;
4193  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4194  obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
4195  obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
4196  LocalContext context;
4197  context->Global()->Set(v8_str("k"), obj->NewInstance());
4198  v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
4199    "k[10] = 0;"
4200    "k.a = 0;"
4201    "k[5] = 0;"
4202    "k.b = 0;"
4203    "k[4294967295] = 0;"
4204    "k.c = 0;"
4205    "k[4294967296] = 0;"
4206    "k.d = 0;"
4207    "k[140000] = 0;"
4208    "k.e = 0;"
4209    "k[30000000000] = 0;"
4210    "k.f = 0;"
4211    "var result = [];"
4212    "for (var prop in k) {"
4213    "  result.push(prop);"
4214    "}"
4215    "result"));
4216  // Check that we get all the property names returned including the
4217  // ones from the enumerators in the right order: indexed properties
4218  // in numerical order, indexed interceptor properties, named
4219  // properties in insertion order, named interceptor properties.
4220  // This order is not mandated by the spec, so this test is just
4221  // documenting our behavior.
4222  CHECK_EQ(17, result->Length());
4223  // Indexed properties in numerical order.
4224  CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(0)));
4225  CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(1)));
4226  CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(2)));
4227  CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(3)));
4228  // Indexed interceptor properties in the order they are returned
4229  // from the enumerator interceptor.
4230  CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(4)));
4231  CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(5)));
4232  // Named properties in insertion order.
4233  CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(6)));
4234  CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(7)));
4235  CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(8)));
4236  CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(9)));
4237  CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(10)));
4238  CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(11)));
4239  CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(12)));
4240  CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(13)));
4241  // Named interceptor properties.
4242  CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(14)));
4243  CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(15)));
4244  CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(16)));
4245}
4246
4247
4248int p_getter_count;
4249int p_getter_count2;
4250
4251
4252static v8::Handle<Value> PGetter(Local<String> name, const AccessorInfo& info) {
4253  ApiTestFuzzer::Fuzz();
4254  p_getter_count++;
4255  v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
4256  CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
4257  if (name->Equals(v8_str("p1"))) {
4258    CHECK_EQ(info.This(), global->Get(v8_str("o1")));
4259  } else if (name->Equals(v8_str("p2"))) {
4260    CHECK_EQ(info.This(), global->Get(v8_str("o2")));
4261  } else if (name->Equals(v8_str("p3"))) {
4262    CHECK_EQ(info.This(), global->Get(v8_str("o3")));
4263  } else if (name->Equals(v8_str("p4"))) {
4264    CHECK_EQ(info.This(), global->Get(v8_str("o4")));
4265  }
4266  return v8::Undefined();
4267}
4268
4269
4270static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
4271  ApiTestFuzzer::Fuzz();
4272  LocalContext context;
4273  context->Global()->Set(v8_str("o1"), obj->NewInstance());
4274  CompileRun(
4275    "o1.__proto__ = { };"
4276    "var o2 = { __proto__: o1 };"
4277    "var o3 = { __proto__: o2 };"
4278    "var o4 = { __proto__: o3 };"
4279    "for (var i = 0; i < 10; i++) o4.p4;"
4280    "for (var i = 0; i < 10; i++) o3.p3;"
4281    "for (var i = 0; i < 10; i++) o2.p2;"
4282    "for (var i = 0; i < 10; i++) o1.p1;");
4283}
4284
4285
4286static v8::Handle<Value> PGetter2(Local<String> name,
4287                                  const AccessorInfo& info) {
4288  ApiTestFuzzer::Fuzz();
4289  p_getter_count2++;
4290  v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
4291  CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
4292  if (name->Equals(v8_str("p1"))) {
4293    CHECK_EQ(info.This(), global->Get(v8_str("o1")));
4294  } else if (name->Equals(v8_str("p2"))) {
4295    CHECK_EQ(info.This(), global->Get(v8_str("o2")));
4296  } else if (name->Equals(v8_str("p3"))) {
4297    CHECK_EQ(info.This(), global->Get(v8_str("o3")));
4298  } else if (name->Equals(v8_str("p4"))) {
4299    CHECK_EQ(info.This(), global->Get(v8_str("o4")));
4300  }
4301  return v8::Undefined();
4302}
4303
4304
4305THREADED_TEST(GetterHolders) {
4306  v8::HandleScope scope;
4307  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4308  obj->SetAccessor(v8_str("p1"), PGetter);
4309  obj->SetAccessor(v8_str("p2"), PGetter);
4310  obj->SetAccessor(v8_str("p3"), PGetter);
4311  obj->SetAccessor(v8_str("p4"), PGetter);
4312  p_getter_count = 0;
4313  RunHolderTest(obj);
4314  CHECK_EQ(40, p_getter_count);
4315}
4316
4317
4318THREADED_TEST(PreInterceptorHolders) {
4319  v8::HandleScope scope;
4320  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4321  obj->SetNamedPropertyHandler(PGetter2);
4322  p_getter_count2 = 0;
4323  RunHolderTest(obj);
4324  CHECK_EQ(40, p_getter_count2);
4325}
4326
4327
4328THREADED_TEST(ObjectInstantiation) {
4329  v8::HandleScope scope;
4330  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
4331  templ->SetAccessor(v8_str("t"), PGetter2);
4332  LocalContext context;
4333  context->Global()->Set(v8_str("o"), templ->NewInstance());
4334  for (int i = 0; i < 100; i++) {
4335    v8::HandleScope inner_scope;
4336    v8::Handle<v8::Object> obj = templ->NewInstance();
4337    CHECK_NE(obj, context->Global()->Get(v8_str("o")));
4338    context->Global()->Set(v8_str("o2"), obj);
4339    v8::Handle<Value> value =
4340        Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run();
4341    CHECK_EQ(v8::True(), value);
4342    context->Global()->Set(v8_str("o"), obj);
4343  }
4344}
4345
4346
4347THREADED_TEST(StringWrite) {
4348  v8::HandleScope scope;
4349  v8::Handle<String> str = v8_str("abcde");
4350
4351  char buf[100];
4352  int len;
4353
4354  memset(buf, 0x1, sizeof(buf));
4355  len = str->WriteAscii(buf);
4356  CHECK_EQ(len, 5);
4357  CHECK_EQ(strncmp("abcde\0", buf, 6), 0);
4358
4359  memset(buf, 0x1, sizeof(buf));
4360  len = str->WriteAscii(buf, 0, 4);
4361  CHECK_EQ(len, 4);
4362  CHECK_EQ(strncmp("abcd\1", buf, 5), 0);
4363
4364  memset(buf, 0x1, sizeof(buf));
4365  len = str->WriteAscii(buf, 0, 5);
4366  CHECK_EQ(len, 5);
4367  CHECK_EQ(strncmp("abcde\1", buf, 6), 0);
4368
4369  memset(buf, 0x1, sizeof(buf));
4370  len = str->WriteAscii(buf, 0, 6);
4371  CHECK_EQ(len, 5);
4372  CHECK_EQ(strncmp("abcde\0", buf, 6), 0);
4373
4374  memset(buf, 0x1, sizeof(buf));
4375  len = str->WriteAscii(buf, 4, -1);
4376  CHECK_EQ(len, 1);
4377  CHECK_EQ(strncmp("e\0", buf, 2), 0);
4378
4379  memset(buf, 0x1, sizeof(buf));
4380  len = str->WriteAscii(buf, 4, 6);
4381  CHECK_EQ(len, 1);
4382  CHECK_EQ(strncmp("e\0", buf, 2), 0);
4383
4384  memset(buf, 0x1, sizeof(buf));
4385  len = str->WriteAscii(buf, 4, 1);
4386  CHECK_EQ(len, 1);
4387  CHECK_EQ(strncmp("e\1", buf, 2), 0);
4388}
4389
4390
4391THREADED_TEST(ToArrayIndex) {
4392  v8::HandleScope scope;
4393  LocalContext context;
4394
4395  v8::Handle<String> str = v8_str("42");
4396  v8::Handle<v8::Uint32> index = str->ToArrayIndex();
4397  CHECK(!index.IsEmpty());
4398  CHECK_EQ(42.0, index->Uint32Value());
4399  str = v8_str("42asdf");
4400  index = str->ToArrayIndex();
4401  CHECK(index.IsEmpty());
4402  str = v8_str("-42");
4403  index = str->ToArrayIndex();
4404  CHECK(index.IsEmpty());
4405  str = v8_str("4294967295");
4406  index = str->ToArrayIndex();
4407  CHECK(!index.IsEmpty());
4408  CHECK_EQ(4294967295.0, index->Uint32Value());
4409  v8::Handle<v8::Number> num = v8::Number::New(1);
4410  index = num->ToArrayIndex();
4411  CHECK(!index.IsEmpty());
4412  CHECK_EQ(1.0, index->Uint32Value());
4413  num = v8::Number::New(-1);
4414  index = num->ToArrayIndex();
4415  CHECK(index.IsEmpty());
4416  v8::Handle<v8::Object> obj = v8::Object::New();
4417  index = obj->ToArrayIndex();
4418  CHECK(index.IsEmpty());
4419}
4420
4421
4422THREADED_TEST(ErrorConstruction) {
4423  v8::HandleScope scope;
4424  LocalContext context;
4425
4426  v8::Handle<String> foo = v8_str("foo");
4427  v8::Handle<String> message = v8_str("message");
4428  v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
4429  CHECK(range_error->IsObject());
4430  v8::Handle<v8::Object> range_obj = range_error.As<v8::Object>();
4431  CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
4432  v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
4433  CHECK(reference_error->IsObject());
4434  CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
4435  v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
4436  CHECK(syntax_error->IsObject());
4437  CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
4438  v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
4439  CHECK(type_error->IsObject());
4440  CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
4441  v8::Handle<Value> error = v8::Exception::Error(foo);
4442  CHECK(error->IsObject());
4443  CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
4444}
4445
4446
4447static v8::Handle<Value> YGetter(Local<String> name, const AccessorInfo& info) {
4448  ApiTestFuzzer::Fuzz();
4449  return v8_num(10);
4450}
4451
4452
4453static void YSetter(Local<String> name,
4454                    Local<Value> value,
4455                    const AccessorInfo& info) {
4456  if (info.This()->Has(name)) {
4457    info.This()->Delete(name);
4458  }
4459  info.This()->Set(name, value);
4460}
4461
4462
4463THREADED_TEST(DeleteAccessor) {
4464  v8::HandleScope scope;
4465  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4466  obj->SetAccessor(v8_str("y"), YGetter, YSetter);
4467  LocalContext context;
4468  v8::Handle<v8::Object> holder = obj->NewInstance();
4469  context->Global()->Set(v8_str("holder"), holder);
4470  v8::Handle<Value> result = CompileRun(
4471      "holder.y = 11; holder.y = 12; holder.y");
4472  CHECK_EQ(12, result->Uint32Value());
4473}
4474
4475
4476THREADED_TEST(TypeSwitch) {
4477  v8::HandleScope scope;
4478  v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New();
4479  v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New();
4480  v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New();
4481  v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
4482  v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
4483  LocalContext context;
4484  v8::Handle<v8::Object> obj0 = v8::Object::New();
4485  v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
4486  v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
4487  v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
4488  for (int i = 0; i < 10; i++) {
4489    CHECK_EQ(0, type_switch->match(obj0));
4490    CHECK_EQ(1, type_switch->match(obj1));
4491    CHECK_EQ(2, type_switch->match(obj2));
4492    CHECK_EQ(3, type_switch->match(obj3));
4493    CHECK_EQ(3, type_switch->match(obj3));
4494    CHECK_EQ(2, type_switch->match(obj2));
4495    CHECK_EQ(1, type_switch->match(obj1));
4496    CHECK_EQ(0, type_switch->match(obj0));
4497  }
4498}
4499
4500
4501// For use within the TestSecurityHandler() test.
4502static bool g_security_callback_result = false;
4503static bool NamedSecurityTestCallback(Local<v8::Object> global,
4504                                      Local<Value> name,
4505                                      v8::AccessType type,
4506                                      Local<Value> data) {
4507  // Always allow read access.
4508  if (type == v8::ACCESS_GET)
4509    return true;
4510
4511  // Sometimes allow other access.
4512  return g_security_callback_result;
4513}
4514
4515
4516static bool IndexedSecurityTestCallback(Local<v8::Object> global,
4517                                        uint32_t key,
4518                                        v8::AccessType type,
4519                                        Local<Value> data) {
4520  // Always allow read access.
4521  if (type == v8::ACCESS_GET)
4522    return true;
4523
4524  // Sometimes allow other access.
4525  return g_security_callback_result;
4526}
4527
4528
4529static int trouble_nesting = 0;
4530static v8::Handle<Value> TroubleCallback(const v8::Arguments& args) {
4531  ApiTestFuzzer::Fuzz();
4532  trouble_nesting++;
4533
4534  // Call a JS function that throws an uncaught exception.
4535  Local<v8::Object> arg_this = Context::GetCurrent()->Global();
4536  Local<Value> trouble_callee = (trouble_nesting == 3) ?
4537    arg_this->Get(v8_str("trouble_callee")) :
4538    arg_this->Get(v8_str("trouble_caller"));
4539  CHECK(trouble_callee->IsFunction());
4540  return Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL);
4541}
4542
4543
4544static int report_count = 0;
4545static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
4546                                             v8::Handle<Value>) {
4547  report_count++;
4548}
4549
4550
4551// Counts uncaught exceptions, but other tests running in parallel
4552// also have uncaught exceptions.
4553TEST(ApiUncaughtException) {
4554  report_count = 0;
4555  v8::HandleScope scope;
4556  LocalContext env;
4557  v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
4558
4559  Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
4560  v8::Local<v8::Object> global = env->Global();
4561  global->Set(v8_str("trouble"), fun->GetFunction());
4562
4563  Script::Compile(v8_str("function trouble_callee() {"
4564                         "  var x = null;"
4565                         "  return x.foo;"
4566                         "};"
4567                         "function trouble_caller() {"
4568                         "  trouble();"
4569                         "};"))->Run();
4570  Local<Value> trouble = global->Get(v8_str("trouble"));
4571  CHECK(trouble->IsFunction());
4572  Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
4573  CHECK(trouble_callee->IsFunction());
4574  Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
4575  CHECK(trouble_caller->IsFunction());
4576  Function::Cast(*trouble_caller)->Call(global, 0, NULL);
4577  CHECK_EQ(1, report_count);
4578  v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
4579}
4580
4581static const char* script_resource_name = "ExceptionInNativeScript.js";
4582static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
4583                                                v8::Handle<Value>) {
4584  v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
4585  CHECK(!name_val.IsEmpty() && name_val->IsString());
4586  v8::String::AsciiValue name(message->GetScriptResourceName());
4587  CHECK_EQ(script_resource_name, *name);
4588  CHECK_EQ(3, message->GetLineNumber());
4589  v8::String::AsciiValue source_line(message->GetSourceLine());
4590  CHECK_EQ("  new o.foo();", *source_line);
4591}
4592
4593TEST(ExceptionInNativeScript) {
4594  v8::HandleScope scope;
4595  LocalContext env;
4596  v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
4597
4598  Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
4599  v8::Local<v8::Object> global = env->Global();
4600  global->Set(v8_str("trouble"), fun->GetFunction());
4601
4602  Script::Compile(v8_str("function trouble() {\n"
4603                         "  var o = {};\n"
4604                         "  new o.foo();\n"
4605                         "};"), v8::String::New(script_resource_name))->Run();
4606  Local<Value> trouble = global->Get(v8_str("trouble"));
4607  CHECK(trouble->IsFunction());
4608  Function::Cast(*trouble)->Call(global, 0, NULL);
4609  v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
4610}
4611
4612
4613TEST(CompilationErrorUsingTryCatchHandler) {
4614  v8::HandleScope scope;
4615  LocalContext env;
4616  v8::TryCatch try_catch;
4617  Script::Compile(v8_str("This doesn't &*&@#$&*^ compile."));
4618  CHECK_NE(NULL, *try_catch.Exception());
4619  CHECK(try_catch.HasCaught());
4620}
4621
4622
4623TEST(TryCatchFinallyUsingTryCatchHandler) {
4624  v8::HandleScope scope;
4625  LocalContext env;
4626  v8::TryCatch try_catch;
4627  Script::Compile(v8_str("try { throw ''; } catch (e) {}"))->Run();
4628  CHECK(!try_catch.HasCaught());
4629  Script::Compile(v8_str("try { throw ''; } finally {}"))->Run();
4630  CHECK(try_catch.HasCaught());
4631  try_catch.Reset();
4632  Script::Compile(v8_str("(function() {"
4633                         "try { throw ''; } finally { return; }"
4634                         "})()"))->Run();
4635  CHECK(!try_catch.HasCaught());
4636  Script::Compile(v8_str("(function()"
4637                         "  { try { throw ''; } finally { throw 0; }"
4638                         "})()"))->Run();
4639  CHECK(try_catch.HasCaught());
4640}
4641
4642
4643// SecurityHandler can't be run twice
4644TEST(SecurityHandler) {
4645  v8::HandleScope scope0;
4646  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
4647  global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
4648                                           IndexedSecurityTestCallback);
4649  // Create an environment
4650  v8::Persistent<Context> context0 =
4651    Context::New(NULL, global_template);
4652  context0->Enter();
4653
4654  v8::Handle<v8::Object> global0 = context0->Global();
4655  v8::Handle<Script> script0 = v8_compile("foo = 111");
4656  script0->Run();
4657  global0->Set(v8_str("0"), v8_num(999));
4658  v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
4659  CHECK_EQ(111, foo0->Int32Value());
4660  v8::Handle<Value> z0 = global0->Get(v8_str("0"));
4661  CHECK_EQ(999, z0->Int32Value());
4662
4663  // Create another environment, should fail security checks.
4664  v8::HandleScope scope1;
4665
4666  v8::Persistent<Context> context1 =
4667    Context::New(NULL, global_template);
4668  context1->Enter();
4669
4670  v8::Handle<v8::Object> global1 = context1->Global();
4671  global1->Set(v8_str("othercontext"), global0);
4672  // This set will fail the security check.
4673  v8::Handle<Script> script1 =
4674    v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
4675  script1->Run();
4676  // This read will pass the security check.
4677  v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
4678  CHECK_EQ(111, foo1->Int32Value());
4679  // This read will pass the security check.
4680  v8::Handle<Value> z1 = global0->Get(v8_str("0"));
4681  CHECK_EQ(999, z1->Int32Value());
4682
4683  // Create another environment, should pass security checks.
4684  { g_security_callback_result = true;  // allow security handler to pass.
4685    v8::HandleScope scope2;
4686    LocalContext context2;
4687    v8::Handle<v8::Object> global2 = context2->Global();
4688    global2->Set(v8_str("othercontext"), global0);
4689    v8::Handle<Script> script2 =
4690        v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
4691    script2->Run();
4692    v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
4693    CHECK_EQ(333, foo2->Int32Value());
4694    v8::Handle<Value> z2 = global0->Get(v8_str("0"));
4695    CHECK_EQ(888, z2->Int32Value());
4696  }
4697
4698  context1->Exit();
4699  context1.Dispose();
4700
4701  context0->Exit();
4702  context0.Dispose();
4703}
4704
4705
4706THREADED_TEST(SecurityChecks) {
4707  v8::HandleScope handle_scope;
4708  LocalContext env1;
4709  v8::Persistent<Context> env2 = Context::New();
4710
4711  Local<Value> foo = v8_str("foo");
4712  Local<Value> bar = v8_str("bar");
4713
4714  // Set to the same domain.
4715  env1->SetSecurityToken(foo);
4716
4717  // Create a function in env1.
4718  Script::Compile(v8_str("spy=function(){return spy;}"))->Run();
4719  Local<Value> spy = env1->Global()->Get(v8_str("spy"));
4720  CHECK(spy->IsFunction());
4721
4722  // Create another function accessing global objects.
4723  Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run();
4724  Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
4725  CHECK(spy2->IsFunction());
4726
4727  // Switch to env2 in the same domain and invoke spy on env2.
4728  {
4729    env2->SetSecurityToken(foo);
4730    // Enter env2
4731    Context::Scope scope_env2(env2);
4732    Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
4733    CHECK(result->IsFunction());
4734  }
4735
4736  {
4737    env2->SetSecurityToken(bar);
4738    Context::Scope scope_env2(env2);
4739
4740    // Call cross_domain_call, it should throw an exception
4741    v8::TryCatch try_catch;
4742    Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
4743    CHECK(try_catch.HasCaught());
4744  }
4745
4746  env2.Dispose();
4747}
4748
4749
4750// Regression test case for issue 1183439.
4751THREADED_TEST(SecurityChecksForPrototypeChain) {
4752  v8::HandleScope scope;
4753  LocalContext current;
4754  v8::Persistent<Context> other = Context::New();
4755
4756  // Change context to be able to get to the Object function in the
4757  // other context without hitting the security checks.
4758  v8::Local<Value> other_object;
4759  { Context::Scope scope(other);
4760    other_object = other->Global()->Get(v8_str("Object"));
4761    other->Global()->Set(v8_num(42), v8_num(87));
4762  }
4763
4764  current->Global()->Set(v8_str("other"), other->Global());
4765  CHECK(v8_compile("other")->Run()->Equals(other->Global()));
4766
4767  // Make sure the security check fails here and we get an undefined
4768  // result instead of getting the Object function. Repeat in a loop
4769  // to make sure to exercise the IC code.
4770  v8::Local<Script> access_other0 = v8_compile("other.Object");
4771  v8::Local<Script> access_other1 = v8_compile("other[42]");
4772  for (int i = 0; i < 5; i++) {
4773    CHECK(!access_other0->Run()->Equals(other_object));
4774    CHECK(access_other0->Run()->IsUndefined());
4775    CHECK(!access_other1->Run()->Equals(v8_num(87)));
4776    CHECK(access_other1->Run()->IsUndefined());
4777  }
4778
4779  // Create an object that has 'other' in its prototype chain and make
4780  // sure we cannot access the Object function indirectly through
4781  // that. Repeat in a loop to make sure to exercise the IC code.
4782  v8_compile("function F() { };"
4783             "F.prototype = other;"
4784             "var f = new F();")->Run();
4785  v8::Local<Script> access_f0 = v8_compile("f.Object");
4786  v8::Local<Script> access_f1 = v8_compile("f[42]");
4787  for (int j = 0; j < 5; j++) {
4788    CHECK(!access_f0->Run()->Equals(other_object));
4789    CHECK(access_f0->Run()->IsUndefined());
4790    CHECK(!access_f1->Run()->Equals(v8_num(87)));
4791    CHECK(access_f1->Run()->IsUndefined());
4792  }
4793
4794  // Now it gets hairy: Set the prototype for the other global object
4795  // to be the current global object. The prototype chain for 'f' now
4796  // goes through 'other' but ends up in the current global object.
4797  { Context::Scope scope(other);
4798    other->Global()->Set(v8_str("__proto__"), current->Global());
4799  }
4800  // Set a named and an index property on the current global
4801  // object. To force the lookup to go through the other global object,
4802  // the properties must not exist in the other global object.
4803  current->Global()->Set(v8_str("foo"), v8_num(100));
4804  current->Global()->Set(v8_num(99), v8_num(101));
4805  // Try to read the properties from f and make sure that the access
4806  // gets stopped by the security checks on the other global object.
4807  Local<Script> access_f2 = v8_compile("f.foo");
4808  Local<Script> access_f3 = v8_compile("f[99]");
4809  for (int k = 0; k < 5; k++) {
4810    CHECK(!access_f2->Run()->Equals(v8_num(100)));
4811    CHECK(access_f2->Run()->IsUndefined());
4812    CHECK(!access_f3->Run()->Equals(v8_num(101)));
4813    CHECK(access_f3->Run()->IsUndefined());
4814  }
4815  other.Dispose();
4816}
4817
4818
4819THREADED_TEST(CrossDomainDelete) {
4820  v8::HandleScope handle_scope;
4821  LocalContext env1;
4822  v8::Persistent<Context> env2 = Context::New();
4823
4824  Local<Value> foo = v8_str("foo");
4825  Local<Value> bar = v8_str("bar");
4826
4827  // Set to the same domain.
4828  env1->SetSecurityToken(foo);
4829  env2->SetSecurityToken(foo);
4830
4831  env1->Global()->Set(v8_str("prop"), v8_num(3));
4832  env2->Global()->Set(v8_str("env1"), env1->Global());
4833
4834  // Change env2 to a different domain and delete env1.prop.
4835  env2->SetSecurityToken(bar);
4836  {
4837    Context::Scope scope_env2(env2);
4838    Local<Value> result =
4839        Script::Compile(v8_str("delete env1.prop"))->Run();
4840    CHECK(result->IsFalse());
4841  }
4842
4843  // Check that env1.prop still exists.
4844  Local<Value> v = env1->Global()->Get(v8_str("prop"));
4845  CHECK(v->IsNumber());
4846  CHECK_EQ(3, v->Int32Value());
4847
4848  env2.Dispose();
4849}
4850
4851
4852THREADED_TEST(CrossDomainIsPropertyEnumerable) {
4853  v8::HandleScope handle_scope;
4854  LocalContext env1;
4855  v8::Persistent<Context> env2 = Context::New();
4856
4857  Local<Value> foo = v8_str("foo");
4858  Local<Value> bar = v8_str("bar");
4859
4860  // Set to the same domain.
4861  env1->SetSecurityToken(foo);
4862  env2->SetSecurityToken(foo);
4863
4864  env1->Global()->Set(v8_str("prop"), v8_num(3));
4865  env2->Global()->Set(v8_str("env1"), env1->Global());
4866
4867  // env1.prop is enumerable in env2.
4868  Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
4869  {
4870    Context::Scope scope_env2(env2);
4871    Local<Value> result = Script::Compile(test)->Run();
4872    CHECK(result->IsTrue());
4873  }
4874
4875  // Change env2 to a different domain and test again.
4876  env2->SetSecurityToken(bar);
4877  {
4878    Context::Scope scope_env2(env2);
4879    Local<Value> result = Script::Compile(test)->Run();
4880    CHECK(result->IsFalse());
4881  }
4882
4883  env2.Dispose();
4884}
4885
4886
4887THREADED_TEST(CrossDomainForIn) {
4888  v8::HandleScope handle_scope;
4889  LocalContext env1;
4890  v8::Persistent<Context> env2 = Context::New();
4891
4892  Local<Value> foo = v8_str("foo");
4893  Local<Value> bar = v8_str("bar");
4894
4895  // Set to the same domain.
4896  env1->SetSecurityToken(foo);
4897  env2->SetSecurityToken(foo);
4898
4899  env1->Global()->Set(v8_str("prop"), v8_num(3));
4900  env2->Global()->Set(v8_str("env1"), env1->Global());
4901
4902  // Change env2 to a different domain and set env1's global object
4903  // as the __proto__ of an object in env2 and enumerate properties
4904  // in for-in. It shouldn't enumerate properties on env1's global
4905  // object.
4906  env2->SetSecurityToken(bar);
4907  {
4908    Context::Scope scope_env2(env2);
4909    Local<Value> result =
4910        CompileRun("(function(){var obj = {'__proto__':env1};"
4911                   "for (var p in obj)"
4912                   "   if (p == 'prop') return false;"
4913                   "return true;})()");
4914    CHECK(result->IsTrue());
4915  }
4916  env2.Dispose();
4917}
4918
4919
4920TEST(ContextDetachGlobal) {
4921  v8::HandleScope handle_scope;
4922  LocalContext env1;
4923  v8::Persistent<Context> env2 = Context::New();
4924
4925  Local<v8::Object> global1 = env1->Global();
4926
4927  Local<Value> foo = v8_str("foo");
4928
4929  // Set to the same domain.
4930  env1->SetSecurityToken(foo);
4931  env2->SetSecurityToken(foo);
4932
4933  // Enter env2
4934  env2->Enter();
4935
4936  // Create a function in env2 and add a reference to it in env1.
4937  Local<v8::Object> global2 = env2->Global();
4938  global2->Set(v8_str("prop"), v8::Integer::New(1));
4939  CompileRun("function getProp() {return prop;}");
4940
4941  env1->Global()->Set(v8_str("getProp"),
4942                      global2->Get(v8_str("getProp")));
4943
4944  // Detach env2's global, and reuse the global object of env2
4945  env2->Exit();
4946  env2->DetachGlobal();
4947  // env2 has a new global object.
4948  CHECK(!env2->Global()->Equals(global2));
4949
4950  v8::Persistent<Context> env3 =
4951      Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
4952  env3->SetSecurityToken(v8_str("bar"));
4953  env3->Enter();
4954
4955  Local<v8::Object> global3 = env3->Global();
4956  CHECK_EQ(global2, global3);
4957  CHECK(global3->Get(v8_str("prop"))->IsUndefined());
4958  CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
4959  global3->Set(v8_str("prop"), v8::Integer::New(-1));
4960  global3->Set(v8_str("prop2"), v8::Integer::New(2));
4961  env3->Exit();
4962
4963  // Call getProp in env1, and it should return the value 1
4964  {
4965    Local<Value> get_prop = global1->Get(v8_str("getProp"));
4966    CHECK(get_prop->IsFunction());
4967    v8::TryCatch try_catch;
4968    Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
4969    CHECK(!try_catch.HasCaught());
4970    CHECK_EQ(1, r->Int32Value());
4971  }
4972
4973  // Check that env3 is not accessible from env1
4974  {
4975    Local<Value> r = global3->Get(v8_str("prop2"));
4976    CHECK(r->IsUndefined());
4977  }
4978
4979  env2.Dispose();
4980  env3.Dispose();
4981}
4982
4983
4984TEST(DetachAndReattachGlobal) {
4985  v8::HandleScope scope;
4986  LocalContext env1;
4987
4988  // Create second environment.
4989  v8::Persistent<Context> env2 = Context::New();
4990
4991  Local<Value> foo = v8_str("foo");
4992
4993  // Set same security token for env1 and env2.
4994  env1->SetSecurityToken(foo);
4995  env2->SetSecurityToken(foo);
4996
4997  // Create a property on the global object in env2.
4998  {
4999    v8::Context::Scope scope(env2);
5000    env2->Global()->Set(v8_str("p"), v8::Integer::New(42));
5001  }
5002
5003  // Create a reference to env2 global from env1 global.
5004  env1->Global()->Set(v8_str("other"), env2->Global());
5005
5006  // Check that we have access to other.p in env2 from env1.
5007  Local<Value> result = CompileRun("other.p");
5008  CHECK(result->IsInt32());
5009  CHECK_EQ(42, result->Int32Value());
5010
5011  // Hold on to global from env2 and detach global from env2.
5012  Local<v8::Object> global2 = env2->Global();
5013  env2->DetachGlobal();
5014
5015  // Check that the global has been detached. No other.p property can
5016  // be found.
5017  result = CompileRun("other.p");
5018  CHECK(result->IsUndefined());
5019
5020  // Reuse global2 for env3.
5021  v8::Persistent<Context> env3 =
5022      Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
5023  CHECK_EQ(global2, env3->Global());
5024
5025  // Start by using the same security token for env3 as for env1 and env2.
5026  env3->SetSecurityToken(foo);
5027
5028  // Create a property on the global object in env3.
5029  {
5030    v8::Context::Scope scope(env3);
5031    env3->Global()->Set(v8_str("p"), v8::Integer::New(24));
5032  }
5033
5034  // Check that other.p is now the property in env3 and that we have access.
5035  result = CompileRun("other.p");
5036  CHECK(result->IsInt32());
5037  CHECK_EQ(24, result->Int32Value());
5038
5039  // Change security token for env3 to something different from env1 and env2.
5040  env3->SetSecurityToken(v8_str("bar"));
5041
5042  // Check that we do not have access to other.p in env1. |other| is now
5043  // the global object for env3 which has a different security token,
5044  // so access should be blocked.
5045  result = CompileRun("other.p");
5046  CHECK(result->IsUndefined());
5047
5048  // Detach the global for env3 and reattach it to env2.
5049  env3->DetachGlobal();
5050  env2->ReattachGlobal(global2);
5051
5052  // Check that we have access to other.p again in env1.  |other| is now
5053  // the global object for env2 which has the same security token as env1.
5054  result = CompileRun("other.p");
5055  CHECK(result->IsInt32());
5056  CHECK_EQ(42, result->Int32Value());
5057
5058  env2.Dispose();
5059  env3.Dispose();
5060}
5061
5062
5063static bool NamedAccessBlocker(Local<v8::Object> global,
5064                               Local<Value> name,
5065                               v8::AccessType type,
5066                               Local<Value> data) {
5067  return Context::GetCurrent()->Global()->Equals(global);
5068}
5069
5070
5071static bool IndexedAccessBlocker(Local<v8::Object> global,
5072                                 uint32_t key,
5073                                 v8::AccessType type,
5074                                 Local<Value> data) {
5075  return Context::GetCurrent()->Global()->Equals(global);
5076}
5077
5078
5079static int g_echo_value = -1;
5080static v8::Handle<Value> EchoGetter(Local<String> name,
5081                                    const AccessorInfo& info) {
5082  return v8_num(g_echo_value);
5083}
5084
5085
5086static void EchoSetter(Local<String> name,
5087                       Local<Value> value,
5088                       const AccessorInfo&) {
5089  if (value->IsNumber())
5090    g_echo_value = value->Int32Value();
5091}
5092
5093
5094static v8::Handle<Value> UnreachableGetter(Local<String> name,
5095                                           const AccessorInfo& info) {
5096  CHECK(false);  // This function should not be called..
5097  return v8::Undefined();
5098}
5099
5100
5101static void UnreachableSetter(Local<String>, Local<Value>,
5102                              const AccessorInfo&) {
5103  CHECK(false);  // This function should nto be called.
5104}
5105
5106
5107THREADED_TEST(AccessControl) {
5108  v8::HandleScope handle_scope;
5109  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
5110
5111  global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
5112                                           IndexedAccessBlocker);
5113
5114  // Add an accessor accessible by cross-domain JS code.
5115  global_template->SetAccessor(
5116      v8_str("accessible_prop"),
5117      EchoGetter, EchoSetter,
5118      v8::Handle<Value>(),
5119      v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
5120
5121  // Add an accessor that is not accessible by cross-domain JS code.
5122  global_template->SetAccessor(v8_str("blocked_prop"),
5123                               UnreachableGetter, UnreachableSetter,
5124                               v8::Handle<Value>(),
5125                               v8::DEFAULT);
5126
5127  // Create an environment
5128  v8::Persistent<Context> context0 = Context::New(NULL, global_template);
5129  context0->Enter();
5130
5131  v8::Handle<v8::Object> global0 = context0->Global();
5132
5133  v8::HandleScope scope1;
5134
5135  v8::Persistent<Context> context1 = Context::New();
5136  context1->Enter();
5137
5138  v8::Handle<v8::Object> global1 = context1->Global();
5139  global1->Set(v8_str("other"), global0);
5140
5141  v8::Handle<Value> value;
5142
5143  // Access blocked property
5144  value = v8_compile("other.blocked_prop = 1")->Run();
5145  value = v8_compile("other.blocked_prop")->Run();
5146  CHECK(value->IsUndefined());
5147
5148  value = v8_compile("propertyIsEnumerable.call(other, 'blocked_prop')")->Run();
5149  CHECK(value->IsFalse());
5150
5151  // Access accessible property
5152  value = v8_compile("other.accessible_prop = 3")->Run();
5153  CHECK(value->IsNumber());
5154  CHECK_EQ(3, value->Int32Value());
5155  CHECK_EQ(3, g_echo_value);
5156
5157  value = v8_compile("other.accessible_prop")->Run();
5158  CHECK(value->IsNumber());
5159  CHECK_EQ(3, value->Int32Value());
5160
5161  value =
5162    v8_compile("propertyIsEnumerable.call(other, 'accessible_prop')")->Run();
5163  CHECK(value->IsTrue());
5164
5165  // Enumeration doesn't enumerate accessors from inaccessible objects in
5166  // the prototype chain even if the accessors are in themselves accessible.
5167  Local<Value> result =
5168      CompileRun("(function(){var obj = {'__proto__':other};"
5169                 "for (var p in obj)"
5170                 "   if (p == 'accessible_prop' || p == 'blocked_prop') {"
5171                 "     return false;"
5172                 "   }"
5173                 "return true;})()");
5174  CHECK(result->IsTrue());
5175
5176  context1->Exit();
5177  context0->Exit();
5178  context1.Dispose();
5179  context0.Dispose();
5180}
5181
5182
5183static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
5184                                            Local<Value> name,
5185                                            v8::AccessType type,
5186                                            Local<Value> data) {
5187  return false;
5188}
5189
5190
5191static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
5192                                              uint32_t key,
5193                                              v8::AccessType type,
5194                                              Local<Value> data) {
5195  return false;
5196}
5197
5198
5199THREADED_TEST(AccessControlGetOwnPropertyNames) {
5200  v8::HandleScope handle_scope;
5201  v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
5202
5203  obj_template->Set(v8_str("x"), v8::Integer::New(42));
5204  obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
5205                                        GetOwnPropertyNamesIndexedBlocker);
5206
5207  // Create an environment
5208  v8::Persistent<Context> context0 = Context::New(NULL, obj_template);
5209  context0->Enter();
5210
5211  v8::Handle<v8::Object> global0 = context0->Global();
5212
5213  v8::HandleScope scope1;
5214
5215  v8::Persistent<Context> context1 = Context::New();
5216  context1->Enter();
5217
5218  v8::Handle<v8::Object> global1 = context1->Global();
5219  global1->Set(v8_str("other"), global0);
5220  global1->Set(v8_str("object"), obj_template->NewInstance());
5221
5222  v8::Handle<Value> value;
5223
5224  // Attempt to get the property names of the other global object and
5225  // of an object that requires access checks.  Accessing the other
5226  // global object should be blocked by access checks on the global
5227  // proxy object.  Accessing the object that requires access checks
5228  // is blocked by the access checks on the object itself.
5229  value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
5230  CHECK(value->IsTrue());
5231
5232  value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
5233  CHECK(value->IsTrue());
5234
5235  context1->Exit();
5236  context0->Exit();
5237  context1.Dispose();
5238  context0.Dispose();
5239}
5240
5241
5242static v8::Handle<v8::Array> NamedPropertyEnumerator(const AccessorInfo& info) {
5243  v8::Handle<v8::Array> result = v8::Array::New(1);
5244  result->Set(0, v8_str("x"));
5245  return result;
5246}
5247
5248
5249THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
5250  v8::HandleScope handle_scope;
5251  v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
5252
5253  obj_template->Set(v8_str("x"), v8::Integer::New(42));
5254  obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
5255                                        NamedPropertyEnumerator);
5256
5257  LocalContext context;
5258  v8::Handle<v8::Object> global = context->Global();
5259  global->Set(v8_str("object"), obj_template->NewInstance());
5260
5261  v8::Handle<Value> value =
5262      CompileRun("Object.getOwnPropertyNames(object).join(',')");
5263  CHECK_EQ(v8_str("x"), value);
5264}
5265
5266
5267static v8::Handle<Value> ConstTenGetter(Local<String> name,
5268                                        const AccessorInfo& info) {
5269  return v8_num(10);
5270}
5271
5272
5273THREADED_TEST(CrossDomainAccessors) {
5274  v8::HandleScope handle_scope;
5275
5276  v8::Handle<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
5277
5278  v8::Handle<v8::ObjectTemplate> global_template =
5279      func_template->InstanceTemplate();
5280
5281  v8::Handle<v8::ObjectTemplate> proto_template =
5282      func_template->PrototypeTemplate();
5283
5284  // Add an accessor to proto that's accessible by cross-domain JS code.
5285  proto_template->SetAccessor(v8_str("accessible"),
5286                              ConstTenGetter, 0,
5287                              v8::Handle<Value>(),
5288                              v8::ALL_CAN_READ);
5289
5290  // Add an accessor that is not accessible by cross-domain JS code.
5291  global_template->SetAccessor(v8_str("unreachable"),
5292                               UnreachableGetter, 0,
5293                               v8::Handle<Value>(),
5294                               v8::DEFAULT);
5295
5296  v8::Persistent<Context> context0 = Context::New(NULL, global_template);
5297  context0->Enter();
5298
5299  Local<v8::Object> global = context0->Global();
5300  // Add a normal property that shadows 'accessible'
5301  global->Set(v8_str("accessible"), v8_num(11));
5302
5303  // Enter a new context.
5304  v8::HandleScope scope1;
5305  v8::Persistent<Context> context1 = Context::New();
5306  context1->Enter();
5307
5308  v8::Handle<v8::Object> global1 = context1->Global();
5309  global1->Set(v8_str("other"), global);
5310
5311  // Should return 10, instead of 11
5312  v8::Handle<Value> value = v8_compile("other.accessible")->Run();
5313  CHECK(value->IsNumber());
5314  CHECK_EQ(10, value->Int32Value());
5315
5316  value = v8_compile("other.unreachable")->Run();
5317  CHECK(value->IsUndefined());
5318
5319  context1->Exit();
5320  context0->Exit();
5321  context1.Dispose();
5322  context0.Dispose();
5323}
5324
5325
5326static int named_access_count = 0;
5327static int indexed_access_count = 0;
5328
5329static bool NamedAccessCounter(Local<v8::Object> global,
5330                               Local<Value> name,
5331                               v8::AccessType type,
5332                               Local<Value> data) {
5333  named_access_count++;
5334  return true;
5335}
5336
5337
5338static bool IndexedAccessCounter(Local<v8::Object> global,
5339                                 uint32_t key,
5340                                 v8::AccessType type,
5341                                 Local<Value> data) {
5342  indexed_access_count++;
5343  return true;
5344}
5345
5346
5347// This one is too easily disturbed by other tests.
5348TEST(AccessControlIC) {
5349  named_access_count = 0;
5350  indexed_access_count = 0;
5351
5352  v8::HandleScope handle_scope;
5353
5354  // Create an environment.
5355  v8::Persistent<Context> context0 = Context::New();
5356  context0->Enter();
5357
5358  // Create an object that requires access-check functions to be
5359  // called for cross-domain access.
5360  v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
5361  object_template->SetAccessCheckCallbacks(NamedAccessCounter,
5362                                           IndexedAccessCounter);
5363  Local<v8::Object> object = object_template->NewInstance();
5364
5365  v8::HandleScope scope1;
5366
5367  // Create another environment.
5368  v8::Persistent<Context> context1 = Context::New();
5369  context1->Enter();
5370
5371  // Make easy access to the object from the other environment.
5372  v8::Handle<v8::Object> global1 = context1->Global();
5373  global1->Set(v8_str("obj"), object);
5374
5375  v8::Handle<Value> value;
5376
5377  // Check that the named access-control function is called every time.
5378  CompileRun("function testProp(obj) {"
5379             "  for (var i = 0; i < 10; i++) obj.prop = 1;"
5380             "  for (var j = 0; j < 10; j++) obj.prop;"
5381             "  return obj.prop"
5382             "}");
5383  value = CompileRun("testProp(obj)");
5384  CHECK(value->IsNumber());
5385  CHECK_EQ(1, value->Int32Value());
5386  CHECK_EQ(21, named_access_count);
5387
5388  // Check that the named access-control function is called every time.
5389  CompileRun("var p = 'prop';"
5390             "function testKeyed(obj) {"
5391             "  for (var i = 0; i < 10; i++) obj[p] = 1;"
5392             "  for (var j = 0; j < 10; j++) obj[p];"
5393             "  return obj[p];"
5394             "}");
5395  // Use obj which requires access checks.  No inline caching is used
5396  // in that case.
5397  value = CompileRun("testKeyed(obj)");
5398  CHECK(value->IsNumber());
5399  CHECK_EQ(1, value->Int32Value());
5400  CHECK_EQ(42, named_access_count);
5401  // Force the inline caches into generic state and try again.
5402  CompileRun("testKeyed({ a: 0 })");
5403  CompileRun("testKeyed({ b: 0 })");
5404  value = CompileRun("testKeyed(obj)");
5405  CHECK(value->IsNumber());
5406  CHECK_EQ(1, value->Int32Value());
5407  CHECK_EQ(63, named_access_count);
5408
5409  // Check that the indexed access-control function is called every time.
5410  CompileRun("function testIndexed(obj) {"
5411             "  for (var i = 0; i < 10; i++) obj[0] = 1;"
5412             "  for (var j = 0; j < 10; j++) obj[0];"
5413             "  return obj[0]"
5414             "}");
5415  value = CompileRun("testIndexed(obj)");
5416  CHECK(value->IsNumber());
5417  CHECK_EQ(1, value->Int32Value());
5418  CHECK_EQ(21, indexed_access_count);
5419  // Force the inline caches into generic state.
5420  CompileRun("testIndexed(new Array(1))");
5421  // Test that the indexed access check is called.
5422  value = CompileRun("testIndexed(obj)");
5423  CHECK(value->IsNumber());
5424  CHECK_EQ(1, value->Int32Value());
5425  CHECK_EQ(42, indexed_access_count);
5426
5427  // Check that the named access check is called when invoking
5428  // functions on an object that requires access checks.
5429  CompileRun("obj.f = function() {}");
5430  CompileRun("function testCallNormal(obj) {"
5431             "  for (var i = 0; i < 10; i++) obj.f();"
5432             "}");
5433  CompileRun("testCallNormal(obj)");
5434  CHECK_EQ(74, named_access_count);
5435
5436  // Force obj into slow case.
5437  value = CompileRun("delete obj.prop");
5438  CHECK(value->BooleanValue());
5439  // Force inline caches into dictionary probing mode.
5440  CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
5441  // Test that the named access check is called.
5442  value = CompileRun("testProp(obj);");
5443  CHECK(value->IsNumber());
5444  CHECK_EQ(1, value->Int32Value());
5445  CHECK_EQ(96, named_access_count);
5446
5447  // Force the call inline cache into dictionary probing mode.
5448  CompileRun("o.f = function() {}; testCallNormal(o)");
5449  // Test that the named access check is still called for each
5450  // invocation of the function.
5451  value = CompileRun("testCallNormal(obj)");
5452  CHECK_EQ(106, named_access_count);
5453
5454  context1->Exit();
5455  context0->Exit();
5456  context1.Dispose();
5457  context0.Dispose();
5458}
5459
5460
5461static bool NamedAccessFlatten(Local<v8::Object> global,
5462                               Local<Value> name,
5463                               v8::AccessType type,
5464                               Local<Value> data) {
5465  char buf[100];
5466  int len;
5467
5468  CHECK(name->IsString());
5469
5470  memset(buf, 0x1, sizeof(buf));
5471  len = name.As<String>()->WriteAscii(buf);
5472  CHECK_EQ(4, len);
5473
5474  uint16_t buf2[100];
5475
5476  memset(buf, 0x1, sizeof(buf));
5477  len = name.As<String>()->Write(buf2);
5478  CHECK_EQ(4, len);
5479
5480  return true;
5481}
5482
5483
5484static bool IndexedAccessFlatten(Local<v8::Object> global,
5485                                 uint32_t key,
5486                                 v8::AccessType type,
5487                                 Local<Value> data) {
5488  return true;
5489}
5490
5491
5492// Regression test.  In access checks, operations that may cause
5493// garbage collection are not allowed.  It used to be the case that
5494// using the Write operation on a string could cause a garbage
5495// collection due to flattening of the string.  This is no longer the
5496// case.
5497THREADED_TEST(AccessControlFlatten) {
5498  named_access_count = 0;
5499  indexed_access_count = 0;
5500
5501  v8::HandleScope handle_scope;
5502
5503  // Create an environment.
5504  v8::Persistent<Context> context0 = Context::New();
5505  context0->Enter();
5506
5507  // Create an object that requires access-check functions to be
5508  // called for cross-domain access.
5509  v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
5510  object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
5511                                           IndexedAccessFlatten);
5512  Local<v8::Object> object = object_template->NewInstance();
5513
5514  v8::HandleScope scope1;
5515
5516  // Create another environment.
5517  v8::Persistent<Context> context1 = Context::New();
5518  context1->Enter();
5519
5520  // Make easy access to the object from the other environment.
5521  v8::Handle<v8::Object> global1 = context1->Global();
5522  global1->Set(v8_str("obj"), object);
5523
5524  v8::Handle<Value> value;
5525
5526  value = v8_compile("var p = 'as' + 'df';")->Run();
5527  value = v8_compile("obj[p];")->Run();
5528
5529  context1->Exit();
5530  context0->Exit();
5531  context1.Dispose();
5532  context0.Dispose();
5533}
5534
5535
5536static v8::Handle<Value> AccessControlNamedGetter(
5537    Local<String>, const AccessorInfo&) {
5538  return v8::Integer::New(42);
5539}
5540
5541
5542static v8::Handle<Value> AccessControlNamedSetter(
5543    Local<String>, Local<Value> value, const AccessorInfo&) {
5544  return value;
5545}
5546
5547
5548static v8::Handle<Value> AccessControlIndexedGetter(
5549      uint32_t index,
5550      const AccessorInfo& info) {
5551  return v8_num(42);
5552}
5553
5554
5555static v8::Handle<Value> AccessControlIndexedSetter(
5556    uint32_t, Local<Value> value, const AccessorInfo&) {
5557  return value;
5558}
5559
5560
5561THREADED_TEST(AccessControlInterceptorIC) {
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.  The object also has interceptors
5573  // interceptor.
5574  v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
5575  object_template->SetAccessCheckCallbacks(NamedAccessCounter,
5576                                           IndexedAccessCounter);
5577  object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
5578                                           AccessControlNamedSetter);
5579  object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
5580                                             AccessControlIndexedSetter);
5581  Local<v8::Object> object = object_template->NewInstance();
5582
5583  v8::HandleScope scope1;
5584
5585  // Create another environment.
5586  v8::Persistent<Context> context1 = Context::New();
5587  context1->Enter();
5588
5589  // Make easy access to the object from the other environment.
5590  v8::Handle<v8::Object> global1 = context1->Global();
5591  global1->Set(v8_str("obj"), object);
5592
5593  v8::Handle<Value> value;
5594
5595  // Check that the named access-control function is called every time
5596  // eventhough there is an interceptor on the object.
5597  value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
5598  value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
5599                     "obj.x")->Run();
5600  CHECK(value->IsNumber());
5601  CHECK_EQ(42, value->Int32Value());
5602  CHECK_EQ(21, named_access_count);
5603
5604  value = v8_compile("var p = 'x';")->Run();
5605  value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
5606  value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
5607                     "obj[p]")->Run();
5608  CHECK(value->IsNumber());
5609  CHECK_EQ(42, value->Int32Value());
5610  CHECK_EQ(42, named_access_count);
5611
5612  // Check that the indexed access-control function is called every
5613  // time eventhough there is an interceptor on the object.
5614  value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
5615  value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
5616                     "obj[0]")->Run();
5617  CHECK(value->IsNumber());
5618  CHECK_EQ(42, value->Int32Value());
5619  CHECK_EQ(21, indexed_access_count);
5620
5621  context1->Exit();
5622  context0->Exit();
5623  context1.Dispose();
5624  context0.Dispose();
5625}
5626
5627
5628THREADED_TEST(Version) {
5629  v8::V8::GetVersion();
5630}
5631
5632
5633static v8::Handle<Value> InstanceFunctionCallback(const v8::Arguments& args) {
5634  ApiTestFuzzer::Fuzz();
5635  return v8_num(12);
5636}
5637
5638
5639THREADED_TEST(InstanceProperties) {
5640  v8::HandleScope handle_scope;
5641  LocalContext context;
5642
5643  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
5644  Local<ObjectTemplate> instance = t->InstanceTemplate();
5645
5646  instance->Set(v8_str("x"), v8_num(42));
5647  instance->Set(v8_str("f"),
5648                v8::FunctionTemplate::New(InstanceFunctionCallback));
5649
5650  Local<Value> o = t->GetFunction()->NewInstance();
5651
5652  context->Global()->Set(v8_str("i"), o);
5653  Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
5654  CHECK_EQ(42, value->Int32Value());
5655
5656  value = Script::Compile(v8_str("i.f()"))->Run();
5657  CHECK_EQ(12, value->Int32Value());
5658}
5659
5660
5661static v8::Handle<Value>
5662GlobalObjectInstancePropertiesGet(Local<String> key, const AccessorInfo&) {
5663  ApiTestFuzzer::Fuzz();
5664  return v8::Handle<Value>();
5665}
5666
5667
5668THREADED_TEST(GlobalObjectInstanceProperties) {
5669  v8::HandleScope handle_scope;
5670
5671  Local<Value> global_object;
5672
5673  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
5674  t->InstanceTemplate()->SetNamedPropertyHandler(
5675      GlobalObjectInstancePropertiesGet);
5676  Local<ObjectTemplate> instance_template = t->InstanceTemplate();
5677  instance_template->Set(v8_str("x"), v8_num(42));
5678  instance_template->Set(v8_str("f"),
5679                         v8::FunctionTemplate::New(InstanceFunctionCallback));
5680
5681  {
5682    LocalContext env(NULL, instance_template);
5683    // Hold on to the global object so it can be used again in another
5684    // environment initialization.
5685    global_object = env->Global();
5686
5687    Local<Value> value = Script::Compile(v8_str("x"))->Run();
5688    CHECK_EQ(42, value->Int32Value());
5689    value = Script::Compile(v8_str("f()"))->Run();
5690    CHECK_EQ(12, value->Int32Value());
5691  }
5692
5693  {
5694    // Create new environment reusing the global object.
5695    LocalContext env(NULL, instance_template, global_object);
5696    Local<Value> value = Script::Compile(v8_str("x"))->Run();
5697    CHECK_EQ(42, value->Int32Value());
5698    value = Script::Compile(v8_str("f()"))->Run();
5699    CHECK_EQ(12, value->Int32Value());
5700  }
5701}
5702
5703
5704static v8::Handle<Value> ShadowFunctionCallback(const v8::Arguments& args) {
5705  ApiTestFuzzer::Fuzz();
5706  return v8_num(42);
5707}
5708
5709
5710static int shadow_y;
5711static int shadow_y_setter_call_count;
5712static int shadow_y_getter_call_count;
5713
5714
5715static void ShadowYSetter(Local<String>, Local<Value>, const AccessorInfo&) {
5716  shadow_y_setter_call_count++;
5717  shadow_y = 42;
5718}
5719
5720
5721static v8::Handle<Value> ShadowYGetter(Local<String> name,
5722                                       const AccessorInfo& info) {
5723  ApiTestFuzzer::Fuzz();
5724  shadow_y_getter_call_count++;
5725  return v8_num(shadow_y);
5726}
5727
5728
5729static v8::Handle<Value> ShadowIndexedGet(uint32_t index,
5730                                          const AccessorInfo& info) {
5731  return v8::Handle<Value>();
5732}
5733
5734
5735static v8::Handle<Value> ShadowNamedGet(Local<String> key,
5736                                        const AccessorInfo&) {
5737  return v8::Handle<Value>();
5738}
5739
5740
5741THREADED_TEST(ShadowObject) {
5742  shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
5743  v8::HandleScope handle_scope;
5744
5745  Local<ObjectTemplate> global_template = v8::ObjectTemplate::New();
5746  LocalContext context(NULL, global_template);
5747
5748  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
5749  t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
5750  t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
5751  Local<ObjectTemplate> proto = t->PrototypeTemplate();
5752  Local<ObjectTemplate> instance = t->InstanceTemplate();
5753
5754  // Only allow calls of f on instances of t.
5755  Local<v8::Signature> signature = v8::Signature::New(t);
5756  proto->Set(v8_str("f"),
5757             v8::FunctionTemplate::New(ShadowFunctionCallback,
5758                                       Local<Value>(),
5759                                       signature));
5760  proto->Set(v8_str("x"), v8_num(12));
5761
5762  instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
5763
5764  Local<Value> o = t->GetFunction()->NewInstance();
5765  context->Global()->Set(v8_str("__proto__"), o);
5766
5767  Local<Value> value =
5768      Script::Compile(v8_str("propertyIsEnumerable(0)"))->Run();
5769  CHECK(value->IsBoolean());
5770  CHECK(!value->BooleanValue());
5771
5772  value = Script::Compile(v8_str("x"))->Run();
5773  CHECK_EQ(12, value->Int32Value());
5774
5775  value = Script::Compile(v8_str("f()"))->Run();
5776  CHECK_EQ(42, value->Int32Value());
5777
5778  Script::Compile(v8_str("y = 42"))->Run();
5779  CHECK_EQ(1, shadow_y_setter_call_count);
5780  value = Script::Compile(v8_str("y"))->Run();
5781  CHECK_EQ(1, shadow_y_getter_call_count);
5782  CHECK_EQ(42, value->Int32Value());
5783}
5784
5785
5786THREADED_TEST(HiddenPrototype) {
5787  v8::HandleScope handle_scope;
5788  LocalContext context;
5789
5790  Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
5791  t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
5792  Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
5793  t1->SetHiddenPrototype(true);
5794  t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
5795  Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
5796  t2->SetHiddenPrototype(true);
5797  t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
5798  Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
5799  t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
5800
5801  Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
5802  Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
5803  Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
5804  Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
5805
5806  // Setting the prototype on an object skips hidden prototypes.
5807  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5808  o0->Set(v8_str("__proto__"), o1);
5809  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5810  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
5811  o0->Set(v8_str("__proto__"), o2);
5812  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5813  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
5814  CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
5815  o0->Set(v8_str("__proto__"), o3);
5816  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5817  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
5818  CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
5819  CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
5820
5821  // Getting the prototype of o0 should get the first visible one
5822  // which is o3.  Therefore, z should not be defined on the prototype
5823  // object.
5824  Local<Value> proto = o0->Get(v8_str("__proto__"));
5825  CHECK(proto->IsObject());
5826  CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
5827}
5828
5829
5830THREADED_TEST(SetPrototype) {
5831  v8::HandleScope handle_scope;
5832  LocalContext context;
5833
5834  Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
5835  t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
5836  Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
5837  t1->SetHiddenPrototype(true);
5838  t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
5839  Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
5840  t2->SetHiddenPrototype(true);
5841  t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
5842  Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
5843  t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
5844
5845  Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
5846  Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
5847  Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
5848  Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
5849
5850  // Setting the prototype on an object does not skip hidden prototypes.
5851  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5852  CHECK(o0->SetPrototype(o1));
5853  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5854  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
5855  CHECK(o1->SetPrototype(o2));
5856  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5857  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
5858  CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
5859  CHECK(o2->SetPrototype(o3));
5860  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5861  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
5862  CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
5863  CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
5864
5865  // Getting the prototype of o0 should get the first visible one
5866  // which is o3.  Therefore, z should not be defined on the prototype
5867  // object.
5868  Local<Value> proto = o0->Get(v8_str("__proto__"));
5869  CHECK(proto->IsObject());
5870  CHECK_EQ(proto.As<v8::Object>(), o3);
5871
5872  // However, Object::GetPrototype ignores hidden prototype.
5873  Local<Value> proto0 = o0->GetPrototype();
5874  CHECK(proto0->IsObject());
5875  CHECK_EQ(proto0.As<v8::Object>(), o1);
5876
5877  Local<Value> proto1 = o1->GetPrototype();
5878  CHECK(proto1->IsObject());
5879  CHECK_EQ(proto1.As<v8::Object>(), o2);
5880
5881  Local<Value> proto2 = o2->GetPrototype();
5882  CHECK(proto2->IsObject());
5883  CHECK_EQ(proto2.As<v8::Object>(), o3);
5884}
5885
5886
5887THREADED_TEST(SetPrototypeThrows) {
5888  v8::HandleScope handle_scope;
5889  LocalContext context;
5890
5891  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
5892
5893  Local<v8::Object> o0 = t->GetFunction()->NewInstance();
5894  Local<v8::Object> o1 = t->GetFunction()->NewInstance();
5895
5896  CHECK(o0->SetPrototype(o1));
5897  // If setting the prototype leads to the cycle, SetPrototype should
5898  // return false and keep VM in sane state.
5899  v8::TryCatch try_catch;
5900  CHECK(!o1->SetPrototype(o0));
5901  CHECK(!try_catch.HasCaught());
5902  ASSERT(!i::Top::has_pending_exception());
5903
5904  CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
5905}
5906
5907
5908THREADED_TEST(GetterSetterExceptions) {
5909  v8::HandleScope handle_scope;
5910  LocalContext context;
5911  CompileRun(
5912    "function Foo() { };"
5913    "function Throw() { throw 5; };"
5914    "var x = { };"
5915    "x.__defineSetter__('set', Throw);"
5916    "x.__defineGetter__('get', Throw);");
5917  Local<v8::Object> x =
5918      Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
5919  v8::TryCatch try_catch;
5920  x->Set(v8_str("set"), v8::Integer::New(8));
5921  x->Get(v8_str("get"));
5922  x->Set(v8_str("set"), v8::Integer::New(8));
5923  x->Get(v8_str("get"));
5924  x->Set(v8_str("set"), v8::Integer::New(8));
5925  x->Get(v8_str("get"));
5926  x->Set(v8_str("set"), v8::Integer::New(8));
5927  x->Get(v8_str("get"));
5928}
5929
5930
5931THREADED_TEST(Constructor) {
5932  v8::HandleScope handle_scope;
5933  LocalContext context;
5934  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
5935  templ->SetClassName(v8_str("Fun"));
5936  Local<Function> cons = templ->GetFunction();
5937  context->Global()->Set(v8_str("Fun"), cons);
5938  Local<v8::Object> inst = cons->NewInstance();
5939  i::Handle<i::JSObject> obj = v8::Utils::OpenHandle(*inst);
5940  Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
5941  CHECK(value->BooleanValue());
5942}
5943
5944THREADED_TEST(FunctionDescriptorException) {
5945  v8::HandleScope handle_scope;
5946  LocalContext context;
5947  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
5948  templ->SetClassName(v8_str("Fun"));
5949  Local<Function> cons = templ->GetFunction();
5950  context->Global()->Set(v8_str("Fun"), cons);
5951  Local<Value> value = CompileRun(
5952    "function test() {"
5953    "  try {"
5954    "    (new Fun()).blah()"
5955    "  } catch (e) {"
5956    "    var str = String(e);"
5957    "    if (str.indexOf('TypeError') == -1) return 1;"
5958    "    if (str.indexOf('[object Fun]') != -1) return 2;"
5959    "    if (str.indexOf('#<a Fun>') == -1) return 3;"
5960    "    return 0;"
5961    "  }"
5962    "  return 4;"
5963    "}"
5964    "test();");
5965  CHECK_EQ(0, value->Int32Value());
5966}
5967
5968
5969THREADED_TEST(EvalAliasedDynamic) {
5970  v8::HandleScope scope;
5971  LocalContext current;
5972
5973  // Tests where aliased eval can only be resolved dynamically.
5974  Local<Script> script =
5975      Script::Compile(v8_str("function f(x) { "
5976                             "  var foo = 2;"
5977                             "  with (x) { return eval('foo'); }"
5978                             "}"
5979                             "foo = 0;"
5980                             "result1 = f(new Object());"
5981                             "result2 = f(this);"
5982                             "var x = new Object();"
5983                             "x.eval = function(x) { return 1; };"
5984                             "result3 = f(x);"));
5985  script->Run();
5986  CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
5987  CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
5988  CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
5989
5990  v8::TryCatch try_catch;
5991  script =
5992    Script::Compile(v8_str("function f(x) { "
5993                           "  var bar = 2;"
5994                           "  with (x) { return eval('bar'); }"
5995                           "}"
5996                           "f(this)"));
5997  script->Run();
5998  CHECK(try_catch.HasCaught());
5999  try_catch.Reset();
6000}
6001
6002
6003THREADED_TEST(CrossEval) {
6004  v8::HandleScope scope;
6005  LocalContext other;
6006  LocalContext current;
6007
6008  Local<String> token = v8_str("<security token>");
6009  other->SetSecurityToken(token);
6010  current->SetSecurityToken(token);
6011
6012  // Setup reference from current to other.
6013  current->Global()->Set(v8_str("other"), other->Global());
6014
6015  // Check that new variables are introduced in other context.
6016  Local<Script> script =
6017      Script::Compile(v8_str("other.eval('var foo = 1234')"));
6018  script->Run();
6019  Local<Value> foo = other->Global()->Get(v8_str("foo"));
6020  CHECK_EQ(1234, foo->Int32Value());
6021  CHECK(!current->Global()->Has(v8_str("foo")));
6022
6023  // Check that writing to non-existing properties introduces them in
6024  // the other context.
6025  script =
6026      Script::Compile(v8_str("other.eval('na = 1234')"));
6027  script->Run();
6028  CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
6029  CHECK(!current->Global()->Has(v8_str("na")));
6030
6031  // Check that global variables in current context are not visible in other
6032  // context.
6033  v8::TryCatch try_catch;
6034  script =
6035      Script::Compile(v8_str("var bar = 42; other.eval('bar');"));
6036  Local<Value> result = script->Run();
6037  CHECK(try_catch.HasCaught());
6038  try_catch.Reset();
6039
6040  // Check that local variables in current context are not visible in other
6041  // context.
6042  script =
6043      Script::Compile(v8_str("(function() { "
6044                             "  var baz = 87;"
6045                             "  return other.eval('baz');"
6046                             "})();"));
6047  result = script->Run();
6048  CHECK(try_catch.HasCaught());
6049  try_catch.Reset();
6050
6051  // Check that global variables in the other environment are visible
6052  // when evaluting code.
6053  other->Global()->Set(v8_str("bis"), v8_num(1234));
6054  script = Script::Compile(v8_str("other.eval('bis')"));
6055  CHECK_EQ(1234, script->Run()->Int32Value());
6056  CHECK(!try_catch.HasCaught());
6057
6058  // Check that the 'this' pointer points to the global object evaluating
6059  // code.
6060  other->Global()->Set(v8_str("t"), other->Global());
6061  script = Script::Compile(v8_str("other.eval('this == t')"));
6062  result = script->Run();
6063  CHECK(result->IsTrue());
6064  CHECK(!try_catch.HasCaught());
6065
6066  // Check that variables introduced in with-statement are not visible in
6067  // other context.
6068  script =
6069      Script::Compile(v8_str("with({x:2}){other.eval('x')}"));
6070  result = script->Run();
6071  CHECK(try_catch.HasCaught());
6072  try_catch.Reset();
6073
6074  // Check that you cannot use 'eval.call' with another object than the
6075  // current global object.
6076  script =
6077      Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')"));
6078  result = script->Run();
6079  CHECK(try_catch.HasCaught());
6080}
6081
6082
6083// Test that calling eval in a context which has been detached from
6084// its global throws an exception.  This behavior is consistent with
6085// other JavaScript implementations.
6086THREADED_TEST(EvalInDetachedGlobal) {
6087  v8::HandleScope scope;
6088
6089  v8::Persistent<Context> context0 = Context::New();
6090  v8::Persistent<Context> context1 = Context::New();
6091
6092  // Setup function in context0 that uses eval from context0.
6093  context0->Enter();
6094  v8::Handle<v8::Value> fun =
6095      CompileRun("var x = 42;"
6096                 "(function() {"
6097                 "  var e = eval;"
6098                 "  return function(s) { return e(s); }"
6099                 "})()");
6100  context0->Exit();
6101
6102  // Put the function into context1 and call it before and after
6103  // detaching the global.  Before detaching, the call succeeds and
6104  // after detaching and exception is thrown.
6105  context1->Enter();
6106  context1->Global()->Set(v8_str("fun"), fun);
6107  v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
6108  CHECK_EQ(42, x_value->Int32Value());
6109  context0->DetachGlobal();
6110  v8::TryCatch catcher;
6111  x_value = CompileRun("fun('x')");
6112  CHECK(x_value.IsEmpty());
6113  CHECK(catcher.HasCaught());
6114  context1->Exit();
6115
6116  context1.Dispose();
6117  context0.Dispose();
6118}
6119
6120
6121THREADED_TEST(CrossLazyLoad) {
6122  v8::HandleScope scope;
6123  LocalContext other;
6124  LocalContext current;
6125
6126  Local<String> token = v8_str("<security token>");
6127  other->SetSecurityToken(token);
6128  current->SetSecurityToken(token);
6129
6130  // Setup reference from current to other.
6131  current->Global()->Set(v8_str("other"), other->Global());
6132
6133  // Trigger lazy loading in other context.
6134  Local<Script> script =
6135      Script::Compile(v8_str("other.eval('new Date(42)')"));
6136  Local<Value> value = script->Run();
6137  CHECK_EQ(42.0, value->NumberValue());
6138}
6139
6140
6141static v8::Handle<Value> call_as_function(const v8::Arguments& args) {
6142  ApiTestFuzzer::Fuzz();
6143  if (args.IsConstructCall()) {
6144    if (args[0]->IsInt32()) {
6145       return v8_num(-args[0]->Int32Value());
6146    }
6147  }
6148
6149  return args[0];
6150}
6151
6152
6153// Test that a call handler can be set for objects which will allow
6154// non-function objects created through the API to be called as
6155// functions.
6156THREADED_TEST(CallAsFunction) {
6157  v8::HandleScope scope;
6158  LocalContext context;
6159
6160  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6161  Local<ObjectTemplate> instance_template = t->InstanceTemplate();
6162  instance_template->SetCallAsFunctionHandler(call_as_function);
6163  Local<v8::Object> instance = t->GetFunction()->NewInstance();
6164  context->Global()->Set(v8_str("obj"), instance);
6165  v8::TryCatch try_catch;
6166  Local<Value> value;
6167  CHECK(!try_catch.HasCaught());
6168
6169  value = CompileRun("obj(42)");
6170  CHECK(!try_catch.HasCaught());
6171  CHECK_EQ(42, value->Int32Value());
6172
6173  value = CompileRun("(function(o){return o(49)})(obj)");
6174  CHECK(!try_catch.HasCaught());
6175  CHECK_EQ(49, value->Int32Value());
6176
6177  // test special case of call as function
6178  value = CompileRun("[obj]['0'](45)");
6179  CHECK(!try_catch.HasCaught());
6180  CHECK_EQ(45, value->Int32Value());
6181
6182  value = CompileRun("obj.call = Function.prototype.call;"
6183                     "obj.call(null, 87)");
6184  CHECK(!try_catch.HasCaught());
6185  CHECK_EQ(87, value->Int32Value());
6186
6187  // Regression tests for bug #1116356: Calling call through call/apply
6188  // must work for non-function receivers.
6189  const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
6190  value = CompileRun(apply_99);
6191  CHECK(!try_catch.HasCaught());
6192  CHECK_EQ(99, value->Int32Value());
6193
6194  const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
6195  value = CompileRun(call_17);
6196  CHECK(!try_catch.HasCaught());
6197  CHECK_EQ(17, value->Int32Value());
6198
6199  // Check that the call-as-function handler can be called through
6200  // new.
6201  value = CompileRun("new obj(43)");
6202  CHECK(!try_catch.HasCaught());
6203  CHECK_EQ(-43, value->Int32Value());
6204}
6205
6206
6207static int CountHandles() {
6208  return v8::HandleScope::NumberOfHandles();
6209}
6210
6211
6212static int Recurse(int depth, int iterations) {
6213  v8::HandleScope scope;
6214  if (depth == 0) return CountHandles();
6215  for (int i = 0; i < iterations; i++) {
6216    Local<v8::Number> n = v8::Integer::New(42);
6217  }
6218  return Recurse(depth - 1, iterations);
6219}
6220
6221
6222THREADED_TEST(HandleIteration) {
6223  static const int kIterations = 500;
6224  static const int kNesting = 200;
6225  CHECK_EQ(0, CountHandles());
6226  {
6227    v8::HandleScope scope1;
6228    CHECK_EQ(0, CountHandles());
6229    for (int i = 0; i < kIterations; i++) {
6230      Local<v8::Number> n = v8::Integer::New(42);
6231      CHECK_EQ(i + 1, CountHandles());
6232    }
6233
6234    CHECK_EQ(kIterations, CountHandles());
6235    {
6236      v8::HandleScope scope2;
6237      for (int j = 0; j < kIterations; j++) {
6238        Local<v8::Number> n = v8::Integer::New(42);
6239        CHECK_EQ(j + 1 + kIterations, CountHandles());
6240      }
6241    }
6242    CHECK_EQ(kIterations, CountHandles());
6243  }
6244  CHECK_EQ(0, CountHandles());
6245  CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations));
6246}
6247
6248
6249static v8::Handle<Value> InterceptorHasOwnPropertyGetter(
6250    Local<String> name,
6251    const AccessorInfo& info) {
6252  ApiTestFuzzer::Fuzz();
6253  return v8::Handle<Value>();
6254}
6255
6256
6257THREADED_TEST(InterceptorHasOwnProperty) {
6258  v8::HandleScope scope;
6259  LocalContext context;
6260  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6261  Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
6262  instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
6263  Local<Function> function = fun_templ->GetFunction();
6264  context->Global()->Set(v8_str("constructor"), function);
6265  v8::Handle<Value> value = CompileRun(
6266      "var o = new constructor();"
6267      "o.hasOwnProperty('ostehaps');");
6268  CHECK_EQ(false, value->BooleanValue());
6269  value = CompileRun(
6270      "o.ostehaps = 42;"
6271      "o.hasOwnProperty('ostehaps');");
6272  CHECK_EQ(true, value->BooleanValue());
6273  value = CompileRun(
6274      "var p = new constructor();"
6275      "p.hasOwnProperty('ostehaps');");
6276  CHECK_EQ(false, value->BooleanValue());
6277}
6278
6279
6280static v8::Handle<Value> InterceptorHasOwnPropertyGetterGC(
6281    Local<String> name,
6282    const AccessorInfo& info) {
6283  ApiTestFuzzer::Fuzz();
6284  i::Heap::CollectAllGarbage(false);
6285  return v8::Handle<Value>();
6286}
6287
6288
6289THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
6290  v8::HandleScope scope;
6291  LocalContext context;
6292  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6293  Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
6294  instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
6295  Local<Function> function = fun_templ->GetFunction();
6296  context->Global()->Set(v8_str("constructor"), function);
6297  // Let's first make some stuff so we can be sure to get a good GC.
6298  CompileRun(
6299      "function makestr(size) {"
6300      "  switch (size) {"
6301      "    case 1: return 'f';"
6302      "    case 2: return 'fo';"
6303      "    case 3: return 'foo';"
6304      "  }"
6305      "  return makestr(size >> 1) + makestr((size + 1) >> 1);"
6306      "}"
6307      "var x = makestr(12345);"
6308      "x = makestr(31415);"
6309      "x = makestr(23456);");
6310  v8::Handle<Value> value = CompileRun(
6311      "var o = new constructor();"
6312      "o.__proto__ = new String(x);"
6313      "o.hasOwnProperty('ostehaps');");
6314  CHECK_EQ(false, value->BooleanValue());
6315}
6316
6317
6318typedef v8::Handle<Value> (*NamedPropertyGetter)(Local<String> property,
6319                                                 const AccessorInfo& info);
6320
6321
6322static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
6323                                   const char* source,
6324                                   int expected) {
6325  v8::HandleScope scope;
6326  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6327  templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
6328  LocalContext context;
6329  context->Global()->Set(v8_str("o"), templ->NewInstance());
6330  v8::Handle<Value> value = CompileRun(source);
6331  CHECK_EQ(expected, value->Int32Value());
6332}
6333
6334
6335static v8::Handle<Value> InterceptorLoadICGetter(Local<String> name,
6336                                                 const AccessorInfo& info) {
6337  ApiTestFuzzer::Fuzz();
6338  CHECK_EQ(v8_str("data"), info.Data());
6339  CHECK_EQ(v8_str("x"), name);
6340  return v8::Integer::New(42);
6341}
6342
6343
6344// This test should hit the load IC for the interceptor case.
6345THREADED_TEST(InterceptorLoadIC) {
6346  CheckInterceptorLoadIC(InterceptorLoadICGetter,
6347    "var result = 0;"
6348    "for (var i = 0; i < 1000; i++) {"
6349    "  result = o.x;"
6350    "}",
6351    42);
6352}
6353
6354
6355// Below go several tests which verify that JITing for various
6356// configurations of interceptor and explicit fields works fine
6357// (those cases are special cased to get better performance).
6358
6359static v8::Handle<Value> InterceptorLoadXICGetter(Local<String> name,
6360                                                 const AccessorInfo& info) {
6361  ApiTestFuzzer::Fuzz();
6362  return v8_str("x")->Equals(name)
6363      ? v8::Integer::New(42) : v8::Handle<v8::Value>();
6364}
6365
6366
6367THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
6368  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6369    "var result = 0;"
6370    "o.y = 239;"
6371    "for (var i = 0; i < 1000; i++) {"
6372    "  result = o.y;"
6373    "}",
6374    239);
6375}
6376
6377
6378THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
6379  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6380    "var result = 0;"
6381    "o.__proto__ = { 'y': 239 };"
6382    "for (var i = 0; i < 1000; i++) {"
6383    "  result = o.y + o.x;"
6384    "}",
6385    239 + 42);
6386}
6387
6388
6389THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
6390  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6391    "var result = 0;"
6392    "o.__proto__.y = 239;"
6393    "for (var i = 0; i < 1000; i++) {"
6394    "  result = o.y + o.x;"
6395    "}",
6396    239 + 42);
6397}
6398
6399
6400THREADED_TEST(InterceptorLoadICUndefined) {
6401  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6402    "var result = 0;"
6403    "for (var i = 0; i < 1000; i++) {"
6404    "  result = (o.y == undefined) ? 239 : 42;"
6405    "}",
6406    239);
6407}
6408
6409
6410THREADED_TEST(InterceptorLoadICWithOverride) {
6411  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6412    "fst = new Object();  fst.__proto__ = o;"
6413    "snd = new Object();  snd.__proto__ = fst;"
6414    "var result1 = 0;"
6415    "for (var i = 0; i < 1000;  i++) {"
6416    "  result1 = snd.x;"
6417    "}"
6418    "fst.x = 239;"
6419    "var result = 0;"
6420    "for (var i = 0; i < 1000; i++) {"
6421    "  result = snd.x;"
6422    "}"
6423    "result + result1",
6424    239 + 42);
6425}
6426
6427
6428// Test the case when we stored field into
6429// a stub, but interceptor produced value on its own.
6430THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
6431  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6432    "proto = new Object();"
6433    "o.__proto__ = proto;"
6434    "proto.x = 239;"
6435    "for (var i = 0; i < 1000; i++) {"
6436    "  o.x;"
6437    // Now it should be ICed and keep a reference to x defined on proto
6438    "}"
6439    "var result = 0;"
6440    "for (var i = 0; i < 1000; i++) {"
6441    "  result += o.x;"
6442    "}"
6443    "result;",
6444    42 * 1000);
6445}
6446
6447
6448// Test the case when we stored field into
6449// a stub, but it got invalidated later on.
6450THREADED_TEST(InterceptorLoadICInvalidatedField) {
6451  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6452    "proto1 = new Object();"
6453    "proto2 = new Object();"
6454    "o.__proto__ = proto1;"
6455    "proto1.__proto__ = proto2;"
6456    "proto2.y = 239;"
6457    "for (var i = 0; i < 1000; i++) {"
6458    "  o.y;"
6459    // Now it should be ICed and keep a reference to y defined on proto2
6460    "}"
6461    "proto1.y = 42;"
6462    "var result = 0;"
6463    "for (var i = 0; i < 1000; i++) {"
6464    "  result += o.y;"
6465    "}"
6466    "result;",
6467    42 * 1000);
6468}
6469
6470
6471static int interceptor_load_not_handled_calls = 0;
6472static v8::Handle<Value> InterceptorLoadNotHandled(Local<String> name,
6473                                                   const AccessorInfo& info) {
6474  ++interceptor_load_not_handled_calls;
6475  return v8::Handle<v8::Value>();
6476}
6477
6478
6479// Test how post-interceptor lookups are done in the non-cacheable
6480// case: the interceptor should not be invoked during this lookup.
6481THREADED_TEST(InterceptorLoadICPostInterceptor) {
6482  interceptor_load_not_handled_calls = 0;
6483  CheckInterceptorLoadIC(InterceptorLoadNotHandled,
6484    "receiver = new Object();"
6485    "receiver.__proto__ = o;"
6486    "proto = new Object();"
6487    "/* Make proto a slow-case object. */"
6488    "for (var i = 0; i < 1000; i++) {"
6489    "  proto[\"xxxxxxxx\" + i] = [];"
6490    "}"
6491    "proto.x = 17;"
6492    "o.__proto__ = proto;"
6493    "var result = 0;"
6494    "for (var i = 0; i < 1000; i++) {"
6495    "  result += receiver.x;"
6496    "}"
6497    "result;",
6498    17 * 1000);
6499  CHECK_EQ(1000, interceptor_load_not_handled_calls);
6500}
6501
6502
6503// Test the case when we stored field into
6504// a stub, but it got invalidated later on due to override on
6505// global object which is between interceptor and fields' holders.
6506THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
6507  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6508    "o.__proto__ = this;"  // set a global to be a proto of o.
6509    "this.__proto__.y = 239;"
6510    "for (var i = 0; i < 10; i++) {"
6511    "  if (o.y != 239) throw 'oops: ' + o.y;"
6512    // Now it should be ICed and keep a reference to y defined on field_holder.
6513    "}"
6514    "this.y = 42;"  // Assign on a global.
6515    "var result = 0;"
6516    "for (var i = 0; i < 10; i++) {"
6517    "  result += o.y;"
6518    "}"
6519    "result;",
6520    42 * 10);
6521}
6522
6523
6524static void SetOnThis(Local<String> name,
6525                      Local<Value> value,
6526                      const AccessorInfo& info) {
6527  info.This()->ForceSet(name, value);
6528}
6529
6530
6531THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
6532  v8::HandleScope scope;
6533  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6534  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6535  templ->SetAccessor(v8_str("y"), Return239);
6536  LocalContext context;
6537  context->Global()->Set(v8_str("o"), templ->NewInstance());
6538
6539  // Check the case when receiver and interceptor's holder
6540  // are the same objects.
6541  v8::Handle<Value> value = CompileRun(
6542      "var result = 0;"
6543      "for (var i = 0; i < 7; i++) {"
6544      "  result = o.y;"
6545      "}");
6546  CHECK_EQ(239, value->Int32Value());
6547
6548  // Check the case when interceptor's holder is in proto chain
6549  // of receiver.
6550  value = CompileRun(
6551      "r = { __proto__: o };"
6552      "var result = 0;"
6553      "for (var i = 0; i < 7; i++) {"
6554      "  result = r.y;"
6555      "}");
6556  CHECK_EQ(239, value->Int32Value());
6557}
6558
6559
6560THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
6561  v8::HandleScope scope;
6562  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6563  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6564  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
6565  templ_p->SetAccessor(v8_str("y"), Return239);
6566
6567  LocalContext context;
6568  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6569  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
6570
6571  // Check the case when receiver and interceptor's holder
6572  // are the same objects.
6573  v8::Handle<Value> value = CompileRun(
6574      "o.__proto__ = p;"
6575      "var result = 0;"
6576      "for (var i = 0; i < 7; i++) {"
6577      "  result = o.x + o.y;"
6578      "}");
6579  CHECK_EQ(239 + 42, value->Int32Value());
6580
6581  // Check the case when interceptor's holder is in proto chain
6582  // of receiver.
6583  value = CompileRun(
6584      "r = { __proto__: o };"
6585      "var result = 0;"
6586      "for (var i = 0; i < 7; i++) {"
6587      "  result = r.x + r.y;"
6588      "}");
6589  CHECK_EQ(239 + 42, value->Int32Value());
6590}
6591
6592
6593THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
6594  v8::HandleScope scope;
6595  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6596  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6597  templ->SetAccessor(v8_str("y"), Return239);
6598
6599  LocalContext context;
6600  context->Global()->Set(v8_str("o"), templ->NewInstance());
6601
6602  v8::Handle<Value> value = CompileRun(
6603    "fst = new Object();  fst.__proto__ = o;"
6604    "snd = new Object();  snd.__proto__ = fst;"
6605    "var result1 = 0;"
6606    "for (var i = 0; i < 7;  i++) {"
6607    "  result1 = snd.x;"
6608    "}"
6609    "fst.x = 239;"
6610    "var result = 0;"
6611    "for (var i = 0; i < 7; i++) {"
6612    "  result = snd.x;"
6613    "}"
6614    "result + result1");
6615  CHECK_EQ(239 + 42, value->Int32Value());
6616}
6617
6618
6619// Test the case when we stored callback into
6620// a stub, but interceptor produced value on its own.
6621THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
6622  v8::HandleScope scope;
6623  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6624  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6625  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
6626  templ_p->SetAccessor(v8_str("y"), Return239);
6627
6628  LocalContext context;
6629  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6630  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
6631
6632  v8::Handle<Value> value = CompileRun(
6633    "o.__proto__ = p;"
6634    "for (var i = 0; i < 7; i++) {"
6635    "  o.x;"
6636    // Now it should be ICed and keep a reference to x defined on p
6637    "}"
6638    "var result = 0;"
6639    "for (var i = 0; i < 7; i++) {"
6640    "  result += o.x;"
6641    "}"
6642    "result");
6643  CHECK_EQ(42 * 7, value->Int32Value());
6644}
6645
6646
6647// Test the case when we stored callback into
6648// a stub, but it got invalidated later on.
6649THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
6650  v8::HandleScope scope;
6651  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6652  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6653  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
6654  templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
6655
6656  LocalContext context;
6657  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6658  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
6659
6660  v8::Handle<Value> value = CompileRun(
6661    "inbetween = new Object();"
6662    "o.__proto__ = inbetween;"
6663    "inbetween.__proto__ = p;"
6664    "for (var i = 0; i < 10; i++) {"
6665    "  o.y;"
6666    // Now it should be ICed and keep a reference to y defined on p
6667    "}"
6668    "inbetween.y = 42;"
6669    "var result = 0;"
6670    "for (var i = 0; i < 10; i++) {"
6671    "  result += o.y;"
6672    "}"
6673    "result");
6674  CHECK_EQ(42 * 10, value->Int32Value());
6675}
6676
6677
6678// Test the case when we stored callback into
6679// a stub, but it got invalidated later on due to override on
6680// global object which is between interceptor and callbacks' holders.
6681THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
6682  v8::HandleScope scope;
6683  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6684  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6685  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
6686  templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
6687
6688  LocalContext context;
6689  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6690  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
6691
6692  v8::Handle<Value> value = CompileRun(
6693    "o.__proto__ = this;"
6694    "this.__proto__ = p;"
6695    "for (var i = 0; i < 10; i++) {"
6696    "  if (o.y != 239) throw 'oops: ' + o.y;"
6697    // Now it should be ICed and keep a reference to y defined on p
6698    "}"
6699    "this.y = 42;"
6700    "var result = 0;"
6701    "for (var i = 0; i < 10; i++) {"
6702    "  result += o.y;"
6703    "}"
6704    "result");
6705  CHECK_EQ(42 * 10, value->Int32Value());
6706}
6707
6708
6709static v8::Handle<Value> InterceptorLoadICGetter0(Local<String> name,
6710                                                  const AccessorInfo& info) {
6711  ApiTestFuzzer::Fuzz();
6712  CHECK(v8_str("x")->Equals(name));
6713  return v8::Integer::New(0);
6714}
6715
6716
6717THREADED_TEST(InterceptorReturningZero) {
6718  CheckInterceptorLoadIC(InterceptorLoadICGetter0,
6719     "o.x == undefined ? 1 : 0",
6720     0);
6721}
6722
6723
6724static v8::Handle<Value> InterceptorStoreICSetter(
6725    Local<String> key, Local<Value> value, const AccessorInfo&) {
6726  CHECK(v8_str("x")->Equals(key));
6727  CHECK_EQ(42, value->Int32Value());
6728  return value;
6729}
6730
6731
6732// This test should hit the store IC for the interceptor case.
6733THREADED_TEST(InterceptorStoreIC) {
6734  v8::HandleScope scope;
6735  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6736  templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
6737                                 InterceptorStoreICSetter,
6738                                 0, 0, 0, v8_str("data"));
6739  LocalContext context;
6740  context->Global()->Set(v8_str("o"), templ->NewInstance());
6741  v8::Handle<Value> value = CompileRun(
6742    "for (var i = 0; i < 1000; i++) {"
6743    "  o.x = 42;"
6744    "}");
6745}
6746
6747
6748THREADED_TEST(InterceptorStoreICWithNoSetter) {
6749  v8::HandleScope scope;
6750  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6751  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6752  LocalContext context;
6753  context->Global()->Set(v8_str("o"), templ->NewInstance());
6754  v8::Handle<Value> value = CompileRun(
6755    "for (var i = 0; i < 1000; i++) {"
6756    "  o.y = 239;"
6757    "}"
6758    "42 + o.y");
6759  CHECK_EQ(239 + 42, value->Int32Value());
6760}
6761
6762
6763
6764
6765v8::Handle<Value> call_ic_function;
6766v8::Handle<Value> call_ic_function2;
6767v8::Handle<Value> call_ic_function3;
6768
6769static v8::Handle<Value> InterceptorCallICGetter(Local<String> name,
6770                                                 const AccessorInfo& info) {
6771  ApiTestFuzzer::Fuzz();
6772  CHECK(v8_str("x")->Equals(name));
6773  return call_ic_function;
6774}
6775
6776
6777// This test should hit the call IC for the interceptor case.
6778THREADED_TEST(InterceptorCallIC) {
6779  v8::HandleScope scope;
6780  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6781  templ->SetNamedPropertyHandler(InterceptorCallICGetter);
6782  LocalContext context;
6783  context->Global()->Set(v8_str("o"), templ->NewInstance());
6784  call_ic_function =
6785      v8_compile("function f(x) { return x + 1; }; f")->Run();
6786  v8::Handle<Value> value = CompileRun(
6787    "var result = 0;"
6788    "for (var i = 0; i < 1000; i++) {"
6789    "  result = o.x(41);"
6790    "}");
6791  CHECK_EQ(42, value->Int32Value());
6792}
6793
6794
6795// This test checks that if interceptor doesn't provide
6796// a value, we can fetch regular value.
6797THREADED_TEST(InterceptorCallICSeesOthers) {
6798  v8::HandleScope scope;
6799  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6800  templ->SetNamedPropertyHandler(NoBlockGetterX);
6801  LocalContext context;
6802  context->Global()->Set(v8_str("o"), templ->NewInstance());
6803  v8::Handle<Value> value = CompileRun(
6804    "o.x = function f(x) { return x + 1; };"
6805    "var result = 0;"
6806    "for (var i = 0; i < 7; i++) {"
6807    "  result = o.x(41);"
6808    "}");
6809  CHECK_EQ(42, value->Int32Value());
6810}
6811
6812
6813static v8::Handle<Value> call_ic_function4;
6814static v8::Handle<Value> InterceptorCallICGetter4(Local<String> name,
6815                                                  const AccessorInfo& info) {
6816  ApiTestFuzzer::Fuzz();
6817  CHECK(v8_str("x")->Equals(name));
6818  return call_ic_function4;
6819}
6820
6821
6822// This test checks that if interceptor provides a function,
6823// even if we cached shadowed variant, interceptor's function
6824// is invoked
6825THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
6826  v8::HandleScope scope;
6827  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6828  templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
6829  LocalContext context;
6830  context->Global()->Set(v8_str("o"), templ->NewInstance());
6831  call_ic_function4 =
6832      v8_compile("function f(x) { return x - 1; }; f")->Run();
6833  v8::Handle<Value> value = CompileRun(
6834    "o.__proto__.x = function(x) { return x + 1; };"
6835    "var result = 0;"
6836    "for (var i = 0; i < 1000; i++) {"
6837    "  result = o.x(42);"
6838    "}");
6839  CHECK_EQ(41, value->Int32Value());
6840}
6841
6842
6843// Test the case when we stored cacheable lookup into
6844// a stub, but it got invalidated later on
6845THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
6846  v8::HandleScope scope;
6847  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6848  templ->SetNamedPropertyHandler(NoBlockGetterX);
6849  LocalContext context;
6850  context->Global()->Set(v8_str("o"), templ->NewInstance());
6851  v8::Handle<Value> value = CompileRun(
6852    "proto1 = new Object();"
6853    "proto2 = new Object();"
6854    "o.__proto__ = proto1;"
6855    "proto1.__proto__ = proto2;"
6856    "proto2.y = function(x) { return x + 1; };"
6857    // Invoke it many times to compile a stub
6858    "for (var i = 0; i < 7; i++) {"
6859    "  o.y(42);"
6860    "}"
6861    "proto1.y = function(x) { return x - 1; };"
6862    "var result = 0;"
6863    "for (var i = 0; i < 7; i++) {"
6864    "  result += o.y(42);"
6865    "}");
6866  CHECK_EQ(41 * 7, value->Int32Value());
6867}
6868
6869
6870static v8::Handle<Value> call_ic_function5;
6871static v8::Handle<Value> InterceptorCallICGetter5(Local<String> name,
6872                                                  const AccessorInfo& info) {
6873  ApiTestFuzzer::Fuzz();
6874  if (v8_str("x")->Equals(name))
6875    return call_ic_function5;
6876  else
6877    return Local<Value>();
6878}
6879
6880
6881// This test checks that if interceptor doesn't provide a function,
6882// cached constant function is used
6883THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
6884  v8::HandleScope scope;
6885  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6886  templ->SetNamedPropertyHandler(NoBlockGetterX);
6887  LocalContext context;
6888  context->Global()->Set(v8_str("o"), templ->NewInstance());
6889  v8::Handle<Value> value = CompileRun(
6890    "function inc(x) { return x + 1; };"
6891    "inc(1);"
6892    "o.x = inc;"
6893    "var result = 0;"
6894    "for (var i = 0; i < 1000; i++) {"
6895    "  result = o.x(42);"
6896    "}");
6897  CHECK_EQ(43, value->Int32Value());
6898}
6899
6900
6901// This test checks that if interceptor provides a function,
6902// even if we cached constant function, interceptor's function
6903// is invoked
6904THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
6905  v8::HandleScope scope;
6906  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6907  templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
6908  LocalContext context;
6909  context->Global()->Set(v8_str("o"), templ->NewInstance());
6910  call_ic_function5 =
6911      v8_compile("function f(x) { return x - 1; }; f")->Run();
6912  v8::Handle<Value> value = CompileRun(
6913    "function inc(x) { return x + 1; };"
6914    "inc(1);"
6915    "o.x = inc;"
6916    "var result = 0;"
6917    "for (var i = 0; i < 1000; i++) {"
6918    "  result = o.x(42);"
6919    "}");
6920  CHECK_EQ(41, value->Int32Value());
6921}
6922
6923
6924// Test the case when we stored constant function into
6925// a stub, but it got invalidated later on
6926THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
6927  v8::HandleScope scope;
6928  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6929  templ->SetNamedPropertyHandler(NoBlockGetterX);
6930  LocalContext context;
6931  context->Global()->Set(v8_str("o"), templ->NewInstance());
6932  v8::Handle<Value> value = CompileRun(
6933    "function inc(x) { return x + 1; };"
6934    "inc(1);"
6935    "proto1 = new Object();"
6936    "proto2 = new Object();"
6937    "o.__proto__ = proto1;"
6938    "proto1.__proto__ = proto2;"
6939    "proto2.y = inc;"
6940    // Invoke it many times to compile a stub
6941    "for (var i = 0; i < 7; i++) {"
6942    "  o.y(42);"
6943    "}"
6944    "proto1.y = function(x) { return x - 1; };"
6945    "var result = 0;"
6946    "for (var i = 0; i < 7; i++) {"
6947    "  result += o.y(42);"
6948    "}");
6949  CHECK_EQ(41 * 7, value->Int32Value());
6950}
6951
6952
6953// Test the case when we stored constant function into
6954// a stub, but it got invalidated later on due to override on
6955// global object which is between interceptor and constant function' holders.
6956THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
6957  v8::HandleScope scope;
6958  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6959  templ->SetNamedPropertyHandler(NoBlockGetterX);
6960  LocalContext context;
6961  context->Global()->Set(v8_str("o"), templ->NewInstance());
6962  v8::Handle<Value> value = CompileRun(
6963    "function inc(x) { return x + 1; };"
6964    "inc(1);"
6965    "o.__proto__ = this;"
6966    "this.__proto__.y = inc;"
6967    // Invoke it many times to compile a stub
6968    "for (var i = 0; i < 7; i++) {"
6969    "  if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
6970    "}"
6971    "this.y = function(x) { return x - 1; };"
6972    "var result = 0;"
6973    "for (var i = 0; i < 7; i++) {"
6974    "  result += o.y(42);"
6975    "}");
6976  CHECK_EQ(41 * 7, value->Int32Value());
6977}
6978
6979
6980// Test the case when actual function to call sits on global object.
6981THREADED_TEST(InterceptorCallICCachedFromGlobal) {
6982  v8::HandleScope scope;
6983  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6984  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
6985
6986  LocalContext context;
6987  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6988
6989  v8::Handle<Value> value = CompileRun(
6990    "try {"
6991    "  o.__proto__ = this;"
6992    "  for (var i = 0; i < 10; i++) {"
6993    "    var v = o.parseFloat('239');"
6994    "    if (v != 239) throw v;"
6995      // Now it should be ICed and keep a reference to parseFloat.
6996    "  }"
6997    "  var result = 0;"
6998    "  for (var i = 0; i < 10; i++) {"
6999    "    result += o.parseFloat('239');"
7000    "  }"
7001    "  result"
7002    "} catch(e) {"
7003    "  e"
7004    "};");
7005  CHECK_EQ(239 * 10, value->Int32Value());
7006}
7007
7008static v8::Handle<Value> InterceptorCallICFastApi(Local<String> name,
7009                                                  const AccessorInfo& info) {
7010  ApiTestFuzzer::Fuzz();
7011  int* call_count = reinterpret_cast<int*>(v8::External::Unwrap(info.Data()));
7012  ++(*call_count);
7013  if ((*call_count) % 20 == 0) {
7014    i::Heap::CollectAllGarbage(true);
7015  }
7016  return v8::Handle<Value>();
7017}
7018
7019static v8::Handle<Value> FastApiCallback_TrivialSignature(
7020    const v8::Arguments& args) {
7021  ApiTestFuzzer::Fuzz();
7022  CHECK_EQ(args.This(), args.Holder());
7023  CHECK(args.Data()->Equals(v8_str("method_data")));
7024  return v8::Integer::New(args[0]->Int32Value() + 1);
7025}
7026
7027static v8::Handle<Value> FastApiCallback_SimpleSignature(
7028    const v8::Arguments& args) {
7029  ApiTestFuzzer::Fuzz();
7030  CHECK_EQ(args.This()->GetPrototype(), args.Holder());
7031  CHECK(args.Data()->Equals(v8_str("method_data")));
7032  // Note, we're using HasRealNamedProperty instead of Has to avoid
7033  // invoking the interceptor again.
7034  CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
7035  return v8::Integer::New(args[0]->Int32Value() + 1);
7036}
7037
7038// Helper to maximize the odds of object moving.
7039static void GenerateSomeGarbage() {
7040  CompileRun(
7041      "var garbage;"
7042      "for (var i = 0; i < 1000; i++) {"
7043      "  garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
7044      "}"
7045      "garbage = undefined;");
7046}
7047
7048THREADED_TEST(InterceptorCallICFastApi_TrivialSignature) {
7049  int interceptor_call_count = 0;
7050  v8::HandleScope scope;
7051  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7052  v8::Handle<v8::FunctionTemplate> method_templ =
7053      v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
7054                                v8_str("method_data"),
7055                                v8::Handle<v8::Signature>());
7056  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7057  proto_templ->Set(v8_str("method"), method_templ);
7058  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7059  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
7060                                 NULL, NULL, NULL, NULL,
7061                                 v8::External::Wrap(&interceptor_call_count));
7062  LocalContext context;
7063  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7064  GenerateSomeGarbage();
7065  context->Global()->Set(v8_str("o"), fun->NewInstance());
7066  v8::Handle<Value> value = CompileRun(
7067      "var result = 0;"
7068      "for (var i = 0; i < 100; i++) {"
7069      "  result = o.method(41);"
7070      "}");
7071  CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
7072  CHECK_EQ(100, interceptor_call_count);
7073}
7074
7075THREADED_TEST(InterceptorCallICFastApi_SimpleSignature) {
7076  int interceptor_call_count = 0;
7077  v8::HandleScope scope;
7078  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7079  v8::Handle<v8::FunctionTemplate> method_templ =
7080      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7081                                v8_str("method_data"),
7082                                v8::Signature::New(fun_templ));
7083  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7084  proto_templ->Set(v8_str("method"), method_templ);
7085  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7086  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
7087                                 NULL, NULL, NULL, NULL,
7088                                 v8::External::Wrap(&interceptor_call_count));
7089  LocalContext context;
7090  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7091  GenerateSomeGarbage();
7092  context->Global()->Set(v8_str("o"), fun->NewInstance());
7093  v8::Handle<Value> value = CompileRun(
7094      "o.foo = 17;"
7095      "var receiver = {};"
7096      "receiver.__proto__ = o;"
7097      "var result = 0;"
7098      "for (var i = 0; i < 100; i++) {"
7099      "  result = receiver.method(41);"
7100      "}");
7101  CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
7102  CHECK_EQ(100, interceptor_call_count);
7103}
7104
7105THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
7106  int interceptor_call_count = 0;
7107  v8::HandleScope scope;
7108  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7109  v8::Handle<v8::FunctionTemplate> method_templ =
7110      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7111                                v8_str("method_data"),
7112                                v8::Signature::New(fun_templ));
7113  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7114  proto_templ->Set(v8_str("method"), method_templ);
7115  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7116  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
7117                                 NULL, NULL, NULL, NULL,
7118                                 v8::External::Wrap(&interceptor_call_count));
7119  LocalContext context;
7120  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7121  GenerateSomeGarbage();
7122  context->Global()->Set(v8_str("o"), fun->NewInstance());
7123  v8::Handle<Value> value = CompileRun(
7124      "o.foo = 17;"
7125      "var receiver = {};"
7126      "receiver.__proto__ = o;"
7127      "var result = 0;"
7128      "var saved_result = 0;"
7129      "for (var i = 0; i < 100; i++) {"
7130      "  result = receiver.method(41);"
7131      "  if (i == 50) {"
7132      "    saved_result = result;"
7133      "    receiver = {method: function(x) { return x - 1 }};"
7134      "  }"
7135      "}");
7136  CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
7137  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7138  CHECK_GE(interceptor_call_count, 50);
7139}
7140
7141THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
7142  int interceptor_call_count = 0;
7143  v8::HandleScope scope;
7144  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7145  v8::Handle<v8::FunctionTemplate> method_templ =
7146      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7147                                v8_str("method_data"),
7148                                v8::Signature::New(fun_templ));
7149  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7150  proto_templ->Set(v8_str("method"), method_templ);
7151  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7152  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
7153                                 NULL, NULL, NULL, NULL,
7154                                 v8::External::Wrap(&interceptor_call_count));
7155  LocalContext context;
7156  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7157  GenerateSomeGarbage();
7158  context->Global()->Set(v8_str("o"), fun->NewInstance());
7159  v8::Handle<Value> value = CompileRun(
7160      "o.foo = 17;"
7161      "var receiver = {};"
7162      "receiver.__proto__ = o;"
7163      "var result = 0;"
7164      "var saved_result = 0;"
7165      "for (var i = 0; i < 100; i++) {"
7166      "  result = receiver.method(41);"
7167      "  if (i == 50) {"
7168      "    saved_result = result;"
7169      "    o.method = function(x) { return x - 1 };"
7170      "  }"
7171      "}");
7172  CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
7173  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7174  CHECK_GE(interceptor_call_count, 50);
7175}
7176
7177THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
7178  int interceptor_call_count = 0;
7179  v8::HandleScope scope;
7180  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7181  v8::Handle<v8::FunctionTemplate> method_templ =
7182      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7183                                v8_str("method_data"),
7184                                v8::Signature::New(fun_templ));
7185  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7186  proto_templ->Set(v8_str("method"), method_templ);
7187  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7188  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
7189                                 NULL, NULL, NULL, NULL,
7190                                 v8::External::Wrap(&interceptor_call_count));
7191  LocalContext context;
7192  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7193  GenerateSomeGarbage();
7194  context->Global()->Set(v8_str("o"), fun->NewInstance());
7195  v8::TryCatch try_catch;
7196  v8::Handle<Value> value = CompileRun(
7197      "o.foo = 17;"
7198      "var receiver = {};"
7199      "receiver.__proto__ = o;"
7200      "var result = 0;"
7201      "var saved_result = 0;"
7202      "for (var i = 0; i < 100; i++) {"
7203      "  result = receiver.method(41);"
7204      "  if (i == 50) {"
7205      "    saved_result = result;"
7206      "    receiver = 333;"
7207      "  }"
7208      "}");
7209  CHECK(try_catch.HasCaught());
7210  CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
7211           try_catch.Exception()->ToString());
7212  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7213  CHECK_GE(interceptor_call_count, 50);
7214}
7215
7216THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
7217  int interceptor_call_count = 0;
7218  v8::HandleScope scope;
7219  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7220  v8::Handle<v8::FunctionTemplate> method_templ =
7221      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7222                                v8_str("method_data"),
7223                                v8::Signature::New(fun_templ));
7224  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7225  proto_templ->Set(v8_str("method"), method_templ);
7226  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7227  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
7228                                 NULL, NULL, NULL, NULL,
7229                                 v8::External::Wrap(&interceptor_call_count));
7230  LocalContext context;
7231  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7232  GenerateSomeGarbage();
7233  context->Global()->Set(v8_str("o"), fun->NewInstance());
7234  v8::TryCatch try_catch;
7235  v8::Handle<Value> value = CompileRun(
7236      "o.foo = 17;"
7237      "var receiver = {};"
7238      "receiver.__proto__ = o;"
7239      "var result = 0;"
7240      "var saved_result = 0;"
7241      "for (var i = 0; i < 100; i++) {"
7242      "  result = receiver.method(41);"
7243      "  if (i == 50) {"
7244      "    saved_result = result;"
7245      "    receiver = {method: receiver.method};"
7246      "  }"
7247      "}");
7248  CHECK(try_catch.HasCaught());
7249  CHECK_EQ(v8_str("TypeError: Illegal invocation"),
7250           try_catch.Exception()->ToString());
7251  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7252  CHECK_GE(interceptor_call_count, 50);
7253}
7254
7255THREADED_TEST(CallICFastApi_TrivialSignature) {
7256  v8::HandleScope scope;
7257  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7258  v8::Handle<v8::FunctionTemplate> method_templ =
7259      v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
7260                                v8_str("method_data"),
7261                                v8::Handle<v8::Signature>());
7262  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7263  proto_templ->Set(v8_str("method"), method_templ);
7264  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7265  LocalContext context;
7266  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7267  GenerateSomeGarbage();
7268  context->Global()->Set(v8_str("o"), fun->NewInstance());
7269  v8::Handle<Value> value = CompileRun(
7270      "var result = 0;"
7271      "for (var i = 0; i < 100; i++) {"
7272      "  result = o.method(41);"
7273      "}");
7274
7275  CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
7276}
7277
7278THREADED_TEST(CallICFastApi_SimpleSignature) {
7279  v8::HandleScope scope;
7280  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7281  v8::Handle<v8::FunctionTemplate> method_templ =
7282      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7283                                v8_str("method_data"),
7284                                v8::Signature::New(fun_templ));
7285  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7286  proto_templ->Set(v8_str("method"), method_templ);
7287  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7288  LocalContext context;
7289  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7290  GenerateSomeGarbage();
7291  context->Global()->Set(v8_str("o"), fun->NewInstance());
7292  v8::Handle<Value> value = CompileRun(
7293      "o.foo = 17;"
7294      "var receiver = {};"
7295      "receiver.__proto__ = o;"
7296      "var result = 0;"
7297      "for (var i = 0; i < 100; i++) {"
7298      "  result = receiver.method(41);"
7299      "}");
7300
7301  CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
7302}
7303
7304THREADED_TEST(CallICFastApi_SimpleSignature_Miss1) {
7305  v8::HandleScope scope;
7306  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7307  v8::Handle<v8::FunctionTemplate> method_templ =
7308      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7309                                v8_str("method_data"),
7310                                v8::Signature::New(fun_templ));
7311  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7312  proto_templ->Set(v8_str("method"), method_templ);
7313  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7314  LocalContext context;
7315  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7316  GenerateSomeGarbage();
7317  context->Global()->Set(v8_str("o"), fun->NewInstance());
7318  v8::Handle<Value> value = CompileRun(
7319      "o.foo = 17;"
7320      "var receiver = {};"
7321      "receiver.__proto__ = o;"
7322      "var result = 0;"
7323      "var saved_result = 0;"
7324      "for (var i = 0; i < 100; i++) {"
7325      "  result = receiver.method(41);"
7326      "  if (i == 50) {"
7327      "    saved_result = result;"
7328      "    receiver = {method: function(x) { return x - 1 }};"
7329      "  }"
7330      "}");
7331  CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
7332  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7333}
7334
7335THREADED_TEST(CallICFastApi_SimpleSignature_Miss2) {
7336  v8::HandleScope scope;
7337  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7338  v8::Handle<v8::FunctionTemplate> method_templ =
7339      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7340                                v8_str("method_data"),
7341                                v8::Signature::New(fun_templ));
7342  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7343  proto_templ->Set(v8_str("method"), method_templ);
7344  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7345  LocalContext context;
7346  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7347  GenerateSomeGarbage();
7348  context->Global()->Set(v8_str("o"), fun->NewInstance());
7349  v8::TryCatch try_catch;
7350  v8::Handle<Value> value = CompileRun(
7351      "o.foo = 17;"
7352      "var receiver = {};"
7353      "receiver.__proto__ = o;"
7354      "var result = 0;"
7355      "var saved_result = 0;"
7356      "for (var i = 0; i < 100; i++) {"
7357      "  result = receiver.method(41);"
7358      "  if (i == 50) {"
7359      "    saved_result = result;"
7360      "    receiver = 333;"
7361      "  }"
7362      "}");
7363  CHECK(try_catch.HasCaught());
7364  CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
7365           try_catch.Exception()->ToString());
7366  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7367}
7368
7369
7370v8::Handle<Value> keyed_call_ic_function;
7371
7372static v8::Handle<Value> InterceptorKeyedCallICGetter(
7373    Local<String> name, const AccessorInfo& info) {
7374  ApiTestFuzzer::Fuzz();
7375  if (v8_str("x")->Equals(name)) {
7376    return keyed_call_ic_function;
7377  }
7378  return v8::Handle<Value>();
7379}
7380
7381
7382// Test the case when we stored cacheable lookup into
7383// a stub, but the function name changed (to another cacheable function).
7384THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
7385  v8::HandleScope scope;
7386  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7387  templ->SetNamedPropertyHandler(NoBlockGetterX);
7388  LocalContext context;
7389  context->Global()->Set(v8_str("o"), templ->NewInstance());
7390  v8::Handle<Value> value = CompileRun(
7391    "proto = new Object();"
7392    "proto.y = function(x) { return x + 1; };"
7393    "proto.z = function(x) { return x - 1; };"
7394    "o.__proto__ = proto;"
7395    "var result = 0;"
7396    "var method = 'y';"
7397    "for (var i = 0; i < 10; i++) {"
7398    "  if (i == 5) { method = 'z'; };"
7399    "  result += o[method](41);"
7400    "}");
7401  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
7402}
7403
7404
7405// Test the case when we stored cacheable lookup into
7406// a stub, but the function name changed (and the new function is present
7407// both before and after the interceptor in the prototype chain).
7408THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
7409  v8::HandleScope scope;
7410  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7411  templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
7412  LocalContext context;
7413  context->Global()->Set(v8_str("proto1"), templ->NewInstance());
7414  keyed_call_ic_function =
7415      v8_compile("function f(x) { return x - 1; }; f")->Run();
7416  v8::Handle<Value> value = CompileRun(
7417    "o = new Object();"
7418    "proto2 = new Object();"
7419    "o.y = function(x) { return x + 1; };"
7420    "proto2.y = function(x) { return x + 2; };"
7421    "o.__proto__ = proto1;"
7422    "proto1.__proto__ = proto2;"
7423    "var result = 0;"
7424    "var method = 'x';"
7425    "for (var i = 0; i < 10; i++) {"
7426    "  if (i == 5) { method = 'y'; };"
7427    "  result += o[method](41);"
7428    "}");
7429  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
7430}
7431
7432
7433// Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
7434// on the global object.
7435THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
7436  v8::HandleScope scope;
7437  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7438  templ->SetNamedPropertyHandler(NoBlockGetterX);
7439  LocalContext context;
7440  context->Global()->Set(v8_str("o"), templ->NewInstance());
7441  v8::Handle<Value> value = CompileRun(
7442    "function inc(x) { return x + 1; };"
7443    "inc(1);"
7444    "function dec(x) { return x - 1; };"
7445    "dec(1);"
7446    "o.__proto__ = this;"
7447    "this.__proto__.x = inc;"
7448    "this.__proto__.y = dec;"
7449    "var result = 0;"
7450    "var method = 'x';"
7451    "for (var i = 0; i < 10; i++) {"
7452    "  if (i == 5) { method = 'y'; };"
7453    "  result += o[method](41);"
7454    "}");
7455  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
7456}
7457
7458
7459// Test the case when actual function to call sits on global object.
7460THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
7461  v8::HandleScope scope;
7462  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7463  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
7464  LocalContext context;
7465  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
7466
7467  v8::Handle<Value> value = CompileRun(
7468    "function len(x) { return x.length; };"
7469    "o.__proto__ = this;"
7470    "var m = 'parseFloat';"
7471    "var result = 0;"
7472    "for (var i = 0; i < 10; i++) {"
7473    "  if (i == 5) {"
7474    "    m = 'len';"
7475    "    saved_result = result;"
7476    "  };"
7477    "  result = o[m]('239');"
7478    "}");
7479  CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
7480  CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7481}
7482
7483// Test the map transition before the interceptor.
7484THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
7485  v8::HandleScope scope;
7486  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7487  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
7488  LocalContext context;
7489  context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
7490
7491  v8::Handle<Value> value = CompileRun(
7492    "var o = new Object();"
7493    "o.__proto__ = proto;"
7494    "o.method = function(x) { return x + 1; };"
7495    "var m = 'method';"
7496    "var result = 0;"
7497    "for (var i = 0; i < 10; i++) {"
7498    "  if (i == 5) { o.method = function(x) { return x - 1; }; };"
7499    "  result += o[m](41);"
7500    "}");
7501  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
7502}
7503
7504
7505// Test the map transition after the interceptor.
7506THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
7507  v8::HandleScope scope;
7508  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7509  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
7510  LocalContext context;
7511  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
7512
7513  v8::Handle<Value> value = CompileRun(
7514    "var proto = new Object();"
7515    "o.__proto__ = proto;"
7516    "proto.method = function(x) { return x + 1; };"
7517    "var m = 'method';"
7518    "var result = 0;"
7519    "for (var i = 0; i < 10; i++) {"
7520    "  if (i == 5) { proto.method = function(x) { return x - 1; }; };"
7521    "  result += o[m](41);"
7522    "}");
7523  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
7524}
7525
7526
7527static int interceptor_call_count = 0;
7528
7529static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name,
7530                                                     const AccessorInfo& info) {
7531  ApiTestFuzzer::Fuzz();
7532  if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
7533    return call_ic_function2;
7534  }
7535  return v8::Handle<Value>();
7536}
7537
7538
7539// This test should hit load and call ICs for the interceptor case.
7540// Once in a while, the interceptor will reply that a property was not
7541// found in which case we should get a reference error.
7542THREADED_TEST(InterceptorICReferenceErrors) {
7543  v8::HandleScope scope;
7544  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7545  templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
7546  LocalContext context(0, templ, v8::Handle<Value>());
7547  call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
7548  v8::Handle<Value> value = CompileRun(
7549    "function f() {"
7550    "  for (var i = 0; i < 1000; i++) {"
7551    "    try { x; } catch(e) { return true; }"
7552    "  }"
7553    "  return false;"
7554    "};"
7555    "f();");
7556  CHECK_EQ(true, value->BooleanValue());
7557  interceptor_call_count = 0;
7558  value = CompileRun(
7559    "function g() {"
7560    "  for (var i = 0; i < 1000; i++) {"
7561    "    try { x(42); } catch(e) { return true; }"
7562    "  }"
7563    "  return false;"
7564    "};"
7565    "g();");
7566  CHECK_EQ(true, value->BooleanValue());
7567}
7568
7569
7570static int interceptor_ic_exception_get_count = 0;
7571
7572static v8::Handle<Value> InterceptorICExceptionGetter(
7573    Local<String> name,
7574    const AccessorInfo& info) {
7575  ApiTestFuzzer::Fuzz();
7576  if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
7577    return call_ic_function3;
7578  }
7579  if (interceptor_ic_exception_get_count == 20) {
7580    return v8::ThrowException(v8_num(42));
7581  }
7582  // Do not handle get for properties other than x.
7583  return v8::Handle<Value>();
7584}
7585
7586// Test interceptor load/call IC where the interceptor throws an
7587// exception once in a while.
7588THREADED_TEST(InterceptorICGetterExceptions) {
7589  interceptor_ic_exception_get_count = 0;
7590  v8::HandleScope scope;
7591  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7592  templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
7593  LocalContext context(0, templ, v8::Handle<Value>());
7594  call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
7595  v8::Handle<Value> value = CompileRun(
7596    "function f() {"
7597    "  for (var i = 0; i < 100; i++) {"
7598    "    try { x; } catch(e) { return true; }"
7599    "  }"
7600    "  return false;"
7601    "};"
7602    "f();");
7603  CHECK_EQ(true, value->BooleanValue());
7604  interceptor_ic_exception_get_count = 0;
7605  value = CompileRun(
7606    "function f() {"
7607    "  for (var i = 0; i < 100; i++) {"
7608    "    try { x(42); } catch(e) { return true; }"
7609    "  }"
7610    "  return false;"
7611    "};"
7612    "f();");
7613  CHECK_EQ(true, value->BooleanValue());
7614}
7615
7616
7617static int interceptor_ic_exception_set_count = 0;
7618
7619static v8::Handle<Value> InterceptorICExceptionSetter(
7620      Local<String> key, Local<Value> value, const AccessorInfo&) {
7621  ApiTestFuzzer::Fuzz();
7622  if (++interceptor_ic_exception_set_count > 20) {
7623    return v8::ThrowException(v8_num(42));
7624  }
7625  // Do not actually handle setting.
7626  return v8::Handle<Value>();
7627}
7628
7629// Test interceptor store IC where the interceptor throws an exception
7630// once in a while.
7631THREADED_TEST(InterceptorICSetterExceptions) {
7632  interceptor_ic_exception_set_count = 0;
7633  v8::HandleScope scope;
7634  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7635  templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
7636  LocalContext context(0, templ, v8::Handle<Value>());
7637  v8::Handle<Value> value = CompileRun(
7638    "function f() {"
7639    "  for (var i = 0; i < 100; i++) {"
7640    "    try { x = 42; } catch(e) { return true; }"
7641    "  }"
7642    "  return false;"
7643    "};"
7644    "f();");
7645  CHECK_EQ(true, value->BooleanValue());
7646}
7647
7648
7649// Test that we ignore null interceptors.
7650THREADED_TEST(NullNamedInterceptor) {
7651  v8::HandleScope scope;
7652  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7653  templ->SetNamedPropertyHandler(0);
7654  LocalContext context;
7655  templ->Set("x", v8_num(42));
7656  v8::Handle<v8::Object> obj = templ->NewInstance();
7657  context->Global()->Set(v8_str("obj"), obj);
7658  v8::Handle<Value> value = CompileRun("obj.x");
7659  CHECK(value->IsInt32());
7660  CHECK_EQ(42, value->Int32Value());
7661}
7662
7663
7664// Test that we ignore null interceptors.
7665THREADED_TEST(NullIndexedInterceptor) {
7666  v8::HandleScope scope;
7667  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7668  templ->SetIndexedPropertyHandler(0);
7669  LocalContext context;
7670  templ->Set("42", v8_num(42));
7671  v8::Handle<v8::Object> obj = templ->NewInstance();
7672  context->Global()->Set(v8_str("obj"), obj);
7673  v8::Handle<Value> value = CompileRun("obj[42]");
7674  CHECK(value->IsInt32());
7675  CHECK_EQ(42, value->Int32Value());
7676}
7677
7678
7679THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
7680  v8::HandleScope scope;
7681  v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
7682  templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
7683  LocalContext env;
7684  env->Global()->Set(v8_str("obj"),
7685                     templ->GetFunction()->NewInstance());
7686  ExpectTrue("obj.x === 42");
7687  ExpectTrue("!obj.propertyIsEnumerable('x')");
7688}
7689
7690
7691static v8::Handle<Value> ParentGetter(Local<String> name,
7692                                      const AccessorInfo& info) {
7693  ApiTestFuzzer::Fuzz();
7694  return v8_num(1);
7695}
7696
7697
7698static v8::Handle<Value> ChildGetter(Local<String> name,
7699                                     const AccessorInfo& info) {
7700  ApiTestFuzzer::Fuzz();
7701  return v8_num(42);
7702}
7703
7704
7705THREADED_TEST(Overriding) {
7706  v8::HandleScope scope;
7707  LocalContext context;
7708
7709  // Parent template.
7710  Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New();
7711  Local<ObjectTemplate> parent_instance_templ =
7712      parent_templ->InstanceTemplate();
7713  parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
7714
7715  // Template that inherits from the parent template.
7716  Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New();
7717  Local<ObjectTemplate> child_instance_templ =
7718      child_templ->InstanceTemplate();
7719  child_templ->Inherit(parent_templ);
7720  // Override 'f'.  The child version of 'f' should get called for child
7721  // instances.
7722  child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
7723  // Add 'g' twice.  The 'g' added last should get called for instances.
7724  child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
7725  child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
7726
7727  // Add 'h' as an accessor to the proto template with ReadOnly attributes
7728  // so 'h' can be shadowed on the instance object.
7729  Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
7730  child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
7731      v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
7732
7733  // Add 'i' as an accessor to the instance template with ReadOnly attributes
7734  // but the attribute does not have effect because it is duplicated with
7735  // NULL setter.
7736  child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
7737      v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
7738
7739
7740
7741  // Instantiate the child template.
7742  Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
7743
7744  // Check that the child function overrides the parent one.
7745  context->Global()->Set(v8_str("o"), instance);
7746  Local<Value> value = v8_compile("o.f")->Run();
7747  // Check that the 'g' that was added last is hit.
7748  CHECK_EQ(42, value->Int32Value());
7749  value = v8_compile("o.g")->Run();
7750  CHECK_EQ(42, value->Int32Value());
7751
7752  // Check 'h' can be shadowed.
7753  value = v8_compile("o.h = 3; o.h")->Run();
7754  CHECK_EQ(3, value->Int32Value());
7755
7756  // Check 'i' is cannot be shadowed or changed.
7757  value = v8_compile("o.i = 3; o.i")->Run();
7758  CHECK_EQ(42, value->Int32Value());
7759}
7760
7761
7762static v8::Handle<Value> IsConstructHandler(const v8::Arguments& args) {
7763  ApiTestFuzzer::Fuzz();
7764  if (args.IsConstructCall()) {
7765    return v8::Boolean::New(true);
7766  }
7767  return v8::Boolean::New(false);
7768}
7769
7770
7771THREADED_TEST(IsConstructCall) {
7772  v8::HandleScope scope;
7773
7774  // Function template with call handler.
7775  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
7776  templ->SetCallHandler(IsConstructHandler);
7777
7778  LocalContext context;
7779
7780  context->Global()->Set(v8_str("f"), templ->GetFunction());
7781  Local<Value> value = v8_compile("f()")->Run();
7782  CHECK(!value->BooleanValue());
7783  value = v8_compile("new f()")->Run();
7784  CHECK(value->BooleanValue());
7785}
7786
7787
7788THREADED_TEST(ObjectProtoToString) {
7789  v8::HandleScope scope;
7790  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
7791  templ->SetClassName(v8_str("MyClass"));
7792
7793  LocalContext context;
7794
7795  Local<String> customized_tostring = v8_str("customized toString");
7796
7797  // Replace Object.prototype.toString
7798  v8_compile("Object.prototype.toString = function() {"
7799                  "  return 'customized toString';"
7800                  "}")->Run();
7801
7802  // Normal ToString call should call replaced Object.prototype.toString
7803  Local<v8::Object> instance = templ->GetFunction()->NewInstance();
7804  Local<String> value = instance->ToString();
7805  CHECK(value->IsString() && value->Equals(customized_tostring));
7806
7807  // ObjectProtoToString should not call replace toString function.
7808  value = instance->ObjectProtoToString();
7809  CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
7810
7811  // Check global
7812  value = context->Global()->ObjectProtoToString();
7813  CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
7814
7815  // Check ordinary object
7816  Local<Value> object = v8_compile("new Object()")->Run();
7817  value = object.As<v8::Object>()->ObjectProtoToString();
7818  CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
7819}
7820
7821
7822THREADED_TEST(ObjectGetConstructorName) {
7823  v8::HandleScope scope;
7824  LocalContext context;
7825  v8_compile("function Parent() {};"
7826             "function Child() {};"
7827             "Child.prototype = new Parent();"
7828             "var outer = { inner: function() { } };"
7829             "var p = new Parent();"
7830             "var c = new Child();"
7831             "var x = new outer.inner();")->Run();
7832
7833  Local<v8::Value> p = context->Global()->Get(v8_str("p"));
7834  CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
7835      v8_str("Parent")));
7836
7837  Local<v8::Value> c = context->Global()->Get(v8_str("c"));
7838  CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
7839      v8_str("Child")));
7840
7841  Local<v8::Value> x = context->Global()->Get(v8_str("x"));
7842  CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
7843      v8_str("outer.inner")));
7844}
7845
7846
7847bool ApiTestFuzzer::fuzzing_ = false;
7848i::Semaphore* ApiTestFuzzer::all_tests_done_=
7849  i::OS::CreateSemaphore(0);
7850int ApiTestFuzzer::active_tests_;
7851int ApiTestFuzzer::tests_being_run_;
7852int ApiTestFuzzer::current_;
7853
7854
7855// We are in a callback and want to switch to another thread (if we
7856// are currently running the thread fuzzing test).
7857void ApiTestFuzzer::Fuzz() {
7858  if (!fuzzing_) return;
7859  ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
7860  test->ContextSwitch();
7861}
7862
7863
7864// Let the next thread go.  Since it is also waiting on the V8 lock it may
7865// not start immediately.
7866bool ApiTestFuzzer::NextThread() {
7867  int test_position = GetNextTestNumber();
7868  const char* test_name = RegisterThreadedTest::nth(current_)->name();
7869  if (test_position == current_) {
7870    if (kLogThreading)
7871      printf("Stay with %s\n", test_name);
7872    return false;
7873  }
7874  if (kLogThreading) {
7875    printf("Switch from %s to %s\n",
7876           test_name,
7877           RegisterThreadedTest::nth(test_position)->name());
7878  }
7879  current_ = test_position;
7880  RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal();
7881  return true;
7882}
7883
7884
7885void ApiTestFuzzer::Run() {
7886  // When it is our turn...
7887  gate_->Wait();
7888  {
7889    // ... get the V8 lock and start running the test.
7890    v8::Locker locker;
7891    CallTest();
7892  }
7893  // This test finished.
7894  active_ = false;
7895  active_tests_--;
7896  // If it was the last then signal that fact.
7897  if (active_tests_ == 0) {
7898    all_tests_done_->Signal();
7899  } else {
7900    // Otherwise select a new test and start that.
7901    NextThread();
7902  }
7903}
7904
7905
7906static unsigned linear_congruential_generator;
7907
7908
7909void ApiTestFuzzer::Setup(PartOfTest part) {
7910  linear_congruential_generator = i::FLAG_testing_prng_seed;
7911  fuzzing_ = true;
7912  int start = (part == FIRST_PART) ? 0 : (RegisterThreadedTest::count() >> 1);
7913  int end = (part == FIRST_PART)
7914      ? (RegisterThreadedTest::count() >> 1)
7915      : RegisterThreadedTest::count();
7916  active_tests_ = tests_being_run_ = end - start;
7917  for (int i = 0; i < tests_being_run_; i++) {
7918    RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
7919  }
7920  for (int i = 0; i < active_tests_; i++) {
7921    RegisterThreadedTest::nth(i)->fuzzer_->Start();
7922  }
7923}
7924
7925
7926static void CallTestNumber(int test_number) {
7927  (RegisterThreadedTest::nth(test_number)->callback())();
7928}
7929
7930
7931void ApiTestFuzzer::RunAllTests() {
7932  // Set off the first test.
7933  current_ = -1;
7934  NextThread();
7935  // Wait till they are all done.
7936  all_tests_done_->Wait();
7937}
7938
7939
7940int ApiTestFuzzer::GetNextTestNumber() {
7941  int next_test;
7942  do {
7943    next_test = (linear_congruential_generator >> 16) % tests_being_run_;
7944    linear_congruential_generator *= 1664525u;
7945    linear_congruential_generator += 1013904223u;
7946  } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
7947  return next_test;
7948}
7949
7950
7951void ApiTestFuzzer::ContextSwitch() {
7952  // If the new thread is the same as the current thread there is nothing to do.
7953  if (NextThread()) {
7954    // Now it can start.
7955    v8::Unlocker unlocker;
7956    // Wait till someone starts us again.
7957    gate_->Wait();
7958    // And we're off.
7959  }
7960}
7961
7962
7963void ApiTestFuzzer::TearDown() {
7964  fuzzing_ = false;
7965  for (int i = 0; i < RegisterThreadedTest::count(); i++) {
7966    ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
7967    if (fuzzer != NULL) fuzzer->Join();
7968  }
7969}
7970
7971
7972// Lets not be needlessly self-referential.
7973TEST(Threading) {
7974  ApiTestFuzzer::Setup(ApiTestFuzzer::FIRST_PART);
7975  ApiTestFuzzer::RunAllTests();
7976  ApiTestFuzzer::TearDown();
7977}
7978
7979TEST(Threading2) {
7980  ApiTestFuzzer::Setup(ApiTestFuzzer::SECOND_PART);
7981  ApiTestFuzzer::RunAllTests();
7982  ApiTestFuzzer::TearDown();
7983}
7984
7985
7986void ApiTestFuzzer::CallTest() {
7987  if (kLogThreading)
7988    printf("Start test %d\n", test_number_);
7989  CallTestNumber(test_number_);
7990  if (kLogThreading)
7991    printf("End test %d\n", test_number_);
7992}
7993
7994
7995static v8::Handle<Value> ThrowInJS(const v8::Arguments& args) {
7996  CHECK(v8::Locker::IsLocked());
7997  ApiTestFuzzer::Fuzz();
7998  v8::Unlocker unlocker;
7999  const char* code = "throw 7;";
8000  {
8001    v8::Locker nested_locker;
8002    v8::HandleScope scope;
8003    v8::Handle<Value> exception;
8004    { v8::TryCatch try_catch;
8005      v8::Handle<Value> value = CompileRun(code);
8006      CHECK(value.IsEmpty());
8007      CHECK(try_catch.HasCaught());
8008      // Make sure to wrap the exception in a new handle because
8009      // the handle returned from the TryCatch is destroyed
8010      // when the TryCatch is destroyed.
8011      exception = Local<Value>::New(try_catch.Exception());
8012    }
8013    return v8::ThrowException(exception);
8014  }
8015}
8016
8017
8018static v8::Handle<Value> ThrowInJSNoCatch(const v8::Arguments& args) {
8019  CHECK(v8::Locker::IsLocked());
8020  ApiTestFuzzer::Fuzz();
8021  v8::Unlocker unlocker;
8022  const char* code = "throw 7;";
8023  {
8024    v8::Locker nested_locker;
8025    v8::HandleScope scope;
8026    v8::Handle<Value> value = CompileRun(code);
8027    CHECK(value.IsEmpty());
8028    return v8_str("foo");
8029  }
8030}
8031
8032
8033// These are locking tests that don't need to be run again
8034// as part of the locking aggregation tests.
8035TEST(NestedLockers) {
8036  v8::Locker locker;
8037  CHECK(v8::Locker::IsLocked());
8038  v8::HandleScope scope;
8039  LocalContext env;
8040  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS);
8041  Local<Function> fun = fun_templ->GetFunction();
8042  env->Global()->Set(v8_str("throw_in_js"), fun);
8043  Local<Script> script = v8_compile("(function () {"
8044                                    "  try {"
8045                                    "    throw_in_js();"
8046                                    "    return 42;"
8047                                    "  } catch (e) {"
8048                                    "    return e * 13;"
8049                                    "  }"
8050                                    "})();");
8051  CHECK_EQ(91, script->Run()->Int32Value());
8052}
8053
8054
8055// These are locking tests that don't need to be run again
8056// as part of the locking aggregation tests.
8057TEST(NestedLockersNoTryCatch) {
8058  v8::Locker locker;
8059  v8::HandleScope scope;
8060  LocalContext env;
8061  Local<v8::FunctionTemplate> fun_templ =
8062      v8::FunctionTemplate::New(ThrowInJSNoCatch);
8063  Local<Function> fun = fun_templ->GetFunction();
8064  env->Global()->Set(v8_str("throw_in_js"), fun);
8065  Local<Script> script = v8_compile("(function () {"
8066                                    "  try {"
8067                                    "    throw_in_js();"
8068                                    "    return 42;"
8069                                    "  } catch (e) {"
8070                                    "    return e * 13;"
8071                                    "  }"
8072                                    "})();");
8073  CHECK_EQ(91, script->Run()->Int32Value());
8074}
8075
8076
8077THREADED_TEST(RecursiveLocking) {
8078  v8::Locker locker;
8079  {
8080    v8::Locker locker2;
8081    CHECK(v8::Locker::IsLocked());
8082  }
8083}
8084
8085
8086static v8::Handle<Value> UnlockForAMoment(const v8::Arguments& args) {
8087  ApiTestFuzzer::Fuzz();
8088  v8::Unlocker unlocker;
8089  return v8::Undefined();
8090}
8091
8092
8093THREADED_TEST(LockUnlockLock) {
8094  {
8095    v8::Locker locker;
8096    v8::HandleScope scope;
8097    LocalContext env;
8098    Local<v8::FunctionTemplate> fun_templ =
8099        v8::FunctionTemplate::New(UnlockForAMoment);
8100    Local<Function> fun = fun_templ->GetFunction();
8101    env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
8102    Local<Script> script = v8_compile("(function () {"
8103                                      "  unlock_for_a_moment();"
8104                                      "  return 42;"
8105                                      "})();");
8106    CHECK_EQ(42, script->Run()->Int32Value());
8107  }
8108  {
8109    v8::Locker locker;
8110    v8::HandleScope scope;
8111    LocalContext env;
8112    Local<v8::FunctionTemplate> fun_templ =
8113        v8::FunctionTemplate::New(UnlockForAMoment);
8114    Local<Function> fun = fun_templ->GetFunction();
8115    env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
8116    Local<Script> script = v8_compile("(function () {"
8117                                      "  unlock_for_a_moment();"
8118                                      "  return 42;"
8119                                      "})();");
8120    CHECK_EQ(42, script->Run()->Int32Value());
8121  }
8122}
8123
8124
8125static int GetGlobalObjectsCount() {
8126  int count = 0;
8127  i::HeapIterator it;
8128  for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
8129    if (object->IsJSGlobalObject()) count++;
8130  return count;
8131}
8132
8133
8134static void CheckSurvivingGlobalObjectsCount(int expected) {
8135  // We need to collect all garbage twice to be sure that everything
8136  // has been collected.  This is because inline caches are cleared in
8137  // the first garbage collection but some of the maps have already
8138  // been marked at that point.  Therefore some of the maps are not
8139  // collected until the second garbage collection.
8140  i::Heap::CollectAllGarbage(false);
8141  i::Heap::CollectAllGarbage(false);
8142  int count = GetGlobalObjectsCount();
8143#ifdef DEBUG
8144  if (count != expected) i::Heap::TracePathToGlobal();
8145#endif
8146  CHECK_EQ(expected, count);
8147}
8148
8149
8150TEST(DontLeakGlobalObjects) {
8151  // Regression test for issues 1139850 and 1174891.
8152
8153  v8::V8::Initialize();
8154
8155  for (int i = 0; i < 5; i++) {
8156    { v8::HandleScope scope;
8157      LocalContext context;
8158    }
8159    CheckSurvivingGlobalObjectsCount(0);
8160
8161    { v8::HandleScope scope;
8162      LocalContext context;
8163      v8_compile("Date")->Run();
8164    }
8165    CheckSurvivingGlobalObjectsCount(0);
8166
8167    { v8::HandleScope scope;
8168      LocalContext context;
8169      v8_compile("/aaa/")->Run();
8170    }
8171    CheckSurvivingGlobalObjectsCount(0);
8172
8173    { v8::HandleScope scope;
8174      const char* extension_list[] = { "v8/gc" };
8175      v8::ExtensionConfiguration extensions(1, extension_list);
8176      LocalContext context(&extensions);
8177      v8_compile("gc();")->Run();
8178    }
8179    CheckSurvivingGlobalObjectsCount(0);
8180  }
8181}
8182
8183
8184v8::Persistent<v8::Object> some_object;
8185v8::Persistent<v8::Object> bad_handle;
8186
8187void NewPersistentHandleCallback(v8::Persistent<v8::Value> handle, void*) {
8188  v8::HandleScope scope;
8189  bad_handle = v8::Persistent<v8::Object>::New(some_object);
8190  handle.Dispose();
8191}
8192
8193
8194THREADED_TEST(NewPersistentHandleFromWeakCallback) {
8195  LocalContext context;
8196
8197  v8::Persistent<v8::Object> handle1, handle2;
8198  {
8199    v8::HandleScope scope;
8200    some_object = v8::Persistent<v8::Object>::New(v8::Object::New());
8201    handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
8202    handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
8203  }
8204  // Note: order is implementation dependent alas: currently
8205  // global handle nodes are processed by PostGarbageCollectionProcessing
8206  // in reverse allocation order, so if second allocated handle is deleted,
8207  // weak callback of the first handle would be able to 'reallocate' it.
8208  handle1.MakeWeak(NULL, NewPersistentHandleCallback);
8209  handle2.Dispose();
8210  i::Heap::CollectAllGarbage(false);
8211}
8212
8213
8214v8::Persistent<v8::Object> to_be_disposed;
8215
8216void DisposeAndForceGcCallback(v8::Persistent<v8::Value> handle, void*) {
8217  to_be_disposed.Dispose();
8218  i::Heap::CollectAllGarbage(false);
8219  handle.Dispose();
8220}
8221
8222
8223THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
8224  LocalContext context;
8225
8226  v8::Persistent<v8::Object> handle1, handle2;
8227  {
8228    v8::HandleScope scope;
8229    handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
8230    handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
8231  }
8232  handle1.MakeWeak(NULL, DisposeAndForceGcCallback);
8233  to_be_disposed = handle2;
8234  i::Heap::CollectAllGarbage(false);
8235}
8236
8237void DisposingCallback(v8::Persistent<v8::Value> handle, void*) {
8238  handle.Dispose();
8239}
8240
8241void HandleCreatingCallback(v8::Persistent<v8::Value> handle, void*) {
8242  v8::HandleScope scope;
8243  v8::Persistent<v8::Object>::New(v8::Object::New());
8244  handle.Dispose();
8245}
8246
8247
8248THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
8249  LocalContext context;
8250
8251  v8::Persistent<v8::Object> handle1, handle2, handle3;
8252  {
8253    v8::HandleScope scope;
8254    handle3 = v8::Persistent<v8::Object>::New(v8::Object::New());
8255    handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
8256    handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
8257  }
8258  handle2.MakeWeak(NULL, DisposingCallback);
8259  handle3.MakeWeak(NULL, HandleCreatingCallback);
8260  i::Heap::CollectAllGarbage(false);
8261}
8262
8263
8264THREADED_TEST(CheckForCrossContextObjectLiterals) {
8265  v8::V8::Initialize();
8266
8267  const int nof = 2;
8268  const char* sources[nof] = {
8269    "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
8270    "Object()"
8271  };
8272
8273  for (int i = 0; i < nof; i++) {
8274    const char* source = sources[i];
8275    { v8::HandleScope scope;
8276      LocalContext context;
8277      CompileRun(source);
8278    }
8279    { v8::HandleScope scope;
8280      LocalContext context;
8281      CompileRun(source);
8282    }
8283  }
8284}
8285
8286
8287static v8::Handle<Value> NestedScope(v8::Persistent<Context> env) {
8288  v8::HandleScope inner;
8289  env->Enter();
8290  v8::Handle<Value> three = v8_num(3);
8291  v8::Handle<Value> value = inner.Close(three);
8292  env->Exit();
8293  return value;
8294}
8295
8296
8297THREADED_TEST(NestedHandleScopeAndContexts) {
8298  v8::HandleScope outer;
8299  v8::Persistent<Context> env = Context::New();
8300  env->Enter();
8301  v8::Handle<Value> value = NestedScope(env);
8302  v8::Handle<String> str = value->ToString();
8303  env->Exit();
8304  env.Dispose();
8305}
8306
8307
8308THREADED_TEST(ExternalAllocatedMemory) {
8309  v8::HandleScope outer;
8310  v8::Persistent<Context> env = Context::New();
8311  const int kSize = 1024*1024;
8312  CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize), kSize);
8313  CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize), 0);
8314}
8315
8316
8317THREADED_TEST(DisposeEnteredContext) {
8318  v8::HandleScope scope;
8319  LocalContext outer;
8320  { v8::Persistent<v8::Context> inner = v8::Context::New();
8321    inner->Enter();
8322    inner.Dispose();
8323    inner.Clear();
8324    inner->Exit();
8325  }
8326}
8327
8328
8329// Regression test for issue 54, object templates with internal fields
8330// but no accessors or interceptors did not get their internal field
8331// count set on instances.
8332THREADED_TEST(Regress54) {
8333  v8::HandleScope outer;
8334  LocalContext context;
8335  static v8::Persistent<v8::ObjectTemplate> templ;
8336  if (templ.IsEmpty()) {
8337    v8::HandleScope inner;
8338    v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New();
8339    local->SetInternalFieldCount(1);
8340    templ = v8::Persistent<v8::ObjectTemplate>::New(inner.Close(local));
8341  }
8342  v8::Handle<v8::Object> result = templ->NewInstance();
8343  CHECK_EQ(1, result->InternalFieldCount());
8344}
8345
8346
8347// If part of the threaded tests, this test makes ThreadingTest fail
8348// on mac.
8349TEST(CatchStackOverflow) {
8350  v8::HandleScope scope;
8351  LocalContext context;
8352  v8::TryCatch try_catch;
8353  v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(
8354    "function f() {"
8355    "  return f();"
8356    "}"
8357    ""
8358    "f();"));
8359  v8::Handle<v8::Value> result = script->Run();
8360  CHECK(result.IsEmpty());
8361}
8362
8363
8364static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
8365                                    const char* resource_name,
8366                                    int line_offset) {
8367  v8::HandleScope scope;
8368  v8::TryCatch try_catch;
8369  v8::Handle<v8::Value> result = script->Run();
8370  CHECK(result.IsEmpty());
8371  CHECK(try_catch.HasCaught());
8372  v8::Handle<v8::Message> message = try_catch.Message();
8373  CHECK(!message.IsEmpty());
8374  CHECK_EQ(10 + line_offset, message->GetLineNumber());
8375  CHECK_EQ(91, message->GetStartPosition());
8376  CHECK_EQ(92, message->GetEndPosition());
8377  CHECK_EQ(2, message->GetStartColumn());
8378  CHECK_EQ(3, message->GetEndColumn());
8379  v8::String::AsciiValue line(message->GetSourceLine());
8380  CHECK_EQ("  throw 'nirk';", *line);
8381  v8::String::AsciiValue name(message->GetScriptResourceName());
8382  CHECK_EQ(resource_name, *name);
8383}
8384
8385
8386THREADED_TEST(TryCatchSourceInfo) {
8387  v8::HandleScope scope;
8388  LocalContext context;
8389  v8::Handle<v8::String> source = v8::String::New(
8390      "function Foo() {\n"
8391      "  return Bar();\n"
8392      "}\n"
8393      "\n"
8394      "function Bar() {\n"
8395      "  return Baz();\n"
8396      "}\n"
8397      "\n"
8398      "function Baz() {\n"
8399      "  throw 'nirk';\n"
8400      "}\n"
8401      "\n"
8402      "Foo();\n");
8403
8404  const char* resource_name;
8405  v8::Handle<v8::Script> script;
8406  resource_name = "test.js";
8407  script = v8::Script::Compile(source, v8::String::New(resource_name));
8408  CheckTryCatchSourceInfo(script, resource_name, 0);
8409
8410  resource_name = "test1.js";
8411  v8::ScriptOrigin origin1(v8::String::New(resource_name));
8412  script = v8::Script::Compile(source, &origin1);
8413  CheckTryCatchSourceInfo(script, resource_name, 0);
8414
8415  resource_name = "test2.js";
8416  v8::ScriptOrigin origin2(v8::String::New(resource_name), v8::Integer::New(7));
8417  script = v8::Script::Compile(source, &origin2);
8418  CheckTryCatchSourceInfo(script, resource_name, 7);
8419}
8420
8421
8422THREADED_TEST(CompilationCache) {
8423  v8::HandleScope scope;
8424  LocalContext context;
8425  v8::Handle<v8::String> source0 = v8::String::New("1234");
8426  v8::Handle<v8::String> source1 = v8::String::New("1234");
8427  v8::Handle<v8::Script> script0 =
8428      v8::Script::Compile(source0, v8::String::New("test.js"));
8429  v8::Handle<v8::Script> script1 =
8430      v8::Script::Compile(source1, v8::String::New("test.js"));
8431  v8::Handle<v8::Script> script2 =
8432      v8::Script::Compile(source0);  // different origin
8433  CHECK_EQ(1234, script0->Run()->Int32Value());
8434  CHECK_EQ(1234, script1->Run()->Int32Value());
8435  CHECK_EQ(1234, script2->Run()->Int32Value());
8436}
8437
8438
8439static v8::Handle<Value> FunctionNameCallback(const v8::Arguments& args) {
8440  ApiTestFuzzer::Fuzz();
8441  return v8_num(42);
8442}
8443
8444
8445THREADED_TEST(CallbackFunctionName) {
8446  v8::HandleScope scope;
8447  LocalContext context;
8448  Local<ObjectTemplate> t = ObjectTemplate::New();
8449  t->Set(v8_str("asdf"), v8::FunctionTemplate::New(FunctionNameCallback));
8450  context->Global()->Set(v8_str("obj"), t->NewInstance());
8451  v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
8452  CHECK(value->IsString());
8453  v8::String::AsciiValue name(value);
8454  CHECK_EQ("asdf", *name);
8455}
8456
8457
8458THREADED_TEST(DateAccess) {
8459  v8::HandleScope scope;
8460  LocalContext context;
8461  v8::Handle<v8::Value> date = v8::Date::New(1224744689038.0);
8462  CHECK(date->IsDate());
8463  CHECK_EQ(1224744689038.0, date.As<v8::Date>()->NumberValue());
8464}
8465
8466
8467void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) {
8468  v8::Handle<v8::Object> obj = val.As<v8::Object>();
8469  v8::Handle<v8::Array> props = obj->GetPropertyNames();
8470  CHECK_EQ(elmc, props->Length());
8471  for (int i = 0; i < elmc; i++) {
8472    v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
8473    CHECK_EQ(elmv[i], *elm);
8474  }
8475}
8476
8477
8478THREADED_TEST(PropertyEnumeration) {
8479  v8::HandleScope scope;
8480  LocalContext context;
8481  v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
8482      "var result = [];"
8483      "result[0] = {};"
8484      "result[1] = {a: 1, b: 2};"
8485      "result[2] = [1, 2, 3];"
8486      "var proto = {x: 1, y: 2, z: 3};"
8487      "var x = { __proto__: proto, w: 0, z: 1 };"
8488      "result[3] = x;"
8489      "result;"))->Run();
8490  v8::Handle<v8::Array> elms = obj.As<v8::Array>();
8491  CHECK_EQ(4, elms->Length());
8492  int elmc0 = 0;
8493  const char** elmv0 = NULL;
8494  CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
8495  int elmc1 = 2;
8496  const char* elmv1[] = {"a", "b"};
8497  CheckProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
8498  int elmc2 = 3;
8499  const char* elmv2[] = {"0", "1", "2"};
8500  CheckProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
8501  int elmc3 = 4;
8502  const char* elmv3[] = {"w", "z", "x", "y"};
8503  CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3);
8504}
8505
8506
8507static bool NamedSetAccessBlocker(Local<v8::Object> obj,
8508                                  Local<Value> name,
8509                                  v8::AccessType type,
8510                                  Local<Value> data) {
8511  return type != v8::ACCESS_SET;
8512}
8513
8514
8515static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
8516                                    uint32_t key,
8517                                    v8::AccessType type,
8518                                    Local<Value> data) {
8519  return type != v8::ACCESS_SET;
8520}
8521
8522
8523THREADED_TEST(DisableAccessChecksWhileConfiguring) {
8524  v8::HandleScope scope;
8525  LocalContext context;
8526  Local<ObjectTemplate> templ = ObjectTemplate::New();
8527  templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
8528                                 IndexedSetAccessBlocker);
8529  templ->Set(v8_str("x"), v8::True());
8530  Local<v8::Object> instance = templ->NewInstance();
8531  context->Global()->Set(v8_str("obj"), instance);
8532  Local<Value> value = CompileRun("obj.x");
8533  CHECK(value->BooleanValue());
8534}
8535
8536
8537static bool NamedGetAccessBlocker(Local<v8::Object> obj,
8538                                  Local<Value> name,
8539                                  v8::AccessType type,
8540                                  Local<Value> data) {
8541  return false;
8542}
8543
8544
8545static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
8546                                    uint32_t key,
8547                                    v8::AccessType type,
8548                                    Local<Value> data) {
8549  return false;
8550}
8551
8552
8553
8554THREADED_TEST(AccessChecksReenabledCorrectly) {
8555  v8::HandleScope scope;
8556  LocalContext context;
8557  Local<ObjectTemplate> templ = ObjectTemplate::New();
8558  templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
8559                                 IndexedGetAccessBlocker);
8560  templ->Set(v8_str("a"), v8_str("a"));
8561  // Add more than 8 (see kMaxFastProperties) properties
8562  // so that the constructor will force copying map.
8563  // Cannot sprintf, gcc complains unsafety.
8564  char buf[4];
8565  for (char i = '0'; i <= '9' ; i++) {
8566    buf[0] = i;
8567    for (char j = '0'; j <= '9'; j++) {
8568      buf[1] = j;
8569      for (char k = '0'; k <= '9'; k++) {
8570        buf[2] = k;
8571        buf[3] = 0;
8572        templ->Set(v8_str(buf), v8::Number::New(k));
8573      }
8574    }
8575  }
8576
8577  Local<v8::Object> instance_1 = templ->NewInstance();
8578  context->Global()->Set(v8_str("obj_1"), instance_1);
8579
8580  Local<Value> value_1 = CompileRun("obj_1.a");
8581  CHECK(value_1->IsUndefined());
8582
8583  Local<v8::Object> instance_2 = templ->NewInstance();
8584  context->Global()->Set(v8_str("obj_2"), instance_2);
8585
8586  Local<Value> value_2 = CompileRun("obj_2.a");
8587  CHECK(value_2->IsUndefined());
8588}
8589
8590
8591// This tests that access check information remains on the global
8592// object template when creating contexts.
8593THREADED_TEST(AccessControlRepeatedContextCreation) {
8594  v8::HandleScope handle_scope;
8595  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
8596  global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
8597                                           IndexedSetAccessBlocker);
8598  i::Handle<i::ObjectTemplateInfo> internal_template =
8599      v8::Utils::OpenHandle(*global_template);
8600  CHECK(!internal_template->constructor()->IsUndefined());
8601  i::Handle<i::FunctionTemplateInfo> constructor(
8602      i::FunctionTemplateInfo::cast(internal_template->constructor()));
8603  CHECK(!constructor->access_check_info()->IsUndefined());
8604  v8::Persistent<Context> context0 = Context::New(NULL, global_template);
8605  CHECK(!constructor->access_check_info()->IsUndefined());
8606}
8607
8608
8609THREADED_TEST(TurnOnAccessCheck) {
8610  v8::HandleScope handle_scope;
8611
8612  // Create an environment with access check to the global object disabled by
8613  // default.
8614  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
8615  global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
8616                                           IndexedGetAccessBlocker,
8617                                           v8::Handle<v8::Value>(),
8618                                           false);
8619  v8::Persistent<Context> context = Context::New(NULL, global_template);
8620  Context::Scope context_scope(context);
8621
8622  // Set up a property and a number of functions.
8623  context->Global()->Set(v8_str("a"), v8_num(1));
8624  CompileRun("function f1() {return a;}"
8625             "function f2() {return a;}"
8626             "function g1() {return h();}"
8627             "function g2() {return h();}"
8628             "function h() {return 1;}");
8629  Local<Function> f1 =
8630      Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
8631  Local<Function> f2 =
8632      Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
8633  Local<Function> g1 =
8634      Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
8635  Local<Function> g2 =
8636      Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
8637  Local<Function> h =
8638      Local<Function>::Cast(context->Global()->Get(v8_str("h")));
8639
8640  // Get the global object.
8641  v8::Handle<v8::Object> global = context->Global();
8642
8643  // Call f1 one time and f2 a number of times. This will ensure that f1 still
8644  // uses the runtime system to retreive property a whereas f2 uses global load
8645  // inline cache.
8646  CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
8647  for (int i = 0; i < 4; i++) {
8648    CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
8649  }
8650
8651  // Same for g1 and g2.
8652  CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
8653  for (int i = 0; i < 4; i++) {
8654    CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
8655  }
8656
8657  // Detach the global and turn on access check.
8658  context->DetachGlobal();
8659  context->Global()->TurnOnAccessCheck();
8660
8661  // Failing access check to property get results in undefined.
8662  CHECK(f1->Call(global, 0, NULL)->IsUndefined());
8663  CHECK(f2->Call(global, 0, NULL)->IsUndefined());
8664
8665  // Failing access check to function call results in exception.
8666  CHECK(g1->Call(global, 0, NULL).IsEmpty());
8667  CHECK(g2->Call(global, 0, NULL).IsEmpty());
8668
8669  // No failing access check when just returning a constant.
8670  CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
8671}
8672
8673
8674// This test verifies that pre-compilation (aka preparsing) can be called
8675// without initializing the whole VM. Thus we cannot run this test in a
8676// multi-threaded setup.
8677TEST(PreCompile) {
8678  // TODO(155): This test would break without the initialization of V8. This is
8679  // a workaround for now to make this test not fail.
8680  v8::V8::Initialize();
8681  const char* script = "function foo(a) { return a+1; }";
8682  v8::ScriptData* sd =
8683      v8::ScriptData::PreCompile(script, i::StrLength(script));
8684  CHECK_NE(sd->Length(), 0);
8685  CHECK_NE(sd->Data(), NULL);
8686  CHECK(!sd->HasError());
8687  delete sd;
8688}
8689
8690
8691TEST(PreCompileWithError) {
8692  v8::V8::Initialize();
8693  const char* script = "function foo(a) { return 1 * * 2; }";
8694  v8::ScriptData* sd =
8695      v8::ScriptData::PreCompile(script, i::StrLength(script));
8696  CHECK(sd->HasError());
8697  delete sd;
8698}
8699
8700
8701TEST(Regress31661) {
8702  v8::V8::Initialize();
8703  const char* script = " The Definintive Guide";
8704  v8::ScriptData* sd =
8705      v8::ScriptData::PreCompile(script, i::StrLength(script));
8706  CHECK(sd->HasError());
8707  delete sd;
8708}
8709
8710
8711// Tests that ScriptData can be serialized and deserialized.
8712TEST(PreCompileSerialization) {
8713  v8::V8::Initialize();
8714  const char* script = "function foo(a) { return a+1; }";
8715  v8::ScriptData* sd =
8716      v8::ScriptData::PreCompile(script, i::StrLength(script));
8717
8718  // Serialize.
8719  int serialized_data_length = sd->Length();
8720  char* serialized_data = i::NewArray<char>(serialized_data_length);
8721  memcpy(serialized_data, sd->Data(), serialized_data_length);
8722
8723  // Deserialize.
8724  v8::ScriptData* deserialized_sd =
8725      v8::ScriptData::New(serialized_data, serialized_data_length);
8726
8727  // Verify that the original is the same as the deserialized.
8728  CHECK_EQ(sd->Length(), deserialized_sd->Length());
8729  CHECK_EQ(0, memcmp(sd->Data(), deserialized_sd->Data(), sd->Length()));
8730  CHECK_EQ(sd->HasError(), deserialized_sd->HasError());
8731
8732  delete sd;
8733  delete deserialized_sd;
8734}
8735
8736
8737// Attempts to deserialize bad data.
8738TEST(PreCompileDeserializationError) {
8739  v8::V8::Initialize();
8740  const char* data = "DONT CARE";
8741  int invalid_size = 3;
8742  v8::ScriptData* sd = v8::ScriptData::New(data, invalid_size);
8743
8744  CHECK_EQ(0, sd->Length());
8745
8746  delete sd;
8747}
8748
8749
8750// Attempts to deserialize bad data.
8751TEST(PreCompileInvalidPreparseDataError) {
8752  v8::V8::Initialize();
8753  v8::HandleScope scope;
8754  LocalContext context;
8755
8756  const char* script = "function foo(){ return 5;}\n"
8757      "function bar(){ return 6 + 7;}  foo();";
8758  v8::ScriptData* sd =
8759      v8::ScriptData::PreCompile(script, i::StrLength(script));
8760  CHECK(!sd->HasError());
8761  // ScriptDataImpl private implementation details
8762  const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
8763  const int kFunctionEntrySize = i::FunctionEntry::kSize;
8764  const int kFunctionEntryStartOffset = 0;
8765  const int kFunctionEntryEndOffset = 1;
8766  unsigned* sd_data =
8767      reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
8768
8769  // Overwrite function bar's end position with 0.
8770  sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
8771  v8::TryCatch try_catch;
8772
8773  Local<String> source = String::New(script);
8774  Local<Script> compiled_script = Script::New(source, NULL, sd);
8775  CHECK(try_catch.HasCaught());
8776  String::AsciiValue exception_value(try_catch.Message()->Get());
8777  CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
8778           *exception_value);
8779
8780  try_catch.Reset();
8781  // Overwrite function bar's start position with 200.  The function entry
8782  // will not be found when searching for it by position.
8783  sd = v8::ScriptData::PreCompile(script, i::StrLength(script));
8784  sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
8785  sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
8786      200;
8787  compiled_script = Script::New(source, NULL, sd);
8788  CHECK(try_catch.HasCaught());
8789  String::AsciiValue second_exception_value(try_catch.Message()->Get());
8790  CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
8791           *second_exception_value);
8792
8793  delete sd;
8794}
8795
8796
8797// Verifies that the Handle<String> and const char* versions of the API produce
8798// the same results (at least for one trivial case).
8799TEST(PreCompileAPIVariationsAreSame) {
8800  v8::V8::Initialize();
8801  v8::HandleScope scope;
8802
8803  const char* cstring = "function foo(a) { return a+1; }";
8804
8805  v8::ScriptData* sd_from_cstring =
8806      v8::ScriptData::PreCompile(cstring, i::StrLength(cstring));
8807
8808  TestAsciiResource* resource = new TestAsciiResource(cstring);
8809  v8::ScriptData* sd_from_external_string = v8::ScriptData::PreCompile(
8810      v8::String::NewExternal(resource));
8811
8812  v8::ScriptData* sd_from_string = v8::ScriptData::PreCompile(
8813      v8::String::New(cstring));
8814
8815  CHECK_EQ(sd_from_cstring->Length(), sd_from_external_string->Length());
8816  CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
8817                     sd_from_external_string->Data(),
8818                     sd_from_cstring->Length()));
8819
8820  CHECK_EQ(sd_from_cstring->Length(), sd_from_string->Length());
8821  CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
8822                     sd_from_string->Data(),
8823                     sd_from_cstring->Length()));
8824
8825
8826  delete sd_from_cstring;
8827  delete sd_from_external_string;
8828  delete sd_from_string;
8829}
8830
8831
8832// This tests that we do not allow dictionary load/call inline caches
8833// to use functions that have not yet been compiled.  The potential
8834// problem of loading a function that has not yet been compiled can
8835// arise because we share code between contexts via the compilation
8836// cache.
8837THREADED_TEST(DictionaryICLoadedFunction) {
8838  v8::HandleScope scope;
8839  // Test LoadIC.
8840  for (int i = 0; i < 2; i++) {
8841    LocalContext context;
8842    context->Global()->Set(v8_str("tmp"), v8::True());
8843    context->Global()->Delete(v8_str("tmp"));
8844    CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
8845  }
8846  // Test CallIC.
8847  for (int i = 0; i < 2; i++) {
8848    LocalContext context;
8849    context->Global()->Set(v8_str("tmp"), v8::True());
8850    context->Global()->Delete(v8_str("tmp"));
8851    CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
8852  }
8853}
8854
8855
8856// Test that cross-context new calls use the context of the callee to
8857// create the new JavaScript object.
8858THREADED_TEST(CrossContextNew) {
8859  v8::HandleScope scope;
8860  v8::Persistent<Context> context0 = Context::New();
8861  v8::Persistent<Context> context1 = Context::New();
8862
8863  // Allow cross-domain access.
8864  Local<String> token = v8_str("<security token>");
8865  context0->SetSecurityToken(token);
8866  context1->SetSecurityToken(token);
8867
8868  // Set an 'x' property on the Object prototype and define a
8869  // constructor function in context0.
8870  context0->Enter();
8871  CompileRun("Object.prototype.x = 42; function C() {};");
8872  context0->Exit();
8873
8874  // Call the constructor function from context0 and check that the
8875  // result has the 'x' property.
8876  context1->Enter();
8877  context1->Global()->Set(v8_str("other"), context0->Global());
8878  Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
8879  CHECK(value->IsInt32());
8880  CHECK_EQ(42, value->Int32Value());
8881  context1->Exit();
8882
8883  // Dispose the contexts to allow them to be garbage collected.
8884  context0.Dispose();
8885  context1.Dispose();
8886}
8887
8888
8889class RegExpInterruptTest {
8890 public:
8891  RegExpInterruptTest() : block_(NULL) {}
8892  ~RegExpInterruptTest() { delete block_; }
8893  void RunTest() {
8894    block_ = i::OS::CreateSemaphore(0);
8895    gc_count_ = 0;
8896    gc_during_regexp_ = 0;
8897    regexp_success_ = false;
8898    gc_success_ = false;
8899    GCThread gc_thread(this);
8900    gc_thread.Start();
8901    v8::Locker::StartPreemption(1);
8902
8903    LongRunningRegExp();
8904    {
8905      v8::Unlocker unlock;
8906      gc_thread.Join();
8907    }
8908    v8::Locker::StopPreemption();
8909    CHECK(regexp_success_);
8910    CHECK(gc_success_);
8911  }
8912 private:
8913  // Number of garbage collections required.
8914  static const int kRequiredGCs = 5;
8915
8916  class GCThread : public i::Thread {
8917   public:
8918    explicit GCThread(RegExpInterruptTest* test)
8919        : test_(test) {}
8920    virtual void Run() {
8921      test_->CollectGarbage();
8922    }
8923   private:
8924     RegExpInterruptTest* test_;
8925  };
8926
8927  void CollectGarbage() {
8928    block_->Wait();
8929    while (gc_during_regexp_ < kRequiredGCs) {
8930      {
8931        v8::Locker lock;
8932        // TODO(lrn): Perhaps create some garbage before collecting.
8933        i::Heap::CollectAllGarbage(false);
8934        gc_count_++;
8935      }
8936      i::OS::Sleep(1);
8937    }
8938    gc_success_ = true;
8939  }
8940
8941  void LongRunningRegExp() {
8942    block_->Signal();  // Enable garbage collection thread on next preemption.
8943    int rounds = 0;
8944    while (gc_during_regexp_ < kRequiredGCs) {
8945      int gc_before = gc_count_;
8946      {
8947        // Match 15-30 "a"'s against 14 and a "b".
8948        const char* c_source =
8949            "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
8950            ".exec('aaaaaaaaaaaaaaab') === null";
8951        Local<String> source = String::New(c_source);
8952        Local<Script> script = Script::Compile(source);
8953        Local<Value> result = script->Run();
8954        if (!result->BooleanValue()) {
8955          gc_during_regexp_ = kRequiredGCs;  // Allow gc thread to exit.
8956          return;
8957        }
8958      }
8959      {
8960        // Match 15-30 "a"'s against 15 and a "b".
8961        const char* c_source =
8962            "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
8963            ".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'";
8964        Local<String> source = String::New(c_source);
8965        Local<Script> script = Script::Compile(source);
8966        Local<Value> result = script->Run();
8967        if (!result->BooleanValue()) {
8968          gc_during_regexp_ = kRequiredGCs;
8969          return;
8970        }
8971      }
8972      int gc_after = gc_count_;
8973      gc_during_regexp_ += gc_after - gc_before;
8974      rounds++;
8975      i::OS::Sleep(1);
8976    }
8977    regexp_success_ = true;
8978  }
8979
8980  i::Semaphore* block_;
8981  int gc_count_;
8982  int gc_during_regexp_;
8983  bool regexp_success_;
8984  bool gc_success_;
8985};
8986
8987
8988// Test that a regular expression execution can be interrupted and
8989// survive a garbage collection.
8990TEST(RegExpInterruption) {
8991  v8::Locker lock;
8992  v8::V8::Initialize();
8993  v8::HandleScope scope;
8994  Local<Context> local_env;
8995  {
8996    LocalContext env;
8997    local_env = env.local();
8998  }
8999
9000  // Local context should still be live.
9001  CHECK(!local_env.IsEmpty());
9002  local_env->Enter();
9003
9004  // Should complete without problems.
9005  RegExpInterruptTest().RunTest();
9006
9007  local_env->Exit();
9008}
9009
9010
9011class ApplyInterruptTest {
9012 public:
9013  ApplyInterruptTest() : block_(NULL) {}
9014  ~ApplyInterruptTest() { delete block_; }
9015  void RunTest() {
9016    block_ = i::OS::CreateSemaphore(0);
9017    gc_count_ = 0;
9018    gc_during_apply_ = 0;
9019    apply_success_ = false;
9020    gc_success_ = false;
9021    GCThread gc_thread(this);
9022    gc_thread.Start();
9023    v8::Locker::StartPreemption(1);
9024
9025    LongRunningApply();
9026    {
9027      v8::Unlocker unlock;
9028      gc_thread.Join();
9029    }
9030    v8::Locker::StopPreemption();
9031    CHECK(apply_success_);
9032    CHECK(gc_success_);
9033  }
9034 private:
9035  // Number of garbage collections required.
9036  static const int kRequiredGCs = 2;
9037
9038  class GCThread : public i::Thread {
9039   public:
9040    explicit GCThread(ApplyInterruptTest* test)
9041        : test_(test) {}
9042    virtual void Run() {
9043      test_->CollectGarbage();
9044    }
9045   private:
9046     ApplyInterruptTest* test_;
9047  };
9048
9049  void CollectGarbage() {
9050    block_->Wait();
9051    while (gc_during_apply_ < kRequiredGCs) {
9052      {
9053        v8::Locker lock;
9054        i::Heap::CollectAllGarbage(false);
9055        gc_count_++;
9056      }
9057      i::OS::Sleep(1);
9058    }
9059    gc_success_ = true;
9060  }
9061
9062  void LongRunningApply() {
9063    block_->Signal();
9064    int rounds = 0;
9065    while (gc_during_apply_ < kRequiredGCs) {
9066      int gc_before = gc_count_;
9067      {
9068        const char* c_source =
9069            "function do_very_little(bar) {"
9070            "  this.foo = bar;"
9071            "}"
9072            "for (var i = 0; i < 100000; i++) {"
9073            "  do_very_little.apply(this, ['bar']);"
9074            "}";
9075        Local<String> source = String::New(c_source);
9076        Local<Script> script = Script::Compile(source);
9077        Local<Value> result = script->Run();
9078        // Check that no exception was thrown.
9079        CHECK(!result.IsEmpty());
9080      }
9081      int gc_after = gc_count_;
9082      gc_during_apply_ += gc_after - gc_before;
9083      rounds++;
9084    }
9085    apply_success_ = true;
9086  }
9087
9088  i::Semaphore* block_;
9089  int gc_count_;
9090  int gc_during_apply_;
9091  bool apply_success_;
9092  bool gc_success_;
9093};
9094
9095
9096// Test that nothing bad happens if we get a preemption just when we were
9097// about to do an apply().
9098TEST(ApplyInterruption) {
9099  v8::Locker lock;
9100  v8::V8::Initialize();
9101  v8::HandleScope scope;
9102  Local<Context> local_env;
9103  {
9104    LocalContext env;
9105    local_env = env.local();
9106  }
9107
9108  // Local context should still be live.
9109  CHECK(!local_env.IsEmpty());
9110  local_env->Enter();
9111
9112  // Should complete without problems.
9113  ApplyInterruptTest().RunTest();
9114
9115  local_env->Exit();
9116}
9117
9118
9119// Verify that we can clone an object
9120TEST(ObjectClone) {
9121  v8::HandleScope scope;
9122  LocalContext env;
9123
9124  const char* sample =
9125    "var rv = {};"      \
9126    "rv.alpha = 'hello';" \
9127    "rv.beta = 123;"     \
9128    "rv;";
9129
9130  // Create an object, verify basics.
9131  Local<Value> val = CompileRun(sample);
9132  CHECK(val->IsObject());
9133  Local<v8::Object> obj = val.As<v8::Object>();
9134  obj->Set(v8_str("gamma"), v8_str("cloneme"));
9135
9136  CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
9137  CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
9138  CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
9139
9140  // Clone it.
9141  Local<v8::Object> clone = obj->Clone();
9142  CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
9143  CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta")));
9144  CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
9145
9146  // Set a property on the clone, verify each object.
9147  clone->Set(v8_str("beta"), v8::Integer::New(456));
9148  CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
9149  CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta")));
9150}
9151
9152
9153class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
9154 public:
9155  explicit AsciiVectorResource(i::Vector<const char> vector)
9156      : data_(vector) {}
9157  virtual ~AsciiVectorResource() {}
9158  virtual size_t length() const { return data_.length(); }
9159  virtual const char* data() const { return data_.start(); }
9160 private:
9161  i::Vector<const char> data_;
9162};
9163
9164
9165class UC16VectorResource : public v8::String::ExternalStringResource {
9166 public:
9167  explicit UC16VectorResource(i::Vector<const i::uc16> vector)
9168      : data_(vector) {}
9169  virtual ~UC16VectorResource() {}
9170  virtual size_t length() const { return data_.length(); }
9171  virtual const i::uc16* data() const { return data_.start(); }
9172 private:
9173  i::Vector<const i::uc16> data_;
9174};
9175
9176
9177static void MorphAString(i::String* string,
9178                         AsciiVectorResource* ascii_resource,
9179                         UC16VectorResource* uc16_resource) {
9180  CHECK(i::StringShape(string).IsExternal());
9181  if (string->IsAsciiRepresentation()) {
9182    // Check old map is not symbol or long.
9183    CHECK(string->map() == i::Heap::external_ascii_string_map());
9184    // Morph external string to be TwoByte string.
9185    string->set_map(i::Heap::external_string_map());
9186    i::ExternalTwoByteString* morphed =
9187         i::ExternalTwoByteString::cast(string);
9188    morphed->set_resource(uc16_resource);
9189  } else {
9190    // Check old map is not symbol or long.
9191    CHECK(string->map() == i::Heap::external_string_map());
9192    // Morph external string to be ASCII string.
9193    string->set_map(i::Heap::external_ascii_string_map());
9194    i::ExternalAsciiString* morphed =
9195         i::ExternalAsciiString::cast(string);
9196    morphed->set_resource(ascii_resource);
9197  }
9198}
9199
9200
9201// Test that we can still flatten a string if the components it is built up
9202// from have been turned into 16 bit strings in the mean time.
9203THREADED_TEST(MorphCompositeStringTest) {
9204  const char* c_string = "Now is the time for all good men"
9205                         " to come to the aid of the party";
9206  uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
9207  {
9208    v8::HandleScope scope;
9209    LocalContext env;
9210    AsciiVectorResource ascii_resource(
9211        i::Vector<const char>(c_string, i::StrLength(c_string)));
9212    UC16VectorResource uc16_resource(
9213        i::Vector<const uint16_t>(two_byte_string,
9214                                  i::StrLength(c_string)));
9215
9216    Local<String> lhs(v8::Utils::ToLocal(
9217        i::Factory::NewExternalStringFromAscii(&ascii_resource)));
9218    Local<String> rhs(v8::Utils::ToLocal(
9219        i::Factory::NewExternalStringFromAscii(&ascii_resource)));
9220
9221    env->Global()->Set(v8_str("lhs"), lhs);
9222    env->Global()->Set(v8_str("rhs"), rhs);
9223
9224    CompileRun(
9225        "var cons = lhs + rhs;"
9226        "var slice = lhs.substring(1, lhs.length - 1);"
9227        "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
9228
9229    MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
9230    MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
9231
9232    // Now do some stuff to make sure the strings are flattened, etc.
9233    CompileRun(
9234        "/[^a-z]/.test(cons);"
9235        "/[^a-z]/.test(slice);"
9236        "/[^a-z]/.test(slice_on_cons);");
9237    const char* expected_cons =
9238        "Now is the time for all good men to come to the aid of the party"
9239        "Now is the time for all good men to come to the aid of the party";
9240    const char* expected_slice =
9241        "ow is the time for all good men to come to the aid of the part";
9242    const char* expected_slice_on_cons =
9243        "ow is the time for all good men to come to the aid of the party"
9244        "Now is the time for all good men to come to the aid of the part";
9245    CHECK_EQ(String::New(expected_cons),
9246             env->Global()->Get(v8_str("cons")));
9247    CHECK_EQ(String::New(expected_slice),
9248             env->Global()->Get(v8_str("slice")));
9249    CHECK_EQ(String::New(expected_slice_on_cons),
9250             env->Global()->Get(v8_str("slice_on_cons")));
9251  }
9252  i::DeleteArray(two_byte_string);
9253}
9254
9255
9256TEST(CompileExternalTwoByteSource) {
9257  v8::HandleScope scope;
9258  LocalContext context;
9259
9260  // This is a very short list of sources, which currently is to check for a
9261  // regression caused by r2703.
9262  const char* ascii_sources[] = {
9263    "0.5",
9264    "-0.5",   // This mainly testes PushBack in the Scanner.
9265    "--0.5",  // This mainly testes PushBack in the Scanner.
9266    NULL
9267  };
9268
9269  // Compile the sources as external two byte strings.
9270  for (int i = 0; ascii_sources[i] != NULL; i++) {
9271    uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
9272    UC16VectorResource uc16_resource(
9273        i::Vector<const uint16_t>(two_byte_string,
9274                                  i::StrLength(ascii_sources[i])));
9275    v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource);
9276    v8::Script::Compile(source);
9277    i::DeleteArray(two_byte_string);
9278  }
9279}
9280
9281
9282class RegExpStringModificationTest {
9283 public:
9284  RegExpStringModificationTest()
9285      : block_(i::OS::CreateSemaphore(0)),
9286        morphs_(0),
9287        morphs_during_regexp_(0),
9288        ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)),
9289        uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {}
9290  ~RegExpStringModificationTest() { delete block_; }
9291  void RunTest() {
9292    regexp_success_ = false;
9293    morph_success_ = false;
9294
9295    // Initialize the contents of two_byte_content_ to be a uc16 representation
9296    // of "aaaaaaaaaaaaaab".
9297    for (int i = 0; i < 14; i++) {
9298      two_byte_content_[i] = 'a';
9299    }
9300    two_byte_content_[14] = 'b';
9301
9302    // Create the input string for the regexp - the one we are going to change
9303    // properties of.
9304    input_ = i::Factory::NewExternalStringFromAscii(&ascii_resource_);
9305
9306    // Inject the input as a global variable.
9307    i::Handle<i::String> input_name =
9308        i::Factory::NewStringFromAscii(i::Vector<const char>("input", 5));
9309    i::Top::global_context()->global()->SetProperty(*input_name,
9310                                                    *input_,
9311                                                    NONE)->ToObjectChecked();
9312
9313
9314    MorphThread morph_thread(this);
9315    morph_thread.Start();
9316    v8::Locker::StartPreemption(1);
9317    LongRunningRegExp();
9318    {
9319      v8::Unlocker unlock;
9320      morph_thread.Join();
9321    }
9322    v8::Locker::StopPreemption();
9323    CHECK(regexp_success_);
9324    CHECK(morph_success_);
9325  }
9326 private:
9327
9328  // Number of string modifications required.
9329  static const int kRequiredModifications = 5;
9330  static const int kMaxModifications = 100;
9331
9332  class MorphThread : public i::Thread {
9333   public:
9334    explicit MorphThread(RegExpStringModificationTest* test)
9335        : test_(test) {}
9336    virtual void Run() {
9337      test_->MorphString();
9338    }
9339   private:
9340     RegExpStringModificationTest* test_;
9341  };
9342
9343  void MorphString() {
9344    block_->Wait();
9345    while (morphs_during_regexp_ < kRequiredModifications &&
9346           morphs_ < kMaxModifications) {
9347      {
9348        v8::Locker lock;
9349        // Swap string between ascii and two-byte representation.
9350        i::String* string = *input_;
9351        MorphAString(string, &ascii_resource_, &uc16_resource_);
9352        morphs_++;
9353      }
9354      i::OS::Sleep(1);
9355    }
9356    morph_success_ = true;
9357  }
9358
9359  void LongRunningRegExp() {
9360    block_->Signal();  // Enable morphing thread on next preemption.
9361    while (morphs_during_regexp_ < kRequiredModifications &&
9362           morphs_ < kMaxModifications) {
9363      int morphs_before = morphs_;
9364      {
9365        v8::HandleScope scope;
9366        // Match 15-30 "a"'s against 14 and a "b".
9367        const char* c_source =
9368            "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
9369            ".exec(input) === null";
9370        Local<String> source = String::New(c_source);
9371        Local<Script> script = Script::Compile(source);
9372        Local<Value> result = script->Run();
9373        CHECK(result->IsTrue());
9374      }
9375      int morphs_after = morphs_;
9376      morphs_during_regexp_ += morphs_after - morphs_before;
9377    }
9378    regexp_success_ = true;
9379  }
9380
9381  i::uc16 two_byte_content_[15];
9382  i::Semaphore* block_;
9383  int morphs_;
9384  int morphs_during_regexp_;
9385  bool regexp_success_;
9386  bool morph_success_;
9387  i::Handle<i::String> input_;
9388  AsciiVectorResource ascii_resource_;
9389  UC16VectorResource uc16_resource_;
9390};
9391
9392
9393// Test that a regular expression execution can be interrupted and
9394// the string changed without failing.
9395TEST(RegExpStringModification) {
9396  v8::Locker lock;
9397  v8::V8::Initialize();
9398  v8::HandleScope scope;
9399  Local<Context> local_env;
9400  {
9401    LocalContext env;
9402    local_env = env.local();
9403  }
9404
9405  // Local context should still be live.
9406  CHECK(!local_env.IsEmpty());
9407  local_env->Enter();
9408
9409  // Should complete without problems.
9410  RegExpStringModificationTest().RunTest();
9411
9412  local_env->Exit();
9413}
9414
9415
9416// Test that we can set a property on the global object even if there
9417// is a read-only property in the prototype chain.
9418TEST(ReadOnlyPropertyInGlobalProto) {
9419  v8::HandleScope scope;
9420  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
9421  LocalContext context(0, templ);
9422  v8::Handle<v8::Object> global = context->Global();
9423  v8::Handle<v8::Object> global_proto =
9424      v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
9425  global_proto->Set(v8_str("x"), v8::Integer::New(0), v8::ReadOnly);
9426  global_proto->Set(v8_str("y"), v8::Integer::New(0), v8::ReadOnly);
9427  // Check without 'eval' or 'with'.
9428  v8::Handle<v8::Value> res =
9429      CompileRun("function f() { x = 42; return x; }; f()");
9430  // Check with 'eval'.
9431  res = CompileRun("function f() { eval('1'); y = 42; return y; }; f()");
9432  CHECK_EQ(v8::Integer::New(42), res);
9433  // Check with 'with'.
9434  res = CompileRun("function f() { with (this) { y = 42 }; return y; }; f()");
9435  CHECK_EQ(v8::Integer::New(42), res);
9436}
9437
9438static int force_set_set_count = 0;
9439static int force_set_get_count = 0;
9440bool pass_on_get = false;
9441
9442static v8::Handle<v8::Value> ForceSetGetter(v8::Local<v8::String> name,
9443                                            const v8::AccessorInfo& info) {
9444  force_set_get_count++;
9445  if (pass_on_get) {
9446    return v8::Handle<v8::Value>();
9447  } else {
9448    return v8::Int32::New(3);
9449  }
9450}
9451
9452static void ForceSetSetter(v8::Local<v8::String> name,
9453                           v8::Local<v8::Value> value,
9454                           const v8::AccessorInfo& info) {
9455  force_set_set_count++;
9456}
9457
9458static v8::Handle<v8::Value> ForceSetInterceptSetter(
9459    v8::Local<v8::String> name,
9460    v8::Local<v8::Value> value,
9461    const v8::AccessorInfo& info) {
9462  force_set_set_count++;
9463  return v8::Undefined();
9464}
9465
9466TEST(ForceSet) {
9467  force_set_get_count = 0;
9468  force_set_set_count = 0;
9469  pass_on_get = false;
9470
9471  v8::HandleScope scope;
9472  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
9473  v8::Handle<v8::String> access_property = v8::String::New("a");
9474  templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
9475  LocalContext context(NULL, templ);
9476  v8::Handle<v8::Object> global = context->Global();
9477
9478  // Ordinary properties
9479  v8::Handle<v8::String> simple_property = v8::String::New("p");
9480  global->Set(simple_property, v8::Int32::New(4), v8::ReadOnly);
9481  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
9482  // This should fail because the property is read-only
9483  global->Set(simple_property, v8::Int32::New(5));
9484  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
9485  // This should succeed even though the property is read-only
9486  global->ForceSet(simple_property, v8::Int32::New(6));
9487  CHECK_EQ(6, global->Get(simple_property)->Int32Value());
9488
9489  // Accessors
9490  CHECK_EQ(0, force_set_set_count);
9491  CHECK_EQ(0, force_set_get_count);
9492  CHECK_EQ(3, global->Get(access_property)->Int32Value());
9493  // CHECK_EQ the property shouldn't override it, just call the setter
9494  // which in this case does nothing.
9495  global->Set(access_property, v8::Int32::New(7));
9496  CHECK_EQ(3, global->Get(access_property)->Int32Value());
9497  CHECK_EQ(1, force_set_set_count);
9498  CHECK_EQ(2, force_set_get_count);
9499  // Forcing the property to be set should override the accessor without
9500  // calling it
9501  global->ForceSet(access_property, v8::Int32::New(8));
9502  CHECK_EQ(8, global->Get(access_property)->Int32Value());
9503  CHECK_EQ(1, force_set_set_count);
9504  CHECK_EQ(2, force_set_get_count);
9505}
9506
9507TEST(ForceSetWithInterceptor) {
9508  force_set_get_count = 0;
9509  force_set_set_count = 0;
9510  pass_on_get = false;
9511
9512  v8::HandleScope scope;
9513  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
9514  templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
9515  LocalContext context(NULL, templ);
9516  v8::Handle<v8::Object> global = context->Global();
9517
9518  v8::Handle<v8::String> some_property = v8::String::New("a");
9519  CHECK_EQ(0, force_set_set_count);
9520  CHECK_EQ(0, force_set_get_count);
9521  CHECK_EQ(3, global->Get(some_property)->Int32Value());
9522  // Setting the property shouldn't override it, just call the setter
9523  // which in this case does nothing.
9524  global->Set(some_property, v8::Int32::New(7));
9525  CHECK_EQ(3, global->Get(some_property)->Int32Value());
9526  CHECK_EQ(1, force_set_set_count);
9527  CHECK_EQ(2, force_set_get_count);
9528  // Getting the property when the interceptor returns an empty handle
9529  // should yield undefined, since the property isn't present on the
9530  // object itself yet.
9531  pass_on_get = true;
9532  CHECK(global->Get(some_property)->IsUndefined());
9533  CHECK_EQ(1, force_set_set_count);
9534  CHECK_EQ(3, force_set_get_count);
9535  // Forcing the property to be set should cause the value to be
9536  // set locally without calling the interceptor.
9537  global->ForceSet(some_property, v8::Int32::New(8));
9538  CHECK_EQ(8, global->Get(some_property)->Int32Value());
9539  CHECK_EQ(1, force_set_set_count);
9540  CHECK_EQ(4, force_set_get_count);
9541  // Reenabling the interceptor should cause it to take precedence over
9542  // the property
9543  pass_on_get = false;
9544  CHECK_EQ(3, global->Get(some_property)->Int32Value());
9545  CHECK_EQ(1, force_set_set_count);
9546  CHECK_EQ(5, force_set_get_count);
9547  // The interceptor should also work for other properties
9548  CHECK_EQ(3, global->Get(v8::String::New("b"))->Int32Value());
9549  CHECK_EQ(1, force_set_set_count);
9550  CHECK_EQ(6, force_set_get_count);
9551}
9552
9553
9554THREADED_TEST(ForceDelete) {
9555  v8::HandleScope scope;
9556  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
9557  LocalContext context(NULL, templ);
9558  v8::Handle<v8::Object> global = context->Global();
9559
9560  // Ordinary properties
9561  v8::Handle<v8::String> simple_property = v8::String::New("p");
9562  global->Set(simple_property, v8::Int32::New(4), v8::DontDelete);
9563  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
9564  // This should fail because the property is dont-delete.
9565  CHECK(!global->Delete(simple_property));
9566  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
9567  // This should succeed even though the property is dont-delete.
9568  CHECK(global->ForceDelete(simple_property));
9569  CHECK(global->Get(simple_property)->IsUndefined());
9570}
9571
9572
9573static int force_delete_interceptor_count = 0;
9574static bool pass_on_delete = false;
9575
9576
9577static v8::Handle<v8::Boolean> ForceDeleteDeleter(
9578    v8::Local<v8::String> name,
9579    const v8::AccessorInfo& info) {
9580  force_delete_interceptor_count++;
9581  if (pass_on_delete) {
9582    return v8::Handle<v8::Boolean>();
9583  } else {
9584    return v8::True();
9585  }
9586}
9587
9588
9589THREADED_TEST(ForceDeleteWithInterceptor) {
9590  force_delete_interceptor_count = 0;
9591  pass_on_delete = false;
9592
9593  v8::HandleScope scope;
9594  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
9595  templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
9596  LocalContext context(NULL, templ);
9597  v8::Handle<v8::Object> global = context->Global();
9598
9599  v8::Handle<v8::String> some_property = v8::String::New("a");
9600  global->Set(some_property, v8::Integer::New(42), v8::DontDelete);
9601
9602  // Deleting a property should get intercepted and nothing should
9603  // happen.
9604  CHECK_EQ(0, force_delete_interceptor_count);
9605  CHECK(global->Delete(some_property));
9606  CHECK_EQ(1, force_delete_interceptor_count);
9607  CHECK_EQ(42, global->Get(some_property)->Int32Value());
9608  // Deleting the property when the interceptor returns an empty
9609  // handle should not delete the property since it is DontDelete.
9610  pass_on_delete = true;
9611  CHECK(!global->Delete(some_property));
9612  CHECK_EQ(2, force_delete_interceptor_count);
9613  CHECK_EQ(42, global->Get(some_property)->Int32Value());
9614  // Forcing the property to be deleted should delete the value
9615  // without calling the interceptor.
9616  CHECK(global->ForceDelete(some_property));
9617  CHECK(global->Get(some_property)->IsUndefined());
9618  CHECK_EQ(2, force_delete_interceptor_count);
9619}
9620
9621
9622// Make sure that forcing a delete invalidates any IC stubs, so we
9623// don't read the hole value.
9624THREADED_TEST(ForceDeleteIC) {
9625  v8::HandleScope scope;
9626  LocalContext context;
9627  // Create a DontDelete variable on the global object.
9628  CompileRun("this.__proto__ = { foo: 'horse' };"
9629             "var foo = 'fish';"
9630             "function f() { return foo.length; }");
9631  // Initialize the IC for foo in f.
9632  CompileRun("for (var i = 0; i < 4; i++) f();");
9633  // Make sure the value of foo is correct before the deletion.
9634  CHECK_EQ(4, CompileRun("f()")->Int32Value());
9635  // Force the deletion of foo.
9636  CHECK(context->Global()->ForceDelete(v8_str("foo")));
9637  // Make sure the value for foo is read from the prototype, and that
9638  // we don't get in trouble with reading the deleted cell value
9639  // sentinel.
9640  CHECK_EQ(5, CompileRun("f()")->Int32Value());
9641}
9642
9643
9644v8::Persistent<Context> calling_context0;
9645v8::Persistent<Context> calling_context1;
9646v8::Persistent<Context> calling_context2;
9647
9648
9649// Check that the call to the callback is initiated in
9650// calling_context2, the directly calling context is calling_context1
9651// and the callback itself is in calling_context0.
9652static v8::Handle<Value> GetCallingContextCallback(const v8::Arguments& args) {
9653  ApiTestFuzzer::Fuzz();
9654  CHECK(Context::GetCurrent() == calling_context0);
9655  CHECK(Context::GetCalling() == calling_context1);
9656  CHECK(Context::GetEntered() == calling_context2);
9657  return v8::Integer::New(42);
9658}
9659
9660
9661THREADED_TEST(GetCallingContext) {
9662  v8::HandleScope scope;
9663
9664  calling_context0 = Context::New();
9665  calling_context1 = Context::New();
9666  calling_context2 = Context::New();
9667
9668  // Allow cross-domain access.
9669  Local<String> token = v8_str("<security token>");
9670  calling_context0->SetSecurityToken(token);
9671  calling_context1->SetSecurityToken(token);
9672  calling_context2->SetSecurityToken(token);
9673
9674  // Create an object with a C++ callback in context0.
9675  calling_context0->Enter();
9676  Local<v8::FunctionTemplate> callback_templ =
9677      v8::FunctionTemplate::New(GetCallingContextCallback);
9678  calling_context0->Global()->Set(v8_str("callback"),
9679                                  callback_templ->GetFunction());
9680  calling_context0->Exit();
9681
9682  // Expose context0 in context1 and setup a function that calls the
9683  // callback function.
9684  calling_context1->Enter();
9685  calling_context1->Global()->Set(v8_str("context0"),
9686                                  calling_context0->Global());
9687  CompileRun("function f() { context0.callback() }");
9688  calling_context1->Exit();
9689
9690  // Expose context1 in context2 and call the callback function in
9691  // context0 indirectly through f in context1.
9692  calling_context2->Enter();
9693  calling_context2->Global()->Set(v8_str("context1"),
9694                                  calling_context1->Global());
9695  CompileRun("context1.f()");
9696  calling_context2->Exit();
9697
9698  // Dispose the contexts to allow them to be garbage collected.
9699  calling_context0.Dispose();
9700  calling_context1.Dispose();
9701  calling_context2.Dispose();
9702  calling_context0.Clear();
9703  calling_context1.Clear();
9704  calling_context2.Clear();
9705}
9706
9707
9708// Check that a variable declaration with no explicit initialization
9709// value does not shadow an existing property in the prototype chain.
9710//
9711// This is consistent with Firefox and Safari.
9712//
9713// See http://crbug.com/12548.
9714THREADED_TEST(InitGlobalVarInProtoChain) {
9715  v8::HandleScope scope;
9716  LocalContext context;
9717  // Introduce a variable in the prototype chain.
9718  CompileRun("__proto__.x = 42");
9719  v8::Handle<v8::Value> result = CompileRun("var x; x");
9720  CHECK(!result->IsUndefined());
9721  CHECK_EQ(42, result->Int32Value());
9722}
9723
9724
9725// Regression test for issue 398.
9726// If a function is added to an object, creating a constant function
9727// field, and the result is cloned, replacing the constant function on the
9728// original should not affect the clone.
9729// See http://code.google.com/p/v8/issues/detail?id=398
9730THREADED_TEST(ReplaceConstantFunction) {
9731  v8::HandleScope scope;
9732  LocalContext context;
9733  v8::Handle<v8::Object> obj = v8::Object::New();
9734  v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
9735  v8::Handle<v8::String> foo_string = v8::String::New("foo");
9736  obj->Set(foo_string, func_templ->GetFunction());
9737  v8::Handle<v8::Object> obj_clone = obj->Clone();
9738  obj_clone->Set(foo_string, v8::String::New("Hello"));
9739  CHECK(!obj->Get(foo_string)->IsUndefined());
9740}
9741
9742
9743// Regression test for http://crbug.com/16276.
9744THREADED_TEST(Regress16276) {
9745  v8::HandleScope scope;
9746  LocalContext context;
9747  // Force the IC in f to be a dictionary load IC.
9748  CompileRun("function f(obj) { return obj.x; }\n"
9749             "var obj = { x: { foo: 42 }, y: 87 };\n"
9750             "var x = obj.x;\n"
9751             "delete obj.y;\n"
9752             "for (var i = 0; i < 5; i++) f(obj);");
9753  // Detach the global object to make 'this' refer directly to the
9754  // global object (not the proxy), and make sure that the dictionary
9755  // load IC doesn't mess up loading directly from the global object.
9756  context->DetachGlobal();
9757  CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value());
9758}
9759
9760
9761THREADED_TEST(PixelArray) {
9762  v8::HandleScope scope;
9763  LocalContext context;
9764  const int kElementCount = 260;
9765  uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
9766  i::Handle<i::PixelArray> pixels = i::Factory::NewPixelArray(kElementCount,
9767                                                              pixel_data);
9768  i::Heap::CollectAllGarbage(false);  // Force GC to trigger verification.
9769  for (int i = 0; i < kElementCount; i++) {
9770    pixels->set(i, i % 256);
9771  }
9772  i::Heap::CollectAllGarbage(false);  // Force GC to trigger verification.
9773  for (int i = 0; i < kElementCount; i++) {
9774    CHECK_EQ(i % 256, pixels->get(i));
9775    CHECK_EQ(i % 256, pixel_data[i]);
9776  }
9777
9778  v8::Handle<v8::Object> obj = v8::Object::New();
9779  i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
9780  // Set the elements to be the pixels.
9781  // jsobj->set_elements(*pixels);
9782  obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
9783  CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
9784  obj->Set(v8_str("field"), v8::Int32::New(1503));
9785  context->Global()->Set(v8_str("pixels"), obj);
9786  v8::Handle<v8::Value> result = CompileRun("pixels.field");
9787  CHECK_EQ(1503, result->Int32Value());
9788  result = CompileRun("pixels[1]");
9789  CHECK_EQ(1, result->Int32Value());
9790
9791  result = CompileRun("var sum = 0;"
9792                      "for (var i = 0; i < 8; i++) {"
9793                      "  sum += pixels[i] = pixels[i] = -i;"
9794                      "}"
9795                      "sum;");
9796  CHECK_EQ(-28, result->Int32Value());
9797
9798  result = CompileRun("var sum = 0;"
9799                      "for (var i = 0; i < 8; i++) {"
9800                      "  sum += pixels[i] = pixels[i] = 0;"
9801                      "}"
9802                      "sum;");
9803  CHECK_EQ(0, result->Int32Value());
9804
9805  result = CompileRun("var sum = 0;"
9806                      "for (var i = 0; i < 8; i++) {"
9807                      "  sum += pixels[i] = pixels[i] = 255;"
9808                      "}"
9809                      "sum;");
9810  CHECK_EQ(8 * 255, result->Int32Value());
9811
9812  result = CompileRun("var sum = 0;"
9813                      "for (var i = 0; i < 8; i++) {"
9814                      "  sum += pixels[i] = pixels[i] = 256 + i;"
9815                      "}"
9816                      "sum;");
9817  CHECK_EQ(2076, result->Int32Value());
9818
9819  result = CompileRun("var sum = 0;"
9820                      "for (var i = 0; i < 8; i++) {"
9821                      "  sum += pixels[i] = pixels[i] = i;"
9822                      "}"
9823                      "sum;");
9824  CHECK_EQ(28, result->Int32Value());
9825
9826  result = CompileRun("var sum = 0;"
9827                      "for (var i = 0; i < 8; i++) {"
9828                      "  sum += pixels[i];"
9829                      "}"
9830                      "sum;");
9831  CHECK_EQ(28, result->Int32Value());
9832
9833  i::Handle<i::Smi> value(i::Smi::FromInt(2));
9834  i::SetElement(jsobj, 1, value);
9835  CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
9836  *value.location() = i::Smi::FromInt(256);
9837  i::SetElement(jsobj, 1, value);
9838  CHECK_EQ(255,
9839           i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
9840  *value.location() = i::Smi::FromInt(-1);
9841  i::SetElement(jsobj, 1, value);
9842  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
9843
9844  result = CompileRun("for (var i = 0; i < 8; i++) {"
9845                      "  pixels[i] = (i * 65) - 109;"
9846                      "}"
9847                      "pixels[1] + pixels[6];");
9848  CHECK_EQ(255, result->Int32Value());
9849  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
9850  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
9851  CHECK_EQ(21,
9852           i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
9853  CHECK_EQ(86,
9854           i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
9855  CHECK_EQ(151,
9856           i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
9857  CHECK_EQ(216,
9858           i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
9859  CHECK_EQ(255,
9860           i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
9861  CHECK_EQ(255,
9862           i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
9863  result = CompileRun("var sum = 0;"
9864                      "for (var i = 0; i < 8; i++) {"
9865                      "  sum += pixels[i];"
9866                      "}"
9867                      "sum;");
9868  CHECK_EQ(984, result->Int32Value());
9869
9870  result = CompileRun("for (var i = 0; i < 8; i++) {"
9871                      "  pixels[i] = (i * 1.1);"
9872                      "}"
9873                      "pixels[1] + pixels[6];");
9874  CHECK_EQ(8, result->Int32Value());
9875  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
9876  CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
9877  CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
9878  CHECK_EQ(3, i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
9879  CHECK_EQ(4, i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
9880  CHECK_EQ(6, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
9881  CHECK_EQ(7, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
9882  CHECK_EQ(8, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
9883
9884  result = CompileRun("for (var i = 0; i < 8; i++) {"
9885                      "  pixels[7] = undefined;"
9886                      "}"
9887                      "pixels[7];");
9888  CHECK_EQ(0, result->Int32Value());
9889  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
9890
9891  result = CompileRun("for (var i = 0; i < 8; i++) {"
9892                      "  pixels[6] = '2.3';"
9893                      "}"
9894                      "pixels[6];");
9895  CHECK_EQ(2, result->Int32Value());
9896  CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
9897
9898  result = CompileRun("for (var i = 0; i < 8; i++) {"
9899                      "  pixels[5] = NaN;"
9900                      "}"
9901                      "pixels[5];");
9902  CHECK_EQ(0, result->Int32Value());
9903  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
9904
9905  result = CompileRun("for (var i = 0; i < 8; i++) {"
9906                      "  pixels[8] = Infinity;"
9907                      "}"
9908                      "pixels[8];");
9909  CHECK_EQ(255, result->Int32Value());
9910  CHECK_EQ(255,
9911           i::Smi::cast(jsobj->GetElement(8)->ToObjectChecked())->value());
9912
9913  result = CompileRun("for (var i = 0; i < 8; i++) {"
9914                      "  pixels[9] = -Infinity;"
9915                      "}"
9916                      "pixels[9];");
9917  CHECK_EQ(0, result->Int32Value());
9918  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(9)->ToObjectChecked())->value());
9919
9920  result = CompileRun("pixels[3] = 33;"
9921                      "delete pixels[3];"
9922                      "pixels[3];");
9923  CHECK_EQ(33, result->Int32Value());
9924
9925  result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
9926                      "pixels[2] = 12; pixels[3] = 13;"
9927                      "pixels.__defineGetter__('2',"
9928                      "function() { return 120; });"
9929                      "pixels[2];");
9930  CHECK_EQ(12, result->Int32Value());
9931
9932  result = CompileRun("var js_array = new Array(40);"
9933                      "js_array[0] = 77;"
9934                      "js_array;");
9935  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
9936
9937  result = CompileRun("pixels[1] = 23;"
9938                      "pixels.__proto__ = [];"
9939                      "js_array.__proto__ = pixels;"
9940                      "js_array.concat(pixels);");
9941  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
9942  CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
9943
9944  result = CompileRun("pixels[1] = 23;");
9945  CHECK_EQ(23, result->Int32Value());
9946
9947  // Test for index greater than 255.  Regression test for:
9948  // http://code.google.com/p/chromium/issues/detail?id=26337.
9949  result = CompileRun("pixels[256] = 255;");
9950  CHECK_EQ(255, result->Int32Value());
9951  result = CompileRun("var i = 0;"
9952                      "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
9953                      "i");
9954  CHECK_EQ(255, result->Int32Value());
9955
9956  free(pixel_data);
9957}
9958
9959
9960THREADED_TEST(PixelArrayInfo) {
9961  v8::HandleScope scope;
9962  LocalContext context;
9963  for (int size = 0; size < 100; size += 10) {
9964    uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
9965    v8::Handle<v8::Object> obj = v8::Object::New();
9966    obj->SetIndexedPropertiesToPixelData(pixel_data, size);
9967    CHECK(obj->HasIndexedPropertiesInPixelData());
9968    CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
9969    CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
9970    free(pixel_data);
9971  }
9972}
9973
9974
9975static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
9976  switch (array_type) {
9977    case v8::kExternalByteArray:
9978    case v8::kExternalUnsignedByteArray:
9979      return 1;
9980      break;
9981    case v8::kExternalShortArray:
9982    case v8::kExternalUnsignedShortArray:
9983      return 2;
9984      break;
9985    case v8::kExternalIntArray:
9986    case v8::kExternalUnsignedIntArray:
9987    case v8::kExternalFloatArray:
9988      return 4;
9989      break;
9990    default:
9991      UNREACHABLE();
9992      return -1;
9993  }
9994  UNREACHABLE();
9995  return -1;
9996}
9997
9998
9999template <class ExternalArrayClass, class ElementType>
10000static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
10001                                    int64_t low,
10002                                    int64_t high) {
10003  v8::HandleScope scope;
10004  LocalContext context;
10005  const int kElementCount = 40;
10006  int element_size = ExternalArrayElementSize(array_type);
10007  ElementType* array_data =
10008      static_cast<ElementType*>(malloc(kElementCount * element_size));
10009  i::Handle<ExternalArrayClass> array =
10010      i::Handle<ExternalArrayClass>::cast(
10011          i::Factory::NewExternalArray(kElementCount, array_type, array_data));
10012  i::Heap::CollectAllGarbage(false);  // Force GC to trigger verification.
10013  for (int i = 0; i < kElementCount; i++) {
10014    array->set(i, static_cast<ElementType>(i));
10015  }
10016  i::Heap::CollectAllGarbage(false);  // Force GC to trigger verification.
10017  for (int i = 0; i < kElementCount; i++) {
10018    CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array->get(i)));
10019    CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
10020  }
10021
10022  v8::Handle<v8::Object> obj = v8::Object::New();
10023  i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
10024  // Set the elements to be the external array.
10025  obj->SetIndexedPropertiesToExternalArrayData(array_data,
10026                                               array_type,
10027                                               kElementCount);
10028  CHECK_EQ(
10029      1, static_cast<int>(jsobj->GetElement(1)->ToObjectChecked()->Number()));
10030  obj->Set(v8_str("field"), v8::Int32::New(1503));
10031  context->Global()->Set(v8_str("ext_array"), obj);
10032  v8::Handle<v8::Value> result = CompileRun("ext_array.field");
10033  CHECK_EQ(1503, result->Int32Value());
10034  result = CompileRun("ext_array[1]");
10035  CHECK_EQ(1, result->Int32Value());
10036
10037  // Check pass through of assigned smis
10038  result = CompileRun("var sum = 0;"
10039                      "for (var i = 0; i < 8; i++) {"
10040                      "  sum += ext_array[i] = ext_array[i] = -i;"
10041                      "}"
10042                      "sum;");
10043  CHECK_EQ(-28, result->Int32Value());
10044
10045  // Check assigned smis
10046  result = CompileRun("for (var i = 0; i < 8; i++) {"
10047                      "  ext_array[i] = i;"
10048                      "}"
10049                      "var sum = 0;"
10050                      "for (var i = 0; i < 8; i++) {"
10051                      "  sum += ext_array[i];"
10052                      "}"
10053                      "sum;");
10054  CHECK_EQ(28, result->Int32Value());
10055
10056  // Check assigned smis in reverse order
10057  result = CompileRun("for (var i = 8; --i >= 0; ) {"
10058                      "  ext_array[i] = i;"
10059                      "}"
10060                      "var sum = 0;"
10061                      "for (var i = 0; i < 8; i++) {"
10062                      "  sum += ext_array[i];"
10063                      "}"
10064                      "sum;");
10065  CHECK_EQ(28, result->Int32Value());
10066
10067  // Check pass through of assigned HeapNumbers
10068  result = CompileRun("var sum = 0;"
10069                      "for (var i = 0; i < 16; i+=2) {"
10070                      "  sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
10071                      "}"
10072                      "sum;");
10073  CHECK_EQ(-28, result->Int32Value());
10074
10075  // Check assigned HeapNumbers
10076  result = CompileRun("for (var i = 0; i < 16; i+=2) {"
10077                      "  ext_array[i] = (i * 0.5);"
10078                      "}"
10079                      "var sum = 0;"
10080                      "for (var i = 0; i < 16; i+=2) {"
10081                      "  sum += ext_array[i];"
10082                      "}"
10083                      "sum;");
10084  CHECK_EQ(28, result->Int32Value());
10085
10086  // Check assigned HeapNumbers in reverse order
10087  result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
10088                      "  ext_array[i] = (i * 0.5);"
10089                      "}"
10090                      "var sum = 0;"
10091                      "for (var i = 0; i < 16; i+=2) {"
10092                      "  sum += ext_array[i];"
10093                      "}"
10094                      "sum;");
10095  CHECK_EQ(28, result->Int32Value());
10096
10097  i::ScopedVector<char> test_buf(1024);
10098
10099  // Check legal boundary conditions.
10100  // The repeated loads and stores ensure the ICs are exercised.
10101  const char* boundary_program =
10102      "var res = 0;"
10103      "for (var i = 0; i < 16; i++) {"
10104      "  ext_array[i] = %lld;"
10105      "  if (i > 8) {"
10106      "    res = ext_array[i];"
10107      "  }"
10108      "}"
10109      "res;";
10110  i::OS::SNPrintF(test_buf,
10111                  boundary_program,
10112                  low);
10113  result = CompileRun(test_buf.start());
10114  CHECK_EQ(low, result->IntegerValue());
10115
10116  i::OS::SNPrintF(test_buf,
10117                  boundary_program,
10118                  high);
10119  result = CompileRun(test_buf.start());
10120  CHECK_EQ(high, result->IntegerValue());
10121
10122  // Check misprediction of type in IC.
10123  result = CompileRun("var tmp_array = ext_array;"
10124                      "var sum = 0;"
10125                      "for (var i = 0; i < 8; i++) {"
10126                      "  tmp_array[i] = i;"
10127                      "  sum += tmp_array[i];"
10128                      "  if (i == 4) {"
10129                      "    tmp_array = {};"
10130                      "  }"
10131                      "}"
10132                      "sum;");
10133  i::Heap::CollectAllGarbage(false);  // Force GC to trigger verification.
10134  CHECK_EQ(28, result->Int32Value());
10135
10136  // Make sure out-of-range loads do not throw.
10137  i::OS::SNPrintF(test_buf,
10138                  "var caught_exception = false;"
10139                  "try {"
10140                  "  ext_array[%d];"
10141                  "} catch (e) {"
10142                  "  caught_exception = true;"
10143                  "}"
10144                  "caught_exception;",
10145                  kElementCount);
10146  result = CompileRun(test_buf.start());
10147  CHECK_EQ(false, result->BooleanValue());
10148
10149  // Make sure out-of-range stores do not throw.
10150  i::OS::SNPrintF(test_buf,
10151                  "var caught_exception = false;"
10152                  "try {"
10153                  "  ext_array[%d] = 1;"
10154                  "} catch (e) {"
10155                  "  caught_exception = true;"
10156                  "}"
10157                  "caught_exception;",
10158                  kElementCount);
10159  result = CompileRun(test_buf.start());
10160  CHECK_EQ(false, result->BooleanValue());
10161
10162  // Check other boundary conditions, values and operations.
10163  result = CompileRun("for (var i = 0; i < 8; i++) {"
10164                      "  ext_array[7] = undefined;"
10165                      "}"
10166                      "ext_array[7];");
10167  CHECK_EQ(0, result->Int32Value());
10168  CHECK_EQ(
10169      0, static_cast<int>(jsobj->GetElement(7)->ToObjectChecked()->Number()));
10170
10171  result = CompileRun("for (var i = 0; i < 8; i++) {"
10172                      "  ext_array[6] = '2.3';"
10173                      "}"
10174                      "ext_array[6];");
10175  CHECK_EQ(2, result->Int32Value());
10176  CHECK_EQ(
10177      2, static_cast<int>(jsobj->GetElement(6)->ToObjectChecked()->Number()));
10178
10179  if (array_type != v8::kExternalFloatArray) {
10180    // Though the specification doesn't state it, be explicit about
10181    // converting NaNs and +/-Infinity to zero.
10182    result = CompileRun("for (var i = 0; i < 8; i++) {"
10183                        "  ext_array[i] = 5;"
10184                        "}"
10185                        "for (var i = 0; i < 8; i++) {"
10186                        "  ext_array[i] = NaN;"
10187                        "}"
10188                        "ext_array[5];");
10189    CHECK_EQ(0, result->Int32Value());
10190    CHECK_EQ(0,
10191             i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
10192
10193    result = CompileRun("for (var i = 0; i < 8; i++) {"
10194                        "  ext_array[i] = 5;"
10195                        "}"
10196                        "for (var i = 0; i < 8; i++) {"
10197                        "  ext_array[i] = Infinity;"
10198                        "}"
10199                        "ext_array[5];");
10200    CHECK_EQ(0, result->Int32Value());
10201    CHECK_EQ(0,
10202             i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
10203
10204    result = CompileRun("for (var i = 0; i < 8; i++) {"
10205                        "  ext_array[i] = 5;"
10206                        "}"
10207                        "for (var i = 0; i < 8; i++) {"
10208                        "  ext_array[i] = -Infinity;"
10209                        "}"
10210                        "ext_array[5];");
10211    CHECK_EQ(0, result->Int32Value());
10212    CHECK_EQ(0,
10213             i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
10214  }
10215
10216  result = CompileRun("ext_array[3] = 33;"
10217                      "delete ext_array[3];"
10218                      "ext_array[3];");
10219  CHECK_EQ(33, result->Int32Value());
10220
10221  result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
10222                      "ext_array[2] = 12; ext_array[3] = 13;"
10223                      "ext_array.__defineGetter__('2',"
10224                      "function() { return 120; });"
10225                      "ext_array[2];");
10226  CHECK_EQ(12, result->Int32Value());
10227
10228  result = CompileRun("var js_array = new Array(40);"
10229                      "js_array[0] = 77;"
10230                      "js_array;");
10231  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
10232
10233  result = CompileRun("ext_array[1] = 23;"
10234                      "ext_array.__proto__ = [];"
10235                      "js_array.__proto__ = ext_array;"
10236                      "js_array.concat(ext_array);");
10237  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
10238  CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
10239
10240  result = CompileRun("ext_array[1] = 23;");
10241  CHECK_EQ(23, result->Int32Value());
10242
10243  // Test more complex manipulations which cause eax to contain values
10244  // that won't be completely overwritten by loads from the arrays.
10245  // This catches bugs in the instructions used for the KeyedLoadIC
10246  // for byte and word types.
10247  {
10248    const int kXSize = 300;
10249    const int kYSize = 300;
10250    const int kLargeElementCount = kXSize * kYSize * 4;
10251    ElementType* large_array_data =
10252        static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
10253    i::Handle<ExternalArrayClass> large_array =
10254        i::Handle<ExternalArrayClass>::cast(
10255            i::Factory::NewExternalArray(kLargeElementCount,
10256                                         array_type,
10257                                         array_data));
10258    v8::Handle<v8::Object> large_obj = v8::Object::New();
10259    // Set the elements to be the external array.
10260    large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
10261                                                       array_type,
10262                                                       kLargeElementCount);
10263    context->Global()->Set(v8_str("large_array"), large_obj);
10264    // Initialize contents of a few rows.
10265    for (int x = 0; x < 300; x++) {
10266      int row = 0;
10267      int offset = row * 300 * 4;
10268      large_array_data[offset + 4 * x + 0] = (ElementType) 127;
10269      large_array_data[offset + 4 * x + 1] = (ElementType) 0;
10270      large_array_data[offset + 4 * x + 2] = (ElementType) 0;
10271      large_array_data[offset + 4 * x + 3] = (ElementType) 127;
10272      row = 150;
10273      offset = row * 300 * 4;
10274      large_array_data[offset + 4 * x + 0] = (ElementType) 127;
10275      large_array_data[offset + 4 * x + 1] = (ElementType) 0;
10276      large_array_data[offset + 4 * x + 2] = (ElementType) 0;
10277      large_array_data[offset + 4 * x + 3] = (ElementType) 127;
10278      row = 298;
10279      offset = row * 300 * 4;
10280      large_array_data[offset + 4 * x + 0] = (ElementType) 127;
10281      large_array_data[offset + 4 * x + 1] = (ElementType) 0;
10282      large_array_data[offset + 4 * x + 2] = (ElementType) 0;
10283      large_array_data[offset + 4 * x + 3] = (ElementType) 127;
10284    }
10285    // The goal of the code below is to make "offset" large enough
10286    // that the computation of the index (which goes into eax) has
10287    // high bits set which will not be overwritten by a byte or short
10288    // load.
10289    result = CompileRun("var failed = false;"
10290                        "var offset = 0;"
10291                        "for (var i = 0; i < 300; i++) {"
10292                        "  if (large_array[4 * i] != 127 ||"
10293                        "      large_array[4 * i + 1] != 0 ||"
10294                        "      large_array[4 * i + 2] != 0 ||"
10295                        "      large_array[4 * i + 3] != 127) {"
10296                        "    failed = true;"
10297                        "  }"
10298                        "}"
10299                        "offset = 150 * 300 * 4;"
10300                        "for (var i = 0; i < 300; i++) {"
10301                        "  if (large_array[offset + 4 * i] != 127 ||"
10302                        "      large_array[offset + 4 * i + 1] != 0 ||"
10303                        "      large_array[offset + 4 * i + 2] != 0 ||"
10304                        "      large_array[offset + 4 * i + 3] != 127) {"
10305                        "    failed = true;"
10306                        "  }"
10307                        "}"
10308                        "offset = 298 * 300 * 4;"
10309                        "for (var i = 0; i < 300; i++) {"
10310                        "  if (large_array[offset + 4 * i] != 127 ||"
10311                        "      large_array[offset + 4 * i + 1] != 0 ||"
10312                        "      large_array[offset + 4 * i + 2] != 0 ||"
10313                        "      large_array[offset + 4 * i + 3] != 127) {"
10314                        "    failed = true;"
10315                        "  }"
10316                        "}"
10317                        "!failed;");
10318    CHECK_EQ(true, result->BooleanValue());
10319    free(large_array_data);
10320  }
10321
10322  free(array_data);
10323}
10324
10325
10326THREADED_TEST(ExternalByteArray) {
10327  ExternalArrayTestHelper<i::ExternalByteArray, int8_t>(
10328      v8::kExternalByteArray,
10329      -128,
10330      127);
10331}
10332
10333
10334THREADED_TEST(ExternalUnsignedByteArray) {
10335  ExternalArrayTestHelper<i::ExternalUnsignedByteArray, uint8_t>(
10336      v8::kExternalUnsignedByteArray,
10337      0,
10338      255);
10339}
10340
10341
10342THREADED_TEST(ExternalShortArray) {
10343  ExternalArrayTestHelper<i::ExternalShortArray, int16_t>(
10344      v8::kExternalShortArray,
10345      -32768,
10346      32767);
10347}
10348
10349
10350THREADED_TEST(ExternalUnsignedShortArray) {
10351  ExternalArrayTestHelper<i::ExternalUnsignedShortArray, uint16_t>(
10352      v8::kExternalUnsignedShortArray,
10353      0,
10354      65535);
10355}
10356
10357
10358THREADED_TEST(ExternalIntArray) {
10359  ExternalArrayTestHelper<i::ExternalIntArray, int32_t>(
10360      v8::kExternalIntArray,
10361      INT_MIN,   // -2147483648
10362      INT_MAX);  //  2147483647
10363}
10364
10365
10366THREADED_TEST(ExternalUnsignedIntArray) {
10367  ExternalArrayTestHelper<i::ExternalUnsignedIntArray, uint32_t>(
10368      v8::kExternalUnsignedIntArray,
10369      0,
10370      UINT_MAX);  // 4294967295
10371}
10372
10373
10374THREADED_TEST(ExternalFloatArray) {
10375  ExternalArrayTestHelper<i::ExternalFloatArray, float>(
10376      v8::kExternalFloatArray,
10377      -500,
10378      500);
10379}
10380
10381
10382THREADED_TEST(ExternalArrays) {
10383  TestExternalByteArray();
10384  TestExternalUnsignedByteArray();
10385  TestExternalShortArray();
10386  TestExternalUnsignedShortArray();
10387  TestExternalIntArray();
10388  TestExternalUnsignedIntArray();
10389  TestExternalFloatArray();
10390}
10391
10392
10393void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
10394  v8::HandleScope scope;
10395  LocalContext context;
10396  for (int size = 0; size < 100; size += 10) {
10397    int element_size = ExternalArrayElementSize(array_type);
10398    void* external_data = malloc(size * element_size);
10399    v8::Handle<v8::Object> obj = v8::Object::New();
10400    obj->SetIndexedPropertiesToExternalArrayData(
10401        external_data, array_type, size);
10402    CHECK(obj->HasIndexedPropertiesInExternalArrayData());
10403    CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
10404    CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
10405    CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
10406    free(external_data);
10407  }
10408}
10409
10410
10411THREADED_TEST(ExternalArrayInfo) {
10412  ExternalArrayInfoTestHelper(v8::kExternalByteArray);
10413  ExternalArrayInfoTestHelper(v8::kExternalUnsignedByteArray);
10414  ExternalArrayInfoTestHelper(v8::kExternalShortArray);
10415  ExternalArrayInfoTestHelper(v8::kExternalUnsignedShortArray);
10416  ExternalArrayInfoTestHelper(v8::kExternalIntArray);
10417  ExternalArrayInfoTestHelper(v8::kExternalUnsignedIntArray);
10418  ExternalArrayInfoTestHelper(v8::kExternalFloatArray);
10419}
10420
10421
10422THREADED_TEST(ScriptContextDependence) {
10423  v8::HandleScope scope;
10424  LocalContext c1;
10425  const char *source = "foo";
10426  v8::Handle<v8::Script> dep = v8::Script::Compile(v8::String::New(source));
10427  v8::Handle<v8::Script> indep = v8::Script::New(v8::String::New(source));
10428  c1->Global()->Set(v8::String::New("foo"), v8::Integer::New(100));
10429  CHECK_EQ(dep->Run()->Int32Value(), 100);
10430  CHECK_EQ(indep->Run()->Int32Value(), 100);
10431  LocalContext c2;
10432  c2->Global()->Set(v8::String::New("foo"), v8::Integer::New(101));
10433  CHECK_EQ(dep->Run()->Int32Value(), 100);
10434  CHECK_EQ(indep->Run()->Int32Value(), 101);
10435}
10436
10437
10438THREADED_TEST(StackTrace) {
10439  v8::HandleScope scope;
10440  LocalContext context;
10441  v8::TryCatch try_catch;
10442  const char *source = "function foo() { FAIL.FAIL; }; foo();";
10443  v8::Handle<v8::String> src = v8::String::New(source);
10444  v8::Handle<v8::String> origin = v8::String::New("stack-trace-test");
10445  v8::Script::New(src, origin)->Run();
10446  CHECK(try_catch.HasCaught());
10447  v8::String::Utf8Value stack(try_catch.StackTrace());
10448  CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
10449}
10450
10451
10452// Checks that a StackFrame has certain expected values.
10453void checkStackFrame(const char* expected_script_name,
10454    const char* expected_func_name, int expected_line_number,
10455    int expected_column, bool is_eval, bool is_constructor,
10456    v8::Handle<v8::StackFrame> frame) {
10457  v8::HandleScope scope;
10458  v8::String::Utf8Value func_name(frame->GetFunctionName());
10459  v8::String::Utf8Value script_name(frame->GetScriptName());
10460  if (*script_name == NULL) {
10461    // The situation where there is no associated script, like for evals.
10462    CHECK(expected_script_name == NULL);
10463  } else {
10464    CHECK(strstr(*script_name, expected_script_name) != NULL);
10465  }
10466  CHECK(strstr(*func_name, expected_func_name) != NULL);
10467  CHECK_EQ(expected_line_number, frame->GetLineNumber());
10468  CHECK_EQ(expected_column, frame->GetColumn());
10469  CHECK_EQ(is_eval, frame->IsEval());
10470  CHECK_EQ(is_constructor, frame->IsConstructor());
10471}
10472
10473
10474v8::Handle<Value> AnalyzeStackInNativeCode(const v8::Arguments& args) {
10475  v8::HandleScope scope;
10476  const char* origin = "capture-stack-trace-test";
10477  const int kOverviewTest = 1;
10478  const int kDetailedTest = 2;
10479
10480  ASSERT(args.Length() == 1);
10481
10482  int testGroup = args[0]->Int32Value();
10483  if (testGroup == kOverviewTest) {
10484    v8::Handle<v8::StackTrace> stackTrace =
10485        v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kOverview);
10486    CHECK_EQ(4, stackTrace->GetFrameCount());
10487    checkStackFrame(origin, "bar", 2, 10, false, false,
10488                    stackTrace->GetFrame(0));
10489    checkStackFrame(origin, "foo", 6, 3, false, false,
10490                    stackTrace->GetFrame(1));
10491    checkStackFrame(NULL, "", 1, 1, false, false,
10492                    stackTrace->GetFrame(2));
10493    // The last frame is an anonymous function that has the initial call.
10494    checkStackFrame(origin, "", 8, 7, false, false,
10495                    stackTrace->GetFrame(3));
10496
10497    CHECK(stackTrace->AsArray()->IsArray());
10498  } else if (testGroup == kDetailedTest) {
10499    v8::Handle<v8::StackTrace> stackTrace =
10500        v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
10501    CHECK_EQ(4, stackTrace->GetFrameCount());
10502    checkStackFrame(origin, "bat", 4, 22, false, false,
10503                    stackTrace->GetFrame(0));
10504    checkStackFrame(origin, "baz", 8, 3, false, true,
10505                    stackTrace->GetFrame(1));
10506#ifdef ENABLE_DEBUGGER_SUPPORT
10507    bool is_eval = true;
10508#else  // ENABLE_DEBUGGER_SUPPORT
10509    bool is_eval = false;
10510#endif  // ENABLE_DEBUGGER_SUPPORT
10511
10512    checkStackFrame(NULL, "", 1, 1, is_eval, false,
10513                    stackTrace->GetFrame(2));
10514    // The last frame is an anonymous function that has the initial call to foo.
10515    checkStackFrame(origin, "", 10, 1, false, false,
10516                    stackTrace->GetFrame(3));
10517
10518    CHECK(stackTrace->AsArray()->IsArray());
10519  }
10520  return v8::Undefined();
10521}
10522
10523
10524// Tests the C++ StackTrace API.
10525THREADED_TEST(CaptureStackTrace) {
10526  v8::HandleScope scope;
10527  v8::Handle<v8::String> origin = v8::String::New("capture-stack-trace-test");
10528  Local<ObjectTemplate> templ = ObjectTemplate::New();
10529  templ->Set(v8_str("AnalyzeStackInNativeCode"),
10530             v8::FunctionTemplate::New(AnalyzeStackInNativeCode));
10531  LocalContext context(0, templ);
10532
10533  // Test getting OVERVIEW information. Should ignore information that is not
10534  // script name, function name, line number, and column offset.
10535  const char *overview_source =
10536    "function bar() {\n"
10537    "  var y; AnalyzeStackInNativeCode(1);\n"
10538    "}\n"
10539    "function foo() {\n"
10540    "\n"
10541    "  bar();\n"
10542    "}\n"
10543    "var x;eval('new foo();');";
10544  v8::Handle<v8::String> overview_src = v8::String::New(overview_source);
10545  v8::Handle<Value> overview_result =
10546      v8::Script::New(overview_src, origin)->Run();
10547  ASSERT(!overview_result.IsEmpty());
10548  ASSERT(overview_result->IsObject());
10549
10550  // Test getting DETAILED information.
10551  const char *detailed_source =
10552    "function bat() {AnalyzeStackInNativeCode(2);\n"
10553    "}\n"
10554    "\n"
10555    "function baz() {\n"
10556    "  bat();\n"
10557    "}\n"
10558    "eval('new baz();');";
10559  v8::Handle<v8::String> detailed_src = v8::String::New(detailed_source);
10560  // Make the script using a non-zero line and column offset.
10561  v8::Handle<v8::Integer> line_offset = v8::Integer::New(3);
10562  v8::Handle<v8::Integer> column_offset = v8::Integer::New(5);
10563  v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
10564  v8::Handle<v8::Script> detailed_script(
10565      v8::Script::New(detailed_src, &detailed_origin));
10566  v8::Handle<Value> detailed_result = detailed_script->Run();
10567  ASSERT(!detailed_result.IsEmpty());
10568  ASSERT(detailed_result->IsObject());
10569}
10570
10571
10572static void StackTraceForUncaughtExceptionListener(
10573    v8::Handle<v8::Message> message,
10574    v8::Handle<Value>) {
10575  v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
10576  CHECK_EQ(2, stack_trace->GetFrameCount());
10577  checkStackFrame("origin", "foo", 2, 3, false, false,
10578                  stack_trace->GetFrame(0));
10579  checkStackFrame("origin", "bar", 5, 3, false, false,
10580                  stack_trace->GetFrame(1));
10581}
10582
10583TEST(CaptureStackTraceForUncaughtException) {
10584  report_count = 0;
10585  v8::HandleScope scope;
10586  LocalContext env;
10587  v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
10588  v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
10589
10590  Script::Compile(v8_str("function foo() {\n"
10591                         "  throw 1;\n"
10592                         "};\n"
10593                         "function bar() {\n"
10594                         "  foo();\n"
10595                         "};"),
10596                  v8_str("origin"))->Run();
10597  v8::Local<v8::Object> global = env->Global();
10598  Local<Value> trouble = global->Get(v8_str("bar"));
10599  CHECK(trouble->IsFunction());
10600  Function::Cast(*trouble)->Call(global, 0, NULL);
10601  v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
10602  v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
10603}
10604
10605
10606v8::Handle<Value> AnalyzeStackOfEvalWithSourceURL(const v8::Arguments& args) {
10607  v8::HandleScope scope;
10608  v8::Handle<v8::StackTrace> stackTrace =
10609      v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
10610  CHECK_EQ(5, stackTrace->GetFrameCount());
10611  v8::Handle<v8::String> url = v8_str("eval_url");
10612  for (int i = 0; i < 3; i++) {
10613    v8::Handle<v8::String> name =
10614        stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
10615    CHECK(!name.IsEmpty());
10616    CHECK_EQ(url, name);
10617  }
10618  return v8::Undefined();
10619}
10620
10621
10622TEST(SourceURLInStackTrace) {
10623  v8::HandleScope scope;
10624  Local<ObjectTemplate> templ = ObjectTemplate::New();
10625  templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
10626             v8::FunctionTemplate::New(AnalyzeStackOfEvalWithSourceURL));
10627  LocalContext context(0, templ);
10628
10629  const char *source =
10630    "function outer() {\n"
10631    "function bar() {\n"
10632    "  AnalyzeStackOfEvalWithSourceURL();\n"
10633    "}\n"
10634    "function foo() {\n"
10635    "\n"
10636    "  bar();\n"
10637    "}\n"
10638    "foo();\n"
10639    "}\n"
10640    "eval('(' + outer +')()//@ sourceURL=eval_url');";
10641  CHECK(CompileRun(source)->IsUndefined());
10642}
10643
10644
10645// Test that idle notification can be handled and eventually returns true.
10646THREADED_TEST(IdleNotification) {
10647  bool rv = false;
10648  for (int i = 0; i < 100; i++) {
10649    rv = v8::V8::IdleNotification();
10650    if (rv)
10651      break;
10652  }
10653  CHECK(rv == true);
10654}
10655
10656
10657static uint32_t* stack_limit;
10658
10659static v8::Handle<Value> GetStackLimitCallback(const v8::Arguments& args) {
10660  stack_limit = reinterpret_cast<uint32_t*>(i::StackGuard::real_climit());
10661  return v8::Undefined();
10662}
10663
10664
10665// Uses the address of a local variable to determine the stack top now.
10666// Given a size, returns an address that is that far from the current
10667// top of stack.
10668static uint32_t* ComputeStackLimit(uint32_t size) {
10669  uint32_t* answer = &size - (size / sizeof(size));
10670  // If the size is very large and the stack is very near the bottom of
10671  // memory then the calculation above may wrap around and give an address
10672  // that is above the (downwards-growing) stack.  In that case we return
10673  // a very low address.
10674  if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
10675  return answer;
10676}
10677
10678
10679TEST(SetResourceConstraints) {
10680  static const int K = 1024;
10681  uint32_t* set_limit = ComputeStackLimit(128 * K);
10682
10683  // Set stack limit.
10684  v8::ResourceConstraints constraints;
10685  constraints.set_stack_limit(set_limit);
10686  CHECK(v8::SetResourceConstraints(&constraints));
10687
10688  // Execute a script.
10689  v8::HandleScope scope;
10690  LocalContext env;
10691  Local<v8::FunctionTemplate> fun_templ =
10692      v8::FunctionTemplate::New(GetStackLimitCallback);
10693  Local<Function> fun = fun_templ->GetFunction();
10694  env->Global()->Set(v8_str("get_stack_limit"), fun);
10695  CompileRun("get_stack_limit();");
10696
10697  CHECK(stack_limit == set_limit);
10698}
10699
10700
10701TEST(SetResourceConstraintsInThread) {
10702  uint32_t* set_limit;
10703  {
10704    v8::Locker locker;
10705    static const int K = 1024;
10706    set_limit = ComputeStackLimit(128 * K);
10707
10708    // Set stack limit.
10709    v8::ResourceConstraints constraints;
10710    constraints.set_stack_limit(set_limit);
10711    CHECK(v8::SetResourceConstraints(&constraints));
10712
10713    // Execute a script.
10714    v8::HandleScope scope;
10715    LocalContext env;
10716    Local<v8::FunctionTemplate> fun_templ =
10717        v8::FunctionTemplate::New(GetStackLimitCallback);
10718    Local<Function> fun = fun_templ->GetFunction();
10719    env->Global()->Set(v8_str("get_stack_limit"), fun);
10720    CompileRun("get_stack_limit();");
10721
10722    CHECK(stack_limit == set_limit);
10723  }
10724  {
10725    v8::Locker locker;
10726    CHECK(stack_limit == set_limit);
10727  }
10728}
10729
10730
10731THREADED_TEST(GetHeapStatistics) {
10732  v8::HandleScope scope;
10733  LocalContext c1;
10734  v8::HeapStatistics heap_statistics;
10735  CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
10736  CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
10737  v8::V8::GetHeapStatistics(&heap_statistics);
10738  CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
10739  CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
10740}
10741
10742
10743static double DoubleFromBits(uint64_t value) {
10744  double target;
10745#ifdef BIG_ENDIAN_FLOATING_POINT
10746  const int kIntSize = 4;
10747  // Somebody swapped the lower and higher half of doubles.
10748  memcpy(&target, reinterpret_cast<char*>(&value) + kIntSize, kIntSize);
10749  memcpy(reinterpret_cast<char*>(&target) + kIntSize, &value, kIntSize);
10750#else
10751  memcpy(&target, &value, sizeof(target));
10752#endif
10753  return target;
10754}
10755
10756
10757static uint64_t DoubleToBits(double value) {
10758  uint64_t target;
10759#ifdef BIG_ENDIAN_FLOATING_POINT
10760  const int kIntSize = 4;
10761  // Somebody swapped the lower and higher half of doubles.
10762  memcpy(&target, reinterpret_cast<char*>(&value) + kIntSize, kIntSize);
10763  memcpy(reinterpret_cast<char*>(&target) + kIntSize, &value, kIntSize);
10764#else
10765  memcpy(&target, &value, sizeof(target));
10766#endif
10767  return target;
10768}
10769
10770
10771static double DoubleToDateTime(double input) {
10772  double date_limit = 864e13;
10773  if (IsNaN(input) || input < -date_limit || input > date_limit) {
10774    return i::OS::nan_value();
10775  }
10776  return (input < 0) ? -(floor(-input)) : floor(input);
10777}
10778
10779// We don't have a consistent way to write 64-bit constants syntactically, so we
10780// split them into two 32-bit constants and combine them programmatically.
10781static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
10782  return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
10783}
10784
10785
10786THREADED_TEST(QuietSignalingNaNs) {
10787  v8::HandleScope scope;
10788  LocalContext context;
10789  v8::TryCatch try_catch;
10790
10791  // Special double values.
10792  double snan = DoubleFromBits(0x7ff00000, 0x00000001);
10793  double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
10794  double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
10795  double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
10796  double min_normal = DoubleFromBits(0x00100000, 0x00000000);
10797  double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
10798  double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
10799
10800  // Date values are capped at +/-100000000 days (times 864e5 ms per day)
10801  // on either side of the epoch.
10802  double date_limit = 864e13;
10803
10804  double test_values[] = {
10805      snan,
10806      qnan,
10807      infinity,
10808      max_normal,
10809      date_limit + 1,
10810      date_limit,
10811      min_normal,
10812      max_denormal,
10813      min_denormal,
10814      0,
10815      -0,
10816      -min_denormal,
10817      -max_denormal,
10818      -min_normal,
10819      -date_limit,
10820      -date_limit - 1,
10821      -max_normal,
10822      -infinity,
10823      -qnan,
10824      -snan
10825  };
10826  int num_test_values = 20;
10827
10828  for (int i = 0; i < num_test_values; i++) {
10829    double test_value = test_values[i];
10830
10831    // Check that Number::New preserves non-NaNs and quiets SNaNs.
10832    v8::Handle<v8::Value> number = v8::Number::New(test_value);
10833    double stored_number = number->NumberValue();
10834    if (!IsNaN(test_value)) {
10835      CHECK_EQ(test_value, stored_number);
10836    } else {
10837      uint64_t stored_bits = DoubleToBits(stored_number);
10838      // Check if quiet nan (bits 51..62 all set).
10839      CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
10840    }
10841
10842    // Check that Date::New preserves non-NaNs in the date range and
10843    // quiets SNaNs.
10844    v8::Handle<v8::Value> date = v8::Date::New(test_value);
10845    double expected_stored_date = DoubleToDateTime(test_value);
10846    double stored_date = date->NumberValue();
10847    if (!IsNaN(expected_stored_date)) {
10848      CHECK_EQ(expected_stored_date, stored_date);
10849    } else {
10850      uint64_t stored_bits = DoubleToBits(stored_date);
10851      // Check if quiet nan (bits 51..62 all set).
10852      CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
10853    }
10854  }
10855}
10856
10857
10858static v8::Handle<Value> SpaghettiIncident(const v8::Arguments& args) {
10859  v8::HandleScope scope;
10860  v8::TryCatch tc;
10861  v8::Handle<v8::String> str = args[0]->ToString();
10862  if (tc.HasCaught())
10863    return tc.ReThrow();
10864  return v8::Undefined();
10865}
10866
10867
10868// Test that an exception can be propagated down through a spaghetti
10869// stack using ReThrow.
10870THREADED_TEST(SpaghettiStackReThrow) {
10871  v8::HandleScope scope;
10872  LocalContext context;
10873  context->Global()->Set(
10874      v8::String::New("s"),
10875      v8::FunctionTemplate::New(SpaghettiIncident)->GetFunction());
10876  v8::TryCatch try_catch;
10877  CompileRun(
10878      "var i = 0;"
10879      "var o = {"
10880      "  toString: function () {"
10881      "    if (i == 10) {"
10882      "      throw 'Hey!';"
10883      "    } else {"
10884      "      i++;"
10885      "      return s(o);"
10886      "    }"
10887      "  }"
10888      "};"
10889      "s(o);");
10890  CHECK(try_catch.HasCaught());
10891  v8::String::Utf8Value value(try_catch.Exception());
10892  CHECK_EQ(0, strcmp(*value, "Hey!"));
10893}
10894
10895
10896TEST(Regress528) {
10897  v8::V8::Initialize();
10898
10899  v8::HandleScope scope;
10900  v8::Persistent<Context> context;
10901  v8::Persistent<Context> other_context;
10902  int gc_count;
10903
10904  // Create a context used to keep the code from aging in the compilation
10905  // cache.
10906  other_context = Context::New();
10907
10908  // Context-dependent context data creates reference from the compilation
10909  // cache to the global object.
10910  const char* source_simple = "1";
10911  context = Context::New();
10912  {
10913    v8::HandleScope scope;
10914
10915    context->Enter();
10916    Local<v8::String> obj = v8::String::New("");
10917    context->SetData(obj);
10918    CompileRun(source_simple);
10919    context->Exit();
10920  }
10921  context.Dispose();
10922  for (gc_count = 1; gc_count < 10; gc_count++) {
10923    other_context->Enter();
10924    CompileRun(source_simple);
10925    other_context->Exit();
10926    i::Heap::CollectAllGarbage(false);
10927    if (GetGlobalObjectsCount() == 1) break;
10928  }
10929  CHECK_GE(2, gc_count);
10930  CHECK_EQ(1, GetGlobalObjectsCount());
10931
10932  // Eval in a function creates reference from the compilation cache to the
10933  // global object.
10934  const char* source_eval = "function f(){eval('1')}; f()";
10935  context = Context::New();
10936  {
10937    v8::HandleScope scope;
10938
10939    context->Enter();
10940    CompileRun(source_eval);
10941    context->Exit();
10942  }
10943  context.Dispose();
10944  for (gc_count = 1; gc_count < 10; gc_count++) {
10945    other_context->Enter();
10946    CompileRun(source_eval);
10947    other_context->Exit();
10948    i::Heap::CollectAllGarbage(false);
10949    if (GetGlobalObjectsCount() == 1) break;
10950  }
10951  CHECK_GE(2, gc_count);
10952  CHECK_EQ(1, GetGlobalObjectsCount());
10953
10954  // Looking up the line number for an exception creates reference from the
10955  // compilation cache to the global object.
10956  const char* source_exception = "function f(){throw 1;} f()";
10957  context = Context::New();
10958  {
10959    v8::HandleScope scope;
10960
10961    context->Enter();
10962    v8::TryCatch try_catch;
10963    CompileRun(source_exception);
10964    CHECK(try_catch.HasCaught());
10965    v8::Handle<v8::Message> message = try_catch.Message();
10966    CHECK(!message.IsEmpty());
10967    CHECK_EQ(1, message->GetLineNumber());
10968    context->Exit();
10969  }
10970  context.Dispose();
10971  for (gc_count = 1; gc_count < 10; gc_count++) {
10972    other_context->Enter();
10973    CompileRun(source_exception);
10974    other_context->Exit();
10975    i::Heap::CollectAllGarbage(false);
10976    if (GetGlobalObjectsCount() == 1) break;
10977  }
10978  CHECK_GE(2, gc_count);
10979  CHECK_EQ(1, GetGlobalObjectsCount());
10980
10981  other_context.Dispose();
10982}
10983
10984
10985THREADED_TEST(ScriptOrigin) {
10986  v8::HandleScope scope;
10987  LocalContext env;
10988  v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
10989  v8::Handle<v8::String> script = v8::String::New(
10990      "function f() {}\n\nfunction g() {}");
10991  v8::Script::Compile(script, &origin)->Run();
10992  v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
10993      env->Global()->Get(v8::String::New("f")));
10994  v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
10995      env->Global()->Get(v8::String::New("g")));
10996
10997  v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
10998  CHECK_EQ("test", *v8::String::AsciiValue(script_origin_f.ResourceName()));
10999  CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
11000
11001  v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
11002  CHECK_EQ("test", *v8::String::AsciiValue(script_origin_g.ResourceName()));
11003  CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
11004}
11005
11006
11007THREADED_TEST(ScriptLineNumber) {
11008  v8::HandleScope scope;
11009  LocalContext env;
11010  v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
11011  v8::Handle<v8::String> script = v8::String::New(
11012      "function f() {}\n\nfunction g() {}");
11013  v8::Script::Compile(script, &origin)->Run();
11014  v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
11015      env->Global()->Get(v8::String::New("f")));
11016  v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
11017      env->Global()->Get(v8::String::New("g")));
11018  CHECK_EQ(0, f->GetScriptLineNumber());
11019  CHECK_EQ(2, g->GetScriptLineNumber());
11020}
11021
11022
11023static v8::Handle<Value> GetterWhichReturns42(Local<String> name,
11024                                              const AccessorInfo& info) {
11025  return v8_num(42);
11026}
11027
11028
11029static void SetterWhichSetsYOnThisTo23(Local<String> name,
11030                                       Local<Value> value,
11031                                       const AccessorInfo& info) {
11032  info.This()->Set(v8_str("y"), v8_num(23));
11033}
11034
11035
11036TEST(SetterOnConstructorPrototype) {
11037  v8::HandleScope scope;
11038  Local<ObjectTemplate> templ = ObjectTemplate::New();
11039  templ->SetAccessor(v8_str("x"),
11040                     GetterWhichReturns42,
11041                     SetterWhichSetsYOnThisTo23);
11042  LocalContext context;
11043  context->Global()->Set(v8_str("P"), templ->NewInstance());
11044  CompileRun("function C1() {"
11045             "  this.x = 23;"
11046             "};"
11047             "C1.prototype = P;"
11048             "function C2() {"
11049             "  this.x = 23"
11050             "};"
11051             "C2.prototype = { };"
11052             "C2.prototype.__proto__ = P;");
11053
11054  v8::Local<v8::Script> script;
11055  script = v8::Script::Compile(v8_str("new C1();"));
11056  for (int i = 0; i < 10; i++) {
11057    v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
11058    CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
11059    CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
11060  }
11061
11062  script = v8::Script::Compile(v8_str("new C2();"));
11063  for (int i = 0; i < 10; i++) {
11064    v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
11065    CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
11066    CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
11067  }
11068}
11069
11070
11071static v8::Handle<Value> NamedPropertyGetterWhichReturns42(
11072    Local<String> name, const AccessorInfo& info) {
11073  return v8_num(42);
11074}
11075
11076
11077static v8::Handle<Value> NamedPropertySetterWhichSetsYOnThisTo23(
11078    Local<String> name, Local<Value> value, const AccessorInfo& info) {
11079  if (name->Equals(v8_str("x"))) {
11080    info.This()->Set(v8_str("y"), v8_num(23));
11081  }
11082  return v8::Handle<Value>();
11083}
11084
11085
11086THREADED_TEST(InterceptorOnConstructorPrototype) {
11087  v8::HandleScope scope;
11088  Local<ObjectTemplate> templ = ObjectTemplate::New();
11089  templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
11090                                 NamedPropertySetterWhichSetsYOnThisTo23);
11091  LocalContext context;
11092  context->Global()->Set(v8_str("P"), templ->NewInstance());
11093  CompileRun("function C1() {"
11094             "  this.x = 23;"
11095             "};"
11096             "C1.prototype = P;"
11097             "function C2() {"
11098             "  this.x = 23"
11099             "};"
11100             "C2.prototype = { };"
11101             "C2.prototype.__proto__ = P;");
11102
11103  v8::Local<v8::Script> script;
11104  script = v8::Script::Compile(v8_str("new C1();"));
11105  for (int i = 0; i < 10; i++) {
11106    v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
11107    CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
11108    CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
11109  }
11110
11111  script = v8::Script::Compile(v8_str("new C2();"));
11112  for (int i = 0; i < 10; i++) {
11113    v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
11114    CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
11115    CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
11116  }
11117}
11118
11119
11120TEST(Bug618) {
11121  const char* source = "function C1() {"
11122                       "  this.x = 23;"
11123                       "};"
11124                       "C1.prototype = P;";
11125
11126  v8::HandleScope scope;
11127  LocalContext context;
11128  v8::Local<v8::Script> script;
11129
11130  // Use a simple object as prototype.
11131  v8::Local<v8::Object> prototype = v8::Object::New();
11132  prototype->Set(v8_str("y"), v8_num(42));
11133  context->Global()->Set(v8_str("P"), prototype);
11134
11135  // This compile will add the code to the compilation cache.
11136  CompileRun(source);
11137
11138  script = v8::Script::Compile(v8_str("new C1();"));
11139  // Allow enough iterations for the inobject slack tracking logic
11140  // to finalize instance size and install the fast construct stub.
11141  for (int i = 0; i < 256; i++) {
11142    v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
11143    CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
11144    CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
11145  }
11146
11147  // Use an API object with accessors as prototype.
11148  Local<ObjectTemplate> templ = ObjectTemplate::New();
11149  templ->SetAccessor(v8_str("x"),
11150                     GetterWhichReturns42,
11151                     SetterWhichSetsYOnThisTo23);
11152  context->Global()->Set(v8_str("P"), templ->NewInstance());
11153
11154  // This compile will get the code from the compilation cache.
11155  CompileRun(source);
11156
11157  script = v8::Script::Compile(v8_str("new C1();"));
11158  for (int i = 0; i < 10; i++) {
11159    v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
11160    CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
11161    CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
11162  }
11163}
11164
11165int prologue_call_count = 0;
11166int epilogue_call_count = 0;
11167int prologue_call_count_second = 0;
11168int epilogue_call_count_second = 0;
11169
11170void PrologueCallback(v8::GCType, v8::GCCallbackFlags) {
11171  ++prologue_call_count;
11172}
11173
11174void EpilogueCallback(v8::GCType, v8::GCCallbackFlags) {
11175  ++epilogue_call_count;
11176}
11177
11178void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
11179  ++prologue_call_count_second;
11180}
11181
11182void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
11183  ++epilogue_call_count_second;
11184}
11185
11186TEST(GCCallbacks) {
11187  LocalContext context;
11188
11189  v8::V8::AddGCPrologueCallback(PrologueCallback);
11190  v8::V8::AddGCEpilogueCallback(EpilogueCallback);
11191  CHECK_EQ(0, prologue_call_count);
11192  CHECK_EQ(0, epilogue_call_count);
11193  i::Heap::CollectAllGarbage(false);
11194  CHECK_EQ(1, prologue_call_count);
11195  CHECK_EQ(1, epilogue_call_count);
11196  v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
11197  v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
11198  i::Heap::CollectAllGarbage(false);
11199  CHECK_EQ(2, prologue_call_count);
11200  CHECK_EQ(2, epilogue_call_count);
11201  CHECK_EQ(1, prologue_call_count_second);
11202  CHECK_EQ(1, epilogue_call_count_second);
11203  v8::V8::RemoveGCPrologueCallback(PrologueCallback);
11204  v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
11205  i::Heap::CollectAllGarbage(false);
11206  CHECK_EQ(2, prologue_call_count);
11207  CHECK_EQ(2, epilogue_call_count);
11208  CHECK_EQ(2, prologue_call_count_second);
11209  CHECK_EQ(2, epilogue_call_count_second);
11210  v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
11211  v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
11212  i::Heap::CollectAllGarbage(false);
11213  CHECK_EQ(2, prologue_call_count);
11214  CHECK_EQ(2, epilogue_call_count);
11215  CHECK_EQ(2, prologue_call_count_second);
11216  CHECK_EQ(2, epilogue_call_count_second);
11217}
11218
11219
11220THREADED_TEST(AddToJSFunctionResultCache) {
11221  i::FLAG_allow_natives_syntax = true;
11222  v8::HandleScope scope;
11223
11224  LocalContext context;
11225
11226  const char* code =
11227      "(function() {"
11228      "  var key0 = 'a';"
11229      "  var key1 = 'b';"
11230      "  var r0 = %_GetFromCache(0, key0);"
11231      "  var r1 = %_GetFromCache(0, key1);"
11232      "  var r0_ = %_GetFromCache(0, key0);"
11233      "  if (r0 !== r0_)"
11234      "    return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
11235      "  var r1_ = %_GetFromCache(0, key1);"
11236      "  if (r1 !== r1_)"
11237      "    return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
11238      "  return 'PASSED';"
11239      "})()";
11240  i::Heap::ClearJSFunctionResultCaches();
11241  ExpectString(code, "PASSED");
11242}
11243
11244
11245static const int k0CacheSize = 16;
11246
11247THREADED_TEST(FillJSFunctionResultCache) {
11248  i::FLAG_allow_natives_syntax = true;
11249  v8::HandleScope scope;
11250
11251  LocalContext context;
11252
11253  const char* code =
11254      "(function() {"
11255      "  var k = 'a';"
11256      "  var r = %_GetFromCache(0, k);"
11257      "  for (var i = 0; i < 16; i++) {"
11258      "    %_GetFromCache(0, 'a' + i);"
11259      "  };"
11260      "  if (r === %_GetFromCache(0, k))"
11261      "    return 'FAILED: k0CacheSize is too small';"
11262      "  return 'PASSED';"
11263      "})()";
11264  i::Heap::ClearJSFunctionResultCaches();
11265  ExpectString(code, "PASSED");
11266}
11267
11268
11269THREADED_TEST(RoundRobinGetFromCache) {
11270  i::FLAG_allow_natives_syntax = true;
11271  v8::HandleScope scope;
11272
11273  LocalContext context;
11274
11275  const char* code =
11276      "(function() {"
11277      "  var keys = [];"
11278      "  for (var i = 0; i < 16; i++) keys.push(i);"
11279      "  var values = [];"
11280      "  for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
11281      "  for (var i = 0; i < 16; i++) {"
11282      "    var v = %_GetFromCache(0, keys[i]);"
11283      "    if (v !== values[i])"
11284      "      return 'Wrong value for ' + "
11285      "          keys[i] + ': ' + v + ' vs. ' + values[i];"
11286      "  };"
11287      "  return 'PASSED';"
11288      "})()";
11289  i::Heap::ClearJSFunctionResultCaches();
11290  ExpectString(code, "PASSED");
11291}
11292
11293
11294THREADED_TEST(ReverseGetFromCache) {
11295  i::FLAG_allow_natives_syntax = true;
11296  v8::HandleScope scope;
11297
11298  LocalContext context;
11299
11300  const char* code =
11301      "(function() {"
11302      "  var keys = [];"
11303      "  for (var i = 0; i < 16; i++) keys.push(i);"
11304      "  var values = [];"
11305      "  for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
11306      "  for (var i = 15; i >= 16; i--) {"
11307      "    var v = %_GetFromCache(0, keys[i]);"
11308      "    if (v !== values[i])"
11309      "      return 'Wrong value for ' + "
11310      "          keys[i] + ': ' + v + ' vs. ' + values[i];"
11311      "  };"
11312      "  return 'PASSED';"
11313      "})()";
11314  i::Heap::ClearJSFunctionResultCaches();
11315  ExpectString(code, "PASSED");
11316}
11317
11318
11319THREADED_TEST(TestEviction) {
11320  i::FLAG_allow_natives_syntax = true;
11321  v8::HandleScope scope;
11322
11323  LocalContext context;
11324
11325  const char* code =
11326      "(function() {"
11327      "  for (var i = 0; i < 2*16; i++) {"
11328      "    %_GetFromCache(0, 'a' + i);"
11329      "  };"
11330      "  return 'PASSED';"
11331      "})()";
11332  i::Heap::ClearJSFunctionResultCaches();
11333  ExpectString(code, "PASSED");
11334}
11335
11336
11337THREADED_TEST(TwoByteStringInAsciiCons) {
11338  // See Chromium issue 47824.
11339  v8::HandleScope scope;
11340
11341  LocalContext context;
11342  const char* init_code =
11343      "var str1 = 'abelspendabel';"
11344      "var str2 = str1 + str1 + str1;"
11345      "str2;";
11346  Local<Value> result = CompileRun(init_code);
11347
11348  CHECK(result->IsString());
11349  i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
11350  int length = string->length();
11351  CHECK(string->IsAsciiRepresentation());
11352
11353  FlattenString(string);
11354  i::Handle<i::String> flat_string = FlattenGetString(string);
11355
11356  CHECK(string->IsAsciiRepresentation());
11357  CHECK(flat_string->IsAsciiRepresentation());
11358
11359  // Create external resource.
11360  uint16_t* uc16_buffer = new uint16_t[length + 1];
11361
11362  i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
11363  uc16_buffer[length] = 0;
11364
11365  TestResource resource(uc16_buffer);
11366
11367  flat_string->MakeExternal(&resource);
11368
11369  CHECK(flat_string->IsTwoByteRepresentation());
11370
11371  // At this point, we should have a Cons string which is flat and ASCII,
11372  // with a first half that is a two-byte string (although it only contains
11373  // ASCII characters). This is a valid sequence of steps, and it can happen
11374  // in real pages.
11375
11376  CHECK(string->IsAsciiRepresentation());
11377  i::ConsString* cons = i::ConsString::cast(*string);
11378  CHECK_EQ(0, cons->second()->length());
11379  CHECK(cons->first()->IsTwoByteRepresentation());
11380
11381  // Check that some string operations work.
11382
11383  // Atom RegExp.
11384  Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
11385  CHECK_EQ(6, reresult->Int32Value());
11386
11387  // Nonatom RegExp.
11388  reresult = CompileRun("str2.match(/abe./g).length;");
11389  CHECK_EQ(6, reresult->Int32Value());
11390
11391  reresult = CompileRun("str2.search(/bel/g);");
11392  CHECK_EQ(1, reresult->Int32Value());
11393
11394  reresult = CompileRun("str2.search(/be./g);");
11395  CHECK_EQ(1, reresult->Int32Value());
11396
11397  ExpectTrue("/bel/g.test(str2);");
11398
11399  ExpectTrue("/be./g.test(str2);");
11400
11401  reresult = CompileRun("/bel/g.exec(str2);");
11402  CHECK(!reresult->IsNull());
11403
11404  reresult = CompileRun("/be./g.exec(str2);");
11405  CHECK(!reresult->IsNull());
11406
11407  ExpectString("str2.substring(2, 10);", "elspenda");
11408
11409  ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
11410
11411  ExpectString("str2.charAt(2);", "e");
11412
11413  reresult = CompileRun("str2.charCodeAt(2);");
11414  CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
11415}
11416
11417
11418// Failed access check callback that performs a GC on each invocation.
11419void FailedAccessCheckCallbackGC(Local<v8::Object> target,
11420                                 v8::AccessType type,
11421                                 Local<v8::Value> data) {
11422  i::Heap::CollectAllGarbage(true);
11423}
11424
11425
11426TEST(GCInFailedAccessCheckCallback) {
11427  // Install a failed access check callback that performs a GC on each
11428  // invocation. Then force the callback to be called from va
11429
11430  v8::V8::Initialize();
11431  v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
11432
11433  v8::HandleScope scope;
11434
11435  // Create an ObjectTemplate for global objects and install access
11436  // check callbacks that will block access.
11437  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
11438  global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
11439                                           IndexedGetAccessBlocker,
11440                                           v8::Handle<v8::Value>(),
11441                                           false);
11442
11443  // Create a context and set an x property on it's global object.
11444  LocalContext context0(NULL, global_template);
11445  context0->Global()->Set(v8_str("x"), v8_num(42));
11446  v8::Handle<v8::Object> global0 = context0->Global();
11447
11448  // Create a context with a different security token so that the
11449  // failed access check callback will be called on each access.
11450  LocalContext context1(NULL, global_template);
11451  context1->Global()->Set(v8_str("other"), global0);
11452
11453  // Get property with failed access check.
11454  ExpectUndefined("other.x");
11455
11456  // Get element with failed access check.
11457  ExpectUndefined("other[0]");
11458
11459  // Set property with failed access check.
11460  v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
11461  CHECK(result->IsObject());
11462
11463  // Set element with failed access check.
11464  result = CompileRun("other[0] = new Object()");
11465  CHECK(result->IsObject());
11466
11467  // Get property attribute with failed access check.
11468  ExpectFalse("\'x\' in other");
11469
11470  // Get property attribute for element with failed access check.
11471  ExpectFalse("0 in other");
11472
11473  // Delete property.
11474  ExpectFalse("delete other.x");
11475
11476  // Delete element.
11477  CHECK_EQ(false, global0->Delete(0));
11478
11479  // DefineAccessor.
11480  CHECK_EQ(false,
11481           global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
11482
11483  // Define JavaScript accessor.
11484  ExpectUndefined("Object.prototype.__defineGetter__.call("
11485                  "    other, \'x\', function() { return 42; })");
11486
11487  // LookupAccessor.
11488  ExpectUndefined("Object.prototype.__lookupGetter__.call("
11489                  "    other, \'x\')");
11490
11491  // HasLocalElement.
11492  ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
11493
11494  CHECK_EQ(false, global0->HasRealIndexedProperty(0));
11495  CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
11496  CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
11497
11498  // Reset the failed access check callback so it does not influence
11499  // the other tests.
11500  v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
11501}
11502
11503
11504TEST(StringCheckMultipleContexts) {
11505  const char* code =
11506      "(function() { return \"a\".charAt(0); })()";
11507
11508  {
11509    // Run the code twice in the first context to initialize the call IC.
11510    v8::HandleScope scope;
11511    LocalContext context1;
11512    ExpectString(code, "a");
11513    ExpectString(code, "a");
11514  }
11515
11516  {
11517    // Change the String.prototype in the second context and check
11518    // that the right function gets called.
11519    v8::HandleScope scope;
11520    LocalContext context2;
11521    CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
11522    ExpectString(code, "not a");
11523  }
11524}
11525
11526
11527TEST(NumberCheckMultipleContexts) {
11528  const char* code =
11529      "(function() { return (42).toString(); })()";
11530
11531  {
11532    // Run the code twice in the first context to initialize the call IC.
11533    v8::HandleScope scope;
11534    LocalContext context1;
11535    ExpectString(code, "42");
11536    ExpectString(code, "42");
11537  }
11538
11539  {
11540    // Change the Number.prototype in the second context and check
11541    // that the right function gets called.
11542    v8::HandleScope scope;
11543    LocalContext context2;
11544    CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
11545    ExpectString(code, "not 42");
11546  }
11547}
11548
11549
11550TEST(BooleanCheckMultipleContexts) {
11551  const char* code =
11552      "(function() { return true.toString(); })()";
11553
11554  {
11555    // Run the code twice in the first context to initialize the call IC.
11556    v8::HandleScope scope;
11557    LocalContext context1;
11558    ExpectString(code, "true");
11559    ExpectString(code, "true");
11560  }
11561
11562  {
11563    // Change the Boolean.prototype in the second context and check
11564    // that the right function gets called.
11565    v8::HandleScope scope;
11566    LocalContext context2;
11567    CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
11568    ExpectString(code, "");
11569  }
11570}
11571
11572
11573TEST(DontDeleteCellLoadIC) {
11574  const char* function_code =
11575      "function readCell() { while (true) { return cell; } }";
11576
11577  {
11578    // Run the code twice in the first context to initialize the load
11579    // IC for a don't delete cell.
11580    v8::HandleScope scope;
11581    LocalContext context1;
11582    CompileRun("var cell = \"first\";");
11583    ExpectBoolean("delete cell", false);
11584    CompileRun(function_code);
11585    ExpectString("readCell()", "first");
11586    ExpectString("readCell()", "first");
11587  }
11588
11589  {
11590    // Use a deletable cell in the second context.
11591    v8::HandleScope scope;
11592    LocalContext context2;
11593    CompileRun("cell = \"second\";");
11594    CompileRun(function_code);
11595    ExpectString("readCell()", "second");
11596    ExpectBoolean("delete cell", true);
11597    ExpectString("(function() {"
11598                 "  try {"
11599                 "    return readCell();"
11600                 "  } catch(e) {"
11601                 "    return e.toString();"
11602                 "  }"
11603                 "})()",
11604                 "ReferenceError: cell is not defined");
11605    CompileRun("cell = \"new_second\";");
11606    i::Heap::CollectAllGarbage(true);
11607    ExpectString("readCell()", "new_second");
11608    ExpectString("readCell()", "new_second");
11609  }
11610}
11611
11612
11613TEST(DontDeleteCellLoadICForceDelete) {
11614  const char* function_code =
11615      "function readCell() { while (true) { return cell; } }";
11616
11617  // Run the code twice to initialize the load IC for a don't delete
11618  // cell.
11619  v8::HandleScope scope;
11620  LocalContext context;
11621  CompileRun("var cell = \"value\";");
11622  ExpectBoolean("delete cell", false);
11623  CompileRun(function_code);
11624  ExpectString("readCell()", "value");
11625  ExpectString("readCell()", "value");
11626
11627  // Delete the cell using the API and check the inlined code works
11628  // correctly.
11629  CHECK(context->Global()->ForceDelete(v8_str("cell")));
11630  ExpectString("(function() {"
11631               "  try {"
11632               "    return readCell();"
11633               "  } catch(e) {"
11634               "    return e.toString();"
11635               "  }"
11636               "})()",
11637               "ReferenceError: cell is not defined");
11638}
11639
11640
11641TEST(DontDeleteCellLoadICAPI) {
11642  const char* function_code =
11643      "function readCell() { while (true) { return cell; } }";
11644
11645  // Run the code twice to initialize the load IC for a don't delete
11646  // cell created using the API.
11647  v8::HandleScope scope;
11648  LocalContext context;
11649  context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete);
11650  ExpectBoolean("delete cell", false);
11651  CompileRun(function_code);
11652  ExpectString("readCell()", "value");
11653  ExpectString("readCell()", "value");
11654
11655  // Delete the cell using the API and check the inlined code works
11656  // correctly.
11657  CHECK(context->Global()->ForceDelete(v8_str("cell")));
11658  ExpectString("(function() {"
11659               "  try {"
11660               "    return readCell();"
11661               "  } catch(e) {"
11662               "    return e.toString();"
11663               "  }"
11664               "})()",
11665               "ReferenceError: cell is not defined");
11666}
11667
11668
11669TEST(GlobalLoadICGC) {
11670  const char* function_code =
11671      "function readCell() { while (true) { return cell; } }";
11672
11673  // Check inline load code for a don't delete cell is cleared during
11674  // GC.
11675  {
11676    v8::HandleScope scope;
11677    LocalContext context;
11678    CompileRun("var cell = \"value\";");
11679    ExpectBoolean("delete cell", false);
11680    CompileRun(function_code);
11681    ExpectString("readCell()", "value");
11682    ExpectString("readCell()", "value");
11683  }
11684  {
11685    v8::HandleScope scope;
11686    LocalContext context2;
11687    // Hold the code object in the second context.
11688    CompileRun(function_code);
11689    CheckSurvivingGlobalObjectsCount(1);
11690  }
11691
11692  // Check inline load code for a deletable cell is cleared during GC.
11693  {
11694    v8::HandleScope scope;
11695    LocalContext context;
11696    CompileRun("cell = \"value\";");
11697    CompileRun(function_code);
11698    ExpectString("readCell()", "value");
11699    ExpectString("readCell()", "value");
11700  }
11701  {
11702    v8::HandleScope scope;
11703    LocalContext context2;
11704    // Hold the code object in the second context.
11705    CompileRun(function_code);
11706    CheckSurvivingGlobalObjectsCount(1);
11707  }
11708}
11709
11710
11711TEST(RegExp) {
11712  v8::HandleScope scope;
11713  LocalContext context;
11714
11715  v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
11716  CHECK(re->IsRegExp());
11717  CHECK(re->GetSource()->Equals(v8_str("foo")));
11718  CHECK_EQ(re->GetFlags(), v8::RegExp::kNone);
11719
11720  re = v8::RegExp::New(v8_str("bar"),
11721                       static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
11722                                                      v8::RegExp::kGlobal));
11723  CHECK(re->IsRegExp());
11724  CHECK(re->GetSource()->Equals(v8_str("bar")));
11725  CHECK_EQ(static_cast<int>(re->GetFlags()),
11726           v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal);
11727
11728  re = v8::RegExp::New(v8_str("baz"),
11729                       static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
11730                                                      v8::RegExp::kMultiline));
11731  CHECK(re->IsRegExp());
11732  CHECK(re->GetSource()->Equals(v8_str("baz")));
11733  CHECK_EQ(static_cast<int>(re->GetFlags()),
11734           v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline);
11735
11736  re = CompileRun("/quux/").As<v8::RegExp>();
11737  CHECK(re->IsRegExp());
11738  CHECK(re->GetSource()->Equals(v8_str("quux")));
11739  CHECK_EQ(re->GetFlags(), v8::RegExp::kNone);
11740
11741  re = CompileRun("/quux/gm").As<v8::RegExp>();
11742  CHECK(re->IsRegExp());
11743  CHECK(re->GetSource()->Equals(v8_str("quux")));
11744  CHECK_EQ(static_cast<int>(re->GetFlags()),
11745           v8::RegExp::kGlobal | v8::RegExp::kMultiline);
11746
11747  // Override the RegExp constructor and check the API constructor
11748  // still works.
11749  CompileRun("RegExp = function() {}");
11750
11751  re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
11752  CHECK(re->IsRegExp());
11753  CHECK(re->GetSource()->Equals(v8_str("foobar")));
11754  CHECK_EQ(re->GetFlags(), v8::RegExp::kNone);
11755
11756  re = v8::RegExp::New(v8_str("foobarbaz"),
11757                       static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
11758                                                      v8::RegExp::kMultiline));
11759  CHECK(re->IsRegExp());
11760  CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
11761  CHECK_EQ(static_cast<int>(re->GetFlags()),
11762           v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline);
11763
11764  context->Global()->Set(v8_str("re"), re);
11765  ExpectTrue("re.test('FoobarbaZ')");
11766
11767  v8::TryCatch try_catch;
11768  re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
11769  CHECK(re.IsEmpty());
11770  CHECK(try_catch.HasCaught());
11771  context->Global()->Set(v8_str("ex"), try_catch.Exception());
11772  ExpectTrue("ex instanceof SyntaxError");
11773}
11774
11775
11776static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
11777                                    const v8::AccessorInfo& info ) {
11778  return v8_str("42!");
11779}
11780
11781
11782static v8::Handle<v8::Array> Enumerator(const v8::AccessorInfo& info) {
11783  v8::Handle<v8::Array> result = v8::Array::New();
11784  result->Set(0, v8_str("universalAnswer"));
11785  return result;
11786}
11787
11788
11789TEST(NamedEnumeratorAndForIn) {
11790  v8::HandleScope handle_scope;
11791  LocalContext context;
11792  v8::Context::Scope context_scope(context.local());
11793
11794  v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New();
11795  tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
11796  context->Global()->Set(v8_str("o"), tmpl->NewInstance());
11797  v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
11798        "var result = []; for (var k in o) result.push(k); result"));
11799  CHECK_EQ(1, result->Length());
11800  CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
11801}
11802