test-api.cc revision 9dcf7e2f83591d471e88bf7d230651900b8e424b
1// Copyright 2007-2009 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6//     * Redistributions of source code must retain the above copyright
7//       notice, this list of conditions and the following disclaimer.
8//     * Redistributions in binary form must reproduce the above
9//       copyright notice, this list of conditions and the following
10//       disclaimer in the documentation and/or other materials provided
11//       with the distribution.
12//     * Neither the name of Google Inc. nor the names of its
13//       contributors may be used to endorse or promote products derived
14//       from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include <limits.h>
29
30#include "v8.h"
31
32#include "api.h"
33#include "compilation-cache.h"
34#include "execution.h"
35#include "snapshot.h"
36#include "platform.h"
37#include "top.h"
38#include "utils.h"
39#include "cctest.h"
40
41static const bool kLogThreading = true;
42
43static bool IsNaN(double x) {
44#ifdef WIN32
45  return _isnan(x);
46#else
47  return isnan(x);
48#endif
49}
50
51using ::v8::ObjectTemplate;
52using ::v8::Value;
53using ::v8::Context;
54using ::v8::Local;
55using ::v8::String;
56using ::v8::Script;
57using ::v8::Function;
58using ::v8::AccessorInfo;
59using ::v8::Extension;
60
61namespace i = ::v8::internal;
62
63
64static void ExpectString(const char* code, const char* expected) {
65  Local<Value> result = CompileRun(code);
66  CHECK(result->IsString());
67  String::AsciiValue ascii(result);
68  CHECK_EQ(expected, *ascii);
69}
70
71
72static void ExpectBoolean(const char* code, bool expected) {
73  Local<Value> result = CompileRun(code);
74  CHECK(result->IsBoolean());
75  CHECK_EQ(expected, result->BooleanValue());
76}
77
78
79static void ExpectTrue(const char* code) {
80  ExpectBoolean(code, true);
81}
82
83
84static void ExpectObject(const char* code, Local<Value> expected) {
85  Local<Value> result = CompileRun(code);
86  CHECK(result->Equals(expected));
87}
88
89
90static int signature_callback_count;
91static v8::Handle<Value> IncrementingSignatureCallback(
92    const v8::Arguments& args) {
93  ApiTestFuzzer::Fuzz();
94  signature_callback_count++;
95  v8::Handle<v8::Array> result = v8::Array::New(args.Length());
96  for (int i = 0; i < args.Length(); i++)
97    result->Set(v8::Integer::New(i), args[i]);
98  return result;
99}
100
101
102static v8::Handle<Value> SignatureCallback(const v8::Arguments& args) {
103  ApiTestFuzzer::Fuzz();
104  v8::Handle<v8::Array> result = v8::Array::New(args.Length());
105  for (int i = 0; i < args.Length(); i++) {
106    result->Set(v8::Integer::New(i), args[i]);
107  }
108  return result;
109}
110
111
112THREADED_TEST(Handles) {
113  v8::HandleScope scope;
114  Local<Context> local_env;
115  {
116    LocalContext env;
117    local_env = env.local();
118  }
119
120  // Local context should still be live.
121  CHECK(!local_env.IsEmpty());
122  local_env->Enter();
123
124  v8::Handle<v8::Primitive> undef = v8::Undefined();
125  CHECK(!undef.IsEmpty());
126  CHECK(undef->IsUndefined());
127
128  const char* c_source = "1 + 2 + 3";
129  Local<String> source = String::New(c_source);
130  Local<Script> script = Script::Compile(source);
131  CHECK_EQ(6, script->Run()->Int32Value());
132
133  local_env->Exit();
134}
135
136
137THREADED_TEST(ReceiverSignature) {
138  v8::HandleScope scope;
139  LocalContext env;
140  v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
141  v8::Handle<v8::Signature> sig = v8::Signature::New(fun);
142  fun->PrototypeTemplate()->Set(
143      v8_str("m"),
144      v8::FunctionTemplate::New(IncrementingSignatureCallback,
145                                v8::Handle<Value>(),
146                                sig));
147  env->Global()->Set(v8_str("Fun"), fun->GetFunction());
148  signature_callback_count = 0;
149  CompileRun(
150      "var o = new Fun();"
151      "o.m();");
152  CHECK_EQ(1, signature_callback_count);
153  v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New();
154  sub_fun->Inherit(fun);
155  env->Global()->Set(v8_str("SubFun"), sub_fun->GetFunction());
156  CompileRun(
157      "var o = new SubFun();"
158      "o.m();");
159  CHECK_EQ(2, signature_callback_count);
160
161  v8::TryCatch try_catch;
162  CompileRun(
163      "var o = { };"
164      "o.m = Fun.prototype.m;"
165      "o.m();");
166  CHECK_EQ(2, signature_callback_count);
167  CHECK(try_catch.HasCaught());
168  try_catch.Reset();
169  v8::Handle<v8::FunctionTemplate> unrel_fun = v8::FunctionTemplate::New();
170  sub_fun->Inherit(fun);
171  env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
172  CompileRun(
173      "var o = new UnrelFun();"
174      "o.m = Fun.prototype.m;"
175      "o.m();");
176  CHECK_EQ(2, signature_callback_count);
177  CHECK(try_catch.HasCaught());
178}
179
180
181
182
183THREADED_TEST(ArgumentSignature) {
184  v8::HandleScope scope;
185  LocalContext env;
186  v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New();
187  cons->SetClassName(v8_str("Cons"));
188  v8::Handle<v8::Signature> sig =
189      v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 1, &cons);
190  v8::Handle<v8::FunctionTemplate> fun =
191      v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), sig);
192  env->Global()->Set(v8_str("Cons"), cons->GetFunction());
193  env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
194
195  v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
196  CHECK(value1->IsTrue());
197
198  v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
199  CHECK(value2->IsTrue());
200
201  v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
202  CHECK(value3->IsTrue());
203
204  v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New();
205  cons1->SetClassName(v8_str("Cons1"));
206  v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New();
207  cons2->SetClassName(v8_str("Cons2"));
208  v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New();
209  cons3->SetClassName(v8_str("Cons3"));
210
211  v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
212  v8::Handle<v8::Signature> wsig =
213      v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 3, args);
214  v8::Handle<v8::FunctionTemplate> fun2 =
215      v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), wsig);
216
217  env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
218  env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
219  env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
220  env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
221  v8::Handle<Value> value4 = CompileRun(
222      "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
223      "'[object Cons1],[object Cons2],[object Cons3]'");
224  CHECK(value4->IsTrue());
225
226  v8::Handle<Value> value5 = CompileRun(
227      "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
228  CHECK(value5->IsTrue());
229
230  v8::Handle<Value> value6 = CompileRun(
231      "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
232  CHECK(value6->IsTrue());
233
234  v8::Handle<Value> value7 = CompileRun(
235      "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
236      "'[object Cons1],[object Cons2],[object Cons3],d';");
237  CHECK(value7->IsTrue());
238
239  v8::Handle<Value> value8 = CompileRun(
240      "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
241  CHECK(value8->IsTrue());
242}
243
244
245THREADED_TEST(HulIgennem) {
246  v8::HandleScope scope;
247  LocalContext env;
248  v8::Handle<v8::Primitive> undef = v8::Undefined();
249  Local<String> undef_str = undef->ToString();
250  char* value = i::NewArray<char>(undef_str->Length() + 1);
251  undef_str->WriteAscii(value);
252  CHECK_EQ(0, strcmp(value, "undefined"));
253  i::DeleteArray(value);
254}
255
256
257THREADED_TEST(Access) {
258  v8::HandleScope scope;
259  LocalContext env;
260  Local<v8::Object> obj = v8::Object::New();
261  Local<Value> foo_before = obj->Get(v8_str("foo"));
262  CHECK(foo_before->IsUndefined());
263  Local<String> bar_str = v8_str("bar");
264  obj->Set(v8_str("foo"), bar_str);
265  Local<Value> foo_after = obj->Get(v8_str("foo"));
266  CHECK(!foo_after->IsUndefined());
267  CHECK(foo_after->IsString());
268  CHECK_EQ(bar_str, foo_after);
269}
270
271
272THREADED_TEST(AccessElement) {
273  v8::HandleScope scope;
274  LocalContext env;
275  Local<v8::Object> obj = v8::Object::New();
276  Local<Value> before = obj->Get(1);
277  CHECK(before->IsUndefined());
278  Local<String> bar_str = v8_str("bar");
279  obj->Set(1, bar_str);
280  Local<Value> after = obj->Get(1);
281  CHECK(!after->IsUndefined());
282  CHECK(after->IsString());
283  CHECK_EQ(bar_str, after);
284
285  Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
286  CHECK_EQ(v8_str("a"), value->Get(0));
287  CHECK_EQ(v8_str("b"), value->Get(1));
288}
289
290
291THREADED_TEST(Script) {
292  v8::HandleScope scope;
293  LocalContext env;
294  const char* c_source = "1 + 2 + 3";
295  Local<String> source = String::New(c_source);
296  Local<Script> script = Script::Compile(source);
297  CHECK_EQ(6, script->Run()->Int32Value());
298}
299
300
301static uint16_t* AsciiToTwoByteString(const char* source) {
302  int array_length = i::StrLength(source) + 1;
303  uint16_t* converted = i::NewArray<uint16_t>(array_length);
304  for (int i = 0; i < array_length; i++) converted[i] = source[i];
305  return converted;
306}
307
308
309class TestResource: public String::ExternalStringResource {
310 public:
311  static int dispose_count;
312
313  explicit TestResource(uint16_t* data)
314      : data_(data), length_(0) {
315    while (data[length_]) ++length_;
316  }
317
318  ~TestResource() {
319    i::DeleteArray(data_);
320    ++dispose_count;
321  }
322
323  const uint16_t* data() const {
324    return data_;
325  }
326
327  size_t length() const {
328    return length_;
329  }
330 private:
331  uint16_t* data_;
332  size_t length_;
333};
334
335
336int TestResource::dispose_count = 0;
337
338
339class TestAsciiResource: public String::ExternalAsciiStringResource {
340 public:
341  static int dispose_count;
342
343  explicit TestAsciiResource(const char* data)
344      : data_(data),
345        length_(strlen(data)) { }
346
347  ~TestAsciiResource() {
348    i::DeleteArray(data_);
349    ++dispose_count;
350  }
351
352  const char* data() const {
353    return data_;
354  }
355
356  size_t length() const {
357    return length_;
358  }
359 private:
360  const char* data_;
361  size_t length_;
362};
363
364
365int TestAsciiResource::dispose_count = 0;
366
367
368THREADED_TEST(ScriptUsingStringResource) {
369  TestResource::dispose_count = 0;
370  const char* c_source = "1 + 2 * 3";
371  uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
372  {
373    v8::HandleScope scope;
374    LocalContext env;
375    TestResource* resource = new TestResource(two_byte_source);
376    Local<String> source = String::NewExternal(resource);
377    Local<Script> script = Script::Compile(source);
378    Local<Value> value = script->Run();
379    CHECK(value->IsNumber());
380    CHECK_EQ(7, value->Int32Value());
381    CHECK(source->IsExternal());
382    CHECK_EQ(resource,
383             static_cast<TestResource*>(source->GetExternalStringResource()));
384    v8::internal::Heap::CollectAllGarbage(false);
385    CHECK_EQ(0, TestResource::dispose_count);
386  }
387  v8::internal::CompilationCache::Clear();
388  v8::internal::Heap::CollectAllGarbage(false);
389  CHECK_EQ(1, TestResource::dispose_count);
390}
391
392
393THREADED_TEST(ScriptUsingAsciiStringResource) {
394  TestAsciiResource::dispose_count = 0;
395  const char* c_source = "1 + 2 * 3";
396  {
397    v8::HandleScope scope;
398    LocalContext env;
399    Local<String> source =
400        String::NewExternal(new TestAsciiResource(i::StrDup(c_source)));
401    Local<Script> script = Script::Compile(source);
402    Local<Value> value = script->Run();
403    CHECK(value->IsNumber());
404    CHECK_EQ(7, value->Int32Value());
405    v8::internal::Heap::CollectAllGarbage(false);
406    CHECK_EQ(0, TestAsciiResource::dispose_count);
407  }
408  v8::internal::CompilationCache::Clear();
409  v8::internal::Heap::CollectAllGarbage(false);
410  CHECK_EQ(1, TestAsciiResource::dispose_count);
411}
412
413
414THREADED_TEST(ScriptMakingExternalString) {
415  TestResource::dispose_count = 0;
416  uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
417  {
418    v8::HandleScope scope;
419    LocalContext env;
420    Local<String> source = String::New(two_byte_source);
421    // Trigger GCs so that the newly allocated string moves to old gen.
422    i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in survivor space now
423    i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in old gen now
424    bool success = source->MakeExternal(new TestResource(two_byte_source));
425    CHECK(success);
426    Local<Script> script = Script::Compile(source);
427    Local<Value> value = script->Run();
428    CHECK(value->IsNumber());
429    CHECK_EQ(7, value->Int32Value());
430    v8::internal::Heap::CollectAllGarbage(false);
431    CHECK_EQ(0, TestResource::dispose_count);
432  }
433  v8::internal::CompilationCache::Clear();
434  v8::internal::Heap::CollectAllGarbage(false);
435  CHECK_EQ(1, TestResource::dispose_count);
436}
437
438
439THREADED_TEST(ScriptMakingExternalAsciiString) {
440  TestAsciiResource::dispose_count = 0;
441  const char* c_source = "1 + 2 * 3";
442  {
443    v8::HandleScope scope;
444    LocalContext env;
445    Local<String> source = v8_str(c_source);
446    // Trigger GCs so that the newly allocated string moves to old gen.
447    i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in survivor space now
448    i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in old gen now
449    bool success = source->MakeExternal(
450        new TestAsciiResource(i::StrDup(c_source)));
451    CHECK(success);
452    Local<Script> script = Script::Compile(source);
453    Local<Value> value = script->Run();
454    CHECK(value->IsNumber());
455    CHECK_EQ(7, value->Int32Value());
456    v8::internal::Heap::CollectAllGarbage(false);
457    CHECK_EQ(0, TestAsciiResource::dispose_count);
458  }
459  v8::internal::CompilationCache::Clear();
460  v8::internal::Heap::CollectAllGarbage(false);
461  CHECK_EQ(1, TestAsciiResource::dispose_count);
462}
463
464
465TEST(MakingExternalStringConditions) {
466  v8::HandleScope scope;
467  LocalContext env;
468
469  // Free some space in the new space so that we can check freshness.
470  i::Heap::CollectGarbage(0, i::NEW_SPACE);
471  i::Heap::CollectGarbage(0, i::NEW_SPACE);
472
473  Local<String> small_string = String::New(AsciiToTwoByteString("small"));
474  // We should refuse to externalize newly created small string.
475  CHECK(!small_string->CanMakeExternal());
476  // Trigger GCs so that the newly allocated string moves to old gen.
477  i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in survivor space now
478  i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in old gen now
479  // Old space strings should be accepted.
480  CHECK(small_string->CanMakeExternal());
481
482  small_string = String::New(AsciiToTwoByteString("small 2"));
483  // We should refuse externalizing newly created small string.
484  CHECK(!small_string->CanMakeExternal());
485  for (int i = 0; i < 100; i++) {
486    String::Value value(small_string);
487  }
488  // Frequently used strings should be accepted.
489  CHECK(small_string->CanMakeExternal());
490
491  const int buf_size = 10 * 1024;
492  char* buf = i::NewArray<char>(buf_size);
493  memset(buf, 'a', buf_size);
494  buf[buf_size - 1] = '\0';
495  Local<String> large_string = String::New(AsciiToTwoByteString(buf));
496  i::DeleteArray(buf);
497  // Large strings should be immediately accepted.
498  CHECK(large_string->CanMakeExternal());
499}
500
501
502TEST(MakingExternalAsciiStringConditions) {
503  v8::HandleScope scope;
504  LocalContext env;
505
506  // Free some space in the new space so that we can check freshness.
507  i::Heap::CollectGarbage(0, i::NEW_SPACE);
508  i::Heap::CollectGarbage(0, i::NEW_SPACE);
509
510  Local<String> small_string = String::New("small");
511  // We should refuse to externalize newly created small string.
512  CHECK(!small_string->CanMakeExternal());
513  // Trigger GCs so that the newly allocated string moves to old gen.
514  i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in survivor space now
515  i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in old gen now
516  // Old space strings should be accepted.
517  CHECK(small_string->CanMakeExternal());
518
519  small_string = String::New("small 2");
520  // We should refuse externalizing newly created small string.
521  CHECK(!small_string->CanMakeExternal());
522  for (int i = 0; i < 100; i++) {
523    String::Value value(small_string);
524  }
525  // Frequently used strings should be accepted.
526  CHECK(small_string->CanMakeExternal());
527
528  const int buf_size = 10 * 1024;
529  char* buf = i::NewArray<char>(buf_size);
530  memset(buf, 'a', buf_size);
531  buf[buf_size - 1] = '\0';
532  Local<String> large_string = String::New(buf);
533  i::DeleteArray(buf);
534  // Large strings should be immediately accepted.
535  CHECK(large_string->CanMakeExternal());
536}
537
538
539THREADED_TEST(UsingExternalString) {
540  {
541    v8::HandleScope scope;
542    uint16_t* two_byte_string = AsciiToTwoByteString("test string");
543    Local<String> string =
544        String::NewExternal(new TestResource(two_byte_string));
545    i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
546    // Trigger GCs so that the newly allocated string moves to old gen.
547    i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in survivor space now
548    i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in old gen now
549    i::Handle<i::String> isymbol = i::Factory::SymbolFromString(istring);
550    CHECK(isymbol->IsSymbol());
551  }
552  i::Heap::CollectAllGarbage(false);
553  i::Heap::CollectAllGarbage(false);
554}
555
556
557THREADED_TEST(UsingExternalAsciiString) {
558  {
559    v8::HandleScope scope;
560    const char* one_byte_string = "test string";
561    Local<String> string = String::NewExternal(
562        new TestAsciiResource(i::StrDup(one_byte_string)));
563    i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
564    // Trigger GCs so that the newly allocated string moves to old gen.
565    i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in survivor space now
566    i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in old gen now
567    i::Handle<i::String> isymbol = i::Factory::SymbolFromString(istring);
568    CHECK(isymbol->IsSymbol());
569  }
570  i::Heap::CollectAllGarbage(false);
571  i::Heap::CollectAllGarbage(false);
572}
573
574
575THREADED_TEST(ScavengeExternalString) {
576  TestResource::dispose_count = 0;
577  bool in_new_space = false;
578  {
579    v8::HandleScope scope;
580    uint16_t* two_byte_string = AsciiToTwoByteString("test string");
581    Local<String> string =
582        String::NewExternal(new TestResource(two_byte_string));
583    i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
584    i::Heap::CollectGarbage(0, i::NEW_SPACE);
585    in_new_space = i::Heap::InNewSpace(*istring);
586    CHECK(in_new_space || i::Heap::old_data_space()->Contains(*istring));
587    CHECK_EQ(0, TestResource::dispose_count);
588  }
589  i::Heap::CollectGarbage(0, in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
590  CHECK_EQ(1, TestResource::dispose_count);
591}
592
593
594THREADED_TEST(ScavengeExternalAsciiString) {
595  TestAsciiResource::dispose_count = 0;
596  bool in_new_space = false;
597  {
598    v8::HandleScope scope;
599    const char* one_byte_string = "test string";
600    Local<String> string = String::NewExternal(
601        new TestAsciiResource(i::StrDup(one_byte_string)));
602    i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
603    i::Heap::CollectGarbage(0, i::NEW_SPACE);
604    in_new_space = i::Heap::InNewSpace(*istring);
605    CHECK(in_new_space || i::Heap::old_data_space()->Contains(*istring));
606    CHECK_EQ(0, TestAsciiResource::dispose_count);
607  }
608  i::Heap::CollectGarbage(0, in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
609  CHECK_EQ(1, TestAsciiResource::dispose_count);
610}
611
612
613class TestAsciiResourceWithDisposeControl: public TestAsciiResource {
614 public:
615  static int dispose_calls;
616
617  TestAsciiResourceWithDisposeControl(const char* data, bool dispose)
618      : TestAsciiResource(data),
619        dispose_(dispose) { }
620
621  void Dispose() {
622    ++dispose_calls;
623    if (dispose_) delete this;
624  }
625 private:
626  bool dispose_;
627};
628
629
630int TestAsciiResourceWithDisposeControl::dispose_calls = 0;
631
632
633TEST(ExternalStringWithDisposeHandling) {
634  const char* c_source = "1 + 2 * 3";
635
636  // Use a stack allocated external string resource allocated object.
637  TestAsciiResource::dispose_count = 0;
638  TestAsciiResourceWithDisposeControl::dispose_calls = 0;
639  TestAsciiResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
640  {
641    v8::HandleScope scope;
642    LocalContext env;
643    Local<String> source =  String::NewExternal(&res_stack);
644    Local<Script> script = Script::Compile(source);
645    Local<Value> value = script->Run();
646    CHECK(value->IsNumber());
647    CHECK_EQ(7, value->Int32Value());
648    v8::internal::Heap::CollectAllGarbage(false);
649    CHECK_EQ(0, TestAsciiResource::dispose_count);
650  }
651  v8::internal::CompilationCache::Clear();
652  v8::internal::Heap::CollectAllGarbage(false);
653  CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
654  CHECK_EQ(0, TestAsciiResource::dispose_count);
655
656  // Use a heap allocated external string resource allocated object.
657  TestAsciiResource::dispose_count = 0;
658  TestAsciiResourceWithDisposeControl::dispose_calls = 0;
659  TestAsciiResource* res_heap =
660      new TestAsciiResourceWithDisposeControl(i::StrDup(c_source), true);
661  {
662    v8::HandleScope scope;
663    LocalContext env;
664    Local<String> source =  String::NewExternal(res_heap);
665    Local<Script> script = Script::Compile(source);
666    Local<Value> value = script->Run();
667    CHECK(value->IsNumber());
668    CHECK_EQ(7, value->Int32Value());
669    v8::internal::Heap::CollectAllGarbage(false);
670    CHECK_EQ(0, TestAsciiResource::dispose_count);
671  }
672  v8::internal::CompilationCache::Clear();
673  v8::internal::Heap::CollectAllGarbage(false);
674  CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
675  CHECK_EQ(1, TestAsciiResource::dispose_count);
676}
677
678
679THREADED_TEST(StringConcat) {
680  {
681    v8::HandleScope scope;
682    LocalContext env;
683    const char* one_byte_string_1 = "function a_times_t";
684    const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
685    const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
686    const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
687    const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
688    const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
689    const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
690    Local<String> left = v8_str(one_byte_string_1);
691    Local<String> right = String::New(AsciiToTwoByteString(two_byte_string_1));
692    Local<String> source = String::Concat(left, right);
693    right = String::NewExternal(
694        new TestAsciiResource(i::StrDup(one_byte_extern_1)));
695    source = String::Concat(source, right);
696    right = String::NewExternal(
697        new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
698    source = String::Concat(source, right);
699    right = v8_str(one_byte_string_2);
700    source = String::Concat(source, right);
701    right = String::New(AsciiToTwoByteString(two_byte_string_2));
702    source = String::Concat(source, right);
703    right = String::NewExternal(
704        new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
705    source = String::Concat(source, right);
706    Local<Script> script = Script::Compile(source);
707    Local<Value> value = script->Run();
708    CHECK(value->IsNumber());
709    CHECK_EQ(68, value->Int32Value());
710  }
711  v8::internal::CompilationCache::Clear();
712  i::Heap::CollectAllGarbage(false);
713  i::Heap::CollectAllGarbage(false);
714}
715
716
717THREADED_TEST(GlobalProperties) {
718  v8::HandleScope scope;
719  LocalContext env;
720  v8::Handle<v8::Object> global = env->Global();
721  global->Set(v8_str("pi"), v8_num(3.1415926));
722  Local<Value> pi = global->Get(v8_str("pi"));
723  CHECK_EQ(3.1415926, pi->NumberValue());
724}
725
726
727static v8::Handle<Value> handle_call(const v8::Arguments& args) {
728  ApiTestFuzzer::Fuzz();
729  return v8_num(102);
730}
731
732
733static v8::Handle<Value> construct_call(const v8::Arguments& args) {
734  ApiTestFuzzer::Fuzz();
735  args.This()->Set(v8_str("x"), v8_num(1));
736  args.This()->Set(v8_str("y"), v8_num(2));
737  return args.This();
738}
739
740THREADED_TEST(FunctionTemplate) {
741  v8::HandleScope scope;
742  LocalContext env;
743  {
744    Local<v8::FunctionTemplate> fun_templ =
745        v8::FunctionTemplate::New(handle_call);
746    Local<Function> fun = fun_templ->GetFunction();
747    env->Global()->Set(v8_str("obj"), fun);
748    Local<Script> script = v8_compile("obj()");
749    CHECK_EQ(102, script->Run()->Int32Value());
750  }
751  // Use SetCallHandler to initialize a function template, should work like the
752  // previous one.
753  {
754    Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
755    fun_templ->SetCallHandler(handle_call);
756    Local<Function> fun = fun_templ->GetFunction();
757    env->Global()->Set(v8_str("obj"), fun);
758    Local<Script> script = v8_compile("obj()");
759    CHECK_EQ(102, script->Run()->Int32Value());
760  }
761  // Test constructor calls.
762  {
763    Local<v8::FunctionTemplate> fun_templ =
764        v8::FunctionTemplate::New(construct_call);
765    fun_templ->SetClassName(v8_str("funky"));
766    Local<Function> fun = fun_templ->GetFunction();
767    env->Global()->Set(v8_str("obj"), fun);
768    Local<Script> script = v8_compile("var s = new obj(); s.x");
769    CHECK_EQ(1, script->Run()->Int32Value());
770
771    Local<Value> result = v8_compile("(new obj()).toString()")->Run();
772    CHECK_EQ(v8_str("[object funky]"), result);
773  }
774}
775
776
777THREADED_TEST(FindInstanceInPrototypeChain) {
778  v8::HandleScope scope;
779  LocalContext env;
780
781  Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New();
782  Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New();
783  Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New();
784  derived->Inherit(base);
785
786  Local<v8::Function> base_function = base->GetFunction();
787  Local<v8::Function> derived_function = derived->GetFunction();
788  Local<v8::Function> other_function = other->GetFunction();
789
790  Local<v8::Object> base_instance = base_function->NewInstance();
791  Local<v8::Object> derived_instance = derived_function->NewInstance();
792  Local<v8::Object> derived_instance2 = derived_function->NewInstance();
793  Local<v8::Object> other_instance = other_function->NewInstance();
794  derived_instance2->Set(v8_str("__proto__"), derived_instance);
795  other_instance->Set(v8_str("__proto__"), derived_instance2);
796
797  // base_instance is only an instance of base.
798  CHECK_EQ(base_instance,
799           base_instance->FindInstanceInPrototypeChain(base));
800  CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
801  CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
802
803  // derived_instance is an instance of base and derived.
804  CHECK_EQ(derived_instance,
805           derived_instance->FindInstanceInPrototypeChain(base));
806  CHECK_EQ(derived_instance,
807           derived_instance->FindInstanceInPrototypeChain(derived));
808  CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
809
810  // other_instance is an instance of other and its immediate
811  // prototype derived_instance2 is an instance of base and derived.
812  // Note, derived_instance is an instance of base and derived too,
813  // but it comes after derived_instance2 in the prototype chain of
814  // other_instance.
815  CHECK_EQ(derived_instance2,
816           other_instance->FindInstanceInPrototypeChain(base));
817  CHECK_EQ(derived_instance2,
818           other_instance->FindInstanceInPrototypeChain(derived));
819  CHECK_EQ(other_instance,
820           other_instance->FindInstanceInPrototypeChain(other));
821}
822
823
824THREADED_TEST(TinyInteger) {
825  v8::HandleScope scope;
826  LocalContext env;
827  int32_t value = 239;
828  Local<v8::Integer> value_obj = v8::Integer::New(value);
829  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
830}
831
832
833THREADED_TEST(BigSmiInteger) {
834  v8::HandleScope scope;
835  LocalContext env;
836  int32_t value = i::Smi::kMaxValue;
837  // We cannot add one to a Smi::kMaxValue without wrapping.
838  if (i::kSmiValueSize < 32) {
839    CHECK(i::Smi::IsValid(value));
840    CHECK(!i::Smi::IsValid(value + 1));
841    Local<v8::Integer> value_obj = v8::Integer::New(value);
842    CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
843  }
844}
845
846
847THREADED_TEST(BigInteger) {
848  v8::HandleScope scope;
849  LocalContext env;
850  // We cannot add one to a Smi::kMaxValue without wrapping.
851  if (i::kSmiValueSize < 32) {
852    // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
853    // The code will not be run in that case, due to the "if" guard.
854    int32_t value =
855        static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
856    CHECK(value > i::Smi::kMaxValue);
857    CHECK(!i::Smi::IsValid(value));
858    Local<v8::Integer> value_obj = v8::Integer::New(value);
859    CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
860  }
861}
862
863
864THREADED_TEST(TinyUnsignedInteger) {
865  v8::HandleScope scope;
866  LocalContext env;
867  uint32_t value = 239;
868  Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
869  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
870}
871
872
873THREADED_TEST(BigUnsignedSmiInteger) {
874  v8::HandleScope scope;
875  LocalContext env;
876  uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
877  CHECK(i::Smi::IsValid(value));
878  CHECK(!i::Smi::IsValid(value + 1));
879  Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
880  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
881}
882
883
884THREADED_TEST(BigUnsignedInteger) {
885  v8::HandleScope scope;
886  LocalContext env;
887  uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
888  CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
889  CHECK(!i::Smi::IsValid(value));
890  Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
891  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
892}
893
894
895THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
896  v8::HandleScope scope;
897  LocalContext env;
898  uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
899  uint32_t value = INT32_MAX_AS_UINT + 1;
900  CHECK(value > INT32_MAX_AS_UINT);  // No overflow.
901  Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
902  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
903}
904
905
906THREADED_TEST(Number) {
907  v8::HandleScope scope;
908  LocalContext env;
909  double PI = 3.1415926;
910  Local<v8::Number> pi_obj = v8::Number::New(PI);
911  CHECK_EQ(PI, pi_obj->NumberValue());
912}
913
914
915THREADED_TEST(ToNumber) {
916  v8::HandleScope scope;
917  LocalContext env;
918  Local<String> str = v8_str("3.1415926");
919  CHECK_EQ(3.1415926, str->NumberValue());
920  v8::Handle<v8::Boolean> t = v8::True();
921  CHECK_EQ(1.0, t->NumberValue());
922  v8::Handle<v8::Boolean> f = v8::False();
923  CHECK_EQ(0.0, f->NumberValue());
924}
925
926
927THREADED_TEST(Date) {
928  v8::HandleScope scope;
929  LocalContext env;
930  double PI = 3.1415926;
931  Local<Value> date_obj = v8::Date::New(PI);
932  CHECK_EQ(3.0, date_obj->NumberValue());
933}
934
935
936THREADED_TEST(Boolean) {
937  v8::HandleScope scope;
938  LocalContext env;
939  v8::Handle<v8::Boolean> t = v8::True();
940  CHECK(t->Value());
941  v8::Handle<v8::Boolean> f = v8::False();
942  CHECK(!f->Value());
943  v8::Handle<v8::Primitive> u = v8::Undefined();
944  CHECK(!u->BooleanValue());
945  v8::Handle<v8::Primitive> n = v8::Null();
946  CHECK(!n->BooleanValue());
947  v8::Handle<String> str1 = v8_str("");
948  CHECK(!str1->BooleanValue());
949  v8::Handle<String> str2 = v8_str("x");
950  CHECK(str2->BooleanValue());
951  CHECK(!v8::Number::New(0)->BooleanValue());
952  CHECK(v8::Number::New(-1)->BooleanValue());
953  CHECK(v8::Number::New(1)->BooleanValue());
954  CHECK(v8::Number::New(42)->BooleanValue());
955  CHECK(!v8_compile("NaN")->Run()->BooleanValue());
956}
957
958
959static v8::Handle<Value> DummyCallHandler(const v8::Arguments& args) {
960  ApiTestFuzzer::Fuzz();
961  return v8_num(13.4);
962}
963
964
965static v8::Handle<Value> GetM(Local<String> name, const AccessorInfo&) {
966  ApiTestFuzzer::Fuzz();
967  return v8_num(876);
968}
969
970
971THREADED_TEST(GlobalPrototype) {
972  v8::HandleScope scope;
973  v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
974  func_templ->PrototypeTemplate()->Set(
975      "dummy",
976      v8::FunctionTemplate::New(DummyCallHandler));
977  v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
978  templ->Set("x", v8_num(200));
979  templ->SetAccessor(v8_str("m"), GetM);
980  LocalContext env(0, templ);
981  v8::Handle<v8::Object> obj = env->Global();
982  v8::Handle<Script> script = v8_compile("dummy()");
983  v8::Handle<Value> result = script->Run();
984  CHECK_EQ(13.4, result->NumberValue());
985  CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
986  CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
987}
988
989
990THREADED_TEST(ObjectTemplate) {
991  v8::HandleScope scope;
992  Local<ObjectTemplate> templ1 = ObjectTemplate::New();
993  templ1->Set("x", v8_num(10));
994  templ1->Set("y", v8_num(13));
995  LocalContext env;
996  Local<v8::Object> instance1 = templ1->NewInstance();
997  env->Global()->Set(v8_str("p"), instance1);
998  CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
999  CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1000  Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
1001  fun->PrototypeTemplate()->Set("nirk", v8_num(123));
1002  Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1003  templ2->Set("a", v8_num(12));
1004  templ2->Set("b", templ1);
1005  Local<v8::Object> instance2 = templ2->NewInstance();
1006  env->Global()->Set(v8_str("q"), instance2);
1007  CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1008  CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1009  CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1010  CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1011}
1012
1013
1014static v8::Handle<Value> GetFlabby(const v8::Arguments& args) {
1015  ApiTestFuzzer::Fuzz();
1016  return v8_num(17.2);
1017}
1018
1019
1020static v8::Handle<Value> GetKnurd(Local<String> property, const AccessorInfo&) {
1021  ApiTestFuzzer::Fuzz();
1022  return v8_num(15.2);
1023}
1024
1025
1026THREADED_TEST(DescriptorInheritance) {
1027  v8::HandleScope scope;
1028  v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New();
1029  super->PrototypeTemplate()->Set("flabby",
1030                                  v8::FunctionTemplate::New(GetFlabby));
1031  super->PrototypeTemplate()->Set("PI", v8_num(3.14));
1032
1033  super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1034
1035  v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New();
1036  base1->Inherit(super);
1037  base1->PrototypeTemplate()->Set("v1", v8_num(20.1));
1038
1039  v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New();
1040  base2->Inherit(super);
1041  base2->PrototypeTemplate()->Set("v2", v8_num(10.1));
1042
1043  LocalContext env;
1044
1045  env->Global()->Set(v8_str("s"), super->GetFunction());
1046  env->Global()->Set(v8_str("base1"), base1->GetFunction());
1047  env->Global()->Set(v8_str("base2"), base2->GetFunction());
1048
1049  // Checks right __proto__ chain.
1050  CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1051  CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1052
1053  CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1054
1055  // Instance accessor should not be visible on function object or its prototype
1056  CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1057  CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1058  CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1059
1060  env->Global()->Set(v8_str("obj"),
1061                     base1->GetFunction()->NewInstance());
1062  CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1063  CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1064  CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1065  CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1066  CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1067
1068  env->Global()->Set(v8_str("obj2"),
1069                     base2->GetFunction()->NewInstance());
1070  CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1071  CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1072  CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1073  CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1074  CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1075
1076  // base1 and base2 cannot cross reference to each's prototype
1077  CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1078  CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1079}
1080
1081
1082int echo_named_call_count;
1083
1084
1085static v8::Handle<Value> EchoNamedProperty(Local<String> name,
1086                                           const AccessorInfo& info) {
1087  ApiTestFuzzer::Fuzz();
1088  CHECK_EQ(v8_str("data"), info.Data());
1089  echo_named_call_count++;
1090  return name;
1091}
1092
1093
1094THREADED_TEST(NamedPropertyHandlerGetter) {
1095  echo_named_call_count = 0;
1096  v8::HandleScope scope;
1097  v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1098  templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
1099                                                     0, 0, 0, 0,
1100                                                     v8_str("data"));
1101  LocalContext env;
1102  env->Global()->Set(v8_str("obj"),
1103                     templ->GetFunction()->NewInstance());
1104  CHECK_EQ(echo_named_call_count, 0);
1105  v8_compile("obj.x")->Run();
1106  CHECK_EQ(echo_named_call_count, 1);
1107  const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
1108  v8::Handle<Value> str = CompileRun(code);
1109  String::AsciiValue value(str);
1110  CHECK_EQ(*value, "oddlepoddle");
1111  // Check default behavior
1112  CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
1113  CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
1114  CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
1115}
1116
1117
1118int echo_indexed_call_count = 0;
1119
1120
1121static v8::Handle<Value> EchoIndexedProperty(uint32_t index,
1122                                             const AccessorInfo& info) {
1123  ApiTestFuzzer::Fuzz();
1124  CHECK_EQ(v8_num(637), info.Data());
1125  echo_indexed_call_count++;
1126  return v8_num(index);
1127}
1128
1129
1130THREADED_TEST(IndexedPropertyHandlerGetter) {
1131  v8::HandleScope scope;
1132  v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1133  templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
1134                                                       0, 0, 0, 0,
1135                                                       v8_num(637));
1136  LocalContext env;
1137  env->Global()->Set(v8_str("obj"),
1138                     templ->GetFunction()->NewInstance());
1139  Local<Script> script = v8_compile("obj[900]");
1140  CHECK_EQ(script->Run()->Int32Value(), 900);
1141}
1142
1143
1144v8::Handle<v8::Object> bottom;
1145
1146static v8::Handle<Value> CheckThisIndexedPropertyHandler(
1147    uint32_t index,
1148    const AccessorInfo& info) {
1149  ApiTestFuzzer::Fuzz();
1150  CHECK(info.This()->Equals(bottom));
1151  return v8::Handle<Value>();
1152}
1153
1154static v8::Handle<Value> CheckThisNamedPropertyHandler(
1155    Local<String> name,
1156    const AccessorInfo& info) {
1157  ApiTestFuzzer::Fuzz();
1158  CHECK(info.This()->Equals(bottom));
1159  return v8::Handle<Value>();
1160}
1161
1162
1163v8::Handle<Value> CheckThisIndexedPropertySetter(uint32_t index,
1164                                                 Local<Value> value,
1165                                                 const AccessorInfo& info) {
1166  ApiTestFuzzer::Fuzz();
1167  CHECK(info.This()->Equals(bottom));
1168  return v8::Handle<Value>();
1169}
1170
1171
1172v8::Handle<Value> CheckThisNamedPropertySetter(Local<String> property,
1173                                               Local<Value> value,
1174                                               const AccessorInfo& info) {
1175  ApiTestFuzzer::Fuzz();
1176  CHECK(info.This()->Equals(bottom));
1177  return v8::Handle<Value>();
1178}
1179
1180v8::Handle<v8::Boolean> CheckThisIndexedPropertyQuery(
1181    uint32_t index,
1182    const AccessorInfo& info) {
1183  ApiTestFuzzer::Fuzz();
1184  CHECK(info.This()->Equals(bottom));
1185  return v8::Handle<v8::Boolean>();
1186}
1187
1188
1189v8::Handle<v8::Integer> CheckThisNamedPropertyQuery(Local<String> property,
1190                                                    const AccessorInfo& info) {
1191  ApiTestFuzzer::Fuzz();
1192  CHECK(info.This()->Equals(bottom));
1193  return v8::Handle<v8::Integer>();
1194}
1195
1196
1197v8::Handle<v8::Boolean> CheckThisIndexedPropertyDeleter(
1198    uint32_t index,
1199    const AccessorInfo& info) {
1200  ApiTestFuzzer::Fuzz();
1201  CHECK(info.This()->Equals(bottom));
1202  return v8::Handle<v8::Boolean>();
1203}
1204
1205
1206v8::Handle<v8::Boolean> CheckThisNamedPropertyDeleter(
1207    Local<String> property,
1208    const AccessorInfo& info) {
1209  ApiTestFuzzer::Fuzz();
1210  CHECK(info.This()->Equals(bottom));
1211  return v8::Handle<v8::Boolean>();
1212}
1213
1214
1215v8::Handle<v8::Array> CheckThisIndexedPropertyEnumerator(
1216    const AccessorInfo& info) {
1217  ApiTestFuzzer::Fuzz();
1218  CHECK(info.This()->Equals(bottom));
1219  return v8::Handle<v8::Array>();
1220}
1221
1222
1223v8::Handle<v8::Array> CheckThisNamedPropertyEnumerator(
1224    const AccessorInfo& info) {
1225  ApiTestFuzzer::Fuzz();
1226  CHECK(info.This()->Equals(bottom));
1227  return v8::Handle<v8::Array>();
1228}
1229
1230
1231THREADED_TEST(PropertyHandlerInPrototype) {
1232  v8::HandleScope scope;
1233  LocalContext env;
1234
1235  // Set up a prototype chain with three interceptors.
1236  v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1237  templ->InstanceTemplate()->SetIndexedPropertyHandler(
1238      CheckThisIndexedPropertyHandler,
1239      CheckThisIndexedPropertySetter,
1240      CheckThisIndexedPropertyQuery,
1241      CheckThisIndexedPropertyDeleter,
1242      CheckThisIndexedPropertyEnumerator);
1243
1244  templ->InstanceTemplate()->SetNamedPropertyHandler(
1245      CheckThisNamedPropertyHandler,
1246      CheckThisNamedPropertySetter,
1247      CheckThisNamedPropertyQuery,
1248      CheckThisNamedPropertyDeleter,
1249      CheckThisNamedPropertyEnumerator);
1250
1251  bottom = templ->GetFunction()->NewInstance();
1252  Local<v8::Object> top = templ->GetFunction()->NewInstance();
1253  Local<v8::Object> middle = templ->GetFunction()->NewInstance();
1254
1255  bottom->Set(v8_str("__proto__"), middle);
1256  middle->Set(v8_str("__proto__"), top);
1257  env->Global()->Set(v8_str("obj"), bottom);
1258
1259  // Indexed and named get.
1260  Script::Compile(v8_str("obj[0]"))->Run();
1261  Script::Compile(v8_str("obj.x"))->Run();
1262
1263  // Indexed and named set.
1264  Script::Compile(v8_str("obj[1] = 42"))->Run();
1265  Script::Compile(v8_str("obj.y = 42"))->Run();
1266
1267  // Indexed and named query.
1268  Script::Compile(v8_str("0 in obj"))->Run();
1269  Script::Compile(v8_str("'x' in obj"))->Run();
1270
1271  // Indexed and named deleter.
1272  Script::Compile(v8_str("delete obj[0]"))->Run();
1273  Script::Compile(v8_str("delete obj.x"))->Run();
1274
1275  // Enumerators.
1276  Script::Compile(v8_str("for (var p in obj) ;"))->Run();
1277}
1278
1279
1280static v8::Handle<Value> PrePropertyHandlerGet(Local<String> key,
1281                                               const AccessorInfo& info) {
1282  ApiTestFuzzer::Fuzz();
1283  if (v8_str("pre")->Equals(key)) {
1284    return v8_str("PrePropertyHandler: pre");
1285  }
1286  return v8::Handle<String>();
1287}
1288
1289
1290static v8::Handle<v8::Integer> PrePropertyHandlerQuery(Local<String> key,
1291                                                       const AccessorInfo&) {
1292  if (v8_str("pre")->Equals(key)) {
1293    return v8::Integer::New(v8::None);
1294  }
1295
1296  return v8::Handle<v8::Integer>();  // do not intercept the call
1297}
1298
1299
1300THREADED_TEST(PrePropertyHandler) {
1301  v8::HandleScope scope;
1302  v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
1303  desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
1304                                                    0,
1305                                                    PrePropertyHandlerQuery);
1306  LocalContext env(NULL, desc->InstanceTemplate());
1307  Script::Compile(v8_str(
1308      "var pre = 'Object: pre'; var on = 'Object: on';"))->Run();
1309  v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run();
1310  CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
1311  v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run();
1312  CHECK_EQ(v8_str("Object: on"), result_on);
1313  v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run();
1314  CHECK(result_post.IsEmpty());
1315}
1316
1317
1318THREADED_TEST(UndefinedIsNotEnumerable) {
1319  v8::HandleScope scope;
1320  LocalContext env;
1321  v8::Handle<Value> result = Script::Compile(v8_str(
1322      "this.propertyIsEnumerable(undefined)"))->Run();
1323  CHECK(result->IsFalse());
1324}
1325
1326
1327v8::Handle<Script> call_recursively_script;
1328static const int kTargetRecursionDepth = 200;  // near maximum
1329
1330
1331static v8::Handle<Value> CallScriptRecursivelyCall(const v8::Arguments& args) {
1332  ApiTestFuzzer::Fuzz();
1333  int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1334  if (depth == kTargetRecursionDepth) return v8::Undefined();
1335  args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1336  return call_recursively_script->Run();
1337}
1338
1339
1340static v8::Handle<Value> CallFunctionRecursivelyCall(
1341    const v8::Arguments& args) {
1342  ApiTestFuzzer::Fuzz();
1343  int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1344  if (depth == kTargetRecursionDepth) {
1345    printf("[depth = %d]\n", depth);
1346    return v8::Undefined();
1347  }
1348  args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1349  v8::Handle<Value> function =
1350      args.This()->Get(v8_str("callFunctionRecursively"));
1351  return function.As<Function>()->Call(args.This(), 0, NULL);
1352}
1353
1354
1355THREADED_TEST(DeepCrossLanguageRecursion) {
1356  v8::HandleScope scope;
1357  v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
1358  global->Set(v8_str("callScriptRecursively"),
1359              v8::FunctionTemplate::New(CallScriptRecursivelyCall));
1360  global->Set(v8_str("callFunctionRecursively"),
1361              v8::FunctionTemplate::New(CallFunctionRecursivelyCall));
1362  LocalContext env(NULL, global);
1363
1364  env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1365  call_recursively_script = v8_compile("callScriptRecursively()");
1366  v8::Handle<Value> result = call_recursively_script->Run();
1367  call_recursively_script = v8::Handle<Script>();
1368
1369  env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1370  Script::Compile(v8_str("callFunctionRecursively()"))->Run();
1371}
1372
1373
1374static v8::Handle<Value>
1375    ThrowingPropertyHandlerGet(Local<String> key, const AccessorInfo&) {
1376  ApiTestFuzzer::Fuzz();
1377  return v8::ThrowException(key);
1378}
1379
1380
1381static v8::Handle<Value> ThrowingPropertyHandlerSet(Local<String> key,
1382                                                    Local<Value>,
1383                                                    const AccessorInfo&) {
1384  v8::ThrowException(key);
1385  return v8::Undefined();  // not the same as v8::Handle<v8::Value>()
1386}
1387
1388
1389THREADED_TEST(CallbackExceptionRegression) {
1390  v8::HandleScope scope;
1391  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
1392  obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
1393                               ThrowingPropertyHandlerSet);
1394  LocalContext env;
1395  env->Global()->Set(v8_str("obj"), obj->NewInstance());
1396  v8::Handle<Value> otto = Script::Compile(v8_str(
1397      "try { with (obj) { otto; } } catch (e) { e; }"))->Run();
1398  CHECK_EQ(v8_str("otto"), otto);
1399  v8::Handle<Value> netto = Script::Compile(v8_str(
1400      "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run();
1401  CHECK_EQ(v8_str("netto"), netto);
1402}
1403
1404
1405THREADED_TEST(FunctionPrototype) {
1406  v8::HandleScope scope;
1407  Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New();
1408  Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
1409  LocalContext env;
1410  env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
1411  Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak"));
1412  CHECK_EQ(script->Run()->Int32Value(), 321);
1413}
1414
1415
1416THREADED_TEST(InternalFields) {
1417  v8::HandleScope scope;
1418  LocalContext env;
1419
1420  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1421  Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1422  instance_templ->SetInternalFieldCount(1);
1423  Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1424  CHECK_EQ(1, obj->InternalFieldCount());
1425  CHECK(obj->GetInternalField(0)->IsUndefined());
1426  obj->SetInternalField(0, v8_num(17));
1427  CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
1428}
1429
1430
1431THREADED_TEST(GlobalObjectInternalFields) {
1432  v8::HandleScope scope;
1433  Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
1434  global_template->SetInternalFieldCount(1);
1435  LocalContext env(NULL, global_template);
1436  v8::Handle<v8::Object> global_proxy = env->Global();
1437  v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
1438  CHECK_EQ(1, global->InternalFieldCount());
1439  CHECK(global->GetInternalField(0)->IsUndefined());
1440  global->SetInternalField(0, v8_num(17));
1441  CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
1442}
1443
1444
1445THREADED_TEST(InternalFieldsNativePointers) {
1446  v8::HandleScope scope;
1447  LocalContext env;
1448
1449  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1450  Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1451  instance_templ->SetInternalFieldCount(1);
1452  Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1453  CHECK_EQ(1, obj->InternalFieldCount());
1454  CHECK(obj->GetPointerFromInternalField(0) == NULL);
1455
1456  char* data = new char[100];
1457
1458  void* aligned = data;
1459  CHECK_EQ(0, reinterpret_cast<uintptr_t>(aligned) & 0x1);
1460  void* unaligned = data + 1;
1461  CHECK_EQ(1, reinterpret_cast<uintptr_t>(unaligned) & 0x1);
1462
1463  // Check reading and writing aligned pointers.
1464  obj->SetPointerInInternalField(0, aligned);
1465  i::Heap::CollectAllGarbage(false);
1466  CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1467
1468  // Check reading and writing unaligned pointers.
1469  obj->SetPointerInInternalField(0, unaligned);
1470  i::Heap::CollectAllGarbage(false);
1471  CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1472
1473  delete[] data;
1474}
1475
1476
1477THREADED_TEST(InternalFieldsNativePointersAndExternal) {
1478  v8::HandleScope scope;
1479  LocalContext env;
1480
1481  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1482  Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1483  instance_templ->SetInternalFieldCount(1);
1484  Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1485  CHECK_EQ(1, obj->InternalFieldCount());
1486  CHECK(obj->GetPointerFromInternalField(0) == NULL);
1487
1488  char* data = new char[100];
1489
1490  void* aligned = data;
1491  CHECK_EQ(0, reinterpret_cast<uintptr_t>(aligned) & 0x1);
1492  void* unaligned = data + 1;
1493  CHECK_EQ(1, reinterpret_cast<uintptr_t>(unaligned) & 0x1);
1494
1495  obj->SetPointerInInternalField(0, aligned);
1496  i::Heap::CollectAllGarbage(false);
1497  CHECK_EQ(aligned, v8::External::Unwrap(obj->GetInternalField(0)));
1498
1499  obj->SetPointerInInternalField(0, unaligned);
1500  i::Heap::CollectAllGarbage(false);
1501  CHECK_EQ(unaligned, v8::External::Unwrap(obj->GetInternalField(0)));
1502
1503  obj->SetInternalField(0, v8::External::Wrap(aligned));
1504  i::Heap::CollectAllGarbage(false);
1505  CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1506
1507  obj->SetInternalField(0, v8::External::Wrap(unaligned));
1508  i::Heap::CollectAllGarbage(false);
1509  CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1510
1511  delete[] data;
1512}
1513
1514
1515THREADED_TEST(IdentityHash) {
1516  v8::HandleScope scope;
1517  LocalContext env;
1518
1519  // Ensure that the test starts with an fresh heap to test whether the hash
1520  // code is based on the address.
1521  i::Heap::CollectAllGarbage(false);
1522  Local<v8::Object> obj = v8::Object::New();
1523  int hash = obj->GetIdentityHash();
1524  int hash1 = obj->GetIdentityHash();
1525  CHECK_EQ(hash, hash1);
1526  int hash2 = v8::Object::New()->GetIdentityHash();
1527  // Since the identity hash is essentially a random number two consecutive
1528  // objects should not be assigned the same hash code. If the test below fails
1529  // the random number generator should be evaluated.
1530  CHECK_NE(hash, hash2);
1531  i::Heap::CollectAllGarbage(false);
1532  int hash3 = v8::Object::New()->GetIdentityHash();
1533  // Make sure that the identity hash is not based on the initial address of
1534  // the object alone. If the test below fails the random number generator
1535  // should be evaluated.
1536  CHECK_NE(hash, hash3);
1537  int hash4 = obj->GetIdentityHash();
1538  CHECK_EQ(hash, hash4);
1539}
1540
1541
1542THREADED_TEST(HiddenProperties) {
1543  v8::HandleScope scope;
1544  LocalContext env;
1545
1546  v8::Local<v8::Object> obj = v8::Object::New();
1547  v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1548  v8::Local<v8::String> empty = v8_str("");
1549  v8::Local<v8::String> prop_name = v8_str("prop_name");
1550
1551  i::Heap::CollectAllGarbage(false);
1552
1553  // Make sure delete of a non-existent hidden value works
1554  CHECK(obj->DeleteHiddenValue(key));
1555
1556  CHECK(obj->SetHiddenValue(key, v8::Integer::New(1503)));
1557  CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
1558  CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
1559  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1560
1561  i::Heap::CollectAllGarbage(false);
1562
1563  // Make sure we do not find the hidden property.
1564  CHECK(!obj->Has(empty));
1565  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1566  CHECK(obj->Get(empty)->IsUndefined());
1567  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1568  CHECK(obj->Set(empty, v8::Integer::New(2003)));
1569  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1570  CHECK_EQ(2003, obj->Get(empty)->Int32Value());
1571
1572  i::Heap::CollectAllGarbage(false);
1573
1574  // Add another property and delete it afterwards to force the object in
1575  // slow case.
1576  CHECK(obj->Set(prop_name, v8::Integer::New(2008)));
1577  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1578  CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
1579  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1580  CHECK(obj->Delete(prop_name));
1581  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1582
1583  i::Heap::CollectAllGarbage(false);
1584
1585  CHECK(obj->DeleteHiddenValue(key));
1586  CHECK(obj->GetHiddenValue(key).IsEmpty());
1587}
1588
1589
1590static bool interceptor_for_hidden_properties_called;
1591static v8::Handle<Value> InterceptorForHiddenProperties(
1592    Local<String> name, const AccessorInfo& info) {
1593  interceptor_for_hidden_properties_called = true;
1594  return v8::Handle<Value>();
1595}
1596
1597
1598THREADED_TEST(HiddenPropertiesWithInterceptors) {
1599  v8::HandleScope scope;
1600  LocalContext context;
1601
1602  interceptor_for_hidden_properties_called = false;
1603
1604  v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1605
1606  // Associate an interceptor with an object and start setting hidden values.
1607  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
1608  Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
1609  instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
1610  Local<v8::Function> function = fun_templ->GetFunction();
1611  Local<v8::Object> obj = function->NewInstance();
1612  CHECK(obj->SetHiddenValue(key, v8::Integer::New(2302)));
1613  CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
1614  CHECK(!interceptor_for_hidden_properties_called);
1615}
1616
1617
1618THREADED_TEST(External) {
1619  v8::HandleScope scope;
1620  int x = 3;
1621  Local<v8::External> ext = v8::External::New(&x);
1622  LocalContext env;
1623  env->Global()->Set(v8_str("ext"), ext);
1624  Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
1625  v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
1626  int* ptr = static_cast<int*>(reext->Value());
1627  CHECK_EQ(x, 3);
1628  *ptr = 10;
1629  CHECK_EQ(x, 10);
1630
1631  // Make sure unaligned pointers are wrapped properly.
1632  char* data = i::StrDup("0123456789");
1633  Local<v8::Value> zero = v8::External::Wrap(&data[0]);
1634  Local<v8::Value> one = v8::External::Wrap(&data[1]);
1635  Local<v8::Value> two = v8::External::Wrap(&data[2]);
1636  Local<v8::Value> three = v8::External::Wrap(&data[3]);
1637
1638  char* char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(zero));
1639  CHECK_EQ('0', *char_ptr);
1640  char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(one));
1641  CHECK_EQ('1', *char_ptr);
1642  char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(two));
1643  CHECK_EQ('2', *char_ptr);
1644  char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(three));
1645  CHECK_EQ('3', *char_ptr);
1646  i::DeleteArray(data);
1647}
1648
1649
1650THREADED_TEST(GlobalHandle) {
1651  v8::Persistent<String> global;
1652  {
1653    v8::HandleScope scope;
1654    Local<String> str = v8_str("str");
1655    global = v8::Persistent<String>::New(str);
1656  }
1657  CHECK_EQ(global->Length(), 3);
1658  global.Dispose();
1659}
1660
1661
1662THREADED_TEST(ScriptException) {
1663  v8::HandleScope scope;
1664  LocalContext env;
1665  Local<Script> script = Script::Compile(v8_str("throw 'panama!';"));
1666  v8::TryCatch try_catch;
1667  Local<Value> result = script->Run();
1668  CHECK(result.IsEmpty());
1669  CHECK(try_catch.HasCaught());
1670  String::AsciiValue exception_value(try_catch.Exception());
1671  CHECK_EQ(*exception_value, "panama!");
1672}
1673
1674
1675bool message_received;
1676
1677
1678static void check_message(v8::Handle<v8::Message> message,
1679                          v8::Handle<Value> data) {
1680  CHECK_EQ(5.76, data->NumberValue());
1681  CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
1682  CHECK_EQ(7.56, message->GetScriptData()->NumberValue());
1683  message_received = true;
1684}
1685
1686
1687THREADED_TEST(MessageHandlerData) {
1688  message_received = false;
1689  v8::HandleScope scope;
1690  CHECK(!message_received);
1691  v8::V8::AddMessageListener(check_message, v8_num(5.76));
1692  LocalContext context;
1693  v8::ScriptOrigin origin =
1694      v8::ScriptOrigin(v8_str("6.75"));
1695  v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
1696                                                  &origin);
1697  script->SetData(v8_str("7.56"));
1698  script->Run();
1699  CHECK(message_received);
1700  // clear out the message listener
1701  v8::V8::RemoveMessageListeners(check_message);
1702}
1703
1704
1705THREADED_TEST(GetSetProperty) {
1706  v8::HandleScope scope;
1707  LocalContext context;
1708  context->Global()->Set(v8_str("foo"), v8_num(14));
1709  context->Global()->Set(v8_str("12"), v8_num(92));
1710  context->Global()->Set(v8::Integer::New(16), v8_num(32));
1711  context->Global()->Set(v8_num(13), v8_num(56));
1712  Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run();
1713  CHECK_EQ(14, foo->Int32Value());
1714  Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run();
1715  CHECK_EQ(92, twelve->Int32Value());
1716  Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run();
1717  CHECK_EQ(32, sixteen->Int32Value());
1718  Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run();
1719  CHECK_EQ(56, thirteen->Int32Value());
1720  CHECK_EQ(92, context->Global()->Get(v8::Integer::New(12))->Int32Value());
1721  CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
1722  CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
1723  CHECK_EQ(32, context->Global()->Get(v8::Integer::New(16))->Int32Value());
1724  CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
1725  CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
1726  CHECK_EQ(56, context->Global()->Get(v8::Integer::New(13))->Int32Value());
1727  CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
1728  CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
1729}
1730
1731
1732THREADED_TEST(PropertyAttributes) {
1733  v8::HandleScope scope;
1734  LocalContext context;
1735  // read-only
1736  Local<String> prop = v8_str("read_only");
1737  context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
1738  CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
1739  Script::Compile(v8_str("read_only = 9"))->Run();
1740  CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
1741  context->Global()->Set(prop, v8_num(10));
1742  CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
1743  // dont-delete
1744  prop = v8_str("dont_delete");
1745  context->Global()->Set(prop, v8_num(13), v8::DontDelete);
1746  CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
1747  Script::Compile(v8_str("delete dont_delete"))->Run();
1748  CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
1749}
1750
1751
1752THREADED_TEST(Array) {
1753  v8::HandleScope scope;
1754  LocalContext context;
1755  Local<v8::Array> array = v8::Array::New();
1756  CHECK_EQ(0, array->Length());
1757  CHECK(array->Get(0)->IsUndefined());
1758  CHECK(!array->Has(0));
1759  CHECK(array->Get(100)->IsUndefined());
1760  CHECK(!array->Has(100));
1761  array->Set(2, v8_num(7));
1762  CHECK_EQ(3, array->Length());
1763  CHECK(!array->Has(0));
1764  CHECK(!array->Has(1));
1765  CHECK(array->Has(2));
1766  CHECK_EQ(7, array->Get(2)->Int32Value());
1767  Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
1768  Local<v8::Array> arr = obj.As<v8::Array>();
1769  CHECK_EQ(3, arr->Length());
1770  CHECK_EQ(1, arr->Get(0)->Int32Value());
1771  CHECK_EQ(2, arr->Get(1)->Int32Value());
1772  CHECK_EQ(3, arr->Get(2)->Int32Value());
1773}
1774
1775
1776v8::Handle<Value> HandleF(const v8::Arguments& args) {
1777  v8::HandleScope scope;
1778  ApiTestFuzzer::Fuzz();
1779  Local<v8::Array> result = v8::Array::New(args.Length());
1780  for (int i = 0; i < args.Length(); i++)
1781    result->Set(i, args[i]);
1782  return scope.Close(result);
1783}
1784
1785
1786THREADED_TEST(Vector) {
1787  v8::HandleScope scope;
1788  Local<ObjectTemplate> global = ObjectTemplate::New();
1789  global->Set(v8_str("f"), v8::FunctionTemplate::New(HandleF));
1790  LocalContext context(0, global);
1791
1792  const char* fun = "f()";
1793  Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
1794  CHECK_EQ(0, a0->Length());
1795
1796  const char* fun2 = "f(11)";
1797  Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
1798  CHECK_EQ(1, a1->Length());
1799  CHECK_EQ(11, a1->Get(0)->Int32Value());
1800
1801  const char* fun3 = "f(12, 13)";
1802  Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
1803  CHECK_EQ(2, a2->Length());
1804  CHECK_EQ(12, a2->Get(0)->Int32Value());
1805  CHECK_EQ(13, a2->Get(1)->Int32Value());
1806
1807  const char* fun4 = "f(14, 15, 16)";
1808  Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
1809  CHECK_EQ(3, a3->Length());
1810  CHECK_EQ(14, a3->Get(0)->Int32Value());
1811  CHECK_EQ(15, a3->Get(1)->Int32Value());
1812  CHECK_EQ(16, a3->Get(2)->Int32Value());
1813
1814  const char* fun5 = "f(17, 18, 19, 20)";
1815  Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
1816  CHECK_EQ(4, a4->Length());
1817  CHECK_EQ(17, a4->Get(0)->Int32Value());
1818  CHECK_EQ(18, a4->Get(1)->Int32Value());
1819  CHECK_EQ(19, a4->Get(2)->Int32Value());
1820  CHECK_EQ(20, a4->Get(3)->Int32Value());
1821}
1822
1823
1824THREADED_TEST(FunctionCall) {
1825  v8::HandleScope scope;
1826  LocalContext context;
1827  CompileRun(
1828    "function Foo() {"
1829    "  var result = [];"
1830    "  for (var i = 0; i < arguments.length; i++) {"
1831    "    result.push(arguments[i]);"
1832    "  }"
1833    "  return result;"
1834    "}");
1835  Local<Function> Foo =
1836      Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
1837
1838  v8::Handle<Value>* args0 = NULL;
1839  Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
1840  CHECK_EQ(0, a0->Length());
1841
1842  v8::Handle<Value> args1[] = { v8_num(1.1) };
1843  Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
1844  CHECK_EQ(1, a1->Length());
1845  CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
1846
1847  v8::Handle<Value> args2[] = { v8_num(2.2),
1848                                v8_num(3.3) };
1849  Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
1850  CHECK_EQ(2, a2->Length());
1851  CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
1852  CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
1853
1854  v8::Handle<Value> args3[] = { v8_num(4.4),
1855                                v8_num(5.5),
1856                                v8_num(6.6) };
1857  Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
1858  CHECK_EQ(3, a3->Length());
1859  CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
1860  CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
1861  CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
1862
1863  v8::Handle<Value> args4[] = { v8_num(7.7),
1864                                v8_num(8.8),
1865                                v8_num(9.9),
1866                                v8_num(10.11) };
1867  Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
1868  CHECK_EQ(4, a4->Length());
1869  CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
1870  CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
1871  CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
1872  CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
1873}
1874
1875
1876static const char* js_code_causing_out_of_memory =
1877    "var a = new Array(); while(true) a.push(a);";
1878
1879
1880// These tests run for a long time and prevent us from running tests
1881// that come after them so they cannot run in parallel.
1882TEST(OutOfMemory) {
1883  // It's not possible to read a snapshot into a heap with different dimensions.
1884  if (v8::internal::Snapshot::IsEnabled()) return;
1885  // Set heap limits.
1886  static const int K = 1024;
1887  v8::ResourceConstraints constraints;
1888  constraints.set_max_young_space_size(256 * K);
1889  constraints.set_max_old_space_size(4 * K * K);
1890  v8::SetResourceConstraints(&constraints);
1891
1892  // Execute a script that causes out of memory.
1893  v8::HandleScope scope;
1894  LocalContext context;
1895  v8::V8::IgnoreOutOfMemoryException();
1896  Local<Script> script =
1897      Script::Compile(String::New(js_code_causing_out_of_memory));
1898  Local<Value> result = script->Run();
1899
1900  // Check for out of memory state.
1901  CHECK(result.IsEmpty());
1902  CHECK(context->HasOutOfMemoryException());
1903}
1904
1905
1906v8::Handle<Value> ProvokeOutOfMemory(const v8::Arguments& args) {
1907  ApiTestFuzzer::Fuzz();
1908
1909  v8::HandleScope scope;
1910  LocalContext context;
1911  Local<Script> script =
1912      Script::Compile(String::New(js_code_causing_out_of_memory));
1913  Local<Value> result = script->Run();
1914
1915  // Check for out of memory state.
1916  CHECK(result.IsEmpty());
1917  CHECK(context->HasOutOfMemoryException());
1918
1919  return result;
1920}
1921
1922
1923TEST(OutOfMemoryNested) {
1924  // It's not possible to read a snapshot into a heap with different dimensions.
1925  if (v8::internal::Snapshot::IsEnabled()) return;
1926  // Set heap limits.
1927  static const int K = 1024;
1928  v8::ResourceConstraints constraints;
1929  constraints.set_max_young_space_size(256 * K);
1930  constraints.set_max_old_space_size(4 * K * K);
1931  v8::SetResourceConstraints(&constraints);
1932
1933  v8::HandleScope scope;
1934  Local<ObjectTemplate> templ = ObjectTemplate::New();
1935  templ->Set(v8_str("ProvokeOutOfMemory"),
1936             v8::FunctionTemplate::New(ProvokeOutOfMemory));
1937  LocalContext context(0, templ);
1938  v8::V8::IgnoreOutOfMemoryException();
1939  Local<Value> result = CompileRun(
1940    "var thrown = false;"
1941    "try {"
1942    "  ProvokeOutOfMemory();"
1943    "} catch (e) {"
1944    "  thrown = true;"
1945    "}");
1946  // Check for out of memory state.
1947  CHECK(result.IsEmpty());
1948  CHECK(context->HasOutOfMemoryException());
1949}
1950
1951
1952TEST(HugeConsStringOutOfMemory) {
1953  // It's not possible to read a snapshot into a heap with different dimensions.
1954  if (v8::internal::Snapshot::IsEnabled()) return;
1955  v8::HandleScope scope;
1956  LocalContext context;
1957  // Set heap limits.
1958  static const int K = 1024;
1959  v8::ResourceConstraints constraints;
1960  constraints.set_max_young_space_size(256 * K);
1961  constraints.set_max_old_space_size(2 * K * K);
1962  v8::SetResourceConstraints(&constraints);
1963
1964  // Execute a script that causes out of memory.
1965  v8::V8::IgnoreOutOfMemoryException();
1966
1967  // Build huge string. This should fail with out of memory exception.
1968  Local<Value> result = CompileRun(
1969    "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();"
1970    "for (var i = 0; i < 22; i++) { str = str + str; }");
1971
1972  // Check for out of memory state.
1973  CHECK(result.IsEmpty());
1974  CHECK(context->HasOutOfMemoryException());
1975}
1976
1977
1978THREADED_TEST(ConstructCall) {
1979  v8::HandleScope scope;
1980  LocalContext context;
1981  CompileRun(
1982    "function Foo() {"
1983    "  var result = [];"
1984    "  for (var i = 0; i < arguments.length; i++) {"
1985    "    result.push(arguments[i]);"
1986    "  }"
1987    "  return result;"
1988    "}");
1989  Local<Function> Foo =
1990      Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
1991
1992  v8::Handle<Value>* args0 = NULL;
1993  Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
1994  CHECK_EQ(0, a0->Length());
1995
1996  v8::Handle<Value> args1[] = { v8_num(1.1) };
1997  Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
1998  CHECK_EQ(1, a1->Length());
1999  CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
2000
2001  v8::Handle<Value> args2[] = { v8_num(2.2),
2002                                v8_num(3.3) };
2003  Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
2004  CHECK_EQ(2, a2->Length());
2005  CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
2006  CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
2007
2008  v8::Handle<Value> args3[] = { v8_num(4.4),
2009                                v8_num(5.5),
2010                                v8_num(6.6) };
2011  Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
2012  CHECK_EQ(3, a3->Length());
2013  CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
2014  CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
2015  CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
2016
2017  v8::Handle<Value> args4[] = { v8_num(7.7),
2018                                v8_num(8.8),
2019                                v8_num(9.9),
2020                                v8_num(10.11) };
2021  Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
2022  CHECK_EQ(4, a4->Length());
2023  CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
2024  CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
2025  CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
2026  CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
2027}
2028
2029
2030static void CheckUncle(v8::TryCatch* try_catch) {
2031  CHECK(try_catch->HasCaught());
2032  String::AsciiValue str_value(try_catch->Exception());
2033  CHECK_EQ(*str_value, "uncle?");
2034  try_catch->Reset();
2035}
2036
2037
2038THREADED_TEST(ConversionNumber) {
2039  v8::HandleScope scope;
2040  LocalContext env;
2041  // Very large number.
2042  CompileRun("var obj = Math.pow(2,32) * 1237;");
2043  Local<Value> obj = env->Global()->Get(v8_str("obj"));
2044  CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
2045  CHECK_EQ(0, obj->ToInt32()->Value());
2046  CHECK(0u == obj->ToUint32()->Value());  // NOLINT - no CHECK_EQ for unsigned.
2047  // Large number.
2048  CompileRun("var obj = -1234567890123;");
2049  obj = env->Global()->Get(v8_str("obj"));
2050  CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
2051  CHECK_EQ(-1912276171, obj->ToInt32()->Value());
2052  CHECK(2382691125u == obj->ToUint32()->Value());  // NOLINT
2053  // Small positive integer.
2054  CompileRun("var obj = 42;");
2055  obj = env->Global()->Get(v8_str("obj"));
2056  CHECK_EQ(42.0, obj->ToNumber()->Value());
2057  CHECK_EQ(42, obj->ToInt32()->Value());
2058  CHECK(42u == obj->ToUint32()->Value());  // NOLINT
2059  // Negative integer.
2060  CompileRun("var obj = -37;");
2061  obj = env->Global()->Get(v8_str("obj"));
2062  CHECK_EQ(-37.0, obj->ToNumber()->Value());
2063  CHECK_EQ(-37, obj->ToInt32()->Value());
2064  CHECK(4294967259u == obj->ToUint32()->Value());  // NOLINT
2065  // Positive non-int32 integer.
2066  CompileRun("var obj = 0x81234567;");
2067  obj = env->Global()->Get(v8_str("obj"));
2068  CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
2069  CHECK_EQ(-2128394905, obj->ToInt32()->Value());
2070  CHECK(2166572391u == obj->ToUint32()->Value());  // NOLINT
2071  // Fraction.
2072  CompileRun("var obj = 42.3;");
2073  obj = env->Global()->Get(v8_str("obj"));
2074  CHECK_EQ(42.3, obj->ToNumber()->Value());
2075  CHECK_EQ(42, obj->ToInt32()->Value());
2076  CHECK(42u == obj->ToUint32()->Value());  // NOLINT
2077  // Large negative fraction.
2078  CompileRun("var obj = -5726623061.75;");
2079  obj = env->Global()->Get(v8_str("obj"));
2080  CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
2081  CHECK_EQ(-1431655765, obj->ToInt32()->Value());
2082  CHECK(2863311531u == obj->ToUint32()->Value());  // NOLINT
2083}
2084
2085
2086THREADED_TEST(isNumberType) {
2087  v8::HandleScope scope;
2088  LocalContext env;
2089  // Very large number.
2090  CompileRun("var obj = Math.pow(2,32) * 1237;");
2091  Local<Value> obj = env->Global()->Get(v8_str("obj"));
2092  CHECK(!obj->IsInt32());
2093  CHECK(!obj->IsUint32());
2094  // Large negative number.
2095  CompileRun("var obj = -1234567890123;");
2096  obj = env->Global()->Get(v8_str("obj"));
2097  CHECK(!obj->IsInt32());
2098  CHECK(!obj->IsUint32());
2099  // Small positive integer.
2100  CompileRun("var obj = 42;");
2101  obj = env->Global()->Get(v8_str("obj"));
2102  CHECK(obj->IsInt32());
2103  CHECK(obj->IsUint32());
2104  // Negative integer.
2105  CompileRun("var obj = -37;");
2106  obj = env->Global()->Get(v8_str("obj"));
2107  CHECK(obj->IsInt32());
2108  CHECK(!obj->IsUint32());
2109  // Positive non-int32 integer.
2110  CompileRun("var obj = 0x81234567;");
2111  obj = env->Global()->Get(v8_str("obj"));
2112  CHECK(!obj->IsInt32());
2113  CHECK(obj->IsUint32());
2114  // Fraction.
2115  CompileRun("var obj = 42.3;");
2116  obj = env->Global()->Get(v8_str("obj"));
2117  CHECK(!obj->IsInt32());
2118  CHECK(!obj->IsUint32());
2119  // Large negative fraction.
2120  CompileRun("var obj = -5726623061.75;");
2121  obj = env->Global()->Get(v8_str("obj"));
2122  CHECK(!obj->IsInt32());
2123  CHECK(!obj->IsUint32());
2124}
2125
2126
2127THREADED_TEST(ConversionException) {
2128  v8::HandleScope scope;
2129  LocalContext env;
2130  CompileRun(
2131    "function TestClass() { };"
2132    "TestClass.prototype.toString = function () { throw 'uncle?'; };"
2133    "var obj = new TestClass();");
2134  Local<Value> obj = env->Global()->Get(v8_str("obj"));
2135
2136  v8::TryCatch try_catch;
2137
2138  Local<Value> to_string_result = obj->ToString();
2139  CHECK(to_string_result.IsEmpty());
2140  CheckUncle(&try_catch);
2141
2142  Local<Value> to_number_result = obj->ToNumber();
2143  CHECK(to_number_result.IsEmpty());
2144  CheckUncle(&try_catch);
2145
2146  Local<Value> to_integer_result = obj->ToInteger();
2147  CHECK(to_integer_result.IsEmpty());
2148  CheckUncle(&try_catch);
2149
2150  Local<Value> to_uint32_result = obj->ToUint32();
2151  CHECK(to_uint32_result.IsEmpty());
2152  CheckUncle(&try_catch);
2153
2154  Local<Value> to_int32_result = obj->ToInt32();
2155  CHECK(to_int32_result.IsEmpty());
2156  CheckUncle(&try_catch);
2157
2158  Local<Value> to_object_result = v8::Undefined()->ToObject();
2159  CHECK(to_object_result.IsEmpty());
2160  CHECK(try_catch.HasCaught());
2161  try_catch.Reset();
2162
2163  int32_t int32_value = obj->Int32Value();
2164  CHECK_EQ(0, int32_value);
2165  CheckUncle(&try_catch);
2166
2167  uint32_t uint32_value = obj->Uint32Value();
2168  CHECK_EQ(0, uint32_value);
2169  CheckUncle(&try_catch);
2170
2171  double number_value = obj->NumberValue();
2172  CHECK_NE(0, IsNaN(number_value));
2173  CheckUncle(&try_catch);
2174
2175  int64_t integer_value = obj->IntegerValue();
2176  CHECK_EQ(0.0, static_cast<double>(integer_value));
2177  CheckUncle(&try_catch);
2178}
2179
2180
2181v8::Handle<Value> ThrowFromC(const v8::Arguments& args) {
2182  ApiTestFuzzer::Fuzz();
2183  return v8::ThrowException(v8_str("konto"));
2184}
2185
2186
2187v8::Handle<Value> CCatcher(const v8::Arguments& args) {
2188  if (args.Length() < 1) return v8::Boolean::New(false);
2189  v8::HandleScope scope;
2190  v8::TryCatch try_catch;
2191  Local<Value> result = v8::Script::Compile(args[0]->ToString())->Run();
2192  CHECK(!try_catch.HasCaught() || result.IsEmpty());
2193  return v8::Boolean::New(try_catch.HasCaught());
2194}
2195
2196
2197THREADED_TEST(APICatch) {
2198  v8::HandleScope scope;
2199  Local<ObjectTemplate> templ = ObjectTemplate::New();
2200  templ->Set(v8_str("ThrowFromC"),
2201             v8::FunctionTemplate::New(ThrowFromC));
2202  LocalContext context(0, templ);
2203  CompileRun(
2204    "var thrown = false;"
2205    "try {"
2206    "  ThrowFromC();"
2207    "} catch (e) {"
2208    "  thrown = true;"
2209    "}");
2210  Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
2211  CHECK(thrown->BooleanValue());
2212}
2213
2214
2215THREADED_TEST(APIThrowTryCatch) {
2216  v8::HandleScope scope;
2217  Local<ObjectTemplate> templ = ObjectTemplate::New();
2218  templ->Set(v8_str("ThrowFromC"),
2219             v8::FunctionTemplate::New(ThrowFromC));
2220  LocalContext context(0, templ);
2221  v8::TryCatch try_catch;
2222  CompileRun("ThrowFromC();");
2223  CHECK(try_catch.HasCaught());
2224}
2225
2226
2227// Test that a try-finally block doesn't shadow a try-catch block
2228// when setting up an external handler.
2229//
2230// BUG(271): Some of the exception propagation does not work on the
2231// ARM simulator because the simulator separates the C++ stack and the
2232// JS stack.  This test therefore fails on the simulator.  The test is
2233// not threaded to allow the threading tests to run on the simulator.
2234TEST(TryCatchInTryFinally) {
2235  v8::HandleScope scope;
2236  Local<ObjectTemplate> templ = ObjectTemplate::New();
2237  templ->Set(v8_str("CCatcher"),
2238             v8::FunctionTemplate::New(CCatcher));
2239  LocalContext context(0, templ);
2240  Local<Value> result = CompileRun("try {"
2241                                   "  try {"
2242                                   "    CCatcher('throw 7;');"
2243                                   "  } finally {"
2244                                   "  }"
2245                                   "} catch (e) {"
2246                                   "}");
2247  CHECK(result->IsTrue());
2248}
2249
2250
2251static void receive_message(v8::Handle<v8::Message> message,
2252                            v8::Handle<v8::Value> data) {
2253  message->Get();
2254  message_received = true;
2255}
2256
2257
2258TEST(APIThrowMessage) {
2259  message_received = false;
2260  v8::HandleScope scope;
2261  v8::V8::AddMessageListener(receive_message);
2262  Local<ObjectTemplate> templ = ObjectTemplate::New();
2263  templ->Set(v8_str("ThrowFromC"),
2264             v8::FunctionTemplate::New(ThrowFromC));
2265  LocalContext context(0, templ);
2266  CompileRun("ThrowFromC();");
2267  CHECK(message_received);
2268  v8::V8::RemoveMessageListeners(check_message);
2269}
2270
2271
2272TEST(APIThrowMessageAndVerboseTryCatch) {
2273  message_received = false;
2274  v8::HandleScope scope;
2275  v8::V8::AddMessageListener(receive_message);
2276  Local<ObjectTemplate> templ = ObjectTemplate::New();
2277  templ->Set(v8_str("ThrowFromC"),
2278             v8::FunctionTemplate::New(ThrowFromC));
2279  LocalContext context(0, templ);
2280  v8::TryCatch try_catch;
2281  try_catch.SetVerbose(true);
2282  Local<Value> result = CompileRun("ThrowFromC();");
2283  CHECK(try_catch.HasCaught());
2284  CHECK(result.IsEmpty());
2285  CHECK(message_received);
2286  v8::V8::RemoveMessageListeners(check_message);
2287}
2288
2289
2290THREADED_TEST(ExternalScriptException) {
2291  v8::HandleScope scope;
2292  Local<ObjectTemplate> templ = ObjectTemplate::New();
2293  templ->Set(v8_str("ThrowFromC"),
2294             v8::FunctionTemplate::New(ThrowFromC));
2295  LocalContext context(0, templ);
2296
2297  v8::TryCatch try_catch;
2298  Local<Script> script
2299      = Script::Compile(v8_str("ThrowFromC(); throw 'panama';"));
2300  Local<Value> result = script->Run();
2301  CHECK(result.IsEmpty());
2302  CHECK(try_catch.HasCaught());
2303  String::AsciiValue exception_value(try_catch.Exception());
2304  CHECK_EQ("konto", *exception_value);
2305}
2306
2307
2308
2309v8::Handle<Value> CThrowCountDown(const v8::Arguments& args) {
2310  ApiTestFuzzer::Fuzz();
2311  CHECK_EQ(4, args.Length());
2312  int count = args[0]->Int32Value();
2313  int cInterval = args[2]->Int32Value();
2314  if (count == 0) {
2315    return v8::ThrowException(v8_str("FromC"));
2316  } else {
2317    Local<v8::Object> global = Context::GetCurrent()->Global();
2318    Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
2319    v8::Handle<Value> argv[] = { v8_num(count - 1),
2320                                 args[1],
2321                                 args[2],
2322                                 args[3] };
2323    if (count % cInterval == 0) {
2324      v8::TryCatch try_catch;
2325      Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
2326      int expected = args[3]->Int32Value();
2327      if (try_catch.HasCaught()) {
2328        CHECK_EQ(expected, count);
2329        CHECK(result.IsEmpty());
2330        CHECK(!i::Top::has_scheduled_exception());
2331      } else {
2332        CHECK_NE(expected, count);
2333      }
2334      return result;
2335    } else {
2336      return fun.As<Function>()->Call(global, 4, argv);
2337    }
2338  }
2339}
2340
2341
2342v8::Handle<Value> JSCheck(const v8::Arguments& args) {
2343  ApiTestFuzzer::Fuzz();
2344  CHECK_EQ(3, args.Length());
2345  bool equality = args[0]->BooleanValue();
2346  int count = args[1]->Int32Value();
2347  int expected = args[2]->Int32Value();
2348  if (equality) {
2349    CHECK_EQ(count, expected);
2350  } else {
2351    CHECK_NE(count, expected);
2352  }
2353  return v8::Undefined();
2354}
2355
2356
2357THREADED_TEST(EvalInTryFinally) {
2358  v8::HandleScope scope;
2359  LocalContext context;
2360  v8::TryCatch try_catch;
2361  CompileRun("(function() {"
2362             "  try {"
2363             "    eval('asldkf (*&^&*^');"
2364             "  } finally {"
2365             "    return;"
2366             "  }"
2367             "})()");
2368  CHECK(!try_catch.HasCaught());
2369}
2370
2371
2372// This test works by making a stack of alternating JavaScript and C
2373// activations.  These activations set up exception handlers with regular
2374// intervals, one interval for C activations and another for JavaScript
2375// activations.  When enough activations have been created an exception is
2376// thrown and we check that the right activation catches the exception and that
2377// no other activations do.  The right activation is always the topmost one with
2378// a handler, regardless of whether it is in JavaScript or C.
2379//
2380// The notation used to describe a test case looks like this:
2381//
2382//    *JS[4] *C[3] @JS[2] C[1] JS[0]
2383//
2384// Each entry is an activation, either JS or C.  The index is the count at that
2385// level.  Stars identify activations with exception handlers, the @ identifies
2386// the exception handler that should catch the exception.
2387//
2388// BUG(271): Some of the exception propagation does not work on the
2389// ARM simulator because the simulator separates the C++ stack and the
2390// JS stack.  This test therefore fails on the simulator.  The test is
2391// not threaded to allow the threading tests to run on the simulator.
2392TEST(ExceptionOrder) {
2393  v8::HandleScope scope;
2394  Local<ObjectTemplate> templ = ObjectTemplate::New();
2395  templ->Set(v8_str("check"), v8::FunctionTemplate::New(JSCheck));
2396  templ->Set(v8_str("CThrowCountDown"),
2397             v8::FunctionTemplate::New(CThrowCountDown));
2398  LocalContext context(0, templ);
2399  CompileRun(
2400    "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
2401    "  if (count == 0) throw 'FromJS';"
2402    "  if (count % jsInterval == 0) {"
2403    "    try {"
2404    "      var value = CThrowCountDown(count - 1,"
2405    "                                  jsInterval,"
2406    "                                  cInterval,"
2407    "                                  expected);"
2408    "      check(false, count, expected);"
2409    "      return value;"
2410    "    } catch (e) {"
2411    "      check(true, count, expected);"
2412    "    }"
2413    "  } else {"
2414    "    return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
2415    "  }"
2416    "}");
2417  Local<Function> fun =
2418      Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
2419
2420  const int argc = 4;
2421  //                             count      jsInterval cInterval  expected
2422
2423  // *JS[4] *C[3] @JS[2] C[1] JS[0]
2424  v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
2425  fun->Call(fun, argc, a0);
2426
2427  // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
2428  v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
2429  fun->Call(fun, argc, a1);
2430
2431  // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
2432  v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
2433  fun->Call(fun, argc, a2);
2434
2435  // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
2436  v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
2437  fun->Call(fun, argc, a3);
2438
2439  // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
2440  v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
2441  fun->Call(fun, argc, a4);
2442
2443  // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
2444  v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
2445  fun->Call(fun, argc, a5);
2446}
2447
2448
2449v8::Handle<Value> ThrowValue(const v8::Arguments& args) {
2450  ApiTestFuzzer::Fuzz();
2451  CHECK_EQ(1, args.Length());
2452  return v8::ThrowException(args[0]);
2453}
2454
2455
2456THREADED_TEST(ThrowValues) {
2457  v8::HandleScope scope;
2458  Local<ObjectTemplate> templ = ObjectTemplate::New();
2459  templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(ThrowValue));
2460  LocalContext context(0, templ);
2461  v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
2462    "function Run(obj) {"
2463    "  try {"
2464    "    Throw(obj);"
2465    "  } catch (e) {"
2466    "    return e;"
2467    "  }"
2468    "  return 'no exception';"
2469    "}"
2470    "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
2471  CHECK_EQ(5, result->Length());
2472  CHECK(result->Get(v8::Integer::New(0))->IsString());
2473  CHECK(result->Get(v8::Integer::New(1))->IsNumber());
2474  CHECK_EQ(1, result->Get(v8::Integer::New(1))->Int32Value());
2475  CHECK(result->Get(v8::Integer::New(2))->IsNumber());
2476  CHECK_EQ(0, result->Get(v8::Integer::New(2))->Int32Value());
2477  CHECK(result->Get(v8::Integer::New(3))->IsNull());
2478  CHECK(result->Get(v8::Integer::New(4))->IsUndefined());
2479}
2480
2481
2482THREADED_TEST(CatchZero) {
2483  v8::HandleScope scope;
2484  LocalContext context;
2485  v8::TryCatch try_catch;
2486  CHECK(!try_catch.HasCaught());
2487  Script::Compile(v8_str("throw 10"))->Run();
2488  CHECK(try_catch.HasCaught());
2489  CHECK_EQ(10, try_catch.Exception()->Int32Value());
2490  try_catch.Reset();
2491  CHECK(!try_catch.HasCaught());
2492  Script::Compile(v8_str("throw 0"))->Run();
2493  CHECK(try_catch.HasCaught());
2494  CHECK_EQ(0, try_catch.Exception()->Int32Value());
2495}
2496
2497
2498THREADED_TEST(CatchExceptionFromWith) {
2499  v8::HandleScope scope;
2500  LocalContext context;
2501  v8::TryCatch try_catch;
2502  CHECK(!try_catch.HasCaught());
2503  Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run();
2504  CHECK(try_catch.HasCaught());
2505}
2506
2507
2508THREADED_TEST(Equality) {
2509  v8::HandleScope scope;
2510  LocalContext context;
2511  // Check that equality works at all before relying on CHECK_EQ
2512  CHECK(v8_str("a")->Equals(v8_str("a")));
2513  CHECK(!v8_str("a")->Equals(v8_str("b")));
2514
2515  CHECK_EQ(v8_str("a"), v8_str("a"));
2516  CHECK_NE(v8_str("a"), v8_str("b"));
2517  CHECK_EQ(v8_num(1), v8_num(1));
2518  CHECK_EQ(v8_num(1.00), v8_num(1));
2519  CHECK_NE(v8_num(1), v8_num(2));
2520
2521  // Assume String is not symbol.
2522  CHECK(v8_str("a")->StrictEquals(v8_str("a")));
2523  CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
2524  CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
2525  CHECK(v8_num(1)->StrictEquals(v8_num(1)));
2526  CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
2527  CHECK(v8_num(0)->StrictEquals(v8_num(-0)));
2528  Local<Value> not_a_number = v8_num(i::OS::nan_value());
2529  CHECK(!not_a_number->StrictEquals(not_a_number));
2530  CHECK(v8::False()->StrictEquals(v8::False()));
2531  CHECK(!v8::False()->StrictEquals(v8::Undefined()));
2532
2533  v8::Handle<v8::Object> obj = v8::Object::New();
2534  v8::Persistent<v8::Object> alias = v8::Persistent<v8::Object>::New(obj);
2535  CHECK(alias->StrictEquals(obj));
2536  alias.Dispose();
2537}
2538
2539
2540THREADED_TEST(MultiRun) {
2541  v8::HandleScope scope;
2542  LocalContext context;
2543  Local<Script> script = Script::Compile(v8_str("x"));
2544  for (int i = 0; i < 10; i++)
2545    script->Run();
2546}
2547
2548
2549static v8::Handle<Value> GetXValue(Local<String> name,
2550                                   const AccessorInfo& info) {
2551  ApiTestFuzzer::Fuzz();
2552  CHECK_EQ(info.Data(), v8_str("donut"));
2553  CHECK_EQ(name, v8_str("x"));
2554  return name;
2555}
2556
2557
2558THREADED_TEST(SimplePropertyRead) {
2559  v8::HandleScope scope;
2560  Local<ObjectTemplate> templ = ObjectTemplate::New();
2561  templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
2562  LocalContext context;
2563  context->Global()->Set(v8_str("obj"), templ->NewInstance());
2564  Local<Script> script = Script::Compile(v8_str("obj.x"));
2565  for (int i = 0; i < 10; i++) {
2566    Local<Value> result = script->Run();
2567    CHECK_EQ(result, v8_str("x"));
2568  }
2569}
2570
2571THREADED_TEST(DefinePropertyOnAPIAccessor) {
2572  v8::HandleScope scope;
2573  Local<ObjectTemplate> templ = ObjectTemplate::New();
2574  templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
2575  LocalContext context;
2576  context->Global()->Set(v8_str("obj"), templ->NewInstance());
2577
2578  // Uses getOwnPropertyDescriptor to check the configurable status
2579  Local<Script> script_desc
2580    = Script::Compile(v8_str("var prop = Object.getOwnPropertyDescriptor( "
2581                             "obj, 'x');"
2582                             "prop.configurable;"));
2583  Local<Value> result = script_desc->Run();
2584  CHECK_EQ(result->BooleanValue(), true);
2585
2586  // Redefine get - but still configurable
2587  Local<Script> script_define
2588    = Script::Compile(v8_str("var desc = { get: function(){return 42; },"
2589                             "            configurable: true };"
2590                             "Object.defineProperty(obj, 'x', desc);"
2591                             "obj.x"));
2592  result = script_define->Run();
2593  CHECK_EQ(result, v8_num(42));
2594
2595  // Check that the accessor is still configurable
2596  result = script_desc->Run();
2597  CHECK_EQ(result->BooleanValue(), true);
2598
2599  // Redefine to a non-configurable
2600  script_define
2601    = Script::Compile(v8_str("var desc = { get: function(){return 43; },"
2602                             "             configurable: false };"
2603                             "Object.defineProperty(obj, 'x', desc);"
2604                             "obj.x"));
2605  result = script_define->Run();
2606  CHECK_EQ(result, v8_num(43));
2607  result = script_desc->Run();
2608  CHECK_EQ(result->BooleanValue(), false);
2609
2610  // Make sure that it is not possible to redefine again
2611  v8::TryCatch try_catch;
2612  result = script_define->Run();
2613  CHECK(try_catch.HasCaught());
2614  String::AsciiValue exception_value(try_catch.Exception());
2615  CHECK_EQ(*exception_value,
2616           "TypeError: Cannot redefine property: defineProperty");
2617}
2618
2619THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
2620  v8::HandleScope scope;
2621  Local<ObjectTemplate> templ = ObjectTemplate::New();
2622  templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
2623  LocalContext context;
2624  context->Global()->Set(v8_str("obj"), templ->NewInstance());
2625
2626  Local<Script> script_desc = Script::Compile(v8_str("var prop ="
2627                                    "Object.getOwnPropertyDescriptor( "
2628                                    "obj, 'x');"
2629                                    "prop.configurable;"));
2630  Local<Value> result = script_desc->Run();
2631  CHECK_EQ(result->BooleanValue(), true);
2632
2633  Local<Script> script_define =
2634    Script::Compile(v8_str("var desc = {get: function(){return 42; },"
2635                           "            configurable: true };"
2636                           "Object.defineProperty(obj, 'x', desc);"
2637                           "obj.x"));
2638  result = script_define->Run();
2639  CHECK_EQ(result, v8_num(42));
2640
2641
2642  result = script_desc->Run();
2643  CHECK_EQ(result->BooleanValue(), true);
2644
2645
2646  script_define =
2647    Script::Compile(v8_str("var desc = {get: function(){return 43; },"
2648                           "            configurable: false };"
2649                           "Object.defineProperty(obj, 'x', desc);"
2650                           "obj.x"));
2651  result = script_define->Run();
2652  CHECK_EQ(result, v8_num(43));
2653  result = script_desc->Run();
2654
2655  CHECK_EQ(result->BooleanValue(), false);
2656
2657  v8::TryCatch try_catch;
2658  result = script_define->Run();
2659  CHECK(try_catch.HasCaught());
2660  String::AsciiValue exception_value(try_catch.Exception());
2661  CHECK_EQ(*exception_value,
2662           "TypeError: Cannot redefine property: defineProperty");
2663}
2664
2665
2666static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
2667                                                char const* name) {
2668  return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
2669}
2670
2671
2672THREADED_TEST(DefineAPIAccessorOnObject) {
2673  v8::HandleScope scope;
2674  Local<ObjectTemplate> templ = ObjectTemplate::New();
2675  LocalContext context;
2676
2677  context->Global()->Set(v8_str("obj1"), templ->NewInstance());
2678  CompileRun("var obj2 = {};");
2679
2680  CHECK(CompileRun("obj1.x")->IsUndefined());
2681  CHECK(CompileRun("obj2.x")->IsUndefined());
2682
2683  CHECK(GetGlobalProperty(&context, "obj1")->
2684      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2685
2686  ExpectString("obj1.x", "x");
2687  CHECK(CompileRun("obj2.x")->IsUndefined());
2688
2689  CHECK(GetGlobalProperty(&context, "obj2")->
2690      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2691
2692  ExpectString("obj1.x", "x");
2693  ExpectString("obj2.x", "x");
2694
2695  ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
2696  ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
2697
2698  CompileRun("Object.defineProperty(obj1, 'x',"
2699             "{ get: function() { return 'y'; }, configurable: true })");
2700
2701  ExpectString("obj1.x", "y");
2702  ExpectString("obj2.x", "x");
2703
2704  CompileRun("Object.defineProperty(obj2, 'x',"
2705             "{ get: function() { return 'y'; }, configurable: true })");
2706
2707  ExpectString("obj1.x", "y");
2708  ExpectString("obj2.x", "y");
2709
2710  ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
2711  ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
2712
2713  CHECK(GetGlobalProperty(&context, "obj1")->
2714      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2715  CHECK(GetGlobalProperty(&context, "obj2")->
2716      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2717
2718  ExpectString("obj1.x", "x");
2719  ExpectString("obj2.x", "x");
2720
2721  ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
2722  ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
2723
2724  // Define getters/setters, but now make them not configurable.
2725  CompileRun("Object.defineProperty(obj1, 'x',"
2726             "{ get: function() { return 'z'; }, configurable: false })");
2727  CompileRun("Object.defineProperty(obj2, 'x',"
2728             "{ get: function() { return 'z'; }, configurable: false })");
2729
2730  ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
2731  ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
2732
2733  ExpectString("obj1.x", "z");
2734  ExpectString("obj2.x", "z");
2735
2736  CHECK(!GetGlobalProperty(&context, "obj1")->
2737      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2738  CHECK(!GetGlobalProperty(&context, "obj2")->
2739      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2740
2741  ExpectString("obj1.x", "z");
2742  ExpectString("obj2.x", "z");
2743}
2744
2745
2746THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
2747  v8::HandleScope scope;
2748  Local<ObjectTemplate> templ = ObjectTemplate::New();
2749  LocalContext context;
2750
2751  context->Global()->Set(v8_str("obj1"), templ->NewInstance());
2752  CompileRun("var obj2 = {};");
2753
2754  CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
2755        v8_str("x"),
2756        GetXValue, NULL,
2757        v8_str("donut"), v8::DEFAULT, v8::DontDelete));
2758  CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
2759        v8_str("x"),
2760        GetXValue, NULL,
2761        v8_str("donut"), v8::DEFAULT, v8::DontDelete));
2762
2763  ExpectString("obj1.x", "x");
2764  ExpectString("obj2.x", "x");
2765
2766  ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
2767  ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
2768
2769  CHECK(!GetGlobalProperty(&context, "obj1")->
2770      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2771  CHECK(!GetGlobalProperty(&context, "obj2")->
2772      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2773
2774  {
2775    v8::TryCatch try_catch;
2776    CompileRun("Object.defineProperty(obj1, 'x',"
2777        "{get: function() { return 'func'; }})");
2778    CHECK(try_catch.HasCaught());
2779    String::AsciiValue exception_value(try_catch.Exception());
2780    CHECK_EQ(*exception_value,
2781            "TypeError: Cannot redefine property: defineProperty");
2782  }
2783  {
2784    v8::TryCatch try_catch;
2785    CompileRun("Object.defineProperty(obj2, 'x',"
2786        "{get: function() { return 'func'; }})");
2787    CHECK(try_catch.HasCaught());
2788    String::AsciiValue exception_value(try_catch.Exception());
2789    CHECK_EQ(*exception_value,
2790            "TypeError: Cannot redefine property: defineProperty");
2791  }
2792}
2793
2794
2795static v8::Handle<Value> Get239Value(Local<String> name,
2796                                     const AccessorInfo& info) {
2797  ApiTestFuzzer::Fuzz();
2798  CHECK_EQ(info.Data(), v8_str("donut"));
2799  CHECK_EQ(name, v8_str("239"));
2800  return name;
2801}
2802
2803
2804THREADED_TEST(ElementAPIAccessor) {
2805  v8::HandleScope scope;
2806  Local<ObjectTemplate> templ = ObjectTemplate::New();
2807  LocalContext context;
2808
2809  context->Global()->Set(v8_str("obj1"), templ->NewInstance());
2810  CompileRun("var obj2 = {};");
2811
2812  CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
2813        v8_str("239"),
2814        Get239Value, NULL,
2815        v8_str("donut")));
2816  CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
2817        v8_str("239"),
2818        Get239Value, NULL,
2819        v8_str("donut")));
2820
2821  ExpectString("obj1[239]", "239");
2822  ExpectString("obj2[239]", "239");
2823  ExpectString("obj1['239']", "239");
2824  ExpectString("obj2['239']", "239");
2825}
2826
2827
2828v8::Persistent<Value> xValue;
2829
2830
2831static void SetXValue(Local<String> name,
2832                      Local<Value> value,
2833                      const AccessorInfo& info) {
2834  CHECK_EQ(value, v8_num(4));
2835  CHECK_EQ(info.Data(), v8_str("donut"));
2836  CHECK_EQ(name, v8_str("x"));
2837  CHECK(xValue.IsEmpty());
2838  xValue = v8::Persistent<Value>::New(value);
2839}
2840
2841
2842THREADED_TEST(SimplePropertyWrite) {
2843  v8::HandleScope scope;
2844  Local<ObjectTemplate> templ = ObjectTemplate::New();
2845  templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
2846  LocalContext context;
2847  context->Global()->Set(v8_str("obj"), templ->NewInstance());
2848  Local<Script> script = Script::Compile(v8_str("obj.x = 4"));
2849  for (int i = 0; i < 10; i++) {
2850    CHECK(xValue.IsEmpty());
2851    script->Run();
2852    CHECK_EQ(v8_num(4), xValue);
2853    xValue.Dispose();
2854    xValue = v8::Persistent<Value>();
2855  }
2856}
2857
2858
2859static v8::Handle<Value> XPropertyGetter(Local<String> property,
2860                                         const AccessorInfo& info) {
2861  ApiTestFuzzer::Fuzz();
2862  CHECK(info.Data()->IsUndefined());
2863  return property;
2864}
2865
2866
2867THREADED_TEST(NamedInterceptorPropertyRead) {
2868  v8::HandleScope scope;
2869  Local<ObjectTemplate> templ = ObjectTemplate::New();
2870  templ->SetNamedPropertyHandler(XPropertyGetter);
2871  LocalContext context;
2872  context->Global()->Set(v8_str("obj"), templ->NewInstance());
2873  Local<Script> script = Script::Compile(v8_str("obj.x"));
2874  for (int i = 0; i < 10; i++) {
2875    Local<Value> result = script->Run();
2876    CHECK_EQ(result, v8_str("x"));
2877  }
2878}
2879
2880
2881THREADED_TEST(NamedInterceptorDictionaryIC) {
2882  v8::HandleScope scope;
2883  Local<ObjectTemplate> templ = ObjectTemplate::New();
2884  templ->SetNamedPropertyHandler(XPropertyGetter);
2885  LocalContext context;
2886  // Create an object with a named interceptor.
2887  context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
2888  Local<Script> script = Script::Compile(v8_str("interceptor_obj.x"));
2889  for (int i = 0; i < 10; i++) {
2890    Local<Value> result = script->Run();
2891    CHECK_EQ(result, v8_str("x"));
2892  }
2893  // Create a slow case object and a function accessing a property in
2894  // that slow case object (with dictionary probing in generated
2895  // code). Then force object with a named interceptor into slow-case,
2896  // pass it to the function, and check that the interceptor is called
2897  // instead of accessing the local property.
2898  Local<Value> result =
2899      CompileRun("function get_x(o) { return o.x; };"
2900                 "var obj = { x : 42, y : 0 };"
2901                 "delete obj.y;"
2902                 "for (var i = 0; i < 10; i++) get_x(obj);"
2903                 "interceptor_obj.x = 42;"
2904                 "interceptor_obj.y = 10;"
2905                 "delete interceptor_obj.y;"
2906                 "get_x(interceptor_obj)");
2907  CHECK_EQ(result, v8_str("x"));
2908}
2909
2910
2911static v8::Handle<Value> SetXOnPrototypeGetter(Local<String> property,
2912                                               const AccessorInfo& info) {
2913  // Set x on the prototype object and do not handle the get request.
2914  v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
2915  proto.As<v8::Object>()->Set(v8_str("x"), v8::Integer::New(23));
2916  return v8::Handle<Value>();
2917}
2918
2919
2920// This is a regression test for http://crbug.com/20104. Map
2921// transitions should not interfere with post interceptor lookup.
2922THREADED_TEST(NamedInterceptorMapTransitionRead) {
2923  v8::HandleScope scope;
2924  Local<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New();
2925  Local<v8::ObjectTemplate> instance_template
2926      = function_template->InstanceTemplate();
2927  instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
2928  LocalContext context;
2929  context->Global()->Set(v8_str("F"), function_template->GetFunction());
2930  // Create an instance of F and introduce a map transition for x.
2931  CompileRun("var o = new F(); o.x = 23;");
2932  // Create an instance of F and invoke the getter. The result should be 23.
2933  Local<Value> result = CompileRun("o = new F(); o.x");
2934  CHECK_EQ(result->Int32Value(), 23);
2935}
2936
2937
2938static v8::Handle<Value> IndexedPropertyGetter(uint32_t index,
2939                                               const AccessorInfo& info) {
2940  ApiTestFuzzer::Fuzz();
2941  if (index == 37) {
2942    return v8::Handle<Value>(v8_num(625));
2943  }
2944  return v8::Handle<Value>();
2945}
2946
2947
2948static v8::Handle<Value> IndexedPropertySetter(uint32_t index,
2949                                               Local<Value> value,
2950                                               const AccessorInfo& info) {
2951  ApiTestFuzzer::Fuzz();
2952  if (index == 39) {
2953    return value;
2954  }
2955  return v8::Handle<Value>();
2956}
2957
2958
2959THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
2960  v8::HandleScope scope;
2961  Local<ObjectTemplate> templ = ObjectTemplate::New();
2962  templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
2963                                   IndexedPropertySetter);
2964  LocalContext context;
2965  context->Global()->Set(v8_str("obj"), templ->NewInstance());
2966  Local<Script> getter_script = Script::Compile(v8_str(
2967      "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];"));
2968  Local<Script> setter_script = Script::Compile(v8_str(
2969      "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
2970      "obj[17] = 23;"
2971      "obj.foo;"));
2972  Local<Script> interceptor_setter_script = Script::Compile(v8_str(
2973      "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
2974      "obj[39] = 47;"
2975      "obj.foo;"));  // This setter should not run, due to the interceptor.
2976  Local<Script> interceptor_getter_script = Script::Compile(v8_str(
2977      "obj[37];"));
2978  Local<Value> result = getter_script->Run();
2979  CHECK_EQ(v8_num(5), result);
2980  result = setter_script->Run();
2981  CHECK_EQ(v8_num(23), result);
2982  result = interceptor_setter_script->Run();
2983  CHECK_EQ(v8_num(23), result);
2984  result = interceptor_getter_script->Run();
2985  CHECK_EQ(v8_num(625), result);
2986}
2987
2988
2989static v8::Handle<Value> IdentityIndexedPropertyGetter(
2990    uint32_t index,
2991    const AccessorInfo& info) {
2992  return v8::Integer::New(index);
2993}
2994
2995
2996THREADED_TEST(IndexedInterceptorWithNoSetter) {
2997  v8::HandleScope scope;
2998  Local<ObjectTemplate> templ = ObjectTemplate::New();
2999  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3000
3001  LocalContext context;
3002  context->Global()->Set(v8_str("obj"), templ->NewInstance());
3003
3004  const char* code =
3005      "try {"
3006      "  obj[0] = 239;"
3007      "  for (var i = 0; i < 100; i++) {"
3008      "    var v = obj[0];"
3009      "    if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
3010      "  }"
3011      "  'PASSED'"
3012      "} catch(e) {"
3013      "  e"
3014      "}";
3015  ExpectString(code, "PASSED");
3016}
3017
3018
3019THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
3020  v8::HandleScope scope;
3021  Local<ObjectTemplate> templ = ObjectTemplate::New();
3022  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3023
3024  LocalContext context;
3025  Local<v8::Object> obj = templ->NewInstance();
3026  obj->TurnOnAccessCheck();
3027  context->Global()->Set(v8_str("obj"), obj);
3028
3029  const char* code =
3030      "try {"
3031      "  for (var i = 0; i < 100; i++) {"
3032      "    var v = obj[0];"
3033      "    if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
3034      "  }"
3035      "  'PASSED'"
3036      "} catch(e) {"
3037      "  e"
3038      "}";
3039  ExpectString(code, "PASSED");
3040}
3041
3042
3043THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
3044  i::FLAG_allow_natives_syntax = true;
3045  v8::HandleScope scope;
3046  Local<ObjectTemplate> templ = ObjectTemplate::New();
3047  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3048
3049  LocalContext context;
3050  Local<v8::Object> obj = templ->NewInstance();
3051  context->Global()->Set(v8_str("obj"), obj);
3052
3053  const char* code =
3054      "try {"
3055      "  for (var i = 0; i < 100; i++) {"
3056      "    var expected = i;"
3057      "    if (i == 5) {"
3058      "      %EnableAccessChecks(obj);"
3059      "      expected = undefined;"
3060      "    }"
3061      "    var v = obj[i];"
3062      "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3063      "    if (i == 5) %DisableAccessChecks(obj);"
3064      "  }"
3065      "  'PASSED'"
3066      "} catch(e) {"
3067      "  e"
3068      "}";
3069  ExpectString(code, "PASSED");
3070}
3071
3072
3073THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
3074  v8::HandleScope scope;
3075  Local<ObjectTemplate> templ = ObjectTemplate::New();
3076  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3077
3078  LocalContext context;
3079  Local<v8::Object> obj = templ->NewInstance();
3080  context->Global()->Set(v8_str("obj"), obj);
3081
3082  const char* code =
3083      "try {"
3084      "  for (var i = 0; i < 100; i++) {"
3085      "    var v = obj[i];"
3086      "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
3087      "  }"
3088      "  'PASSED'"
3089      "} catch(e) {"
3090      "  e"
3091      "}";
3092  ExpectString(code, "PASSED");
3093}
3094
3095
3096THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
3097  v8::HandleScope scope;
3098  Local<ObjectTemplate> templ = ObjectTemplate::New();
3099  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3100
3101  LocalContext context;
3102  Local<v8::Object> obj = templ->NewInstance();
3103  context->Global()->Set(v8_str("obj"), obj);
3104
3105  const char* code =
3106      "try {"
3107      "  for (var i = 0; i < 100; i++) {"
3108      "    var expected = i;"
3109      "    if (i == 50) {"
3110      "       i = 'foobar';"
3111      "       expected = undefined;"
3112      "    }"
3113      "    var v = obj[i];"
3114      "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3115      "  }"
3116      "  'PASSED'"
3117      "} catch(e) {"
3118      "  e"
3119      "}";
3120  ExpectString(code, "PASSED");
3121}
3122
3123
3124THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
3125  v8::HandleScope scope;
3126  Local<ObjectTemplate> templ = ObjectTemplate::New();
3127  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3128
3129  LocalContext context;
3130  Local<v8::Object> obj = templ->NewInstance();
3131  context->Global()->Set(v8_str("obj"), obj);
3132
3133  const char* code =
3134      "var original = obj;"
3135      "try {"
3136      "  for (var i = 0; i < 100; i++) {"
3137      "    var expected = i;"
3138      "    if (i == 50) {"
3139      "       obj = {50: 'foobar'};"
3140      "       expected = 'foobar';"
3141      "    }"
3142      "    var v = obj[i];"
3143      "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3144      "    if (i == 50) obj = original;"
3145      "  }"
3146      "  'PASSED'"
3147      "} catch(e) {"
3148      "  e"
3149      "}";
3150  ExpectString(code, "PASSED");
3151}
3152
3153
3154THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
3155  v8::HandleScope scope;
3156  Local<ObjectTemplate> templ = ObjectTemplate::New();
3157  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3158
3159  LocalContext context;
3160  Local<v8::Object> obj = templ->NewInstance();
3161  context->Global()->Set(v8_str("obj"), obj);
3162
3163  const char* code =
3164      "var original = obj;"
3165      "try {"
3166      "  for (var i = 0; i < 100; i++) {"
3167      "    var expected = i;"
3168      "    if (i == 5) {"
3169      "       obj = 239;"
3170      "       expected = undefined;"
3171      "    }"
3172      "    var v = obj[i];"
3173      "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3174      "    if (i == 5) obj = original;"
3175      "  }"
3176      "  'PASSED'"
3177      "} catch(e) {"
3178      "  e"
3179      "}";
3180  ExpectString(code, "PASSED");
3181}
3182
3183
3184THREADED_TEST(IndexedInterceptorOnProto) {
3185  v8::HandleScope scope;
3186  Local<ObjectTemplate> templ = ObjectTemplate::New();
3187  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3188
3189  LocalContext context;
3190  Local<v8::Object> obj = templ->NewInstance();
3191  context->Global()->Set(v8_str("obj"), obj);
3192
3193  const char* code =
3194      "var o = {__proto__: obj};"
3195      "try {"
3196      "  for (var i = 0; i < 100; i++) {"
3197      "    var v = o[i];"
3198      "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
3199      "  }"
3200      "  'PASSED'"
3201      "} catch(e) {"
3202      "  e"
3203      "}";
3204  ExpectString(code, "PASSED");
3205}
3206
3207
3208THREADED_TEST(MultiContexts) {
3209  v8::HandleScope scope;
3210  v8::Handle<ObjectTemplate> templ = ObjectTemplate::New();
3211  templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(DummyCallHandler));
3212
3213  Local<String> password = v8_str("Password");
3214
3215  // Create an environment
3216  LocalContext context0(0, templ);
3217  context0->SetSecurityToken(password);
3218  v8::Handle<v8::Object> global0 = context0->Global();
3219  global0->Set(v8_str("custom"), v8_num(1234));
3220  CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
3221
3222  // Create an independent environment
3223  LocalContext context1(0, templ);
3224  context1->SetSecurityToken(password);
3225  v8::Handle<v8::Object> global1 = context1->Global();
3226  global1->Set(v8_str("custom"), v8_num(1234));
3227  CHECK_NE(global0, global1);
3228  CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
3229  CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
3230
3231  // Now create a new context with the old global
3232  LocalContext context2(0, templ, global1);
3233  context2->SetSecurityToken(password);
3234  v8::Handle<v8::Object> global2 = context2->Global();
3235  CHECK_EQ(global1, global2);
3236  CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
3237  CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
3238}
3239
3240
3241THREADED_TEST(FunctionPrototypeAcrossContexts) {
3242  // Make sure that functions created by cloning boilerplates cannot
3243  // communicate through their __proto__ field.
3244
3245  v8::HandleScope scope;
3246
3247  LocalContext env0;
3248  v8::Handle<v8::Object> global0 =
3249      env0->Global();
3250  v8::Handle<v8::Object> object0 =
3251      global0->Get(v8_str("Object")).As<v8::Object>();
3252  v8::Handle<v8::Object> tostring0 =
3253      object0->Get(v8_str("toString")).As<v8::Object>();
3254  v8::Handle<v8::Object> proto0 =
3255      tostring0->Get(v8_str("__proto__")).As<v8::Object>();
3256  proto0->Set(v8_str("custom"), v8_num(1234));
3257
3258  LocalContext env1;
3259  v8::Handle<v8::Object> global1 =
3260      env1->Global();
3261  v8::Handle<v8::Object> object1 =
3262      global1->Get(v8_str("Object")).As<v8::Object>();
3263  v8::Handle<v8::Object> tostring1 =
3264      object1->Get(v8_str("toString")).As<v8::Object>();
3265  v8::Handle<v8::Object> proto1 =
3266      tostring1->Get(v8_str("__proto__")).As<v8::Object>();
3267  CHECK(!proto1->Has(v8_str("custom")));
3268}
3269
3270
3271THREADED_TEST(Regress892105) {
3272  // Make sure that object and array literals created by cloning
3273  // boilerplates cannot communicate through their __proto__
3274  // field. This is rather difficult to check, but we try to add stuff
3275  // to Object.prototype and Array.prototype and create a new
3276  // environment. This should succeed.
3277
3278  v8::HandleScope scope;
3279
3280  Local<String> source = v8_str("Object.prototype.obj = 1234;"
3281                                "Array.prototype.arr = 4567;"
3282                                "8901");
3283
3284  LocalContext env0;
3285  Local<Script> script0 = Script::Compile(source);
3286  CHECK_EQ(8901.0, script0->Run()->NumberValue());
3287
3288  LocalContext env1;
3289  Local<Script> script1 = Script::Compile(source);
3290  CHECK_EQ(8901.0, script1->Run()->NumberValue());
3291}
3292
3293
3294THREADED_TEST(UndetectableObject) {
3295  v8::HandleScope scope;
3296  LocalContext env;
3297
3298  Local<v8::FunctionTemplate> desc =
3299      v8::FunctionTemplate::New(0, v8::Handle<Value>());
3300  desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
3301
3302  Local<v8::Object> obj = desc->GetFunction()->NewInstance();
3303  env->Global()->Set(v8_str("undetectable"), obj);
3304
3305  ExpectString("undetectable.toString()", "[object Object]");
3306  ExpectString("typeof undetectable", "undefined");
3307  ExpectString("typeof(undetectable)", "undefined");
3308  ExpectBoolean("typeof undetectable == 'undefined'", true);
3309  ExpectBoolean("typeof undetectable == 'object'", false);
3310  ExpectBoolean("if (undetectable) { true; } else { false; }", false);
3311  ExpectBoolean("!undetectable", true);
3312
3313  ExpectObject("true&&undetectable", obj);
3314  ExpectBoolean("false&&undetectable", false);
3315  ExpectBoolean("true||undetectable", true);
3316  ExpectObject("false||undetectable", obj);
3317
3318  ExpectObject("undetectable&&true", obj);
3319  ExpectObject("undetectable&&false", obj);
3320  ExpectBoolean("undetectable||true", true);
3321  ExpectBoolean("undetectable||false", false);
3322
3323  ExpectBoolean("undetectable==null", true);
3324  ExpectBoolean("null==undetectable", true);
3325  ExpectBoolean("undetectable==undefined", true);
3326  ExpectBoolean("undefined==undetectable", true);
3327  ExpectBoolean("undetectable==undetectable", true);
3328
3329
3330  ExpectBoolean("undetectable===null", false);
3331  ExpectBoolean("null===undetectable", false);
3332  ExpectBoolean("undetectable===undefined", false);
3333  ExpectBoolean("undefined===undetectable", false);
3334  ExpectBoolean("undetectable===undetectable", true);
3335}
3336
3337
3338THREADED_TEST(UndetectableString) {
3339  v8::HandleScope scope;
3340  LocalContext env;
3341
3342  Local<String> obj = String::NewUndetectable("foo");
3343  env->Global()->Set(v8_str("undetectable"), obj);
3344
3345  ExpectString("undetectable", "foo");
3346  ExpectString("typeof undetectable", "undefined");
3347  ExpectString("typeof(undetectable)", "undefined");
3348  ExpectBoolean("typeof undetectable == 'undefined'", true);
3349  ExpectBoolean("typeof undetectable == 'string'", false);
3350  ExpectBoolean("if (undetectable) { true; } else { false; }", false);
3351  ExpectBoolean("!undetectable", true);
3352
3353  ExpectObject("true&&undetectable", obj);
3354  ExpectBoolean("false&&undetectable", false);
3355  ExpectBoolean("true||undetectable", true);
3356  ExpectObject("false||undetectable", obj);
3357
3358  ExpectObject("undetectable&&true", obj);
3359  ExpectObject("undetectable&&false", obj);
3360  ExpectBoolean("undetectable||true", true);
3361  ExpectBoolean("undetectable||false", false);
3362
3363  ExpectBoolean("undetectable==null", true);
3364  ExpectBoolean("null==undetectable", true);
3365  ExpectBoolean("undetectable==undefined", true);
3366  ExpectBoolean("undefined==undetectable", true);
3367  ExpectBoolean("undetectable==undetectable", true);
3368
3369
3370  ExpectBoolean("undetectable===null", false);
3371  ExpectBoolean("null===undetectable", false);
3372  ExpectBoolean("undetectable===undefined", false);
3373  ExpectBoolean("undefined===undetectable", false);
3374  ExpectBoolean("undetectable===undetectable", true);
3375}
3376
3377
3378template <typename T> static void USE(T) { }
3379
3380
3381// This test is not intended to be run, just type checked.
3382static void PersistentHandles() {
3383  USE(PersistentHandles);
3384  Local<String> str = v8_str("foo");
3385  v8::Persistent<String> p_str = v8::Persistent<String>::New(str);
3386  USE(p_str);
3387  Local<Script> scr = Script::Compile(v8_str(""));
3388  v8::Persistent<Script> p_scr = v8::Persistent<Script>::New(scr);
3389  USE(p_scr);
3390  Local<ObjectTemplate> templ = ObjectTemplate::New();
3391  v8::Persistent<ObjectTemplate> p_templ =
3392    v8::Persistent<ObjectTemplate>::New(templ);
3393  USE(p_templ);
3394}
3395
3396
3397static v8::Handle<Value> HandleLogDelegator(const v8::Arguments& args) {
3398  ApiTestFuzzer::Fuzz();
3399  return v8::Undefined();
3400}
3401
3402
3403THREADED_TEST(GlobalObjectTemplate) {
3404  v8::HandleScope handle_scope;
3405  Local<ObjectTemplate> global_template = ObjectTemplate::New();
3406  global_template->Set(v8_str("JSNI_Log"),
3407                       v8::FunctionTemplate::New(HandleLogDelegator));
3408  v8::Persistent<Context> context = Context::New(0, global_template);
3409  Context::Scope context_scope(context);
3410  Script::Compile(v8_str("JSNI_Log('LOG')"))->Run();
3411  context.Dispose();
3412}
3413
3414
3415static const char* kSimpleExtensionSource =
3416  "function Foo() {"
3417  "  return 4;"
3418  "}";
3419
3420
3421THREADED_TEST(SimpleExtensions) {
3422  v8::HandleScope handle_scope;
3423  v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
3424  const char* extension_names[] = { "simpletest" };
3425  v8::ExtensionConfiguration extensions(1, extension_names);
3426  v8::Handle<Context> context = Context::New(&extensions);
3427  Context::Scope lock(context);
3428  v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
3429  CHECK_EQ(result, v8::Integer::New(4));
3430}
3431
3432
3433static const char* kEvalExtensionSource1 =
3434  "function UseEval1() {"
3435  "  var x = 42;"
3436  "  return eval('x');"
3437  "}";
3438
3439
3440static const char* kEvalExtensionSource2 =
3441  "(function() {"
3442  "  var x = 42;"
3443  "  function e() {"
3444  "    return eval('x');"
3445  "  }"
3446  "  this.UseEval2 = e;"
3447  "})()";
3448
3449
3450THREADED_TEST(UseEvalFromExtension) {
3451  v8::HandleScope handle_scope;
3452  v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
3453  v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
3454  const char* extension_names[] = { "evaltest1", "evaltest2" };
3455  v8::ExtensionConfiguration extensions(2, extension_names);
3456  v8::Handle<Context> context = Context::New(&extensions);
3457  Context::Scope lock(context);
3458  v8::Handle<Value> result = Script::Compile(v8_str("UseEval1()"))->Run();
3459  CHECK_EQ(result, v8::Integer::New(42));
3460  result = Script::Compile(v8_str("UseEval2()"))->Run();
3461  CHECK_EQ(result, v8::Integer::New(42));
3462}
3463
3464
3465static const char* kWithExtensionSource1 =
3466  "function UseWith1() {"
3467  "  var x = 42;"
3468  "  with({x:87}) { return x; }"
3469  "}";
3470
3471
3472
3473static const char* kWithExtensionSource2 =
3474  "(function() {"
3475  "  var x = 42;"
3476  "  function e() {"
3477  "    with ({x:87}) { return x; }"
3478  "  }"
3479  "  this.UseWith2 = e;"
3480  "})()";
3481
3482
3483THREADED_TEST(UseWithFromExtension) {
3484  v8::HandleScope handle_scope;
3485  v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
3486  v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
3487  const char* extension_names[] = { "withtest1", "withtest2" };
3488  v8::ExtensionConfiguration extensions(2, extension_names);
3489  v8::Handle<Context> context = Context::New(&extensions);
3490  Context::Scope lock(context);
3491  v8::Handle<Value> result = Script::Compile(v8_str("UseWith1()"))->Run();
3492  CHECK_EQ(result, v8::Integer::New(87));
3493  result = Script::Compile(v8_str("UseWith2()"))->Run();
3494  CHECK_EQ(result, v8::Integer::New(87));
3495}
3496
3497
3498THREADED_TEST(AutoExtensions) {
3499  v8::HandleScope handle_scope;
3500  Extension* extension = new Extension("autotest", kSimpleExtensionSource);
3501  extension->set_auto_enable(true);
3502  v8::RegisterExtension(extension);
3503  v8::Handle<Context> context = Context::New();
3504  Context::Scope lock(context);
3505  v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
3506  CHECK_EQ(result, v8::Integer::New(4));
3507}
3508
3509
3510static const char* kSyntaxErrorInExtensionSource =
3511    "[";
3512
3513
3514// Test that a syntax error in an extension does not cause a fatal
3515// error but results in an empty context.
3516THREADED_TEST(SyntaxErrorExtensions) {
3517  v8::HandleScope handle_scope;
3518  v8::RegisterExtension(new Extension("syntaxerror",
3519                                      kSyntaxErrorInExtensionSource));
3520  const char* extension_names[] = { "syntaxerror" };
3521  v8::ExtensionConfiguration extensions(1, extension_names);
3522  v8::Handle<Context> context = Context::New(&extensions);
3523  CHECK(context.IsEmpty());
3524}
3525
3526
3527static const char* kExceptionInExtensionSource =
3528    "throw 42";
3529
3530
3531// Test that an exception when installing an extension does not cause
3532// a fatal error but results in an empty context.
3533THREADED_TEST(ExceptionExtensions) {
3534  v8::HandleScope handle_scope;
3535  v8::RegisterExtension(new Extension("exception",
3536                                      kExceptionInExtensionSource));
3537  const char* extension_names[] = { "exception" };
3538  v8::ExtensionConfiguration extensions(1, extension_names);
3539  v8::Handle<Context> context = Context::New(&extensions);
3540  CHECK(context.IsEmpty());
3541}
3542
3543
3544static void CheckDependencies(const char* name, const char* expected) {
3545  v8::HandleScope handle_scope;
3546  v8::ExtensionConfiguration config(1, &name);
3547  LocalContext context(&config);
3548  CHECK_EQ(String::New(expected), context->Global()->Get(v8_str("loaded")));
3549}
3550
3551
3552/*
3553 * Configuration:
3554 *
3555 *     /-- B <--\
3556 * A <-          -- D <-- E
3557 *     \-- C <--/
3558 */
3559THREADED_TEST(ExtensionDependency) {
3560  static const char* kEDeps[] = { "D" };
3561  v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
3562  static const char* kDDeps[] = { "B", "C" };
3563  v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
3564  static const char* kBCDeps[] = { "A" };
3565  v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
3566  v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
3567  v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
3568  CheckDependencies("A", "undefinedA");
3569  CheckDependencies("B", "undefinedAB");
3570  CheckDependencies("C", "undefinedAC");
3571  CheckDependencies("D", "undefinedABCD");
3572  CheckDependencies("E", "undefinedABCDE");
3573  v8::HandleScope handle_scope;
3574  static const char* exts[2] = { "C", "E" };
3575  v8::ExtensionConfiguration config(2, exts);
3576  LocalContext context(&config);
3577  CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
3578}
3579
3580
3581static const char* kExtensionTestScript =
3582  "native function A();"
3583  "native function B();"
3584  "native function C();"
3585  "function Foo(i) {"
3586  "  if (i == 0) return A();"
3587  "  if (i == 1) return B();"
3588  "  if (i == 2) return C();"
3589  "}";
3590
3591
3592static v8::Handle<Value> CallFun(const v8::Arguments& args) {
3593  ApiTestFuzzer::Fuzz();
3594  if (args.IsConstructCall()) {
3595    args.This()->Set(v8_str("data"), args.Data());
3596    return v8::Null();
3597  }
3598  return args.Data();
3599}
3600
3601
3602class FunctionExtension : public Extension {
3603 public:
3604  FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
3605  virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
3606      v8::Handle<String> name);
3607};
3608
3609
3610static int lookup_count = 0;
3611v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunction(
3612      v8::Handle<String> name) {
3613  lookup_count++;
3614  if (name->Equals(v8_str("A"))) {
3615    return v8::FunctionTemplate::New(CallFun, v8::Integer::New(8));
3616  } else if (name->Equals(v8_str("B"))) {
3617    return v8::FunctionTemplate::New(CallFun, v8::Integer::New(7));
3618  } else if (name->Equals(v8_str("C"))) {
3619    return v8::FunctionTemplate::New(CallFun, v8::Integer::New(6));
3620  } else {
3621    return v8::Handle<v8::FunctionTemplate>();
3622  }
3623}
3624
3625
3626THREADED_TEST(FunctionLookup) {
3627  v8::RegisterExtension(new FunctionExtension());
3628  v8::HandleScope handle_scope;
3629  static const char* exts[1] = { "functiontest" };
3630  v8::ExtensionConfiguration config(1, exts);
3631  LocalContext context(&config);
3632  CHECK_EQ(3, lookup_count);
3633  CHECK_EQ(v8::Integer::New(8), Script::Compile(v8_str("Foo(0)"))->Run());
3634  CHECK_EQ(v8::Integer::New(7), Script::Compile(v8_str("Foo(1)"))->Run());
3635  CHECK_EQ(v8::Integer::New(6), Script::Compile(v8_str("Foo(2)"))->Run());
3636}
3637
3638
3639THREADED_TEST(NativeFunctionConstructCall) {
3640  v8::RegisterExtension(new FunctionExtension());
3641  v8::HandleScope handle_scope;
3642  static const char* exts[1] = { "functiontest" };
3643  v8::ExtensionConfiguration config(1, exts);
3644  LocalContext context(&config);
3645  for (int i = 0; i < 10; i++) {
3646    // Run a few times to ensure that allocation of objects doesn't
3647    // change behavior of a constructor function.
3648    CHECK_EQ(v8::Integer::New(8),
3649             Script::Compile(v8_str("(new A()).data"))->Run());
3650    CHECK_EQ(v8::Integer::New(7),
3651             Script::Compile(v8_str("(new B()).data"))->Run());
3652    CHECK_EQ(v8::Integer::New(6),
3653             Script::Compile(v8_str("(new C()).data"))->Run());
3654  }
3655}
3656
3657
3658static const char* last_location;
3659static const char* last_message;
3660void StoringErrorCallback(const char* location, const char* message) {
3661  if (last_location == NULL) {
3662    last_location = location;
3663    last_message = message;
3664  }
3665}
3666
3667
3668// ErrorReporting creates a circular extensions configuration and
3669// tests that the fatal error handler gets called.  This renders V8
3670// unusable and therefore this test cannot be run in parallel.
3671TEST(ErrorReporting) {
3672  v8::V8::SetFatalErrorHandler(StoringErrorCallback);
3673  static const char* aDeps[] = { "B" };
3674  v8::RegisterExtension(new Extension("A", "", 1, aDeps));
3675  static const char* bDeps[] = { "A" };
3676  v8::RegisterExtension(new Extension("B", "", 1, bDeps));
3677  last_location = NULL;
3678  v8::ExtensionConfiguration config(1, bDeps);
3679  v8::Handle<Context> context = Context::New(&config);
3680  CHECK(context.IsEmpty());
3681  CHECK_NE(last_location, NULL);
3682}
3683
3684
3685static const char* js_code_causing_huge_string_flattening =
3686    "var str = 'X';"
3687    "for (var i = 0; i < 30; i++) {"
3688    "  str = str + str;"
3689    "}"
3690    "str.match(/X/);";
3691
3692
3693void OOMCallback(const char* location, const char* message) {
3694  exit(0);
3695}
3696
3697
3698TEST(RegexpOutOfMemory) {
3699  // Execute a script that causes out of memory when flattening a string.
3700  v8::HandleScope scope;
3701  v8::V8::SetFatalErrorHandler(OOMCallback);
3702  LocalContext context;
3703  Local<Script> script =
3704      Script::Compile(String::New(js_code_causing_huge_string_flattening));
3705  last_location = NULL;
3706  Local<Value> result = script->Run();
3707
3708  CHECK(false);  // Should not return.
3709}
3710
3711
3712static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
3713                                             v8::Handle<Value> data) {
3714  CHECK_EQ(v8::Undefined(), data);
3715  CHECK(message->GetScriptResourceName()->IsUndefined());
3716  CHECK_EQ(v8::Undefined(), message->GetScriptResourceName());
3717  message->GetLineNumber();
3718  message->GetSourceLine();
3719}
3720
3721
3722THREADED_TEST(ErrorWithMissingScriptInfo) {
3723  v8::HandleScope scope;
3724  LocalContext context;
3725  v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
3726  Script::Compile(v8_str("throw Error()"))->Run();
3727  v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
3728}
3729
3730
3731int global_index = 0;
3732
3733class Snorkel {
3734 public:
3735  Snorkel() { index_ = global_index++; }
3736  int index_;
3737};
3738
3739class Whammy {
3740 public:
3741  Whammy() {
3742    cursor_ = 0;
3743  }
3744  ~Whammy() {
3745    script_.Dispose();
3746  }
3747  v8::Handle<Script> getScript() {
3748    if (script_.IsEmpty())
3749      script_ = v8::Persistent<Script>::New(v8_compile("({}).blammo"));
3750    return Local<Script>(*script_);
3751  }
3752
3753 public:
3754  static const int kObjectCount = 256;
3755  int cursor_;
3756  v8::Persistent<v8::Object> objects_[kObjectCount];
3757  v8::Persistent<Script> script_;
3758};
3759
3760static void HandleWeakReference(v8::Persistent<v8::Value> obj, void* data) {
3761  Snorkel* snorkel = reinterpret_cast<Snorkel*>(data);
3762  delete snorkel;
3763  obj.ClearWeak();
3764}
3765
3766v8::Handle<Value> WhammyPropertyGetter(Local<String> name,
3767                                       const AccessorInfo& info) {
3768  Whammy* whammy =
3769    static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
3770
3771  v8::Persistent<v8::Object> prev = whammy->objects_[whammy->cursor_];
3772
3773  v8::Handle<v8::Object> obj = v8::Object::New();
3774  v8::Persistent<v8::Object> global = v8::Persistent<v8::Object>::New(obj);
3775  if (!prev.IsEmpty()) {
3776    prev->Set(v8_str("next"), obj);
3777    prev.MakeWeak(new Snorkel(), &HandleWeakReference);
3778    whammy->objects_[whammy->cursor_].Clear();
3779  }
3780  whammy->objects_[whammy->cursor_] = global;
3781  whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount;
3782  return whammy->getScript()->Run();
3783}
3784
3785THREADED_TEST(WeakReference) {
3786  v8::HandleScope handle_scope;
3787  v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New();
3788  templ->SetNamedPropertyHandler(WhammyPropertyGetter,
3789                                 0, 0, 0, 0,
3790                                 v8::External::New(new Whammy()));
3791  const char* extension_list[] = { "v8/gc" };
3792  v8::ExtensionConfiguration extensions(1, extension_list);
3793  v8::Persistent<Context> context = Context::New(&extensions);
3794  Context::Scope context_scope(context);
3795
3796  v8::Handle<v8::Object> interceptor = templ->NewInstance();
3797  context->Global()->Set(v8_str("whammy"), interceptor);
3798  const char* code =
3799      "var last;"
3800      "for (var i = 0; i < 10000; i++) {"
3801      "  var obj = whammy.length;"
3802      "  if (last) last.next = obj;"
3803      "  last = obj;"
3804      "}"
3805      "gc();"
3806      "4";
3807  v8::Handle<Value> result = CompileRun(code);
3808  CHECK_EQ(4.0, result->NumberValue());
3809
3810  context.Dispose();
3811}
3812
3813
3814static bool in_scavenge = false;
3815static int last = -1;
3816
3817static void ForceScavenge(v8::Persistent<v8::Value> obj, void* data) {
3818  CHECK_EQ(-1, last);
3819  last = 0;
3820  obj.Dispose();
3821  obj.Clear();
3822  in_scavenge = true;
3823  i::Heap::PerformScavenge();
3824  in_scavenge = false;
3825  *(reinterpret_cast<bool*>(data)) = true;
3826}
3827
3828static void CheckIsNotInvokedInScavenge(v8::Persistent<v8::Value> obj,
3829                                        void* data) {
3830  CHECK_EQ(0, last);
3831  last = 1;
3832  *(reinterpret_cast<bool*>(data)) = in_scavenge;
3833  obj.Dispose();
3834  obj.Clear();
3835}
3836
3837THREADED_TEST(NoWeakRefCallbacksInScavenge) {
3838  // Test verifies that scavenge cannot invoke WeakReferenceCallbacks.
3839  // Calling callbacks from scavenges is unsafe as objects held by those
3840  // handlers might have become strongly reachable, but scavenge doesn't
3841  // check that.
3842  v8::Persistent<Context> context = Context::New();
3843  Context::Scope context_scope(context);
3844
3845  v8::Persistent<v8::Object> object_a;
3846  v8::Persistent<v8::Object> object_b;
3847
3848  {
3849    v8::HandleScope handle_scope;
3850    object_b = v8::Persistent<v8::Object>::New(v8::Object::New());
3851    object_a = v8::Persistent<v8::Object>::New(v8::Object::New());
3852  }
3853
3854  bool object_a_disposed = false;
3855  object_a.MakeWeak(&object_a_disposed, &ForceScavenge);
3856  bool released_in_scavenge = false;
3857  object_b.MakeWeak(&released_in_scavenge, &CheckIsNotInvokedInScavenge);
3858
3859  while (!object_a_disposed) {
3860    i::Heap::CollectAllGarbage(false);
3861  }
3862  CHECK(!released_in_scavenge);
3863}
3864
3865
3866v8::Handle<Function> args_fun;
3867
3868
3869static v8::Handle<Value> ArgumentsTestCallback(const v8::Arguments& args) {
3870  ApiTestFuzzer::Fuzz();
3871  CHECK_EQ(args_fun, args.Callee());
3872  CHECK_EQ(3, args.Length());
3873  CHECK_EQ(v8::Integer::New(1), args[0]);
3874  CHECK_EQ(v8::Integer::New(2), args[1]);
3875  CHECK_EQ(v8::Integer::New(3), args[2]);
3876  CHECK_EQ(v8::Undefined(), args[3]);
3877  v8::HandleScope scope;
3878  i::Heap::CollectAllGarbage(false);
3879  return v8::Undefined();
3880}
3881
3882
3883THREADED_TEST(Arguments) {
3884  v8::HandleScope scope;
3885  v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
3886  global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback));
3887  LocalContext context(NULL, global);
3888  args_fun = context->Global()->Get(v8_str("f")).As<Function>();
3889  v8_compile("f(1, 2, 3)")->Run();
3890}
3891
3892
3893static v8::Handle<Value> NoBlockGetterX(Local<String> name,
3894                                        const AccessorInfo&) {
3895  return v8::Handle<Value>();
3896}
3897
3898
3899static v8::Handle<Value> NoBlockGetterI(uint32_t index,
3900                                        const AccessorInfo&) {
3901  return v8::Handle<Value>();
3902}
3903
3904
3905static v8::Handle<v8::Boolean> PDeleter(Local<String> name,
3906                                        const AccessorInfo&) {
3907  if (!name->Equals(v8_str("foo"))) {
3908    return v8::Handle<v8::Boolean>();  // not intercepted
3909  }
3910
3911  return v8::False();  // intercepted, and don't delete the property
3912}
3913
3914
3915static v8::Handle<v8::Boolean> IDeleter(uint32_t index, const AccessorInfo&) {
3916  if (index != 2) {
3917    return v8::Handle<v8::Boolean>();  // not intercepted
3918  }
3919
3920  return v8::False();  // intercepted, and don't delete the property
3921}
3922
3923
3924THREADED_TEST(Deleter) {
3925  v8::HandleScope scope;
3926  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
3927  obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
3928  obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
3929  LocalContext context;
3930  context->Global()->Set(v8_str("k"), obj->NewInstance());
3931  CompileRun(
3932    "k.foo = 'foo';"
3933    "k.bar = 'bar';"
3934    "k[2] = 2;"
3935    "k[4] = 4;");
3936  CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
3937  CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
3938
3939  CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
3940  CHECK(v8_compile("k.bar")->Run()->IsUndefined());
3941
3942  CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
3943  CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
3944
3945  CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
3946  CHECK(v8_compile("k[4]")->Run()->IsUndefined());
3947}
3948
3949
3950static v8::Handle<Value> GetK(Local<String> name, const AccessorInfo&) {
3951  ApiTestFuzzer::Fuzz();
3952  if (name->Equals(v8_str("foo")) ||
3953      name->Equals(v8_str("bar")) ||
3954      name->Equals(v8_str("baz"))) {
3955    return v8::Undefined();
3956  }
3957  return v8::Handle<Value>();
3958}
3959
3960
3961static v8::Handle<Value> IndexedGetK(uint32_t index, const AccessorInfo&) {
3962  ApiTestFuzzer::Fuzz();
3963  if (index == 0 || index == 1) return v8::Undefined();
3964  return v8::Handle<Value>();
3965}
3966
3967
3968static v8::Handle<v8::Array> NamedEnum(const AccessorInfo&) {
3969  ApiTestFuzzer::Fuzz();
3970  v8::Handle<v8::Array> result = v8::Array::New(3);
3971  result->Set(v8::Integer::New(0), v8_str("foo"));
3972  result->Set(v8::Integer::New(1), v8_str("bar"));
3973  result->Set(v8::Integer::New(2), v8_str("baz"));
3974  return result;
3975}
3976
3977
3978static v8::Handle<v8::Array> IndexedEnum(const AccessorInfo&) {
3979  ApiTestFuzzer::Fuzz();
3980  v8::Handle<v8::Array> result = v8::Array::New(2);
3981  result->Set(v8::Integer::New(0), v8_str("0"));
3982  result->Set(v8::Integer::New(1), v8_str("1"));
3983  return result;
3984}
3985
3986
3987THREADED_TEST(Enumerators) {
3988  v8::HandleScope scope;
3989  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
3990  obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
3991  obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
3992  LocalContext context;
3993  context->Global()->Set(v8_str("k"), obj->NewInstance());
3994  v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
3995    "k[10] = 0;"
3996    "k.a = 0;"
3997    "k[5] = 0;"
3998    "k.b = 0;"
3999    "k[4294967295] = 0;"
4000    "k.c = 0;"
4001    "k[4294967296] = 0;"
4002    "k.d = 0;"
4003    "k[140000] = 0;"
4004    "k.e = 0;"
4005    "k[30000000000] = 0;"
4006    "k.f = 0;"
4007    "var result = [];"
4008    "for (var prop in k) {"
4009    "  result.push(prop);"
4010    "}"
4011    "result"));
4012  // Check that we get all the property names returned including the
4013  // ones from the enumerators in the right order: indexed properties
4014  // in numerical order, indexed interceptor properties, named
4015  // properties in insertion order, named interceptor properties.
4016  // This order is not mandated by the spec, so this test is just
4017  // documenting our behavior.
4018  CHECK_EQ(17, result->Length());
4019  // Indexed properties in numerical order.
4020  CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(0)));
4021  CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(1)));
4022  CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(2)));
4023  CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(3)));
4024  // Indexed interceptor properties in the order they are returned
4025  // from the enumerator interceptor.
4026  CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(4)));
4027  CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(5)));
4028  // Named properties in insertion order.
4029  CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(6)));
4030  CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(7)));
4031  CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(8)));
4032  CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(9)));
4033  CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(10)));
4034  CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(11)));
4035  CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(12)));
4036  CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(13)));
4037  // Named interceptor properties.
4038  CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(14)));
4039  CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(15)));
4040  CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(16)));
4041}
4042
4043
4044int p_getter_count;
4045int p_getter_count2;
4046
4047
4048static v8::Handle<Value> PGetter(Local<String> name, const AccessorInfo& info) {
4049  ApiTestFuzzer::Fuzz();
4050  p_getter_count++;
4051  v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
4052  CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
4053  if (name->Equals(v8_str("p1"))) {
4054    CHECK_EQ(info.This(), global->Get(v8_str("o1")));
4055  } else if (name->Equals(v8_str("p2"))) {
4056    CHECK_EQ(info.This(), global->Get(v8_str("o2")));
4057  } else if (name->Equals(v8_str("p3"))) {
4058    CHECK_EQ(info.This(), global->Get(v8_str("o3")));
4059  } else if (name->Equals(v8_str("p4"))) {
4060    CHECK_EQ(info.This(), global->Get(v8_str("o4")));
4061  }
4062  return v8::Undefined();
4063}
4064
4065
4066static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
4067  ApiTestFuzzer::Fuzz();
4068  LocalContext context;
4069  context->Global()->Set(v8_str("o1"), obj->NewInstance());
4070  CompileRun(
4071    "o1.__proto__ = { };"
4072    "var o2 = { __proto__: o1 };"
4073    "var o3 = { __proto__: o2 };"
4074    "var o4 = { __proto__: o3 };"
4075    "for (var i = 0; i < 10; i++) o4.p4;"
4076    "for (var i = 0; i < 10; i++) o3.p3;"
4077    "for (var i = 0; i < 10; i++) o2.p2;"
4078    "for (var i = 0; i < 10; i++) o1.p1;");
4079}
4080
4081
4082static v8::Handle<Value> PGetter2(Local<String> name,
4083                                  const AccessorInfo& info) {
4084  ApiTestFuzzer::Fuzz();
4085  p_getter_count2++;
4086  v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
4087  CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
4088  if (name->Equals(v8_str("p1"))) {
4089    CHECK_EQ(info.This(), global->Get(v8_str("o1")));
4090  } else if (name->Equals(v8_str("p2"))) {
4091    CHECK_EQ(info.This(), global->Get(v8_str("o2")));
4092  } else if (name->Equals(v8_str("p3"))) {
4093    CHECK_EQ(info.This(), global->Get(v8_str("o3")));
4094  } else if (name->Equals(v8_str("p4"))) {
4095    CHECK_EQ(info.This(), global->Get(v8_str("o4")));
4096  }
4097  return v8::Undefined();
4098}
4099
4100
4101THREADED_TEST(GetterHolders) {
4102  v8::HandleScope scope;
4103  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4104  obj->SetAccessor(v8_str("p1"), PGetter);
4105  obj->SetAccessor(v8_str("p2"), PGetter);
4106  obj->SetAccessor(v8_str("p3"), PGetter);
4107  obj->SetAccessor(v8_str("p4"), PGetter);
4108  p_getter_count = 0;
4109  RunHolderTest(obj);
4110  CHECK_EQ(40, p_getter_count);
4111}
4112
4113
4114THREADED_TEST(PreInterceptorHolders) {
4115  v8::HandleScope scope;
4116  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4117  obj->SetNamedPropertyHandler(PGetter2);
4118  p_getter_count2 = 0;
4119  RunHolderTest(obj);
4120  CHECK_EQ(40, p_getter_count2);
4121}
4122
4123
4124THREADED_TEST(ObjectInstantiation) {
4125  v8::HandleScope scope;
4126  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
4127  templ->SetAccessor(v8_str("t"), PGetter2);
4128  LocalContext context;
4129  context->Global()->Set(v8_str("o"), templ->NewInstance());
4130  for (int i = 0; i < 100; i++) {
4131    v8::HandleScope inner_scope;
4132    v8::Handle<v8::Object> obj = templ->NewInstance();
4133    CHECK_NE(obj, context->Global()->Get(v8_str("o")));
4134    context->Global()->Set(v8_str("o2"), obj);
4135    v8::Handle<Value> value =
4136        Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run();
4137    CHECK_EQ(v8::True(), value);
4138    context->Global()->Set(v8_str("o"), obj);
4139  }
4140}
4141
4142
4143THREADED_TEST(StringWrite) {
4144  v8::HandleScope scope;
4145  v8::Handle<String> str = v8_str("abcde");
4146
4147  char buf[100];
4148  int len;
4149
4150  memset(buf, 0x1, sizeof(buf));
4151  len = str->WriteAscii(buf);
4152  CHECK_EQ(len, 5);
4153  CHECK_EQ(strncmp("abcde\0", buf, 6), 0);
4154
4155  memset(buf, 0x1, sizeof(buf));
4156  len = str->WriteAscii(buf, 0, 4);
4157  CHECK_EQ(len, 4);
4158  CHECK_EQ(strncmp("abcd\1", buf, 5), 0);
4159
4160  memset(buf, 0x1, sizeof(buf));
4161  len = str->WriteAscii(buf, 0, 5);
4162  CHECK_EQ(len, 5);
4163  CHECK_EQ(strncmp("abcde\1", buf, 6), 0);
4164
4165  memset(buf, 0x1, sizeof(buf));
4166  len = str->WriteAscii(buf, 0, 6);
4167  CHECK_EQ(len, 5);
4168  CHECK_EQ(strncmp("abcde\0", buf, 6), 0);
4169
4170  memset(buf, 0x1, sizeof(buf));
4171  len = str->WriteAscii(buf, 4, -1);
4172  CHECK_EQ(len, 1);
4173  CHECK_EQ(strncmp("e\0", buf, 2), 0);
4174
4175  memset(buf, 0x1, sizeof(buf));
4176  len = str->WriteAscii(buf, 4, 6);
4177  CHECK_EQ(len, 1);
4178  CHECK_EQ(strncmp("e\0", buf, 2), 0);
4179
4180  memset(buf, 0x1, sizeof(buf));
4181  len = str->WriteAscii(buf, 4, 1);
4182  CHECK_EQ(len, 1);
4183  CHECK_EQ(strncmp("e\1", buf, 2), 0);
4184}
4185
4186
4187THREADED_TEST(ToArrayIndex) {
4188  v8::HandleScope scope;
4189  LocalContext context;
4190
4191  v8::Handle<String> str = v8_str("42");
4192  v8::Handle<v8::Uint32> index = str->ToArrayIndex();
4193  CHECK(!index.IsEmpty());
4194  CHECK_EQ(42.0, index->Uint32Value());
4195  str = v8_str("42asdf");
4196  index = str->ToArrayIndex();
4197  CHECK(index.IsEmpty());
4198  str = v8_str("-42");
4199  index = str->ToArrayIndex();
4200  CHECK(index.IsEmpty());
4201  str = v8_str("4294967295");
4202  index = str->ToArrayIndex();
4203  CHECK(!index.IsEmpty());
4204  CHECK_EQ(4294967295.0, index->Uint32Value());
4205  v8::Handle<v8::Number> num = v8::Number::New(1);
4206  index = num->ToArrayIndex();
4207  CHECK(!index.IsEmpty());
4208  CHECK_EQ(1.0, index->Uint32Value());
4209  num = v8::Number::New(-1);
4210  index = num->ToArrayIndex();
4211  CHECK(index.IsEmpty());
4212  v8::Handle<v8::Object> obj = v8::Object::New();
4213  index = obj->ToArrayIndex();
4214  CHECK(index.IsEmpty());
4215}
4216
4217
4218THREADED_TEST(ErrorConstruction) {
4219  v8::HandleScope scope;
4220  LocalContext context;
4221
4222  v8::Handle<String> foo = v8_str("foo");
4223  v8::Handle<String> message = v8_str("message");
4224  v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
4225  CHECK(range_error->IsObject());
4226  v8::Handle<v8::Object> range_obj = range_error.As<v8::Object>();
4227  CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
4228  v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
4229  CHECK(reference_error->IsObject());
4230  CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
4231  v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
4232  CHECK(syntax_error->IsObject());
4233  CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
4234  v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
4235  CHECK(type_error->IsObject());
4236  CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
4237  v8::Handle<Value> error = v8::Exception::Error(foo);
4238  CHECK(error->IsObject());
4239  CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
4240}
4241
4242
4243static v8::Handle<Value> YGetter(Local<String> name, const AccessorInfo& info) {
4244  ApiTestFuzzer::Fuzz();
4245  return v8_num(10);
4246}
4247
4248
4249static void YSetter(Local<String> name,
4250                    Local<Value> value,
4251                    const AccessorInfo& info) {
4252  if (info.This()->Has(name)) {
4253    info.This()->Delete(name);
4254  }
4255  info.This()->Set(name, value);
4256}
4257
4258
4259THREADED_TEST(DeleteAccessor) {
4260  v8::HandleScope scope;
4261  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4262  obj->SetAccessor(v8_str("y"), YGetter, YSetter);
4263  LocalContext context;
4264  v8::Handle<v8::Object> holder = obj->NewInstance();
4265  context->Global()->Set(v8_str("holder"), holder);
4266  v8::Handle<Value> result = CompileRun(
4267      "holder.y = 11; holder.y = 12; holder.y");
4268  CHECK_EQ(12, result->Uint32Value());
4269}
4270
4271
4272THREADED_TEST(TypeSwitch) {
4273  v8::HandleScope scope;
4274  v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New();
4275  v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New();
4276  v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New();
4277  v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
4278  v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
4279  LocalContext context;
4280  v8::Handle<v8::Object> obj0 = v8::Object::New();
4281  v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
4282  v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
4283  v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
4284  for (int i = 0; i < 10; i++) {
4285    CHECK_EQ(0, type_switch->match(obj0));
4286    CHECK_EQ(1, type_switch->match(obj1));
4287    CHECK_EQ(2, type_switch->match(obj2));
4288    CHECK_EQ(3, type_switch->match(obj3));
4289    CHECK_EQ(3, type_switch->match(obj3));
4290    CHECK_EQ(2, type_switch->match(obj2));
4291    CHECK_EQ(1, type_switch->match(obj1));
4292    CHECK_EQ(0, type_switch->match(obj0));
4293  }
4294}
4295
4296
4297// For use within the TestSecurityHandler() test.
4298static bool g_security_callback_result = false;
4299static bool NamedSecurityTestCallback(Local<v8::Object> global,
4300                                      Local<Value> name,
4301                                      v8::AccessType type,
4302                                      Local<Value> data) {
4303  // Always allow read access.
4304  if (type == v8::ACCESS_GET)
4305    return true;
4306
4307  // Sometimes allow other access.
4308  return g_security_callback_result;
4309}
4310
4311
4312static bool IndexedSecurityTestCallback(Local<v8::Object> global,
4313                                        uint32_t key,
4314                                        v8::AccessType type,
4315                                        Local<Value> data) {
4316  // Always allow read access.
4317  if (type == v8::ACCESS_GET)
4318    return true;
4319
4320  // Sometimes allow other access.
4321  return g_security_callback_result;
4322}
4323
4324
4325static int trouble_nesting = 0;
4326static v8::Handle<Value> TroubleCallback(const v8::Arguments& args) {
4327  ApiTestFuzzer::Fuzz();
4328  trouble_nesting++;
4329
4330  // Call a JS function that throws an uncaught exception.
4331  Local<v8::Object> arg_this = Context::GetCurrent()->Global();
4332  Local<Value> trouble_callee = (trouble_nesting == 3) ?
4333    arg_this->Get(v8_str("trouble_callee")) :
4334    arg_this->Get(v8_str("trouble_caller"));
4335  CHECK(trouble_callee->IsFunction());
4336  return Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL);
4337}
4338
4339
4340static int report_count = 0;
4341static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
4342                                             v8::Handle<Value>) {
4343  report_count++;
4344}
4345
4346
4347// Counts uncaught exceptions, but other tests running in parallel
4348// also have uncaught exceptions.
4349TEST(ApiUncaughtException) {
4350  report_count = 0;
4351  v8::HandleScope scope;
4352  LocalContext env;
4353  v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
4354
4355  Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
4356  v8::Local<v8::Object> global = env->Global();
4357  global->Set(v8_str("trouble"), fun->GetFunction());
4358
4359  Script::Compile(v8_str("function trouble_callee() {"
4360                         "  var x = null;"
4361                         "  return x.foo;"
4362                         "};"
4363                         "function trouble_caller() {"
4364                         "  trouble();"
4365                         "};"))->Run();
4366  Local<Value> trouble = global->Get(v8_str("trouble"));
4367  CHECK(trouble->IsFunction());
4368  Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
4369  CHECK(trouble_callee->IsFunction());
4370  Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
4371  CHECK(trouble_caller->IsFunction());
4372  Function::Cast(*trouble_caller)->Call(global, 0, NULL);
4373  CHECK_EQ(1, report_count);
4374  v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
4375}
4376
4377static const char* script_resource_name = "ExceptionInNativeScript.js";
4378static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
4379                                                v8::Handle<Value>) {
4380  v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
4381  CHECK(!name_val.IsEmpty() && name_val->IsString());
4382  v8::String::AsciiValue name(message->GetScriptResourceName());
4383  CHECK_EQ(script_resource_name, *name);
4384  CHECK_EQ(3, message->GetLineNumber());
4385  v8::String::AsciiValue source_line(message->GetSourceLine());
4386  CHECK_EQ("  new o.foo();", *source_line);
4387}
4388
4389TEST(ExceptionInNativeScript) {
4390  v8::HandleScope scope;
4391  LocalContext env;
4392  v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
4393
4394  Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
4395  v8::Local<v8::Object> global = env->Global();
4396  global->Set(v8_str("trouble"), fun->GetFunction());
4397
4398  Script::Compile(v8_str("function trouble() {\n"
4399                         "  var o = {};\n"
4400                         "  new o.foo();\n"
4401                         "};"), v8::String::New(script_resource_name))->Run();
4402  Local<Value> trouble = global->Get(v8_str("trouble"));
4403  CHECK(trouble->IsFunction());
4404  Function::Cast(*trouble)->Call(global, 0, NULL);
4405  v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
4406}
4407
4408
4409TEST(CompilationErrorUsingTryCatchHandler) {
4410  v8::HandleScope scope;
4411  LocalContext env;
4412  v8::TryCatch try_catch;
4413  Script::Compile(v8_str("This doesn't &*&@#$&*^ compile."));
4414  CHECK_NE(NULL, *try_catch.Exception());
4415  CHECK(try_catch.HasCaught());
4416}
4417
4418
4419TEST(TryCatchFinallyUsingTryCatchHandler) {
4420  v8::HandleScope scope;
4421  LocalContext env;
4422  v8::TryCatch try_catch;
4423  Script::Compile(v8_str("try { throw ''; } catch (e) {}"))->Run();
4424  CHECK(!try_catch.HasCaught());
4425  Script::Compile(v8_str("try { throw ''; } finally {}"))->Run();
4426  CHECK(try_catch.HasCaught());
4427  try_catch.Reset();
4428  Script::Compile(v8_str("(function() {"
4429                         "try { throw ''; } finally { return; }"
4430                         "})()"))->Run();
4431  CHECK(!try_catch.HasCaught());
4432  Script::Compile(v8_str("(function()"
4433                         "  { try { throw ''; } finally { throw 0; }"
4434                         "})()"))->Run();
4435  CHECK(try_catch.HasCaught());
4436}
4437
4438
4439// SecurityHandler can't be run twice
4440TEST(SecurityHandler) {
4441  v8::HandleScope scope0;
4442  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
4443  global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
4444                                           IndexedSecurityTestCallback);
4445  // Create an environment
4446  v8::Persistent<Context> context0 =
4447    Context::New(NULL, global_template);
4448  context0->Enter();
4449
4450  v8::Handle<v8::Object> global0 = context0->Global();
4451  v8::Handle<Script> script0 = v8_compile("foo = 111");
4452  script0->Run();
4453  global0->Set(v8_str("0"), v8_num(999));
4454  v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
4455  CHECK_EQ(111, foo0->Int32Value());
4456  v8::Handle<Value> z0 = global0->Get(v8_str("0"));
4457  CHECK_EQ(999, z0->Int32Value());
4458
4459  // Create another environment, should fail security checks.
4460  v8::HandleScope scope1;
4461
4462  v8::Persistent<Context> context1 =
4463    Context::New(NULL, global_template);
4464  context1->Enter();
4465
4466  v8::Handle<v8::Object> global1 = context1->Global();
4467  global1->Set(v8_str("othercontext"), global0);
4468  // This set will fail the security check.
4469  v8::Handle<Script> script1 =
4470    v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
4471  script1->Run();
4472  // This read will pass the security check.
4473  v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
4474  CHECK_EQ(111, foo1->Int32Value());
4475  // This read will pass the security check.
4476  v8::Handle<Value> z1 = global0->Get(v8_str("0"));
4477  CHECK_EQ(999, z1->Int32Value());
4478
4479  // Create another environment, should pass security checks.
4480  { g_security_callback_result = true;  // allow security handler to pass.
4481    v8::HandleScope scope2;
4482    LocalContext context2;
4483    v8::Handle<v8::Object> global2 = context2->Global();
4484    global2->Set(v8_str("othercontext"), global0);
4485    v8::Handle<Script> script2 =
4486        v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
4487    script2->Run();
4488    v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
4489    CHECK_EQ(333, foo2->Int32Value());
4490    v8::Handle<Value> z2 = global0->Get(v8_str("0"));
4491    CHECK_EQ(888, z2->Int32Value());
4492  }
4493
4494  context1->Exit();
4495  context1.Dispose();
4496
4497  context0->Exit();
4498  context0.Dispose();
4499}
4500
4501
4502THREADED_TEST(SecurityChecks) {
4503  v8::HandleScope handle_scope;
4504  LocalContext env1;
4505  v8::Persistent<Context> env2 = Context::New();
4506
4507  Local<Value> foo = v8_str("foo");
4508  Local<Value> bar = v8_str("bar");
4509
4510  // Set to the same domain.
4511  env1->SetSecurityToken(foo);
4512
4513  // Create a function in env1.
4514  Script::Compile(v8_str("spy=function(){return spy;}"))->Run();
4515  Local<Value> spy = env1->Global()->Get(v8_str("spy"));
4516  CHECK(spy->IsFunction());
4517
4518  // Create another function accessing global objects.
4519  Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run();
4520  Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
4521  CHECK(spy2->IsFunction());
4522
4523  // Switch to env2 in the same domain and invoke spy on env2.
4524  {
4525    env2->SetSecurityToken(foo);
4526    // Enter env2
4527    Context::Scope scope_env2(env2);
4528    Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
4529    CHECK(result->IsFunction());
4530  }
4531
4532  {
4533    env2->SetSecurityToken(bar);
4534    Context::Scope scope_env2(env2);
4535
4536    // Call cross_domain_call, it should throw an exception
4537    v8::TryCatch try_catch;
4538    Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
4539    CHECK(try_catch.HasCaught());
4540  }
4541
4542  env2.Dispose();
4543}
4544
4545
4546// Regression test case for issue 1183439.
4547THREADED_TEST(SecurityChecksForPrototypeChain) {
4548  v8::HandleScope scope;
4549  LocalContext current;
4550  v8::Persistent<Context> other = Context::New();
4551
4552  // Change context to be able to get to the Object function in the
4553  // other context without hitting the security checks.
4554  v8::Local<Value> other_object;
4555  { Context::Scope scope(other);
4556    other_object = other->Global()->Get(v8_str("Object"));
4557    other->Global()->Set(v8_num(42), v8_num(87));
4558  }
4559
4560  current->Global()->Set(v8_str("other"), other->Global());
4561  CHECK(v8_compile("other")->Run()->Equals(other->Global()));
4562
4563  // Make sure the security check fails here and we get an undefined
4564  // result instead of getting the Object function. Repeat in a loop
4565  // to make sure to exercise the IC code.
4566  v8::Local<Script> access_other0 = v8_compile("other.Object");
4567  v8::Local<Script> access_other1 = v8_compile("other[42]");
4568  for (int i = 0; i < 5; i++) {
4569    CHECK(!access_other0->Run()->Equals(other_object));
4570    CHECK(access_other0->Run()->IsUndefined());
4571    CHECK(!access_other1->Run()->Equals(v8_num(87)));
4572    CHECK(access_other1->Run()->IsUndefined());
4573  }
4574
4575  // Create an object that has 'other' in its prototype chain and make
4576  // sure we cannot access the Object function indirectly through
4577  // that. Repeat in a loop to make sure to exercise the IC code.
4578  v8_compile("function F() { };"
4579             "F.prototype = other;"
4580             "var f = new F();")->Run();
4581  v8::Local<Script> access_f0 = v8_compile("f.Object");
4582  v8::Local<Script> access_f1 = v8_compile("f[42]");
4583  for (int j = 0; j < 5; j++) {
4584    CHECK(!access_f0->Run()->Equals(other_object));
4585    CHECK(access_f0->Run()->IsUndefined());
4586    CHECK(!access_f1->Run()->Equals(v8_num(87)));
4587    CHECK(access_f1->Run()->IsUndefined());
4588  }
4589
4590  // Now it gets hairy: Set the prototype for the other global object
4591  // to be the current global object. The prototype chain for 'f' now
4592  // goes through 'other' but ends up in the current global object.
4593  { Context::Scope scope(other);
4594    other->Global()->Set(v8_str("__proto__"), current->Global());
4595  }
4596  // Set a named and an index property on the current global
4597  // object. To force the lookup to go through the other global object,
4598  // the properties must not exist in the other global object.
4599  current->Global()->Set(v8_str("foo"), v8_num(100));
4600  current->Global()->Set(v8_num(99), v8_num(101));
4601  // Try to read the properties from f and make sure that the access
4602  // gets stopped by the security checks on the other global object.
4603  Local<Script> access_f2 = v8_compile("f.foo");
4604  Local<Script> access_f3 = v8_compile("f[99]");
4605  for (int k = 0; k < 5; k++) {
4606    CHECK(!access_f2->Run()->Equals(v8_num(100)));
4607    CHECK(access_f2->Run()->IsUndefined());
4608    CHECK(!access_f3->Run()->Equals(v8_num(101)));
4609    CHECK(access_f3->Run()->IsUndefined());
4610  }
4611  other.Dispose();
4612}
4613
4614
4615THREADED_TEST(CrossDomainDelete) {
4616  v8::HandleScope handle_scope;
4617  LocalContext env1;
4618  v8::Persistent<Context> env2 = Context::New();
4619
4620  Local<Value> foo = v8_str("foo");
4621  Local<Value> bar = v8_str("bar");
4622
4623  // Set to the same domain.
4624  env1->SetSecurityToken(foo);
4625  env2->SetSecurityToken(foo);
4626
4627  env1->Global()->Set(v8_str("prop"), v8_num(3));
4628  env2->Global()->Set(v8_str("env1"), env1->Global());
4629
4630  // Change env2 to a different domain and delete env1.prop.
4631  env2->SetSecurityToken(bar);
4632  {
4633    Context::Scope scope_env2(env2);
4634    Local<Value> result =
4635        Script::Compile(v8_str("delete env1.prop"))->Run();
4636    CHECK(result->IsFalse());
4637  }
4638
4639  // Check that env1.prop still exists.
4640  Local<Value> v = env1->Global()->Get(v8_str("prop"));
4641  CHECK(v->IsNumber());
4642  CHECK_EQ(3, v->Int32Value());
4643
4644  env2.Dispose();
4645}
4646
4647
4648THREADED_TEST(CrossDomainIsPropertyEnumerable) {
4649  v8::HandleScope handle_scope;
4650  LocalContext env1;
4651  v8::Persistent<Context> env2 = Context::New();
4652
4653  Local<Value> foo = v8_str("foo");
4654  Local<Value> bar = v8_str("bar");
4655
4656  // Set to the same domain.
4657  env1->SetSecurityToken(foo);
4658  env2->SetSecurityToken(foo);
4659
4660  env1->Global()->Set(v8_str("prop"), v8_num(3));
4661  env2->Global()->Set(v8_str("env1"), env1->Global());
4662
4663  // env1.prop is enumerable in env2.
4664  Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
4665  {
4666    Context::Scope scope_env2(env2);
4667    Local<Value> result = Script::Compile(test)->Run();
4668    CHECK(result->IsTrue());
4669  }
4670
4671  // Change env2 to a different domain and test again.
4672  env2->SetSecurityToken(bar);
4673  {
4674    Context::Scope scope_env2(env2);
4675    Local<Value> result = Script::Compile(test)->Run();
4676    CHECK(result->IsFalse());
4677  }
4678
4679  env2.Dispose();
4680}
4681
4682
4683THREADED_TEST(CrossDomainForIn) {
4684  v8::HandleScope handle_scope;
4685  LocalContext env1;
4686  v8::Persistent<Context> env2 = Context::New();
4687
4688  Local<Value> foo = v8_str("foo");
4689  Local<Value> bar = v8_str("bar");
4690
4691  // Set to the same domain.
4692  env1->SetSecurityToken(foo);
4693  env2->SetSecurityToken(foo);
4694
4695  env1->Global()->Set(v8_str("prop"), v8_num(3));
4696  env2->Global()->Set(v8_str("env1"), env1->Global());
4697
4698  // Change env2 to a different domain and set env1's global object
4699  // as the __proto__ of an object in env2 and enumerate properties
4700  // in for-in. It shouldn't enumerate properties on env1's global
4701  // object.
4702  env2->SetSecurityToken(bar);
4703  {
4704    Context::Scope scope_env2(env2);
4705    Local<Value> result =
4706        CompileRun("(function(){var obj = {'__proto__':env1};"
4707                   "for (var p in obj)"
4708                   "   if (p == 'prop') return false;"
4709                   "return true;})()");
4710    CHECK(result->IsTrue());
4711  }
4712  env2.Dispose();
4713}
4714
4715
4716TEST(ContextDetachGlobal) {
4717  v8::HandleScope handle_scope;
4718  LocalContext env1;
4719  v8::Persistent<Context> env2 = Context::New();
4720
4721  Local<v8::Object> global1 = env1->Global();
4722
4723  Local<Value> foo = v8_str("foo");
4724
4725  // Set to the same domain.
4726  env1->SetSecurityToken(foo);
4727  env2->SetSecurityToken(foo);
4728
4729  // Enter env2
4730  env2->Enter();
4731
4732  // Create a function in env2 and add a reference to it in env1.
4733  Local<v8::Object> global2 = env2->Global();
4734  global2->Set(v8_str("prop"), v8::Integer::New(1));
4735  CompileRun("function getProp() {return prop;}");
4736
4737  env1->Global()->Set(v8_str("getProp"),
4738                      global2->Get(v8_str("getProp")));
4739
4740  // Detach env2's global, and reuse the global object of env2
4741  env2->Exit();
4742  env2->DetachGlobal();
4743  // env2 has a new global object.
4744  CHECK(!env2->Global()->Equals(global2));
4745
4746  v8::Persistent<Context> env3 =
4747      Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
4748  env3->SetSecurityToken(v8_str("bar"));
4749  env3->Enter();
4750
4751  Local<v8::Object> global3 = env3->Global();
4752  CHECK_EQ(global2, global3);
4753  CHECK(global3->Get(v8_str("prop"))->IsUndefined());
4754  CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
4755  global3->Set(v8_str("prop"), v8::Integer::New(-1));
4756  global3->Set(v8_str("prop2"), v8::Integer::New(2));
4757  env3->Exit();
4758
4759  // Call getProp in env1, and it should return the value 1
4760  {
4761    Local<Value> get_prop = global1->Get(v8_str("getProp"));
4762    CHECK(get_prop->IsFunction());
4763    v8::TryCatch try_catch;
4764    Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
4765    CHECK(!try_catch.HasCaught());
4766    CHECK_EQ(1, r->Int32Value());
4767  }
4768
4769  // Check that env3 is not accessible from env1
4770  {
4771    Local<Value> r = global3->Get(v8_str("prop2"));
4772    CHECK(r->IsUndefined());
4773  }
4774
4775  env2.Dispose();
4776  env3.Dispose();
4777}
4778
4779
4780TEST(DetachAndReattachGlobal) {
4781  v8::HandleScope scope;
4782  LocalContext env1;
4783
4784  // Create second environment.
4785  v8::Persistent<Context> env2 = Context::New();
4786
4787  Local<Value> foo = v8_str("foo");
4788
4789  // Set same security token for env1 and env2.
4790  env1->SetSecurityToken(foo);
4791  env2->SetSecurityToken(foo);
4792
4793  // Create a property on the global object in env2.
4794  {
4795    v8::Context::Scope scope(env2);
4796    env2->Global()->Set(v8_str("p"), v8::Integer::New(42));
4797  }
4798
4799  // Create a reference to env2 global from env1 global.
4800  env1->Global()->Set(v8_str("other"), env2->Global());
4801
4802  // Check that we have access to other.p in env2 from env1.
4803  Local<Value> result = CompileRun("other.p");
4804  CHECK(result->IsInt32());
4805  CHECK_EQ(42, result->Int32Value());
4806
4807  // Hold on to global from env2 and detach global from env2.
4808  Local<v8::Object> global2 = env2->Global();
4809  env2->DetachGlobal();
4810
4811  // Check that the global has been detached. No other.p property can
4812  // be found.
4813  result = CompileRun("other.p");
4814  CHECK(result->IsUndefined());
4815
4816  // Reuse global2 for env3.
4817  v8::Persistent<Context> env3 =
4818      Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
4819  CHECK_EQ(global2, env3->Global());
4820
4821  // Start by using the same security token for env3 as for env1 and env2.
4822  env3->SetSecurityToken(foo);
4823
4824  // Create a property on the global object in env3.
4825  {
4826    v8::Context::Scope scope(env3);
4827    env3->Global()->Set(v8_str("p"), v8::Integer::New(24));
4828  }
4829
4830  // Check that other.p is now the property in env3 and that we have access.
4831  result = CompileRun("other.p");
4832  CHECK(result->IsInt32());
4833  CHECK_EQ(24, result->Int32Value());
4834
4835  // Change security token for env3 to something different from env1 and env2.
4836  env3->SetSecurityToken(v8_str("bar"));
4837
4838  // Check that we do not have access to other.p in env1. |other| is now
4839  // the global object for env3 which has a different security token,
4840  // so access should be blocked.
4841  result = CompileRun("other.p");
4842  CHECK(result->IsUndefined());
4843
4844  // Detach the global for env3 and reattach it to env2.
4845  env3->DetachGlobal();
4846  env2->ReattachGlobal(global2);
4847
4848  // Check that we have access to other.p again in env1.  |other| is now
4849  // the global object for env2 which has the same security token as env1.
4850  result = CompileRun("other.p");
4851  CHECK(result->IsInt32());
4852  CHECK_EQ(42, result->Int32Value());
4853
4854  env2.Dispose();
4855  env3.Dispose();
4856}
4857
4858
4859static bool NamedAccessBlocker(Local<v8::Object> global,
4860                               Local<Value> name,
4861                               v8::AccessType type,
4862                               Local<Value> data) {
4863  return Context::GetCurrent()->Global()->Equals(global);
4864}
4865
4866
4867static bool IndexedAccessBlocker(Local<v8::Object> global,
4868                                 uint32_t key,
4869                                 v8::AccessType type,
4870                                 Local<Value> data) {
4871  return Context::GetCurrent()->Global()->Equals(global);
4872}
4873
4874
4875static int g_echo_value = -1;
4876static v8::Handle<Value> EchoGetter(Local<String> name,
4877                                    const AccessorInfo& info) {
4878  return v8_num(g_echo_value);
4879}
4880
4881
4882static void EchoSetter(Local<String> name,
4883                       Local<Value> value,
4884                       const AccessorInfo&) {
4885  if (value->IsNumber())
4886    g_echo_value = value->Int32Value();
4887}
4888
4889
4890static v8::Handle<Value> UnreachableGetter(Local<String> name,
4891                                           const AccessorInfo& info) {
4892  CHECK(false);  // This function should not be called..
4893  return v8::Undefined();
4894}
4895
4896
4897static void UnreachableSetter(Local<String>, Local<Value>,
4898                              const AccessorInfo&) {
4899  CHECK(false);  // This function should nto be called.
4900}
4901
4902
4903THREADED_TEST(AccessControl) {
4904  v8::HandleScope handle_scope;
4905  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
4906
4907  global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
4908                                           IndexedAccessBlocker);
4909
4910  // Add an accessor accessible by cross-domain JS code.
4911  global_template->SetAccessor(
4912      v8_str("accessible_prop"),
4913      EchoGetter, EchoSetter,
4914      v8::Handle<Value>(),
4915      v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
4916
4917  // Add an accessor that is not accessible by cross-domain JS code.
4918  global_template->SetAccessor(v8_str("blocked_prop"),
4919                               UnreachableGetter, UnreachableSetter,
4920                               v8::Handle<Value>(),
4921                               v8::DEFAULT);
4922
4923  // Create an environment
4924  v8::Persistent<Context> context0 = Context::New(NULL, global_template);
4925  context0->Enter();
4926
4927  v8::Handle<v8::Object> global0 = context0->Global();
4928
4929  v8::HandleScope scope1;
4930
4931  v8::Persistent<Context> context1 = Context::New();
4932  context1->Enter();
4933
4934  v8::Handle<v8::Object> global1 = context1->Global();
4935  global1->Set(v8_str("other"), global0);
4936
4937  v8::Handle<Value> value;
4938
4939  // Access blocked property
4940  value = v8_compile("other.blocked_prop = 1")->Run();
4941  value = v8_compile("other.blocked_prop")->Run();
4942  CHECK(value->IsUndefined());
4943
4944  value = v8_compile("propertyIsEnumerable.call(other, 'blocked_prop')")->Run();
4945  CHECK(value->IsFalse());
4946
4947  // Access accessible property
4948  value = v8_compile("other.accessible_prop = 3")->Run();
4949  CHECK(value->IsNumber());
4950  CHECK_EQ(3, value->Int32Value());
4951  CHECK_EQ(3, g_echo_value);
4952
4953  value = v8_compile("other.accessible_prop")->Run();
4954  CHECK(value->IsNumber());
4955  CHECK_EQ(3, value->Int32Value());
4956
4957  value =
4958    v8_compile("propertyIsEnumerable.call(other, 'accessible_prop')")->Run();
4959  CHECK(value->IsTrue());
4960
4961  // Enumeration doesn't enumerate accessors from inaccessible objects in
4962  // the prototype chain even if the accessors are in themselves accessible.
4963  Local<Value> result =
4964      CompileRun("(function(){var obj = {'__proto__':other};"
4965                 "for (var p in obj)"
4966                 "   if (p == 'accessible_prop' || p == 'blocked_prop') {"
4967                 "     return false;"
4968                 "   }"
4969                 "return true;})()");
4970  CHECK(result->IsTrue());
4971
4972  context1->Exit();
4973  context0->Exit();
4974  context1.Dispose();
4975  context0.Dispose();
4976}
4977
4978
4979static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
4980                                            Local<Value> name,
4981                                            v8::AccessType type,
4982                                            Local<Value> data) {
4983  return false;
4984}
4985
4986
4987static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
4988                                              uint32_t key,
4989                                              v8::AccessType type,
4990                                              Local<Value> data) {
4991  return false;
4992}
4993
4994
4995THREADED_TEST(AccessControlGetOwnPropertyNames) {
4996  v8::HandleScope handle_scope;
4997  v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
4998
4999  obj_template->Set(v8_str("x"), v8::Integer::New(42));
5000  obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
5001                                        GetOwnPropertyNamesIndexedBlocker);
5002
5003  // Create an environment
5004  v8::Persistent<Context> context0 = Context::New(NULL, obj_template);
5005  context0->Enter();
5006
5007  v8::Handle<v8::Object> global0 = context0->Global();
5008
5009  v8::HandleScope scope1;
5010
5011  v8::Persistent<Context> context1 = Context::New();
5012  context1->Enter();
5013
5014  v8::Handle<v8::Object> global1 = context1->Global();
5015  global1->Set(v8_str("other"), global0);
5016  global1->Set(v8_str("object"), obj_template->NewInstance());
5017
5018  v8::Handle<Value> value;
5019
5020  // Attempt to get the property names of the other global object and
5021  // of an object that requires access checks.  Accessing the other
5022  // global object should be blocked by access checks on the global
5023  // proxy object.  Accessing the object that requires access checks
5024  // is blocked by the access checks on the object itself.
5025  value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
5026  CHECK(value->IsTrue());
5027
5028  value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
5029  CHECK(value->IsTrue());
5030
5031  context1->Exit();
5032  context0->Exit();
5033  context1.Dispose();
5034  context0.Dispose();
5035}
5036
5037
5038static v8::Handle<Value> ConstTenGetter(Local<String> name,
5039                                        const AccessorInfo& info) {
5040  return v8_num(10);
5041}
5042
5043
5044THREADED_TEST(CrossDomainAccessors) {
5045  v8::HandleScope handle_scope;
5046
5047  v8::Handle<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
5048
5049  v8::Handle<v8::ObjectTemplate> global_template =
5050      func_template->InstanceTemplate();
5051
5052  v8::Handle<v8::ObjectTemplate> proto_template =
5053      func_template->PrototypeTemplate();
5054
5055  // Add an accessor to proto that's accessible by cross-domain JS code.
5056  proto_template->SetAccessor(v8_str("accessible"),
5057                              ConstTenGetter, 0,
5058                              v8::Handle<Value>(),
5059                              v8::ALL_CAN_READ);
5060
5061  // Add an accessor that is not accessible by cross-domain JS code.
5062  global_template->SetAccessor(v8_str("unreachable"),
5063                               UnreachableGetter, 0,
5064                               v8::Handle<Value>(),
5065                               v8::DEFAULT);
5066
5067  v8::Persistent<Context> context0 = Context::New(NULL, global_template);
5068  context0->Enter();
5069
5070  Local<v8::Object> global = context0->Global();
5071  // Add a normal property that shadows 'accessible'
5072  global->Set(v8_str("accessible"), v8_num(11));
5073
5074  // Enter a new context.
5075  v8::HandleScope scope1;
5076  v8::Persistent<Context> context1 = Context::New();
5077  context1->Enter();
5078
5079  v8::Handle<v8::Object> global1 = context1->Global();
5080  global1->Set(v8_str("other"), global);
5081
5082  // Should return 10, instead of 11
5083  v8::Handle<Value> value = v8_compile("other.accessible")->Run();
5084  CHECK(value->IsNumber());
5085  CHECK_EQ(10, value->Int32Value());
5086
5087  value = v8_compile("other.unreachable")->Run();
5088  CHECK(value->IsUndefined());
5089
5090  context1->Exit();
5091  context0->Exit();
5092  context1.Dispose();
5093  context0.Dispose();
5094}
5095
5096
5097static int named_access_count = 0;
5098static int indexed_access_count = 0;
5099
5100static bool NamedAccessCounter(Local<v8::Object> global,
5101                               Local<Value> name,
5102                               v8::AccessType type,
5103                               Local<Value> data) {
5104  named_access_count++;
5105  return true;
5106}
5107
5108
5109static bool IndexedAccessCounter(Local<v8::Object> global,
5110                                 uint32_t key,
5111                                 v8::AccessType type,
5112                                 Local<Value> data) {
5113  indexed_access_count++;
5114  return true;
5115}
5116
5117
5118// This one is too easily disturbed by other tests.
5119TEST(AccessControlIC) {
5120  named_access_count = 0;
5121  indexed_access_count = 0;
5122
5123  v8::HandleScope handle_scope;
5124
5125  // Create an environment.
5126  v8::Persistent<Context> context0 = Context::New();
5127  context0->Enter();
5128
5129  // Create an object that requires access-check functions to be
5130  // called for cross-domain access.
5131  v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
5132  object_template->SetAccessCheckCallbacks(NamedAccessCounter,
5133                                           IndexedAccessCounter);
5134  Local<v8::Object> object = object_template->NewInstance();
5135
5136  v8::HandleScope scope1;
5137
5138  // Create another environment.
5139  v8::Persistent<Context> context1 = Context::New();
5140  context1->Enter();
5141
5142  // Make easy access to the object from the other environment.
5143  v8::Handle<v8::Object> global1 = context1->Global();
5144  global1->Set(v8_str("obj"), object);
5145
5146  v8::Handle<Value> value;
5147
5148  // Check that the named access-control function is called every time.
5149  CompileRun("function testProp(obj) {"
5150             "  for (var i = 0; i < 10; i++) obj.prop = 1;"
5151             "  for (var j = 0; j < 10; j++) obj.prop;"
5152             "  return obj.prop"
5153             "}");
5154  value = CompileRun("testProp(obj)");
5155  CHECK(value->IsNumber());
5156  CHECK_EQ(1, value->Int32Value());
5157  CHECK_EQ(21, named_access_count);
5158
5159  // Check that the named access-control function is called every time.
5160  CompileRun("var p = 'prop';"
5161             "function testKeyed(obj) {"
5162             "  for (var i = 0; i < 10; i++) obj[p] = 1;"
5163             "  for (var j = 0; j < 10; j++) obj[p];"
5164             "  return obj[p];"
5165             "}");
5166  // Use obj which requires access checks.  No inline caching is used
5167  // in that case.
5168  value = CompileRun("testKeyed(obj)");
5169  CHECK(value->IsNumber());
5170  CHECK_EQ(1, value->Int32Value());
5171  CHECK_EQ(42, named_access_count);
5172  // Force the inline caches into generic state and try again.
5173  CompileRun("testKeyed({ a: 0 })");
5174  CompileRun("testKeyed({ b: 0 })");
5175  value = CompileRun("testKeyed(obj)");
5176  CHECK(value->IsNumber());
5177  CHECK_EQ(1, value->Int32Value());
5178  CHECK_EQ(63, named_access_count);
5179
5180  // Check that the indexed access-control function is called every time.
5181  CompileRun("function testIndexed(obj) {"
5182             "  for (var i = 0; i < 10; i++) obj[0] = 1;"
5183             "  for (var j = 0; j < 10; j++) obj[0];"
5184             "  return obj[0]"
5185             "}");
5186  value = CompileRun("testIndexed(obj)");
5187  CHECK(value->IsNumber());
5188  CHECK_EQ(1, value->Int32Value());
5189  CHECK_EQ(21, indexed_access_count);
5190  // Force the inline caches into generic state.
5191  CompileRun("testIndexed(new Array(1))");
5192  // Test that the indexed access check is called.
5193  value = CompileRun("testIndexed(obj)");
5194  CHECK(value->IsNumber());
5195  CHECK_EQ(1, value->Int32Value());
5196  CHECK_EQ(42, indexed_access_count);
5197
5198  // Check that the named access check is called when invoking
5199  // functions on an object that requires access checks.
5200  CompileRun("obj.f = function() {}");
5201  CompileRun("function testCallNormal(obj) {"
5202             "  for (var i = 0; i < 10; i++) obj.f();"
5203             "}");
5204  CompileRun("testCallNormal(obj)");
5205  CHECK_EQ(74, named_access_count);
5206
5207  // Force obj into slow case.
5208  value = CompileRun("delete obj.prop");
5209  CHECK(value->BooleanValue());
5210  // Force inline caches into dictionary probing mode.
5211  CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
5212  // Test that the named access check is called.
5213  value = CompileRun("testProp(obj);");
5214  CHECK(value->IsNumber());
5215  CHECK_EQ(1, value->Int32Value());
5216  CHECK_EQ(96, named_access_count);
5217
5218  // Force the call inline cache into dictionary probing mode.
5219  CompileRun("o.f = function() {}; testCallNormal(o)");
5220  // Test that the named access check is still called for each
5221  // invocation of the function.
5222  value = CompileRun("testCallNormal(obj)");
5223  CHECK_EQ(106, named_access_count);
5224
5225  context1->Exit();
5226  context0->Exit();
5227  context1.Dispose();
5228  context0.Dispose();
5229}
5230
5231
5232static bool NamedAccessFlatten(Local<v8::Object> global,
5233                               Local<Value> name,
5234                               v8::AccessType type,
5235                               Local<Value> data) {
5236  char buf[100];
5237  int len;
5238
5239  CHECK(name->IsString());
5240
5241  memset(buf, 0x1, sizeof(buf));
5242  len = name.As<String>()->WriteAscii(buf);
5243  CHECK_EQ(4, len);
5244
5245  uint16_t buf2[100];
5246
5247  memset(buf, 0x1, sizeof(buf));
5248  len = name.As<String>()->Write(buf2);
5249  CHECK_EQ(4, len);
5250
5251  return true;
5252}
5253
5254
5255static bool IndexedAccessFlatten(Local<v8::Object> global,
5256                                 uint32_t key,
5257                                 v8::AccessType type,
5258                                 Local<Value> data) {
5259  return true;
5260}
5261
5262
5263// Regression test.  In access checks, operations that may cause
5264// garbage collection are not allowed.  It used to be the case that
5265// using the Write operation on a string could cause a garbage
5266// collection due to flattening of the string.  This is no longer the
5267// case.
5268THREADED_TEST(AccessControlFlatten) {
5269  named_access_count = 0;
5270  indexed_access_count = 0;
5271
5272  v8::HandleScope handle_scope;
5273
5274  // Create an environment.
5275  v8::Persistent<Context> context0 = Context::New();
5276  context0->Enter();
5277
5278  // Create an object that requires access-check functions to be
5279  // called for cross-domain access.
5280  v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
5281  object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
5282                                           IndexedAccessFlatten);
5283  Local<v8::Object> object = object_template->NewInstance();
5284
5285  v8::HandleScope scope1;
5286
5287  // Create another environment.
5288  v8::Persistent<Context> context1 = Context::New();
5289  context1->Enter();
5290
5291  // Make easy access to the object from the other environment.
5292  v8::Handle<v8::Object> global1 = context1->Global();
5293  global1->Set(v8_str("obj"), object);
5294
5295  v8::Handle<Value> value;
5296
5297  value = v8_compile("var p = 'as' + 'df';")->Run();
5298  value = v8_compile("obj[p];")->Run();
5299
5300  context1->Exit();
5301  context0->Exit();
5302  context1.Dispose();
5303  context0.Dispose();
5304}
5305
5306
5307static v8::Handle<Value> AccessControlNamedGetter(
5308    Local<String>, const AccessorInfo&) {
5309  return v8::Integer::New(42);
5310}
5311
5312
5313static v8::Handle<Value> AccessControlNamedSetter(
5314    Local<String>, Local<Value> value, const AccessorInfo&) {
5315  return value;
5316}
5317
5318
5319static v8::Handle<Value> AccessControlIndexedGetter(
5320      uint32_t index,
5321      const AccessorInfo& info) {
5322  return v8_num(42);
5323}
5324
5325
5326static v8::Handle<Value> AccessControlIndexedSetter(
5327    uint32_t, Local<Value> value, const AccessorInfo&) {
5328  return value;
5329}
5330
5331
5332THREADED_TEST(AccessControlInterceptorIC) {
5333  named_access_count = 0;
5334  indexed_access_count = 0;
5335
5336  v8::HandleScope handle_scope;
5337
5338  // Create an environment.
5339  v8::Persistent<Context> context0 = Context::New();
5340  context0->Enter();
5341
5342  // Create an object that requires access-check functions to be
5343  // called for cross-domain access.  The object also has interceptors
5344  // interceptor.
5345  v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
5346  object_template->SetAccessCheckCallbacks(NamedAccessCounter,
5347                                           IndexedAccessCounter);
5348  object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
5349                                           AccessControlNamedSetter);
5350  object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
5351                                             AccessControlIndexedSetter);
5352  Local<v8::Object> object = object_template->NewInstance();
5353
5354  v8::HandleScope scope1;
5355
5356  // Create another environment.
5357  v8::Persistent<Context> context1 = Context::New();
5358  context1->Enter();
5359
5360  // Make easy access to the object from the other environment.
5361  v8::Handle<v8::Object> global1 = context1->Global();
5362  global1->Set(v8_str("obj"), object);
5363
5364  v8::Handle<Value> value;
5365
5366  // Check that the named access-control function is called every time
5367  // eventhough there is an interceptor on the object.
5368  value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
5369  value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
5370                     "obj.x")->Run();
5371  CHECK(value->IsNumber());
5372  CHECK_EQ(42, value->Int32Value());
5373  CHECK_EQ(21, named_access_count);
5374
5375  value = v8_compile("var p = 'x';")->Run();
5376  value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
5377  value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
5378                     "obj[p]")->Run();
5379  CHECK(value->IsNumber());
5380  CHECK_EQ(42, value->Int32Value());
5381  CHECK_EQ(42, named_access_count);
5382
5383  // Check that the indexed access-control function is called every
5384  // time eventhough there is an interceptor on the object.
5385  value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
5386  value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
5387                     "obj[0]")->Run();
5388  CHECK(value->IsNumber());
5389  CHECK_EQ(42, value->Int32Value());
5390  CHECK_EQ(21, indexed_access_count);
5391
5392  context1->Exit();
5393  context0->Exit();
5394  context1.Dispose();
5395  context0.Dispose();
5396}
5397
5398
5399THREADED_TEST(Version) {
5400  v8::V8::GetVersion();
5401}
5402
5403
5404static v8::Handle<Value> InstanceFunctionCallback(const v8::Arguments& args) {
5405  ApiTestFuzzer::Fuzz();
5406  return v8_num(12);
5407}
5408
5409
5410THREADED_TEST(InstanceProperties) {
5411  v8::HandleScope handle_scope;
5412  LocalContext context;
5413
5414  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
5415  Local<ObjectTemplate> instance = t->InstanceTemplate();
5416
5417  instance->Set(v8_str("x"), v8_num(42));
5418  instance->Set(v8_str("f"),
5419                v8::FunctionTemplate::New(InstanceFunctionCallback));
5420
5421  Local<Value> o = t->GetFunction()->NewInstance();
5422
5423  context->Global()->Set(v8_str("i"), o);
5424  Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
5425  CHECK_EQ(42, value->Int32Value());
5426
5427  value = Script::Compile(v8_str("i.f()"))->Run();
5428  CHECK_EQ(12, value->Int32Value());
5429}
5430
5431
5432static v8::Handle<Value>
5433GlobalObjectInstancePropertiesGet(Local<String> key, const AccessorInfo&) {
5434  ApiTestFuzzer::Fuzz();
5435  return v8::Handle<Value>();
5436}
5437
5438
5439THREADED_TEST(GlobalObjectInstanceProperties) {
5440  v8::HandleScope handle_scope;
5441
5442  Local<Value> global_object;
5443
5444  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
5445  t->InstanceTemplate()->SetNamedPropertyHandler(
5446      GlobalObjectInstancePropertiesGet);
5447  Local<ObjectTemplate> instance_template = t->InstanceTemplate();
5448  instance_template->Set(v8_str("x"), v8_num(42));
5449  instance_template->Set(v8_str("f"),
5450                         v8::FunctionTemplate::New(InstanceFunctionCallback));
5451
5452  {
5453    LocalContext env(NULL, instance_template);
5454    // Hold on to the global object so it can be used again in another
5455    // environment initialization.
5456    global_object = env->Global();
5457
5458    Local<Value> value = Script::Compile(v8_str("x"))->Run();
5459    CHECK_EQ(42, value->Int32Value());
5460    value = Script::Compile(v8_str("f()"))->Run();
5461    CHECK_EQ(12, value->Int32Value());
5462  }
5463
5464  {
5465    // Create new environment reusing the global object.
5466    LocalContext env(NULL, instance_template, global_object);
5467    Local<Value> value = Script::Compile(v8_str("x"))->Run();
5468    CHECK_EQ(42, value->Int32Value());
5469    value = Script::Compile(v8_str("f()"))->Run();
5470    CHECK_EQ(12, value->Int32Value());
5471  }
5472}
5473
5474
5475static v8::Handle<Value> ShadowFunctionCallback(const v8::Arguments& args) {
5476  ApiTestFuzzer::Fuzz();
5477  return v8_num(42);
5478}
5479
5480
5481static int shadow_y;
5482static int shadow_y_setter_call_count;
5483static int shadow_y_getter_call_count;
5484
5485
5486static void ShadowYSetter(Local<String>, Local<Value>, const AccessorInfo&) {
5487  shadow_y_setter_call_count++;
5488  shadow_y = 42;
5489}
5490
5491
5492static v8::Handle<Value> ShadowYGetter(Local<String> name,
5493                                       const AccessorInfo& info) {
5494  ApiTestFuzzer::Fuzz();
5495  shadow_y_getter_call_count++;
5496  return v8_num(shadow_y);
5497}
5498
5499
5500static v8::Handle<Value> ShadowIndexedGet(uint32_t index,
5501                                          const AccessorInfo& info) {
5502  return v8::Handle<Value>();
5503}
5504
5505
5506static v8::Handle<Value> ShadowNamedGet(Local<String> key,
5507                                        const AccessorInfo&) {
5508  return v8::Handle<Value>();
5509}
5510
5511
5512THREADED_TEST(ShadowObject) {
5513  shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
5514  v8::HandleScope handle_scope;
5515
5516  Local<ObjectTemplate> global_template = v8::ObjectTemplate::New();
5517  LocalContext context(NULL, global_template);
5518
5519  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
5520  t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
5521  t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
5522  Local<ObjectTemplate> proto = t->PrototypeTemplate();
5523  Local<ObjectTemplate> instance = t->InstanceTemplate();
5524
5525  // Only allow calls of f on instances of t.
5526  Local<v8::Signature> signature = v8::Signature::New(t);
5527  proto->Set(v8_str("f"),
5528             v8::FunctionTemplate::New(ShadowFunctionCallback,
5529                                       Local<Value>(),
5530                                       signature));
5531  proto->Set(v8_str("x"), v8_num(12));
5532
5533  instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
5534
5535  Local<Value> o = t->GetFunction()->NewInstance();
5536  context->Global()->Set(v8_str("__proto__"), o);
5537
5538  Local<Value> value =
5539      Script::Compile(v8_str("propertyIsEnumerable(0)"))->Run();
5540  CHECK(value->IsBoolean());
5541  CHECK(!value->BooleanValue());
5542
5543  value = Script::Compile(v8_str("x"))->Run();
5544  CHECK_EQ(12, value->Int32Value());
5545
5546  value = Script::Compile(v8_str("f()"))->Run();
5547  CHECK_EQ(42, value->Int32Value());
5548
5549  Script::Compile(v8_str("y = 42"))->Run();
5550  CHECK_EQ(1, shadow_y_setter_call_count);
5551  value = Script::Compile(v8_str("y"))->Run();
5552  CHECK_EQ(1, shadow_y_getter_call_count);
5553  CHECK_EQ(42, value->Int32Value());
5554}
5555
5556
5557THREADED_TEST(HiddenPrototype) {
5558  v8::HandleScope handle_scope;
5559  LocalContext context;
5560
5561  Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
5562  t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
5563  Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
5564  t1->SetHiddenPrototype(true);
5565  t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
5566  Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
5567  t2->SetHiddenPrototype(true);
5568  t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
5569  Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
5570  t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
5571
5572  Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
5573  Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
5574  Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
5575  Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
5576
5577  // Setting the prototype on an object skips hidden prototypes.
5578  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5579  o0->Set(v8_str("__proto__"), o1);
5580  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5581  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
5582  o0->Set(v8_str("__proto__"), o2);
5583  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5584  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
5585  CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
5586  o0->Set(v8_str("__proto__"), o3);
5587  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5588  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
5589  CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
5590  CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
5591
5592  // Getting the prototype of o0 should get the first visible one
5593  // which is o3.  Therefore, z should not be defined on the prototype
5594  // object.
5595  Local<Value> proto = o0->Get(v8_str("__proto__"));
5596  CHECK(proto->IsObject());
5597  CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
5598}
5599
5600
5601THREADED_TEST(SetPrototype) {
5602  v8::HandleScope handle_scope;
5603  LocalContext context;
5604
5605  Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
5606  t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
5607  Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
5608  t1->SetHiddenPrototype(true);
5609  t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
5610  Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
5611  t2->SetHiddenPrototype(true);
5612  t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
5613  Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
5614  t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
5615
5616  Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
5617  Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
5618  Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
5619  Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
5620
5621  // Setting the prototype on an object does not skip hidden prototypes.
5622  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5623  CHECK(o0->SetPrototype(o1));
5624  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5625  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
5626  CHECK(o1->SetPrototype(o2));
5627  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5628  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
5629  CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
5630  CHECK(o2->SetPrototype(o3));
5631  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5632  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
5633  CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
5634  CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
5635
5636  // Getting the prototype of o0 should get the first visible one
5637  // which is o3.  Therefore, z should not be defined on the prototype
5638  // object.
5639  Local<Value> proto = o0->Get(v8_str("__proto__"));
5640  CHECK(proto->IsObject());
5641  CHECK_EQ(proto.As<v8::Object>(), o3);
5642
5643  // However, Object::GetPrototype ignores hidden prototype.
5644  Local<Value> proto0 = o0->GetPrototype();
5645  CHECK(proto0->IsObject());
5646  CHECK_EQ(proto0.As<v8::Object>(), o1);
5647
5648  Local<Value> proto1 = o1->GetPrototype();
5649  CHECK(proto1->IsObject());
5650  CHECK_EQ(proto1.As<v8::Object>(), o2);
5651
5652  Local<Value> proto2 = o2->GetPrototype();
5653  CHECK(proto2->IsObject());
5654  CHECK_EQ(proto2.As<v8::Object>(), o3);
5655}
5656
5657
5658THREADED_TEST(SetPrototypeThrows) {
5659  v8::HandleScope handle_scope;
5660  LocalContext context;
5661
5662  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
5663
5664  Local<v8::Object> o0 = t->GetFunction()->NewInstance();
5665  Local<v8::Object> o1 = t->GetFunction()->NewInstance();
5666
5667  CHECK(o0->SetPrototype(o1));
5668  // If setting the prototype leads to the cycle, SetPrototype should
5669  // return false and keep VM in sane state.
5670  v8::TryCatch try_catch;
5671  CHECK(!o1->SetPrototype(o0));
5672  CHECK(!try_catch.HasCaught());
5673  ASSERT(!i::Top::has_pending_exception());
5674
5675  CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
5676}
5677
5678
5679THREADED_TEST(GetterSetterExceptions) {
5680  v8::HandleScope handle_scope;
5681  LocalContext context;
5682  CompileRun(
5683    "function Foo() { };"
5684    "function Throw() { throw 5; };"
5685    "var x = { };"
5686    "x.__defineSetter__('set', Throw);"
5687    "x.__defineGetter__('get', Throw);");
5688  Local<v8::Object> x =
5689      Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
5690  v8::TryCatch try_catch;
5691  x->Set(v8_str("set"), v8::Integer::New(8));
5692  x->Get(v8_str("get"));
5693  x->Set(v8_str("set"), v8::Integer::New(8));
5694  x->Get(v8_str("get"));
5695  x->Set(v8_str("set"), v8::Integer::New(8));
5696  x->Get(v8_str("get"));
5697  x->Set(v8_str("set"), v8::Integer::New(8));
5698  x->Get(v8_str("get"));
5699}
5700
5701
5702THREADED_TEST(Constructor) {
5703  v8::HandleScope handle_scope;
5704  LocalContext context;
5705  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
5706  templ->SetClassName(v8_str("Fun"));
5707  Local<Function> cons = templ->GetFunction();
5708  context->Global()->Set(v8_str("Fun"), cons);
5709  Local<v8::Object> inst = cons->NewInstance();
5710  i::Handle<i::JSObject> obj = v8::Utils::OpenHandle(*inst);
5711  Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
5712  CHECK(value->BooleanValue());
5713}
5714
5715THREADED_TEST(FunctionDescriptorException) {
5716  v8::HandleScope handle_scope;
5717  LocalContext context;
5718  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
5719  templ->SetClassName(v8_str("Fun"));
5720  Local<Function> cons = templ->GetFunction();
5721  context->Global()->Set(v8_str("Fun"), cons);
5722  Local<Value> value = CompileRun(
5723    "function test() {"
5724    "  try {"
5725    "    (new Fun()).blah()"
5726    "  } catch (e) {"
5727    "    var str = String(e);"
5728    "    if (str.indexOf('TypeError') == -1) return 1;"
5729    "    if (str.indexOf('[object Fun]') != -1) return 2;"
5730    "    if (str.indexOf('#<a Fun>') == -1) return 3;"
5731    "    return 0;"
5732    "  }"
5733    "  return 4;"
5734    "}"
5735    "test();");
5736  CHECK_EQ(0, value->Int32Value());
5737}
5738
5739
5740THREADED_TEST(EvalAliasedDynamic) {
5741  v8::HandleScope scope;
5742  LocalContext current;
5743
5744  // Tests where aliased eval can only be resolved dynamically.
5745  Local<Script> script =
5746      Script::Compile(v8_str("function f(x) { "
5747                             "  var foo = 2;"
5748                             "  with (x) { return eval('foo'); }"
5749                             "}"
5750                             "foo = 0;"
5751                             "result1 = f(new Object());"
5752                             "result2 = f(this);"
5753                             "var x = new Object();"
5754                             "x.eval = function(x) { return 1; };"
5755                             "result3 = f(x);"));
5756  script->Run();
5757  CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
5758  CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
5759  CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
5760
5761  v8::TryCatch try_catch;
5762  script =
5763    Script::Compile(v8_str("function f(x) { "
5764                           "  var bar = 2;"
5765                           "  with (x) { return eval('bar'); }"
5766                           "}"
5767                           "f(this)"));
5768  script->Run();
5769  CHECK(try_catch.HasCaught());
5770  try_catch.Reset();
5771}
5772
5773
5774THREADED_TEST(CrossEval) {
5775  v8::HandleScope scope;
5776  LocalContext other;
5777  LocalContext current;
5778
5779  Local<String> token = v8_str("<security token>");
5780  other->SetSecurityToken(token);
5781  current->SetSecurityToken(token);
5782
5783  // Setup reference from current to other.
5784  current->Global()->Set(v8_str("other"), other->Global());
5785
5786  // Check that new variables are introduced in other context.
5787  Local<Script> script =
5788      Script::Compile(v8_str("other.eval('var foo = 1234')"));
5789  script->Run();
5790  Local<Value> foo = other->Global()->Get(v8_str("foo"));
5791  CHECK_EQ(1234, foo->Int32Value());
5792  CHECK(!current->Global()->Has(v8_str("foo")));
5793
5794  // Check that writing to non-existing properties introduces them in
5795  // the other context.
5796  script =
5797      Script::Compile(v8_str("other.eval('na = 1234')"));
5798  script->Run();
5799  CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
5800  CHECK(!current->Global()->Has(v8_str("na")));
5801
5802  // Check that global variables in current context are not visible in other
5803  // context.
5804  v8::TryCatch try_catch;
5805  script =
5806      Script::Compile(v8_str("var bar = 42; other.eval('bar');"));
5807  Local<Value> result = script->Run();
5808  CHECK(try_catch.HasCaught());
5809  try_catch.Reset();
5810
5811  // Check that local variables in current context are not visible in other
5812  // context.
5813  script =
5814      Script::Compile(v8_str("(function() { "
5815                             "  var baz = 87;"
5816                             "  return other.eval('baz');"
5817                             "})();"));
5818  result = script->Run();
5819  CHECK(try_catch.HasCaught());
5820  try_catch.Reset();
5821
5822  // Check that global variables in the other environment are visible
5823  // when evaluting code.
5824  other->Global()->Set(v8_str("bis"), v8_num(1234));
5825  script = Script::Compile(v8_str("other.eval('bis')"));
5826  CHECK_EQ(1234, script->Run()->Int32Value());
5827  CHECK(!try_catch.HasCaught());
5828
5829  // Check that the 'this' pointer points to the global object evaluating
5830  // code.
5831  other->Global()->Set(v8_str("t"), other->Global());
5832  script = Script::Compile(v8_str("other.eval('this == t')"));
5833  result = script->Run();
5834  CHECK(result->IsTrue());
5835  CHECK(!try_catch.HasCaught());
5836
5837  // Check that variables introduced in with-statement are not visible in
5838  // other context.
5839  script =
5840      Script::Compile(v8_str("with({x:2}){other.eval('x')}"));
5841  result = script->Run();
5842  CHECK(try_catch.HasCaught());
5843  try_catch.Reset();
5844
5845  // Check that you cannot use 'eval.call' with another object than the
5846  // current global object.
5847  script =
5848      Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')"));
5849  result = script->Run();
5850  CHECK(try_catch.HasCaught());
5851}
5852
5853
5854// Test that calling eval in a context which has been detached from
5855// its global throws an exception.  This behavior is consistent with
5856// other JavaScript implementations.
5857THREADED_TEST(EvalInDetachedGlobal) {
5858  v8::HandleScope scope;
5859
5860  v8::Persistent<Context> context0 = Context::New();
5861  v8::Persistent<Context> context1 = Context::New();
5862
5863  // Setup function in context0 that uses eval from context0.
5864  context0->Enter();
5865  v8::Handle<v8::Value> fun =
5866      CompileRun("var x = 42;"
5867                 "(function() {"
5868                 "  var e = eval;"
5869                 "  return function(s) { return e(s); }"
5870                 "})()");
5871  context0->Exit();
5872
5873  // Put the function into context1 and call it before and after
5874  // detaching the global.  Before detaching, the call succeeds and
5875  // after detaching and exception is thrown.
5876  context1->Enter();
5877  context1->Global()->Set(v8_str("fun"), fun);
5878  v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
5879  CHECK_EQ(42, x_value->Int32Value());
5880  context0->DetachGlobal();
5881  v8::TryCatch catcher;
5882  x_value = CompileRun("fun('x')");
5883  CHECK(x_value.IsEmpty());
5884  CHECK(catcher.HasCaught());
5885  context1->Exit();
5886
5887  context1.Dispose();
5888  context0.Dispose();
5889}
5890
5891
5892THREADED_TEST(CrossLazyLoad) {
5893  v8::HandleScope scope;
5894  LocalContext other;
5895  LocalContext current;
5896
5897  Local<String> token = v8_str("<security token>");
5898  other->SetSecurityToken(token);
5899  current->SetSecurityToken(token);
5900
5901  // Setup reference from current to other.
5902  current->Global()->Set(v8_str("other"), other->Global());
5903
5904  // Trigger lazy loading in other context.
5905  Local<Script> script =
5906      Script::Compile(v8_str("other.eval('new Date(42)')"));
5907  Local<Value> value = script->Run();
5908  CHECK_EQ(42.0, value->NumberValue());
5909}
5910
5911
5912static v8::Handle<Value> call_as_function(const v8::Arguments& args) {
5913  ApiTestFuzzer::Fuzz();
5914  if (args.IsConstructCall()) {
5915    if (args[0]->IsInt32()) {
5916       return v8_num(-args[0]->Int32Value());
5917    }
5918  }
5919
5920  return args[0];
5921}
5922
5923
5924// Test that a call handler can be set for objects which will allow
5925// non-function objects created through the API to be called as
5926// functions.
5927THREADED_TEST(CallAsFunction) {
5928  v8::HandleScope scope;
5929  LocalContext context;
5930
5931  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
5932  Local<ObjectTemplate> instance_template = t->InstanceTemplate();
5933  instance_template->SetCallAsFunctionHandler(call_as_function);
5934  Local<v8::Object> instance = t->GetFunction()->NewInstance();
5935  context->Global()->Set(v8_str("obj"), instance);
5936  v8::TryCatch try_catch;
5937  Local<Value> value;
5938  CHECK(!try_catch.HasCaught());
5939
5940  value = CompileRun("obj(42)");
5941  CHECK(!try_catch.HasCaught());
5942  CHECK_EQ(42, value->Int32Value());
5943
5944  value = CompileRun("(function(o){return o(49)})(obj)");
5945  CHECK(!try_catch.HasCaught());
5946  CHECK_EQ(49, value->Int32Value());
5947
5948  // test special case of call as function
5949  value = CompileRun("[obj]['0'](45)");
5950  CHECK(!try_catch.HasCaught());
5951  CHECK_EQ(45, value->Int32Value());
5952
5953  value = CompileRun("obj.call = Function.prototype.call;"
5954                     "obj.call(null, 87)");
5955  CHECK(!try_catch.HasCaught());
5956  CHECK_EQ(87, value->Int32Value());
5957
5958  // Regression tests for bug #1116356: Calling call through call/apply
5959  // must work for non-function receivers.
5960  const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
5961  value = CompileRun(apply_99);
5962  CHECK(!try_catch.HasCaught());
5963  CHECK_EQ(99, value->Int32Value());
5964
5965  const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
5966  value = CompileRun(call_17);
5967  CHECK(!try_catch.HasCaught());
5968  CHECK_EQ(17, value->Int32Value());
5969
5970  // Check that the call-as-function handler can be called through
5971  // new.
5972  value = CompileRun("new obj(43)");
5973  CHECK(!try_catch.HasCaught());
5974  CHECK_EQ(-43, value->Int32Value());
5975}
5976
5977
5978static int CountHandles() {
5979  return v8::HandleScope::NumberOfHandles();
5980}
5981
5982
5983static int Recurse(int depth, int iterations) {
5984  v8::HandleScope scope;
5985  if (depth == 0) return CountHandles();
5986  for (int i = 0; i < iterations; i++) {
5987    Local<v8::Number> n = v8::Integer::New(42);
5988  }
5989  return Recurse(depth - 1, iterations);
5990}
5991
5992
5993THREADED_TEST(HandleIteration) {
5994  static const int kIterations = 500;
5995  static const int kNesting = 200;
5996  CHECK_EQ(0, CountHandles());
5997  {
5998    v8::HandleScope scope1;
5999    CHECK_EQ(0, CountHandles());
6000    for (int i = 0; i < kIterations; i++) {
6001      Local<v8::Number> n = v8::Integer::New(42);
6002      CHECK_EQ(i + 1, CountHandles());
6003    }
6004
6005    CHECK_EQ(kIterations, CountHandles());
6006    {
6007      v8::HandleScope scope2;
6008      for (int j = 0; j < kIterations; j++) {
6009        Local<v8::Number> n = v8::Integer::New(42);
6010        CHECK_EQ(j + 1 + kIterations, CountHandles());
6011      }
6012    }
6013    CHECK_EQ(kIterations, CountHandles());
6014  }
6015  CHECK_EQ(0, CountHandles());
6016  CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations));
6017}
6018
6019
6020static v8::Handle<Value> InterceptorHasOwnPropertyGetter(
6021    Local<String> name,
6022    const AccessorInfo& info) {
6023  ApiTestFuzzer::Fuzz();
6024  return v8::Handle<Value>();
6025}
6026
6027
6028THREADED_TEST(InterceptorHasOwnProperty) {
6029  v8::HandleScope scope;
6030  LocalContext context;
6031  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6032  Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
6033  instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
6034  Local<Function> function = fun_templ->GetFunction();
6035  context->Global()->Set(v8_str("constructor"), function);
6036  v8::Handle<Value> value = CompileRun(
6037      "var o = new constructor();"
6038      "o.hasOwnProperty('ostehaps');");
6039  CHECK_EQ(false, value->BooleanValue());
6040  value = CompileRun(
6041      "o.ostehaps = 42;"
6042      "o.hasOwnProperty('ostehaps');");
6043  CHECK_EQ(true, value->BooleanValue());
6044  value = CompileRun(
6045      "var p = new constructor();"
6046      "p.hasOwnProperty('ostehaps');");
6047  CHECK_EQ(false, value->BooleanValue());
6048}
6049
6050
6051static v8::Handle<Value> InterceptorHasOwnPropertyGetterGC(
6052    Local<String> name,
6053    const AccessorInfo& info) {
6054  ApiTestFuzzer::Fuzz();
6055  i::Heap::CollectAllGarbage(false);
6056  return v8::Handle<Value>();
6057}
6058
6059
6060THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
6061  v8::HandleScope scope;
6062  LocalContext context;
6063  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6064  Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
6065  instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
6066  Local<Function> function = fun_templ->GetFunction();
6067  context->Global()->Set(v8_str("constructor"), function);
6068  // Let's first make some stuff so we can be sure to get a good GC.
6069  CompileRun(
6070      "function makestr(size) {"
6071      "  switch (size) {"
6072      "    case 1: return 'f';"
6073      "    case 2: return 'fo';"
6074      "    case 3: return 'foo';"
6075      "  }"
6076      "  return makestr(size >> 1) + makestr((size + 1) >> 1);"
6077      "}"
6078      "var x = makestr(12345);"
6079      "x = makestr(31415);"
6080      "x = makestr(23456);");
6081  v8::Handle<Value> value = CompileRun(
6082      "var o = new constructor();"
6083      "o.__proto__ = new String(x);"
6084      "o.hasOwnProperty('ostehaps');");
6085  CHECK_EQ(false, value->BooleanValue());
6086}
6087
6088
6089typedef v8::Handle<Value> (*NamedPropertyGetter)(Local<String> property,
6090                                                 const AccessorInfo& info);
6091
6092
6093static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
6094                                   const char* source,
6095                                   int expected) {
6096  v8::HandleScope scope;
6097  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6098  templ->SetNamedPropertyHandler(getter);
6099  LocalContext context;
6100  context->Global()->Set(v8_str("o"), templ->NewInstance());
6101  v8::Handle<Value> value = CompileRun(source);
6102  CHECK_EQ(expected, value->Int32Value());
6103}
6104
6105
6106static v8::Handle<Value> InterceptorLoadICGetter(Local<String> name,
6107                                                 const AccessorInfo& info) {
6108  ApiTestFuzzer::Fuzz();
6109  CHECK(v8_str("x")->Equals(name));
6110  return v8::Integer::New(42);
6111}
6112
6113
6114// This test should hit the load IC for the interceptor case.
6115THREADED_TEST(InterceptorLoadIC) {
6116  CheckInterceptorLoadIC(InterceptorLoadICGetter,
6117    "var result = 0;"
6118    "for (var i = 0; i < 1000; i++) {"
6119    "  result = o.x;"
6120    "}",
6121    42);
6122}
6123
6124
6125// Below go several tests which verify that JITing for various
6126// configurations of interceptor and explicit fields works fine
6127// (those cases are special cased to get better performance).
6128
6129static v8::Handle<Value> InterceptorLoadXICGetter(Local<String> name,
6130                                                 const AccessorInfo& info) {
6131  ApiTestFuzzer::Fuzz();
6132  return v8_str("x")->Equals(name)
6133      ? v8::Integer::New(42) : v8::Handle<v8::Value>();
6134}
6135
6136
6137THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
6138  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6139    "var result = 0;"
6140    "o.y = 239;"
6141    "for (var i = 0; i < 1000; i++) {"
6142    "  result = o.y;"
6143    "}",
6144    239);
6145}
6146
6147
6148THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
6149  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6150    "var result = 0;"
6151    "o.__proto__ = { 'y': 239 };"
6152    "for (var i = 0; i < 1000; i++) {"
6153    "  result = o.y + o.x;"
6154    "}",
6155    239 + 42);
6156}
6157
6158
6159THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
6160  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6161    "var result = 0;"
6162    "o.__proto__.y = 239;"
6163    "for (var i = 0; i < 1000; i++) {"
6164    "  result = o.y + o.x;"
6165    "}",
6166    239 + 42);
6167}
6168
6169
6170THREADED_TEST(InterceptorLoadICUndefined) {
6171  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6172    "var result = 0;"
6173    "for (var i = 0; i < 1000; i++) {"
6174    "  result = (o.y == undefined) ? 239 : 42;"
6175    "}",
6176    239);
6177}
6178
6179
6180THREADED_TEST(InterceptorLoadICWithOverride) {
6181  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6182    "fst = new Object();  fst.__proto__ = o;"
6183    "snd = new Object();  snd.__proto__ = fst;"
6184    "var result1 = 0;"
6185    "for (var i = 0; i < 1000;  i++) {"
6186    "  result1 = snd.x;"
6187    "}"
6188    "fst.x = 239;"
6189    "var result = 0;"
6190    "for (var i = 0; i < 1000; i++) {"
6191    "  result = snd.x;"
6192    "}"
6193    "result + result1",
6194    239 + 42);
6195}
6196
6197
6198// Test the case when we stored field into
6199// a stub, but interceptor produced value on its own.
6200THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
6201  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6202    "proto = new Object();"
6203    "o.__proto__ = proto;"
6204    "proto.x = 239;"
6205    "for (var i = 0; i < 1000; i++) {"
6206    "  o.x;"
6207    // Now it should be ICed and keep a reference to x defined on proto
6208    "}"
6209    "var result = 0;"
6210    "for (var i = 0; i < 1000; i++) {"
6211    "  result += o.x;"
6212    "}"
6213    "result;",
6214    42 * 1000);
6215}
6216
6217
6218// Test the case when we stored field into
6219// a stub, but it got invalidated later on.
6220THREADED_TEST(InterceptorLoadICInvalidatedField) {
6221  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6222    "proto1 = new Object();"
6223    "proto2 = new Object();"
6224    "o.__proto__ = proto1;"
6225    "proto1.__proto__ = proto2;"
6226    "proto2.y = 239;"
6227    "for (var i = 0; i < 1000; i++) {"
6228    "  o.y;"
6229    // Now it should be ICed and keep a reference to y defined on proto2
6230    "}"
6231    "proto1.y = 42;"
6232    "var result = 0;"
6233    "for (var i = 0; i < 1000; i++) {"
6234    "  result += o.y;"
6235    "}"
6236    "result;",
6237    42 * 1000);
6238}
6239
6240
6241static int interceptor_load_not_handled_calls = 0;
6242static v8::Handle<Value> InterceptorLoadNotHandled(Local<String> name,
6243                                                   const AccessorInfo& info) {
6244  ++interceptor_load_not_handled_calls;
6245  return v8::Handle<v8::Value>();
6246}
6247
6248
6249// Test how post-interceptor lookups are done in the non-cacheable
6250// case: the interceptor should not be invoked during this lookup.
6251THREADED_TEST(InterceptorLoadICPostInterceptor) {
6252  interceptor_load_not_handled_calls = 0;
6253  CheckInterceptorLoadIC(InterceptorLoadNotHandled,
6254    "receiver = new Object();"
6255    "receiver.__proto__ = o;"
6256    "proto = new Object();"
6257    "/* Make proto a slow-case object. */"
6258    "for (var i = 0; i < 1000; i++) {"
6259    "  proto[\"xxxxxxxx\" + i] = [];"
6260    "}"
6261    "proto.x = 17;"
6262    "o.__proto__ = proto;"
6263    "var result = 0;"
6264    "for (var i = 0; i < 1000; i++) {"
6265    "  result += receiver.x;"
6266    "}"
6267    "result;",
6268    17 * 1000);
6269  CHECK_EQ(1000, interceptor_load_not_handled_calls);
6270}
6271
6272
6273// Test the case when we stored field into
6274// a stub, but it got invalidated later on due to override on
6275// global object which is between interceptor and fields' holders.
6276THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
6277  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6278    "o.__proto__ = this;"  // set a global to be a proto of o.
6279    "this.__proto__.y = 239;"
6280    "for (var i = 0; i < 10; i++) {"
6281    "  if (o.y != 239) throw 'oops: ' + o.y;"
6282    // Now it should be ICed and keep a reference to y defined on field_holder.
6283    "}"
6284    "this.y = 42;"  // Assign on a global.
6285    "var result = 0;"
6286    "for (var i = 0; i < 10; i++) {"
6287    "  result += o.y;"
6288    "}"
6289    "result;",
6290    42 * 10);
6291}
6292
6293
6294static v8::Handle<Value> Return239(Local<String> name, const AccessorInfo&) {
6295  ApiTestFuzzer::Fuzz();
6296  return v8_num(239);
6297}
6298
6299
6300static void SetOnThis(Local<String> name,
6301                      Local<Value> value,
6302                      const AccessorInfo& info) {
6303  info.This()->ForceSet(name, value);
6304}
6305
6306
6307THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
6308  v8::HandleScope scope;
6309  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6310  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6311  templ->SetAccessor(v8_str("y"), Return239);
6312  LocalContext context;
6313  context->Global()->Set(v8_str("o"), templ->NewInstance());
6314
6315  // Check the case when receiver and interceptor's holder
6316  // are the same objects.
6317  v8::Handle<Value> value = CompileRun(
6318      "var result = 0;"
6319      "for (var i = 0; i < 7; i++) {"
6320      "  result = o.y;"
6321      "}");
6322  CHECK_EQ(239, value->Int32Value());
6323
6324  // Check the case when interceptor's holder is in proto chain
6325  // of receiver.
6326  value = CompileRun(
6327      "r = { __proto__: o };"
6328      "var result = 0;"
6329      "for (var i = 0; i < 7; i++) {"
6330      "  result = r.y;"
6331      "}");
6332  CHECK_EQ(239, value->Int32Value());
6333}
6334
6335
6336THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
6337  v8::HandleScope scope;
6338  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6339  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6340  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
6341  templ_p->SetAccessor(v8_str("y"), Return239);
6342
6343  LocalContext context;
6344  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6345  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
6346
6347  // Check the case when receiver and interceptor's holder
6348  // are the same objects.
6349  v8::Handle<Value> value = CompileRun(
6350      "o.__proto__ = p;"
6351      "var result = 0;"
6352      "for (var i = 0; i < 7; i++) {"
6353      "  result = o.x + o.y;"
6354      "}");
6355  CHECK_EQ(239 + 42, value->Int32Value());
6356
6357  // Check the case when interceptor's holder is in proto chain
6358  // of receiver.
6359  value = CompileRun(
6360      "r = { __proto__: o };"
6361      "var result = 0;"
6362      "for (var i = 0; i < 7; i++) {"
6363      "  result = r.x + r.y;"
6364      "}");
6365  CHECK_EQ(239 + 42, value->Int32Value());
6366}
6367
6368
6369THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
6370  v8::HandleScope scope;
6371  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6372  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6373  templ->SetAccessor(v8_str("y"), Return239);
6374
6375  LocalContext context;
6376  context->Global()->Set(v8_str("o"), templ->NewInstance());
6377
6378  v8::Handle<Value> value = CompileRun(
6379    "fst = new Object();  fst.__proto__ = o;"
6380    "snd = new Object();  snd.__proto__ = fst;"
6381    "var result1 = 0;"
6382    "for (var i = 0; i < 7;  i++) {"
6383    "  result1 = snd.x;"
6384    "}"
6385    "fst.x = 239;"
6386    "var result = 0;"
6387    "for (var i = 0; i < 7; i++) {"
6388    "  result = snd.x;"
6389    "}"
6390    "result + result1");
6391  CHECK_EQ(239 + 42, value->Int32Value());
6392}
6393
6394
6395// Test the case when we stored callback into
6396// a stub, but interceptor produced value on its own.
6397THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
6398  v8::HandleScope scope;
6399  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6400  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6401  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
6402  templ_p->SetAccessor(v8_str("y"), Return239);
6403
6404  LocalContext context;
6405  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6406  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
6407
6408  v8::Handle<Value> value = CompileRun(
6409    "o.__proto__ = p;"
6410    "for (var i = 0; i < 7; i++) {"
6411    "  o.x;"
6412    // Now it should be ICed and keep a reference to x defined on p
6413    "}"
6414    "var result = 0;"
6415    "for (var i = 0; i < 7; i++) {"
6416    "  result += o.x;"
6417    "}"
6418    "result");
6419  CHECK_EQ(42 * 7, value->Int32Value());
6420}
6421
6422
6423// Test the case when we stored callback into
6424// a stub, but it got invalidated later on.
6425THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
6426  v8::HandleScope scope;
6427  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6428  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6429  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
6430  templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
6431
6432  LocalContext context;
6433  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6434  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
6435
6436  v8::Handle<Value> value = CompileRun(
6437    "inbetween = new Object();"
6438    "o.__proto__ = inbetween;"
6439    "inbetween.__proto__ = p;"
6440    "for (var i = 0; i < 10; i++) {"
6441    "  o.y;"
6442    // Now it should be ICed and keep a reference to y defined on p
6443    "}"
6444    "inbetween.y = 42;"
6445    "var result = 0;"
6446    "for (var i = 0; i < 10; i++) {"
6447    "  result += o.y;"
6448    "}"
6449    "result");
6450  CHECK_EQ(42 * 10, value->Int32Value());
6451}
6452
6453
6454// Test the case when we stored callback into
6455// a stub, but it got invalidated later on due to override on
6456// global object which is between interceptor and callbacks' holders.
6457THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
6458  v8::HandleScope scope;
6459  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6460  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6461  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
6462  templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
6463
6464  LocalContext context;
6465  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6466  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
6467
6468  v8::Handle<Value> value = CompileRun(
6469    "o.__proto__ = this;"
6470    "this.__proto__ = p;"
6471    "for (var i = 0; i < 10; i++) {"
6472    "  if (o.y != 239) throw 'oops: ' + o.y;"
6473    // Now it should be ICed and keep a reference to y defined on p
6474    "}"
6475    "this.y = 42;"
6476    "var result = 0;"
6477    "for (var i = 0; i < 10; i++) {"
6478    "  result += o.y;"
6479    "}"
6480    "result");
6481  CHECK_EQ(42 * 10, value->Int32Value());
6482}
6483
6484
6485static v8::Handle<Value> InterceptorLoadICGetter0(Local<String> name,
6486                                                  const AccessorInfo& info) {
6487  ApiTestFuzzer::Fuzz();
6488  CHECK(v8_str("x")->Equals(name));
6489  return v8::Integer::New(0);
6490}
6491
6492
6493THREADED_TEST(InterceptorReturningZero) {
6494  CheckInterceptorLoadIC(InterceptorLoadICGetter0,
6495     "o.x == undefined ? 1 : 0",
6496     0);
6497}
6498
6499
6500static v8::Handle<Value> InterceptorStoreICSetter(
6501    Local<String> key, Local<Value> value, const AccessorInfo&) {
6502  CHECK(v8_str("x")->Equals(key));
6503  CHECK_EQ(42, value->Int32Value());
6504  return value;
6505}
6506
6507
6508// This test should hit the store IC for the interceptor case.
6509THREADED_TEST(InterceptorStoreIC) {
6510  v8::HandleScope scope;
6511  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6512  templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
6513                                 InterceptorStoreICSetter);
6514  LocalContext context;
6515  context->Global()->Set(v8_str("o"), templ->NewInstance());
6516  v8::Handle<Value> value = CompileRun(
6517    "for (var i = 0; i < 1000; i++) {"
6518    "  o.x = 42;"
6519    "}");
6520}
6521
6522
6523THREADED_TEST(InterceptorStoreICWithNoSetter) {
6524  v8::HandleScope scope;
6525  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6526  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6527  LocalContext context;
6528  context->Global()->Set(v8_str("o"), templ->NewInstance());
6529  v8::Handle<Value> value = CompileRun(
6530    "for (var i = 0; i < 1000; i++) {"
6531    "  o.y = 239;"
6532    "}"
6533    "42 + o.y");
6534  CHECK_EQ(239 + 42, value->Int32Value());
6535}
6536
6537
6538
6539
6540v8::Handle<Value> call_ic_function;
6541v8::Handle<Value> call_ic_function2;
6542v8::Handle<Value> call_ic_function3;
6543
6544static v8::Handle<Value> InterceptorCallICGetter(Local<String> name,
6545                                                 const AccessorInfo& info) {
6546  ApiTestFuzzer::Fuzz();
6547  CHECK(v8_str("x")->Equals(name));
6548  return call_ic_function;
6549}
6550
6551
6552// This test should hit the call IC for the interceptor case.
6553THREADED_TEST(InterceptorCallIC) {
6554  v8::HandleScope scope;
6555  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6556  templ->SetNamedPropertyHandler(InterceptorCallICGetter);
6557  LocalContext context;
6558  context->Global()->Set(v8_str("o"), templ->NewInstance());
6559  call_ic_function =
6560      v8_compile("function f(x) { return x + 1; }; f")->Run();
6561  v8::Handle<Value> value = CompileRun(
6562    "var result = 0;"
6563    "for (var i = 0; i < 1000; i++) {"
6564    "  result = o.x(41);"
6565    "}");
6566  CHECK_EQ(42, value->Int32Value());
6567}
6568
6569
6570// This test checks that if interceptor doesn't provide
6571// a value, we can fetch regular value.
6572THREADED_TEST(InterceptorCallICSeesOthers) {
6573  v8::HandleScope scope;
6574  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6575  templ->SetNamedPropertyHandler(NoBlockGetterX);
6576  LocalContext context;
6577  context->Global()->Set(v8_str("o"), templ->NewInstance());
6578  v8::Handle<Value> value = CompileRun(
6579    "o.x = function f(x) { return x + 1; };"
6580    "var result = 0;"
6581    "for (var i = 0; i < 7; i++) {"
6582    "  result = o.x(41);"
6583    "}");
6584  CHECK_EQ(42, value->Int32Value());
6585}
6586
6587
6588static v8::Handle<Value> call_ic_function4;
6589static v8::Handle<Value> InterceptorCallICGetter4(Local<String> name,
6590                                                  const AccessorInfo& info) {
6591  ApiTestFuzzer::Fuzz();
6592  CHECK(v8_str("x")->Equals(name));
6593  return call_ic_function4;
6594}
6595
6596
6597// This test checks that if interceptor provides a function,
6598// even if we cached shadowed variant, interceptor's function
6599// is invoked
6600THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
6601  v8::HandleScope scope;
6602  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6603  templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
6604  LocalContext context;
6605  context->Global()->Set(v8_str("o"), templ->NewInstance());
6606  call_ic_function4 =
6607      v8_compile("function f(x) { return x - 1; }; f")->Run();
6608  v8::Handle<Value> value = CompileRun(
6609    "o.__proto__.x = function(x) { return x + 1; };"
6610    "var result = 0;"
6611    "for (var i = 0; i < 1000; i++) {"
6612    "  result = o.x(42);"
6613    "}");
6614  CHECK_EQ(41, value->Int32Value());
6615}
6616
6617
6618// Test the case when we stored cacheable lookup into
6619// a stub, but it got invalidated later on
6620THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
6621  v8::HandleScope scope;
6622  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6623  templ->SetNamedPropertyHandler(NoBlockGetterX);
6624  LocalContext context;
6625  context->Global()->Set(v8_str("o"), templ->NewInstance());
6626  v8::Handle<Value> value = CompileRun(
6627    "proto1 = new Object();"
6628    "proto2 = new Object();"
6629    "o.__proto__ = proto1;"
6630    "proto1.__proto__ = proto2;"
6631    "proto2.y = function(x) { return x + 1; };"
6632    // Invoke it many times to compile a stub
6633    "for (var i = 0; i < 7; i++) {"
6634    "  o.y(42);"
6635    "}"
6636    "proto1.y = function(x) { return x - 1; };"
6637    "var result = 0;"
6638    "for (var i = 0; i < 7; i++) {"
6639    "  result += o.y(42);"
6640    "}");
6641  CHECK_EQ(41 * 7, value->Int32Value());
6642}
6643
6644
6645static v8::Handle<Value> call_ic_function5;
6646static v8::Handle<Value> InterceptorCallICGetter5(Local<String> name,
6647                                                  const AccessorInfo& info) {
6648  ApiTestFuzzer::Fuzz();
6649  if (v8_str("x")->Equals(name))
6650    return call_ic_function5;
6651  else
6652    return Local<Value>();
6653}
6654
6655
6656// This test checks that if interceptor doesn't provide a function,
6657// cached constant function is used
6658THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
6659  v8::HandleScope scope;
6660  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6661  templ->SetNamedPropertyHandler(NoBlockGetterX);
6662  LocalContext context;
6663  context->Global()->Set(v8_str("o"), templ->NewInstance());
6664  v8::Handle<Value> value = CompileRun(
6665    "function inc(x) { return x + 1; };"
6666    "inc(1);"
6667    "o.x = inc;"
6668    "var result = 0;"
6669    "for (var i = 0; i < 1000; i++) {"
6670    "  result = o.x(42);"
6671    "}");
6672  CHECK_EQ(43, value->Int32Value());
6673}
6674
6675
6676// This test checks that if interceptor provides a function,
6677// even if we cached constant function, interceptor's function
6678// is invoked
6679THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
6680  v8::HandleScope scope;
6681  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6682  templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
6683  LocalContext context;
6684  context->Global()->Set(v8_str("o"), templ->NewInstance());
6685  call_ic_function5 =
6686      v8_compile("function f(x) { return x - 1; }; f")->Run();
6687  v8::Handle<Value> value = CompileRun(
6688    "function inc(x) { return x + 1; };"
6689    "inc(1);"
6690    "o.x = inc;"
6691    "var result = 0;"
6692    "for (var i = 0; i < 1000; i++) {"
6693    "  result = o.x(42);"
6694    "}");
6695  CHECK_EQ(41, value->Int32Value());
6696}
6697
6698
6699// Test the case when we stored constant function into
6700// a stub, but it got invalidated later on
6701THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
6702  v8::HandleScope scope;
6703  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6704  templ->SetNamedPropertyHandler(NoBlockGetterX);
6705  LocalContext context;
6706  context->Global()->Set(v8_str("o"), templ->NewInstance());
6707  v8::Handle<Value> value = CompileRun(
6708    "function inc(x) { return x + 1; };"
6709    "inc(1);"
6710    "proto1 = new Object();"
6711    "proto2 = new Object();"
6712    "o.__proto__ = proto1;"
6713    "proto1.__proto__ = proto2;"
6714    "proto2.y = inc;"
6715    // Invoke it many times to compile a stub
6716    "for (var i = 0; i < 7; i++) {"
6717    "  o.y(42);"
6718    "}"
6719    "proto1.y = function(x) { return x - 1; };"
6720    "var result = 0;"
6721    "for (var i = 0; i < 7; i++) {"
6722    "  result += o.y(42);"
6723    "}");
6724  CHECK_EQ(41 * 7, value->Int32Value());
6725}
6726
6727
6728// Test the case when we stored constant function into
6729// a stub, but it got invalidated later on due to override on
6730// global object which is between interceptor and constant function' holders.
6731THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
6732  v8::HandleScope scope;
6733  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6734  templ->SetNamedPropertyHandler(NoBlockGetterX);
6735  LocalContext context;
6736  context->Global()->Set(v8_str("o"), templ->NewInstance());
6737  v8::Handle<Value> value = CompileRun(
6738    "function inc(x) { return x + 1; };"
6739    "inc(1);"
6740    "o.__proto__ = this;"
6741    "this.__proto__.y = inc;"
6742    // Invoke it many times to compile a stub
6743    "for (var i = 0; i < 7; i++) {"
6744    "  if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
6745    "}"
6746    "this.y = function(x) { return x - 1; };"
6747    "var result = 0;"
6748    "for (var i = 0; i < 7; i++) {"
6749    "  result += o.y(42);"
6750    "}");
6751  CHECK_EQ(41 * 7, value->Int32Value());
6752}
6753
6754
6755// Test the case when actual function to call sits on global object.
6756THREADED_TEST(InterceptorCallICCachedFromGlobal) {
6757  v8::HandleScope scope;
6758  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6759  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
6760
6761  LocalContext context;
6762  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6763
6764  v8::Handle<Value> value = CompileRun(
6765    "try {"
6766    "  o.__proto__ = this;"
6767    "  for (var i = 0; i < 10; i++) {"
6768    "    var v = o.parseFloat('239');"
6769    "    if (v != 239) throw v;"
6770      // Now it should be ICed and keep a reference to parseFloat.
6771    "  }"
6772    "  var result = 0;"
6773    "  for (var i = 0; i < 10; i++) {"
6774    "    result += o.parseFloat('239');"
6775    "  }"
6776    "  result"
6777    "} catch(e) {"
6778    "  e"
6779    "};");
6780  CHECK_EQ(239 * 10, value->Int32Value());
6781}
6782
6783static v8::Handle<Value> InterceptorCallICFastApi(Local<String> name,
6784                                                  const AccessorInfo& info) {
6785  ApiTestFuzzer::Fuzz();
6786  int* call_count = reinterpret_cast<int*>(v8::External::Unwrap(info.Data()));
6787  ++(*call_count);
6788  if ((*call_count) % 20 == 0) {
6789    v8::internal::Heap::CollectAllGarbage(true);
6790  }
6791  return v8::Handle<Value>();
6792}
6793
6794static v8::Handle<Value> FastApiCallback_TrivialSignature(
6795    const v8::Arguments& args) {
6796  ApiTestFuzzer::Fuzz();
6797  CHECK_EQ(args.This(), args.Holder());
6798  CHECK(args.Data()->Equals(v8_str("method_data")));
6799  return v8::Integer::New(args[0]->Int32Value() + 1);
6800}
6801
6802static v8::Handle<Value> FastApiCallback_SimpleSignature(
6803    const v8::Arguments& args) {
6804  ApiTestFuzzer::Fuzz();
6805  CHECK_EQ(args.This()->GetPrototype(), args.Holder());
6806  CHECK(args.Data()->Equals(v8_str("method_data")));
6807  // Note, we're using HasRealNamedProperty instead of Has to avoid
6808  // invoking the interceptor again.
6809  CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
6810  return v8::Integer::New(args[0]->Int32Value() + 1);
6811}
6812
6813// Helper to maximize the odds of object moving.
6814static void GenerateSomeGarbage() {
6815  CompileRun(
6816      "var garbage;"
6817      "for (var i = 0; i < 1000; i++) {"
6818      "  garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
6819      "}"
6820      "garbage = undefined;");
6821}
6822
6823THREADED_TEST(InterceptorCallICFastApi_TrivialSignature) {
6824  int interceptor_call_count = 0;
6825  v8::HandleScope scope;
6826  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6827  v8::Handle<v8::FunctionTemplate> method_templ =
6828      v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
6829                                v8_str("method_data"),
6830                                v8::Handle<v8::Signature>());
6831  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
6832  proto_templ->Set(v8_str("method"), method_templ);
6833  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
6834  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
6835                                 NULL, NULL, NULL, NULL,
6836                                 v8::External::Wrap(&interceptor_call_count));
6837  LocalContext context;
6838  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
6839  GenerateSomeGarbage();
6840  context->Global()->Set(v8_str("o"), fun->NewInstance());
6841  v8::Handle<Value> value = CompileRun(
6842      "var result = 0;"
6843      "for (var i = 0; i < 100; i++) {"
6844      "  result = o.method(41);"
6845      "}");
6846  CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
6847  CHECK_EQ(100, interceptor_call_count);
6848}
6849
6850THREADED_TEST(InterceptorCallICFastApi_SimpleSignature) {
6851  int interceptor_call_count = 0;
6852  v8::HandleScope scope;
6853  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6854  v8::Handle<v8::FunctionTemplate> method_templ =
6855      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
6856                                v8_str("method_data"),
6857                                v8::Signature::New(fun_templ));
6858  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
6859  proto_templ->Set(v8_str("method"), method_templ);
6860  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
6861  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
6862                                 NULL, NULL, NULL, NULL,
6863                                 v8::External::Wrap(&interceptor_call_count));
6864  LocalContext context;
6865  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
6866  GenerateSomeGarbage();
6867  context->Global()->Set(v8_str("o"), fun->NewInstance());
6868  v8::Handle<Value> value = CompileRun(
6869      "o.foo = 17;"
6870      "var receiver = {};"
6871      "receiver.__proto__ = o;"
6872      "var result = 0;"
6873      "for (var i = 0; i < 100; i++) {"
6874      "  result = receiver.method(41);"
6875      "}");
6876  CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
6877  CHECK_EQ(100, interceptor_call_count);
6878}
6879
6880THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
6881  int interceptor_call_count = 0;
6882  v8::HandleScope scope;
6883  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6884  v8::Handle<v8::FunctionTemplate> method_templ =
6885      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
6886                                v8_str("method_data"),
6887                                v8::Signature::New(fun_templ));
6888  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
6889  proto_templ->Set(v8_str("method"), method_templ);
6890  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
6891  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
6892                                 NULL, NULL, NULL, NULL,
6893                                 v8::External::Wrap(&interceptor_call_count));
6894  LocalContext context;
6895  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
6896  GenerateSomeGarbage();
6897  context->Global()->Set(v8_str("o"), fun->NewInstance());
6898  v8::Handle<Value> value = CompileRun(
6899      "o.foo = 17;"
6900      "var receiver = {};"
6901      "receiver.__proto__ = o;"
6902      "var result = 0;"
6903      "var saved_result = 0;"
6904      "for (var i = 0; i < 100; i++) {"
6905      "  result = receiver.method(41);"
6906      "  if (i == 50) {"
6907      "    saved_result = result;"
6908      "    receiver = {method: function(x) { return x - 1 }};"
6909      "  }"
6910      "}");
6911  CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
6912  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
6913  CHECK_GE(interceptor_call_count, 50);
6914}
6915
6916THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
6917  int interceptor_call_count = 0;
6918  v8::HandleScope scope;
6919  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6920  v8::Handle<v8::FunctionTemplate> method_templ =
6921      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
6922                                v8_str("method_data"),
6923                                v8::Signature::New(fun_templ));
6924  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
6925  proto_templ->Set(v8_str("method"), method_templ);
6926  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
6927  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
6928                                 NULL, NULL, NULL, NULL,
6929                                 v8::External::Wrap(&interceptor_call_count));
6930  LocalContext context;
6931  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
6932  GenerateSomeGarbage();
6933  context->Global()->Set(v8_str("o"), fun->NewInstance());
6934  v8::Handle<Value> value = CompileRun(
6935      "o.foo = 17;"
6936      "var receiver = {};"
6937      "receiver.__proto__ = o;"
6938      "var result = 0;"
6939      "var saved_result = 0;"
6940      "for (var i = 0; i < 100; i++) {"
6941      "  result = receiver.method(41);"
6942      "  if (i == 50) {"
6943      "    saved_result = result;"
6944      "    o.method = function(x) { return x - 1 };"
6945      "  }"
6946      "}");
6947  CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
6948  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
6949  CHECK_GE(interceptor_call_count, 50);
6950}
6951
6952THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
6953  int interceptor_call_count = 0;
6954  v8::HandleScope scope;
6955  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6956  v8::Handle<v8::FunctionTemplate> method_templ =
6957      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
6958                                v8_str("method_data"),
6959                                v8::Signature::New(fun_templ));
6960  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
6961  proto_templ->Set(v8_str("method"), method_templ);
6962  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
6963  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
6964                                 NULL, NULL, NULL, NULL,
6965                                 v8::External::Wrap(&interceptor_call_count));
6966  LocalContext context;
6967  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
6968  GenerateSomeGarbage();
6969  context->Global()->Set(v8_str("o"), fun->NewInstance());
6970  v8::TryCatch try_catch;
6971  v8::Handle<Value> value = CompileRun(
6972      "o.foo = 17;"
6973      "var receiver = {};"
6974      "receiver.__proto__ = o;"
6975      "var result = 0;"
6976      "var saved_result = 0;"
6977      "for (var i = 0; i < 100; i++) {"
6978      "  result = receiver.method(41);"
6979      "  if (i == 50) {"
6980      "    saved_result = result;"
6981      "    receiver = 333;"
6982      "  }"
6983      "}");
6984  CHECK(try_catch.HasCaught());
6985  CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
6986           try_catch.Exception()->ToString());
6987  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
6988  CHECK_GE(interceptor_call_count, 50);
6989}
6990
6991THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
6992  int interceptor_call_count = 0;
6993  v8::HandleScope scope;
6994  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6995  v8::Handle<v8::FunctionTemplate> method_templ =
6996      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
6997                                v8_str("method_data"),
6998                                v8::Signature::New(fun_templ));
6999  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7000  proto_templ->Set(v8_str("method"), method_templ);
7001  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7002  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
7003                                 NULL, NULL, NULL, NULL,
7004                                 v8::External::Wrap(&interceptor_call_count));
7005  LocalContext context;
7006  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7007  GenerateSomeGarbage();
7008  context->Global()->Set(v8_str("o"), fun->NewInstance());
7009  v8::TryCatch try_catch;
7010  v8::Handle<Value> value = CompileRun(
7011      "o.foo = 17;"
7012      "var receiver = {};"
7013      "receiver.__proto__ = o;"
7014      "var result = 0;"
7015      "var saved_result = 0;"
7016      "for (var i = 0; i < 100; i++) {"
7017      "  result = receiver.method(41);"
7018      "  if (i == 50) {"
7019      "    saved_result = result;"
7020      "    receiver = {method: receiver.method};"
7021      "  }"
7022      "}");
7023  CHECK(try_catch.HasCaught());
7024  CHECK_EQ(v8_str("TypeError: Illegal invocation"),
7025           try_catch.Exception()->ToString());
7026  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7027  CHECK_GE(interceptor_call_count, 50);
7028}
7029
7030THREADED_TEST(CallICFastApi_TrivialSignature) {
7031  v8::HandleScope scope;
7032  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7033  v8::Handle<v8::FunctionTemplate> method_templ =
7034      v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
7035                                v8_str("method_data"),
7036                                v8::Handle<v8::Signature>());
7037  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7038  proto_templ->Set(v8_str("method"), method_templ);
7039  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7040  LocalContext context;
7041  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7042  GenerateSomeGarbage();
7043  context->Global()->Set(v8_str("o"), fun->NewInstance());
7044  v8::Handle<Value> value = CompileRun(
7045      "var result = 0;"
7046      "for (var i = 0; i < 100; i++) {"
7047      "  result = o.method(41);"
7048      "}");
7049
7050  CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
7051}
7052
7053THREADED_TEST(CallICFastApi_SimpleSignature) {
7054  v8::HandleScope scope;
7055  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7056  v8::Handle<v8::FunctionTemplate> method_templ =
7057      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7058                                v8_str("method_data"),
7059                                v8::Signature::New(fun_templ));
7060  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7061  proto_templ->Set(v8_str("method"), method_templ);
7062  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7063  LocalContext context;
7064  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7065  GenerateSomeGarbage();
7066  context->Global()->Set(v8_str("o"), fun->NewInstance());
7067  v8::Handle<Value> value = CompileRun(
7068      "o.foo = 17;"
7069      "var receiver = {};"
7070      "receiver.__proto__ = o;"
7071      "var result = 0;"
7072      "for (var i = 0; i < 100; i++) {"
7073      "  result = receiver.method(41);"
7074      "}");
7075
7076  CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
7077}
7078
7079THREADED_TEST(CallICFastApi_SimpleSignature_Miss1) {
7080  v8::HandleScope scope;
7081  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7082  v8::Handle<v8::FunctionTemplate> method_templ =
7083      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7084                                v8_str("method_data"),
7085                                v8::Signature::New(fun_templ));
7086  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7087  proto_templ->Set(v8_str("method"), method_templ);
7088  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
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      "var saved_result = 0;"
7099      "for (var i = 0; i < 100; i++) {"
7100      "  result = receiver.method(41);"
7101      "  if (i == 50) {"
7102      "    saved_result = result;"
7103      "    receiver = {method: function(x) { return x - 1 }};"
7104      "  }"
7105      "}");
7106  CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
7107  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7108}
7109
7110THREADED_TEST(CallICFastApi_SimpleSignature_Miss2) {
7111  v8::HandleScope scope;
7112  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7113  v8::Handle<v8::FunctionTemplate> method_templ =
7114      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7115                                v8_str("method_data"),
7116                                v8::Signature::New(fun_templ));
7117  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7118  proto_templ->Set(v8_str("method"), method_templ);
7119  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7120  LocalContext context;
7121  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7122  GenerateSomeGarbage();
7123  context->Global()->Set(v8_str("o"), fun->NewInstance());
7124  v8::TryCatch try_catch;
7125  v8::Handle<Value> value = CompileRun(
7126      "o.foo = 17;"
7127      "var receiver = {};"
7128      "receiver.__proto__ = o;"
7129      "var result = 0;"
7130      "var saved_result = 0;"
7131      "for (var i = 0; i < 100; i++) {"
7132      "  result = receiver.method(41);"
7133      "  if (i == 50) {"
7134      "    saved_result = result;"
7135      "    receiver = 333;"
7136      "  }"
7137      "}");
7138  CHECK(try_catch.HasCaught());
7139  CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
7140           try_catch.Exception()->ToString());
7141  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7142}
7143
7144
7145v8::Handle<Value> keyed_call_ic_function;
7146
7147static v8::Handle<Value> InterceptorKeyedCallICGetter(
7148    Local<String> name, const AccessorInfo& info) {
7149  ApiTestFuzzer::Fuzz();
7150  if (v8_str("x")->Equals(name)) {
7151    return keyed_call_ic_function;
7152  }
7153  return v8::Handle<Value>();
7154}
7155
7156
7157// Test the case when we stored cacheable lookup into
7158// a stub, but the function name changed (to another cacheable function).
7159THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
7160  v8::HandleScope scope;
7161  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7162  templ->SetNamedPropertyHandler(NoBlockGetterX);
7163  LocalContext context;
7164  context->Global()->Set(v8_str("o"), templ->NewInstance());
7165  v8::Handle<Value> value = CompileRun(
7166    "proto = new Object();"
7167    "proto.y = function(x) { return x + 1; };"
7168    "proto.z = function(x) { return x - 1; };"
7169    "o.__proto__ = proto;"
7170    "var result = 0;"
7171    "var method = 'y';"
7172    "for (var i = 0; i < 10; i++) {"
7173    "  if (i == 5) { method = 'z'; };"
7174    "  result += o[method](41);"
7175    "}");
7176  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
7177}
7178
7179
7180// Test the case when we stored cacheable lookup into
7181// a stub, but the function name changed (and the new function is present
7182// both before and after the interceptor in the prototype chain).
7183THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
7184  v8::HandleScope scope;
7185  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7186  templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
7187  LocalContext context;
7188  context->Global()->Set(v8_str("proto1"), templ->NewInstance());
7189  keyed_call_ic_function =
7190      v8_compile("function f(x) { return x - 1; }; f")->Run();
7191  v8::Handle<Value> value = CompileRun(
7192    "o = new Object();"
7193    "proto2 = new Object();"
7194    "o.y = function(x) { return x + 1; };"
7195    "proto2.y = function(x) { return x + 2; };"
7196    "o.__proto__ = proto1;"
7197    "proto1.__proto__ = proto2;"
7198    "var result = 0;"
7199    "var method = 'x';"
7200    "for (var i = 0; i < 10; i++) {"
7201    "  if (i == 5) { method = 'y'; };"
7202    "  result += o[method](41);"
7203    "}");
7204  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
7205}
7206
7207
7208// Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
7209// on the global object.
7210THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
7211  v8::HandleScope scope;
7212  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7213  templ->SetNamedPropertyHandler(NoBlockGetterX);
7214  LocalContext context;
7215  context->Global()->Set(v8_str("o"), templ->NewInstance());
7216  v8::Handle<Value> value = CompileRun(
7217    "function inc(x) { return x + 1; };"
7218    "inc(1);"
7219    "function dec(x) { return x - 1; };"
7220    "dec(1);"
7221    "o.__proto__ = this;"
7222    "this.__proto__.x = inc;"
7223    "this.__proto__.y = dec;"
7224    "var result = 0;"
7225    "var method = 'x';"
7226    "for (var i = 0; i < 10; i++) {"
7227    "  if (i == 5) { method = 'y'; };"
7228    "  result += o[method](41);"
7229    "}");
7230  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
7231}
7232
7233
7234// Test the case when actual function to call sits on global object.
7235THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
7236  v8::HandleScope scope;
7237  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7238  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
7239  LocalContext context;
7240  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
7241
7242  v8::Handle<Value> value = CompileRun(
7243    "function len(x) { return x.length; };"
7244    "o.__proto__ = this;"
7245    "var m = 'parseFloat';"
7246    "var result = 0;"
7247    "for (var i = 0; i < 10; i++) {"
7248    "  if (i == 5) {"
7249    "    m = 'len';"
7250    "    saved_result = result;"
7251    "  };"
7252    "  result = o[m]('239');"
7253    "}");
7254  CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
7255  CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7256}
7257
7258// Test the map transition before the interceptor.
7259THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
7260  v8::HandleScope scope;
7261  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7262  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
7263  LocalContext context;
7264  context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
7265
7266  v8::Handle<Value> value = CompileRun(
7267    "var o = new Object();"
7268    "o.__proto__ = proto;"
7269    "o.method = function(x) { return x + 1; };"
7270    "var m = 'method';"
7271    "var result = 0;"
7272    "for (var i = 0; i < 10; i++) {"
7273    "  if (i == 5) { o.method = function(x) { return x - 1; }; };"
7274    "  result += o[m](41);"
7275    "}");
7276  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
7277}
7278
7279
7280// Test the map transition after the interceptor.
7281THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
7282  v8::HandleScope scope;
7283  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7284  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
7285  LocalContext context;
7286  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
7287
7288  v8::Handle<Value> value = CompileRun(
7289    "var proto = new Object();"
7290    "o.__proto__ = proto;"
7291    "proto.method = function(x) { return x + 1; };"
7292    "var m = 'method';"
7293    "var result = 0;"
7294    "for (var i = 0; i < 10; i++) {"
7295    "  if (i == 5) { proto.method = function(x) { return x - 1; }; };"
7296    "  result += o[m](41);"
7297    "}");
7298  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
7299}
7300
7301
7302static int interceptor_call_count = 0;
7303
7304static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name,
7305                                                     const AccessorInfo& info) {
7306  ApiTestFuzzer::Fuzz();
7307  if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
7308    return call_ic_function2;
7309  }
7310  return v8::Handle<Value>();
7311}
7312
7313
7314// This test should hit load and call ICs for the interceptor case.
7315// Once in a while, the interceptor will reply that a property was not
7316// found in which case we should get a reference error.
7317THREADED_TEST(InterceptorICReferenceErrors) {
7318  v8::HandleScope scope;
7319  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7320  templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
7321  LocalContext context(0, templ, v8::Handle<Value>());
7322  call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
7323  v8::Handle<Value> value = CompileRun(
7324    "function f() {"
7325    "  for (var i = 0; i < 1000; i++) {"
7326    "    try { x; } catch(e) { return true; }"
7327    "  }"
7328    "  return false;"
7329    "};"
7330    "f();");
7331  CHECK_EQ(true, value->BooleanValue());
7332  interceptor_call_count = 0;
7333  value = CompileRun(
7334    "function g() {"
7335    "  for (var i = 0; i < 1000; i++) {"
7336    "    try { x(42); } catch(e) { return true; }"
7337    "  }"
7338    "  return false;"
7339    "};"
7340    "g();");
7341  CHECK_EQ(true, value->BooleanValue());
7342}
7343
7344
7345static int interceptor_ic_exception_get_count = 0;
7346
7347static v8::Handle<Value> InterceptorICExceptionGetter(
7348    Local<String> name,
7349    const AccessorInfo& info) {
7350  ApiTestFuzzer::Fuzz();
7351  if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
7352    return call_ic_function3;
7353  }
7354  if (interceptor_ic_exception_get_count == 20) {
7355    return v8::ThrowException(v8_num(42));
7356  }
7357  // Do not handle get for properties other than x.
7358  return v8::Handle<Value>();
7359}
7360
7361// Test interceptor load/call IC where the interceptor throws an
7362// exception once in a while.
7363THREADED_TEST(InterceptorICGetterExceptions) {
7364  interceptor_ic_exception_get_count = 0;
7365  v8::HandleScope scope;
7366  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7367  templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
7368  LocalContext context(0, templ, v8::Handle<Value>());
7369  call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
7370  v8::Handle<Value> value = CompileRun(
7371    "function f() {"
7372    "  for (var i = 0; i < 100; i++) {"
7373    "    try { x; } catch(e) { return true; }"
7374    "  }"
7375    "  return false;"
7376    "};"
7377    "f();");
7378  CHECK_EQ(true, value->BooleanValue());
7379  interceptor_ic_exception_get_count = 0;
7380  value = CompileRun(
7381    "function f() {"
7382    "  for (var i = 0; i < 100; i++) {"
7383    "    try { x(42); } catch(e) { return true; }"
7384    "  }"
7385    "  return false;"
7386    "};"
7387    "f();");
7388  CHECK_EQ(true, value->BooleanValue());
7389}
7390
7391
7392static int interceptor_ic_exception_set_count = 0;
7393
7394static v8::Handle<Value> InterceptorICExceptionSetter(
7395      Local<String> key, Local<Value> value, const AccessorInfo&) {
7396  ApiTestFuzzer::Fuzz();
7397  if (++interceptor_ic_exception_set_count > 20) {
7398    return v8::ThrowException(v8_num(42));
7399  }
7400  // Do not actually handle setting.
7401  return v8::Handle<Value>();
7402}
7403
7404// Test interceptor store IC where the interceptor throws an exception
7405// once in a while.
7406THREADED_TEST(InterceptorICSetterExceptions) {
7407  interceptor_ic_exception_set_count = 0;
7408  v8::HandleScope scope;
7409  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7410  templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
7411  LocalContext context(0, templ, v8::Handle<Value>());
7412  v8::Handle<Value> value = CompileRun(
7413    "function f() {"
7414    "  for (var i = 0; i < 100; i++) {"
7415    "    try { x = 42; } catch(e) { return true; }"
7416    "  }"
7417    "  return false;"
7418    "};"
7419    "f();");
7420  CHECK_EQ(true, value->BooleanValue());
7421}
7422
7423
7424// Test that we ignore null interceptors.
7425THREADED_TEST(NullNamedInterceptor) {
7426  v8::HandleScope scope;
7427  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7428  templ->SetNamedPropertyHandler(0);
7429  LocalContext context;
7430  templ->Set("x", v8_num(42));
7431  v8::Handle<v8::Object> obj = templ->NewInstance();
7432  context->Global()->Set(v8_str("obj"), obj);
7433  v8::Handle<Value> value = CompileRun("obj.x");
7434  CHECK(value->IsInt32());
7435  CHECK_EQ(42, value->Int32Value());
7436}
7437
7438
7439// Test that we ignore null interceptors.
7440THREADED_TEST(NullIndexedInterceptor) {
7441  v8::HandleScope scope;
7442  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7443  templ->SetIndexedPropertyHandler(0);
7444  LocalContext context;
7445  templ->Set("42", v8_num(42));
7446  v8::Handle<v8::Object> obj = templ->NewInstance();
7447  context->Global()->Set(v8_str("obj"), obj);
7448  v8::Handle<Value> value = CompileRun("obj[42]");
7449  CHECK(value->IsInt32());
7450  CHECK_EQ(42, value->Int32Value());
7451}
7452
7453
7454THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
7455  v8::HandleScope scope;
7456  v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
7457  templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
7458  LocalContext env;
7459  env->Global()->Set(v8_str("obj"),
7460                     templ->GetFunction()->NewInstance());
7461  ExpectTrue("obj.x === 42");
7462  ExpectTrue("!obj.propertyIsEnumerable('x')");
7463}
7464
7465
7466static v8::Handle<Value> ParentGetter(Local<String> name,
7467                                      const AccessorInfo& info) {
7468  ApiTestFuzzer::Fuzz();
7469  return v8_num(1);
7470}
7471
7472
7473static v8::Handle<Value> ChildGetter(Local<String> name,
7474                                     const AccessorInfo& info) {
7475  ApiTestFuzzer::Fuzz();
7476  return v8_num(42);
7477}
7478
7479
7480THREADED_TEST(Overriding) {
7481  v8::HandleScope scope;
7482  LocalContext context;
7483
7484  // Parent template.
7485  Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New();
7486  Local<ObjectTemplate> parent_instance_templ =
7487      parent_templ->InstanceTemplate();
7488  parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
7489
7490  // Template that inherits from the parent template.
7491  Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New();
7492  Local<ObjectTemplate> child_instance_templ =
7493      child_templ->InstanceTemplate();
7494  child_templ->Inherit(parent_templ);
7495  // Override 'f'.  The child version of 'f' should get called for child
7496  // instances.
7497  child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
7498  // Add 'g' twice.  The 'g' added last should get called for instances.
7499  child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
7500  child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
7501
7502  // Add 'h' as an accessor to the proto template with ReadOnly attributes
7503  // so 'h' can be shadowed on the instance object.
7504  Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
7505  child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
7506      v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
7507
7508  // Add 'i' as an accessor to the instance template with ReadOnly attributes
7509  // but the attribute does not have effect because it is duplicated with
7510  // NULL setter.
7511  child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
7512      v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
7513
7514
7515
7516  // Instantiate the child template.
7517  Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
7518
7519  // Check that the child function overrides the parent one.
7520  context->Global()->Set(v8_str("o"), instance);
7521  Local<Value> value = v8_compile("o.f")->Run();
7522  // Check that the 'g' that was added last is hit.
7523  CHECK_EQ(42, value->Int32Value());
7524  value = v8_compile("o.g")->Run();
7525  CHECK_EQ(42, value->Int32Value());
7526
7527  // Check 'h' can be shadowed.
7528  value = v8_compile("o.h = 3; o.h")->Run();
7529  CHECK_EQ(3, value->Int32Value());
7530
7531  // Check 'i' is cannot be shadowed or changed.
7532  value = v8_compile("o.i = 3; o.i")->Run();
7533  CHECK_EQ(42, value->Int32Value());
7534}
7535
7536
7537static v8::Handle<Value> IsConstructHandler(const v8::Arguments& args) {
7538  ApiTestFuzzer::Fuzz();
7539  if (args.IsConstructCall()) {
7540    return v8::Boolean::New(true);
7541  }
7542  return v8::Boolean::New(false);
7543}
7544
7545
7546THREADED_TEST(IsConstructCall) {
7547  v8::HandleScope scope;
7548
7549  // Function template with call handler.
7550  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
7551  templ->SetCallHandler(IsConstructHandler);
7552
7553  LocalContext context;
7554
7555  context->Global()->Set(v8_str("f"), templ->GetFunction());
7556  Local<Value> value = v8_compile("f()")->Run();
7557  CHECK(!value->BooleanValue());
7558  value = v8_compile("new f()")->Run();
7559  CHECK(value->BooleanValue());
7560}
7561
7562
7563THREADED_TEST(ObjectProtoToString) {
7564  v8::HandleScope scope;
7565  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
7566  templ->SetClassName(v8_str("MyClass"));
7567
7568  LocalContext context;
7569
7570  Local<String> customized_tostring = v8_str("customized toString");
7571
7572  // Replace Object.prototype.toString
7573  v8_compile("Object.prototype.toString = function() {"
7574                  "  return 'customized toString';"
7575                  "}")->Run();
7576
7577  // Normal ToString call should call replaced Object.prototype.toString
7578  Local<v8::Object> instance = templ->GetFunction()->NewInstance();
7579  Local<String> value = instance->ToString();
7580  CHECK(value->IsString() && value->Equals(customized_tostring));
7581
7582  // ObjectProtoToString should not call replace toString function.
7583  value = instance->ObjectProtoToString();
7584  CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
7585
7586  // Check global
7587  value = context->Global()->ObjectProtoToString();
7588  CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
7589
7590  // Check ordinary object
7591  Local<Value> object = v8_compile("new Object()")->Run();
7592  value = object.As<v8::Object>()->ObjectProtoToString();
7593  CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
7594}
7595
7596
7597bool ApiTestFuzzer::fuzzing_ = false;
7598v8::internal::Semaphore* ApiTestFuzzer::all_tests_done_=
7599  v8::internal::OS::CreateSemaphore(0);
7600int ApiTestFuzzer::active_tests_;
7601int ApiTestFuzzer::tests_being_run_;
7602int ApiTestFuzzer::current_;
7603
7604
7605// We are in a callback and want to switch to another thread (if we
7606// are currently running the thread fuzzing test).
7607void ApiTestFuzzer::Fuzz() {
7608  if (!fuzzing_) return;
7609  ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
7610  test->ContextSwitch();
7611}
7612
7613
7614// Let the next thread go.  Since it is also waiting on the V8 lock it may
7615// not start immediately.
7616bool ApiTestFuzzer::NextThread() {
7617  int test_position = GetNextTestNumber();
7618  const char* test_name = RegisterThreadedTest::nth(current_)->name();
7619  if (test_position == current_) {
7620    if (kLogThreading)
7621      printf("Stay with %s\n", test_name);
7622    return false;
7623  }
7624  if (kLogThreading) {
7625    printf("Switch from %s to %s\n",
7626           test_name,
7627           RegisterThreadedTest::nth(test_position)->name());
7628  }
7629  current_ = test_position;
7630  RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal();
7631  return true;
7632}
7633
7634
7635void ApiTestFuzzer::Run() {
7636  // When it is our turn...
7637  gate_->Wait();
7638  {
7639    // ... get the V8 lock and start running the test.
7640    v8::Locker locker;
7641    CallTest();
7642  }
7643  // This test finished.
7644  active_ = false;
7645  active_tests_--;
7646  // If it was the last then signal that fact.
7647  if (active_tests_ == 0) {
7648    all_tests_done_->Signal();
7649  } else {
7650    // Otherwise select a new test and start that.
7651    NextThread();
7652  }
7653}
7654
7655
7656static unsigned linear_congruential_generator;
7657
7658
7659void ApiTestFuzzer::Setup(PartOfTest part) {
7660  linear_congruential_generator = i::FLAG_testing_prng_seed;
7661  fuzzing_ = true;
7662  int start = (part == FIRST_PART) ? 0 : (RegisterThreadedTest::count() >> 1);
7663  int end = (part == FIRST_PART)
7664      ? (RegisterThreadedTest::count() >> 1)
7665      : RegisterThreadedTest::count();
7666  active_tests_ = tests_being_run_ = end - start;
7667  for (int i = 0; i < tests_being_run_; i++) {
7668    RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
7669  }
7670  for (int i = 0; i < active_tests_; i++) {
7671    RegisterThreadedTest::nth(i)->fuzzer_->Start();
7672  }
7673}
7674
7675
7676static void CallTestNumber(int test_number) {
7677  (RegisterThreadedTest::nth(test_number)->callback())();
7678}
7679
7680
7681void ApiTestFuzzer::RunAllTests() {
7682  // Set off the first test.
7683  current_ = -1;
7684  NextThread();
7685  // Wait till they are all done.
7686  all_tests_done_->Wait();
7687}
7688
7689
7690int ApiTestFuzzer::GetNextTestNumber() {
7691  int next_test;
7692  do {
7693    next_test = (linear_congruential_generator >> 16) % tests_being_run_;
7694    linear_congruential_generator *= 1664525u;
7695    linear_congruential_generator += 1013904223u;
7696  } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
7697  return next_test;
7698}
7699
7700
7701void ApiTestFuzzer::ContextSwitch() {
7702  // If the new thread is the same as the current thread there is nothing to do.
7703  if (NextThread()) {
7704    // Now it can start.
7705    v8::Unlocker unlocker;
7706    // Wait till someone starts us again.
7707    gate_->Wait();
7708    // And we're off.
7709  }
7710}
7711
7712
7713void ApiTestFuzzer::TearDown() {
7714  fuzzing_ = false;
7715  for (int i = 0; i < RegisterThreadedTest::count(); i++) {
7716    ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
7717    if (fuzzer != NULL) fuzzer->Join();
7718  }
7719}
7720
7721
7722// Lets not be needlessly self-referential.
7723TEST(Threading) {
7724  ApiTestFuzzer::Setup(ApiTestFuzzer::FIRST_PART);
7725  ApiTestFuzzer::RunAllTests();
7726  ApiTestFuzzer::TearDown();
7727}
7728
7729TEST(Threading2) {
7730  ApiTestFuzzer::Setup(ApiTestFuzzer::SECOND_PART);
7731  ApiTestFuzzer::RunAllTests();
7732  ApiTestFuzzer::TearDown();
7733}
7734
7735
7736void ApiTestFuzzer::CallTest() {
7737  if (kLogThreading)
7738    printf("Start test %d\n", test_number_);
7739  CallTestNumber(test_number_);
7740  if (kLogThreading)
7741    printf("End test %d\n", test_number_);
7742}
7743
7744
7745static v8::Handle<Value> ThrowInJS(const v8::Arguments& args) {
7746  CHECK(v8::Locker::IsLocked());
7747  ApiTestFuzzer::Fuzz();
7748  v8::Unlocker unlocker;
7749  const char* code = "throw 7;";
7750  {
7751    v8::Locker nested_locker;
7752    v8::HandleScope scope;
7753    v8::Handle<Value> exception;
7754    { v8::TryCatch try_catch;
7755      v8::Handle<Value> value = CompileRun(code);
7756      CHECK(value.IsEmpty());
7757      CHECK(try_catch.HasCaught());
7758      // Make sure to wrap the exception in a new handle because
7759      // the handle returned from the TryCatch is destroyed
7760      // when the TryCatch is destroyed.
7761      exception = Local<Value>::New(try_catch.Exception());
7762    }
7763    return v8::ThrowException(exception);
7764  }
7765}
7766
7767
7768static v8::Handle<Value> ThrowInJSNoCatch(const v8::Arguments& args) {
7769  CHECK(v8::Locker::IsLocked());
7770  ApiTestFuzzer::Fuzz();
7771  v8::Unlocker unlocker;
7772  const char* code = "throw 7;";
7773  {
7774    v8::Locker nested_locker;
7775    v8::HandleScope scope;
7776    v8::Handle<Value> value = CompileRun(code);
7777    CHECK(value.IsEmpty());
7778    return v8_str("foo");
7779  }
7780}
7781
7782
7783// These are locking tests that don't need to be run again
7784// as part of the locking aggregation tests.
7785TEST(NestedLockers) {
7786  v8::Locker locker;
7787  CHECK(v8::Locker::IsLocked());
7788  v8::HandleScope scope;
7789  LocalContext env;
7790  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS);
7791  Local<Function> fun = fun_templ->GetFunction();
7792  env->Global()->Set(v8_str("throw_in_js"), fun);
7793  Local<Script> script = v8_compile("(function () {"
7794                                    "  try {"
7795                                    "    throw_in_js();"
7796                                    "    return 42;"
7797                                    "  } catch (e) {"
7798                                    "    return e * 13;"
7799                                    "  }"
7800                                    "})();");
7801  CHECK_EQ(91, script->Run()->Int32Value());
7802}
7803
7804
7805// These are locking tests that don't need to be run again
7806// as part of the locking aggregation tests.
7807TEST(NestedLockersNoTryCatch) {
7808  v8::Locker locker;
7809  v8::HandleScope scope;
7810  LocalContext env;
7811  Local<v8::FunctionTemplate> fun_templ =
7812      v8::FunctionTemplate::New(ThrowInJSNoCatch);
7813  Local<Function> fun = fun_templ->GetFunction();
7814  env->Global()->Set(v8_str("throw_in_js"), fun);
7815  Local<Script> script = v8_compile("(function () {"
7816                                    "  try {"
7817                                    "    throw_in_js();"
7818                                    "    return 42;"
7819                                    "  } catch (e) {"
7820                                    "    return e * 13;"
7821                                    "  }"
7822                                    "})();");
7823  CHECK_EQ(91, script->Run()->Int32Value());
7824}
7825
7826
7827THREADED_TEST(RecursiveLocking) {
7828  v8::Locker locker;
7829  {
7830    v8::Locker locker2;
7831    CHECK(v8::Locker::IsLocked());
7832  }
7833}
7834
7835
7836static v8::Handle<Value> UnlockForAMoment(const v8::Arguments& args) {
7837  ApiTestFuzzer::Fuzz();
7838  v8::Unlocker unlocker;
7839  return v8::Undefined();
7840}
7841
7842
7843THREADED_TEST(LockUnlockLock) {
7844  {
7845    v8::Locker locker;
7846    v8::HandleScope scope;
7847    LocalContext env;
7848    Local<v8::FunctionTemplate> fun_templ =
7849        v8::FunctionTemplate::New(UnlockForAMoment);
7850    Local<Function> fun = fun_templ->GetFunction();
7851    env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
7852    Local<Script> script = v8_compile("(function () {"
7853                                      "  unlock_for_a_moment();"
7854                                      "  return 42;"
7855                                      "})();");
7856    CHECK_EQ(42, script->Run()->Int32Value());
7857  }
7858  {
7859    v8::Locker locker;
7860    v8::HandleScope scope;
7861    LocalContext env;
7862    Local<v8::FunctionTemplate> fun_templ =
7863        v8::FunctionTemplate::New(UnlockForAMoment);
7864    Local<Function> fun = fun_templ->GetFunction();
7865    env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
7866    Local<Script> script = v8_compile("(function () {"
7867                                      "  unlock_for_a_moment();"
7868                                      "  return 42;"
7869                                      "})();");
7870    CHECK_EQ(42, script->Run()->Int32Value());
7871  }
7872}
7873
7874
7875static int GetGlobalObjectsCount() {
7876  int count = 0;
7877  v8::internal::HeapIterator it;
7878  for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
7879    if (object->IsJSGlobalObject()) count++;
7880  return count;
7881}
7882
7883
7884static int GetSurvivingGlobalObjectsCount() {
7885  // We need to collect all garbage twice to be sure that everything
7886  // has been collected.  This is because inline caches are cleared in
7887  // the first garbage collection but some of the maps have already
7888  // been marked at that point.  Therefore some of the maps are not
7889  // collected until the second garbage collection.
7890  v8::internal::Heap::CollectAllGarbage(false);
7891  v8::internal::Heap::CollectAllGarbage(false);
7892  int count = GetGlobalObjectsCount();
7893#ifdef DEBUG
7894  if (count > 0) v8::internal::Heap::TracePathToGlobal();
7895#endif
7896  return count;
7897}
7898
7899
7900TEST(DontLeakGlobalObjects) {
7901  // Regression test for issues 1139850 and 1174891.
7902
7903  v8::V8::Initialize();
7904
7905  int count = GetSurvivingGlobalObjectsCount();
7906
7907  for (int i = 0; i < 5; i++) {
7908    { v8::HandleScope scope;
7909      LocalContext context;
7910    }
7911    CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
7912
7913    { v8::HandleScope scope;
7914      LocalContext context;
7915      v8_compile("Date")->Run();
7916    }
7917    CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
7918
7919    { v8::HandleScope scope;
7920      LocalContext context;
7921      v8_compile("/aaa/")->Run();
7922    }
7923    CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
7924
7925    { v8::HandleScope scope;
7926      const char* extension_list[] = { "v8/gc" };
7927      v8::ExtensionConfiguration extensions(1, extension_list);
7928      LocalContext context(&extensions);
7929      v8_compile("gc();")->Run();
7930    }
7931    CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
7932  }
7933}
7934
7935
7936v8::Persistent<v8::Object> some_object;
7937v8::Persistent<v8::Object> bad_handle;
7938
7939void NewPersistentHandleCallback(v8::Persistent<v8::Value>, void*) {
7940  v8::HandleScope scope;
7941  bad_handle = v8::Persistent<v8::Object>::New(some_object);
7942}
7943
7944
7945THREADED_TEST(NewPersistentHandleFromWeakCallback) {
7946  LocalContext context;
7947
7948  v8::Persistent<v8::Object> handle1, handle2;
7949  {
7950    v8::HandleScope scope;
7951    some_object = v8::Persistent<v8::Object>::New(v8::Object::New());
7952    handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
7953    handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
7954  }
7955  // Note: order is implementation dependent alas: currently
7956  // global handle nodes are processed by PostGarbageCollectionProcessing
7957  // in reverse allocation order, so if second allocated handle is deleted,
7958  // weak callback of the first handle would be able to 'reallocate' it.
7959  handle1.MakeWeak(NULL, NewPersistentHandleCallback);
7960  handle2.Dispose();
7961  i::Heap::CollectAllGarbage(false);
7962}
7963
7964
7965v8::Persistent<v8::Object> to_be_disposed;
7966
7967void DisposeAndForceGcCallback(v8::Persistent<v8::Value> handle, void*) {
7968  to_be_disposed.Dispose();
7969  i::Heap::CollectAllGarbage(false);
7970}
7971
7972
7973THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
7974  LocalContext context;
7975
7976  v8::Persistent<v8::Object> handle1, handle2;
7977  {
7978    v8::HandleScope scope;
7979    handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
7980    handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
7981  }
7982  handle1.MakeWeak(NULL, DisposeAndForceGcCallback);
7983  to_be_disposed = handle2;
7984  i::Heap::CollectAllGarbage(false);
7985}
7986
7987void DisposingCallback(v8::Persistent<v8::Value> handle, void*) {
7988  handle.Dispose();
7989}
7990
7991void HandleCreatingCallback(v8::Persistent<v8::Value> handle, void*) {
7992  v8::HandleScope scope;
7993  v8::Persistent<v8::Object>::New(v8::Object::New());
7994}
7995
7996
7997THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
7998  LocalContext context;
7999
8000  v8::Persistent<v8::Object> handle1, handle2, handle3;
8001  {
8002    v8::HandleScope scope;
8003    handle3 = v8::Persistent<v8::Object>::New(v8::Object::New());
8004    handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
8005    handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
8006  }
8007  handle2.MakeWeak(NULL, DisposingCallback);
8008  handle3.MakeWeak(NULL, HandleCreatingCallback);
8009  i::Heap::CollectAllGarbage(false);
8010}
8011
8012
8013THREADED_TEST(CheckForCrossContextObjectLiterals) {
8014  v8::V8::Initialize();
8015
8016  const int nof = 2;
8017  const char* sources[nof] = {
8018    "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
8019    "Object()"
8020  };
8021
8022  for (int i = 0; i < nof; i++) {
8023    const char* source = sources[i];
8024    { v8::HandleScope scope;
8025      LocalContext context;
8026      CompileRun(source);
8027    }
8028    { v8::HandleScope scope;
8029      LocalContext context;
8030      CompileRun(source);
8031    }
8032  }
8033}
8034
8035
8036static v8::Handle<Value> NestedScope(v8::Persistent<Context> env) {
8037  v8::HandleScope inner;
8038  env->Enter();
8039  v8::Handle<Value> three = v8_num(3);
8040  v8::Handle<Value> value = inner.Close(three);
8041  env->Exit();
8042  return value;
8043}
8044
8045
8046THREADED_TEST(NestedHandleScopeAndContexts) {
8047  v8::HandleScope outer;
8048  v8::Persistent<Context> env = Context::New();
8049  env->Enter();
8050  v8::Handle<Value> value = NestedScope(env);
8051  v8::Handle<String> str = value->ToString();
8052  env->Exit();
8053  env.Dispose();
8054}
8055
8056
8057THREADED_TEST(ExternalAllocatedMemory) {
8058  v8::HandleScope outer;
8059  v8::Persistent<Context> env = Context::New();
8060  const int kSize = 1024*1024;
8061  CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize), kSize);
8062  CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize), 0);
8063}
8064
8065
8066THREADED_TEST(DisposeEnteredContext) {
8067  v8::HandleScope scope;
8068  LocalContext outer;
8069  { v8::Persistent<v8::Context> inner = v8::Context::New();
8070    inner->Enter();
8071    inner.Dispose();
8072    inner.Clear();
8073    inner->Exit();
8074  }
8075}
8076
8077
8078// Regression test for issue 54, object templates with internal fields
8079// but no accessors or interceptors did not get their internal field
8080// count set on instances.
8081THREADED_TEST(Regress54) {
8082  v8::HandleScope outer;
8083  LocalContext context;
8084  static v8::Persistent<v8::ObjectTemplate> templ;
8085  if (templ.IsEmpty()) {
8086    v8::HandleScope inner;
8087    v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New();
8088    local->SetInternalFieldCount(1);
8089    templ = v8::Persistent<v8::ObjectTemplate>::New(inner.Close(local));
8090  }
8091  v8::Handle<v8::Object> result = templ->NewInstance();
8092  CHECK_EQ(1, result->InternalFieldCount());
8093}
8094
8095
8096// If part of the threaded tests, this test makes ThreadingTest fail
8097// on mac.
8098TEST(CatchStackOverflow) {
8099  v8::HandleScope scope;
8100  LocalContext context;
8101  v8::TryCatch try_catch;
8102  v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(
8103    "function f() {"
8104    "  return f();"
8105    "}"
8106    ""
8107    "f();"));
8108  v8::Handle<v8::Value> result = script->Run();
8109  CHECK(result.IsEmpty());
8110}
8111
8112
8113static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
8114                                    const char* resource_name,
8115                                    int line_offset) {
8116  v8::HandleScope scope;
8117  v8::TryCatch try_catch;
8118  v8::Handle<v8::Value> result = script->Run();
8119  CHECK(result.IsEmpty());
8120  CHECK(try_catch.HasCaught());
8121  v8::Handle<v8::Message> message = try_catch.Message();
8122  CHECK(!message.IsEmpty());
8123  CHECK_EQ(10 + line_offset, message->GetLineNumber());
8124  CHECK_EQ(91, message->GetStartPosition());
8125  CHECK_EQ(92, message->GetEndPosition());
8126  CHECK_EQ(2, message->GetStartColumn());
8127  CHECK_EQ(3, message->GetEndColumn());
8128  v8::String::AsciiValue line(message->GetSourceLine());
8129  CHECK_EQ("  throw 'nirk';", *line);
8130  v8::String::AsciiValue name(message->GetScriptResourceName());
8131  CHECK_EQ(resource_name, *name);
8132}
8133
8134
8135THREADED_TEST(TryCatchSourceInfo) {
8136  v8::HandleScope scope;
8137  LocalContext context;
8138  v8::Handle<v8::String> source = v8::String::New(
8139      "function Foo() {\n"
8140      "  return Bar();\n"
8141      "}\n"
8142      "\n"
8143      "function Bar() {\n"
8144      "  return Baz();\n"
8145      "}\n"
8146      "\n"
8147      "function Baz() {\n"
8148      "  throw 'nirk';\n"
8149      "}\n"
8150      "\n"
8151      "Foo();\n");
8152
8153  const char* resource_name;
8154  v8::Handle<v8::Script> script;
8155  resource_name = "test.js";
8156  script = v8::Script::Compile(source, v8::String::New(resource_name));
8157  CheckTryCatchSourceInfo(script, resource_name, 0);
8158
8159  resource_name = "test1.js";
8160  v8::ScriptOrigin origin1(v8::String::New(resource_name));
8161  script = v8::Script::Compile(source, &origin1);
8162  CheckTryCatchSourceInfo(script, resource_name, 0);
8163
8164  resource_name = "test2.js";
8165  v8::ScriptOrigin origin2(v8::String::New(resource_name), v8::Integer::New(7));
8166  script = v8::Script::Compile(source, &origin2);
8167  CheckTryCatchSourceInfo(script, resource_name, 7);
8168}
8169
8170
8171THREADED_TEST(CompilationCache) {
8172  v8::HandleScope scope;
8173  LocalContext context;
8174  v8::Handle<v8::String> source0 = v8::String::New("1234");
8175  v8::Handle<v8::String> source1 = v8::String::New("1234");
8176  v8::Handle<v8::Script> script0 =
8177      v8::Script::Compile(source0, v8::String::New("test.js"));
8178  v8::Handle<v8::Script> script1 =
8179      v8::Script::Compile(source1, v8::String::New("test.js"));
8180  v8::Handle<v8::Script> script2 =
8181      v8::Script::Compile(source0);  // different origin
8182  CHECK_EQ(1234, script0->Run()->Int32Value());
8183  CHECK_EQ(1234, script1->Run()->Int32Value());
8184  CHECK_EQ(1234, script2->Run()->Int32Value());
8185}
8186
8187
8188static v8::Handle<Value> FunctionNameCallback(const v8::Arguments& args) {
8189  ApiTestFuzzer::Fuzz();
8190  return v8_num(42);
8191}
8192
8193
8194THREADED_TEST(CallbackFunctionName) {
8195  v8::HandleScope scope;
8196  LocalContext context;
8197  Local<ObjectTemplate> t = ObjectTemplate::New();
8198  t->Set(v8_str("asdf"), v8::FunctionTemplate::New(FunctionNameCallback));
8199  context->Global()->Set(v8_str("obj"), t->NewInstance());
8200  v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
8201  CHECK(value->IsString());
8202  v8::String::AsciiValue name(value);
8203  CHECK_EQ("asdf", *name);
8204}
8205
8206
8207THREADED_TEST(DateAccess) {
8208  v8::HandleScope scope;
8209  LocalContext context;
8210  v8::Handle<v8::Value> date = v8::Date::New(1224744689038.0);
8211  CHECK(date->IsDate());
8212  CHECK_EQ(1224744689038.0, date.As<v8::Date>()->NumberValue());
8213}
8214
8215
8216void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) {
8217  v8::Handle<v8::Object> obj = val.As<v8::Object>();
8218  v8::Handle<v8::Array> props = obj->GetPropertyNames();
8219  CHECK_EQ(elmc, props->Length());
8220  for (int i = 0; i < elmc; i++) {
8221    v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
8222    CHECK_EQ(elmv[i], *elm);
8223  }
8224}
8225
8226
8227THREADED_TEST(PropertyEnumeration) {
8228  v8::HandleScope scope;
8229  LocalContext context;
8230  v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
8231      "var result = [];"
8232      "result[0] = {};"
8233      "result[1] = {a: 1, b: 2};"
8234      "result[2] = [1, 2, 3];"
8235      "var proto = {x: 1, y: 2, z: 3};"
8236      "var x = { __proto__: proto, w: 0, z: 1 };"
8237      "result[3] = x;"
8238      "result;"))->Run();
8239  v8::Handle<v8::Array> elms = obj.As<v8::Array>();
8240  CHECK_EQ(4, elms->Length());
8241  int elmc0 = 0;
8242  const char** elmv0 = NULL;
8243  CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
8244  int elmc1 = 2;
8245  const char* elmv1[] = {"a", "b"};
8246  CheckProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
8247  int elmc2 = 3;
8248  const char* elmv2[] = {"0", "1", "2"};
8249  CheckProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
8250  int elmc3 = 4;
8251  const char* elmv3[] = {"w", "z", "x", "y"};
8252  CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3);
8253}
8254
8255
8256static bool NamedSetAccessBlocker(Local<v8::Object> obj,
8257                                  Local<Value> name,
8258                                  v8::AccessType type,
8259                                  Local<Value> data) {
8260  return type != v8::ACCESS_SET;
8261}
8262
8263
8264static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
8265                                    uint32_t key,
8266                                    v8::AccessType type,
8267                                    Local<Value> data) {
8268  return type != v8::ACCESS_SET;
8269}
8270
8271
8272THREADED_TEST(DisableAccessChecksWhileConfiguring) {
8273  v8::HandleScope scope;
8274  LocalContext context;
8275  Local<ObjectTemplate> templ = ObjectTemplate::New();
8276  templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
8277                                 IndexedSetAccessBlocker);
8278  templ->Set(v8_str("x"), v8::True());
8279  Local<v8::Object> instance = templ->NewInstance();
8280  context->Global()->Set(v8_str("obj"), instance);
8281  Local<Value> value = CompileRun("obj.x");
8282  CHECK(value->BooleanValue());
8283}
8284
8285
8286static bool NamedGetAccessBlocker(Local<v8::Object> obj,
8287                                  Local<Value> name,
8288                                  v8::AccessType type,
8289                                  Local<Value> data) {
8290  return false;
8291}
8292
8293
8294static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
8295                                    uint32_t key,
8296                                    v8::AccessType type,
8297                                    Local<Value> data) {
8298  return false;
8299}
8300
8301
8302
8303THREADED_TEST(AccessChecksReenabledCorrectly) {
8304  v8::HandleScope scope;
8305  LocalContext context;
8306  Local<ObjectTemplate> templ = ObjectTemplate::New();
8307  templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
8308                                 IndexedGetAccessBlocker);
8309  templ->Set(v8_str("a"), v8_str("a"));
8310  // Add more than 8 (see kMaxFastProperties) properties
8311  // so that the constructor will force copying map.
8312  // Cannot sprintf, gcc complains unsafety.
8313  char buf[4];
8314  for (char i = '0'; i <= '9' ; i++) {
8315    buf[0] = i;
8316    for (char j = '0'; j <= '9'; j++) {
8317      buf[1] = j;
8318      for (char k = '0'; k <= '9'; k++) {
8319        buf[2] = k;
8320        buf[3] = 0;
8321        templ->Set(v8_str(buf), v8::Number::New(k));
8322      }
8323    }
8324  }
8325
8326  Local<v8::Object> instance_1 = templ->NewInstance();
8327  context->Global()->Set(v8_str("obj_1"), instance_1);
8328
8329  Local<Value> value_1 = CompileRun("obj_1.a");
8330  CHECK(value_1->IsUndefined());
8331
8332  Local<v8::Object> instance_2 = templ->NewInstance();
8333  context->Global()->Set(v8_str("obj_2"), instance_2);
8334
8335  Local<Value> value_2 = CompileRun("obj_2.a");
8336  CHECK(value_2->IsUndefined());
8337}
8338
8339
8340// This tests that access check information remains on the global
8341// object template when creating contexts.
8342THREADED_TEST(AccessControlRepeatedContextCreation) {
8343  v8::HandleScope handle_scope;
8344  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
8345  global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
8346                                           IndexedSetAccessBlocker);
8347  i::Handle<i::ObjectTemplateInfo> internal_template =
8348      v8::Utils::OpenHandle(*global_template);
8349  CHECK(!internal_template->constructor()->IsUndefined());
8350  i::Handle<i::FunctionTemplateInfo> constructor(
8351      i::FunctionTemplateInfo::cast(internal_template->constructor()));
8352  CHECK(!constructor->access_check_info()->IsUndefined());
8353  v8::Persistent<Context> context0 = Context::New(NULL, global_template);
8354  CHECK(!constructor->access_check_info()->IsUndefined());
8355}
8356
8357
8358THREADED_TEST(TurnOnAccessCheck) {
8359  v8::HandleScope handle_scope;
8360
8361  // Create an environment with access check to the global object disabled by
8362  // default.
8363  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
8364  global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
8365                                           IndexedGetAccessBlocker,
8366                                           v8::Handle<v8::Value>(),
8367                                           false);
8368  v8::Persistent<Context> context = Context::New(NULL, global_template);
8369  Context::Scope context_scope(context);
8370
8371  // Set up a property and a number of functions.
8372  context->Global()->Set(v8_str("a"), v8_num(1));
8373  CompileRun("function f1() {return a;}"
8374             "function f2() {return a;}"
8375             "function g1() {return h();}"
8376             "function g2() {return h();}"
8377             "function h() {return 1;}");
8378  Local<Function> f1 =
8379      Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
8380  Local<Function> f2 =
8381      Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
8382  Local<Function> g1 =
8383      Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
8384  Local<Function> g2 =
8385      Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
8386  Local<Function> h =
8387      Local<Function>::Cast(context->Global()->Get(v8_str("h")));
8388
8389  // Get the global object.
8390  v8::Handle<v8::Object> global = context->Global();
8391
8392  // Call f1 one time and f2 a number of times. This will ensure that f1 still
8393  // uses the runtime system to retreive property a whereas f2 uses global load
8394  // inline cache.
8395  CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
8396  for (int i = 0; i < 4; i++) {
8397    CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
8398  }
8399
8400  // Same for g1 and g2.
8401  CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
8402  for (int i = 0; i < 4; i++) {
8403    CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
8404  }
8405
8406  // Detach the global and turn on access check.
8407  context->DetachGlobal();
8408  context->Global()->TurnOnAccessCheck();
8409
8410  // Failing access check to property get results in undefined.
8411  CHECK(f1->Call(global, 0, NULL)->IsUndefined());
8412  CHECK(f2->Call(global, 0, NULL)->IsUndefined());
8413
8414  // Failing access check to function call results in exception.
8415  CHECK(g1->Call(global, 0, NULL).IsEmpty());
8416  CHECK(g2->Call(global, 0, NULL).IsEmpty());
8417
8418  // No failing access check when just returning a constant.
8419  CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
8420}
8421
8422
8423// This test verifies that pre-compilation (aka preparsing) can be called
8424// without initializing the whole VM. Thus we cannot run this test in a
8425// multi-threaded setup.
8426TEST(PreCompile) {
8427  // TODO(155): This test would break without the initialization of V8. This is
8428  // a workaround for now to make this test not fail.
8429  v8::V8::Initialize();
8430  const char* script = "function foo(a) { return a+1; }";
8431  v8::ScriptData* sd =
8432      v8::ScriptData::PreCompile(script, i::StrLength(script));
8433  CHECK_NE(sd->Length(), 0);
8434  CHECK_NE(sd->Data(), NULL);
8435  CHECK(!sd->HasError());
8436  delete sd;
8437}
8438
8439
8440TEST(PreCompileWithError) {
8441  v8::V8::Initialize();
8442  const char* script = "function foo(a) { return 1 * * 2; }";
8443  v8::ScriptData* sd =
8444      v8::ScriptData::PreCompile(script, i::StrLength(script));
8445  CHECK(sd->HasError());
8446  delete sd;
8447}
8448
8449
8450TEST(Regress31661) {
8451  v8::V8::Initialize();
8452  const char* script = " The Definintive Guide";
8453  v8::ScriptData* sd =
8454      v8::ScriptData::PreCompile(script, i::StrLength(script));
8455  CHECK(sd->HasError());
8456  delete sd;
8457}
8458
8459
8460// Tests that ScriptData can be serialized and deserialized.
8461TEST(PreCompileSerialization) {
8462  v8::V8::Initialize();
8463  const char* script = "function foo(a) { return a+1; }";
8464  v8::ScriptData* sd =
8465      v8::ScriptData::PreCompile(script, i::StrLength(script));
8466
8467  // Serialize.
8468  int serialized_data_length = sd->Length();
8469  char* serialized_data = i::NewArray<char>(serialized_data_length);
8470  memcpy(serialized_data, sd->Data(), serialized_data_length);
8471
8472  // Deserialize.
8473  v8::ScriptData* deserialized_sd =
8474      v8::ScriptData::New(serialized_data, serialized_data_length);
8475
8476  // Verify that the original is the same as the deserialized.
8477  CHECK_EQ(sd->Length(), deserialized_sd->Length());
8478  CHECK_EQ(0, memcmp(sd->Data(), deserialized_sd->Data(), sd->Length()));
8479  CHECK_EQ(sd->HasError(), deserialized_sd->HasError());
8480
8481  delete sd;
8482  delete deserialized_sd;
8483}
8484
8485
8486// Attempts to deserialize bad data.
8487TEST(PreCompileDeserializationError) {
8488  v8::V8::Initialize();
8489  const char* data = "DONT CARE";
8490  int invalid_size = 3;
8491  v8::ScriptData* sd = v8::ScriptData::New(data, invalid_size);
8492
8493  CHECK_EQ(0, sd->Length());
8494
8495  delete sd;
8496}
8497
8498
8499// Verifies that the Handle<String> and const char* versions of the API produce
8500// the same results (at least for one trivial case).
8501TEST(PreCompileAPIVariationsAreSame) {
8502  v8::V8::Initialize();
8503  v8::HandleScope scope;
8504
8505  const char* cstring = "function foo(a) { return a+1; }";
8506  v8::ScriptData* sd_from_cstring =
8507      v8::ScriptData::PreCompile(cstring, i::StrLength(cstring));
8508
8509  TestAsciiResource* resource = new TestAsciiResource(cstring);
8510  v8::ScriptData* sd_from_istring = v8::ScriptData::PreCompile(
8511      v8::String::NewExternal(resource));
8512
8513  CHECK_EQ(sd_from_cstring->Length(), sd_from_istring->Length());
8514  CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
8515                     sd_from_istring->Data(),
8516                     sd_from_cstring->Length()));
8517
8518  delete sd_from_cstring;
8519  delete sd_from_istring;
8520}
8521
8522
8523// This tests that we do not allow dictionary load/call inline caches
8524// to use functions that have not yet been compiled.  The potential
8525// problem of loading a function that has not yet been compiled can
8526// arise because we share code between contexts via the compilation
8527// cache.
8528THREADED_TEST(DictionaryICLoadedFunction) {
8529  v8::HandleScope scope;
8530  // Test LoadIC.
8531  for (int i = 0; i < 2; i++) {
8532    LocalContext context;
8533    context->Global()->Set(v8_str("tmp"), v8::True());
8534    context->Global()->Delete(v8_str("tmp"));
8535    CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
8536  }
8537  // Test CallIC.
8538  for (int i = 0; i < 2; i++) {
8539    LocalContext context;
8540    context->Global()->Set(v8_str("tmp"), v8::True());
8541    context->Global()->Delete(v8_str("tmp"));
8542    CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
8543  }
8544}
8545
8546
8547// Test that cross-context new calls use the context of the callee to
8548// create the new JavaScript object.
8549THREADED_TEST(CrossContextNew) {
8550  v8::HandleScope scope;
8551  v8::Persistent<Context> context0 = Context::New();
8552  v8::Persistent<Context> context1 = Context::New();
8553
8554  // Allow cross-domain access.
8555  Local<String> token = v8_str("<security token>");
8556  context0->SetSecurityToken(token);
8557  context1->SetSecurityToken(token);
8558
8559  // Set an 'x' property on the Object prototype and define a
8560  // constructor function in context0.
8561  context0->Enter();
8562  CompileRun("Object.prototype.x = 42; function C() {};");
8563  context0->Exit();
8564
8565  // Call the constructor function from context0 and check that the
8566  // result has the 'x' property.
8567  context1->Enter();
8568  context1->Global()->Set(v8_str("other"), context0->Global());
8569  Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
8570  CHECK(value->IsInt32());
8571  CHECK_EQ(42, value->Int32Value());
8572  context1->Exit();
8573
8574  // Dispose the contexts to allow them to be garbage collected.
8575  context0.Dispose();
8576  context1.Dispose();
8577}
8578
8579
8580class RegExpInterruptTest {
8581 public:
8582  RegExpInterruptTest() : block_(NULL) {}
8583  ~RegExpInterruptTest() { delete block_; }
8584  void RunTest() {
8585    block_ = i::OS::CreateSemaphore(0);
8586    gc_count_ = 0;
8587    gc_during_regexp_ = 0;
8588    regexp_success_ = false;
8589    gc_success_ = false;
8590    GCThread gc_thread(this);
8591    gc_thread.Start();
8592    v8::Locker::StartPreemption(1);
8593
8594    LongRunningRegExp();
8595    {
8596      v8::Unlocker unlock;
8597      gc_thread.Join();
8598    }
8599    v8::Locker::StopPreemption();
8600    CHECK(regexp_success_);
8601    CHECK(gc_success_);
8602  }
8603 private:
8604  // Number of garbage collections required.
8605  static const int kRequiredGCs = 5;
8606
8607  class GCThread : public i::Thread {
8608   public:
8609    explicit GCThread(RegExpInterruptTest* test)
8610        : test_(test) {}
8611    virtual void Run() {
8612      test_->CollectGarbage();
8613    }
8614   private:
8615     RegExpInterruptTest* test_;
8616  };
8617
8618  void CollectGarbage() {
8619    block_->Wait();
8620    while (gc_during_regexp_ < kRequiredGCs) {
8621      {
8622        v8::Locker lock;
8623        // TODO(lrn): Perhaps create some garbage before collecting.
8624        i::Heap::CollectAllGarbage(false);
8625        gc_count_++;
8626      }
8627      i::OS::Sleep(1);
8628    }
8629    gc_success_ = true;
8630  }
8631
8632  void LongRunningRegExp() {
8633    block_->Signal();  // Enable garbage collection thread on next preemption.
8634    int rounds = 0;
8635    while (gc_during_regexp_ < kRequiredGCs) {
8636      int gc_before = gc_count_;
8637      {
8638        // Match 15-30 "a"'s against 14 and a "b".
8639        const char* c_source =
8640            "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
8641            ".exec('aaaaaaaaaaaaaaab') === null";
8642        Local<String> source = String::New(c_source);
8643        Local<Script> script = Script::Compile(source);
8644        Local<Value> result = script->Run();
8645        if (!result->BooleanValue()) {
8646          gc_during_regexp_ = kRequiredGCs;  // Allow gc thread to exit.
8647          return;
8648        }
8649      }
8650      {
8651        // Match 15-30 "a"'s against 15 and a "b".
8652        const char* c_source =
8653            "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
8654            ".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'";
8655        Local<String> source = String::New(c_source);
8656        Local<Script> script = Script::Compile(source);
8657        Local<Value> result = script->Run();
8658        if (!result->BooleanValue()) {
8659          gc_during_regexp_ = kRequiredGCs;
8660          return;
8661        }
8662      }
8663      int gc_after = gc_count_;
8664      gc_during_regexp_ += gc_after - gc_before;
8665      rounds++;
8666      i::OS::Sleep(1);
8667    }
8668    regexp_success_ = true;
8669  }
8670
8671  i::Semaphore* block_;
8672  int gc_count_;
8673  int gc_during_regexp_;
8674  bool regexp_success_;
8675  bool gc_success_;
8676};
8677
8678
8679// Test that a regular expression execution can be interrupted and
8680// survive a garbage collection.
8681TEST(RegExpInterruption) {
8682  v8::Locker lock;
8683  v8::V8::Initialize();
8684  v8::HandleScope scope;
8685  Local<Context> local_env;
8686  {
8687    LocalContext env;
8688    local_env = env.local();
8689  }
8690
8691  // Local context should still be live.
8692  CHECK(!local_env.IsEmpty());
8693  local_env->Enter();
8694
8695  // Should complete without problems.
8696  RegExpInterruptTest().RunTest();
8697
8698  local_env->Exit();
8699}
8700
8701
8702class ApplyInterruptTest {
8703 public:
8704  ApplyInterruptTest() : block_(NULL) {}
8705  ~ApplyInterruptTest() { delete block_; }
8706  void RunTest() {
8707    block_ = i::OS::CreateSemaphore(0);
8708    gc_count_ = 0;
8709    gc_during_apply_ = 0;
8710    apply_success_ = false;
8711    gc_success_ = false;
8712    GCThread gc_thread(this);
8713    gc_thread.Start();
8714    v8::Locker::StartPreemption(1);
8715
8716    LongRunningApply();
8717    {
8718      v8::Unlocker unlock;
8719      gc_thread.Join();
8720    }
8721    v8::Locker::StopPreemption();
8722    CHECK(apply_success_);
8723    CHECK(gc_success_);
8724  }
8725 private:
8726  // Number of garbage collections required.
8727  static const int kRequiredGCs = 2;
8728
8729  class GCThread : public i::Thread {
8730   public:
8731    explicit GCThread(ApplyInterruptTest* test)
8732        : test_(test) {}
8733    virtual void Run() {
8734      test_->CollectGarbage();
8735    }
8736   private:
8737     ApplyInterruptTest* test_;
8738  };
8739
8740  void CollectGarbage() {
8741    block_->Wait();
8742    while (gc_during_apply_ < kRequiredGCs) {
8743      {
8744        v8::Locker lock;
8745        i::Heap::CollectAllGarbage(false);
8746        gc_count_++;
8747      }
8748      i::OS::Sleep(1);
8749    }
8750    gc_success_ = true;
8751  }
8752
8753  void LongRunningApply() {
8754    block_->Signal();
8755    int rounds = 0;
8756    while (gc_during_apply_ < kRequiredGCs) {
8757      int gc_before = gc_count_;
8758      {
8759        const char* c_source =
8760            "function do_very_little(bar) {"
8761            "  this.foo = bar;"
8762            "}"
8763            "for (var i = 0; i < 100000; i++) {"
8764            "  do_very_little.apply(this, ['bar']);"
8765            "}";
8766        Local<String> source = String::New(c_source);
8767        Local<Script> script = Script::Compile(source);
8768        Local<Value> result = script->Run();
8769        // Check that no exception was thrown.
8770        CHECK(!result.IsEmpty());
8771      }
8772      int gc_after = gc_count_;
8773      gc_during_apply_ += gc_after - gc_before;
8774      rounds++;
8775    }
8776    apply_success_ = true;
8777  }
8778
8779  i::Semaphore* block_;
8780  int gc_count_;
8781  int gc_during_apply_;
8782  bool apply_success_;
8783  bool gc_success_;
8784};
8785
8786
8787// Test that nothing bad happens if we get a preemption just when we were
8788// about to do an apply().
8789TEST(ApplyInterruption) {
8790  v8::Locker lock;
8791  v8::V8::Initialize();
8792  v8::HandleScope scope;
8793  Local<Context> local_env;
8794  {
8795    LocalContext env;
8796    local_env = env.local();
8797  }
8798
8799  // Local context should still be live.
8800  CHECK(!local_env.IsEmpty());
8801  local_env->Enter();
8802
8803  // Should complete without problems.
8804  ApplyInterruptTest().RunTest();
8805
8806  local_env->Exit();
8807}
8808
8809
8810// Verify that we can clone an object
8811TEST(ObjectClone) {
8812  v8::HandleScope scope;
8813  LocalContext env;
8814
8815  const char* sample =
8816    "var rv = {};"      \
8817    "rv.alpha = 'hello';" \
8818    "rv.beta = 123;"     \
8819    "rv;";
8820
8821  // Create an object, verify basics.
8822  Local<Value> val = CompileRun(sample);
8823  CHECK(val->IsObject());
8824  Local<v8::Object> obj = val.As<v8::Object>();
8825  obj->Set(v8_str("gamma"), v8_str("cloneme"));
8826
8827  CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
8828  CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
8829  CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
8830
8831  // Clone it.
8832  Local<v8::Object> clone = obj->Clone();
8833  CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
8834  CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta")));
8835  CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
8836
8837  // Set a property on the clone, verify each object.
8838  clone->Set(v8_str("beta"), v8::Integer::New(456));
8839  CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
8840  CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta")));
8841}
8842
8843
8844class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
8845 public:
8846  explicit AsciiVectorResource(i::Vector<const char> vector)
8847      : data_(vector) {}
8848  virtual ~AsciiVectorResource() {}
8849  virtual size_t length() const { return data_.length(); }
8850  virtual const char* data() const { return data_.start(); }
8851 private:
8852  i::Vector<const char> data_;
8853};
8854
8855
8856class UC16VectorResource : public v8::String::ExternalStringResource {
8857 public:
8858  explicit UC16VectorResource(i::Vector<const i::uc16> vector)
8859      : data_(vector) {}
8860  virtual ~UC16VectorResource() {}
8861  virtual size_t length() const { return data_.length(); }
8862  virtual const i::uc16* data() const { return data_.start(); }
8863 private:
8864  i::Vector<const i::uc16> data_;
8865};
8866
8867
8868static void MorphAString(i::String* string,
8869                         AsciiVectorResource* ascii_resource,
8870                         UC16VectorResource* uc16_resource) {
8871  CHECK(i::StringShape(string).IsExternal());
8872  if (string->IsAsciiRepresentation()) {
8873    // Check old map is not symbol or long.
8874    CHECK(string->map() == i::Heap::external_ascii_string_map());
8875    // Morph external string to be TwoByte string.
8876    string->set_map(i::Heap::external_string_map());
8877    i::ExternalTwoByteString* morphed =
8878         i::ExternalTwoByteString::cast(string);
8879    morphed->set_resource(uc16_resource);
8880  } else {
8881    // Check old map is not symbol or long.
8882    CHECK(string->map() == i::Heap::external_string_map());
8883    // Morph external string to be ASCII string.
8884    string->set_map(i::Heap::external_ascii_string_map());
8885    i::ExternalAsciiString* morphed =
8886         i::ExternalAsciiString::cast(string);
8887    morphed->set_resource(ascii_resource);
8888  }
8889}
8890
8891
8892// Test that we can still flatten a string if the components it is built up
8893// from have been turned into 16 bit strings in the mean time.
8894THREADED_TEST(MorphCompositeStringTest) {
8895  const char* c_string = "Now is the time for all good men"
8896                         " to come to the aid of the party";
8897  uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
8898  {
8899    v8::HandleScope scope;
8900    LocalContext env;
8901    AsciiVectorResource ascii_resource(
8902        i::Vector<const char>(c_string, i::StrLength(c_string)));
8903    UC16VectorResource uc16_resource(
8904        i::Vector<const uint16_t>(two_byte_string,
8905                                  i::StrLength(c_string)));
8906
8907    Local<String> lhs(v8::Utils::ToLocal(
8908        i::Factory::NewExternalStringFromAscii(&ascii_resource)));
8909    Local<String> rhs(v8::Utils::ToLocal(
8910        i::Factory::NewExternalStringFromAscii(&ascii_resource)));
8911
8912    env->Global()->Set(v8_str("lhs"), lhs);
8913    env->Global()->Set(v8_str("rhs"), rhs);
8914
8915    CompileRun(
8916        "var cons = lhs + rhs;"
8917        "var slice = lhs.substring(1, lhs.length - 1);"
8918        "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
8919
8920    MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
8921    MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
8922
8923    // Now do some stuff to make sure the strings are flattened, etc.
8924    CompileRun(
8925        "/[^a-z]/.test(cons);"
8926        "/[^a-z]/.test(slice);"
8927        "/[^a-z]/.test(slice_on_cons);");
8928    const char* expected_cons =
8929        "Now is the time for all good men to come to the aid of the party"
8930        "Now is the time for all good men to come to the aid of the party";
8931    const char* expected_slice =
8932        "ow is the time for all good men to come to the aid of the part";
8933    const char* expected_slice_on_cons =
8934        "ow is the time for all good men to come to the aid of the party"
8935        "Now is the time for all good men to come to the aid of the part";
8936    CHECK_EQ(String::New(expected_cons),
8937             env->Global()->Get(v8_str("cons")));
8938    CHECK_EQ(String::New(expected_slice),
8939             env->Global()->Get(v8_str("slice")));
8940    CHECK_EQ(String::New(expected_slice_on_cons),
8941             env->Global()->Get(v8_str("slice_on_cons")));
8942  }
8943}
8944
8945
8946TEST(CompileExternalTwoByteSource) {
8947  v8::HandleScope scope;
8948  LocalContext context;
8949
8950  // This is a very short list of sources, which currently is to check for a
8951  // regression caused by r2703.
8952  const char* ascii_sources[] = {
8953    "0.5",
8954    "-0.5",   // This mainly testes PushBack in the Scanner.
8955    "--0.5",  // This mainly testes PushBack in the Scanner.
8956    NULL
8957  };
8958
8959  // Compile the sources as external two byte strings.
8960  for (int i = 0; ascii_sources[i] != NULL; i++) {
8961    uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
8962    UC16VectorResource uc16_resource(
8963        i::Vector<const uint16_t>(two_byte_string,
8964                                  i::StrLength(ascii_sources[i])));
8965    v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource);
8966    v8::Script::Compile(source);
8967  }
8968}
8969
8970
8971class RegExpStringModificationTest {
8972 public:
8973  RegExpStringModificationTest()
8974      : block_(i::OS::CreateSemaphore(0)),
8975        morphs_(0),
8976        morphs_during_regexp_(0),
8977        ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)),
8978        uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {}
8979  ~RegExpStringModificationTest() { delete block_; }
8980  void RunTest() {
8981    regexp_success_ = false;
8982    morph_success_ = false;
8983
8984    // Initialize the contents of two_byte_content_ to be a uc16 representation
8985    // of "aaaaaaaaaaaaaab".
8986    for (int i = 0; i < 14; i++) {
8987      two_byte_content_[i] = 'a';
8988    }
8989    two_byte_content_[14] = 'b';
8990
8991    // Create the input string for the regexp - the one we are going to change
8992    // properties of.
8993    input_ = i::Factory::NewExternalStringFromAscii(&ascii_resource_);
8994
8995    // Inject the input as a global variable.
8996    i::Handle<i::String> input_name =
8997        i::Factory::NewStringFromAscii(i::Vector<const char>("input", 5));
8998    i::Top::global_context()->global()->SetProperty(*input_name, *input_, NONE);
8999
9000
9001    MorphThread morph_thread(this);
9002    morph_thread.Start();
9003    v8::Locker::StartPreemption(1);
9004    LongRunningRegExp();
9005    {
9006      v8::Unlocker unlock;
9007      morph_thread.Join();
9008    }
9009    v8::Locker::StopPreemption();
9010    CHECK(regexp_success_);
9011    CHECK(morph_success_);
9012  }
9013 private:
9014
9015  // Number of string modifications required.
9016  static const int kRequiredModifications = 5;
9017  static const int kMaxModifications = 100;
9018
9019  class MorphThread : public i::Thread {
9020   public:
9021    explicit MorphThread(RegExpStringModificationTest* test)
9022        : test_(test) {}
9023    virtual void Run() {
9024      test_->MorphString();
9025    }
9026   private:
9027     RegExpStringModificationTest* test_;
9028  };
9029
9030  void MorphString() {
9031    block_->Wait();
9032    while (morphs_during_regexp_ < kRequiredModifications &&
9033           morphs_ < kMaxModifications) {
9034      {
9035        v8::Locker lock;
9036        // Swap string between ascii and two-byte representation.
9037        i::String* string = *input_;
9038        MorphAString(string, &ascii_resource_, &uc16_resource_);
9039        morphs_++;
9040      }
9041      i::OS::Sleep(1);
9042    }
9043    morph_success_ = true;
9044  }
9045
9046  void LongRunningRegExp() {
9047    block_->Signal();  // Enable morphing thread on next preemption.
9048    while (morphs_during_regexp_ < kRequiredModifications &&
9049           morphs_ < kMaxModifications) {
9050      int morphs_before = morphs_;
9051      {
9052        // Match 15-30 "a"'s against 14 and a "b".
9053        const char* c_source =
9054            "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
9055            ".exec(input) === null";
9056        Local<String> source = String::New(c_source);
9057        Local<Script> script = Script::Compile(source);
9058        Local<Value> result = script->Run();
9059        CHECK(result->IsTrue());
9060      }
9061      int morphs_after = morphs_;
9062      morphs_during_regexp_ += morphs_after - morphs_before;
9063    }
9064    regexp_success_ = true;
9065  }
9066
9067  i::uc16 two_byte_content_[15];
9068  i::Semaphore* block_;
9069  int morphs_;
9070  int morphs_during_regexp_;
9071  bool regexp_success_;
9072  bool morph_success_;
9073  i::Handle<i::String> input_;
9074  AsciiVectorResource ascii_resource_;
9075  UC16VectorResource uc16_resource_;
9076};
9077
9078
9079// Test that a regular expression execution can be interrupted and
9080// the string changed without failing.
9081TEST(RegExpStringModification) {
9082  v8::Locker lock;
9083  v8::V8::Initialize();
9084  v8::HandleScope scope;
9085  Local<Context> local_env;
9086  {
9087    LocalContext env;
9088    local_env = env.local();
9089  }
9090
9091  // Local context should still be live.
9092  CHECK(!local_env.IsEmpty());
9093  local_env->Enter();
9094
9095  // Should complete without problems.
9096  RegExpStringModificationTest().RunTest();
9097
9098  local_env->Exit();
9099}
9100
9101
9102// Test that we can set a property on the global object even if there
9103// is a read-only property in the prototype chain.
9104TEST(ReadOnlyPropertyInGlobalProto) {
9105  v8::HandleScope scope;
9106  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
9107  LocalContext context(0, templ);
9108  v8::Handle<v8::Object> global = context->Global();
9109  v8::Handle<v8::Object> global_proto =
9110      v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
9111  global_proto->Set(v8_str("x"), v8::Integer::New(0), v8::ReadOnly);
9112  global_proto->Set(v8_str("y"), v8::Integer::New(0), v8::ReadOnly);
9113  // Check without 'eval' or 'with'.
9114  v8::Handle<v8::Value> res =
9115      CompileRun("function f() { x = 42; return x; }; f()");
9116  // Check with 'eval'.
9117  res = CompileRun("function f() { eval('1'); y = 42; return y; }; f()");
9118  CHECK_EQ(v8::Integer::New(42), res);
9119  // Check with 'with'.
9120  res = CompileRun("function f() { with (this) { y = 42 }; return y; }; f()");
9121  CHECK_EQ(v8::Integer::New(42), res);
9122}
9123
9124static int force_set_set_count = 0;
9125static int force_set_get_count = 0;
9126bool pass_on_get = false;
9127
9128static v8::Handle<v8::Value> ForceSetGetter(v8::Local<v8::String> name,
9129                                            const v8::AccessorInfo& info) {
9130  force_set_get_count++;
9131  if (pass_on_get) {
9132    return v8::Handle<v8::Value>();
9133  } else {
9134    return v8::Int32::New(3);
9135  }
9136}
9137
9138static void ForceSetSetter(v8::Local<v8::String> name,
9139                           v8::Local<v8::Value> value,
9140                           const v8::AccessorInfo& info) {
9141  force_set_set_count++;
9142}
9143
9144static v8::Handle<v8::Value> ForceSetInterceptSetter(
9145    v8::Local<v8::String> name,
9146    v8::Local<v8::Value> value,
9147    const v8::AccessorInfo& info) {
9148  force_set_set_count++;
9149  return v8::Undefined();
9150}
9151
9152TEST(ForceSet) {
9153  force_set_get_count = 0;
9154  force_set_set_count = 0;
9155  pass_on_get = false;
9156
9157  v8::HandleScope scope;
9158  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
9159  v8::Handle<v8::String> access_property = v8::String::New("a");
9160  templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
9161  LocalContext context(NULL, templ);
9162  v8::Handle<v8::Object> global = context->Global();
9163
9164  // Ordinary properties
9165  v8::Handle<v8::String> simple_property = v8::String::New("p");
9166  global->Set(simple_property, v8::Int32::New(4), v8::ReadOnly);
9167  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
9168  // This should fail because the property is read-only
9169  global->Set(simple_property, v8::Int32::New(5));
9170  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
9171  // This should succeed even though the property is read-only
9172  global->ForceSet(simple_property, v8::Int32::New(6));
9173  CHECK_EQ(6, global->Get(simple_property)->Int32Value());
9174
9175  // Accessors
9176  CHECK_EQ(0, force_set_set_count);
9177  CHECK_EQ(0, force_set_get_count);
9178  CHECK_EQ(3, global->Get(access_property)->Int32Value());
9179  // CHECK_EQ the property shouldn't override it, just call the setter
9180  // which in this case does nothing.
9181  global->Set(access_property, v8::Int32::New(7));
9182  CHECK_EQ(3, global->Get(access_property)->Int32Value());
9183  CHECK_EQ(1, force_set_set_count);
9184  CHECK_EQ(2, force_set_get_count);
9185  // Forcing the property to be set should override the accessor without
9186  // calling it
9187  global->ForceSet(access_property, v8::Int32::New(8));
9188  CHECK_EQ(8, global->Get(access_property)->Int32Value());
9189  CHECK_EQ(1, force_set_set_count);
9190  CHECK_EQ(2, force_set_get_count);
9191}
9192
9193TEST(ForceSetWithInterceptor) {
9194  force_set_get_count = 0;
9195  force_set_set_count = 0;
9196  pass_on_get = false;
9197
9198  v8::HandleScope scope;
9199  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
9200  templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
9201  LocalContext context(NULL, templ);
9202  v8::Handle<v8::Object> global = context->Global();
9203
9204  v8::Handle<v8::String> some_property = v8::String::New("a");
9205  CHECK_EQ(0, force_set_set_count);
9206  CHECK_EQ(0, force_set_get_count);
9207  CHECK_EQ(3, global->Get(some_property)->Int32Value());
9208  // Setting the property shouldn't override it, just call the setter
9209  // which in this case does nothing.
9210  global->Set(some_property, v8::Int32::New(7));
9211  CHECK_EQ(3, global->Get(some_property)->Int32Value());
9212  CHECK_EQ(1, force_set_set_count);
9213  CHECK_EQ(2, force_set_get_count);
9214  // Getting the property when the interceptor returns an empty handle
9215  // should yield undefined, since the property isn't present on the
9216  // object itself yet.
9217  pass_on_get = true;
9218  CHECK(global->Get(some_property)->IsUndefined());
9219  CHECK_EQ(1, force_set_set_count);
9220  CHECK_EQ(3, force_set_get_count);
9221  // Forcing the property to be set should cause the value to be
9222  // set locally without calling the interceptor.
9223  global->ForceSet(some_property, v8::Int32::New(8));
9224  CHECK_EQ(8, global->Get(some_property)->Int32Value());
9225  CHECK_EQ(1, force_set_set_count);
9226  CHECK_EQ(4, force_set_get_count);
9227  // Reenabling the interceptor should cause it to take precedence over
9228  // the property
9229  pass_on_get = false;
9230  CHECK_EQ(3, global->Get(some_property)->Int32Value());
9231  CHECK_EQ(1, force_set_set_count);
9232  CHECK_EQ(5, force_set_get_count);
9233  // The interceptor should also work for other properties
9234  CHECK_EQ(3, global->Get(v8::String::New("b"))->Int32Value());
9235  CHECK_EQ(1, force_set_set_count);
9236  CHECK_EQ(6, force_set_get_count);
9237}
9238
9239
9240THREADED_TEST(ForceDelete) {
9241  v8::HandleScope scope;
9242  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
9243  LocalContext context(NULL, templ);
9244  v8::Handle<v8::Object> global = context->Global();
9245
9246  // Ordinary properties
9247  v8::Handle<v8::String> simple_property = v8::String::New("p");
9248  global->Set(simple_property, v8::Int32::New(4), v8::DontDelete);
9249  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
9250  // This should fail because the property is dont-delete.
9251  CHECK(!global->Delete(simple_property));
9252  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
9253  // This should succeed even though the property is dont-delete.
9254  CHECK(global->ForceDelete(simple_property));
9255  CHECK(global->Get(simple_property)->IsUndefined());
9256}
9257
9258
9259static int force_delete_interceptor_count = 0;
9260static bool pass_on_delete = false;
9261
9262
9263static v8::Handle<v8::Boolean> ForceDeleteDeleter(
9264    v8::Local<v8::String> name,
9265    const v8::AccessorInfo& info) {
9266  force_delete_interceptor_count++;
9267  if (pass_on_delete) {
9268    return v8::Handle<v8::Boolean>();
9269  } else {
9270    return v8::True();
9271  }
9272}
9273
9274
9275THREADED_TEST(ForceDeleteWithInterceptor) {
9276  force_delete_interceptor_count = 0;
9277  pass_on_delete = false;
9278
9279  v8::HandleScope scope;
9280  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
9281  templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
9282  LocalContext context(NULL, templ);
9283  v8::Handle<v8::Object> global = context->Global();
9284
9285  v8::Handle<v8::String> some_property = v8::String::New("a");
9286  global->Set(some_property, v8::Integer::New(42), v8::DontDelete);
9287
9288  // Deleting a property should get intercepted and nothing should
9289  // happen.
9290  CHECK_EQ(0, force_delete_interceptor_count);
9291  CHECK(global->Delete(some_property));
9292  CHECK_EQ(1, force_delete_interceptor_count);
9293  CHECK_EQ(42, global->Get(some_property)->Int32Value());
9294  // Deleting the property when the interceptor returns an empty
9295  // handle should not delete the property since it is DontDelete.
9296  pass_on_delete = true;
9297  CHECK(!global->Delete(some_property));
9298  CHECK_EQ(2, force_delete_interceptor_count);
9299  CHECK_EQ(42, global->Get(some_property)->Int32Value());
9300  // Forcing the property to be deleted should delete the value
9301  // without calling the interceptor.
9302  CHECK(global->ForceDelete(some_property));
9303  CHECK(global->Get(some_property)->IsUndefined());
9304  CHECK_EQ(2, force_delete_interceptor_count);
9305}
9306
9307
9308// Make sure that forcing a delete invalidates any IC stubs, so we
9309// don't read the hole value.
9310THREADED_TEST(ForceDeleteIC) {
9311  v8::HandleScope scope;
9312  LocalContext context;
9313  // Create a DontDelete variable on the global object.
9314  CompileRun("this.__proto__ = { foo: 'horse' };"
9315             "var foo = 'fish';"
9316             "function f() { return foo.length; }");
9317  // Initialize the IC for foo in f.
9318  CompileRun("for (var i = 0; i < 4; i++) f();");
9319  // Make sure the value of foo is correct before the deletion.
9320  CHECK_EQ(4, CompileRun("f()")->Int32Value());
9321  // Force the deletion of foo.
9322  CHECK(context->Global()->ForceDelete(v8_str("foo")));
9323  // Make sure the value for foo is read from the prototype, and that
9324  // we don't get in trouble with reading the deleted cell value
9325  // sentinel.
9326  CHECK_EQ(5, CompileRun("f()")->Int32Value());
9327}
9328
9329
9330v8::Persistent<Context> calling_context0;
9331v8::Persistent<Context> calling_context1;
9332v8::Persistent<Context> calling_context2;
9333
9334
9335// Check that the call to the callback is initiated in
9336// calling_context2, the directly calling context is calling_context1
9337// and the callback itself is in calling_context0.
9338static v8::Handle<Value> GetCallingContextCallback(const v8::Arguments& args) {
9339  ApiTestFuzzer::Fuzz();
9340  CHECK(Context::GetCurrent() == calling_context0);
9341  CHECK(Context::GetCalling() == calling_context1);
9342  CHECK(Context::GetEntered() == calling_context2);
9343  return v8::Integer::New(42);
9344}
9345
9346
9347THREADED_TEST(GetCallingContext) {
9348  v8::HandleScope scope;
9349
9350  calling_context0 = Context::New();
9351  calling_context1 = Context::New();
9352  calling_context2 = Context::New();
9353
9354  // Allow cross-domain access.
9355  Local<String> token = v8_str("<security token>");
9356  calling_context0->SetSecurityToken(token);
9357  calling_context1->SetSecurityToken(token);
9358  calling_context2->SetSecurityToken(token);
9359
9360  // Create an object with a C++ callback in context0.
9361  calling_context0->Enter();
9362  Local<v8::FunctionTemplate> callback_templ =
9363      v8::FunctionTemplate::New(GetCallingContextCallback);
9364  calling_context0->Global()->Set(v8_str("callback"),
9365                                  callback_templ->GetFunction());
9366  calling_context0->Exit();
9367
9368  // Expose context0 in context1 and setup a function that calls the
9369  // callback function.
9370  calling_context1->Enter();
9371  calling_context1->Global()->Set(v8_str("context0"),
9372                                  calling_context0->Global());
9373  CompileRun("function f() { context0.callback() }");
9374  calling_context1->Exit();
9375
9376  // Expose context1 in context2 and call the callback function in
9377  // context0 indirectly through f in context1.
9378  calling_context2->Enter();
9379  calling_context2->Global()->Set(v8_str("context1"),
9380                                  calling_context1->Global());
9381  CompileRun("context1.f()");
9382  calling_context2->Exit();
9383
9384  // Dispose the contexts to allow them to be garbage collected.
9385  calling_context0.Dispose();
9386  calling_context1.Dispose();
9387  calling_context2.Dispose();
9388  calling_context0.Clear();
9389  calling_context1.Clear();
9390  calling_context2.Clear();
9391}
9392
9393
9394// Check that a variable declaration with no explicit initialization
9395// value does not shadow an existing property in the prototype chain.
9396//
9397// This is consistent with Firefox and Safari.
9398//
9399// See http://crbug.com/12548.
9400THREADED_TEST(InitGlobalVarInProtoChain) {
9401  v8::HandleScope scope;
9402  LocalContext context;
9403  // Introduce a variable in the prototype chain.
9404  CompileRun("__proto__.x = 42");
9405  v8::Handle<v8::Value> result = CompileRun("var x; x");
9406  CHECK(!result->IsUndefined());
9407  CHECK_EQ(42, result->Int32Value());
9408}
9409
9410
9411// Regression test for issue 398.
9412// If a function is added to an object, creating a constant function
9413// field, and the result is cloned, replacing the constant function on the
9414// original should not affect the clone.
9415// See http://code.google.com/p/v8/issues/detail?id=398
9416THREADED_TEST(ReplaceConstantFunction) {
9417  v8::HandleScope scope;
9418  LocalContext context;
9419  v8::Handle<v8::Object> obj = v8::Object::New();
9420  v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
9421  v8::Handle<v8::String> foo_string = v8::String::New("foo");
9422  obj->Set(foo_string, func_templ->GetFunction());
9423  v8::Handle<v8::Object> obj_clone = obj->Clone();
9424  obj_clone->Set(foo_string, v8::String::New("Hello"));
9425  CHECK(!obj->Get(foo_string)->IsUndefined());
9426}
9427
9428
9429// Regression test for http://crbug.com/16276.
9430THREADED_TEST(Regress16276) {
9431  v8::HandleScope scope;
9432  LocalContext context;
9433  // Force the IC in f to be a dictionary load IC.
9434  CompileRun("function f(obj) { return obj.x; }\n"
9435             "var obj = { x: { foo: 42 }, y: 87 };\n"
9436             "var x = obj.x;\n"
9437             "delete obj.y;\n"
9438             "for (var i = 0; i < 5; i++) f(obj);");
9439  // Detach the global object to make 'this' refer directly to the
9440  // global object (not the proxy), and make sure that the dictionary
9441  // load IC doesn't mess up loading directly from the global object.
9442  context->DetachGlobal();
9443  CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value());
9444}
9445
9446
9447THREADED_TEST(PixelArray) {
9448  v8::HandleScope scope;
9449  LocalContext context;
9450  const int kElementCount = 260;
9451  uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
9452  i::Handle<i::PixelArray> pixels = i::Factory::NewPixelArray(kElementCount,
9453                                                              pixel_data);
9454  i::Heap::CollectAllGarbage(false);  // Force GC to trigger verification.
9455  for (int i = 0; i < kElementCount; i++) {
9456    pixels->set(i, i % 256);
9457  }
9458  i::Heap::CollectAllGarbage(false);  // Force GC to trigger verification.
9459  for (int i = 0; i < kElementCount; i++) {
9460    CHECK_EQ(i % 256, pixels->get(i));
9461    CHECK_EQ(i % 256, pixel_data[i]);
9462  }
9463
9464  v8::Handle<v8::Object> obj = v8::Object::New();
9465  i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
9466  // Set the elements to be the pixels.
9467  // jsobj->set_elements(*pixels);
9468  obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
9469  CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1))->value());
9470  obj->Set(v8_str("field"), v8::Int32::New(1503));
9471  context->Global()->Set(v8_str("pixels"), obj);
9472  v8::Handle<v8::Value> result = CompileRun("pixels.field");
9473  CHECK_EQ(1503, result->Int32Value());
9474  result = CompileRun("pixels[1]");
9475  CHECK_EQ(1, result->Int32Value());
9476
9477  result = CompileRun("var sum = 0;"
9478                      "for (var i = 0; i < 8; i++) {"
9479                      "  sum += pixels[i] = pixels[i] = -i;"
9480                      "}"
9481                      "sum;");
9482  CHECK_EQ(-28, result->Int32Value());
9483
9484  result = CompileRun("var sum = 0;"
9485                      "for (var i = 0; i < 8; i++) {"
9486                      "  sum += pixels[i] = pixels[i] = 0;"
9487                      "}"
9488                      "sum;");
9489  CHECK_EQ(0, result->Int32Value());
9490
9491  result = CompileRun("var sum = 0;"
9492                      "for (var i = 0; i < 8; i++) {"
9493                      "  sum += pixels[i] = pixels[i] = 255;"
9494                      "}"
9495                      "sum;");
9496  CHECK_EQ(8 * 255, result->Int32Value());
9497
9498  result = CompileRun("var sum = 0;"
9499                      "for (var i = 0; i < 8; i++) {"
9500                      "  sum += pixels[i] = pixels[i] = 256 + i;"
9501                      "}"
9502                      "sum;");
9503  CHECK_EQ(2076, result->Int32Value());
9504
9505  result = CompileRun("var sum = 0;"
9506                      "for (var i = 0; i < 8; i++) {"
9507                      "  sum += pixels[i] = pixels[i] = i;"
9508                      "}"
9509                      "sum;");
9510  CHECK_EQ(28, result->Int32Value());
9511
9512  result = CompileRun("var sum = 0;"
9513                      "for (var i = 0; i < 8; i++) {"
9514                      "  sum += pixels[i];"
9515                      "}"
9516                      "sum;");
9517  CHECK_EQ(28, result->Int32Value());
9518
9519  i::Handle<i::Smi> value(i::Smi::FromInt(2));
9520  i::SetElement(jsobj, 1, value);
9521  CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(1))->value());
9522  *value.location() = i::Smi::FromInt(256);
9523  i::SetElement(jsobj, 1, value);
9524  CHECK_EQ(255, i::Smi::cast(jsobj->GetElement(1))->value());
9525  *value.location() = i::Smi::FromInt(-1);
9526  i::SetElement(jsobj, 1, value);
9527  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1))->value());
9528
9529  result = CompileRun("for (var i = 0; i < 8; i++) {"
9530                      "  pixels[i] = (i * 65) - 109;"
9531                      "}"
9532                      "pixels[1] + pixels[6];");
9533  CHECK_EQ(255, result->Int32Value());
9534  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0))->value());
9535  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1))->value());
9536  CHECK_EQ(21, i::Smi::cast(jsobj->GetElement(2))->value());
9537  CHECK_EQ(86, i::Smi::cast(jsobj->GetElement(3))->value());
9538  CHECK_EQ(151, i::Smi::cast(jsobj->GetElement(4))->value());
9539  CHECK_EQ(216, i::Smi::cast(jsobj->GetElement(5))->value());
9540  CHECK_EQ(255, i::Smi::cast(jsobj->GetElement(6))->value());
9541  CHECK_EQ(255, i::Smi::cast(jsobj->GetElement(7))->value());
9542  result = CompileRun("var sum = 0;"
9543                      "for (var i = 0; i < 8; i++) {"
9544                      "  sum += pixels[i];"
9545                      "}"
9546                      "sum;");
9547  CHECK_EQ(984, result->Int32Value());
9548
9549  result = CompileRun("for (var i = 0; i < 8; i++) {"
9550                      "  pixels[i] = (i * 1.1);"
9551                      "}"
9552                      "pixels[1] + pixels[6];");
9553  CHECK_EQ(8, result->Int32Value());
9554  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0))->value());
9555  CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1))->value());
9556  CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(2))->value());
9557  CHECK_EQ(3, i::Smi::cast(jsobj->GetElement(3))->value());
9558  CHECK_EQ(4, i::Smi::cast(jsobj->GetElement(4))->value());
9559  CHECK_EQ(6, i::Smi::cast(jsobj->GetElement(5))->value());
9560  CHECK_EQ(7, i::Smi::cast(jsobj->GetElement(6))->value());
9561  CHECK_EQ(8, i::Smi::cast(jsobj->GetElement(7))->value());
9562
9563  result = CompileRun("for (var i = 0; i < 8; i++) {"
9564                      "  pixels[7] = undefined;"
9565                      "}"
9566                      "pixels[7];");
9567  CHECK_EQ(0, result->Int32Value());
9568  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(7))->value());
9569
9570  result = CompileRun("for (var i = 0; i < 8; i++) {"
9571                      "  pixels[6] = '2.3';"
9572                      "}"
9573                      "pixels[6];");
9574  CHECK_EQ(2, result->Int32Value());
9575  CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(6))->value());
9576
9577  result = CompileRun("for (var i = 0; i < 8; i++) {"
9578                      "  pixels[5] = NaN;"
9579                      "}"
9580                      "pixels[5];");
9581  CHECK_EQ(0, result->Int32Value());
9582  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5))->value());
9583
9584  result = CompileRun("for (var i = 0; i < 8; i++) {"
9585                      "  pixels[8] = Infinity;"
9586                      "}"
9587                      "pixels[8];");
9588  CHECK_EQ(255, result->Int32Value());
9589  CHECK_EQ(255, i::Smi::cast(jsobj->GetElement(8))->value());
9590
9591  result = CompileRun("for (var i = 0; i < 8; i++) {"
9592                      "  pixels[9] = -Infinity;"
9593                      "}"
9594                      "pixels[9];");
9595  CHECK_EQ(0, result->Int32Value());
9596  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(9))->value());
9597
9598  result = CompileRun("pixels[3] = 33;"
9599                      "delete pixels[3];"
9600                      "pixels[3];");
9601  CHECK_EQ(33, result->Int32Value());
9602
9603  result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
9604                      "pixels[2] = 12; pixels[3] = 13;"
9605                      "pixels.__defineGetter__('2',"
9606                      "function() { return 120; });"
9607                      "pixels[2];");
9608  CHECK_EQ(12, result->Int32Value());
9609
9610  result = CompileRun("var js_array = new Array(40);"
9611                      "js_array[0] = 77;"
9612                      "js_array;");
9613  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
9614
9615  result = CompileRun("pixels[1] = 23;"
9616                      "pixels.__proto__ = [];"
9617                      "js_array.__proto__ = pixels;"
9618                      "js_array.concat(pixels);");
9619  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
9620  CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
9621
9622  result = CompileRun("pixels[1] = 23;");
9623  CHECK_EQ(23, result->Int32Value());
9624
9625  // Test for index greater than 255.  Regression test for:
9626  // http://code.google.com/p/chromium/issues/detail?id=26337.
9627  result = CompileRun("pixels[256] = 255;");
9628  CHECK_EQ(255, result->Int32Value());
9629  result = CompileRun("var i = 0;"
9630                      "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
9631                      "i");
9632  CHECK_EQ(255, result->Int32Value());
9633
9634  free(pixel_data);
9635}
9636
9637
9638THREADED_TEST(PixelArrayInfo) {
9639  v8::HandleScope scope;
9640  LocalContext context;
9641  for (int size = 0; size < 100; size += 10) {
9642    uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
9643    v8::Handle<v8::Object> obj = v8::Object::New();
9644    obj->SetIndexedPropertiesToPixelData(pixel_data, size);
9645    CHECK(obj->HasIndexedPropertiesInPixelData());
9646    CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
9647    CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
9648    free(pixel_data);
9649  }
9650}
9651
9652
9653static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
9654  switch (array_type) {
9655    case v8::kExternalByteArray:
9656    case v8::kExternalUnsignedByteArray:
9657      return 1;
9658      break;
9659    case v8::kExternalShortArray:
9660    case v8::kExternalUnsignedShortArray:
9661      return 2;
9662      break;
9663    case v8::kExternalIntArray:
9664    case v8::kExternalUnsignedIntArray:
9665    case v8::kExternalFloatArray:
9666      return 4;
9667      break;
9668    default:
9669      UNREACHABLE();
9670      return -1;
9671  }
9672  UNREACHABLE();
9673  return -1;
9674}
9675
9676
9677template <class ExternalArrayClass, class ElementType>
9678static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
9679                                    int64_t low,
9680                                    int64_t high) {
9681  v8::HandleScope scope;
9682  LocalContext context;
9683  const int kElementCount = 40;
9684  int element_size = ExternalArrayElementSize(array_type);
9685  ElementType* array_data =
9686      static_cast<ElementType*>(malloc(kElementCount * element_size));
9687  i::Handle<ExternalArrayClass> array =
9688      i::Handle<ExternalArrayClass>::cast(
9689          i::Factory::NewExternalArray(kElementCount, array_type, array_data));
9690  i::Heap::CollectAllGarbage(false);  // Force GC to trigger verification.
9691  for (int i = 0; i < kElementCount; i++) {
9692    array->set(i, static_cast<ElementType>(i));
9693  }
9694  i::Heap::CollectAllGarbage(false);  // Force GC to trigger verification.
9695  for (int i = 0; i < kElementCount; i++) {
9696    CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array->get(i)));
9697    CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
9698  }
9699
9700  v8::Handle<v8::Object> obj = v8::Object::New();
9701  i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
9702  // Set the elements to be the external array.
9703  obj->SetIndexedPropertiesToExternalArrayData(array_data,
9704                                               array_type,
9705                                               kElementCount);
9706  CHECK_EQ(1, static_cast<int>(jsobj->GetElement(1)->Number()));
9707  obj->Set(v8_str("field"), v8::Int32::New(1503));
9708  context->Global()->Set(v8_str("ext_array"), obj);
9709  v8::Handle<v8::Value> result = CompileRun("ext_array.field");
9710  CHECK_EQ(1503, result->Int32Value());
9711  result = CompileRun("ext_array[1]");
9712  CHECK_EQ(1, result->Int32Value());
9713
9714  // Check pass through of assigned smis
9715  result = CompileRun("var sum = 0;"
9716                      "for (var i = 0; i < 8; i++) {"
9717                      "  sum += ext_array[i] = ext_array[i] = -i;"
9718                      "}"
9719                      "sum;");
9720  CHECK_EQ(-28, result->Int32Value());
9721
9722  // Check assigned smis
9723  result = CompileRun("for (var i = 0; i < 8; i++) {"
9724                      "  ext_array[i] = i;"
9725                      "}"
9726                      "var sum = 0;"
9727                      "for (var i = 0; i < 8; i++) {"
9728                      "  sum += ext_array[i];"
9729                      "}"
9730                      "sum;");
9731  CHECK_EQ(28, result->Int32Value());
9732
9733  // Check assigned smis in reverse order
9734  result = CompileRun("for (var i = 8; --i >= 0; ) {"
9735                      "  ext_array[i] = i;"
9736                      "}"
9737                      "var sum = 0;"
9738                      "for (var i = 0; i < 8; i++) {"
9739                      "  sum += ext_array[i];"
9740                      "}"
9741                      "sum;");
9742  CHECK_EQ(28, result->Int32Value());
9743
9744  // Check pass through of assigned HeapNumbers
9745  result = CompileRun("var sum = 0;"
9746                      "for (var i = 0; i < 16; i+=2) {"
9747                      "  sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
9748                      "}"
9749                      "sum;");
9750  CHECK_EQ(-28, result->Int32Value());
9751
9752  // Check assigned HeapNumbers
9753  result = CompileRun("for (var i = 0; i < 16; i+=2) {"
9754                      "  ext_array[i] = (i * 0.5);"
9755                      "}"
9756                      "var sum = 0;"
9757                      "for (var i = 0; i < 16; i+=2) {"
9758                      "  sum += ext_array[i];"
9759                      "}"
9760                      "sum;");
9761  CHECK_EQ(28, result->Int32Value());
9762
9763  // Check assigned HeapNumbers in reverse order
9764  result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
9765                      "  ext_array[i] = (i * 0.5);"
9766                      "}"
9767                      "var sum = 0;"
9768                      "for (var i = 0; i < 16; i+=2) {"
9769                      "  sum += ext_array[i];"
9770                      "}"
9771                      "sum;");
9772  CHECK_EQ(28, result->Int32Value());
9773
9774  i::ScopedVector<char> test_buf(1024);
9775
9776  // Check legal boundary conditions.
9777  // The repeated loads and stores ensure the ICs are exercised.
9778  const char* boundary_program =
9779      "var res = 0;"
9780      "for (var i = 0; i < 16; i++) {"
9781      "  ext_array[i] = %lld;"
9782      "  if (i > 8) {"
9783      "    res = ext_array[i];"
9784      "  }"
9785      "}"
9786      "res;";
9787  i::OS::SNPrintF(test_buf,
9788                  boundary_program,
9789                  low);
9790  result = CompileRun(test_buf.start());
9791  CHECK_EQ(low, result->IntegerValue());
9792
9793  i::OS::SNPrintF(test_buf,
9794                  boundary_program,
9795                  high);
9796  result = CompileRun(test_buf.start());
9797  CHECK_EQ(high, result->IntegerValue());
9798
9799  // Check misprediction of type in IC.
9800  result = CompileRun("var tmp_array = ext_array;"
9801                      "var sum = 0;"
9802                      "for (var i = 0; i < 8; i++) {"
9803                      "  tmp_array[i] = i;"
9804                      "  sum += tmp_array[i];"
9805                      "  if (i == 4) {"
9806                      "    tmp_array = {};"
9807                      "  }"
9808                      "}"
9809                      "sum;");
9810  i::Heap::CollectAllGarbage(false);  // Force GC to trigger verification.
9811  CHECK_EQ(28, result->Int32Value());
9812
9813  // Make sure out-of-range loads do not throw.
9814  i::OS::SNPrintF(test_buf,
9815                  "var caught_exception = false;"
9816                  "try {"
9817                  "  ext_array[%d];"
9818                  "} catch (e) {"
9819                  "  caught_exception = true;"
9820                  "}"
9821                  "caught_exception;",
9822                  kElementCount);
9823  result = CompileRun(test_buf.start());
9824  CHECK_EQ(false, result->BooleanValue());
9825
9826  // Make sure out-of-range stores do not throw.
9827  i::OS::SNPrintF(test_buf,
9828                  "var caught_exception = false;"
9829                  "try {"
9830                  "  ext_array[%d] = 1;"
9831                  "} catch (e) {"
9832                  "  caught_exception = true;"
9833                  "}"
9834                  "caught_exception;",
9835                  kElementCount);
9836  result = CompileRun(test_buf.start());
9837  CHECK_EQ(false, result->BooleanValue());
9838
9839  // Check other boundary conditions, values and operations.
9840  result = CompileRun("for (var i = 0; i < 8; i++) {"
9841                      "  ext_array[7] = undefined;"
9842                      "}"
9843                      "ext_array[7];");
9844  CHECK_EQ(0, result->Int32Value());
9845  CHECK_EQ(0, static_cast<int>(jsobj->GetElement(7)->Number()));
9846
9847  result = CompileRun("for (var i = 0; i < 8; i++) {"
9848                      "  ext_array[6] = '2.3';"
9849                      "}"
9850                      "ext_array[6];");
9851  CHECK_EQ(2, result->Int32Value());
9852  CHECK_EQ(2, static_cast<int>(jsobj->GetElement(6)->Number()));
9853
9854  if (array_type != v8::kExternalFloatArray) {
9855    // Though the specification doesn't state it, be explicit about
9856    // converting NaNs and +/-Infinity to zero.
9857    result = CompileRun("for (var i = 0; i < 8; i++) {"
9858                        "  ext_array[i] = 5;"
9859                        "}"
9860                        "for (var i = 0; i < 8; i++) {"
9861                        "  ext_array[i] = NaN;"
9862                        "}"
9863                        "ext_array[5];");
9864    CHECK_EQ(0, result->Int32Value());
9865    CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5))->value());
9866
9867    result = CompileRun("for (var i = 0; i < 8; i++) {"
9868                        "  ext_array[i] = 5;"
9869                        "}"
9870                        "for (var i = 0; i < 8; i++) {"
9871                        "  ext_array[i] = Infinity;"
9872                        "}"
9873                        "ext_array[5];");
9874    CHECK_EQ(0, result->Int32Value());
9875    CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5))->value());
9876
9877    result = CompileRun("for (var i = 0; i < 8; i++) {"
9878                        "  ext_array[i] = 5;"
9879                        "}"
9880                        "for (var i = 0; i < 8; i++) {"
9881                        "  ext_array[i] = -Infinity;"
9882                        "}"
9883                        "ext_array[5];");
9884    CHECK_EQ(0, result->Int32Value());
9885    CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5))->value());
9886  }
9887
9888  result = CompileRun("ext_array[3] = 33;"
9889                      "delete ext_array[3];"
9890                      "ext_array[3];");
9891  CHECK_EQ(33, result->Int32Value());
9892
9893  result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
9894                      "ext_array[2] = 12; ext_array[3] = 13;"
9895                      "ext_array.__defineGetter__('2',"
9896                      "function() { return 120; });"
9897                      "ext_array[2];");
9898  CHECK_EQ(12, result->Int32Value());
9899
9900  result = CompileRun("var js_array = new Array(40);"
9901                      "js_array[0] = 77;"
9902                      "js_array;");
9903  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
9904
9905  result = CompileRun("ext_array[1] = 23;"
9906                      "ext_array.__proto__ = [];"
9907                      "js_array.__proto__ = ext_array;"
9908                      "js_array.concat(ext_array);");
9909  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
9910  CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
9911
9912  result = CompileRun("ext_array[1] = 23;");
9913  CHECK_EQ(23, result->Int32Value());
9914
9915  // Test more complex manipulations which cause eax to contain values
9916  // that won't be completely overwritten by loads from the arrays.
9917  // This catches bugs in the instructions used for the KeyedLoadIC
9918  // for byte and word types.
9919  {
9920    const int kXSize = 300;
9921    const int kYSize = 300;
9922    const int kLargeElementCount = kXSize * kYSize * 4;
9923    ElementType* large_array_data =
9924        static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
9925    i::Handle<ExternalArrayClass> large_array =
9926        i::Handle<ExternalArrayClass>::cast(
9927            i::Factory::NewExternalArray(kLargeElementCount,
9928                                         array_type,
9929                                         array_data));
9930    v8::Handle<v8::Object> large_obj = v8::Object::New();
9931    // Set the elements to be the external array.
9932    large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
9933                                                       array_type,
9934                                                       kLargeElementCount);
9935    context->Global()->Set(v8_str("large_array"), large_obj);
9936    // Initialize contents of a few rows.
9937    for (int x = 0; x < 300; x++) {
9938      int row = 0;
9939      int offset = row * 300 * 4;
9940      large_array_data[offset + 4 * x + 0] = (ElementType) 127;
9941      large_array_data[offset + 4 * x + 1] = (ElementType) 0;
9942      large_array_data[offset + 4 * x + 2] = (ElementType) 0;
9943      large_array_data[offset + 4 * x + 3] = (ElementType) 127;
9944      row = 150;
9945      offset = row * 300 * 4;
9946      large_array_data[offset + 4 * x + 0] = (ElementType) 127;
9947      large_array_data[offset + 4 * x + 1] = (ElementType) 0;
9948      large_array_data[offset + 4 * x + 2] = (ElementType) 0;
9949      large_array_data[offset + 4 * x + 3] = (ElementType) 127;
9950      row = 298;
9951      offset = row * 300 * 4;
9952      large_array_data[offset + 4 * x + 0] = (ElementType) 127;
9953      large_array_data[offset + 4 * x + 1] = (ElementType) 0;
9954      large_array_data[offset + 4 * x + 2] = (ElementType) 0;
9955      large_array_data[offset + 4 * x + 3] = (ElementType) 127;
9956    }
9957    // The goal of the code below is to make "offset" large enough
9958    // that the computation of the index (which goes into eax) has
9959    // high bits set which will not be overwritten by a byte or short
9960    // load.
9961    result = CompileRun("var failed = false;"
9962                        "var offset = 0;"
9963                        "for (var i = 0; i < 300; i++) {"
9964                        "  if (large_array[4 * i] != 127 ||"
9965                        "      large_array[4 * i + 1] != 0 ||"
9966                        "      large_array[4 * i + 2] != 0 ||"
9967                        "      large_array[4 * i + 3] != 127) {"
9968                        "    failed = true;"
9969                        "  }"
9970                        "}"
9971                        "offset = 150 * 300 * 4;"
9972                        "for (var i = 0; i < 300; i++) {"
9973                        "  if (large_array[offset + 4 * i] != 127 ||"
9974                        "      large_array[offset + 4 * i + 1] != 0 ||"
9975                        "      large_array[offset + 4 * i + 2] != 0 ||"
9976                        "      large_array[offset + 4 * i + 3] != 127) {"
9977                        "    failed = true;"
9978                        "  }"
9979                        "}"
9980                        "offset = 298 * 300 * 4;"
9981                        "for (var i = 0; i < 300; i++) {"
9982                        "  if (large_array[offset + 4 * i] != 127 ||"
9983                        "      large_array[offset + 4 * i + 1] != 0 ||"
9984                        "      large_array[offset + 4 * i + 2] != 0 ||"
9985                        "      large_array[offset + 4 * i + 3] != 127) {"
9986                        "    failed = true;"
9987                        "  }"
9988                        "}"
9989                        "!failed;");
9990    CHECK_EQ(true, result->BooleanValue());
9991    free(large_array_data);
9992  }
9993
9994  free(array_data);
9995}
9996
9997
9998THREADED_TEST(ExternalByteArray) {
9999  ExternalArrayTestHelper<v8::internal::ExternalByteArray, int8_t>(
10000      v8::kExternalByteArray,
10001      -128,
10002      127);
10003}
10004
10005
10006THREADED_TEST(ExternalUnsignedByteArray) {
10007  ExternalArrayTestHelper<v8::internal::ExternalUnsignedByteArray, uint8_t>(
10008      v8::kExternalUnsignedByteArray,
10009      0,
10010      255);
10011}
10012
10013
10014THREADED_TEST(ExternalShortArray) {
10015  ExternalArrayTestHelper<v8::internal::ExternalShortArray, int16_t>(
10016      v8::kExternalShortArray,
10017      -32768,
10018      32767);
10019}
10020
10021
10022THREADED_TEST(ExternalUnsignedShortArray) {
10023  ExternalArrayTestHelper<v8::internal::ExternalUnsignedShortArray, uint16_t>(
10024      v8::kExternalUnsignedShortArray,
10025      0,
10026      65535);
10027}
10028
10029
10030THREADED_TEST(ExternalIntArray) {
10031  ExternalArrayTestHelper<v8::internal::ExternalIntArray, int32_t>(
10032      v8::kExternalIntArray,
10033      INT_MIN,   // -2147483648
10034      INT_MAX);  //  2147483647
10035}
10036
10037
10038THREADED_TEST(ExternalUnsignedIntArray) {
10039  ExternalArrayTestHelper<v8::internal::ExternalUnsignedIntArray, uint32_t>(
10040      v8::kExternalUnsignedIntArray,
10041      0,
10042      UINT_MAX);  // 4294967295
10043}
10044
10045
10046THREADED_TEST(ExternalFloatArray) {
10047  ExternalArrayTestHelper<v8::internal::ExternalFloatArray, float>(
10048      v8::kExternalFloatArray,
10049      -500,
10050      500);
10051}
10052
10053
10054THREADED_TEST(ExternalArrays) {
10055  TestExternalByteArray();
10056  TestExternalUnsignedByteArray();
10057  TestExternalShortArray();
10058  TestExternalUnsignedShortArray();
10059  TestExternalIntArray();
10060  TestExternalUnsignedIntArray();
10061  TestExternalFloatArray();
10062}
10063
10064
10065void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
10066  v8::HandleScope scope;
10067  LocalContext context;
10068  for (int size = 0; size < 100; size += 10) {
10069    int element_size = ExternalArrayElementSize(array_type);
10070    void* external_data = malloc(size * element_size);
10071    v8::Handle<v8::Object> obj = v8::Object::New();
10072    obj->SetIndexedPropertiesToExternalArrayData(
10073        external_data, array_type, size);
10074    CHECK(obj->HasIndexedPropertiesInExternalArrayData());
10075    CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
10076    CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
10077    CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
10078    free(external_data);
10079  }
10080}
10081
10082
10083THREADED_TEST(ExternalArrayInfo) {
10084  ExternalArrayInfoTestHelper(v8::kExternalByteArray);
10085  ExternalArrayInfoTestHelper(v8::kExternalUnsignedByteArray);
10086  ExternalArrayInfoTestHelper(v8::kExternalShortArray);
10087  ExternalArrayInfoTestHelper(v8::kExternalUnsignedShortArray);
10088  ExternalArrayInfoTestHelper(v8::kExternalIntArray);
10089  ExternalArrayInfoTestHelper(v8::kExternalUnsignedIntArray);
10090  ExternalArrayInfoTestHelper(v8::kExternalFloatArray);
10091}
10092
10093
10094THREADED_TEST(ScriptContextDependence) {
10095  v8::HandleScope scope;
10096  LocalContext c1;
10097  const char *source = "foo";
10098  v8::Handle<v8::Script> dep = v8::Script::Compile(v8::String::New(source));
10099  v8::Handle<v8::Script> indep = v8::Script::New(v8::String::New(source));
10100  c1->Global()->Set(v8::String::New("foo"), v8::Integer::New(100));
10101  CHECK_EQ(dep->Run()->Int32Value(), 100);
10102  CHECK_EQ(indep->Run()->Int32Value(), 100);
10103  LocalContext c2;
10104  c2->Global()->Set(v8::String::New("foo"), v8::Integer::New(101));
10105  CHECK_EQ(dep->Run()->Int32Value(), 100);
10106  CHECK_EQ(indep->Run()->Int32Value(), 101);
10107}
10108
10109
10110THREADED_TEST(StackTrace) {
10111  v8::HandleScope scope;
10112  LocalContext context;
10113  v8::TryCatch try_catch;
10114  const char *source = "function foo() { FAIL.FAIL; }; foo();";
10115  v8::Handle<v8::String> src = v8::String::New(source);
10116  v8::Handle<v8::String> origin = v8::String::New("stack-trace-test");
10117  v8::Script::New(src, origin)->Run();
10118  CHECK(try_catch.HasCaught());
10119  v8::String::Utf8Value stack(try_catch.StackTrace());
10120  CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
10121}
10122
10123
10124// Checks that a StackFrame has certain expected values.
10125void checkStackFrame(const char* expected_script_name,
10126    const char* expected_func_name, int expected_line_number,
10127    int expected_column, bool is_eval, bool is_constructor,
10128    v8::Handle<v8::StackFrame> frame) {
10129  v8::HandleScope scope;
10130  v8::String::Utf8Value func_name(frame->GetFunctionName());
10131  v8::String::Utf8Value script_name(frame->GetScriptName());
10132  if (*script_name == NULL) {
10133    // The situation where there is no associated script, like for evals.
10134    CHECK(expected_script_name == NULL);
10135  } else {
10136    CHECK(strstr(*script_name, expected_script_name) != NULL);
10137  }
10138  CHECK(strstr(*func_name, expected_func_name) != NULL);
10139  CHECK_EQ(expected_line_number, frame->GetLineNumber());
10140  CHECK_EQ(expected_column, frame->GetColumn());
10141  CHECK_EQ(is_eval, frame->IsEval());
10142  CHECK_EQ(is_constructor, frame->IsConstructor());
10143}
10144
10145
10146v8::Handle<Value> AnalyzeStackInNativeCode(const v8::Arguments& args) {
10147  v8::HandleScope scope;
10148  const char* origin = "capture-stack-trace-test";
10149  const int kOverviewTest = 1;
10150  const int kDetailedTest = 2;
10151
10152  ASSERT(args.Length() == 1);
10153
10154  int testGroup = args[0]->Int32Value();
10155  if (testGroup == kOverviewTest) {
10156    v8::Handle<v8::StackTrace> stackTrace =
10157        v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kOverview);
10158    CHECK_EQ(4, stackTrace->GetFrameCount());
10159    checkStackFrame(origin, "bar", 2, 10, false, false,
10160                    stackTrace->GetFrame(0));
10161    checkStackFrame(origin, "foo", 6, 3, false, false,
10162                    stackTrace->GetFrame(1));
10163    checkStackFrame(NULL, "", 1, 1, false, false,
10164                    stackTrace->GetFrame(2));
10165    // The last frame is an anonymous function that has the initial call.
10166    checkStackFrame(origin, "", 8, 7, false, false,
10167                    stackTrace->GetFrame(3));
10168
10169    CHECK(stackTrace->AsArray()->IsArray());
10170  } else if (testGroup == kDetailedTest) {
10171    v8::Handle<v8::StackTrace> stackTrace =
10172        v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
10173    CHECK_EQ(4, stackTrace->GetFrameCount());
10174    checkStackFrame(origin, "bat", 4, 22, false, false,
10175                    stackTrace->GetFrame(0));
10176    checkStackFrame(origin, "baz", 8, 3, false, true,
10177                    stackTrace->GetFrame(1));
10178#ifdef ENABLE_DEBUGGER_SUPPORT
10179    bool is_eval = true;
10180#else  // ENABLE_DEBUGGER_SUPPORT
10181    bool is_eval = false;
10182#endif  // ENABLE_DEBUGGER_SUPPORT
10183
10184    checkStackFrame(NULL, "", 1, 1, is_eval, false,
10185                    stackTrace->GetFrame(2));
10186    // The last frame is an anonymous function that has the initial call to foo.
10187    checkStackFrame(origin, "", 10, 1, false, false,
10188                    stackTrace->GetFrame(3));
10189
10190    CHECK(stackTrace->AsArray()->IsArray());
10191  }
10192  return v8::Undefined();
10193}
10194
10195
10196// Tests the C++ StackTrace API.
10197THREADED_TEST(CaptureStackTrace) {
10198  v8::HandleScope scope;
10199  v8::Handle<v8::String> origin = v8::String::New("capture-stack-trace-test");
10200  Local<ObjectTemplate> templ = ObjectTemplate::New();
10201  templ->Set(v8_str("AnalyzeStackInNativeCode"),
10202             v8::FunctionTemplate::New(AnalyzeStackInNativeCode));
10203  LocalContext context(0, templ);
10204
10205  // Test getting OVERVIEW information. Should ignore information that is not
10206  // script name, function name, line number, and column offset.
10207  const char *overview_source =
10208    "function bar() {\n"
10209    "  var y; AnalyzeStackInNativeCode(1);\n"
10210    "}\n"
10211    "function foo() {\n"
10212    "\n"
10213    "  bar();\n"
10214    "}\n"
10215    "var x;eval('new foo();');";
10216  v8::Handle<v8::String> overview_src = v8::String::New(overview_source);
10217  v8::Handle<Value> overview_result =
10218      v8::Script::New(overview_src, origin)->Run();
10219  ASSERT(!overview_result.IsEmpty());
10220  ASSERT(overview_result->IsObject());
10221
10222  // Test getting DETAILED information.
10223  const char *detailed_source =
10224    "function bat() {AnalyzeStackInNativeCode(2);\n"
10225    "}\n"
10226    "\n"
10227    "function baz() {\n"
10228    "  bat();\n"
10229    "}\n"
10230    "eval('new baz();');";
10231  v8::Handle<v8::String> detailed_src = v8::String::New(detailed_source);
10232  // Make the script using a non-zero line and column offset.
10233  v8::Handle<v8::Integer> line_offset = v8::Integer::New(3);
10234  v8::Handle<v8::Integer> column_offset = v8::Integer::New(5);
10235  v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
10236  v8::Handle<v8::Script> detailed_script(
10237      v8::Script::New(detailed_src, &detailed_origin));
10238  v8::Handle<Value> detailed_result = detailed_script->Run();
10239  ASSERT(!detailed_result.IsEmpty());
10240  ASSERT(detailed_result->IsObject());
10241}
10242
10243
10244// Test that idle notification can be handled and eventually returns true.
10245THREADED_TEST(IdleNotification) {
10246  bool rv = false;
10247  for (int i = 0; i < 100; i++) {
10248    rv = v8::V8::IdleNotification();
10249    if (rv)
10250      break;
10251  }
10252  CHECK(rv == true);
10253}
10254
10255
10256static uint32_t* stack_limit;
10257
10258static v8::Handle<Value> GetStackLimitCallback(const v8::Arguments& args) {
10259  stack_limit = reinterpret_cast<uint32_t*>(i::StackGuard::climit());
10260  return v8::Undefined();
10261}
10262
10263
10264// Uses the address of a local variable to determine the stack top now.
10265// Given a size, returns an address that is that far from the current
10266// top of stack.
10267static uint32_t* ComputeStackLimit(uint32_t size) {
10268  uint32_t* answer = &size - (size / sizeof(size));
10269  // If the size is very large and the stack is very near the bottom of
10270  // memory then the calculation above may wrap around and give an address
10271  // that is above the (downwards-growing) stack.  In that case we return
10272  // a very low address.
10273  if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
10274  return answer;
10275}
10276
10277
10278TEST(SetResourceConstraints) {
10279  static const int K = 1024;
10280  uint32_t* set_limit = ComputeStackLimit(128 * K);
10281
10282  // Set stack limit.
10283  v8::ResourceConstraints constraints;
10284  constraints.set_stack_limit(set_limit);
10285  CHECK(v8::SetResourceConstraints(&constraints));
10286
10287  // Execute a script.
10288  v8::HandleScope scope;
10289  LocalContext env;
10290  Local<v8::FunctionTemplate> fun_templ =
10291      v8::FunctionTemplate::New(GetStackLimitCallback);
10292  Local<Function> fun = fun_templ->GetFunction();
10293  env->Global()->Set(v8_str("get_stack_limit"), fun);
10294  CompileRun("get_stack_limit();");
10295
10296  CHECK(stack_limit == set_limit);
10297}
10298
10299
10300TEST(SetResourceConstraintsInThread) {
10301  uint32_t* set_limit;
10302  {
10303    v8::Locker locker;
10304    static const int K = 1024;
10305    set_limit = ComputeStackLimit(128 * K);
10306
10307    // Set stack limit.
10308    v8::ResourceConstraints constraints;
10309    constraints.set_stack_limit(set_limit);
10310    CHECK(v8::SetResourceConstraints(&constraints));
10311
10312    // Execute a script.
10313    v8::HandleScope scope;
10314    LocalContext env;
10315    Local<v8::FunctionTemplate> fun_templ =
10316        v8::FunctionTemplate::New(GetStackLimitCallback);
10317    Local<Function> fun = fun_templ->GetFunction();
10318    env->Global()->Set(v8_str("get_stack_limit"), fun);
10319    CompileRun("get_stack_limit();");
10320
10321    CHECK(stack_limit == set_limit);
10322  }
10323  {
10324    v8::Locker locker;
10325    CHECK(stack_limit == set_limit);
10326  }
10327}
10328
10329
10330THREADED_TEST(GetHeapStatistics) {
10331  v8::HandleScope scope;
10332  LocalContext c1;
10333  v8::HeapStatistics heap_statistics;
10334  CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
10335  CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
10336  v8::V8::GetHeapStatistics(&heap_statistics);
10337  CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
10338  CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
10339}
10340
10341
10342static double DoubleFromBits(uint64_t value) {
10343  double target;
10344#ifdef BIG_ENDIAN_FLOATING_POINT
10345  const int kIntSize = 4;
10346  // Somebody swapped the lower and higher half of doubles.
10347  memcpy(&target, reinterpret_cast<char*>(&value) + kIntSize, kIntSize);
10348  memcpy(reinterpret_cast<char*>(&target) + kIntSize, &value, kIntSize);
10349#else
10350  memcpy(&target, &value, sizeof(target));
10351#endif
10352  return target;
10353}
10354
10355
10356static uint64_t DoubleToBits(double value) {
10357  uint64_t target;
10358#ifdef BIG_ENDIAN_FLOATING_POINT
10359  const int kIntSize = 4;
10360  // Somebody swapped the lower and higher half of doubles.
10361  memcpy(&target, reinterpret_cast<char*>(&value) + kIntSize, kIntSize);
10362  memcpy(reinterpret_cast<char*>(&target) + kIntSize, &value, kIntSize);
10363#else
10364  memcpy(&target, &value, sizeof(target));
10365#endif
10366  return target;
10367}
10368
10369
10370static double DoubleToDateTime(double input) {
10371  double date_limit = 864e13;
10372  if (IsNaN(input) || input < -date_limit || input > date_limit) {
10373    return i::OS::nan_value();
10374  }
10375  return (input < 0) ? -(floor(-input)) : floor(input);
10376}
10377
10378// We don't have a consistent way to write 64-bit constants syntactically, so we
10379// split them into two 32-bit constants and combine them programmatically.
10380static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
10381  return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
10382}
10383
10384
10385THREADED_TEST(QuietSignalingNaNs) {
10386  v8::HandleScope scope;
10387  LocalContext context;
10388  v8::TryCatch try_catch;
10389
10390  // Special double values.
10391  double snan = DoubleFromBits(0x7ff00000, 0x00000001);
10392  double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
10393  double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
10394  double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
10395  double min_normal = DoubleFromBits(0x00100000, 0x00000000);
10396  double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
10397  double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
10398
10399  // Date values are capped at +/-100000000 days (times 864e5 ms per day)
10400  // on either side of the epoch.
10401  double date_limit = 864e13;
10402
10403  double test_values[] = {
10404      snan,
10405      qnan,
10406      infinity,
10407      max_normal,
10408      date_limit + 1,
10409      date_limit,
10410      min_normal,
10411      max_denormal,
10412      min_denormal,
10413      0,
10414      -0,
10415      -min_denormal,
10416      -max_denormal,
10417      -min_normal,
10418      -date_limit,
10419      -date_limit - 1,
10420      -max_normal,
10421      -infinity,
10422      -qnan,
10423      -snan
10424  };
10425  int num_test_values = 20;
10426
10427  for (int i = 0; i < num_test_values; i++) {
10428    double test_value = test_values[i];
10429
10430    // Check that Number::New preserves non-NaNs and quiets SNaNs.
10431    v8::Handle<v8::Value> number = v8::Number::New(test_value);
10432    double stored_number = number->NumberValue();
10433    if (!IsNaN(test_value)) {
10434      CHECK_EQ(test_value, stored_number);
10435    } else {
10436      uint64_t stored_bits = DoubleToBits(stored_number);
10437      // Check if quiet nan (bits 51..62 all set).
10438      CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
10439    }
10440
10441    // Check that Date::New preserves non-NaNs in the date range and
10442    // quiets SNaNs.
10443    v8::Handle<v8::Value> date = v8::Date::New(test_value);
10444    double expected_stored_date = DoubleToDateTime(test_value);
10445    double stored_date = date->NumberValue();
10446    if (!IsNaN(expected_stored_date)) {
10447      CHECK_EQ(expected_stored_date, stored_date);
10448    } else {
10449      uint64_t stored_bits = DoubleToBits(stored_date);
10450      // Check if quiet nan (bits 51..62 all set).
10451      CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
10452    }
10453  }
10454}
10455
10456
10457static v8::Handle<Value> SpaghettiIncident(const v8::Arguments& args) {
10458  v8::HandleScope scope;
10459  v8::TryCatch tc;
10460  v8::Handle<v8::String> str = args[0]->ToString();
10461  if (tc.HasCaught())
10462    return tc.ReThrow();
10463  return v8::Undefined();
10464}
10465
10466
10467// Test that an exception can be propagated down through a spaghetti
10468// stack using ReThrow.
10469THREADED_TEST(SpaghettiStackReThrow) {
10470  v8::HandleScope scope;
10471  LocalContext context;
10472  context->Global()->Set(
10473      v8::String::New("s"),
10474      v8::FunctionTemplate::New(SpaghettiIncident)->GetFunction());
10475  v8::TryCatch try_catch;
10476  CompileRun(
10477      "var i = 0;"
10478      "var o = {"
10479      "  toString: function () {"
10480      "    if (i == 10) {"
10481      "      throw 'Hey!';"
10482      "    } else {"
10483      "      i++;"
10484      "      return s(o);"
10485      "    }"
10486      "  }"
10487      "};"
10488      "s(o);");
10489  CHECK(try_catch.HasCaught());
10490  v8::String::Utf8Value value(try_catch.Exception());
10491  CHECK_EQ(0, strcmp(*value, "Hey!"));
10492}
10493
10494
10495TEST(Regress528) {
10496  v8::V8::Initialize();
10497
10498  v8::HandleScope scope;
10499  v8::Persistent<Context> context;
10500  v8::Persistent<Context> other_context;
10501  int gc_count;
10502
10503  // Create a context used to keep the code from aging in the compilation
10504  // cache.
10505  other_context = Context::New();
10506
10507  // Context-dependent context data creates reference from the compilation
10508  // cache to the global object.
10509  const char* source_simple = "1";
10510  context = Context::New();
10511  {
10512    v8::HandleScope scope;
10513
10514    context->Enter();
10515    Local<v8::String> obj = v8::String::New("");
10516    context->SetData(obj);
10517    CompileRun(source_simple);
10518    context->Exit();
10519  }
10520  context.Dispose();
10521  for (gc_count = 1; gc_count < 10; gc_count++) {
10522    other_context->Enter();
10523    CompileRun(source_simple);
10524    other_context->Exit();
10525    v8::internal::Heap::CollectAllGarbage(false);
10526    if (GetGlobalObjectsCount() == 1) break;
10527  }
10528  CHECK_GE(2, gc_count);
10529  CHECK_EQ(1, GetGlobalObjectsCount());
10530
10531  // Eval in a function creates reference from the compilation cache to the
10532  // global object.
10533  const char* source_eval = "function f(){eval('1')}; f()";
10534  context = Context::New();
10535  {
10536    v8::HandleScope scope;
10537
10538    context->Enter();
10539    CompileRun(source_eval);
10540    context->Exit();
10541  }
10542  context.Dispose();
10543  for (gc_count = 1; gc_count < 10; gc_count++) {
10544    other_context->Enter();
10545    CompileRun(source_eval);
10546    other_context->Exit();
10547    v8::internal::Heap::CollectAllGarbage(false);
10548    if (GetGlobalObjectsCount() == 1) break;
10549  }
10550  CHECK_GE(2, gc_count);
10551  CHECK_EQ(1, GetGlobalObjectsCount());
10552
10553  // Looking up the line number for an exception creates reference from the
10554  // compilation cache to the global object.
10555  const char* source_exception = "function f(){throw 1;} f()";
10556  context = Context::New();
10557  {
10558    v8::HandleScope scope;
10559
10560    context->Enter();
10561    v8::TryCatch try_catch;
10562    CompileRun(source_exception);
10563    CHECK(try_catch.HasCaught());
10564    v8::Handle<v8::Message> message = try_catch.Message();
10565    CHECK(!message.IsEmpty());
10566    CHECK_EQ(1, message->GetLineNumber());
10567    context->Exit();
10568  }
10569  context.Dispose();
10570  for (gc_count = 1; gc_count < 10; gc_count++) {
10571    other_context->Enter();
10572    CompileRun(source_exception);
10573    other_context->Exit();
10574    v8::internal::Heap::CollectAllGarbage(false);
10575    if (GetGlobalObjectsCount() == 1) break;
10576  }
10577  CHECK_GE(2, gc_count);
10578  CHECK_EQ(1, GetGlobalObjectsCount());
10579
10580  other_context.Dispose();
10581}
10582
10583
10584THREADED_TEST(ScriptOrigin) {
10585  v8::HandleScope scope;
10586  LocalContext env;
10587  v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
10588  v8::Handle<v8::String> script = v8::String::New(
10589      "function f() {}\n\nfunction g() {}");
10590  v8::Script::Compile(script, &origin)->Run();
10591  v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
10592      env->Global()->Get(v8::String::New("f")));
10593  v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
10594      env->Global()->Get(v8::String::New("g")));
10595
10596  v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
10597  CHECK_EQ("test", *v8::String::AsciiValue(script_origin_f.ResourceName()));
10598  CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
10599
10600  v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
10601  CHECK_EQ("test", *v8::String::AsciiValue(script_origin_g.ResourceName()));
10602  CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
10603}
10604
10605
10606THREADED_TEST(ScriptLineNumber) {
10607  v8::HandleScope scope;
10608  LocalContext env;
10609  v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
10610  v8::Handle<v8::String> script = v8::String::New(
10611      "function f() {}\n\nfunction g() {}");
10612  v8::Script::Compile(script, &origin)->Run();
10613  v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
10614      env->Global()->Get(v8::String::New("f")));
10615  v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
10616      env->Global()->Get(v8::String::New("g")));
10617  CHECK_EQ(0, f->GetScriptLineNumber());
10618  CHECK_EQ(2, g->GetScriptLineNumber());
10619}
10620
10621
10622static v8::Handle<Value> GetterWhichReturns42(Local<String> name,
10623                                              const AccessorInfo& info) {
10624  return v8_num(42);
10625}
10626
10627
10628static void SetterWhichSetsYOnThisTo23(Local<String> name,
10629                                       Local<Value> value,
10630                                       const AccessorInfo& info) {
10631  info.This()->Set(v8_str("y"), v8_num(23));
10632}
10633
10634
10635TEST(SetterOnConstructorPrototype) {
10636  v8::HandleScope scope;
10637  Local<ObjectTemplate> templ = ObjectTemplate::New();
10638  templ->SetAccessor(v8_str("x"),
10639                     GetterWhichReturns42,
10640                     SetterWhichSetsYOnThisTo23);
10641  LocalContext context;
10642  context->Global()->Set(v8_str("P"), templ->NewInstance());
10643  CompileRun("function C1() {"
10644             "  this.x = 23;"
10645             "};"
10646             "C1.prototype = P;"
10647             "function C2() {"
10648             "  this.x = 23"
10649             "};"
10650             "C2.prototype = { };"
10651             "C2.prototype.__proto__ = P;");
10652
10653  v8::Local<v8::Script> script;
10654  script = v8::Script::Compile(v8_str("new C1();"));
10655  for (int i = 0; i < 10; i++) {
10656    v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
10657    CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
10658    CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
10659  }
10660
10661  script = v8::Script::Compile(v8_str("new C2();"));
10662  for (int i = 0; i < 10; i++) {
10663    v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
10664    CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
10665    CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
10666  }
10667}
10668
10669
10670static v8::Handle<Value> NamedPropertyGetterWhichReturns42(
10671    Local<String> name, const AccessorInfo& info) {
10672  return v8_num(42);
10673}
10674
10675
10676static v8::Handle<Value> NamedPropertySetterWhichSetsYOnThisTo23(
10677    Local<String> name, Local<Value> value, const AccessorInfo& info) {
10678  if (name->Equals(v8_str("x"))) {
10679    info.This()->Set(v8_str("y"), v8_num(23));
10680  }
10681  return v8::Handle<Value>();
10682}
10683
10684
10685THREADED_TEST(InterceptorOnConstructorPrototype) {
10686  v8::HandleScope scope;
10687  Local<ObjectTemplate> templ = ObjectTemplate::New();
10688  templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
10689                                 NamedPropertySetterWhichSetsYOnThisTo23);
10690  LocalContext context;
10691  context->Global()->Set(v8_str("P"), templ->NewInstance());
10692  CompileRun("function C1() {"
10693             "  this.x = 23;"
10694             "};"
10695             "C1.prototype = P;"
10696             "function C2() {"
10697             "  this.x = 23"
10698             "};"
10699             "C2.prototype = { };"
10700             "C2.prototype.__proto__ = P;");
10701
10702  v8::Local<v8::Script> script;
10703  script = v8::Script::Compile(v8_str("new C1();"));
10704  for (int i = 0; i < 10; i++) {
10705    v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
10706    CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
10707    CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
10708  }
10709
10710  script = v8::Script::Compile(v8_str("new C2();"));
10711  for (int i = 0; i < 10; i++) {
10712    v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
10713    CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
10714    CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
10715  }
10716}
10717
10718
10719TEST(Bug618) {
10720  const char* source = "function C1() {"
10721                       "  this.x = 23;"
10722                       "};"
10723                       "C1.prototype = P;";
10724
10725  v8::HandleScope scope;
10726  LocalContext context;
10727  v8::Local<v8::Script> script;
10728
10729  // Use a simple object as prototype.
10730  v8::Local<v8::Object> prototype = v8::Object::New();
10731  prototype->Set(v8_str("y"), v8_num(42));
10732  context->Global()->Set(v8_str("P"), prototype);
10733
10734  // This compile will add the code to the compilation cache.
10735  CompileRun(source);
10736
10737  script = v8::Script::Compile(v8_str("new C1();"));
10738  for (int i = 0; i < 10; i++) {
10739    v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
10740    CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
10741    CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
10742  }
10743
10744  // Use an API object with accessors as prototype.
10745  Local<ObjectTemplate> templ = ObjectTemplate::New();
10746  templ->SetAccessor(v8_str("x"),
10747                     GetterWhichReturns42,
10748                     SetterWhichSetsYOnThisTo23);
10749  context->Global()->Set(v8_str("P"), templ->NewInstance());
10750
10751  // This compile will get the code from the compilation cache.
10752  CompileRun(source);
10753
10754  script = v8::Script::Compile(v8_str("new C1();"));
10755  for (int i = 0; i < 10; i++) {
10756    v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
10757    CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
10758    CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
10759  }
10760}
10761
10762int prologue_call_count = 0;
10763int epilogue_call_count = 0;
10764int prologue_call_count_second = 0;
10765int epilogue_call_count_second = 0;
10766
10767void PrologueCallback(v8::GCType, v8::GCCallbackFlags) {
10768  ++prologue_call_count;
10769}
10770
10771void EpilogueCallback(v8::GCType, v8::GCCallbackFlags) {
10772  ++epilogue_call_count;
10773}
10774
10775void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
10776  ++prologue_call_count_second;
10777}
10778
10779void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
10780  ++epilogue_call_count_second;
10781}
10782
10783TEST(GCCallbacks) {
10784  LocalContext context;
10785
10786  v8::V8::AddGCPrologueCallback(PrologueCallback);
10787  v8::V8::AddGCEpilogueCallback(EpilogueCallback);
10788  CHECK_EQ(0, prologue_call_count);
10789  CHECK_EQ(0, epilogue_call_count);
10790  i::Heap::CollectAllGarbage(false);
10791  CHECK_EQ(1, prologue_call_count);
10792  CHECK_EQ(1, epilogue_call_count);
10793  v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
10794  v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
10795  i::Heap::CollectAllGarbage(false);
10796  CHECK_EQ(2, prologue_call_count);
10797  CHECK_EQ(2, epilogue_call_count);
10798  CHECK_EQ(1, prologue_call_count_second);
10799  CHECK_EQ(1, epilogue_call_count_second);
10800  v8::V8::RemoveGCPrologueCallback(PrologueCallback);
10801  v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
10802  i::Heap::CollectAllGarbage(false);
10803  CHECK_EQ(2, prologue_call_count);
10804  CHECK_EQ(2, epilogue_call_count);
10805  CHECK_EQ(2, prologue_call_count_second);
10806  CHECK_EQ(2, epilogue_call_count_second);
10807  v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
10808  v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
10809  i::Heap::CollectAllGarbage(false);
10810  CHECK_EQ(2, prologue_call_count);
10811  CHECK_EQ(2, epilogue_call_count);
10812  CHECK_EQ(2, prologue_call_count_second);
10813  CHECK_EQ(2, epilogue_call_count_second);
10814}
10815
10816
10817THREADED_TEST(AddToJSFunctionResultCache) {
10818  i::FLAG_allow_natives_syntax = true;
10819  v8::HandleScope scope;
10820
10821  LocalContext context;
10822
10823  const char* code =
10824      "(function() {"
10825      "  var key0 = 'a';"
10826      "  var key1 = 'b';"
10827      "  var r0 = %_GetFromCache(0, key0);"
10828      "  var r1 = %_GetFromCache(0, key1);"
10829      "  var r0_ = %_GetFromCache(0, key0);"
10830      "  if (r0 !== r0_)"
10831      "    return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
10832      "  var r1_ = %_GetFromCache(0, key1);"
10833      "  if (r1 !== r1_)"
10834      "    return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
10835      "  return 'PASSED';"
10836      "})()";
10837  v8::internal::Heap::ClearJSFunctionResultCaches();
10838  ExpectString(code, "PASSED");
10839}
10840
10841
10842static const int k0CacheSize = 16;
10843
10844THREADED_TEST(FillJSFunctionResultCache) {
10845  i::FLAG_allow_natives_syntax = true;
10846  v8::HandleScope scope;
10847
10848  LocalContext context;
10849
10850  const char* code =
10851      "(function() {"
10852      "  var k = 'a';"
10853      "  var r = %_GetFromCache(0, k);"
10854      "  for (var i = 0; i < 16; i++) {"
10855      "    %_GetFromCache(0, 'a' + i);"
10856      "  };"
10857      "  if (r === %_GetFromCache(0, k))"
10858      "    return 'FAILED: k0CacheSize is too small';"
10859      "  return 'PASSED';"
10860      "})()";
10861  v8::internal::Heap::ClearJSFunctionResultCaches();
10862  ExpectString(code, "PASSED");
10863}
10864
10865
10866THREADED_TEST(RoundRobinGetFromCache) {
10867  i::FLAG_allow_natives_syntax = true;
10868  v8::HandleScope scope;
10869
10870  LocalContext context;
10871
10872  const char* code =
10873      "(function() {"
10874      "  var keys = [];"
10875      "  for (var i = 0; i < 16; i++) keys.push(i);"
10876      "  var values = [];"
10877      "  for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
10878      "  for (var i = 0; i < 16; i++) {"
10879      "    var v = %_GetFromCache(0, keys[i]);"
10880      "    if (v !== values[i])"
10881      "      return 'Wrong value for ' + "
10882      "          keys[i] + ': ' + v + ' vs. ' + values[i];"
10883      "  };"
10884      "  return 'PASSED';"
10885      "})()";
10886  v8::internal::Heap::ClearJSFunctionResultCaches();
10887  ExpectString(code, "PASSED");
10888}
10889
10890
10891THREADED_TEST(ReverseGetFromCache) {
10892  i::FLAG_allow_natives_syntax = true;
10893  v8::HandleScope scope;
10894
10895  LocalContext context;
10896
10897  const char* code =
10898      "(function() {"
10899      "  var keys = [];"
10900      "  for (var i = 0; i < 16; i++) keys.push(i);"
10901      "  var values = [];"
10902      "  for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
10903      "  for (var i = 15; i >= 16; i--) {"
10904      "    var v = %_GetFromCache(0, keys[i]);"
10905      "    if (v !== values[i])"
10906      "      return 'Wrong value for ' + "
10907      "          keys[i] + ': ' + v + ' vs. ' + values[i];"
10908      "  };"
10909      "  return 'PASSED';"
10910      "})()";
10911  v8::internal::Heap::ClearJSFunctionResultCaches();
10912  ExpectString(code, "PASSED");
10913}
10914
10915
10916THREADED_TEST(TestEviction) {
10917  i::FLAG_allow_natives_syntax = true;
10918  v8::HandleScope scope;
10919
10920  LocalContext context;
10921
10922  const char* code =
10923      "(function() {"
10924      "  for (var i = 0; i < 2*16; i++) {"
10925      "    %_GetFromCache(0, 'a' + i);"
10926      "  };"
10927      "  return 'PASSED';"
10928      "})()";
10929  v8::internal::Heap::ClearJSFunctionResultCaches();
10930  ExpectString(code, "PASSED");
10931}
10932