1// Copyright 2011 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 "utils.h"
38#include "cctest.h"
39#include "parser.h"
40#include "unicode-inl.h"
41
42static const bool kLogThreading = true;
43
44static bool IsNaN(double x) {
45#ifdef WIN32
46  return _isnan(x);
47#else
48  return isnan(x);
49#endif
50}
51
52using ::v8::AccessorInfo;
53using ::v8::Arguments;
54using ::v8::Context;
55using ::v8::Extension;
56using ::v8::Function;
57using ::v8::FunctionTemplate;
58using ::v8::Handle;
59using ::v8::HandleScope;
60using ::v8::Local;
61using ::v8::Message;
62using ::v8::MessageCallback;
63using ::v8::Object;
64using ::v8::ObjectTemplate;
65using ::v8::Persistent;
66using ::v8::Script;
67using ::v8::StackTrace;
68using ::v8::String;
69using ::v8::TryCatch;
70using ::v8::Undefined;
71using ::v8::V8;
72using ::v8::Value;
73
74namespace i = ::i;
75
76
77static void ExpectString(const char* code, const char* expected) {
78  Local<Value> result = CompileRun(code);
79  CHECK(result->IsString());
80  String::AsciiValue ascii(result);
81  CHECK_EQ(expected, *ascii);
82}
83
84
85static void ExpectBoolean(const char* code, bool expected) {
86  Local<Value> result = CompileRun(code);
87  CHECK(result->IsBoolean());
88  CHECK_EQ(expected, result->BooleanValue());
89}
90
91
92static void ExpectTrue(const char* code) {
93  ExpectBoolean(code, true);
94}
95
96
97static void ExpectFalse(const char* code) {
98  ExpectBoolean(code, false);
99}
100
101
102static void ExpectObject(const char* code, Local<Value> expected) {
103  Local<Value> result = CompileRun(code);
104  CHECK(result->Equals(expected));
105}
106
107
108static void ExpectUndefined(const char* code) {
109  Local<Value> result = CompileRun(code);
110  CHECK(result->IsUndefined());
111}
112
113
114static int signature_callback_count;
115static v8::Handle<Value> IncrementingSignatureCallback(
116    const v8::Arguments& args) {
117  ApiTestFuzzer::Fuzz();
118  signature_callback_count++;
119  v8::Handle<v8::Array> result = v8::Array::New(args.Length());
120  for (int i = 0; i < args.Length(); i++)
121    result->Set(v8::Integer::New(i), args[i]);
122  return result;
123}
124
125
126static v8::Handle<Value> SignatureCallback(const v8::Arguments& args) {
127  ApiTestFuzzer::Fuzz();
128  v8::Handle<v8::Array> result = v8::Array::New(args.Length());
129  for (int i = 0; i < args.Length(); i++) {
130    result->Set(v8::Integer::New(i), args[i]);
131  }
132  return result;
133}
134
135
136THREADED_TEST(Handles) {
137  v8::HandleScope scope;
138  Local<Context> local_env;
139  {
140    LocalContext env;
141    local_env = env.local();
142  }
143
144  // Local context should still be live.
145  CHECK(!local_env.IsEmpty());
146  local_env->Enter();
147
148  v8::Handle<v8::Primitive> undef = v8::Undefined();
149  CHECK(!undef.IsEmpty());
150  CHECK(undef->IsUndefined());
151
152  const char* c_source = "1 + 2 + 3";
153  Local<String> source = String::New(c_source);
154  Local<Script> script = Script::Compile(source);
155  CHECK_EQ(6, script->Run()->Int32Value());
156
157  local_env->Exit();
158}
159
160
161THREADED_TEST(ReceiverSignature) {
162  v8::HandleScope scope;
163  LocalContext env;
164  v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
165  v8::Handle<v8::Signature> sig = v8::Signature::New(fun);
166  fun->PrototypeTemplate()->Set(
167      v8_str("m"),
168      v8::FunctionTemplate::New(IncrementingSignatureCallback,
169                                v8::Handle<Value>(),
170                                sig));
171  env->Global()->Set(v8_str("Fun"), fun->GetFunction());
172  signature_callback_count = 0;
173  CompileRun(
174      "var o = new Fun();"
175      "o.m();");
176  CHECK_EQ(1, signature_callback_count);
177  v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New();
178  sub_fun->Inherit(fun);
179  env->Global()->Set(v8_str("SubFun"), sub_fun->GetFunction());
180  CompileRun(
181      "var o = new SubFun();"
182      "o.m();");
183  CHECK_EQ(2, signature_callback_count);
184
185  v8::TryCatch try_catch;
186  CompileRun(
187      "var o = { };"
188      "o.m = Fun.prototype.m;"
189      "o.m();");
190  CHECK_EQ(2, signature_callback_count);
191  CHECK(try_catch.HasCaught());
192  try_catch.Reset();
193  v8::Handle<v8::FunctionTemplate> unrel_fun = v8::FunctionTemplate::New();
194  sub_fun->Inherit(fun);
195  env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
196  CompileRun(
197      "var o = new UnrelFun();"
198      "o.m = Fun.prototype.m;"
199      "o.m();");
200  CHECK_EQ(2, signature_callback_count);
201  CHECK(try_catch.HasCaught());
202}
203
204
205
206
207THREADED_TEST(ArgumentSignature) {
208  v8::HandleScope scope;
209  LocalContext env;
210  v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New();
211  cons->SetClassName(v8_str("Cons"));
212  v8::Handle<v8::Signature> sig =
213      v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 1, &cons);
214  v8::Handle<v8::FunctionTemplate> fun =
215      v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), sig);
216  env->Global()->Set(v8_str("Cons"), cons->GetFunction());
217  env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
218
219  v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
220  CHECK(value1->IsTrue());
221
222  v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
223  CHECK(value2->IsTrue());
224
225  v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
226  CHECK(value3->IsTrue());
227
228  v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New();
229  cons1->SetClassName(v8_str("Cons1"));
230  v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New();
231  cons2->SetClassName(v8_str("Cons2"));
232  v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New();
233  cons3->SetClassName(v8_str("Cons3"));
234
235  v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
236  v8::Handle<v8::Signature> wsig =
237      v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 3, args);
238  v8::Handle<v8::FunctionTemplate> fun2 =
239      v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), wsig);
240
241  env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
242  env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
243  env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
244  env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
245  v8::Handle<Value> value4 = CompileRun(
246      "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
247      "'[object Cons1],[object Cons2],[object Cons3]'");
248  CHECK(value4->IsTrue());
249
250  v8::Handle<Value> value5 = CompileRun(
251      "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
252  CHECK(value5->IsTrue());
253
254  v8::Handle<Value> value6 = CompileRun(
255      "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
256  CHECK(value6->IsTrue());
257
258  v8::Handle<Value> value7 = CompileRun(
259      "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
260      "'[object Cons1],[object Cons2],[object Cons3],d';");
261  CHECK(value7->IsTrue());
262
263  v8::Handle<Value> value8 = CompileRun(
264      "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
265  CHECK(value8->IsTrue());
266}
267
268
269THREADED_TEST(HulIgennem) {
270  v8::HandleScope scope;
271  LocalContext env;
272  v8::Handle<v8::Primitive> undef = v8::Undefined();
273  Local<String> undef_str = undef->ToString();
274  char* value = i::NewArray<char>(undef_str->Length() + 1);
275  undef_str->WriteAscii(value);
276  CHECK_EQ(0, strcmp(value, "undefined"));
277  i::DeleteArray(value);
278}
279
280
281THREADED_TEST(Access) {
282  v8::HandleScope scope;
283  LocalContext env;
284  Local<v8::Object> obj = v8::Object::New();
285  Local<Value> foo_before = obj->Get(v8_str("foo"));
286  CHECK(foo_before->IsUndefined());
287  Local<String> bar_str = v8_str("bar");
288  obj->Set(v8_str("foo"), bar_str);
289  Local<Value> foo_after = obj->Get(v8_str("foo"));
290  CHECK(!foo_after->IsUndefined());
291  CHECK(foo_after->IsString());
292  CHECK_EQ(bar_str, foo_after);
293}
294
295
296THREADED_TEST(AccessElement) {
297  v8::HandleScope scope;
298  LocalContext env;
299  Local<v8::Object> obj = v8::Object::New();
300  Local<Value> before = obj->Get(1);
301  CHECK(before->IsUndefined());
302  Local<String> bar_str = v8_str("bar");
303  obj->Set(1, bar_str);
304  Local<Value> after = obj->Get(1);
305  CHECK(!after->IsUndefined());
306  CHECK(after->IsString());
307  CHECK_EQ(bar_str, after);
308
309  Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
310  CHECK_EQ(v8_str("a"), value->Get(0));
311  CHECK_EQ(v8_str("b"), value->Get(1));
312}
313
314
315THREADED_TEST(Script) {
316  v8::HandleScope scope;
317  LocalContext env;
318  const char* c_source = "1 + 2 + 3";
319  Local<String> source = String::New(c_source);
320  Local<Script> script = Script::Compile(source);
321  CHECK_EQ(6, script->Run()->Int32Value());
322}
323
324
325static uint16_t* AsciiToTwoByteString(const char* source) {
326  int array_length = i::StrLength(source) + 1;
327  uint16_t* converted = i::NewArray<uint16_t>(array_length);
328  for (int i = 0; i < array_length; i++) converted[i] = source[i];
329  return converted;
330}
331
332
333class TestResource: public String::ExternalStringResource {
334 public:
335  static int dispose_count;
336
337  explicit TestResource(uint16_t* data)
338      : data_(data), length_(0) {
339    while (data[length_]) ++length_;
340  }
341
342  ~TestResource() {
343    i::DeleteArray(data_);
344    ++dispose_count;
345  }
346
347  const uint16_t* data() const {
348    return data_;
349  }
350
351  size_t length() const {
352    return length_;
353  }
354 private:
355  uint16_t* data_;
356  size_t length_;
357};
358
359
360int TestResource::dispose_count = 0;
361
362
363class TestAsciiResource: public String::ExternalAsciiStringResource {
364 public:
365  static int dispose_count;
366
367  explicit TestAsciiResource(const char* data)
368      : data_(data),
369        length_(strlen(data)) { }
370
371  ~TestAsciiResource() {
372    i::DeleteArray(data_);
373    ++dispose_count;
374  }
375
376  const char* data() const {
377    return data_;
378  }
379
380  size_t length() const {
381    return length_;
382  }
383 private:
384  const char* data_;
385  size_t length_;
386};
387
388
389int TestAsciiResource::dispose_count = 0;
390
391
392THREADED_TEST(ScriptUsingStringResource) {
393  TestResource::dispose_count = 0;
394  const char* c_source = "1 + 2 * 3";
395  uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
396  {
397    v8::HandleScope scope;
398    LocalContext env;
399    TestResource* resource = new TestResource(two_byte_source);
400    Local<String> source = String::NewExternal(resource);
401    Local<Script> script = Script::Compile(source);
402    Local<Value> value = script->Run();
403    CHECK(value->IsNumber());
404    CHECK_EQ(7, value->Int32Value());
405    CHECK(source->IsExternal());
406    CHECK_EQ(resource,
407             static_cast<TestResource*>(source->GetExternalStringResource()));
408    HEAP->CollectAllGarbage(false);
409    CHECK_EQ(0, TestResource::dispose_count);
410  }
411  v8::internal::Isolate::Current()->compilation_cache()->Clear();
412  HEAP->CollectAllGarbage(false);
413  CHECK_EQ(1, TestResource::dispose_count);
414}
415
416
417THREADED_TEST(ScriptUsingAsciiStringResource) {
418  TestAsciiResource::dispose_count = 0;
419  const char* c_source = "1 + 2 * 3";
420  {
421    v8::HandleScope scope;
422    LocalContext env;
423    Local<String> source =
424        String::NewExternal(new TestAsciiResource(i::StrDup(c_source)));
425    Local<Script> script = Script::Compile(source);
426    Local<Value> value = script->Run();
427    CHECK(value->IsNumber());
428    CHECK_EQ(7, value->Int32Value());
429    HEAP->CollectAllGarbage(false);
430    CHECK_EQ(0, TestAsciiResource::dispose_count);
431  }
432  i::Isolate::Current()->compilation_cache()->Clear();
433  HEAP->CollectAllGarbage(false);
434  CHECK_EQ(1, TestAsciiResource::dispose_count);
435}
436
437
438THREADED_TEST(ScriptMakingExternalString) {
439  TestResource::dispose_count = 0;
440  uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
441  {
442    v8::HandleScope scope;
443    LocalContext env;
444    Local<String> source = String::New(two_byte_source);
445    // Trigger GCs so that the newly allocated string moves to old gen.
446    HEAP->CollectGarbage(i::NEW_SPACE);  // in survivor space now
447    HEAP->CollectGarbage(i::NEW_SPACE);  // in old gen now
448    bool success = source->MakeExternal(new TestResource(two_byte_source));
449    CHECK(success);
450    Local<Script> script = Script::Compile(source);
451    Local<Value> value = script->Run();
452    CHECK(value->IsNumber());
453    CHECK_EQ(7, value->Int32Value());
454    HEAP->CollectAllGarbage(false);
455    CHECK_EQ(0, TestResource::dispose_count);
456  }
457  i::Isolate::Current()->compilation_cache()->Clear();
458  HEAP->CollectAllGarbage(false);
459  CHECK_EQ(1, TestResource::dispose_count);
460}
461
462
463THREADED_TEST(ScriptMakingExternalAsciiString) {
464  TestAsciiResource::dispose_count = 0;
465  const char* c_source = "1 + 2 * 3";
466  {
467    v8::HandleScope scope;
468    LocalContext env;
469    Local<String> source = v8_str(c_source);
470    // Trigger GCs so that the newly allocated string moves to old gen.
471    HEAP->CollectGarbage(i::NEW_SPACE);  // in survivor space now
472    HEAP->CollectGarbage(i::NEW_SPACE);  // in old gen now
473    bool success = source->MakeExternal(
474        new TestAsciiResource(i::StrDup(c_source)));
475    CHECK(success);
476    Local<Script> script = Script::Compile(source);
477    Local<Value> value = script->Run();
478    CHECK(value->IsNumber());
479    CHECK_EQ(7, value->Int32Value());
480    HEAP->CollectAllGarbage(false);
481    CHECK_EQ(0, TestAsciiResource::dispose_count);
482  }
483  i::Isolate::Current()->compilation_cache()->Clear();
484  HEAP->CollectAllGarbage(false);
485  CHECK_EQ(1, TestAsciiResource::dispose_count);
486}
487
488
489TEST(MakingExternalStringConditions) {
490  v8::HandleScope scope;
491  LocalContext env;
492
493  // Free some space in the new space so that we can check freshness.
494  HEAP->CollectGarbage(i::NEW_SPACE);
495  HEAP->CollectGarbage(i::NEW_SPACE);
496
497  uint16_t* two_byte_string = AsciiToTwoByteString("small");
498  Local<String> small_string = String::New(two_byte_string);
499  i::DeleteArray(two_byte_string);
500
501  // We should refuse to externalize newly created small string.
502  CHECK(!small_string->CanMakeExternal());
503  // Trigger GCs so that the newly allocated string moves to old gen.
504  HEAP->CollectGarbage(i::NEW_SPACE);  // in survivor space now
505  HEAP->CollectGarbage(i::NEW_SPACE);  // in old gen now
506  // Old space strings should be accepted.
507  CHECK(small_string->CanMakeExternal());
508
509  two_byte_string = AsciiToTwoByteString("small 2");
510  small_string = String::New(two_byte_string);
511  i::DeleteArray(two_byte_string);
512
513  // We should refuse externalizing newly created small string.
514  CHECK(!small_string->CanMakeExternal());
515  for (int i = 0; i < 100; i++) {
516    String::Value value(small_string);
517  }
518  // Frequently used strings should be accepted.
519  CHECK(small_string->CanMakeExternal());
520
521  const int buf_size = 10 * 1024;
522  char* buf = i::NewArray<char>(buf_size);
523  memset(buf, 'a', buf_size);
524  buf[buf_size - 1] = '\0';
525
526  two_byte_string = AsciiToTwoByteString(buf);
527  Local<String> large_string = String::New(two_byte_string);
528  i::DeleteArray(buf);
529  i::DeleteArray(two_byte_string);
530  // Large strings should be immediately accepted.
531  CHECK(large_string->CanMakeExternal());
532}
533
534
535TEST(MakingExternalAsciiStringConditions) {
536  v8::HandleScope scope;
537  LocalContext env;
538
539  // Free some space in the new space so that we can check freshness.
540  HEAP->CollectGarbage(i::NEW_SPACE);
541  HEAP->CollectGarbage(i::NEW_SPACE);
542
543  Local<String> small_string = String::New("small");
544  // We should refuse to externalize newly created small string.
545  CHECK(!small_string->CanMakeExternal());
546  // Trigger GCs so that the newly allocated string moves to old gen.
547  HEAP->CollectGarbage(i::NEW_SPACE);  // in survivor space now
548  HEAP->CollectGarbage(i::NEW_SPACE);  // in old gen now
549  // Old space strings should be accepted.
550  CHECK(small_string->CanMakeExternal());
551
552  small_string = String::New("small 2");
553  // We should refuse externalizing newly created small string.
554  CHECK(!small_string->CanMakeExternal());
555  for (int i = 0; i < 100; i++) {
556    String::Value value(small_string);
557  }
558  // Frequently used strings should be accepted.
559  CHECK(small_string->CanMakeExternal());
560
561  const int buf_size = 10 * 1024;
562  char* buf = i::NewArray<char>(buf_size);
563  memset(buf, 'a', buf_size);
564  buf[buf_size - 1] = '\0';
565  Local<String> large_string = String::New(buf);
566  i::DeleteArray(buf);
567  // Large strings should be immediately accepted.
568  CHECK(large_string->CanMakeExternal());
569}
570
571
572THREADED_TEST(UsingExternalString) {
573  {
574    v8::HandleScope scope;
575    uint16_t* two_byte_string = AsciiToTwoByteString("test string");
576    Local<String> string =
577        String::NewExternal(new TestResource(two_byte_string));
578    i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
579    // Trigger GCs so that the newly allocated string moves to old gen.
580    HEAP->CollectGarbage(i::NEW_SPACE);  // in survivor space now
581    HEAP->CollectGarbage(i::NEW_SPACE);  // in old gen now
582    i::Handle<i::String> isymbol = FACTORY->SymbolFromString(istring);
583    CHECK(isymbol->IsSymbol());
584  }
585  HEAP->CollectAllGarbage(false);
586  HEAP->CollectAllGarbage(false);
587}
588
589
590THREADED_TEST(UsingExternalAsciiString) {
591  {
592    v8::HandleScope scope;
593    const char* one_byte_string = "test string";
594    Local<String> string = String::NewExternal(
595        new TestAsciiResource(i::StrDup(one_byte_string)));
596    i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
597    // Trigger GCs so that the newly allocated string moves to old gen.
598    HEAP->CollectGarbage(i::NEW_SPACE);  // in survivor space now
599    HEAP->CollectGarbage(i::NEW_SPACE);  // in old gen now
600    i::Handle<i::String> isymbol = FACTORY->SymbolFromString(istring);
601    CHECK(isymbol->IsSymbol());
602  }
603  HEAP->CollectAllGarbage(false);
604  HEAP->CollectAllGarbage(false);
605}
606
607
608THREADED_TEST(ScavengeExternalString) {
609  TestResource::dispose_count = 0;
610  bool in_new_space = false;
611  {
612    v8::HandleScope scope;
613    uint16_t* two_byte_string = AsciiToTwoByteString("test string");
614    Local<String> string =
615        String::NewExternal(new TestResource(two_byte_string));
616    i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
617    HEAP->CollectGarbage(i::NEW_SPACE);
618    in_new_space = HEAP->InNewSpace(*istring);
619    CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
620    CHECK_EQ(0, TestResource::dispose_count);
621  }
622  HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
623  CHECK_EQ(1, TestResource::dispose_count);
624}
625
626
627THREADED_TEST(ScavengeExternalAsciiString) {
628  TestAsciiResource::dispose_count = 0;
629  bool in_new_space = false;
630  {
631    v8::HandleScope scope;
632    const char* one_byte_string = "test string";
633    Local<String> string = String::NewExternal(
634        new TestAsciiResource(i::StrDup(one_byte_string)));
635    i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
636    HEAP->CollectGarbage(i::NEW_SPACE);
637    in_new_space = HEAP->InNewSpace(*istring);
638    CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
639    CHECK_EQ(0, TestAsciiResource::dispose_count);
640  }
641  HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
642  CHECK_EQ(1, TestAsciiResource::dispose_count);
643}
644
645
646class TestAsciiResourceWithDisposeControl: public TestAsciiResource {
647 public:
648  static int dispose_calls;
649
650  TestAsciiResourceWithDisposeControl(const char* data, bool dispose)
651      : TestAsciiResource(data),
652        dispose_(dispose) { }
653
654  void Dispose() {
655    ++dispose_calls;
656    if (dispose_) delete this;
657  }
658 private:
659  bool dispose_;
660};
661
662
663int TestAsciiResourceWithDisposeControl::dispose_calls = 0;
664
665
666TEST(ExternalStringWithDisposeHandling) {
667  const char* c_source = "1 + 2 * 3";
668
669  // Use a stack allocated external string resource allocated object.
670  TestAsciiResource::dispose_count = 0;
671  TestAsciiResourceWithDisposeControl::dispose_calls = 0;
672  TestAsciiResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
673  {
674    v8::HandleScope scope;
675    LocalContext env;
676    Local<String> source =  String::NewExternal(&res_stack);
677    Local<Script> script = Script::Compile(source);
678    Local<Value> value = script->Run();
679    CHECK(value->IsNumber());
680    CHECK_EQ(7, value->Int32Value());
681    HEAP->CollectAllGarbage(false);
682    CHECK_EQ(0, TestAsciiResource::dispose_count);
683  }
684  i::Isolate::Current()->compilation_cache()->Clear();
685  HEAP->CollectAllGarbage(false);
686  CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
687  CHECK_EQ(0, TestAsciiResource::dispose_count);
688
689  // Use a heap allocated external string resource allocated object.
690  TestAsciiResource::dispose_count = 0;
691  TestAsciiResourceWithDisposeControl::dispose_calls = 0;
692  TestAsciiResource* res_heap =
693      new TestAsciiResourceWithDisposeControl(i::StrDup(c_source), true);
694  {
695    v8::HandleScope scope;
696    LocalContext env;
697    Local<String> source =  String::NewExternal(res_heap);
698    Local<Script> script = Script::Compile(source);
699    Local<Value> value = script->Run();
700    CHECK(value->IsNumber());
701    CHECK_EQ(7, value->Int32Value());
702    HEAP->CollectAllGarbage(false);
703    CHECK_EQ(0, TestAsciiResource::dispose_count);
704  }
705  i::Isolate::Current()->compilation_cache()->Clear();
706  HEAP->CollectAllGarbage(false);
707  CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
708  CHECK_EQ(1, TestAsciiResource::dispose_count);
709}
710
711
712THREADED_TEST(StringConcat) {
713  {
714    v8::HandleScope scope;
715    LocalContext env;
716    const char* one_byte_string_1 = "function a_times_t";
717    const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
718    const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
719    const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
720    const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
721    const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
722    const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
723    Local<String> left = v8_str(one_byte_string_1);
724
725    uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
726    Local<String> right = String::New(two_byte_source);
727    i::DeleteArray(two_byte_source);
728
729    Local<String> source = String::Concat(left, right);
730    right = String::NewExternal(
731        new TestAsciiResource(i::StrDup(one_byte_extern_1)));
732    source = String::Concat(source, right);
733    right = String::NewExternal(
734        new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
735    source = String::Concat(source, right);
736    right = v8_str(one_byte_string_2);
737    source = String::Concat(source, right);
738
739    two_byte_source = AsciiToTwoByteString(two_byte_string_2);
740    right = String::New(two_byte_source);
741    i::DeleteArray(two_byte_source);
742
743    source = String::Concat(source, right);
744    right = String::NewExternal(
745        new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
746    source = String::Concat(source, right);
747    Local<Script> script = Script::Compile(source);
748    Local<Value> value = script->Run();
749    CHECK(value->IsNumber());
750    CHECK_EQ(68, value->Int32Value());
751  }
752  i::Isolate::Current()->compilation_cache()->Clear();
753  HEAP->CollectAllGarbage(false);
754  HEAP->CollectAllGarbage(false);
755}
756
757
758THREADED_TEST(GlobalProperties) {
759  v8::HandleScope scope;
760  LocalContext env;
761  v8::Handle<v8::Object> global = env->Global();
762  global->Set(v8_str("pi"), v8_num(3.1415926));
763  Local<Value> pi = global->Get(v8_str("pi"));
764  CHECK_EQ(3.1415926, pi->NumberValue());
765}
766
767
768static v8::Handle<Value> handle_call(const v8::Arguments& args) {
769  ApiTestFuzzer::Fuzz();
770  return v8_num(102);
771}
772
773
774static v8::Handle<Value> construct_call(const v8::Arguments& args) {
775  ApiTestFuzzer::Fuzz();
776  args.This()->Set(v8_str("x"), v8_num(1));
777  args.This()->Set(v8_str("y"), v8_num(2));
778  return args.This();
779}
780
781static v8::Handle<Value> Return239(Local<String> name, const AccessorInfo&) {
782  ApiTestFuzzer::Fuzz();
783  return v8_num(239);
784}
785
786
787THREADED_TEST(FunctionTemplate) {
788  v8::HandleScope scope;
789  LocalContext env;
790  {
791    Local<v8::FunctionTemplate> fun_templ =
792        v8::FunctionTemplate::New(handle_call);
793    Local<Function> fun = fun_templ->GetFunction();
794    env->Global()->Set(v8_str("obj"), fun);
795    Local<Script> script = v8_compile("obj()");
796    CHECK_EQ(102, script->Run()->Int32Value());
797  }
798  // Use SetCallHandler to initialize a function template, should work like the
799  // previous one.
800  {
801    Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
802    fun_templ->SetCallHandler(handle_call);
803    Local<Function> fun = fun_templ->GetFunction();
804    env->Global()->Set(v8_str("obj"), fun);
805    Local<Script> script = v8_compile("obj()");
806    CHECK_EQ(102, script->Run()->Int32Value());
807  }
808  // Test constructor calls.
809  {
810    Local<v8::FunctionTemplate> fun_templ =
811        v8::FunctionTemplate::New(construct_call);
812    fun_templ->SetClassName(v8_str("funky"));
813    fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), Return239);
814    Local<Function> fun = fun_templ->GetFunction();
815    env->Global()->Set(v8_str("obj"), fun);
816    Local<Script> script = v8_compile("var s = new obj(); s.x");
817    CHECK_EQ(1, script->Run()->Int32Value());
818
819    Local<Value> result = v8_compile("(new obj()).toString()")->Run();
820    CHECK_EQ(v8_str("[object funky]"), result);
821
822    result = v8_compile("(new obj()).m")->Run();
823    CHECK_EQ(239, result->Int32Value());
824  }
825}
826
827
828static void* expected_ptr;
829static v8::Handle<v8::Value> callback(const v8::Arguments& args) {
830  void* ptr = v8::External::Unwrap(args.Data());
831  CHECK_EQ(expected_ptr, ptr);
832  return v8::Boolean::New(true);
833}
834
835
836static void TestExternalPointerWrapping() {
837  v8::HandleScope scope;
838  LocalContext env;
839
840  v8::Handle<v8::Value> data = v8::External::Wrap(expected_ptr);
841
842  v8::Handle<v8::Object> obj = v8::Object::New();
843  obj->Set(v8_str("func"),
844           v8::FunctionTemplate::New(callback, data)->GetFunction());
845  env->Global()->Set(v8_str("obj"), obj);
846
847  CHECK(CompileRun(
848        "function foo() {\n"
849        "  for (var i = 0; i < 13; i++) obj.func();\n"
850        "}\n"
851        "foo(), true")->BooleanValue());
852}
853
854
855THREADED_TEST(ExternalWrap) {
856  // Check heap allocated object.
857  int* ptr = new int;
858  expected_ptr = ptr;
859  TestExternalPointerWrapping();
860  delete ptr;
861
862  // Check stack allocated object.
863  int foo;
864  expected_ptr = &foo;
865  TestExternalPointerWrapping();
866
867  // Check not aligned addresses.
868  const int n = 100;
869  char* s = new char[n];
870  for (int i = 0; i < n; i++) {
871    expected_ptr = s + i;
872    TestExternalPointerWrapping();
873  }
874
875  delete[] s;
876
877  // Check several invalid addresses.
878  expected_ptr = reinterpret_cast<void*>(1);
879  TestExternalPointerWrapping();
880
881  expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
882  TestExternalPointerWrapping();
883
884  expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
885  TestExternalPointerWrapping();
886
887#if defined(V8_HOST_ARCH_X64)
888  // Check a value with a leading 1 bit in x64 Smi encoding.
889  expected_ptr = reinterpret_cast<void*>(0x400000000);
890  TestExternalPointerWrapping();
891
892  expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
893  TestExternalPointerWrapping();
894
895  expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
896  TestExternalPointerWrapping();
897#endif
898}
899
900
901THREADED_TEST(FindInstanceInPrototypeChain) {
902  v8::HandleScope scope;
903  LocalContext env;
904
905  Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New();
906  Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New();
907  Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New();
908  derived->Inherit(base);
909
910  Local<v8::Function> base_function = base->GetFunction();
911  Local<v8::Function> derived_function = derived->GetFunction();
912  Local<v8::Function> other_function = other->GetFunction();
913
914  Local<v8::Object> base_instance = base_function->NewInstance();
915  Local<v8::Object> derived_instance = derived_function->NewInstance();
916  Local<v8::Object> derived_instance2 = derived_function->NewInstance();
917  Local<v8::Object> other_instance = other_function->NewInstance();
918  derived_instance2->Set(v8_str("__proto__"), derived_instance);
919  other_instance->Set(v8_str("__proto__"), derived_instance2);
920
921  // base_instance is only an instance of base.
922  CHECK_EQ(base_instance,
923           base_instance->FindInstanceInPrototypeChain(base));
924  CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
925  CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
926
927  // derived_instance is an instance of base and derived.
928  CHECK_EQ(derived_instance,
929           derived_instance->FindInstanceInPrototypeChain(base));
930  CHECK_EQ(derived_instance,
931           derived_instance->FindInstanceInPrototypeChain(derived));
932  CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
933
934  // other_instance is an instance of other and its immediate
935  // prototype derived_instance2 is an instance of base and derived.
936  // Note, derived_instance is an instance of base and derived too,
937  // but it comes after derived_instance2 in the prototype chain of
938  // other_instance.
939  CHECK_EQ(derived_instance2,
940           other_instance->FindInstanceInPrototypeChain(base));
941  CHECK_EQ(derived_instance2,
942           other_instance->FindInstanceInPrototypeChain(derived));
943  CHECK_EQ(other_instance,
944           other_instance->FindInstanceInPrototypeChain(other));
945}
946
947
948THREADED_TEST(TinyInteger) {
949  v8::HandleScope scope;
950  LocalContext env;
951  int32_t value = 239;
952  Local<v8::Integer> value_obj = v8::Integer::New(value);
953  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
954}
955
956
957THREADED_TEST(BigSmiInteger) {
958  v8::HandleScope scope;
959  LocalContext env;
960  int32_t value = i::Smi::kMaxValue;
961  // We cannot add one to a Smi::kMaxValue without wrapping.
962  if (i::kSmiValueSize < 32) {
963    CHECK(i::Smi::IsValid(value));
964    CHECK(!i::Smi::IsValid(value + 1));
965    Local<v8::Integer> value_obj = v8::Integer::New(value);
966    CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
967  }
968}
969
970
971THREADED_TEST(BigInteger) {
972  v8::HandleScope scope;
973  LocalContext env;
974  // We cannot add one to a Smi::kMaxValue without wrapping.
975  if (i::kSmiValueSize < 32) {
976    // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
977    // The code will not be run in that case, due to the "if" guard.
978    int32_t value =
979        static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
980    CHECK(value > i::Smi::kMaxValue);
981    CHECK(!i::Smi::IsValid(value));
982    Local<v8::Integer> value_obj = v8::Integer::New(value);
983    CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
984  }
985}
986
987
988THREADED_TEST(TinyUnsignedInteger) {
989  v8::HandleScope scope;
990  LocalContext env;
991  uint32_t value = 239;
992  Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
993  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
994}
995
996
997THREADED_TEST(BigUnsignedSmiInteger) {
998  v8::HandleScope scope;
999  LocalContext env;
1000  uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
1001  CHECK(i::Smi::IsValid(value));
1002  CHECK(!i::Smi::IsValid(value + 1));
1003  Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1004  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1005}
1006
1007
1008THREADED_TEST(BigUnsignedInteger) {
1009  v8::HandleScope scope;
1010  LocalContext env;
1011  uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1012  CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1013  CHECK(!i::Smi::IsValid(value));
1014  Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1015  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1016}
1017
1018
1019THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1020  v8::HandleScope scope;
1021  LocalContext env;
1022  uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1023  uint32_t value = INT32_MAX_AS_UINT + 1;
1024  CHECK(value > INT32_MAX_AS_UINT);  // No overflow.
1025  Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1026  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1027}
1028
1029
1030THREADED_TEST(Number) {
1031  v8::HandleScope scope;
1032  LocalContext env;
1033  double PI = 3.1415926;
1034  Local<v8::Number> pi_obj = v8::Number::New(PI);
1035  CHECK_EQ(PI, pi_obj->NumberValue());
1036}
1037
1038
1039THREADED_TEST(ToNumber) {
1040  v8::HandleScope scope;
1041  LocalContext env;
1042  Local<String> str = v8_str("3.1415926");
1043  CHECK_EQ(3.1415926, str->NumberValue());
1044  v8::Handle<v8::Boolean> t = v8::True();
1045  CHECK_EQ(1.0, t->NumberValue());
1046  v8::Handle<v8::Boolean> f = v8::False();
1047  CHECK_EQ(0.0, f->NumberValue());
1048}
1049
1050
1051THREADED_TEST(Date) {
1052  v8::HandleScope scope;
1053  LocalContext env;
1054  double PI = 3.1415926;
1055  Local<Value> date_obj = v8::Date::New(PI);
1056  CHECK_EQ(3.0, date_obj->NumberValue());
1057}
1058
1059
1060THREADED_TEST(Boolean) {
1061  v8::HandleScope scope;
1062  LocalContext env;
1063  v8::Handle<v8::Boolean> t = v8::True();
1064  CHECK(t->Value());
1065  v8::Handle<v8::Boolean> f = v8::False();
1066  CHECK(!f->Value());
1067  v8::Handle<v8::Primitive> u = v8::Undefined();
1068  CHECK(!u->BooleanValue());
1069  v8::Handle<v8::Primitive> n = v8::Null();
1070  CHECK(!n->BooleanValue());
1071  v8::Handle<String> str1 = v8_str("");
1072  CHECK(!str1->BooleanValue());
1073  v8::Handle<String> str2 = v8_str("x");
1074  CHECK(str2->BooleanValue());
1075  CHECK(!v8::Number::New(0)->BooleanValue());
1076  CHECK(v8::Number::New(-1)->BooleanValue());
1077  CHECK(v8::Number::New(1)->BooleanValue());
1078  CHECK(v8::Number::New(42)->BooleanValue());
1079  CHECK(!v8_compile("NaN")->Run()->BooleanValue());
1080}
1081
1082
1083static v8::Handle<Value> DummyCallHandler(const v8::Arguments& args) {
1084  ApiTestFuzzer::Fuzz();
1085  return v8_num(13.4);
1086}
1087
1088
1089static v8::Handle<Value> GetM(Local<String> name, const AccessorInfo&) {
1090  ApiTestFuzzer::Fuzz();
1091  return v8_num(876);
1092}
1093
1094
1095THREADED_TEST(GlobalPrototype) {
1096  v8::HandleScope scope;
1097  v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
1098  func_templ->PrototypeTemplate()->Set(
1099      "dummy",
1100      v8::FunctionTemplate::New(DummyCallHandler));
1101  v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1102  templ->Set("x", v8_num(200));
1103  templ->SetAccessor(v8_str("m"), GetM);
1104  LocalContext env(0, templ);
1105  v8::Handle<v8::Object> obj = env->Global();
1106  v8::Handle<Script> script = v8_compile("dummy()");
1107  v8::Handle<Value> result = script->Run();
1108  CHECK_EQ(13.4, result->NumberValue());
1109  CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1110  CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1111}
1112
1113
1114THREADED_TEST(ObjectTemplate) {
1115  v8::HandleScope scope;
1116  Local<ObjectTemplate> templ1 = ObjectTemplate::New();
1117  templ1->Set("x", v8_num(10));
1118  templ1->Set("y", v8_num(13));
1119  LocalContext env;
1120  Local<v8::Object> instance1 = templ1->NewInstance();
1121  env->Global()->Set(v8_str("p"), instance1);
1122  CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1123  CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1124  Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
1125  fun->PrototypeTemplate()->Set("nirk", v8_num(123));
1126  Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1127  templ2->Set("a", v8_num(12));
1128  templ2->Set("b", templ1);
1129  Local<v8::Object> instance2 = templ2->NewInstance();
1130  env->Global()->Set(v8_str("q"), instance2);
1131  CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1132  CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1133  CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1134  CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1135}
1136
1137
1138static v8::Handle<Value> GetFlabby(const v8::Arguments& args) {
1139  ApiTestFuzzer::Fuzz();
1140  return v8_num(17.2);
1141}
1142
1143
1144static v8::Handle<Value> GetKnurd(Local<String> property, const AccessorInfo&) {
1145  ApiTestFuzzer::Fuzz();
1146  return v8_num(15.2);
1147}
1148
1149
1150THREADED_TEST(DescriptorInheritance) {
1151  v8::HandleScope scope;
1152  v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New();
1153  super->PrototypeTemplate()->Set("flabby",
1154                                  v8::FunctionTemplate::New(GetFlabby));
1155  super->PrototypeTemplate()->Set("PI", v8_num(3.14));
1156
1157  super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1158
1159  v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New();
1160  base1->Inherit(super);
1161  base1->PrototypeTemplate()->Set("v1", v8_num(20.1));
1162
1163  v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New();
1164  base2->Inherit(super);
1165  base2->PrototypeTemplate()->Set("v2", v8_num(10.1));
1166
1167  LocalContext env;
1168
1169  env->Global()->Set(v8_str("s"), super->GetFunction());
1170  env->Global()->Set(v8_str("base1"), base1->GetFunction());
1171  env->Global()->Set(v8_str("base2"), base2->GetFunction());
1172
1173  // Checks right __proto__ chain.
1174  CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1175  CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1176
1177  CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1178
1179  // Instance accessor should not be visible on function object or its prototype
1180  CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1181  CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1182  CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1183
1184  env->Global()->Set(v8_str("obj"),
1185                     base1->GetFunction()->NewInstance());
1186  CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1187  CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1188  CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1189  CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1190  CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1191
1192  env->Global()->Set(v8_str("obj2"),
1193                     base2->GetFunction()->NewInstance());
1194  CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1195  CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1196  CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1197  CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1198  CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1199
1200  // base1 and base2 cannot cross reference to each's prototype
1201  CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1202  CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1203}
1204
1205
1206int echo_named_call_count;
1207
1208
1209static v8::Handle<Value> EchoNamedProperty(Local<String> name,
1210                                           const AccessorInfo& info) {
1211  ApiTestFuzzer::Fuzz();
1212  CHECK_EQ(v8_str("data"), info.Data());
1213  echo_named_call_count++;
1214  return name;
1215}
1216
1217
1218THREADED_TEST(NamedPropertyHandlerGetter) {
1219  echo_named_call_count = 0;
1220  v8::HandleScope scope;
1221  v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1222  templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
1223                                                     0, 0, 0, 0,
1224                                                     v8_str("data"));
1225  LocalContext env;
1226  env->Global()->Set(v8_str("obj"),
1227                     templ->GetFunction()->NewInstance());
1228  CHECK_EQ(echo_named_call_count, 0);
1229  v8_compile("obj.x")->Run();
1230  CHECK_EQ(echo_named_call_count, 1);
1231  const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
1232  v8::Handle<Value> str = CompileRun(code);
1233  String::AsciiValue value(str);
1234  CHECK_EQ(*value, "oddlepoddle");
1235  // Check default behavior
1236  CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
1237  CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
1238  CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
1239}
1240
1241
1242int echo_indexed_call_count = 0;
1243
1244
1245static v8::Handle<Value> EchoIndexedProperty(uint32_t index,
1246                                             const AccessorInfo& info) {
1247  ApiTestFuzzer::Fuzz();
1248  CHECK_EQ(v8_num(637), info.Data());
1249  echo_indexed_call_count++;
1250  return v8_num(index);
1251}
1252
1253
1254THREADED_TEST(IndexedPropertyHandlerGetter) {
1255  v8::HandleScope scope;
1256  v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1257  templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
1258                                                       0, 0, 0, 0,
1259                                                       v8_num(637));
1260  LocalContext env;
1261  env->Global()->Set(v8_str("obj"),
1262                     templ->GetFunction()->NewInstance());
1263  Local<Script> script = v8_compile("obj[900]");
1264  CHECK_EQ(script->Run()->Int32Value(), 900);
1265}
1266
1267
1268v8::Handle<v8::Object> bottom;
1269
1270static v8::Handle<Value> CheckThisIndexedPropertyHandler(
1271    uint32_t index,
1272    const AccessorInfo& info) {
1273  ApiTestFuzzer::Fuzz();
1274  CHECK(info.This()->Equals(bottom));
1275  return v8::Handle<Value>();
1276}
1277
1278static v8::Handle<Value> CheckThisNamedPropertyHandler(
1279    Local<String> name,
1280    const AccessorInfo& info) {
1281  ApiTestFuzzer::Fuzz();
1282  CHECK(info.This()->Equals(bottom));
1283  return v8::Handle<Value>();
1284}
1285
1286
1287v8::Handle<Value> CheckThisIndexedPropertySetter(uint32_t index,
1288                                                 Local<Value> value,
1289                                                 const AccessorInfo& info) {
1290  ApiTestFuzzer::Fuzz();
1291  CHECK(info.This()->Equals(bottom));
1292  return v8::Handle<Value>();
1293}
1294
1295
1296v8::Handle<Value> CheckThisNamedPropertySetter(Local<String> property,
1297                                               Local<Value> value,
1298                                               const AccessorInfo& info) {
1299  ApiTestFuzzer::Fuzz();
1300  CHECK(info.This()->Equals(bottom));
1301  return v8::Handle<Value>();
1302}
1303
1304v8::Handle<v8::Integer> CheckThisIndexedPropertyQuery(
1305    uint32_t index,
1306    const AccessorInfo& info) {
1307  ApiTestFuzzer::Fuzz();
1308  CHECK(info.This()->Equals(bottom));
1309  return v8::Handle<v8::Integer>();
1310}
1311
1312
1313v8::Handle<v8::Integer> CheckThisNamedPropertyQuery(Local<String> property,
1314                                                    const AccessorInfo& info) {
1315  ApiTestFuzzer::Fuzz();
1316  CHECK(info.This()->Equals(bottom));
1317  return v8::Handle<v8::Integer>();
1318}
1319
1320
1321v8::Handle<v8::Boolean> CheckThisIndexedPropertyDeleter(
1322    uint32_t index,
1323    const AccessorInfo& info) {
1324  ApiTestFuzzer::Fuzz();
1325  CHECK(info.This()->Equals(bottom));
1326  return v8::Handle<v8::Boolean>();
1327}
1328
1329
1330v8::Handle<v8::Boolean> CheckThisNamedPropertyDeleter(
1331    Local<String> property,
1332    const AccessorInfo& info) {
1333  ApiTestFuzzer::Fuzz();
1334  CHECK(info.This()->Equals(bottom));
1335  return v8::Handle<v8::Boolean>();
1336}
1337
1338
1339v8::Handle<v8::Array> CheckThisIndexedPropertyEnumerator(
1340    const AccessorInfo& info) {
1341  ApiTestFuzzer::Fuzz();
1342  CHECK(info.This()->Equals(bottom));
1343  return v8::Handle<v8::Array>();
1344}
1345
1346
1347v8::Handle<v8::Array> CheckThisNamedPropertyEnumerator(
1348    const AccessorInfo& info) {
1349  ApiTestFuzzer::Fuzz();
1350  CHECK(info.This()->Equals(bottom));
1351  return v8::Handle<v8::Array>();
1352}
1353
1354
1355THREADED_TEST(PropertyHandlerInPrototype) {
1356  v8::HandleScope scope;
1357  LocalContext env;
1358
1359  // Set up a prototype chain with three interceptors.
1360  v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1361  templ->InstanceTemplate()->SetIndexedPropertyHandler(
1362      CheckThisIndexedPropertyHandler,
1363      CheckThisIndexedPropertySetter,
1364      CheckThisIndexedPropertyQuery,
1365      CheckThisIndexedPropertyDeleter,
1366      CheckThisIndexedPropertyEnumerator);
1367
1368  templ->InstanceTemplate()->SetNamedPropertyHandler(
1369      CheckThisNamedPropertyHandler,
1370      CheckThisNamedPropertySetter,
1371      CheckThisNamedPropertyQuery,
1372      CheckThisNamedPropertyDeleter,
1373      CheckThisNamedPropertyEnumerator);
1374
1375  bottom = templ->GetFunction()->NewInstance();
1376  Local<v8::Object> top = templ->GetFunction()->NewInstance();
1377  Local<v8::Object> middle = templ->GetFunction()->NewInstance();
1378
1379  bottom->Set(v8_str("__proto__"), middle);
1380  middle->Set(v8_str("__proto__"), top);
1381  env->Global()->Set(v8_str("obj"), bottom);
1382
1383  // Indexed and named get.
1384  Script::Compile(v8_str("obj[0]"))->Run();
1385  Script::Compile(v8_str("obj.x"))->Run();
1386
1387  // Indexed and named set.
1388  Script::Compile(v8_str("obj[1] = 42"))->Run();
1389  Script::Compile(v8_str("obj.y = 42"))->Run();
1390
1391  // Indexed and named query.
1392  Script::Compile(v8_str("0 in obj"))->Run();
1393  Script::Compile(v8_str("'x' in obj"))->Run();
1394
1395  // Indexed and named deleter.
1396  Script::Compile(v8_str("delete obj[0]"))->Run();
1397  Script::Compile(v8_str("delete obj.x"))->Run();
1398
1399  // Enumerators.
1400  Script::Compile(v8_str("for (var p in obj) ;"))->Run();
1401}
1402
1403
1404static v8::Handle<Value> PrePropertyHandlerGet(Local<String> key,
1405                                               const AccessorInfo& info) {
1406  ApiTestFuzzer::Fuzz();
1407  if (v8_str("pre")->Equals(key)) {
1408    return v8_str("PrePropertyHandler: pre");
1409  }
1410  return v8::Handle<String>();
1411}
1412
1413
1414static v8::Handle<v8::Integer> PrePropertyHandlerQuery(Local<String> key,
1415                                                       const AccessorInfo&) {
1416  if (v8_str("pre")->Equals(key)) {
1417    return v8::Integer::New(v8::None);
1418  }
1419
1420  return v8::Handle<v8::Integer>();  // do not intercept the call
1421}
1422
1423
1424THREADED_TEST(PrePropertyHandler) {
1425  v8::HandleScope scope;
1426  v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
1427  desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
1428                                                    0,
1429                                                    PrePropertyHandlerQuery);
1430  LocalContext env(NULL, desc->InstanceTemplate());
1431  Script::Compile(v8_str(
1432      "var pre = 'Object: pre'; var on = 'Object: on';"))->Run();
1433  v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run();
1434  CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
1435  v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run();
1436  CHECK_EQ(v8_str("Object: on"), result_on);
1437  v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run();
1438  CHECK(result_post.IsEmpty());
1439}
1440
1441
1442THREADED_TEST(UndefinedIsNotEnumerable) {
1443  v8::HandleScope scope;
1444  LocalContext env;
1445  v8::Handle<Value> result = Script::Compile(v8_str(
1446      "this.propertyIsEnumerable(undefined)"))->Run();
1447  CHECK(result->IsFalse());
1448}
1449
1450
1451v8::Handle<Script> call_recursively_script;
1452static const int kTargetRecursionDepth = 200;  // near maximum
1453
1454
1455static v8::Handle<Value> CallScriptRecursivelyCall(const v8::Arguments& args) {
1456  ApiTestFuzzer::Fuzz();
1457  int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1458  if (depth == kTargetRecursionDepth) return v8::Undefined();
1459  args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1460  return call_recursively_script->Run();
1461}
1462
1463
1464static v8::Handle<Value> CallFunctionRecursivelyCall(
1465    const v8::Arguments& args) {
1466  ApiTestFuzzer::Fuzz();
1467  int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1468  if (depth == kTargetRecursionDepth) {
1469    printf("[depth = %d]\n", depth);
1470    return v8::Undefined();
1471  }
1472  args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1473  v8::Handle<Value> function =
1474      args.This()->Get(v8_str("callFunctionRecursively"));
1475  return function.As<Function>()->Call(args.This(), 0, NULL);
1476}
1477
1478
1479THREADED_TEST(DeepCrossLanguageRecursion) {
1480  v8::HandleScope scope;
1481  v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
1482  global->Set(v8_str("callScriptRecursively"),
1483              v8::FunctionTemplate::New(CallScriptRecursivelyCall));
1484  global->Set(v8_str("callFunctionRecursively"),
1485              v8::FunctionTemplate::New(CallFunctionRecursivelyCall));
1486  LocalContext env(NULL, global);
1487
1488  env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1489  call_recursively_script = v8_compile("callScriptRecursively()");
1490  v8::Handle<Value> result = call_recursively_script->Run();
1491  call_recursively_script = v8::Handle<Script>();
1492
1493  env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1494  Script::Compile(v8_str("callFunctionRecursively()"))->Run();
1495}
1496
1497
1498static v8::Handle<Value>
1499    ThrowingPropertyHandlerGet(Local<String> key, const AccessorInfo&) {
1500  ApiTestFuzzer::Fuzz();
1501  return v8::ThrowException(key);
1502}
1503
1504
1505static v8::Handle<Value> ThrowingPropertyHandlerSet(Local<String> key,
1506                                                    Local<Value>,
1507                                                    const AccessorInfo&) {
1508  v8::ThrowException(key);
1509  return v8::Undefined();  // not the same as v8::Handle<v8::Value>()
1510}
1511
1512
1513THREADED_TEST(CallbackExceptionRegression) {
1514  v8::HandleScope scope;
1515  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
1516  obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
1517                               ThrowingPropertyHandlerSet);
1518  LocalContext env;
1519  env->Global()->Set(v8_str("obj"), obj->NewInstance());
1520  v8::Handle<Value> otto = Script::Compile(v8_str(
1521      "try { with (obj) { otto; } } catch (e) { e; }"))->Run();
1522  CHECK_EQ(v8_str("otto"), otto);
1523  v8::Handle<Value> netto = Script::Compile(v8_str(
1524      "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run();
1525  CHECK_EQ(v8_str("netto"), netto);
1526}
1527
1528
1529THREADED_TEST(FunctionPrototype) {
1530  v8::HandleScope scope;
1531  Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New();
1532  Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
1533  LocalContext env;
1534  env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
1535  Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak"));
1536  CHECK_EQ(script->Run()->Int32Value(), 321);
1537}
1538
1539
1540THREADED_TEST(InternalFields) {
1541  v8::HandleScope scope;
1542  LocalContext env;
1543
1544  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1545  Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1546  instance_templ->SetInternalFieldCount(1);
1547  Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1548  CHECK_EQ(1, obj->InternalFieldCount());
1549  CHECK(obj->GetInternalField(0)->IsUndefined());
1550  obj->SetInternalField(0, v8_num(17));
1551  CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
1552}
1553
1554
1555THREADED_TEST(GlobalObjectInternalFields) {
1556  v8::HandleScope scope;
1557  Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
1558  global_template->SetInternalFieldCount(1);
1559  LocalContext env(NULL, global_template);
1560  v8::Handle<v8::Object> global_proxy = env->Global();
1561  v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
1562  CHECK_EQ(1, global->InternalFieldCount());
1563  CHECK(global->GetInternalField(0)->IsUndefined());
1564  global->SetInternalField(0, v8_num(17));
1565  CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
1566}
1567
1568
1569THREADED_TEST(InternalFieldsNativePointers) {
1570  v8::HandleScope scope;
1571  LocalContext env;
1572
1573  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1574  Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1575  instance_templ->SetInternalFieldCount(1);
1576  Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1577  CHECK_EQ(1, obj->InternalFieldCount());
1578  CHECK(obj->GetPointerFromInternalField(0) == NULL);
1579
1580  char* data = new char[100];
1581
1582  void* aligned = data;
1583  CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
1584  void* unaligned = data + 1;
1585  CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
1586
1587  // Check reading and writing aligned pointers.
1588  obj->SetPointerInInternalField(0, aligned);
1589  HEAP->CollectAllGarbage(false);
1590  CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1591
1592  // Check reading and writing unaligned pointers.
1593  obj->SetPointerInInternalField(0, unaligned);
1594  HEAP->CollectAllGarbage(false);
1595  CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1596
1597  delete[] data;
1598}
1599
1600
1601THREADED_TEST(InternalFieldsNativePointersAndExternal) {
1602  v8::HandleScope scope;
1603  LocalContext env;
1604
1605  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1606  Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1607  instance_templ->SetInternalFieldCount(1);
1608  Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1609  CHECK_EQ(1, obj->InternalFieldCount());
1610  CHECK(obj->GetPointerFromInternalField(0) == NULL);
1611
1612  char* data = new char[100];
1613
1614  void* aligned = data;
1615  CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
1616  void* unaligned = data + 1;
1617  CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
1618
1619  obj->SetPointerInInternalField(0, aligned);
1620  HEAP->CollectAllGarbage(false);
1621  CHECK_EQ(aligned, v8::External::Unwrap(obj->GetInternalField(0)));
1622
1623  obj->SetPointerInInternalField(0, unaligned);
1624  HEAP->CollectAllGarbage(false);
1625  CHECK_EQ(unaligned, v8::External::Unwrap(obj->GetInternalField(0)));
1626
1627  obj->SetInternalField(0, v8::External::Wrap(aligned));
1628  HEAP->CollectAllGarbage(false);
1629  CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1630
1631  obj->SetInternalField(0, v8::External::Wrap(unaligned));
1632  HEAP->CollectAllGarbage(false);
1633  CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1634
1635  delete[] data;
1636}
1637
1638
1639THREADED_TEST(IdentityHash) {
1640  v8::HandleScope scope;
1641  LocalContext env;
1642
1643  // Ensure that the test starts with an fresh heap to test whether the hash
1644  // code is based on the address.
1645  HEAP->CollectAllGarbage(false);
1646  Local<v8::Object> obj = v8::Object::New();
1647  int hash = obj->GetIdentityHash();
1648  int hash1 = obj->GetIdentityHash();
1649  CHECK_EQ(hash, hash1);
1650  int hash2 = v8::Object::New()->GetIdentityHash();
1651  // Since the identity hash is essentially a random number two consecutive
1652  // objects should not be assigned the same hash code. If the test below fails
1653  // the random number generator should be evaluated.
1654  CHECK_NE(hash, hash2);
1655  HEAP->CollectAllGarbage(false);
1656  int hash3 = v8::Object::New()->GetIdentityHash();
1657  // Make sure that the identity hash is not based on the initial address of
1658  // the object alone. If the test below fails the random number generator
1659  // should be evaluated.
1660  CHECK_NE(hash, hash3);
1661  int hash4 = obj->GetIdentityHash();
1662  CHECK_EQ(hash, hash4);
1663
1664  // Check identity hashes behaviour in the presence of JS accessors.
1665  // Put a getter for 'v8::IdentityHash' on the Object's prototype:
1666  {
1667    CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
1668    Local<v8::Object> o1 = v8::Object::New();
1669    Local<v8::Object> o2 = v8::Object::New();
1670    CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
1671  }
1672  {
1673    CompileRun(
1674        "function cnst() { return 42; };\n"
1675        "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
1676    Local<v8::Object> o1 = v8::Object::New();
1677    Local<v8::Object> o2 = v8::Object::New();
1678    CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
1679  }
1680}
1681
1682
1683THREADED_TEST(HiddenProperties) {
1684  v8::HandleScope scope;
1685  LocalContext env;
1686
1687  v8::Local<v8::Object> obj = v8::Object::New();
1688  v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1689  v8::Local<v8::String> empty = v8_str("");
1690  v8::Local<v8::String> prop_name = v8_str("prop_name");
1691
1692  HEAP->CollectAllGarbage(false);
1693
1694  // Make sure delete of a non-existent hidden value works
1695  CHECK(obj->DeleteHiddenValue(key));
1696
1697  CHECK(obj->SetHiddenValue(key, v8::Integer::New(1503)));
1698  CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
1699  CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
1700  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1701
1702  HEAP->CollectAllGarbage(false);
1703
1704  // Make sure we do not find the hidden property.
1705  CHECK(!obj->Has(empty));
1706  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1707  CHECK(obj->Get(empty)->IsUndefined());
1708  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1709  CHECK(obj->Set(empty, v8::Integer::New(2003)));
1710  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1711  CHECK_EQ(2003, obj->Get(empty)->Int32Value());
1712
1713  HEAP->CollectAllGarbage(false);
1714
1715  // Add another property and delete it afterwards to force the object in
1716  // slow case.
1717  CHECK(obj->Set(prop_name, v8::Integer::New(2008)));
1718  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1719  CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
1720  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1721  CHECK(obj->Delete(prop_name));
1722  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1723
1724  HEAP->CollectAllGarbage(false);
1725
1726  CHECK(obj->DeleteHiddenValue(key));
1727  CHECK(obj->GetHiddenValue(key).IsEmpty());
1728}
1729
1730
1731static bool interceptor_for_hidden_properties_called;
1732static v8::Handle<Value> InterceptorForHiddenProperties(
1733    Local<String> name, const AccessorInfo& info) {
1734  interceptor_for_hidden_properties_called = true;
1735  return v8::Handle<Value>();
1736}
1737
1738
1739THREADED_TEST(HiddenPropertiesWithInterceptors) {
1740  v8::HandleScope scope;
1741  LocalContext context;
1742
1743  interceptor_for_hidden_properties_called = false;
1744
1745  v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1746
1747  // Associate an interceptor with an object and start setting hidden values.
1748  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
1749  Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
1750  instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
1751  Local<v8::Function> function = fun_templ->GetFunction();
1752  Local<v8::Object> obj = function->NewInstance();
1753  CHECK(obj->SetHiddenValue(key, v8::Integer::New(2302)));
1754  CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
1755  CHECK(!interceptor_for_hidden_properties_called);
1756}
1757
1758
1759THREADED_TEST(External) {
1760  v8::HandleScope scope;
1761  int x = 3;
1762  Local<v8::External> ext = v8::External::New(&x);
1763  LocalContext env;
1764  env->Global()->Set(v8_str("ext"), ext);
1765  Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
1766  v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
1767  int* ptr = static_cast<int*>(reext->Value());
1768  CHECK_EQ(x, 3);
1769  *ptr = 10;
1770  CHECK_EQ(x, 10);
1771
1772  // Make sure unaligned pointers are wrapped properly.
1773  char* data = i::StrDup("0123456789");
1774  Local<v8::Value> zero = v8::External::Wrap(&data[0]);
1775  Local<v8::Value> one = v8::External::Wrap(&data[1]);
1776  Local<v8::Value> two = v8::External::Wrap(&data[2]);
1777  Local<v8::Value> three = v8::External::Wrap(&data[3]);
1778
1779  char* char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(zero));
1780  CHECK_EQ('0', *char_ptr);
1781  char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(one));
1782  CHECK_EQ('1', *char_ptr);
1783  char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(two));
1784  CHECK_EQ('2', *char_ptr);
1785  char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(three));
1786  CHECK_EQ('3', *char_ptr);
1787  i::DeleteArray(data);
1788}
1789
1790
1791THREADED_TEST(GlobalHandle) {
1792  v8::Persistent<String> global;
1793  {
1794    v8::HandleScope scope;
1795    Local<String> str = v8_str("str");
1796    global = v8::Persistent<String>::New(str);
1797  }
1798  CHECK_EQ(global->Length(), 3);
1799  global.Dispose();
1800}
1801
1802
1803static int NumberOfWeakCalls = 0;
1804static void WeakPointerCallback(Persistent<Value> handle, void* id) {
1805  CHECK_EQ(reinterpret_cast<void*>(1234), id);
1806  NumberOfWeakCalls++;
1807  handle.Dispose();
1808}
1809
1810THREADED_TEST(ApiObjectGroups) {
1811  HandleScope scope;
1812  LocalContext env;
1813
1814  NumberOfWeakCalls = 0;
1815
1816  Persistent<Object> g1s1;
1817  Persistent<Object> g1s2;
1818  Persistent<Object> g1c1;
1819  Persistent<Object> g2s1;
1820  Persistent<Object> g2s2;
1821  Persistent<Object> g2c1;
1822
1823  {
1824    HandleScope scope;
1825    g1s1 = Persistent<Object>::New(Object::New());
1826    g1s2 = Persistent<Object>::New(Object::New());
1827    g1c1 = Persistent<Object>::New(Object::New());
1828    g1s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1829    g1s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1830    g1c1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1831
1832    g2s1 = Persistent<Object>::New(Object::New());
1833    g2s2 = Persistent<Object>::New(Object::New());
1834    g2c1 = Persistent<Object>::New(Object::New());
1835    g2s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1836    g2s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1837    g2c1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1838  }
1839
1840  Persistent<Object> root = Persistent<Object>::New(g1s1);  // make a root.
1841
1842  // Connect group 1 and 2, make a cycle.
1843  CHECK(g1s2->Set(0, g2s2));
1844  CHECK(g2s1->Set(0, g1s1));
1845
1846  {
1847    Persistent<Value> g1_objects[] = { g1s1, g1s2 };
1848    Persistent<Value> g1_children[] = { g1c1 };
1849    Persistent<Value> g2_objects[] = { g2s1, g2s2 };
1850    Persistent<Value> g2_children[] = { g2c1 };
1851    V8::AddObjectGroup(g1_objects, 2);
1852    V8::AddImplicitReferences(g1s1, g1_children, 1);
1853    V8::AddObjectGroup(g2_objects, 2);
1854    V8::AddImplicitReferences(g2s2, g2_children, 1);
1855  }
1856  // Do a full GC
1857  HEAP->CollectGarbage(i::OLD_POINTER_SPACE);
1858
1859  // All object should be alive.
1860  CHECK_EQ(0, NumberOfWeakCalls);
1861
1862  // Weaken the root.
1863  root.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1864  // But make children strong roots---all the objects (except for children)
1865  // should be collectable now.
1866  g1c1.ClearWeak();
1867  g2c1.ClearWeak();
1868
1869  // Groups are deleted, rebuild groups.
1870  {
1871    Persistent<Value> g1_objects[] = { g1s1, g1s2 };
1872    Persistent<Value> g1_children[] = { g1c1 };
1873    Persistent<Value> g2_objects[] = { g2s1, g2s2 };
1874    Persistent<Value> g2_children[] = { g2c1 };
1875    V8::AddObjectGroup(g1_objects, 2);
1876    V8::AddImplicitReferences(g1s1, g1_children, 1);
1877    V8::AddObjectGroup(g2_objects, 2);
1878    V8::AddImplicitReferences(g2s2, g2_children, 1);
1879  }
1880
1881  HEAP->CollectGarbage(i::OLD_POINTER_SPACE);
1882
1883  // All objects should be gone. 5 global handles in total.
1884  CHECK_EQ(5, NumberOfWeakCalls);
1885
1886  // And now make children weak again and collect them.
1887  g1c1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1888  g2c1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1889
1890  HEAP->CollectGarbage(i::OLD_POINTER_SPACE);
1891  CHECK_EQ(7, NumberOfWeakCalls);
1892}
1893
1894
1895THREADED_TEST(ApiObjectGroupsCycle) {
1896  HandleScope scope;
1897  LocalContext env;
1898
1899  NumberOfWeakCalls = 0;
1900
1901  Persistent<Object> g1s1;
1902  Persistent<Object> g1s2;
1903  Persistent<Object> g2s1;
1904  Persistent<Object> g2s2;
1905  Persistent<Object> g3s1;
1906  Persistent<Object> g3s2;
1907
1908  {
1909    HandleScope scope;
1910    g1s1 = Persistent<Object>::New(Object::New());
1911    g1s2 = Persistent<Object>::New(Object::New());
1912    g1s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1913    g1s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1914
1915    g2s1 = Persistent<Object>::New(Object::New());
1916    g2s2 = Persistent<Object>::New(Object::New());
1917    g2s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1918    g2s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1919
1920    g3s1 = Persistent<Object>::New(Object::New());
1921    g3s2 = Persistent<Object>::New(Object::New());
1922    g3s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1923    g3s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1924  }
1925
1926  Persistent<Object> root = Persistent<Object>::New(g1s1);  // make a root.
1927
1928  // Connect groups.  We're building the following cycle:
1929  // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
1930  // groups.
1931  {
1932    Persistent<Value> g1_objects[] = { g1s1, g1s2 };
1933    Persistent<Value> g1_children[] = { g2s1 };
1934    Persistent<Value> g2_objects[] = { g2s1, g2s2 };
1935    Persistent<Value> g2_children[] = { g3s1 };
1936    Persistent<Value> g3_objects[] = { g3s1, g3s2 };
1937    Persistent<Value> g3_children[] = { g1s1 };
1938    V8::AddObjectGroup(g1_objects, 2);
1939    V8::AddImplicitReferences(g1s1, g1_children, 1);
1940    V8::AddObjectGroup(g2_objects, 2);
1941    V8::AddImplicitReferences(g2s1, g2_children, 1);
1942    V8::AddObjectGroup(g3_objects, 2);
1943    V8::AddImplicitReferences(g3s1, g3_children, 1);
1944  }
1945  // Do a full GC
1946  HEAP->CollectGarbage(i::OLD_POINTER_SPACE);
1947
1948  // All object should be alive.
1949  CHECK_EQ(0, NumberOfWeakCalls);
1950
1951  // Weaken the root.
1952  root.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1953
1954  // Groups are deleted, rebuild groups.
1955  {
1956    Persistent<Value> g1_objects[] = { g1s1, g1s2 };
1957    Persistent<Value> g1_children[] = { g2s1 };
1958    Persistent<Value> g2_objects[] = { g2s1, g2s2 };
1959    Persistent<Value> g2_children[] = { g3s1 };
1960    Persistent<Value> g3_objects[] = { g3s1, g3s2 };
1961    Persistent<Value> g3_children[] = { g1s1 };
1962    V8::AddObjectGroup(g1_objects, 2);
1963    V8::AddImplicitReferences(g1s1, g1_children, 1);
1964    V8::AddObjectGroup(g2_objects, 2);
1965    V8::AddImplicitReferences(g2s1, g2_children, 1);
1966    V8::AddObjectGroup(g3_objects, 2);
1967    V8::AddImplicitReferences(g3s1, g3_children, 1);
1968  }
1969
1970  HEAP->CollectGarbage(i::OLD_POINTER_SPACE);
1971
1972  // All objects should be gone. 7 global handles in total.
1973  CHECK_EQ(7, NumberOfWeakCalls);
1974}
1975
1976
1977THREADED_TEST(ScriptException) {
1978  v8::HandleScope scope;
1979  LocalContext env;
1980  Local<Script> script = Script::Compile(v8_str("throw 'panama!';"));
1981  v8::TryCatch try_catch;
1982  Local<Value> result = script->Run();
1983  CHECK(result.IsEmpty());
1984  CHECK(try_catch.HasCaught());
1985  String::AsciiValue exception_value(try_catch.Exception());
1986  CHECK_EQ(*exception_value, "panama!");
1987}
1988
1989
1990bool message_received;
1991
1992
1993static void check_message(v8::Handle<v8::Message> message,
1994                          v8::Handle<Value> data) {
1995  CHECK_EQ(5.76, data->NumberValue());
1996  CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
1997  CHECK_EQ(7.56, message->GetScriptData()->NumberValue());
1998  message_received = true;
1999}
2000
2001
2002THREADED_TEST(MessageHandlerData) {
2003  message_received = false;
2004  v8::HandleScope scope;
2005  CHECK(!message_received);
2006  v8::V8::AddMessageListener(check_message, v8_num(5.76));
2007  LocalContext context;
2008  v8::ScriptOrigin origin =
2009      v8::ScriptOrigin(v8_str("6.75"));
2010  v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
2011                                                  &origin);
2012  script->SetData(v8_str("7.56"));
2013  script->Run();
2014  CHECK(message_received);
2015  // clear out the message listener
2016  v8::V8::RemoveMessageListeners(check_message);
2017}
2018
2019
2020THREADED_TEST(GetSetProperty) {
2021  v8::HandleScope scope;
2022  LocalContext context;
2023  context->Global()->Set(v8_str("foo"), v8_num(14));
2024  context->Global()->Set(v8_str("12"), v8_num(92));
2025  context->Global()->Set(v8::Integer::New(16), v8_num(32));
2026  context->Global()->Set(v8_num(13), v8_num(56));
2027  Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run();
2028  CHECK_EQ(14, foo->Int32Value());
2029  Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run();
2030  CHECK_EQ(92, twelve->Int32Value());
2031  Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run();
2032  CHECK_EQ(32, sixteen->Int32Value());
2033  Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run();
2034  CHECK_EQ(56, thirteen->Int32Value());
2035  CHECK_EQ(92, context->Global()->Get(v8::Integer::New(12))->Int32Value());
2036  CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
2037  CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
2038  CHECK_EQ(32, context->Global()->Get(v8::Integer::New(16))->Int32Value());
2039  CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
2040  CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
2041  CHECK_EQ(56, context->Global()->Get(v8::Integer::New(13))->Int32Value());
2042  CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
2043  CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
2044}
2045
2046
2047THREADED_TEST(PropertyAttributes) {
2048  v8::HandleScope scope;
2049  LocalContext context;
2050  // read-only
2051  Local<String> prop = v8_str("read_only");
2052  context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
2053  CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2054  Script::Compile(v8_str("read_only = 9"))->Run();
2055  CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2056  context->Global()->Set(prop, v8_num(10));
2057  CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2058  // dont-delete
2059  prop = v8_str("dont_delete");
2060  context->Global()->Set(prop, v8_num(13), v8::DontDelete);
2061  CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
2062  Script::Compile(v8_str("delete dont_delete"))->Run();
2063  CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
2064}
2065
2066
2067THREADED_TEST(Array) {
2068  v8::HandleScope scope;
2069  LocalContext context;
2070  Local<v8::Array> array = v8::Array::New();
2071  CHECK_EQ(0, array->Length());
2072  CHECK(array->Get(0)->IsUndefined());
2073  CHECK(!array->Has(0));
2074  CHECK(array->Get(100)->IsUndefined());
2075  CHECK(!array->Has(100));
2076  array->Set(2, v8_num(7));
2077  CHECK_EQ(3, array->Length());
2078  CHECK(!array->Has(0));
2079  CHECK(!array->Has(1));
2080  CHECK(array->Has(2));
2081  CHECK_EQ(7, array->Get(2)->Int32Value());
2082  Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
2083  Local<v8::Array> arr = obj.As<v8::Array>();
2084  CHECK_EQ(3, arr->Length());
2085  CHECK_EQ(1, arr->Get(0)->Int32Value());
2086  CHECK_EQ(2, arr->Get(1)->Int32Value());
2087  CHECK_EQ(3, arr->Get(2)->Int32Value());
2088  array = v8::Array::New(27);
2089  CHECK_EQ(27, array->Length());
2090  array = v8::Array::New(-27);
2091  CHECK_EQ(0, array->Length());
2092}
2093
2094
2095v8::Handle<Value> HandleF(const v8::Arguments& args) {
2096  v8::HandleScope scope;
2097  ApiTestFuzzer::Fuzz();
2098  Local<v8::Array> result = v8::Array::New(args.Length());
2099  for (int i = 0; i < args.Length(); i++)
2100    result->Set(i, args[i]);
2101  return scope.Close(result);
2102}
2103
2104
2105THREADED_TEST(Vector) {
2106  v8::HandleScope scope;
2107  Local<ObjectTemplate> global = ObjectTemplate::New();
2108  global->Set(v8_str("f"), v8::FunctionTemplate::New(HandleF));
2109  LocalContext context(0, global);
2110
2111  const char* fun = "f()";
2112  Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
2113  CHECK_EQ(0, a0->Length());
2114
2115  const char* fun2 = "f(11)";
2116  Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
2117  CHECK_EQ(1, a1->Length());
2118  CHECK_EQ(11, a1->Get(0)->Int32Value());
2119
2120  const char* fun3 = "f(12, 13)";
2121  Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
2122  CHECK_EQ(2, a2->Length());
2123  CHECK_EQ(12, a2->Get(0)->Int32Value());
2124  CHECK_EQ(13, a2->Get(1)->Int32Value());
2125
2126  const char* fun4 = "f(14, 15, 16)";
2127  Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
2128  CHECK_EQ(3, a3->Length());
2129  CHECK_EQ(14, a3->Get(0)->Int32Value());
2130  CHECK_EQ(15, a3->Get(1)->Int32Value());
2131  CHECK_EQ(16, a3->Get(2)->Int32Value());
2132
2133  const char* fun5 = "f(17, 18, 19, 20)";
2134  Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
2135  CHECK_EQ(4, a4->Length());
2136  CHECK_EQ(17, a4->Get(0)->Int32Value());
2137  CHECK_EQ(18, a4->Get(1)->Int32Value());
2138  CHECK_EQ(19, a4->Get(2)->Int32Value());
2139  CHECK_EQ(20, a4->Get(3)->Int32Value());
2140}
2141
2142
2143THREADED_TEST(FunctionCall) {
2144  v8::HandleScope scope;
2145  LocalContext context;
2146  CompileRun(
2147    "function Foo() {"
2148    "  var result = [];"
2149    "  for (var i = 0; i < arguments.length; i++) {"
2150    "    result.push(arguments[i]);"
2151    "  }"
2152    "  return result;"
2153    "}");
2154  Local<Function> Foo =
2155      Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
2156
2157  v8::Handle<Value>* args0 = NULL;
2158  Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
2159  CHECK_EQ(0, a0->Length());
2160
2161  v8::Handle<Value> args1[] = { v8_num(1.1) };
2162  Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
2163  CHECK_EQ(1, a1->Length());
2164  CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
2165
2166  v8::Handle<Value> args2[] = { v8_num(2.2),
2167                                v8_num(3.3) };
2168  Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
2169  CHECK_EQ(2, a2->Length());
2170  CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
2171  CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
2172
2173  v8::Handle<Value> args3[] = { v8_num(4.4),
2174                                v8_num(5.5),
2175                                v8_num(6.6) };
2176  Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
2177  CHECK_EQ(3, a3->Length());
2178  CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
2179  CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
2180  CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
2181
2182  v8::Handle<Value> args4[] = { v8_num(7.7),
2183                                v8_num(8.8),
2184                                v8_num(9.9),
2185                                v8_num(10.11) };
2186  Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
2187  CHECK_EQ(4, a4->Length());
2188  CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
2189  CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
2190  CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
2191  CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
2192}
2193
2194
2195static const char* js_code_causing_out_of_memory =
2196    "var a = new Array(); while(true) a.push(a);";
2197
2198
2199// These tests run for a long time and prevent us from running tests
2200// that come after them so they cannot run in parallel.
2201TEST(OutOfMemory) {
2202  // It's not possible to read a snapshot into a heap with different dimensions.
2203  if (i::Snapshot::IsEnabled()) return;
2204  // Set heap limits.
2205  static const int K = 1024;
2206  v8::ResourceConstraints constraints;
2207  constraints.set_max_young_space_size(256 * K);
2208  constraints.set_max_old_space_size(4 * K * K);
2209  v8::SetResourceConstraints(&constraints);
2210
2211  // Execute a script that causes out of memory.
2212  v8::HandleScope scope;
2213  LocalContext context;
2214  v8::V8::IgnoreOutOfMemoryException();
2215  Local<Script> script =
2216      Script::Compile(String::New(js_code_causing_out_of_memory));
2217  Local<Value> result = script->Run();
2218
2219  // Check for out of memory state.
2220  CHECK(result.IsEmpty());
2221  CHECK(context->HasOutOfMemoryException());
2222}
2223
2224
2225v8::Handle<Value> ProvokeOutOfMemory(const v8::Arguments& args) {
2226  ApiTestFuzzer::Fuzz();
2227
2228  v8::HandleScope scope;
2229  LocalContext context;
2230  Local<Script> script =
2231      Script::Compile(String::New(js_code_causing_out_of_memory));
2232  Local<Value> result = script->Run();
2233
2234  // Check for out of memory state.
2235  CHECK(result.IsEmpty());
2236  CHECK(context->HasOutOfMemoryException());
2237
2238  return result;
2239}
2240
2241
2242TEST(OutOfMemoryNested) {
2243  // It's not possible to read a snapshot into a heap with different dimensions.
2244  if (i::Snapshot::IsEnabled()) return;
2245  // Set heap limits.
2246  static const int K = 1024;
2247  v8::ResourceConstraints constraints;
2248  constraints.set_max_young_space_size(256 * K);
2249  constraints.set_max_old_space_size(4 * K * K);
2250  v8::SetResourceConstraints(&constraints);
2251
2252  v8::HandleScope scope;
2253  Local<ObjectTemplate> templ = ObjectTemplate::New();
2254  templ->Set(v8_str("ProvokeOutOfMemory"),
2255             v8::FunctionTemplate::New(ProvokeOutOfMemory));
2256  LocalContext context(0, templ);
2257  v8::V8::IgnoreOutOfMemoryException();
2258  Local<Value> result = CompileRun(
2259    "var thrown = false;"
2260    "try {"
2261    "  ProvokeOutOfMemory();"
2262    "} catch (e) {"
2263    "  thrown = true;"
2264    "}");
2265  // Check for out of memory state.
2266  CHECK(result.IsEmpty());
2267  CHECK(context->HasOutOfMemoryException());
2268}
2269
2270
2271TEST(HugeConsStringOutOfMemory) {
2272  // It's not possible to read a snapshot into a heap with different dimensions.
2273  if (i::Snapshot::IsEnabled()) return;
2274  // Set heap limits.
2275  static const int K = 1024;
2276  v8::ResourceConstraints constraints;
2277  constraints.set_max_young_space_size(256 * K);
2278  constraints.set_max_old_space_size(2 * K * K);
2279  v8::SetResourceConstraints(&constraints);
2280
2281  // Execute a script that causes out of memory.
2282  v8::V8::IgnoreOutOfMemoryException();
2283
2284  v8::HandleScope scope;
2285  LocalContext context;
2286
2287  // Build huge string. This should fail with out of memory exception.
2288  Local<Value> result = CompileRun(
2289    "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();"
2290    "for (var i = 0; i < 22; i++) { str = str + str; }");
2291
2292  // Check for out of memory state.
2293  CHECK(result.IsEmpty());
2294  CHECK(context->HasOutOfMemoryException());
2295}
2296
2297
2298THREADED_TEST(ConstructCall) {
2299  v8::HandleScope scope;
2300  LocalContext context;
2301  CompileRun(
2302    "function Foo() {"
2303    "  var result = [];"
2304    "  for (var i = 0; i < arguments.length; i++) {"
2305    "    result.push(arguments[i]);"
2306    "  }"
2307    "  return result;"
2308    "}");
2309  Local<Function> Foo =
2310      Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
2311
2312  v8::Handle<Value>* args0 = NULL;
2313  Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
2314  CHECK_EQ(0, a0->Length());
2315
2316  v8::Handle<Value> args1[] = { v8_num(1.1) };
2317  Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
2318  CHECK_EQ(1, a1->Length());
2319  CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
2320
2321  v8::Handle<Value> args2[] = { v8_num(2.2),
2322                                v8_num(3.3) };
2323  Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
2324  CHECK_EQ(2, a2->Length());
2325  CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
2326  CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
2327
2328  v8::Handle<Value> args3[] = { v8_num(4.4),
2329                                v8_num(5.5),
2330                                v8_num(6.6) };
2331  Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
2332  CHECK_EQ(3, a3->Length());
2333  CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
2334  CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
2335  CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
2336
2337  v8::Handle<Value> args4[] = { v8_num(7.7),
2338                                v8_num(8.8),
2339                                v8_num(9.9),
2340                                v8_num(10.11) };
2341  Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
2342  CHECK_EQ(4, a4->Length());
2343  CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
2344  CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
2345  CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
2346  CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
2347}
2348
2349
2350static void CheckUncle(v8::TryCatch* try_catch) {
2351  CHECK(try_catch->HasCaught());
2352  String::AsciiValue str_value(try_catch->Exception());
2353  CHECK_EQ(*str_value, "uncle?");
2354  try_catch->Reset();
2355}
2356
2357
2358THREADED_TEST(ConversionNumber) {
2359  v8::HandleScope scope;
2360  LocalContext env;
2361  // Very large number.
2362  CompileRun("var obj = Math.pow(2,32) * 1237;");
2363  Local<Value> obj = env->Global()->Get(v8_str("obj"));
2364  CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
2365  CHECK_EQ(0, obj->ToInt32()->Value());
2366  CHECK(0u == obj->ToUint32()->Value());  // NOLINT - no CHECK_EQ for unsigned.
2367  // Large number.
2368  CompileRun("var obj = -1234567890123;");
2369  obj = env->Global()->Get(v8_str("obj"));
2370  CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
2371  CHECK_EQ(-1912276171, obj->ToInt32()->Value());
2372  CHECK(2382691125u == obj->ToUint32()->Value());  // NOLINT
2373  // Small positive integer.
2374  CompileRun("var obj = 42;");
2375  obj = env->Global()->Get(v8_str("obj"));
2376  CHECK_EQ(42.0, obj->ToNumber()->Value());
2377  CHECK_EQ(42, obj->ToInt32()->Value());
2378  CHECK(42u == obj->ToUint32()->Value());  // NOLINT
2379  // Negative integer.
2380  CompileRun("var obj = -37;");
2381  obj = env->Global()->Get(v8_str("obj"));
2382  CHECK_EQ(-37.0, obj->ToNumber()->Value());
2383  CHECK_EQ(-37, obj->ToInt32()->Value());
2384  CHECK(4294967259u == obj->ToUint32()->Value());  // NOLINT
2385  // Positive non-int32 integer.
2386  CompileRun("var obj = 0x81234567;");
2387  obj = env->Global()->Get(v8_str("obj"));
2388  CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
2389  CHECK_EQ(-2128394905, obj->ToInt32()->Value());
2390  CHECK(2166572391u == obj->ToUint32()->Value());  // NOLINT
2391  // Fraction.
2392  CompileRun("var obj = 42.3;");
2393  obj = env->Global()->Get(v8_str("obj"));
2394  CHECK_EQ(42.3, obj->ToNumber()->Value());
2395  CHECK_EQ(42, obj->ToInt32()->Value());
2396  CHECK(42u == obj->ToUint32()->Value());  // NOLINT
2397  // Large negative fraction.
2398  CompileRun("var obj = -5726623061.75;");
2399  obj = env->Global()->Get(v8_str("obj"));
2400  CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
2401  CHECK_EQ(-1431655765, obj->ToInt32()->Value());
2402  CHECK(2863311531u == obj->ToUint32()->Value());  // NOLINT
2403}
2404
2405
2406THREADED_TEST(isNumberType) {
2407  v8::HandleScope scope;
2408  LocalContext env;
2409  // Very large number.
2410  CompileRun("var obj = Math.pow(2,32) * 1237;");
2411  Local<Value> obj = env->Global()->Get(v8_str("obj"));
2412  CHECK(!obj->IsInt32());
2413  CHECK(!obj->IsUint32());
2414  // Large negative number.
2415  CompileRun("var obj = -1234567890123;");
2416  obj = env->Global()->Get(v8_str("obj"));
2417  CHECK(!obj->IsInt32());
2418  CHECK(!obj->IsUint32());
2419  // Small positive integer.
2420  CompileRun("var obj = 42;");
2421  obj = env->Global()->Get(v8_str("obj"));
2422  CHECK(obj->IsInt32());
2423  CHECK(obj->IsUint32());
2424  // Negative integer.
2425  CompileRun("var obj = -37;");
2426  obj = env->Global()->Get(v8_str("obj"));
2427  CHECK(obj->IsInt32());
2428  CHECK(!obj->IsUint32());
2429  // Positive non-int32 integer.
2430  CompileRun("var obj = 0x81234567;");
2431  obj = env->Global()->Get(v8_str("obj"));
2432  CHECK(!obj->IsInt32());
2433  CHECK(obj->IsUint32());
2434  // Fraction.
2435  CompileRun("var obj = 42.3;");
2436  obj = env->Global()->Get(v8_str("obj"));
2437  CHECK(!obj->IsInt32());
2438  CHECK(!obj->IsUint32());
2439  // Large negative fraction.
2440  CompileRun("var obj = -5726623061.75;");
2441  obj = env->Global()->Get(v8_str("obj"));
2442  CHECK(!obj->IsInt32());
2443  CHECK(!obj->IsUint32());
2444}
2445
2446
2447THREADED_TEST(ConversionException) {
2448  v8::HandleScope scope;
2449  LocalContext env;
2450  CompileRun(
2451    "function TestClass() { };"
2452    "TestClass.prototype.toString = function () { throw 'uncle?'; };"
2453    "var obj = new TestClass();");
2454  Local<Value> obj = env->Global()->Get(v8_str("obj"));
2455
2456  v8::TryCatch try_catch;
2457
2458  Local<Value> to_string_result = obj->ToString();
2459  CHECK(to_string_result.IsEmpty());
2460  CheckUncle(&try_catch);
2461
2462  Local<Value> to_number_result = obj->ToNumber();
2463  CHECK(to_number_result.IsEmpty());
2464  CheckUncle(&try_catch);
2465
2466  Local<Value> to_integer_result = obj->ToInteger();
2467  CHECK(to_integer_result.IsEmpty());
2468  CheckUncle(&try_catch);
2469
2470  Local<Value> to_uint32_result = obj->ToUint32();
2471  CHECK(to_uint32_result.IsEmpty());
2472  CheckUncle(&try_catch);
2473
2474  Local<Value> to_int32_result = obj->ToInt32();
2475  CHECK(to_int32_result.IsEmpty());
2476  CheckUncle(&try_catch);
2477
2478  Local<Value> to_object_result = v8::Undefined()->ToObject();
2479  CHECK(to_object_result.IsEmpty());
2480  CHECK(try_catch.HasCaught());
2481  try_catch.Reset();
2482
2483  int32_t int32_value = obj->Int32Value();
2484  CHECK_EQ(0, int32_value);
2485  CheckUncle(&try_catch);
2486
2487  uint32_t uint32_value = obj->Uint32Value();
2488  CHECK_EQ(0, uint32_value);
2489  CheckUncle(&try_catch);
2490
2491  double number_value = obj->NumberValue();
2492  CHECK_NE(0, IsNaN(number_value));
2493  CheckUncle(&try_catch);
2494
2495  int64_t integer_value = obj->IntegerValue();
2496  CHECK_EQ(0.0, static_cast<double>(integer_value));
2497  CheckUncle(&try_catch);
2498}
2499
2500
2501v8::Handle<Value> ThrowFromC(const v8::Arguments& args) {
2502  ApiTestFuzzer::Fuzz();
2503  return v8::ThrowException(v8_str("konto"));
2504}
2505
2506
2507v8::Handle<Value> CCatcher(const v8::Arguments& args) {
2508  if (args.Length() < 1) return v8::Boolean::New(false);
2509  v8::HandleScope scope;
2510  v8::TryCatch try_catch;
2511  Local<Value> result = v8::Script::Compile(args[0]->ToString())->Run();
2512  CHECK(!try_catch.HasCaught() || result.IsEmpty());
2513  return v8::Boolean::New(try_catch.HasCaught());
2514}
2515
2516
2517THREADED_TEST(APICatch) {
2518  v8::HandleScope scope;
2519  Local<ObjectTemplate> templ = ObjectTemplate::New();
2520  templ->Set(v8_str("ThrowFromC"),
2521             v8::FunctionTemplate::New(ThrowFromC));
2522  LocalContext context(0, templ);
2523  CompileRun(
2524    "var thrown = false;"
2525    "try {"
2526    "  ThrowFromC();"
2527    "} catch (e) {"
2528    "  thrown = true;"
2529    "}");
2530  Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
2531  CHECK(thrown->BooleanValue());
2532}
2533
2534
2535THREADED_TEST(APIThrowTryCatch) {
2536  v8::HandleScope scope;
2537  Local<ObjectTemplate> templ = ObjectTemplate::New();
2538  templ->Set(v8_str("ThrowFromC"),
2539             v8::FunctionTemplate::New(ThrowFromC));
2540  LocalContext context(0, templ);
2541  v8::TryCatch try_catch;
2542  CompileRun("ThrowFromC();");
2543  CHECK(try_catch.HasCaught());
2544}
2545
2546
2547// Test that a try-finally block doesn't shadow a try-catch block
2548// when setting up an external handler.
2549//
2550// BUG(271): Some of the exception propagation does not work on the
2551// ARM simulator because the simulator separates the C++ stack and the
2552// JS stack.  This test therefore fails on the simulator.  The test is
2553// not threaded to allow the threading tests to run on the simulator.
2554TEST(TryCatchInTryFinally) {
2555  v8::HandleScope scope;
2556  Local<ObjectTemplate> templ = ObjectTemplate::New();
2557  templ->Set(v8_str("CCatcher"),
2558             v8::FunctionTemplate::New(CCatcher));
2559  LocalContext context(0, templ);
2560  Local<Value> result = CompileRun("try {"
2561                                   "  try {"
2562                                   "    CCatcher('throw 7;');"
2563                                   "  } finally {"
2564                                   "  }"
2565                                   "} catch (e) {"
2566                                   "}");
2567  CHECK(result->IsTrue());
2568}
2569
2570
2571static void check_reference_error_message(
2572    v8::Handle<v8::Message> message,
2573    v8::Handle<v8::Value> data) {
2574  const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
2575  CHECK(message->Get()->Equals(v8_str(reference_error)));
2576}
2577
2578
2579static v8::Handle<Value> Fail(const v8::Arguments& args) {
2580  ApiTestFuzzer::Fuzz();
2581  CHECK(false);
2582  return v8::Undefined();
2583}
2584
2585
2586// Test that overwritten methods are not invoked on uncaught exception
2587// formatting. However, they are invoked when performing normal error
2588// string conversions.
2589TEST(APIThrowMessageOverwrittenToString) {
2590  v8::HandleScope scope;
2591  v8::V8::AddMessageListener(check_reference_error_message);
2592  Local<ObjectTemplate> templ = ObjectTemplate::New();
2593  templ->Set(v8_str("fail"), v8::FunctionTemplate::New(Fail));
2594  LocalContext context(NULL, templ);
2595  CompileRun("asdf;");
2596  CompileRun("var limit = {};"
2597             "limit.valueOf = fail;"
2598             "Error.stackTraceLimit = limit;");
2599  CompileRun("asdf");
2600  CompileRun("Array.prototype.pop = fail;");
2601  CompileRun("Object.prototype.hasOwnProperty = fail;");
2602  CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
2603  CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
2604  CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
2605  CompileRun("ReferenceError.prototype.toString ="
2606             "  function() { return 'Whoops' }");
2607  CompileRun("asdf;");
2608  CompileRun("ReferenceError.prototype.constructor.name = void 0;");
2609  CompileRun("asdf;");
2610  CompileRun("ReferenceError.prototype.constructor = void 0;");
2611  CompileRun("asdf;");
2612  CompileRun("ReferenceError.prototype.__proto__ = new Object();");
2613  CompileRun("asdf;");
2614  CompileRun("ReferenceError.prototype = new Object();");
2615  CompileRun("asdf;");
2616  v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
2617  CHECK(string->Equals(v8_str("Whoops")));
2618  CompileRun("ReferenceError.prototype.constructor = new Object();"
2619             "ReferenceError.prototype.constructor.name = 1;"
2620             "Number.prototype.toString = function() { return 'Whoops'; };"
2621             "ReferenceError.prototype.toString = Object.prototype.toString;");
2622  CompileRun("asdf;");
2623  v8::V8::RemoveMessageListeners(check_message);
2624}
2625
2626
2627static void receive_message(v8::Handle<v8::Message> message,
2628                            v8::Handle<v8::Value> data) {
2629  message->Get();
2630  message_received = true;
2631}
2632
2633
2634TEST(APIThrowMessage) {
2635  message_received = false;
2636  v8::HandleScope scope;
2637  v8::V8::AddMessageListener(receive_message);
2638  Local<ObjectTemplate> templ = ObjectTemplate::New();
2639  templ->Set(v8_str("ThrowFromC"),
2640             v8::FunctionTemplate::New(ThrowFromC));
2641  LocalContext context(0, templ);
2642  CompileRun("ThrowFromC();");
2643  CHECK(message_received);
2644  v8::V8::RemoveMessageListeners(check_message);
2645}
2646
2647
2648TEST(APIThrowMessageAndVerboseTryCatch) {
2649  message_received = false;
2650  v8::HandleScope scope;
2651  v8::V8::AddMessageListener(receive_message);
2652  Local<ObjectTemplate> templ = ObjectTemplate::New();
2653  templ->Set(v8_str("ThrowFromC"),
2654             v8::FunctionTemplate::New(ThrowFromC));
2655  LocalContext context(0, templ);
2656  v8::TryCatch try_catch;
2657  try_catch.SetVerbose(true);
2658  Local<Value> result = CompileRun("ThrowFromC();");
2659  CHECK(try_catch.HasCaught());
2660  CHECK(result.IsEmpty());
2661  CHECK(message_received);
2662  v8::V8::RemoveMessageListeners(check_message);
2663}
2664
2665
2666TEST(APIStackOverflowAndVerboseTryCatch) {
2667  message_received = false;
2668  v8::HandleScope scope;
2669  v8::V8::AddMessageListener(receive_message);
2670  LocalContext context;
2671  v8::TryCatch try_catch;
2672  try_catch.SetVerbose(true);
2673  Local<Value> result = CompileRun("function foo() { foo(); } foo();");
2674  CHECK(try_catch.HasCaught());
2675  CHECK(result.IsEmpty());
2676  CHECK(message_received);
2677  v8::V8::RemoveMessageListeners(receive_message);
2678}
2679
2680
2681THREADED_TEST(ExternalScriptException) {
2682  v8::HandleScope scope;
2683  Local<ObjectTemplate> templ = ObjectTemplate::New();
2684  templ->Set(v8_str("ThrowFromC"),
2685             v8::FunctionTemplate::New(ThrowFromC));
2686  LocalContext context(0, templ);
2687
2688  v8::TryCatch try_catch;
2689  Local<Script> script
2690      = Script::Compile(v8_str("ThrowFromC(); throw 'panama';"));
2691  Local<Value> result = script->Run();
2692  CHECK(result.IsEmpty());
2693  CHECK(try_catch.HasCaught());
2694  String::AsciiValue exception_value(try_catch.Exception());
2695  CHECK_EQ("konto", *exception_value);
2696}
2697
2698
2699
2700v8::Handle<Value> CThrowCountDown(const v8::Arguments& args) {
2701  ApiTestFuzzer::Fuzz();
2702  CHECK_EQ(4, args.Length());
2703  int count = args[0]->Int32Value();
2704  int cInterval = args[2]->Int32Value();
2705  if (count == 0) {
2706    return v8::ThrowException(v8_str("FromC"));
2707  } else {
2708    Local<v8::Object> global = Context::GetCurrent()->Global();
2709    Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
2710    v8::Handle<Value> argv[] = { v8_num(count - 1),
2711                                 args[1],
2712                                 args[2],
2713                                 args[3] };
2714    if (count % cInterval == 0) {
2715      v8::TryCatch try_catch;
2716      Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
2717      int expected = args[3]->Int32Value();
2718      if (try_catch.HasCaught()) {
2719        CHECK_EQ(expected, count);
2720        CHECK(result.IsEmpty());
2721        CHECK(!i::Isolate::Current()->has_scheduled_exception());
2722      } else {
2723        CHECK_NE(expected, count);
2724      }
2725      return result;
2726    } else {
2727      return fun.As<Function>()->Call(global, 4, argv);
2728    }
2729  }
2730}
2731
2732
2733v8::Handle<Value> JSCheck(const v8::Arguments& args) {
2734  ApiTestFuzzer::Fuzz();
2735  CHECK_EQ(3, args.Length());
2736  bool equality = args[0]->BooleanValue();
2737  int count = args[1]->Int32Value();
2738  int expected = args[2]->Int32Value();
2739  if (equality) {
2740    CHECK_EQ(count, expected);
2741  } else {
2742    CHECK_NE(count, expected);
2743  }
2744  return v8::Undefined();
2745}
2746
2747
2748THREADED_TEST(EvalInTryFinally) {
2749  v8::HandleScope scope;
2750  LocalContext context;
2751  v8::TryCatch try_catch;
2752  CompileRun("(function() {"
2753             "  try {"
2754             "    eval('asldkf (*&^&*^');"
2755             "  } finally {"
2756             "    return;"
2757             "  }"
2758             "})()");
2759  CHECK(!try_catch.HasCaught());
2760}
2761
2762
2763// This test works by making a stack of alternating JavaScript and C
2764// activations.  These activations set up exception handlers with regular
2765// intervals, one interval for C activations and another for JavaScript
2766// activations.  When enough activations have been created an exception is
2767// thrown and we check that the right activation catches the exception and that
2768// no other activations do.  The right activation is always the topmost one with
2769// a handler, regardless of whether it is in JavaScript or C.
2770//
2771// The notation used to describe a test case looks like this:
2772//
2773//    *JS[4] *C[3] @JS[2] C[1] JS[0]
2774//
2775// Each entry is an activation, either JS or C.  The index is the count at that
2776// level.  Stars identify activations with exception handlers, the @ identifies
2777// the exception handler that should catch the exception.
2778//
2779// BUG(271): Some of the exception propagation does not work on the
2780// ARM simulator because the simulator separates the C++ stack and the
2781// JS stack.  This test therefore fails on the simulator.  The test is
2782// not threaded to allow the threading tests to run on the simulator.
2783TEST(ExceptionOrder) {
2784  v8::HandleScope scope;
2785  Local<ObjectTemplate> templ = ObjectTemplate::New();
2786  templ->Set(v8_str("check"), v8::FunctionTemplate::New(JSCheck));
2787  templ->Set(v8_str("CThrowCountDown"),
2788             v8::FunctionTemplate::New(CThrowCountDown));
2789  LocalContext context(0, templ);
2790  CompileRun(
2791    "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
2792    "  if (count == 0) throw 'FromJS';"
2793    "  if (count % jsInterval == 0) {"
2794    "    try {"
2795    "      var value = CThrowCountDown(count - 1,"
2796    "                                  jsInterval,"
2797    "                                  cInterval,"
2798    "                                  expected);"
2799    "      check(false, count, expected);"
2800    "      return value;"
2801    "    } catch (e) {"
2802    "      check(true, count, expected);"
2803    "    }"
2804    "  } else {"
2805    "    return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
2806    "  }"
2807    "}");
2808  Local<Function> fun =
2809      Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
2810
2811  const int argc = 4;
2812  //                             count      jsInterval cInterval  expected
2813
2814  // *JS[4] *C[3] @JS[2] C[1] JS[0]
2815  v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
2816  fun->Call(fun, argc, a0);
2817
2818  // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
2819  v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
2820  fun->Call(fun, argc, a1);
2821
2822  // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
2823  v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
2824  fun->Call(fun, argc, a2);
2825
2826  // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
2827  v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
2828  fun->Call(fun, argc, a3);
2829
2830  // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
2831  v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
2832  fun->Call(fun, argc, a4);
2833
2834  // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
2835  v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
2836  fun->Call(fun, argc, a5);
2837}
2838
2839
2840v8::Handle<Value> ThrowValue(const v8::Arguments& args) {
2841  ApiTestFuzzer::Fuzz();
2842  CHECK_EQ(1, args.Length());
2843  return v8::ThrowException(args[0]);
2844}
2845
2846
2847THREADED_TEST(ThrowValues) {
2848  v8::HandleScope scope;
2849  Local<ObjectTemplate> templ = ObjectTemplate::New();
2850  templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(ThrowValue));
2851  LocalContext context(0, templ);
2852  v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
2853    "function Run(obj) {"
2854    "  try {"
2855    "    Throw(obj);"
2856    "  } catch (e) {"
2857    "    return e;"
2858    "  }"
2859    "  return 'no exception';"
2860    "}"
2861    "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
2862  CHECK_EQ(5, result->Length());
2863  CHECK(result->Get(v8::Integer::New(0))->IsString());
2864  CHECK(result->Get(v8::Integer::New(1))->IsNumber());
2865  CHECK_EQ(1, result->Get(v8::Integer::New(1))->Int32Value());
2866  CHECK(result->Get(v8::Integer::New(2))->IsNumber());
2867  CHECK_EQ(0, result->Get(v8::Integer::New(2))->Int32Value());
2868  CHECK(result->Get(v8::Integer::New(3))->IsNull());
2869  CHECK(result->Get(v8::Integer::New(4))->IsUndefined());
2870}
2871
2872
2873THREADED_TEST(CatchZero) {
2874  v8::HandleScope scope;
2875  LocalContext context;
2876  v8::TryCatch try_catch;
2877  CHECK(!try_catch.HasCaught());
2878  Script::Compile(v8_str("throw 10"))->Run();
2879  CHECK(try_catch.HasCaught());
2880  CHECK_EQ(10, try_catch.Exception()->Int32Value());
2881  try_catch.Reset();
2882  CHECK(!try_catch.HasCaught());
2883  Script::Compile(v8_str("throw 0"))->Run();
2884  CHECK(try_catch.HasCaught());
2885  CHECK_EQ(0, try_catch.Exception()->Int32Value());
2886}
2887
2888
2889THREADED_TEST(CatchExceptionFromWith) {
2890  v8::HandleScope scope;
2891  LocalContext context;
2892  v8::TryCatch try_catch;
2893  CHECK(!try_catch.HasCaught());
2894  Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run();
2895  CHECK(try_catch.HasCaught());
2896}
2897
2898
2899THREADED_TEST(TryCatchAndFinallyHidingException) {
2900  v8::HandleScope scope;
2901  LocalContext context;
2902  v8::TryCatch try_catch;
2903  CHECK(!try_catch.HasCaught());
2904  CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
2905  CompileRun("f({toString: function() { throw 42; }});");
2906  CHECK(!try_catch.HasCaught());
2907}
2908
2909
2910v8::Handle<v8::Value> WithTryCatch(const v8::Arguments& args) {
2911  v8::TryCatch try_catch;
2912  return v8::Undefined();
2913}
2914
2915
2916THREADED_TEST(TryCatchAndFinally) {
2917  v8::HandleScope scope;
2918  LocalContext context;
2919  context->Global()->Set(
2920      v8_str("native_with_try_catch"),
2921      v8::FunctionTemplate::New(WithTryCatch)->GetFunction());
2922  v8::TryCatch try_catch;
2923  CHECK(!try_catch.HasCaught());
2924  CompileRun(
2925      "try {\n"
2926      "  throw new Error('a');\n"
2927      "} finally {\n"
2928      "  native_with_try_catch();\n"
2929      "}\n");
2930  CHECK(try_catch.HasCaught());
2931}
2932
2933
2934THREADED_TEST(Equality) {
2935  v8::HandleScope scope;
2936  LocalContext context;
2937  // Check that equality works at all before relying on CHECK_EQ
2938  CHECK(v8_str("a")->Equals(v8_str("a")));
2939  CHECK(!v8_str("a")->Equals(v8_str("b")));
2940
2941  CHECK_EQ(v8_str("a"), v8_str("a"));
2942  CHECK_NE(v8_str("a"), v8_str("b"));
2943  CHECK_EQ(v8_num(1), v8_num(1));
2944  CHECK_EQ(v8_num(1.00), v8_num(1));
2945  CHECK_NE(v8_num(1), v8_num(2));
2946
2947  // Assume String is not symbol.
2948  CHECK(v8_str("a")->StrictEquals(v8_str("a")));
2949  CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
2950  CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
2951  CHECK(v8_num(1)->StrictEquals(v8_num(1)));
2952  CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
2953  CHECK(v8_num(0)->StrictEquals(v8_num(-0)));
2954  Local<Value> not_a_number = v8_num(i::OS::nan_value());
2955  CHECK(!not_a_number->StrictEquals(not_a_number));
2956  CHECK(v8::False()->StrictEquals(v8::False()));
2957  CHECK(!v8::False()->StrictEquals(v8::Undefined()));
2958
2959  v8::Handle<v8::Object> obj = v8::Object::New();
2960  v8::Persistent<v8::Object> alias = v8::Persistent<v8::Object>::New(obj);
2961  CHECK(alias->StrictEquals(obj));
2962  alias.Dispose();
2963}
2964
2965
2966THREADED_TEST(MultiRun) {
2967  v8::HandleScope scope;
2968  LocalContext context;
2969  Local<Script> script = Script::Compile(v8_str("x"));
2970  for (int i = 0; i < 10; i++)
2971    script->Run();
2972}
2973
2974
2975static v8::Handle<Value> GetXValue(Local<String> name,
2976                                   const AccessorInfo& info) {
2977  ApiTestFuzzer::Fuzz();
2978  CHECK_EQ(info.Data(), v8_str("donut"));
2979  CHECK_EQ(name, v8_str("x"));
2980  return name;
2981}
2982
2983
2984THREADED_TEST(SimplePropertyRead) {
2985  v8::HandleScope scope;
2986  Local<ObjectTemplate> templ = ObjectTemplate::New();
2987  templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
2988  LocalContext context;
2989  context->Global()->Set(v8_str("obj"), templ->NewInstance());
2990  Local<Script> script = Script::Compile(v8_str("obj.x"));
2991  for (int i = 0; i < 10; i++) {
2992    Local<Value> result = script->Run();
2993    CHECK_EQ(result, v8_str("x"));
2994  }
2995}
2996
2997THREADED_TEST(DefinePropertyOnAPIAccessor) {
2998  v8::HandleScope scope;
2999  Local<ObjectTemplate> templ = ObjectTemplate::New();
3000  templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3001  LocalContext context;
3002  context->Global()->Set(v8_str("obj"), templ->NewInstance());
3003
3004  // Uses getOwnPropertyDescriptor to check the configurable status
3005  Local<Script> script_desc
3006    = Script::Compile(v8_str("var prop = Object.getOwnPropertyDescriptor( "
3007                             "obj, 'x');"
3008                             "prop.configurable;"));
3009  Local<Value> result = script_desc->Run();
3010  CHECK_EQ(result->BooleanValue(), true);
3011
3012  // Redefine get - but still configurable
3013  Local<Script> script_define
3014    = Script::Compile(v8_str("var desc = { get: function(){return 42; },"
3015                             "            configurable: true };"
3016                             "Object.defineProperty(obj, 'x', desc);"
3017                             "obj.x"));
3018  result = script_define->Run();
3019  CHECK_EQ(result, v8_num(42));
3020
3021  // Check that the accessor is still configurable
3022  result = script_desc->Run();
3023  CHECK_EQ(result->BooleanValue(), true);
3024
3025  // Redefine to a non-configurable
3026  script_define
3027    = Script::Compile(v8_str("var desc = { get: function(){return 43; },"
3028                             "             configurable: false };"
3029                             "Object.defineProperty(obj, 'x', desc);"
3030                             "obj.x"));
3031  result = script_define->Run();
3032  CHECK_EQ(result, v8_num(43));
3033  result = script_desc->Run();
3034  CHECK_EQ(result->BooleanValue(), false);
3035
3036  // Make sure that it is not possible to redefine again
3037  v8::TryCatch try_catch;
3038  result = script_define->Run();
3039  CHECK(try_catch.HasCaught());
3040  String::AsciiValue exception_value(try_catch.Exception());
3041  CHECK_EQ(*exception_value,
3042           "TypeError: Cannot redefine property: defineProperty");
3043}
3044
3045THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
3046  v8::HandleScope scope;
3047  Local<ObjectTemplate> templ = ObjectTemplate::New();
3048  templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3049  LocalContext context;
3050  context->Global()->Set(v8_str("obj"), templ->NewInstance());
3051
3052  Local<Script> script_desc = Script::Compile(v8_str("var prop ="
3053                                    "Object.getOwnPropertyDescriptor( "
3054                                    "obj, 'x');"
3055                                    "prop.configurable;"));
3056  Local<Value> result = script_desc->Run();
3057  CHECK_EQ(result->BooleanValue(), true);
3058
3059  Local<Script> script_define =
3060    Script::Compile(v8_str("var desc = {get: function(){return 42; },"
3061                           "            configurable: true };"
3062                           "Object.defineProperty(obj, 'x', desc);"
3063                           "obj.x"));
3064  result = script_define->Run();
3065  CHECK_EQ(result, v8_num(42));
3066
3067
3068  result = script_desc->Run();
3069  CHECK_EQ(result->BooleanValue(), true);
3070
3071
3072  script_define =
3073    Script::Compile(v8_str("var desc = {get: function(){return 43; },"
3074                           "            configurable: false };"
3075                           "Object.defineProperty(obj, 'x', desc);"
3076                           "obj.x"));
3077  result = script_define->Run();
3078  CHECK_EQ(result, v8_num(43));
3079  result = script_desc->Run();
3080
3081  CHECK_EQ(result->BooleanValue(), false);
3082
3083  v8::TryCatch try_catch;
3084  result = script_define->Run();
3085  CHECK(try_catch.HasCaught());
3086  String::AsciiValue exception_value(try_catch.Exception());
3087  CHECK_EQ(*exception_value,
3088           "TypeError: Cannot redefine property: defineProperty");
3089}
3090
3091
3092static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
3093                                                char const* name) {
3094  return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
3095}
3096
3097
3098THREADED_TEST(DefineAPIAccessorOnObject) {
3099  v8::HandleScope scope;
3100  Local<ObjectTemplate> templ = ObjectTemplate::New();
3101  LocalContext context;
3102
3103  context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3104  CompileRun("var obj2 = {};");
3105
3106  CHECK(CompileRun("obj1.x")->IsUndefined());
3107  CHECK(CompileRun("obj2.x")->IsUndefined());
3108
3109  CHECK(GetGlobalProperty(&context, "obj1")->
3110      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3111
3112  ExpectString("obj1.x", "x");
3113  CHECK(CompileRun("obj2.x")->IsUndefined());
3114
3115  CHECK(GetGlobalProperty(&context, "obj2")->
3116      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3117
3118  ExpectString("obj1.x", "x");
3119  ExpectString("obj2.x", "x");
3120
3121  ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3122  ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3123
3124  CompileRun("Object.defineProperty(obj1, 'x',"
3125             "{ get: function() { return 'y'; }, configurable: true })");
3126
3127  ExpectString("obj1.x", "y");
3128  ExpectString("obj2.x", "x");
3129
3130  CompileRun("Object.defineProperty(obj2, 'x',"
3131             "{ get: function() { return 'y'; }, configurable: true })");
3132
3133  ExpectString("obj1.x", "y");
3134  ExpectString("obj2.x", "y");
3135
3136  ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3137  ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3138
3139  CHECK(GetGlobalProperty(&context, "obj1")->
3140      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3141  CHECK(GetGlobalProperty(&context, "obj2")->
3142      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3143
3144  ExpectString("obj1.x", "x");
3145  ExpectString("obj2.x", "x");
3146
3147  ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3148  ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3149
3150  // Define getters/setters, but now make them not configurable.
3151  CompileRun("Object.defineProperty(obj1, 'x',"
3152             "{ get: function() { return 'z'; }, configurable: false })");
3153  CompileRun("Object.defineProperty(obj2, 'x',"
3154             "{ get: function() { return 'z'; }, configurable: false })");
3155
3156  ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3157  ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3158
3159  ExpectString("obj1.x", "z");
3160  ExpectString("obj2.x", "z");
3161
3162  CHECK(!GetGlobalProperty(&context, "obj1")->
3163      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3164  CHECK(!GetGlobalProperty(&context, "obj2")->
3165      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3166
3167  ExpectString("obj1.x", "z");
3168  ExpectString("obj2.x", "z");
3169}
3170
3171
3172THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
3173  v8::HandleScope scope;
3174  Local<ObjectTemplate> templ = ObjectTemplate::New();
3175  LocalContext context;
3176
3177  context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3178  CompileRun("var obj2 = {};");
3179
3180  CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
3181        v8_str("x"),
3182        GetXValue, NULL,
3183        v8_str("donut"), v8::DEFAULT, v8::DontDelete));
3184  CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
3185        v8_str("x"),
3186        GetXValue, NULL,
3187        v8_str("donut"), v8::DEFAULT, v8::DontDelete));
3188
3189  ExpectString("obj1.x", "x");
3190  ExpectString("obj2.x", "x");
3191
3192  ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3193  ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3194
3195  CHECK(!GetGlobalProperty(&context, "obj1")->
3196      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3197  CHECK(!GetGlobalProperty(&context, "obj2")->
3198      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3199
3200  {
3201    v8::TryCatch try_catch;
3202    CompileRun("Object.defineProperty(obj1, 'x',"
3203        "{get: function() { return 'func'; }})");
3204    CHECK(try_catch.HasCaught());
3205    String::AsciiValue exception_value(try_catch.Exception());
3206    CHECK_EQ(*exception_value,
3207            "TypeError: Cannot redefine property: defineProperty");
3208  }
3209  {
3210    v8::TryCatch try_catch;
3211    CompileRun("Object.defineProperty(obj2, 'x',"
3212        "{get: function() { return 'func'; }})");
3213    CHECK(try_catch.HasCaught());
3214    String::AsciiValue exception_value(try_catch.Exception());
3215    CHECK_EQ(*exception_value,
3216            "TypeError: Cannot redefine property: defineProperty");
3217  }
3218}
3219
3220
3221static v8::Handle<Value> Get239Value(Local<String> name,
3222                                     const AccessorInfo& info) {
3223  ApiTestFuzzer::Fuzz();
3224  CHECK_EQ(info.Data(), v8_str("donut"));
3225  CHECK_EQ(name, v8_str("239"));
3226  return name;
3227}
3228
3229
3230THREADED_TEST(ElementAPIAccessor) {
3231  v8::HandleScope scope;
3232  Local<ObjectTemplate> templ = ObjectTemplate::New();
3233  LocalContext context;
3234
3235  context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3236  CompileRun("var obj2 = {};");
3237
3238  CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
3239        v8_str("239"),
3240        Get239Value, NULL,
3241        v8_str("donut")));
3242  CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
3243        v8_str("239"),
3244        Get239Value, NULL,
3245        v8_str("donut")));
3246
3247  ExpectString("obj1[239]", "239");
3248  ExpectString("obj2[239]", "239");
3249  ExpectString("obj1['239']", "239");
3250  ExpectString("obj2['239']", "239");
3251}
3252
3253
3254v8::Persistent<Value> xValue;
3255
3256
3257static void SetXValue(Local<String> name,
3258                      Local<Value> value,
3259                      const AccessorInfo& info) {
3260  CHECK_EQ(value, v8_num(4));
3261  CHECK_EQ(info.Data(), v8_str("donut"));
3262  CHECK_EQ(name, v8_str("x"));
3263  CHECK(xValue.IsEmpty());
3264  xValue = v8::Persistent<Value>::New(value);
3265}
3266
3267
3268THREADED_TEST(SimplePropertyWrite) {
3269  v8::HandleScope scope;
3270  Local<ObjectTemplate> templ = ObjectTemplate::New();
3271  templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
3272  LocalContext context;
3273  context->Global()->Set(v8_str("obj"), templ->NewInstance());
3274  Local<Script> script = Script::Compile(v8_str("obj.x = 4"));
3275  for (int i = 0; i < 10; i++) {
3276    CHECK(xValue.IsEmpty());
3277    script->Run();
3278    CHECK_EQ(v8_num(4), xValue);
3279    xValue.Dispose();
3280    xValue = v8::Persistent<Value>();
3281  }
3282}
3283
3284
3285static v8::Handle<Value> XPropertyGetter(Local<String> property,
3286                                         const AccessorInfo& info) {
3287  ApiTestFuzzer::Fuzz();
3288  CHECK(info.Data()->IsUndefined());
3289  return property;
3290}
3291
3292
3293THREADED_TEST(NamedInterceptorPropertyRead) {
3294  v8::HandleScope scope;
3295  Local<ObjectTemplate> templ = ObjectTemplate::New();
3296  templ->SetNamedPropertyHandler(XPropertyGetter);
3297  LocalContext context;
3298  context->Global()->Set(v8_str("obj"), templ->NewInstance());
3299  Local<Script> script = Script::Compile(v8_str("obj.x"));
3300  for (int i = 0; i < 10; i++) {
3301    Local<Value> result = script->Run();
3302    CHECK_EQ(result, v8_str("x"));
3303  }
3304}
3305
3306
3307THREADED_TEST(NamedInterceptorDictionaryIC) {
3308  v8::HandleScope scope;
3309  Local<ObjectTemplate> templ = ObjectTemplate::New();
3310  templ->SetNamedPropertyHandler(XPropertyGetter);
3311  LocalContext context;
3312  // Create an object with a named interceptor.
3313  context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
3314  Local<Script> script = Script::Compile(v8_str("interceptor_obj.x"));
3315  for (int i = 0; i < 10; i++) {
3316    Local<Value> result = script->Run();
3317    CHECK_EQ(result, v8_str("x"));
3318  }
3319  // Create a slow case object and a function accessing a property in
3320  // that slow case object (with dictionary probing in generated
3321  // code). Then force object with a named interceptor into slow-case,
3322  // pass it to the function, and check that the interceptor is called
3323  // instead of accessing the local property.
3324  Local<Value> result =
3325      CompileRun("function get_x(o) { return o.x; };"
3326                 "var obj = { x : 42, y : 0 };"
3327                 "delete obj.y;"
3328                 "for (var i = 0; i < 10; i++) get_x(obj);"
3329                 "interceptor_obj.x = 42;"
3330                 "interceptor_obj.y = 10;"
3331                 "delete interceptor_obj.y;"
3332                 "get_x(interceptor_obj)");
3333  CHECK_EQ(result, v8_str("x"));
3334}
3335
3336
3337THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
3338  v8::HandleScope scope;
3339
3340  v8::Persistent<Context> context1 = Context::New();
3341
3342  context1->Enter();
3343  Local<ObjectTemplate> templ = ObjectTemplate::New();
3344  templ->SetNamedPropertyHandler(XPropertyGetter);
3345  // Create an object with a named interceptor.
3346  v8::Local<v8::Object> object = templ->NewInstance();
3347  context1->Global()->Set(v8_str("interceptor_obj"), object);
3348
3349  // Force the object into the slow case.
3350  CompileRun("interceptor_obj.y = 0;"
3351             "delete interceptor_obj.y;");
3352  context1->Exit();
3353
3354  {
3355    // Introduce the object into a different context.
3356    // Repeat named loads to exercise ICs.
3357    LocalContext context2;
3358    context2->Global()->Set(v8_str("interceptor_obj"), object);
3359    Local<Value> result =
3360      CompileRun("function get_x(o) { return o.x; }"
3361                 "interceptor_obj.x = 42;"
3362                 "for (var i=0; i != 10; i++) {"
3363                 "  get_x(interceptor_obj);"
3364                 "}"
3365                 "get_x(interceptor_obj)");
3366    // Check that the interceptor was actually invoked.
3367    CHECK_EQ(result, v8_str("x"));
3368  }
3369
3370  // Return to the original context and force some object to the slow case
3371  // to cause the NormalizedMapCache to verify.
3372  context1->Enter();
3373  CompileRun("var obj = { x : 0 }; delete obj.x;");
3374  context1->Exit();
3375
3376  context1.Dispose();
3377}
3378
3379
3380static v8::Handle<Value> SetXOnPrototypeGetter(Local<String> property,
3381                                               const AccessorInfo& info) {
3382  // Set x on the prototype object and do not handle the get request.
3383  v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
3384  proto.As<v8::Object>()->Set(v8_str("x"), v8::Integer::New(23));
3385  return v8::Handle<Value>();
3386}
3387
3388
3389// This is a regression test for http://crbug.com/20104. Map
3390// transitions should not interfere with post interceptor lookup.
3391THREADED_TEST(NamedInterceptorMapTransitionRead) {
3392  v8::HandleScope scope;
3393  Local<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New();
3394  Local<v8::ObjectTemplate> instance_template
3395      = function_template->InstanceTemplate();
3396  instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
3397  LocalContext context;
3398  context->Global()->Set(v8_str("F"), function_template->GetFunction());
3399  // Create an instance of F and introduce a map transition for x.
3400  CompileRun("var o = new F(); o.x = 23;");
3401  // Create an instance of F and invoke the getter. The result should be 23.
3402  Local<Value> result = CompileRun("o = new F(); o.x");
3403  CHECK_EQ(result->Int32Value(), 23);
3404}
3405
3406
3407static v8::Handle<Value> IndexedPropertyGetter(uint32_t index,
3408                                               const AccessorInfo& info) {
3409  ApiTestFuzzer::Fuzz();
3410  if (index == 37) {
3411    return v8::Handle<Value>(v8_num(625));
3412  }
3413  return v8::Handle<Value>();
3414}
3415
3416
3417static v8::Handle<Value> IndexedPropertySetter(uint32_t index,
3418                                               Local<Value> value,
3419                                               const AccessorInfo& info) {
3420  ApiTestFuzzer::Fuzz();
3421  if (index == 39) {
3422    return value;
3423  }
3424  return v8::Handle<Value>();
3425}
3426
3427
3428THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
3429  v8::HandleScope scope;
3430  Local<ObjectTemplate> templ = ObjectTemplate::New();
3431  templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
3432                                   IndexedPropertySetter);
3433  LocalContext context;
3434  context->Global()->Set(v8_str("obj"), templ->NewInstance());
3435  Local<Script> getter_script = Script::Compile(v8_str(
3436      "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];"));
3437  Local<Script> setter_script = Script::Compile(v8_str(
3438      "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
3439      "obj[17] = 23;"
3440      "obj.foo;"));
3441  Local<Script> interceptor_setter_script = Script::Compile(v8_str(
3442      "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
3443      "obj[39] = 47;"
3444      "obj.foo;"));  // This setter should not run, due to the interceptor.
3445  Local<Script> interceptor_getter_script = Script::Compile(v8_str(
3446      "obj[37];"));
3447  Local<Value> result = getter_script->Run();
3448  CHECK_EQ(v8_num(5), result);
3449  result = setter_script->Run();
3450  CHECK_EQ(v8_num(23), result);
3451  result = interceptor_setter_script->Run();
3452  CHECK_EQ(v8_num(23), result);
3453  result = interceptor_getter_script->Run();
3454  CHECK_EQ(v8_num(625), result);
3455}
3456
3457
3458static v8::Handle<Value> IdentityIndexedPropertyGetter(
3459    uint32_t index,
3460    const AccessorInfo& info) {
3461  return v8::Integer::NewFromUnsigned(index);
3462}
3463
3464
3465THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
3466  v8::HandleScope scope;
3467  Local<ObjectTemplate> templ = ObjectTemplate::New();
3468  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3469
3470  LocalContext context;
3471  context->Global()->Set(v8_str("obj"), templ->NewInstance());
3472
3473  // Check fast object case.
3474  const char* fast_case_code =
3475      "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
3476  ExpectString(fast_case_code, "0");
3477
3478  // Check slow case.
3479  const char* slow_case_code =
3480      "obj.x = 1; delete obj.x;"
3481      "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
3482  ExpectString(slow_case_code, "1");
3483}
3484
3485
3486THREADED_TEST(IndexedInterceptorWithNoSetter) {
3487  v8::HandleScope scope;
3488  Local<ObjectTemplate> templ = ObjectTemplate::New();
3489  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3490
3491  LocalContext context;
3492  context->Global()->Set(v8_str("obj"), templ->NewInstance());
3493
3494  const char* code =
3495      "try {"
3496      "  obj[0] = 239;"
3497      "  for (var i = 0; i < 100; i++) {"
3498      "    var v = obj[0];"
3499      "    if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
3500      "  }"
3501      "  'PASSED'"
3502      "} catch(e) {"
3503      "  e"
3504      "}";
3505  ExpectString(code, "PASSED");
3506}
3507
3508
3509THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
3510  v8::HandleScope scope;
3511  Local<ObjectTemplate> templ = ObjectTemplate::New();
3512  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3513
3514  LocalContext context;
3515  Local<v8::Object> obj = templ->NewInstance();
3516  obj->TurnOnAccessCheck();
3517  context->Global()->Set(v8_str("obj"), obj);
3518
3519  const char* code =
3520      "try {"
3521      "  for (var i = 0; i < 100; i++) {"
3522      "    var v = obj[0];"
3523      "    if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
3524      "  }"
3525      "  'PASSED'"
3526      "} catch(e) {"
3527      "  e"
3528      "}";
3529  ExpectString(code, "PASSED");
3530}
3531
3532
3533THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
3534  i::FLAG_allow_natives_syntax = true;
3535  v8::HandleScope scope;
3536  Local<ObjectTemplate> templ = ObjectTemplate::New();
3537  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3538
3539  LocalContext context;
3540  Local<v8::Object> obj = templ->NewInstance();
3541  context->Global()->Set(v8_str("obj"), obj);
3542
3543  const char* code =
3544      "try {"
3545      "  for (var i = 0; i < 100; i++) {"
3546      "    var expected = i;"
3547      "    if (i == 5) {"
3548      "      %EnableAccessChecks(obj);"
3549      "      expected = undefined;"
3550      "    }"
3551      "    var v = obj[i];"
3552      "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3553      "    if (i == 5) %DisableAccessChecks(obj);"
3554      "  }"
3555      "  'PASSED'"
3556      "} catch(e) {"
3557      "  e"
3558      "}";
3559  ExpectString(code, "PASSED");
3560}
3561
3562
3563THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
3564  v8::HandleScope scope;
3565  Local<ObjectTemplate> templ = ObjectTemplate::New();
3566  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3567
3568  LocalContext context;
3569  Local<v8::Object> obj = templ->NewInstance();
3570  context->Global()->Set(v8_str("obj"), obj);
3571
3572  const char* code =
3573      "try {"
3574      "  for (var i = 0; i < 100; i++) {"
3575      "    var v = obj[i];"
3576      "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
3577      "  }"
3578      "  'PASSED'"
3579      "} catch(e) {"
3580      "  e"
3581      "}";
3582  ExpectString(code, "PASSED");
3583}
3584
3585
3586THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
3587  v8::HandleScope scope;
3588  Local<ObjectTemplate> templ = ObjectTemplate::New();
3589  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3590
3591  LocalContext context;
3592  Local<v8::Object> obj = templ->NewInstance();
3593  context->Global()->Set(v8_str("obj"), obj);
3594
3595  const char* code =
3596      "try {"
3597      "  for (var i = 0; i < 100; i++) {"
3598      "    var expected = i;"
3599      "    var key = i;"
3600      "    if (i == 25) {"
3601      "       key = -1;"
3602      "       expected = undefined;"
3603      "    }"
3604      "    if (i == 50) {"
3605      "       /* probe minimal Smi number on 32-bit platforms */"
3606      "       key = -(1 << 30);"
3607      "       expected = undefined;"
3608      "    }"
3609      "    if (i == 75) {"
3610      "       /* probe minimal Smi number on 64-bit platforms */"
3611      "       key = 1 << 31;"
3612      "       expected = undefined;"
3613      "    }"
3614      "    var v = obj[key];"
3615      "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3616      "  }"
3617      "  'PASSED'"
3618      "} catch(e) {"
3619      "  e"
3620      "}";
3621  ExpectString(code, "PASSED");
3622}
3623
3624
3625THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
3626  v8::HandleScope scope;
3627  Local<ObjectTemplate> templ = ObjectTemplate::New();
3628  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3629
3630  LocalContext context;
3631  Local<v8::Object> obj = templ->NewInstance();
3632  context->Global()->Set(v8_str("obj"), obj);
3633
3634  const char* code =
3635      "try {"
3636      "  for (var i = 0; i < 100; i++) {"
3637      "    var expected = i;"
3638      "    var key = i;"
3639      "    if (i == 50) {"
3640      "       key = 'foobar';"
3641      "       expected = undefined;"
3642      "    }"
3643      "    var v = obj[key];"
3644      "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3645      "  }"
3646      "  'PASSED'"
3647      "} catch(e) {"
3648      "  e"
3649      "}";
3650  ExpectString(code, "PASSED");
3651}
3652
3653
3654THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
3655  v8::HandleScope scope;
3656  Local<ObjectTemplate> templ = ObjectTemplate::New();
3657  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3658
3659  LocalContext context;
3660  Local<v8::Object> obj = templ->NewInstance();
3661  context->Global()->Set(v8_str("obj"), obj);
3662
3663  const char* code =
3664      "var original = obj;"
3665      "try {"
3666      "  for (var i = 0; i < 100; i++) {"
3667      "    var expected = i;"
3668      "    if (i == 50) {"
3669      "       obj = {50: 'foobar'};"
3670      "       expected = 'foobar';"
3671      "    }"
3672      "    var v = obj[i];"
3673      "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3674      "    if (i == 50) obj = original;"
3675      "  }"
3676      "  'PASSED'"
3677      "} catch(e) {"
3678      "  e"
3679      "}";
3680  ExpectString(code, "PASSED");
3681}
3682
3683
3684THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
3685  v8::HandleScope scope;
3686  Local<ObjectTemplate> templ = ObjectTemplate::New();
3687  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3688
3689  LocalContext context;
3690  Local<v8::Object> obj = templ->NewInstance();
3691  context->Global()->Set(v8_str("obj"), obj);
3692
3693  const char* code =
3694      "var original = obj;"
3695      "try {"
3696      "  for (var i = 0; i < 100; i++) {"
3697      "    var expected = i;"
3698      "    if (i == 5) {"
3699      "       obj = 239;"
3700      "       expected = undefined;"
3701      "    }"
3702      "    var v = obj[i];"
3703      "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3704      "    if (i == 5) obj = original;"
3705      "  }"
3706      "  'PASSED'"
3707      "} catch(e) {"
3708      "  e"
3709      "}";
3710  ExpectString(code, "PASSED");
3711}
3712
3713
3714THREADED_TEST(IndexedInterceptorOnProto) {
3715  v8::HandleScope scope;
3716  Local<ObjectTemplate> templ = ObjectTemplate::New();
3717  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3718
3719  LocalContext context;
3720  Local<v8::Object> obj = templ->NewInstance();
3721  context->Global()->Set(v8_str("obj"), obj);
3722
3723  const char* code =
3724      "var o = {__proto__: obj};"
3725      "try {"
3726      "  for (var i = 0; i < 100; i++) {"
3727      "    var v = o[i];"
3728      "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
3729      "  }"
3730      "  'PASSED'"
3731      "} catch(e) {"
3732      "  e"
3733      "}";
3734  ExpectString(code, "PASSED");
3735}
3736
3737
3738THREADED_TEST(MultiContexts) {
3739  v8::HandleScope scope;
3740  v8::Handle<ObjectTemplate> templ = ObjectTemplate::New();
3741  templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(DummyCallHandler));
3742
3743  Local<String> password = v8_str("Password");
3744
3745  // Create an environment
3746  LocalContext context0(0, templ);
3747  context0->SetSecurityToken(password);
3748  v8::Handle<v8::Object> global0 = context0->Global();
3749  global0->Set(v8_str("custom"), v8_num(1234));
3750  CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
3751
3752  // Create an independent environment
3753  LocalContext context1(0, templ);
3754  context1->SetSecurityToken(password);
3755  v8::Handle<v8::Object> global1 = context1->Global();
3756  global1->Set(v8_str("custom"), v8_num(1234));
3757  CHECK_NE(global0, global1);
3758  CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
3759  CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
3760
3761  // Now create a new context with the old global
3762  LocalContext context2(0, templ, global1);
3763  context2->SetSecurityToken(password);
3764  v8::Handle<v8::Object> global2 = context2->Global();
3765  CHECK_EQ(global1, global2);
3766  CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
3767  CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
3768}
3769
3770
3771THREADED_TEST(FunctionPrototypeAcrossContexts) {
3772  // Make sure that functions created by cloning boilerplates cannot
3773  // communicate through their __proto__ field.
3774
3775  v8::HandleScope scope;
3776
3777  LocalContext env0;
3778  v8::Handle<v8::Object> global0 =
3779      env0->Global();
3780  v8::Handle<v8::Object> object0 =
3781      global0->Get(v8_str("Object")).As<v8::Object>();
3782  v8::Handle<v8::Object> tostring0 =
3783      object0->Get(v8_str("toString")).As<v8::Object>();
3784  v8::Handle<v8::Object> proto0 =
3785      tostring0->Get(v8_str("__proto__")).As<v8::Object>();
3786  proto0->Set(v8_str("custom"), v8_num(1234));
3787
3788  LocalContext env1;
3789  v8::Handle<v8::Object> global1 =
3790      env1->Global();
3791  v8::Handle<v8::Object> object1 =
3792      global1->Get(v8_str("Object")).As<v8::Object>();
3793  v8::Handle<v8::Object> tostring1 =
3794      object1->Get(v8_str("toString")).As<v8::Object>();
3795  v8::Handle<v8::Object> proto1 =
3796      tostring1->Get(v8_str("__proto__")).As<v8::Object>();
3797  CHECK(!proto1->Has(v8_str("custom")));
3798}
3799
3800
3801THREADED_TEST(Regress892105) {
3802  // Make sure that object and array literals created by cloning
3803  // boilerplates cannot communicate through their __proto__
3804  // field. This is rather difficult to check, but we try to add stuff
3805  // to Object.prototype and Array.prototype and create a new
3806  // environment. This should succeed.
3807
3808  v8::HandleScope scope;
3809
3810  Local<String> source = v8_str("Object.prototype.obj = 1234;"
3811                                "Array.prototype.arr = 4567;"
3812                                "8901");
3813
3814  LocalContext env0;
3815  Local<Script> script0 = Script::Compile(source);
3816  CHECK_EQ(8901.0, script0->Run()->NumberValue());
3817
3818  LocalContext env1;
3819  Local<Script> script1 = Script::Compile(source);
3820  CHECK_EQ(8901.0, script1->Run()->NumberValue());
3821}
3822
3823
3824THREADED_TEST(UndetectableObject) {
3825  v8::HandleScope scope;
3826  LocalContext env;
3827
3828  Local<v8::FunctionTemplate> desc =
3829      v8::FunctionTemplate::New(0, v8::Handle<Value>());
3830  desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
3831
3832  Local<v8::Object> obj = desc->GetFunction()->NewInstance();
3833  env->Global()->Set(v8_str("undetectable"), obj);
3834
3835  ExpectString("undetectable.toString()", "[object Object]");
3836  ExpectString("typeof undetectable", "undefined");
3837  ExpectString("typeof(undetectable)", "undefined");
3838  ExpectBoolean("typeof undetectable == 'undefined'", true);
3839  ExpectBoolean("typeof undetectable == 'object'", false);
3840  ExpectBoolean("if (undetectable) { true; } else { false; }", false);
3841  ExpectBoolean("!undetectable", true);
3842
3843  ExpectObject("true&&undetectable", obj);
3844  ExpectBoolean("false&&undetectable", false);
3845  ExpectBoolean("true||undetectable", true);
3846  ExpectObject("false||undetectable", obj);
3847
3848  ExpectObject("undetectable&&true", obj);
3849  ExpectObject("undetectable&&false", obj);
3850  ExpectBoolean("undetectable||true", true);
3851  ExpectBoolean("undetectable||false", false);
3852
3853  ExpectBoolean("undetectable==null", true);
3854  ExpectBoolean("null==undetectable", true);
3855  ExpectBoolean("undetectable==undefined", true);
3856  ExpectBoolean("undefined==undetectable", true);
3857  ExpectBoolean("undetectable==undetectable", true);
3858
3859
3860  ExpectBoolean("undetectable===null", false);
3861  ExpectBoolean("null===undetectable", false);
3862  ExpectBoolean("undetectable===undefined", false);
3863  ExpectBoolean("undefined===undetectable", false);
3864  ExpectBoolean("undetectable===undetectable", true);
3865}
3866
3867
3868
3869THREADED_TEST(ExtensibleOnUndetectable) {
3870  v8::HandleScope scope;
3871  LocalContext env;
3872
3873  Local<v8::FunctionTemplate> desc =
3874      v8::FunctionTemplate::New(0, v8::Handle<Value>());
3875  desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
3876
3877  Local<v8::Object> obj = desc->GetFunction()->NewInstance();
3878  env->Global()->Set(v8_str("undetectable"), obj);
3879
3880  Local<String> source = v8_str("undetectable.x = 42;"
3881                                "undetectable.x");
3882
3883  Local<Script> script = Script::Compile(source);
3884
3885  CHECK_EQ(v8::Integer::New(42), script->Run());
3886
3887  ExpectBoolean("Object.isExtensible(undetectable)", true);
3888
3889  source = v8_str("Object.preventExtensions(undetectable);");
3890  script = Script::Compile(source);
3891  script->Run();
3892  ExpectBoolean("Object.isExtensible(undetectable)", false);
3893
3894  source = v8_str("undetectable.y = 2000;");
3895  script = Script::Compile(source);
3896  Local<Value> result = script->Run();
3897  ExpectBoolean("undetectable.y == undefined", true);
3898}
3899
3900
3901
3902THREADED_TEST(UndetectableString) {
3903  v8::HandleScope scope;
3904  LocalContext env;
3905
3906  Local<String> obj = String::NewUndetectable("foo");
3907  env->Global()->Set(v8_str("undetectable"), obj);
3908
3909  ExpectString("undetectable", "foo");
3910  ExpectString("typeof undetectable", "undefined");
3911  ExpectString("typeof(undetectable)", "undefined");
3912  ExpectBoolean("typeof undetectable == 'undefined'", true);
3913  ExpectBoolean("typeof undetectable == 'string'", false);
3914  ExpectBoolean("if (undetectable) { true; } else { false; }", false);
3915  ExpectBoolean("!undetectable", true);
3916
3917  ExpectObject("true&&undetectable", obj);
3918  ExpectBoolean("false&&undetectable", false);
3919  ExpectBoolean("true||undetectable", true);
3920  ExpectObject("false||undetectable", obj);
3921
3922  ExpectObject("undetectable&&true", obj);
3923  ExpectObject("undetectable&&false", obj);
3924  ExpectBoolean("undetectable||true", true);
3925  ExpectBoolean("undetectable||false", false);
3926
3927  ExpectBoolean("undetectable==null", true);
3928  ExpectBoolean("null==undetectable", true);
3929  ExpectBoolean("undetectable==undefined", true);
3930  ExpectBoolean("undefined==undetectable", true);
3931  ExpectBoolean("undetectable==undetectable", true);
3932
3933
3934  ExpectBoolean("undetectable===null", false);
3935  ExpectBoolean("null===undetectable", false);
3936  ExpectBoolean("undetectable===undefined", false);
3937  ExpectBoolean("undefined===undetectable", false);
3938  ExpectBoolean("undetectable===undetectable", true);
3939}
3940
3941
3942template <typename T> static void USE(T) { }
3943
3944
3945// This test is not intended to be run, just type checked.
3946static void PersistentHandles() {
3947  USE(PersistentHandles);
3948  Local<String> str = v8_str("foo");
3949  v8::Persistent<String> p_str = v8::Persistent<String>::New(str);
3950  USE(p_str);
3951  Local<Script> scr = Script::Compile(v8_str(""));
3952  v8::Persistent<Script> p_scr = v8::Persistent<Script>::New(scr);
3953  USE(p_scr);
3954  Local<ObjectTemplate> templ = ObjectTemplate::New();
3955  v8::Persistent<ObjectTemplate> p_templ =
3956    v8::Persistent<ObjectTemplate>::New(templ);
3957  USE(p_templ);
3958}
3959
3960
3961static v8::Handle<Value> HandleLogDelegator(const v8::Arguments& args) {
3962  ApiTestFuzzer::Fuzz();
3963  return v8::Undefined();
3964}
3965
3966
3967THREADED_TEST(GlobalObjectTemplate) {
3968  v8::HandleScope handle_scope;
3969  Local<ObjectTemplate> global_template = ObjectTemplate::New();
3970  global_template->Set(v8_str("JSNI_Log"),
3971                       v8::FunctionTemplate::New(HandleLogDelegator));
3972  v8::Persistent<Context> context = Context::New(0, global_template);
3973  Context::Scope context_scope(context);
3974  Script::Compile(v8_str("JSNI_Log('LOG')"))->Run();
3975  context.Dispose();
3976}
3977
3978
3979static const char* kSimpleExtensionSource =
3980  "function Foo() {"
3981  "  return 4;"
3982  "}";
3983
3984
3985THREADED_TEST(SimpleExtensions) {
3986  v8::HandleScope handle_scope;
3987  v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
3988  const char* extension_names[] = { "simpletest" };
3989  v8::ExtensionConfiguration extensions(1, extension_names);
3990  v8::Handle<Context> context = Context::New(&extensions);
3991  Context::Scope lock(context);
3992  v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
3993  CHECK_EQ(result, v8::Integer::New(4));
3994}
3995
3996
3997static const char* kEvalExtensionSource1 =
3998  "function UseEval1() {"
3999  "  var x = 42;"
4000  "  return eval('x');"
4001  "}";
4002
4003
4004static const char* kEvalExtensionSource2 =
4005  "(function() {"
4006  "  var x = 42;"
4007  "  function e() {"
4008  "    return eval('x');"
4009  "  }"
4010  "  this.UseEval2 = e;"
4011  "})()";
4012
4013
4014THREADED_TEST(UseEvalFromExtension) {
4015  v8::HandleScope handle_scope;
4016  v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
4017  v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
4018  const char* extension_names[] = { "evaltest1", "evaltest2" };
4019  v8::ExtensionConfiguration extensions(2, extension_names);
4020  v8::Handle<Context> context = Context::New(&extensions);
4021  Context::Scope lock(context);
4022  v8::Handle<Value> result = Script::Compile(v8_str("UseEval1()"))->Run();
4023  CHECK_EQ(result, v8::Integer::New(42));
4024  result = Script::Compile(v8_str("UseEval2()"))->Run();
4025  CHECK_EQ(result, v8::Integer::New(42));
4026}
4027
4028
4029static const char* kWithExtensionSource1 =
4030  "function UseWith1() {"
4031  "  var x = 42;"
4032  "  with({x:87}) { return x; }"
4033  "}";
4034
4035
4036
4037static const char* kWithExtensionSource2 =
4038  "(function() {"
4039  "  var x = 42;"
4040  "  function e() {"
4041  "    with ({x:87}) { return x; }"
4042  "  }"
4043  "  this.UseWith2 = e;"
4044  "})()";
4045
4046
4047THREADED_TEST(UseWithFromExtension) {
4048  v8::HandleScope handle_scope;
4049  v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
4050  v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
4051  const char* extension_names[] = { "withtest1", "withtest2" };
4052  v8::ExtensionConfiguration extensions(2, extension_names);
4053  v8::Handle<Context> context = Context::New(&extensions);
4054  Context::Scope lock(context);
4055  v8::Handle<Value> result = Script::Compile(v8_str("UseWith1()"))->Run();
4056  CHECK_EQ(result, v8::Integer::New(87));
4057  result = Script::Compile(v8_str("UseWith2()"))->Run();
4058  CHECK_EQ(result, v8::Integer::New(87));
4059}
4060
4061
4062THREADED_TEST(AutoExtensions) {
4063  v8::HandleScope handle_scope;
4064  Extension* extension = new Extension("autotest", kSimpleExtensionSource);
4065  extension->set_auto_enable(true);
4066  v8::RegisterExtension(extension);
4067  v8::Handle<Context> context = Context::New();
4068  Context::Scope lock(context);
4069  v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
4070  CHECK_EQ(result, v8::Integer::New(4));
4071}
4072
4073
4074static const char* kSyntaxErrorInExtensionSource =
4075    "[";
4076
4077
4078// Test that a syntax error in an extension does not cause a fatal
4079// error but results in an empty context.
4080THREADED_TEST(SyntaxErrorExtensions) {
4081  v8::HandleScope handle_scope;
4082  v8::RegisterExtension(new Extension("syntaxerror",
4083                                      kSyntaxErrorInExtensionSource));
4084  const char* extension_names[] = { "syntaxerror" };
4085  v8::ExtensionConfiguration extensions(1, extension_names);
4086  v8::Handle<Context> context = Context::New(&extensions);
4087  CHECK(context.IsEmpty());
4088}
4089
4090
4091static const char* kExceptionInExtensionSource =
4092    "throw 42";
4093
4094
4095// Test that an exception when installing an extension does not cause
4096// a fatal error but results in an empty context.
4097THREADED_TEST(ExceptionExtensions) {
4098  v8::HandleScope handle_scope;
4099  v8::RegisterExtension(new Extension("exception",
4100                                      kExceptionInExtensionSource));
4101  const char* extension_names[] = { "exception" };
4102  v8::ExtensionConfiguration extensions(1, extension_names);
4103  v8::Handle<Context> context = Context::New(&extensions);
4104  CHECK(context.IsEmpty());
4105}
4106
4107
4108static const char* kNativeCallInExtensionSource =
4109    "function call_runtime_last_index_of(x) {"
4110    "  return %StringLastIndexOf(x, 'bob', 10);"
4111    "}";
4112
4113
4114static const char* kNativeCallTest =
4115    "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
4116
4117// Test that a native runtime calls are supported in extensions.
4118THREADED_TEST(NativeCallInExtensions) {
4119  v8::HandleScope handle_scope;
4120  v8::RegisterExtension(new Extension("nativecall",
4121                                      kNativeCallInExtensionSource));
4122  const char* extension_names[] = { "nativecall" };
4123  v8::ExtensionConfiguration extensions(1, extension_names);
4124  v8::Handle<Context> context = Context::New(&extensions);
4125  Context::Scope lock(context);
4126  v8::Handle<Value> result = Script::Compile(v8_str(kNativeCallTest))->Run();
4127  CHECK_EQ(result, v8::Integer::New(3));
4128}
4129
4130
4131static void CheckDependencies(const char* name, const char* expected) {
4132  v8::HandleScope handle_scope;
4133  v8::ExtensionConfiguration config(1, &name);
4134  LocalContext context(&config);
4135  CHECK_EQ(String::New(expected), context->Global()->Get(v8_str("loaded")));
4136}
4137
4138
4139/*
4140 * Configuration:
4141 *
4142 *     /-- B <--\
4143 * A <-          -- D <-- E
4144 *     \-- C <--/
4145 */
4146THREADED_TEST(ExtensionDependency) {
4147  static const char* kEDeps[] = { "D" };
4148  v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
4149  static const char* kDDeps[] = { "B", "C" };
4150  v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
4151  static const char* kBCDeps[] = { "A" };
4152  v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
4153  v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
4154  v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
4155  CheckDependencies("A", "undefinedA");
4156  CheckDependencies("B", "undefinedAB");
4157  CheckDependencies("C", "undefinedAC");
4158  CheckDependencies("D", "undefinedABCD");
4159  CheckDependencies("E", "undefinedABCDE");
4160  v8::HandleScope handle_scope;
4161  static const char* exts[2] = { "C", "E" };
4162  v8::ExtensionConfiguration config(2, exts);
4163  LocalContext context(&config);
4164  CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
4165}
4166
4167
4168static const char* kExtensionTestScript =
4169  "native function A();"
4170  "native function B();"
4171  "native function C();"
4172  "function Foo(i) {"
4173  "  if (i == 0) return A();"
4174  "  if (i == 1) return B();"
4175  "  if (i == 2) return C();"
4176  "}";
4177
4178
4179static v8::Handle<Value> CallFun(const v8::Arguments& args) {
4180  ApiTestFuzzer::Fuzz();
4181  if (args.IsConstructCall()) {
4182    args.This()->Set(v8_str("data"), args.Data());
4183    return v8::Null();
4184  }
4185  return args.Data();
4186}
4187
4188
4189class FunctionExtension : public Extension {
4190 public:
4191  FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
4192  virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
4193      v8::Handle<String> name);
4194};
4195
4196
4197static int lookup_count = 0;
4198v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunction(
4199      v8::Handle<String> name) {
4200  lookup_count++;
4201  if (name->Equals(v8_str("A"))) {
4202    return v8::FunctionTemplate::New(CallFun, v8::Integer::New(8));
4203  } else if (name->Equals(v8_str("B"))) {
4204    return v8::FunctionTemplate::New(CallFun, v8::Integer::New(7));
4205  } else if (name->Equals(v8_str("C"))) {
4206    return v8::FunctionTemplate::New(CallFun, v8::Integer::New(6));
4207  } else {
4208    return v8::Handle<v8::FunctionTemplate>();
4209  }
4210}
4211
4212
4213THREADED_TEST(FunctionLookup) {
4214  v8::RegisterExtension(new FunctionExtension());
4215  v8::HandleScope handle_scope;
4216  static const char* exts[1] = { "functiontest" };
4217  v8::ExtensionConfiguration config(1, exts);
4218  LocalContext context(&config);
4219  CHECK_EQ(3, lookup_count);
4220  CHECK_EQ(v8::Integer::New(8), Script::Compile(v8_str("Foo(0)"))->Run());
4221  CHECK_EQ(v8::Integer::New(7), Script::Compile(v8_str("Foo(1)"))->Run());
4222  CHECK_EQ(v8::Integer::New(6), Script::Compile(v8_str("Foo(2)"))->Run());
4223}
4224
4225
4226THREADED_TEST(NativeFunctionConstructCall) {
4227  v8::RegisterExtension(new FunctionExtension());
4228  v8::HandleScope handle_scope;
4229  static const char* exts[1] = { "functiontest" };
4230  v8::ExtensionConfiguration config(1, exts);
4231  LocalContext context(&config);
4232  for (int i = 0; i < 10; i++) {
4233    // Run a few times to ensure that allocation of objects doesn't
4234    // change behavior of a constructor function.
4235    CHECK_EQ(v8::Integer::New(8),
4236             Script::Compile(v8_str("(new A()).data"))->Run());
4237    CHECK_EQ(v8::Integer::New(7),
4238             Script::Compile(v8_str("(new B()).data"))->Run());
4239    CHECK_EQ(v8::Integer::New(6),
4240             Script::Compile(v8_str("(new C()).data"))->Run());
4241  }
4242}
4243
4244
4245static const char* last_location;
4246static const char* last_message;
4247void StoringErrorCallback(const char* location, const char* message) {
4248  if (last_location == NULL) {
4249    last_location = location;
4250    last_message = message;
4251  }
4252}
4253
4254
4255// ErrorReporting creates a circular extensions configuration and
4256// tests that the fatal error handler gets called.  This renders V8
4257// unusable and therefore this test cannot be run in parallel.
4258TEST(ErrorReporting) {
4259  v8::V8::SetFatalErrorHandler(StoringErrorCallback);
4260  static const char* aDeps[] = { "B" };
4261  v8::RegisterExtension(new Extension("A", "", 1, aDeps));
4262  static const char* bDeps[] = { "A" };
4263  v8::RegisterExtension(new Extension("B", "", 1, bDeps));
4264  last_location = NULL;
4265  v8::ExtensionConfiguration config(1, bDeps);
4266  v8::Handle<Context> context = Context::New(&config);
4267  CHECK(context.IsEmpty());
4268  CHECK_NE(last_location, NULL);
4269}
4270
4271
4272static const char* js_code_causing_huge_string_flattening =
4273    "var str = 'X';"
4274    "for (var i = 0; i < 30; i++) {"
4275    "  str = str + str;"
4276    "}"
4277    "str.match(/X/);";
4278
4279
4280void OOMCallback(const char* location, const char* message) {
4281  exit(0);
4282}
4283
4284
4285TEST(RegexpOutOfMemory) {
4286  // Execute a script that causes out of memory when flattening a string.
4287  v8::HandleScope scope;
4288  v8::V8::SetFatalErrorHandler(OOMCallback);
4289  LocalContext context;
4290  Local<Script> script =
4291      Script::Compile(String::New(js_code_causing_huge_string_flattening));
4292  last_location = NULL;
4293  Local<Value> result = script->Run();
4294
4295  CHECK(false);  // Should not return.
4296}
4297
4298
4299static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
4300                                             v8::Handle<Value> data) {
4301  CHECK_EQ(v8::Undefined(), data);
4302  CHECK(message->GetScriptResourceName()->IsUndefined());
4303  CHECK_EQ(v8::Undefined(), message->GetScriptResourceName());
4304  message->GetLineNumber();
4305  message->GetSourceLine();
4306}
4307
4308
4309THREADED_TEST(ErrorWithMissingScriptInfo) {
4310  v8::HandleScope scope;
4311  LocalContext context;
4312  v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
4313  Script::Compile(v8_str("throw Error()"))->Run();
4314  v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
4315}
4316
4317
4318int global_index = 0;
4319
4320class Snorkel {
4321 public:
4322  Snorkel() { index_ = global_index++; }
4323  int index_;
4324};
4325
4326class Whammy {
4327 public:
4328  Whammy() {
4329    cursor_ = 0;
4330  }
4331  ~Whammy() {
4332    script_.Dispose();
4333  }
4334  v8::Handle<Script> getScript() {
4335    if (script_.IsEmpty())
4336      script_ = v8::Persistent<Script>::New(v8_compile("({}).blammo"));
4337    return Local<Script>(*script_);
4338  }
4339
4340 public:
4341  static const int kObjectCount = 256;
4342  int cursor_;
4343  v8::Persistent<v8::Object> objects_[kObjectCount];
4344  v8::Persistent<Script> script_;
4345};
4346
4347static void HandleWeakReference(v8::Persistent<v8::Value> obj, void* data) {
4348  Snorkel* snorkel = reinterpret_cast<Snorkel*>(data);
4349  delete snorkel;
4350  obj.ClearWeak();
4351}
4352
4353v8::Handle<Value> WhammyPropertyGetter(Local<String> name,
4354                                       const AccessorInfo& info) {
4355  Whammy* whammy =
4356    static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
4357
4358  v8::Persistent<v8::Object> prev = whammy->objects_[whammy->cursor_];
4359
4360  v8::Handle<v8::Object> obj = v8::Object::New();
4361  v8::Persistent<v8::Object> global = v8::Persistent<v8::Object>::New(obj);
4362  if (!prev.IsEmpty()) {
4363    prev->Set(v8_str("next"), obj);
4364    prev.MakeWeak(new Snorkel(), &HandleWeakReference);
4365    whammy->objects_[whammy->cursor_].Clear();
4366  }
4367  whammy->objects_[whammy->cursor_] = global;
4368  whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount;
4369  return whammy->getScript()->Run();
4370}
4371
4372THREADED_TEST(WeakReference) {
4373  v8::HandleScope handle_scope;
4374  v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New();
4375  Whammy* whammy = new Whammy();
4376  templ->SetNamedPropertyHandler(WhammyPropertyGetter,
4377                                 0, 0, 0, 0,
4378                                 v8::External::New(whammy));
4379  const char* extension_list[] = { "v8/gc" };
4380  v8::ExtensionConfiguration extensions(1, extension_list);
4381  v8::Persistent<Context> context = Context::New(&extensions);
4382  Context::Scope context_scope(context);
4383
4384  v8::Handle<v8::Object> interceptor = templ->NewInstance();
4385  context->Global()->Set(v8_str("whammy"), interceptor);
4386  const char* code =
4387      "var last;"
4388      "for (var i = 0; i < 10000; i++) {"
4389      "  var obj = whammy.length;"
4390      "  if (last) last.next = obj;"
4391      "  last = obj;"
4392      "}"
4393      "gc();"
4394      "4";
4395  v8::Handle<Value> result = CompileRun(code);
4396  CHECK_EQ(4.0, result->NumberValue());
4397  delete whammy;
4398  context.Dispose();
4399}
4400
4401
4402static bool in_scavenge = false;
4403static int last = -1;
4404
4405static void ForceScavenge(v8::Persistent<v8::Value> obj, void* data) {
4406  CHECK_EQ(-1, last);
4407  last = 0;
4408  obj.Dispose();
4409  obj.Clear();
4410  in_scavenge = true;
4411  HEAP->PerformScavenge();
4412  in_scavenge = false;
4413  *(reinterpret_cast<bool*>(data)) = true;
4414}
4415
4416static void CheckIsNotInvokedInScavenge(v8::Persistent<v8::Value> obj,
4417                                        void* data) {
4418  CHECK_EQ(0, last);
4419  last = 1;
4420  *(reinterpret_cast<bool*>(data)) = in_scavenge;
4421  obj.Dispose();
4422  obj.Clear();
4423}
4424
4425THREADED_TEST(NoWeakRefCallbacksInScavenge) {
4426  // Test verifies that scavenge cannot invoke WeakReferenceCallbacks.
4427  // Calling callbacks from scavenges is unsafe as objects held by those
4428  // handlers might have become strongly reachable, but scavenge doesn't
4429  // check that.
4430  v8::Persistent<Context> context = Context::New();
4431  Context::Scope context_scope(context);
4432
4433  v8::Persistent<v8::Object> object_a;
4434  v8::Persistent<v8::Object> object_b;
4435
4436  {
4437    v8::HandleScope handle_scope;
4438    object_b = v8::Persistent<v8::Object>::New(v8::Object::New());
4439    object_a = v8::Persistent<v8::Object>::New(v8::Object::New());
4440  }
4441
4442  bool object_a_disposed = false;
4443  object_a.MakeWeak(&object_a_disposed, &ForceScavenge);
4444  bool released_in_scavenge = false;
4445  object_b.MakeWeak(&released_in_scavenge, &CheckIsNotInvokedInScavenge);
4446
4447  while (!object_a_disposed) {
4448    HEAP->CollectAllGarbage(false);
4449  }
4450  CHECK(!released_in_scavenge);
4451}
4452
4453
4454v8::Handle<Function> args_fun;
4455
4456
4457static v8::Handle<Value> ArgumentsTestCallback(const v8::Arguments& args) {
4458  ApiTestFuzzer::Fuzz();
4459  CHECK_EQ(args_fun, args.Callee());
4460  CHECK_EQ(3, args.Length());
4461  CHECK_EQ(v8::Integer::New(1), args[0]);
4462  CHECK_EQ(v8::Integer::New(2), args[1]);
4463  CHECK_EQ(v8::Integer::New(3), args[2]);
4464  CHECK_EQ(v8::Undefined(), args[3]);
4465  v8::HandleScope scope;
4466  HEAP->CollectAllGarbage(false);
4467  return v8::Undefined();
4468}
4469
4470
4471THREADED_TEST(Arguments) {
4472  v8::HandleScope scope;
4473  v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
4474  global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback));
4475  LocalContext context(NULL, global);
4476  args_fun = context->Global()->Get(v8_str("f")).As<Function>();
4477  v8_compile("f(1, 2, 3)")->Run();
4478}
4479
4480
4481static v8::Handle<Value> NoBlockGetterX(Local<String> name,
4482                                        const AccessorInfo&) {
4483  return v8::Handle<Value>();
4484}
4485
4486
4487static v8::Handle<Value> NoBlockGetterI(uint32_t index,
4488                                        const AccessorInfo&) {
4489  return v8::Handle<Value>();
4490}
4491
4492
4493static v8::Handle<v8::Boolean> PDeleter(Local<String> name,
4494                                        const AccessorInfo&) {
4495  if (!name->Equals(v8_str("foo"))) {
4496    return v8::Handle<v8::Boolean>();  // not intercepted
4497  }
4498
4499  return v8::False();  // intercepted, and don't delete the property
4500}
4501
4502
4503static v8::Handle<v8::Boolean> IDeleter(uint32_t index, const AccessorInfo&) {
4504  if (index != 2) {
4505    return v8::Handle<v8::Boolean>();  // not intercepted
4506  }
4507
4508  return v8::False();  // intercepted, and don't delete the property
4509}
4510
4511
4512THREADED_TEST(Deleter) {
4513  v8::HandleScope scope;
4514  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4515  obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
4516  obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
4517  LocalContext context;
4518  context->Global()->Set(v8_str("k"), obj->NewInstance());
4519  CompileRun(
4520    "k.foo = 'foo';"
4521    "k.bar = 'bar';"
4522    "k[2] = 2;"
4523    "k[4] = 4;");
4524  CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
4525  CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
4526
4527  CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
4528  CHECK(v8_compile("k.bar")->Run()->IsUndefined());
4529
4530  CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
4531  CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
4532
4533  CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
4534  CHECK(v8_compile("k[4]")->Run()->IsUndefined());
4535}
4536
4537
4538static v8::Handle<Value> GetK(Local<String> name, const AccessorInfo&) {
4539  ApiTestFuzzer::Fuzz();
4540  if (name->Equals(v8_str("foo")) ||
4541      name->Equals(v8_str("bar")) ||
4542      name->Equals(v8_str("baz"))) {
4543    return v8::Undefined();
4544  }
4545  return v8::Handle<Value>();
4546}
4547
4548
4549static v8::Handle<Value> IndexedGetK(uint32_t index, const AccessorInfo&) {
4550  ApiTestFuzzer::Fuzz();
4551  if (index == 0 || index == 1) return v8::Undefined();
4552  return v8::Handle<Value>();
4553}
4554
4555
4556static v8::Handle<v8::Array> NamedEnum(const AccessorInfo&) {
4557  ApiTestFuzzer::Fuzz();
4558  v8::Handle<v8::Array> result = v8::Array::New(3);
4559  result->Set(v8::Integer::New(0), v8_str("foo"));
4560  result->Set(v8::Integer::New(1), v8_str("bar"));
4561  result->Set(v8::Integer::New(2), v8_str("baz"));
4562  return result;
4563}
4564
4565
4566static v8::Handle<v8::Array> IndexedEnum(const AccessorInfo&) {
4567  ApiTestFuzzer::Fuzz();
4568  v8::Handle<v8::Array> result = v8::Array::New(2);
4569  result->Set(v8::Integer::New(0), v8_str("0"));
4570  result->Set(v8::Integer::New(1), v8_str("1"));
4571  return result;
4572}
4573
4574
4575THREADED_TEST(Enumerators) {
4576  v8::HandleScope scope;
4577  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4578  obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
4579  obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
4580  LocalContext context;
4581  context->Global()->Set(v8_str("k"), obj->NewInstance());
4582  v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
4583    "k[10] = 0;"
4584    "k.a = 0;"
4585    "k[5] = 0;"
4586    "k.b = 0;"
4587    "k[4294967295] = 0;"
4588    "k.c = 0;"
4589    "k[4294967296] = 0;"
4590    "k.d = 0;"
4591    "k[140000] = 0;"
4592    "k.e = 0;"
4593    "k[30000000000] = 0;"
4594    "k.f = 0;"
4595    "var result = [];"
4596    "for (var prop in k) {"
4597    "  result.push(prop);"
4598    "}"
4599    "result"));
4600  // Check that we get all the property names returned including the
4601  // ones from the enumerators in the right order: indexed properties
4602  // in numerical order, indexed interceptor properties, named
4603  // properties in insertion order, named interceptor properties.
4604  // This order is not mandated by the spec, so this test is just
4605  // documenting our behavior.
4606  CHECK_EQ(17, result->Length());
4607  // Indexed properties in numerical order.
4608  CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(0)));
4609  CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(1)));
4610  CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(2)));
4611  CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(3)));
4612  // Indexed interceptor properties in the order they are returned
4613  // from the enumerator interceptor.
4614  CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(4)));
4615  CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(5)));
4616  // Named properties in insertion order.
4617  CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(6)));
4618  CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(7)));
4619  CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(8)));
4620  CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(9)));
4621  CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(10)));
4622  CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(11)));
4623  CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(12)));
4624  CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(13)));
4625  // Named interceptor properties.
4626  CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(14)));
4627  CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(15)));
4628  CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(16)));
4629}
4630
4631
4632int p_getter_count;
4633int p_getter_count2;
4634
4635
4636static v8::Handle<Value> PGetter(Local<String> name, const AccessorInfo& info) {
4637  ApiTestFuzzer::Fuzz();
4638  p_getter_count++;
4639  v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
4640  CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
4641  if (name->Equals(v8_str("p1"))) {
4642    CHECK_EQ(info.This(), global->Get(v8_str("o1")));
4643  } else if (name->Equals(v8_str("p2"))) {
4644    CHECK_EQ(info.This(), global->Get(v8_str("o2")));
4645  } else if (name->Equals(v8_str("p3"))) {
4646    CHECK_EQ(info.This(), global->Get(v8_str("o3")));
4647  } else if (name->Equals(v8_str("p4"))) {
4648    CHECK_EQ(info.This(), global->Get(v8_str("o4")));
4649  }
4650  return v8::Undefined();
4651}
4652
4653
4654static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
4655  ApiTestFuzzer::Fuzz();
4656  LocalContext context;
4657  context->Global()->Set(v8_str("o1"), obj->NewInstance());
4658  CompileRun(
4659    "o1.__proto__ = { };"
4660    "var o2 = { __proto__: o1 };"
4661    "var o3 = { __proto__: o2 };"
4662    "var o4 = { __proto__: o3 };"
4663    "for (var i = 0; i < 10; i++) o4.p4;"
4664    "for (var i = 0; i < 10; i++) o3.p3;"
4665    "for (var i = 0; i < 10; i++) o2.p2;"
4666    "for (var i = 0; i < 10; i++) o1.p1;");
4667}
4668
4669
4670static v8::Handle<Value> PGetter2(Local<String> name,
4671                                  const AccessorInfo& info) {
4672  ApiTestFuzzer::Fuzz();
4673  p_getter_count2++;
4674  v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
4675  CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
4676  if (name->Equals(v8_str("p1"))) {
4677    CHECK_EQ(info.This(), global->Get(v8_str("o1")));
4678  } else if (name->Equals(v8_str("p2"))) {
4679    CHECK_EQ(info.This(), global->Get(v8_str("o2")));
4680  } else if (name->Equals(v8_str("p3"))) {
4681    CHECK_EQ(info.This(), global->Get(v8_str("o3")));
4682  } else if (name->Equals(v8_str("p4"))) {
4683    CHECK_EQ(info.This(), global->Get(v8_str("o4")));
4684  }
4685  return v8::Undefined();
4686}
4687
4688
4689THREADED_TEST(GetterHolders) {
4690  v8::HandleScope scope;
4691  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4692  obj->SetAccessor(v8_str("p1"), PGetter);
4693  obj->SetAccessor(v8_str("p2"), PGetter);
4694  obj->SetAccessor(v8_str("p3"), PGetter);
4695  obj->SetAccessor(v8_str("p4"), PGetter);
4696  p_getter_count = 0;
4697  RunHolderTest(obj);
4698  CHECK_EQ(40, p_getter_count);
4699}
4700
4701
4702THREADED_TEST(PreInterceptorHolders) {
4703  v8::HandleScope scope;
4704  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4705  obj->SetNamedPropertyHandler(PGetter2);
4706  p_getter_count2 = 0;
4707  RunHolderTest(obj);
4708  CHECK_EQ(40, p_getter_count2);
4709}
4710
4711
4712THREADED_TEST(ObjectInstantiation) {
4713  v8::HandleScope scope;
4714  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
4715  templ->SetAccessor(v8_str("t"), PGetter2);
4716  LocalContext context;
4717  context->Global()->Set(v8_str("o"), templ->NewInstance());
4718  for (int i = 0; i < 100; i++) {
4719    v8::HandleScope inner_scope;
4720    v8::Handle<v8::Object> obj = templ->NewInstance();
4721    CHECK_NE(obj, context->Global()->Get(v8_str("o")));
4722    context->Global()->Set(v8_str("o2"), obj);
4723    v8::Handle<Value> value =
4724        Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run();
4725    CHECK_EQ(v8::True(), value);
4726    context->Global()->Set(v8_str("o"), obj);
4727  }
4728}
4729
4730
4731static int StrCmp16(uint16_t* a, uint16_t* b) {
4732  while (true) {
4733    if (*a == 0 && *b == 0) return 0;
4734    if (*a != *b) return 0 + *a - *b;
4735    a++;
4736    b++;
4737  }
4738}
4739
4740
4741static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
4742  while (true) {
4743    if (n-- == 0) return 0;
4744    if (*a == 0 && *b == 0) return 0;
4745    if (*a != *b) return 0 + *a - *b;
4746    a++;
4747    b++;
4748  }
4749}
4750
4751
4752THREADED_TEST(StringWrite) {
4753  v8::HandleScope scope;
4754  v8::Handle<String> str = v8_str("abcde");
4755  // abc<Icelandic eth><Unicode snowman>.
4756  v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
4757
4758  CHECK_EQ(5, str2->Length());
4759
4760  char buf[100];
4761  char utf8buf[100];
4762  uint16_t wbuf[100];
4763  int len;
4764  int charlen;
4765
4766  memset(utf8buf, 0x1, sizeof(utf8buf));
4767  len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
4768  CHECK_EQ(9, len);
4769  CHECK_EQ(5, charlen);
4770  CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
4771
4772  memset(utf8buf, 0x1, sizeof(utf8buf));
4773  len = str2->WriteUtf8(utf8buf, 8, &charlen);
4774  CHECK_EQ(8, len);
4775  CHECK_EQ(5, charlen);
4776  CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
4777
4778  memset(utf8buf, 0x1, sizeof(utf8buf));
4779  len = str2->WriteUtf8(utf8buf, 7, &charlen);
4780  CHECK_EQ(5, len);
4781  CHECK_EQ(4, charlen);
4782  CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
4783
4784  memset(utf8buf, 0x1, sizeof(utf8buf));
4785  len = str2->WriteUtf8(utf8buf, 6, &charlen);
4786  CHECK_EQ(5, len);
4787  CHECK_EQ(4, charlen);
4788  CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
4789
4790  memset(utf8buf, 0x1, sizeof(utf8buf));
4791  len = str2->WriteUtf8(utf8buf, 5, &charlen);
4792  CHECK_EQ(5, len);
4793  CHECK_EQ(4, charlen);
4794  CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
4795
4796  memset(utf8buf, 0x1, sizeof(utf8buf));
4797  len = str2->WriteUtf8(utf8buf, 4, &charlen);
4798  CHECK_EQ(3, len);
4799  CHECK_EQ(3, charlen);
4800  CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
4801
4802  memset(utf8buf, 0x1, sizeof(utf8buf));
4803  len = str2->WriteUtf8(utf8buf, 3, &charlen);
4804  CHECK_EQ(3, len);
4805  CHECK_EQ(3, charlen);
4806  CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
4807
4808  memset(utf8buf, 0x1, sizeof(utf8buf));
4809  len = str2->WriteUtf8(utf8buf, 2, &charlen);
4810  CHECK_EQ(2, len);
4811  CHECK_EQ(2, charlen);
4812  CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
4813
4814  memset(buf, 0x1, sizeof(buf));
4815  memset(wbuf, 0x1, sizeof(wbuf));
4816  len = str->WriteAscii(buf);
4817  CHECK_EQ(5, len);
4818  len = str->Write(wbuf);
4819  CHECK_EQ(5, len);
4820  CHECK_EQ(0, strcmp("abcde", buf));
4821  uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
4822  CHECK_EQ(0, StrCmp16(answer1, wbuf));
4823
4824  memset(buf, 0x1, sizeof(buf));
4825  memset(wbuf, 0x1, sizeof(wbuf));
4826  len = str->WriteAscii(buf, 0, 4);
4827  CHECK_EQ(4, len);
4828  len = str->Write(wbuf, 0, 4);
4829  CHECK_EQ(4, len);
4830  CHECK_EQ(0, strncmp("abcd\1", buf, 5));
4831  uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
4832  CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
4833
4834  memset(buf, 0x1, sizeof(buf));
4835  memset(wbuf, 0x1, sizeof(wbuf));
4836  len = str->WriteAscii(buf, 0, 5);
4837  CHECK_EQ(5, len);
4838  len = str->Write(wbuf, 0, 5);
4839  CHECK_EQ(5, len);
4840  CHECK_EQ(0, strncmp("abcde\1", buf, 6));
4841  uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
4842  CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
4843
4844  memset(buf, 0x1, sizeof(buf));
4845  memset(wbuf, 0x1, sizeof(wbuf));
4846  len = str->WriteAscii(buf, 0, 6);
4847  CHECK_EQ(5, len);
4848  len = str->Write(wbuf, 0, 6);
4849  CHECK_EQ(5, len);
4850  CHECK_EQ(0, strcmp("abcde", buf));
4851  uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
4852  CHECK_EQ(0, StrCmp16(answer4, wbuf));
4853
4854  memset(buf, 0x1, sizeof(buf));
4855  memset(wbuf, 0x1, sizeof(wbuf));
4856  len = str->WriteAscii(buf, 4, -1);
4857  CHECK_EQ(1, len);
4858  len = str->Write(wbuf, 4, -1);
4859  CHECK_EQ(1, len);
4860  CHECK_EQ(0, strcmp("e", buf));
4861  uint16_t answer5[] = {'e', '\0'};
4862  CHECK_EQ(0, StrCmp16(answer5, wbuf));
4863
4864  memset(buf, 0x1, sizeof(buf));
4865  memset(wbuf, 0x1, sizeof(wbuf));
4866  len = str->WriteAscii(buf, 4, 6);
4867  CHECK_EQ(1, len);
4868  len = str->Write(wbuf, 4, 6);
4869  CHECK_EQ(1, len);
4870  CHECK_EQ(0, strcmp("e", buf));
4871  CHECK_EQ(0, StrCmp16(answer5, wbuf));
4872
4873  memset(buf, 0x1, sizeof(buf));
4874  memset(wbuf, 0x1, sizeof(wbuf));
4875  len = str->WriteAscii(buf, 4, 1);
4876  CHECK_EQ(1, len);
4877  len = str->Write(wbuf, 4, 1);
4878  CHECK_EQ(1, len);
4879  CHECK_EQ(0, strncmp("e\1", buf, 2));
4880  uint16_t answer6[] = {'e', 0x101};
4881  CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
4882
4883  memset(buf, 0x1, sizeof(buf));
4884  memset(wbuf, 0x1, sizeof(wbuf));
4885  len = str->WriteAscii(buf, 3, 1);
4886  CHECK_EQ(1, len);
4887  len = str->Write(wbuf, 3, 1);
4888  CHECK_EQ(1, len);
4889  CHECK_EQ(0, strncmp("d\1", buf, 2));
4890  uint16_t answer7[] = {'d', 0x101};
4891  CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
4892}
4893
4894
4895THREADED_TEST(ToArrayIndex) {
4896  v8::HandleScope scope;
4897  LocalContext context;
4898
4899  v8::Handle<String> str = v8_str("42");
4900  v8::Handle<v8::Uint32> index = str->ToArrayIndex();
4901  CHECK(!index.IsEmpty());
4902  CHECK_EQ(42.0, index->Uint32Value());
4903  str = v8_str("42asdf");
4904  index = str->ToArrayIndex();
4905  CHECK(index.IsEmpty());
4906  str = v8_str("-42");
4907  index = str->ToArrayIndex();
4908  CHECK(index.IsEmpty());
4909  str = v8_str("4294967295");
4910  index = str->ToArrayIndex();
4911  CHECK(!index.IsEmpty());
4912  CHECK_EQ(4294967295.0, index->Uint32Value());
4913  v8::Handle<v8::Number> num = v8::Number::New(1);
4914  index = num->ToArrayIndex();
4915  CHECK(!index.IsEmpty());
4916  CHECK_EQ(1.0, index->Uint32Value());
4917  num = v8::Number::New(-1);
4918  index = num->ToArrayIndex();
4919  CHECK(index.IsEmpty());
4920  v8::Handle<v8::Object> obj = v8::Object::New();
4921  index = obj->ToArrayIndex();
4922  CHECK(index.IsEmpty());
4923}
4924
4925
4926THREADED_TEST(ErrorConstruction) {
4927  v8::HandleScope scope;
4928  LocalContext context;
4929
4930  v8::Handle<String> foo = v8_str("foo");
4931  v8::Handle<String> message = v8_str("message");
4932  v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
4933  CHECK(range_error->IsObject());
4934  v8::Handle<v8::Object> range_obj = range_error.As<v8::Object>();
4935  CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
4936  v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
4937  CHECK(reference_error->IsObject());
4938  CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
4939  v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
4940  CHECK(syntax_error->IsObject());
4941  CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
4942  v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
4943  CHECK(type_error->IsObject());
4944  CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
4945  v8::Handle<Value> error = v8::Exception::Error(foo);
4946  CHECK(error->IsObject());
4947  CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
4948}
4949
4950
4951static v8::Handle<Value> YGetter(Local<String> name, const AccessorInfo& info) {
4952  ApiTestFuzzer::Fuzz();
4953  return v8_num(10);
4954}
4955
4956
4957static void YSetter(Local<String> name,
4958                    Local<Value> value,
4959                    const AccessorInfo& info) {
4960  if (info.This()->Has(name)) {
4961    info.This()->Delete(name);
4962  }
4963  info.This()->Set(name, value);
4964}
4965
4966
4967THREADED_TEST(DeleteAccessor) {
4968  v8::HandleScope scope;
4969  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4970  obj->SetAccessor(v8_str("y"), YGetter, YSetter);
4971  LocalContext context;
4972  v8::Handle<v8::Object> holder = obj->NewInstance();
4973  context->Global()->Set(v8_str("holder"), holder);
4974  v8::Handle<Value> result = CompileRun(
4975      "holder.y = 11; holder.y = 12; holder.y");
4976  CHECK_EQ(12, result->Uint32Value());
4977}
4978
4979
4980THREADED_TEST(TypeSwitch) {
4981  v8::HandleScope scope;
4982  v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New();
4983  v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New();
4984  v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New();
4985  v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
4986  v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
4987  LocalContext context;
4988  v8::Handle<v8::Object> obj0 = v8::Object::New();
4989  v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
4990  v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
4991  v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
4992  for (int i = 0; i < 10; i++) {
4993    CHECK_EQ(0, type_switch->match(obj0));
4994    CHECK_EQ(1, type_switch->match(obj1));
4995    CHECK_EQ(2, type_switch->match(obj2));
4996    CHECK_EQ(3, type_switch->match(obj3));
4997    CHECK_EQ(3, type_switch->match(obj3));
4998    CHECK_EQ(2, type_switch->match(obj2));
4999    CHECK_EQ(1, type_switch->match(obj1));
5000    CHECK_EQ(0, type_switch->match(obj0));
5001  }
5002}
5003
5004
5005// For use within the TestSecurityHandler() test.
5006static bool g_security_callback_result = false;
5007static bool NamedSecurityTestCallback(Local<v8::Object> global,
5008                                      Local<Value> name,
5009                                      v8::AccessType type,
5010                                      Local<Value> data) {
5011  // Always allow read access.
5012  if (type == v8::ACCESS_GET)
5013    return true;
5014
5015  // Sometimes allow other access.
5016  return g_security_callback_result;
5017}
5018
5019
5020static bool IndexedSecurityTestCallback(Local<v8::Object> global,
5021                                        uint32_t key,
5022                                        v8::AccessType type,
5023                                        Local<Value> data) {
5024  // Always allow read access.
5025  if (type == v8::ACCESS_GET)
5026    return true;
5027
5028  // Sometimes allow other access.
5029  return g_security_callback_result;
5030}
5031
5032
5033static int trouble_nesting = 0;
5034static v8::Handle<Value> TroubleCallback(const v8::Arguments& args) {
5035  ApiTestFuzzer::Fuzz();
5036  trouble_nesting++;
5037
5038  // Call a JS function that throws an uncaught exception.
5039  Local<v8::Object> arg_this = Context::GetCurrent()->Global();
5040  Local<Value> trouble_callee = (trouble_nesting == 3) ?
5041    arg_this->Get(v8_str("trouble_callee")) :
5042    arg_this->Get(v8_str("trouble_caller"));
5043  CHECK(trouble_callee->IsFunction());
5044  return Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL);
5045}
5046
5047
5048static int report_count = 0;
5049static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
5050                                             v8::Handle<Value>) {
5051  report_count++;
5052}
5053
5054
5055// Counts uncaught exceptions, but other tests running in parallel
5056// also have uncaught exceptions.
5057TEST(ApiUncaughtException) {
5058  report_count = 0;
5059  v8::HandleScope scope;
5060  LocalContext env;
5061  v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
5062
5063  Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
5064  v8::Local<v8::Object> global = env->Global();
5065  global->Set(v8_str("trouble"), fun->GetFunction());
5066
5067  Script::Compile(v8_str("function trouble_callee() {"
5068                         "  var x = null;"
5069                         "  return x.foo;"
5070                         "};"
5071                         "function trouble_caller() {"
5072                         "  trouble();"
5073                         "};"))->Run();
5074  Local<Value> trouble = global->Get(v8_str("trouble"));
5075  CHECK(trouble->IsFunction());
5076  Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
5077  CHECK(trouble_callee->IsFunction());
5078  Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
5079  CHECK(trouble_caller->IsFunction());
5080  Function::Cast(*trouble_caller)->Call(global, 0, NULL);
5081  CHECK_EQ(1, report_count);
5082  v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
5083}
5084
5085static const char* script_resource_name = "ExceptionInNativeScript.js";
5086static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
5087                                                v8::Handle<Value>) {
5088  v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
5089  CHECK(!name_val.IsEmpty() && name_val->IsString());
5090  v8::String::AsciiValue name(message->GetScriptResourceName());
5091  CHECK_EQ(script_resource_name, *name);
5092  CHECK_EQ(3, message->GetLineNumber());
5093  v8::String::AsciiValue source_line(message->GetSourceLine());
5094  CHECK_EQ("  new o.foo();", *source_line);
5095}
5096
5097TEST(ExceptionInNativeScript) {
5098  v8::HandleScope scope;
5099  LocalContext env;
5100  v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
5101
5102  Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
5103  v8::Local<v8::Object> global = env->Global();
5104  global->Set(v8_str("trouble"), fun->GetFunction());
5105
5106  Script::Compile(v8_str("function trouble() {\n"
5107                         "  var o = {};\n"
5108                         "  new o.foo();\n"
5109                         "};"), v8::String::New(script_resource_name))->Run();
5110  Local<Value> trouble = global->Get(v8_str("trouble"));
5111  CHECK(trouble->IsFunction());
5112  Function::Cast(*trouble)->Call(global, 0, NULL);
5113  v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
5114}
5115
5116
5117TEST(CompilationErrorUsingTryCatchHandler) {
5118  v8::HandleScope scope;
5119  LocalContext env;
5120  v8::TryCatch try_catch;
5121  Script::Compile(v8_str("This doesn't &*&@#$&*^ compile."));
5122  CHECK_NE(NULL, *try_catch.Exception());
5123  CHECK(try_catch.HasCaught());
5124}
5125
5126
5127TEST(TryCatchFinallyUsingTryCatchHandler) {
5128  v8::HandleScope scope;
5129  LocalContext env;
5130  v8::TryCatch try_catch;
5131  Script::Compile(v8_str("try { throw ''; } catch (e) {}"))->Run();
5132  CHECK(!try_catch.HasCaught());
5133  Script::Compile(v8_str("try { throw ''; } finally {}"))->Run();
5134  CHECK(try_catch.HasCaught());
5135  try_catch.Reset();
5136  Script::Compile(v8_str("(function() {"
5137                         "try { throw ''; } finally { return; }"
5138                         "})()"))->Run();
5139  CHECK(!try_catch.HasCaught());
5140  Script::Compile(v8_str("(function()"
5141                         "  { try { throw ''; } finally { throw 0; }"
5142                         "})()"))->Run();
5143  CHECK(try_catch.HasCaught());
5144}
5145
5146
5147// SecurityHandler can't be run twice
5148TEST(SecurityHandler) {
5149  v8::HandleScope scope0;
5150  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
5151  global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
5152                                           IndexedSecurityTestCallback);
5153  // Create an environment
5154  v8::Persistent<Context> context0 =
5155    Context::New(NULL, global_template);
5156  context0->Enter();
5157
5158  v8::Handle<v8::Object> global0 = context0->Global();
5159  v8::Handle<Script> script0 = v8_compile("foo = 111");
5160  script0->Run();
5161  global0->Set(v8_str("0"), v8_num(999));
5162  v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
5163  CHECK_EQ(111, foo0->Int32Value());
5164  v8::Handle<Value> z0 = global0->Get(v8_str("0"));
5165  CHECK_EQ(999, z0->Int32Value());
5166
5167  // Create another environment, should fail security checks.
5168  v8::HandleScope scope1;
5169
5170  v8::Persistent<Context> context1 =
5171    Context::New(NULL, global_template);
5172  context1->Enter();
5173
5174  v8::Handle<v8::Object> global1 = context1->Global();
5175  global1->Set(v8_str("othercontext"), global0);
5176  // This set will fail the security check.
5177  v8::Handle<Script> script1 =
5178    v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
5179  script1->Run();
5180  // This read will pass the security check.
5181  v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
5182  CHECK_EQ(111, foo1->Int32Value());
5183  // This read will pass the security check.
5184  v8::Handle<Value> z1 = global0->Get(v8_str("0"));
5185  CHECK_EQ(999, z1->Int32Value());
5186
5187  // Create another environment, should pass security checks.
5188  { g_security_callback_result = true;  // allow security handler to pass.
5189    v8::HandleScope scope2;
5190    LocalContext context2;
5191    v8::Handle<v8::Object> global2 = context2->Global();
5192    global2->Set(v8_str("othercontext"), global0);
5193    v8::Handle<Script> script2 =
5194        v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
5195    script2->Run();
5196    v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
5197    CHECK_EQ(333, foo2->Int32Value());
5198    v8::Handle<Value> z2 = global0->Get(v8_str("0"));
5199    CHECK_EQ(888, z2->Int32Value());
5200  }
5201
5202  context1->Exit();
5203  context1.Dispose();
5204
5205  context0->Exit();
5206  context0.Dispose();
5207}
5208
5209
5210THREADED_TEST(SecurityChecks) {
5211  v8::HandleScope handle_scope;
5212  LocalContext env1;
5213  v8::Persistent<Context> env2 = Context::New();
5214
5215  Local<Value> foo = v8_str("foo");
5216  Local<Value> bar = v8_str("bar");
5217
5218  // Set to the same domain.
5219  env1->SetSecurityToken(foo);
5220
5221  // Create a function in env1.
5222  Script::Compile(v8_str("spy=function(){return spy;}"))->Run();
5223  Local<Value> spy = env1->Global()->Get(v8_str("spy"));
5224  CHECK(spy->IsFunction());
5225
5226  // Create another function accessing global objects.
5227  Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run();
5228  Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
5229  CHECK(spy2->IsFunction());
5230
5231  // Switch to env2 in the same domain and invoke spy on env2.
5232  {
5233    env2->SetSecurityToken(foo);
5234    // Enter env2
5235    Context::Scope scope_env2(env2);
5236    Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
5237    CHECK(result->IsFunction());
5238  }
5239
5240  {
5241    env2->SetSecurityToken(bar);
5242    Context::Scope scope_env2(env2);
5243
5244    // Call cross_domain_call, it should throw an exception
5245    v8::TryCatch try_catch;
5246    Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
5247    CHECK(try_catch.HasCaught());
5248  }
5249
5250  env2.Dispose();
5251}
5252
5253
5254// Regression test case for issue 1183439.
5255THREADED_TEST(SecurityChecksForPrototypeChain) {
5256  v8::HandleScope scope;
5257  LocalContext current;
5258  v8::Persistent<Context> other = Context::New();
5259
5260  // Change context to be able to get to the Object function in the
5261  // other context without hitting the security checks.
5262  v8::Local<Value> other_object;
5263  { Context::Scope scope(other);
5264    other_object = other->Global()->Get(v8_str("Object"));
5265    other->Global()->Set(v8_num(42), v8_num(87));
5266  }
5267
5268  current->Global()->Set(v8_str("other"), other->Global());
5269  CHECK(v8_compile("other")->Run()->Equals(other->Global()));
5270
5271  // Make sure the security check fails here and we get an undefined
5272  // result instead of getting the Object function. Repeat in a loop
5273  // to make sure to exercise the IC code.
5274  v8::Local<Script> access_other0 = v8_compile("other.Object");
5275  v8::Local<Script> access_other1 = v8_compile("other[42]");
5276  for (int i = 0; i < 5; i++) {
5277    CHECK(!access_other0->Run()->Equals(other_object));
5278    CHECK(access_other0->Run()->IsUndefined());
5279    CHECK(!access_other1->Run()->Equals(v8_num(87)));
5280    CHECK(access_other1->Run()->IsUndefined());
5281  }
5282
5283  // Create an object that has 'other' in its prototype chain and make
5284  // sure we cannot access the Object function indirectly through
5285  // that. Repeat in a loop to make sure to exercise the IC code.
5286  v8_compile("function F() { };"
5287             "F.prototype = other;"
5288             "var f = new F();")->Run();
5289  v8::Local<Script> access_f0 = v8_compile("f.Object");
5290  v8::Local<Script> access_f1 = v8_compile("f[42]");
5291  for (int j = 0; j < 5; j++) {
5292    CHECK(!access_f0->Run()->Equals(other_object));
5293    CHECK(access_f0->Run()->IsUndefined());
5294    CHECK(!access_f1->Run()->Equals(v8_num(87)));
5295    CHECK(access_f1->Run()->IsUndefined());
5296  }
5297
5298  // Now it gets hairy: Set the prototype for the other global object
5299  // to be the current global object. The prototype chain for 'f' now
5300  // goes through 'other' but ends up in the current global object.
5301  { Context::Scope scope(other);
5302    other->Global()->Set(v8_str("__proto__"), current->Global());
5303  }
5304  // Set a named and an index property on the current global
5305  // object. To force the lookup to go through the other global object,
5306  // the properties must not exist in the other global object.
5307  current->Global()->Set(v8_str("foo"), v8_num(100));
5308  current->Global()->Set(v8_num(99), v8_num(101));
5309  // Try to read the properties from f and make sure that the access
5310  // gets stopped by the security checks on the other global object.
5311  Local<Script> access_f2 = v8_compile("f.foo");
5312  Local<Script> access_f3 = v8_compile("f[99]");
5313  for (int k = 0; k < 5; k++) {
5314    CHECK(!access_f2->Run()->Equals(v8_num(100)));
5315    CHECK(access_f2->Run()->IsUndefined());
5316    CHECK(!access_f3->Run()->Equals(v8_num(101)));
5317    CHECK(access_f3->Run()->IsUndefined());
5318  }
5319  other.Dispose();
5320}
5321
5322
5323THREADED_TEST(CrossDomainDelete) {
5324  v8::HandleScope handle_scope;
5325  LocalContext env1;
5326  v8::Persistent<Context> env2 = Context::New();
5327
5328  Local<Value> foo = v8_str("foo");
5329  Local<Value> bar = v8_str("bar");
5330
5331  // Set to the same domain.
5332  env1->SetSecurityToken(foo);
5333  env2->SetSecurityToken(foo);
5334
5335  env1->Global()->Set(v8_str("prop"), v8_num(3));
5336  env2->Global()->Set(v8_str("env1"), env1->Global());
5337
5338  // Change env2 to a different domain and delete env1.prop.
5339  env2->SetSecurityToken(bar);
5340  {
5341    Context::Scope scope_env2(env2);
5342    Local<Value> result =
5343        Script::Compile(v8_str("delete env1.prop"))->Run();
5344    CHECK(result->IsFalse());
5345  }
5346
5347  // Check that env1.prop still exists.
5348  Local<Value> v = env1->Global()->Get(v8_str("prop"));
5349  CHECK(v->IsNumber());
5350  CHECK_EQ(3, v->Int32Value());
5351
5352  env2.Dispose();
5353}
5354
5355
5356THREADED_TEST(CrossDomainIsPropertyEnumerable) {
5357  v8::HandleScope handle_scope;
5358  LocalContext env1;
5359  v8::Persistent<Context> env2 = Context::New();
5360
5361  Local<Value> foo = v8_str("foo");
5362  Local<Value> bar = v8_str("bar");
5363
5364  // Set to the same domain.
5365  env1->SetSecurityToken(foo);
5366  env2->SetSecurityToken(foo);
5367
5368  env1->Global()->Set(v8_str("prop"), v8_num(3));
5369  env2->Global()->Set(v8_str("env1"), env1->Global());
5370
5371  // env1.prop is enumerable in env2.
5372  Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
5373  {
5374    Context::Scope scope_env2(env2);
5375    Local<Value> result = Script::Compile(test)->Run();
5376    CHECK(result->IsTrue());
5377  }
5378
5379  // Change env2 to a different domain and test again.
5380  env2->SetSecurityToken(bar);
5381  {
5382    Context::Scope scope_env2(env2);
5383    Local<Value> result = Script::Compile(test)->Run();
5384    CHECK(result->IsFalse());
5385  }
5386
5387  env2.Dispose();
5388}
5389
5390
5391THREADED_TEST(CrossDomainForIn) {
5392  v8::HandleScope handle_scope;
5393  LocalContext env1;
5394  v8::Persistent<Context> env2 = Context::New();
5395
5396  Local<Value> foo = v8_str("foo");
5397  Local<Value> bar = v8_str("bar");
5398
5399  // Set to the same domain.
5400  env1->SetSecurityToken(foo);
5401  env2->SetSecurityToken(foo);
5402
5403  env1->Global()->Set(v8_str("prop"), v8_num(3));
5404  env2->Global()->Set(v8_str("env1"), env1->Global());
5405
5406  // Change env2 to a different domain and set env1's global object
5407  // as the __proto__ of an object in env2 and enumerate properties
5408  // in for-in. It shouldn't enumerate properties on env1's global
5409  // object.
5410  env2->SetSecurityToken(bar);
5411  {
5412    Context::Scope scope_env2(env2);
5413    Local<Value> result =
5414        CompileRun("(function(){var obj = {'__proto__':env1};"
5415                   "for (var p in obj)"
5416                   "   if (p == 'prop') return false;"
5417                   "return true;})()");
5418    CHECK(result->IsTrue());
5419  }
5420  env2.Dispose();
5421}
5422
5423
5424TEST(ContextDetachGlobal) {
5425  v8::HandleScope handle_scope;
5426  LocalContext env1;
5427  v8::Persistent<Context> env2 = Context::New();
5428
5429  Local<v8::Object> global1 = env1->Global();
5430
5431  Local<Value> foo = v8_str("foo");
5432
5433  // Set to the same domain.
5434  env1->SetSecurityToken(foo);
5435  env2->SetSecurityToken(foo);
5436
5437  // Enter env2
5438  env2->Enter();
5439
5440  // Create a function in env2 and add a reference to it in env1.
5441  Local<v8::Object> global2 = env2->Global();
5442  global2->Set(v8_str("prop"), v8::Integer::New(1));
5443  CompileRun("function getProp() {return prop;}");
5444
5445  env1->Global()->Set(v8_str("getProp"),
5446                      global2->Get(v8_str("getProp")));
5447
5448  // Detach env2's global, and reuse the global object of env2
5449  env2->Exit();
5450  env2->DetachGlobal();
5451  // env2 has a new global object.
5452  CHECK(!env2->Global()->Equals(global2));
5453
5454  v8::Persistent<Context> env3 =
5455      Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
5456  env3->SetSecurityToken(v8_str("bar"));
5457  env3->Enter();
5458
5459  Local<v8::Object> global3 = env3->Global();
5460  CHECK_EQ(global2, global3);
5461  CHECK(global3->Get(v8_str("prop"))->IsUndefined());
5462  CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
5463  global3->Set(v8_str("prop"), v8::Integer::New(-1));
5464  global3->Set(v8_str("prop2"), v8::Integer::New(2));
5465  env3->Exit();
5466
5467  // Call getProp in env1, and it should return the value 1
5468  {
5469    Local<Value> get_prop = global1->Get(v8_str("getProp"));
5470    CHECK(get_prop->IsFunction());
5471    v8::TryCatch try_catch;
5472    Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
5473    CHECK(!try_catch.HasCaught());
5474    CHECK_EQ(1, r->Int32Value());
5475  }
5476
5477  // Check that env3 is not accessible from env1
5478  {
5479    Local<Value> r = global3->Get(v8_str("prop2"));
5480    CHECK(r->IsUndefined());
5481  }
5482
5483  env2.Dispose();
5484  env3.Dispose();
5485}
5486
5487
5488TEST(DetachAndReattachGlobal) {
5489  v8::HandleScope scope;
5490  LocalContext env1;
5491
5492  // Create second environment.
5493  v8::Persistent<Context> env2 = Context::New();
5494
5495  Local<Value> foo = v8_str("foo");
5496
5497  // Set same security token for env1 and env2.
5498  env1->SetSecurityToken(foo);
5499  env2->SetSecurityToken(foo);
5500
5501  // Create a property on the global object in env2.
5502  {
5503    v8::Context::Scope scope(env2);
5504    env2->Global()->Set(v8_str("p"), v8::Integer::New(42));
5505  }
5506
5507  // Create a reference to env2 global from env1 global.
5508  env1->Global()->Set(v8_str("other"), env2->Global());
5509
5510  // Check that we have access to other.p in env2 from env1.
5511  Local<Value> result = CompileRun("other.p");
5512  CHECK(result->IsInt32());
5513  CHECK_EQ(42, result->Int32Value());
5514
5515  // Hold on to global from env2 and detach global from env2.
5516  Local<v8::Object> global2 = env2->Global();
5517  env2->DetachGlobal();
5518
5519  // Check that the global has been detached. No other.p property can
5520  // be found.
5521  result = CompileRun("other.p");
5522  CHECK(result->IsUndefined());
5523
5524  // Reuse global2 for env3.
5525  v8::Persistent<Context> env3 =
5526      Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
5527  CHECK_EQ(global2, env3->Global());
5528
5529  // Start by using the same security token for env3 as for env1 and env2.
5530  env3->SetSecurityToken(foo);
5531
5532  // Create a property on the global object in env3.
5533  {
5534    v8::Context::Scope scope(env3);
5535    env3->Global()->Set(v8_str("p"), v8::Integer::New(24));
5536  }
5537
5538  // Check that other.p is now the property in env3 and that we have access.
5539  result = CompileRun("other.p");
5540  CHECK(result->IsInt32());
5541  CHECK_EQ(24, result->Int32Value());
5542
5543  // Change security token for env3 to something different from env1 and env2.
5544  env3->SetSecurityToken(v8_str("bar"));
5545
5546  // Check that we do not have access to other.p in env1. |other| is now
5547  // the global object for env3 which has a different security token,
5548  // so access should be blocked.
5549  result = CompileRun("other.p");
5550  CHECK(result->IsUndefined());
5551
5552  // Detach the global for env3 and reattach it to env2.
5553  env3->DetachGlobal();
5554  env2->ReattachGlobal(global2);
5555
5556  // Check that we have access to other.p again in env1.  |other| is now
5557  // the global object for env2 which has the same security token as env1.
5558  result = CompileRun("other.p");
5559  CHECK(result->IsInt32());
5560  CHECK_EQ(42, result->Int32Value());
5561
5562  env2.Dispose();
5563  env3.Dispose();
5564}
5565
5566
5567static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
5568static bool NamedAccessBlocker(Local<v8::Object> global,
5569                               Local<Value> name,
5570                               v8::AccessType type,
5571                               Local<Value> data) {
5572  return Context::GetCurrent()->Global()->Equals(global) ||
5573      allowed_access_type[type];
5574}
5575
5576
5577static bool IndexedAccessBlocker(Local<v8::Object> global,
5578                                 uint32_t key,
5579                                 v8::AccessType type,
5580                                 Local<Value> data) {
5581  return Context::GetCurrent()->Global()->Equals(global) ||
5582      allowed_access_type[type];
5583}
5584
5585
5586static int g_echo_value = -1;
5587static v8::Handle<Value> EchoGetter(Local<String> name,
5588                                    const AccessorInfo& info) {
5589  return v8_num(g_echo_value);
5590}
5591
5592
5593static void EchoSetter(Local<String> name,
5594                       Local<Value> value,
5595                       const AccessorInfo&) {
5596  if (value->IsNumber())
5597    g_echo_value = value->Int32Value();
5598}
5599
5600
5601static v8::Handle<Value> UnreachableGetter(Local<String> name,
5602                                           const AccessorInfo& info) {
5603  CHECK(false);  // This function should not be called..
5604  return v8::Undefined();
5605}
5606
5607
5608static void UnreachableSetter(Local<String>, Local<Value>,
5609                              const AccessorInfo&) {
5610  CHECK(false);  // This function should nto be called.
5611}
5612
5613
5614TEST(AccessControl) {
5615  v8::HandleScope handle_scope;
5616  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
5617
5618  global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
5619                                           IndexedAccessBlocker);
5620
5621  // Add an accessor accessible by cross-domain JS code.
5622  global_template->SetAccessor(
5623      v8_str("accessible_prop"),
5624      EchoGetter, EchoSetter,
5625      v8::Handle<Value>(),
5626      v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
5627
5628  // Add an accessor that is not accessible by cross-domain JS code.
5629  global_template->SetAccessor(v8_str("blocked_prop"),
5630                               UnreachableGetter, UnreachableSetter,
5631                               v8::Handle<Value>(),
5632                               v8::DEFAULT);
5633
5634  // Create an environment
5635  v8::Persistent<Context> context0 = Context::New(NULL, global_template);
5636  context0->Enter();
5637
5638  v8::Handle<v8::Object> global0 = context0->Global();
5639
5640  // Define a property with JS getter and setter.
5641  CompileRun(
5642      "function getter() { return 'getter'; };\n"
5643      "function setter() { return 'setter'; }\n"
5644      "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
5645
5646  Local<Value> getter = global0->Get(v8_str("getter"));
5647  Local<Value> setter = global0->Get(v8_str("setter"));
5648
5649  // And define normal element.
5650  global0->Set(239, v8_str("239"));
5651
5652  // Define an element with JS getter and setter.
5653  CompileRun(
5654      "function el_getter() { return 'el_getter'; };\n"
5655      "function el_setter() { return 'el_setter'; };\n"
5656      "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
5657
5658  Local<Value> el_getter = global0->Get(v8_str("el_getter"));
5659  Local<Value> el_setter = global0->Get(v8_str("el_setter"));
5660
5661  v8::HandleScope scope1;
5662
5663  v8::Persistent<Context> context1 = Context::New();
5664  context1->Enter();
5665
5666  v8::Handle<v8::Object> global1 = context1->Global();
5667  global1->Set(v8_str("other"), global0);
5668
5669  // Access blocked property.
5670  CompileRun("other.blocked_prop = 1");
5671
5672  ExpectUndefined("other.blocked_prop");
5673  ExpectUndefined(
5674      "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
5675  ExpectFalse("propertyIsEnumerable.call(other, 'blocked_prop')");
5676
5677  // Enable ACCESS_HAS
5678  allowed_access_type[v8::ACCESS_HAS] = true;
5679  ExpectUndefined("other.blocked_prop");
5680  // ... and now we can get the descriptor...
5681  ExpectUndefined(
5682      "Object.getOwnPropertyDescriptor(other, 'blocked_prop').value");
5683  // ... and enumerate the property.
5684  ExpectTrue("propertyIsEnumerable.call(other, 'blocked_prop')");
5685  allowed_access_type[v8::ACCESS_HAS] = false;
5686
5687  // Access blocked element.
5688  CompileRun("other[239] = 1");
5689
5690  ExpectUndefined("other[239]");
5691  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239')");
5692  ExpectFalse("propertyIsEnumerable.call(other, '239')");
5693
5694  // Enable ACCESS_HAS
5695  allowed_access_type[v8::ACCESS_HAS] = true;
5696  ExpectUndefined("other[239]");
5697  // ... and now we can get the descriptor...
5698  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239').value");
5699  // ... and enumerate the property.
5700  ExpectTrue("propertyIsEnumerable.call(other, '239')");
5701  allowed_access_type[v8::ACCESS_HAS] = false;
5702
5703  // Access a property with JS accessor.
5704  CompileRun("other.js_accessor_p = 2");
5705
5706  ExpectUndefined("other.js_accessor_p");
5707  ExpectUndefined(
5708      "Object.getOwnPropertyDescriptor(other, 'js_accessor_p')");
5709
5710  // Enable ACCESS_HAS.
5711  allowed_access_type[v8::ACCESS_HAS] = true;
5712  ExpectUndefined("other.js_accessor_p");
5713  ExpectUndefined(
5714      "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
5715  ExpectUndefined(
5716      "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
5717  ExpectUndefined(
5718      "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
5719  allowed_access_type[v8::ACCESS_HAS] = false;
5720
5721  // Enable both ACCESS_HAS and ACCESS_GET.
5722  allowed_access_type[v8::ACCESS_HAS] = true;
5723  allowed_access_type[v8::ACCESS_GET] = true;
5724
5725  ExpectString("other.js_accessor_p", "getter");
5726  ExpectObject(
5727      "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
5728  ExpectUndefined(
5729      "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
5730  ExpectUndefined(
5731      "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
5732
5733  allowed_access_type[v8::ACCESS_GET] = false;
5734  allowed_access_type[v8::ACCESS_HAS] = false;
5735
5736  // Enable both ACCESS_HAS and ACCESS_SET.
5737  allowed_access_type[v8::ACCESS_HAS] = true;
5738  allowed_access_type[v8::ACCESS_SET] = true;
5739
5740  ExpectUndefined("other.js_accessor_p");
5741  ExpectUndefined(
5742      "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
5743  ExpectObject(
5744      "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
5745  ExpectUndefined(
5746      "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
5747
5748  allowed_access_type[v8::ACCESS_SET] = false;
5749  allowed_access_type[v8::ACCESS_HAS] = false;
5750
5751  // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
5752  allowed_access_type[v8::ACCESS_HAS] = true;
5753  allowed_access_type[v8::ACCESS_GET] = true;
5754  allowed_access_type[v8::ACCESS_SET] = true;
5755
5756  ExpectString("other.js_accessor_p", "getter");
5757  ExpectObject(
5758      "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
5759  ExpectObject(
5760      "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
5761  ExpectUndefined(
5762      "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
5763
5764  allowed_access_type[v8::ACCESS_SET] = false;
5765  allowed_access_type[v8::ACCESS_GET] = false;
5766  allowed_access_type[v8::ACCESS_HAS] = false;
5767
5768  // Access an element with JS accessor.
5769  CompileRun("other[42] = 2");
5770
5771  ExpectUndefined("other[42]");
5772  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42')");
5773
5774  // Enable ACCESS_HAS.
5775  allowed_access_type[v8::ACCESS_HAS] = true;
5776  ExpectUndefined("other[42]");
5777  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
5778  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
5779  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
5780  allowed_access_type[v8::ACCESS_HAS] = false;
5781
5782  // Enable both ACCESS_HAS and ACCESS_GET.
5783  allowed_access_type[v8::ACCESS_HAS] = true;
5784  allowed_access_type[v8::ACCESS_GET] = true;
5785
5786  ExpectString("other[42]", "el_getter");
5787  ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
5788  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
5789  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
5790
5791  allowed_access_type[v8::ACCESS_GET] = false;
5792  allowed_access_type[v8::ACCESS_HAS] = false;
5793
5794  // Enable both ACCESS_HAS and ACCESS_SET.
5795  allowed_access_type[v8::ACCESS_HAS] = true;
5796  allowed_access_type[v8::ACCESS_SET] = true;
5797
5798  ExpectUndefined("other[42]");
5799  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
5800  ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
5801  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
5802
5803  allowed_access_type[v8::ACCESS_SET] = false;
5804  allowed_access_type[v8::ACCESS_HAS] = false;
5805
5806  // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
5807  allowed_access_type[v8::ACCESS_HAS] = true;
5808  allowed_access_type[v8::ACCESS_GET] = true;
5809  allowed_access_type[v8::ACCESS_SET] = true;
5810
5811  ExpectString("other[42]", "el_getter");
5812  ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
5813  ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
5814  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
5815
5816  allowed_access_type[v8::ACCESS_SET] = false;
5817  allowed_access_type[v8::ACCESS_GET] = false;
5818  allowed_access_type[v8::ACCESS_HAS] = false;
5819
5820  v8::Handle<Value> value;
5821
5822  // Access accessible property
5823  value = CompileRun("other.accessible_prop = 3");
5824  CHECK(value->IsNumber());
5825  CHECK_EQ(3, value->Int32Value());
5826  CHECK_EQ(3, g_echo_value);
5827
5828  value = CompileRun("other.accessible_prop");
5829  CHECK(value->IsNumber());
5830  CHECK_EQ(3, value->Int32Value());
5831
5832  value = CompileRun(
5833      "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
5834  CHECK(value->IsNumber());
5835  CHECK_EQ(3, value->Int32Value());
5836
5837  value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
5838  CHECK(value->IsTrue());
5839
5840  // Enumeration doesn't enumerate accessors from inaccessible objects in
5841  // the prototype chain even if the accessors are in themselves accessible.
5842  value =
5843      CompileRun("(function(){var obj = {'__proto__':other};"
5844                 "for (var p in obj)"
5845                 "   if (p == 'accessible_prop' || p == 'blocked_prop') {"
5846                 "     return false;"
5847                 "   }"
5848                 "return true;})()");
5849  CHECK(value->IsTrue());
5850
5851  context1->Exit();
5852  context0->Exit();
5853  context1.Dispose();
5854  context0.Dispose();
5855}
5856
5857
5858TEST(AccessControlES5) {
5859  v8::HandleScope handle_scope;
5860  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
5861
5862  global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
5863                                           IndexedAccessBlocker);
5864
5865  // Add accessible accessor.
5866  global_template->SetAccessor(
5867      v8_str("accessible_prop"),
5868      EchoGetter, EchoSetter,
5869      v8::Handle<Value>(),
5870      v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
5871
5872
5873  // Add an accessor that is not accessible by cross-domain JS code.
5874  global_template->SetAccessor(v8_str("blocked_prop"),
5875                               UnreachableGetter, UnreachableSetter,
5876                               v8::Handle<Value>(),
5877                               v8::DEFAULT);
5878
5879  // Create an environment
5880  v8::Persistent<Context> context0 = Context::New(NULL, global_template);
5881  context0->Enter();
5882
5883  v8::Handle<v8::Object> global0 = context0->Global();
5884
5885  v8::Persistent<Context> context1 = Context::New();
5886  context1->Enter();
5887  v8::Handle<v8::Object> global1 = context1->Global();
5888  global1->Set(v8_str("other"), global0);
5889
5890  // Regression test for issue 1154.
5891  ExpectTrue("Object.keys(other).indexOf('blocked_prop') == -1");
5892
5893  ExpectUndefined("other.blocked_prop");
5894
5895  // Regression test for issue 1027.
5896  CompileRun("Object.defineProperty(\n"
5897             "  other, 'blocked_prop', {configurable: false})");
5898  ExpectUndefined("other.blocked_prop");
5899  ExpectUndefined(
5900      "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
5901
5902  // Regression test for issue 1171.
5903  ExpectTrue("Object.isExtensible(other)");
5904  CompileRun("Object.preventExtensions(other)");
5905  ExpectTrue("Object.isExtensible(other)");
5906
5907  // Object.seal and Object.freeze.
5908  CompileRun("Object.freeze(other)");
5909  ExpectTrue("Object.isExtensible(other)");
5910
5911  CompileRun("Object.seal(other)");
5912  ExpectTrue("Object.isExtensible(other)");
5913
5914  // Regression test for issue 1250.
5915  // Make sure that we can set the accessible accessors value using normal
5916  // assignment.
5917  CompileRun("other.accessible_prop = 42");
5918  CHECK_EQ(42, g_echo_value);
5919
5920  v8::Handle<Value> value;
5921  // We follow Safari in ignoring assignments to host object accessors.
5922  CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
5923  value = CompileRun("other.accessible_prop == 42");
5924  CHECK(value->IsTrue());
5925}
5926
5927
5928static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
5929                                            Local<Value> name,
5930                                            v8::AccessType type,
5931                                            Local<Value> data) {
5932  return false;
5933}
5934
5935
5936static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
5937                                              uint32_t key,
5938                                              v8::AccessType type,
5939                                              Local<Value> data) {
5940  return false;
5941}
5942
5943
5944THREADED_TEST(AccessControlGetOwnPropertyNames) {
5945  v8::HandleScope handle_scope;
5946  v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
5947
5948  obj_template->Set(v8_str("x"), v8::Integer::New(42));
5949  obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
5950                                        GetOwnPropertyNamesIndexedBlocker);
5951
5952  // Create an environment
5953  v8::Persistent<Context> context0 = Context::New(NULL, obj_template);
5954  context0->Enter();
5955
5956  v8::Handle<v8::Object> global0 = context0->Global();
5957
5958  v8::HandleScope scope1;
5959
5960  v8::Persistent<Context> context1 = Context::New();
5961  context1->Enter();
5962
5963  v8::Handle<v8::Object> global1 = context1->Global();
5964  global1->Set(v8_str("other"), global0);
5965  global1->Set(v8_str("object"), obj_template->NewInstance());
5966
5967  v8::Handle<Value> value;
5968
5969  // Attempt to get the property names of the other global object and
5970  // of an object that requires access checks.  Accessing the other
5971  // global object should be blocked by access checks on the global
5972  // proxy object.  Accessing the object that requires access checks
5973  // is blocked by the access checks on the object itself.
5974  value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
5975  CHECK(value->IsTrue());
5976
5977  value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
5978  CHECK(value->IsTrue());
5979
5980  context1->Exit();
5981  context0->Exit();
5982  context1.Dispose();
5983  context0.Dispose();
5984}
5985
5986
5987static v8::Handle<v8::Array> NamedPropertyEnumerator(const AccessorInfo& info) {
5988  v8::Handle<v8::Array> result = v8::Array::New(1);
5989  result->Set(0, v8_str("x"));
5990  return result;
5991}
5992
5993
5994THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
5995  v8::HandleScope handle_scope;
5996  v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
5997
5998  obj_template->Set(v8_str("x"), v8::Integer::New(42));
5999  obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
6000                                        NamedPropertyEnumerator);
6001
6002  LocalContext context;
6003  v8::Handle<v8::Object> global = context->Global();
6004  global->Set(v8_str("object"), obj_template->NewInstance());
6005
6006  v8::Handle<Value> value =
6007      CompileRun("Object.getOwnPropertyNames(object).join(',')");
6008  CHECK_EQ(v8_str("x"), value);
6009}
6010
6011
6012static v8::Handle<Value> ConstTenGetter(Local<String> name,
6013                                        const AccessorInfo& info) {
6014  return v8_num(10);
6015}
6016
6017
6018THREADED_TEST(CrossDomainAccessors) {
6019  v8::HandleScope handle_scope;
6020
6021  v8::Handle<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
6022
6023  v8::Handle<v8::ObjectTemplate> global_template =
6024      func_template->InstanceTemplate();
6025
6026  v8::Handle<v8::ObjectTemplate> proto_template =
6027      func_template->PrototypeTemplate();
6028
6029  // Add an accessor to proto that's accessible by cross-domain JS code.
6030  proto_template->SetAccessor(v8_str("accessible"),
6031                              ConstTenGetter, 0,
6032                              v8::Handle<Value>(),
6033                              v8::ALL_CAN_READ);
6034
6035  // Add an accessor that is not accessible by cross-domain JS code.
6036  global_template->SetAccessor(v8_str("unreachable"),
6037                               UnreachableGetter, 0,
6038                               v8::Handle<Value>(),
6039                               v8::DEFAULT);
6040
6041  v8::Persistent<Context> context0 = Context::New(NULL, global_template);
6042  context0->Enter();
6043
6044  Local<v8::Object> global = context0->Global();
6045  // Add a normal property that shadows 'accessible'
6046  global->Set(v8_str("accessible"), v8_num(11));
6047
6048  // Enter a new context.
6049  v8::HandleScope scope1;
6050  v8::Persistent<Context> context1 = Context::New();
6051  context1->Enter();
6052
6053  v8::Handle<v8::Object> global1 = context1->Global();
6054  global1->Set(v8_str("other"), global);
6055
6056  // Should return 10, instead of 11
6057  v8::Handle<Value> value = v8_compile("other.accessible")->Run();
6058  CHECK(value->IsNumber());
6059  CHECK_EQ(10, value->Int32Value());
6060
6061  value = v8_compile("other.unreachable")->Run();
6062  CHECK(value->IsUndefined());
6063
6064  context1->Exit();
6065  context0->Exit();
6066  context1.Dispose();
6067  context0.Dispose();
6068}
6069
6070
6071static int named_access_count = 0;
6072static int indexed_access_count = 0;
6073
6074static bool NamedAccessCounter(Local<v8::Object> global,
6075                               Local<Value> name,
6076                               v8::AccessType type,
6077                               Local<Value> data) {
6078  named_access_count++;
6079  return true;
6080}
6081
6082
6083static bool IndexedAccessCounter(Local<v8::Object> global,
6084                                 uint32_t key,
6085                                 v8::AccessType type,
6086                                 Local<Value> data) {
6087  indexed_access_count++;
6088  return true;
6089}
6090
6091
6092// This one is too easily disturbed by other tests.
6093TEST(AccessControlIC) {
6094  named_access_count = 0;
6095  indexed_access_count = 0;
6096
6097  v8::HandleScope handle_scope;
6098
6099  // Create an environment.
6100  v8::Persistent<Context> context0 = Context::New();
6101  context0->Enter();
6102
6103  // Create an object that requires access-check functions to be
6104  // called for cross-domain access.
6105  v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
6106  object_template->SetAccessCheckCallbacks(NamedAccessCounter,
6107                                           IndexedAccessCounter);
6108  Local<v8::Object> object = object_template->NewInstance();
6109
6110  v8::HandleScope scope1;
6111
6112  // Create another environment.
6113  v8::Persistent<Context> context1 = Context::New();
6114  context1->Enter();
6115
6116  // Make easy access to the object from the other environment.
6117  v8::Handle<v8::Object> global1 = context1->Global();
6118  global1->Set(v8_str("obj"), object);
6119
6120  v8::Handle<Value> value;
6121
6122  // Check that the named access-control function is called every time.
6123  CompileRun("function testProp(obj) {"
6124             "  for (var i = 0; i < 10; i++) obj.prop = 1;"
6125             "  for (var j = 0; j < 10; j++) obj.prop;"
6126             "  return obj.prop"
6127             "}");
6128  value = CompileRun("testProp(obj)");
6129  CHECK(value->IsNumber());
6130  CHECK_EQ(1, value->Int32Value());
6131  CHECK_EQ(21, named_access_count);
6132
6133  // Check that the named access-control function is called every time.
6134  CompileRun("var p = 'prop';"
6135             "function testKeyed(obj) {"
6136             "  for (var i = 0; i < 10; i++) obj[p] = 1;"
6137             "  for (var j = 0; j < 10; j++) obj[p];"
6138             "  return obj[p];"
6139             "}");
6140  // Use obj which requires access checks.  No inline caching is used
6141  // in that case.
6142  value = CompileRun("testKeyed(obj)");
6143  CHECK(value->IsNumber());
6144  CHECK_EQ(1, value->Int32Value());
6145  CHECK_EQ(42, named_access_count);
6146  // Force the inline caches into generic state and try again.
6147  CompileRun("testKeyed({ a: 0 })");
6148  CompileRun("testKeyed({ b: 0 })");
6149  value = CompileRun("testKeyed(obj)");
6150  CHECK(value->IsNumber());
6151  CHECK_EQ(1, value->Int32Value());
6152  CHECK_EQ(63, named_access_count);
6153
6154  // Check that the indexed access-control function is called every time.
6155  CompileRun("function testIndexed(obj) {"
6156             "  for (var i = 0; i < 10; i++) obj[0] = 1;"
6157             "  for (var j = 0; j < 10; j++) obj[0];"
6158             "  return obj[0]"
6159             "}");
6160  value = CompileRun("testIndexed(obj)");
6161  CHECK(value->IsNumber());
6162  CHECK_EQ(1, value->Int32Value());
6163  CHECK_EQ(21, indexed_access_count);
6164  // Force the inline caches into generic state.
6165  CompileRun("testIndexed(new Array(1))");
6166  // Test that the indexed access check is called.
6167  value = CompileRun("testIndexed(obj)");
6168  CHECK(value->IsNumber());
6169  CHECK_EQ(1, value->Int32Value());
6170  CHECK_EQ(42, indexed_access_count);
6171
6172  // Check that the named access check is called when invoking
6173  // functions on an object that requires access checks.
6174  CompileRun("obj.f = function() {}");
6175  CompileRun("function testCallNormal(obj) {"
6176             "  for (var i = 0; i < 10; i++) obj.f();"
6177             "}");
6178  CompileRun("testCallNormal(obj)");
6179  CHECK_EQ(74, named_access_count);
6180
6181  // Force obj into slow case.
6182  value = CompileRun("delete obj.prop");
6183  CHECK(value->BooleanValue());
6184  // Force inline caches into dictionary probing mode.
6185  CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
6186  // Test that the named access check is called.
6187  value = CompileRun("testProp(obj);");
6188  CHECK(value->IsNumber());
6189  CHECK_EQ(1, value->Int32Value());
6190  CHECK_EQ(96, named_access_count);
6191
6192  // Force the call inline cache into dictionary probing mode.
6193  CompileRun("o.f = function() {}; testCallNormal(o)");
6194  // Test that the named access check is still called for each
6195  // invocation of the function.
6196  value = CompileRun("testCallNormal(obj)");
6197  CHECK_EQ(106, named_access_count);
6198
6199  context1->Exit();
6200  context0->Exit();
6201  context1.Dispose();
6202  context0.Dispose();
6203}
6204
6205
6206static bool NamedAccessFlatten(Local<v8::Object> global,
6207                               Local<Value> name,
6208                               v8::AccessType type,
6209                               Local<Value> data) {
6210  char buf[100];
6211  int len;
6212
6213  CHECK(name->IsString());
6214
6215  memset(buf, 0x1, sizeof(buf));
6216  len = name.As<String>()->WriteAscii(buf);
6217  CHECK_EQ(4, len);
6218
6219  uint16_t buf2[100];
6220
6221  memset(buf, 0x1, sizeof(buf));
6222  len = name.As<String>()->Write(buf2);
6223  CHECK_EQ(4, len);
6224
6225  return true;
6226}
6227
6228
6229static bool IndexedAccessFlatten(Local<v8::Object> global,
6230                                 uint32_t key,
6231                                 v8::AccessType type,
6232                                 Local<Value> data) {
6233  return true;
6234}
6235
6236
6237// Regression test.  In access checks, operations that may cause
6238// garbage collection are not allowed.  It used to be the case that
6239// using the Write operation on a string could cause a garbage
6240// collection due to flattening of the string.  This is no longer the
6241// case.
6242THREADED_TEST(AccessControlFlatten) {
6243  named_access_count = 0;
6244  indexed_access_count = 0;
6245
6246  v8::HandleScope handle_scope;
6247
6248  // Create an environment.
6249  v8::Persistent<Context> context0 = Context::New();
6250  context0->Enter();
6251
6252  // Create an object that requires access-check functions to be
6253  // called for cross-domain access.
6254  v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
6255  object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
6256                                           IndexedAccessFlatten);
6257  Local<v8::Object> object = object_template->NewInstance();
6258
6259  v8::HandleScope scope1;
6260
6261  // Create another environment.
6262  v8::Persistent<Context> context1 = Context::New();
6263  context1->Enter();
6264
6265  // Make easy access to the object from the other environment.
6266  v8::Handle<v8::Object> global1 = context1->Global();
6267  global1->Set(v8_str("obj"), object);
6268
6269  v8::Handle<Value> value;
6270
6271  value = v8_compile("var p = 'as' + 'df';")->Run();
6272  value = v8_compile("obj[p];")->Run();
6273
6274  context1->Exit();
6275  context0->Exit();
6276  context1.Dispose();
6277  context0.Dispose();
6278}
6279
6280
6281static v8::Handle<Value> AccessControlNamedGetter(
6282    Local<String>, const AccessorInfo&) {
6283  return v8::Integer::New(42);
6284}
6285
6286
6287static v8::Handle<Value> AccessControlNamedSetter(
6288    Local<String>, Local<Value> value, const AccessorInfo&) {
6289  return value;
6290}
6291
6292
6293static v8::Handle<Value> AccessControlIndexedGetter(
6294      uint32_t index,
6295      const AccessorInfo& info) {
6296  return v8_num(42);
6297}
6298
6299
6300static v8::Handle<Value> AccessControlIndexedSetter(
6301    uint32_t, Local<Value> value, const AccessorInfo&) {
6302  return value;
6303}
6304
6305
6306THREADED_TEST(AccessControlInterceptorIC) {
6307  named_access_count = 0;
6308  indexed_access_count = 0;
6309
6310  v8::HandleScope handle_scope;
6311
6312  // Create an environment.
6313  v8::Persistent<Context> context0 = Context::New();
6314  context0->Enter();
6315
6316  // Create an object that requires access-check functions to be
6317  // called for cross-domain access.  The object also has interceptors
6318  // interceptor.
6319  v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
6320  object_template->SetAccessCheckCallbacks(NamedAccessCounter,
6321                                           IndexedAccessCounter);
6322  object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
6323                                           AccessControlNamedSetter);
6324  object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
6325                                             AccessControlIndexedSetter);
6326  Local<v8::Object> object = object_template->NewInstance();
6327
6328  v8::HandleScope scope1;
6329
6330  // Create another environment.
6331  v8::Persistent<Context> context1 = Context::New();
6332  context1->Enter();
6333
6334  // Make easy access to the object from the other environment.
6335  v8::Handle<v8::Object> global1 = context1->Global();
6336  global1->Set(v8_str("obj"), object);
6337
6338  v8::Handle<Value> value;
6339
6340  // Check that the named access-control function is called every time
6341  // eventhough there is an interceptor on the object.
6342  value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
6343  value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
6344                     "obj.x")->Run();
6345  CHECK(value->IsNumber());
6346  CHECK_EQ(42, value->Int32Value());
6347  CHECK_EQ(21, named_access_count);
6348
6349  value = v8_compile("var p = 'x';")->Run();
6350  value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
6351  value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
6352                     "obj[p]")->Run();
6353  CHECK(value->IsNumber());
6354  CHECK_EQ(42, value->Int32Value());
6355  CHECK_EQ(42, named_access_count);
6356
6357  // Check that the indexed access-control function is called every
6358  // time eventhough there is an interceptor on the object.
6359  value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
6360  value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
6361                     "obj[0]")->Run();
6362  CHECK(value->IsNumber());
6363  CHECK_EQ(42, value->Int32Value());
6364  CHECK_EQ(21, indexed_access_count);
6365
6366  context1->Exit();
6367  context0->Exit();
6368  context1.Dispose();
6369  context0.Dispose();
6370}
6371
6372
6373THREADED_TEST(Version) {
6374  v8::V8::GetVersion();
6375}
6376
6377
6378static v8::Handle<Value> InstanceFunctionCallback(const v8::Arguments& args) {
6379  ApiTestFuzzer::Fuzz();
6380  return v8_num(12);
6381}
6382
6383
6384THREADED_TEST(InstanceProperties) {
6385  v8::HandleScope handle_scope;
6386  LocalContext context;
6387
6388  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6389  Local<ObjectTemplate> instance = t->InstanceTemplate();
6390
6391  instance->Set(v8_str("x"), v8_num(42));
6392  instance->Set(v8_str("f"),
6393                v8::FunctionTemplate::New(InstanceFunctionCallback));
6394
6395  Local<Value> o = t->GetFunction()->NewInstance();
6396
6397  context->Global()->Set(v8_str("i"), o);
6398  Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
6399  CHECK_EQ(42, value->Int32Value());
6400
6401  value = Script::Compile(v8_str("i.f()"))->Run();
6402  CHECK_EQ(12, value->Int32Value());
6403}
6404
6405
6406static v8::Handle<Value>
6407GlobalObjectInstancePropertiesGet(Local<String> key, const AccessorInfo&) {
6408  ApiTestFuzzer::Fuzz();
6409  return v8::Handle<Value>();
6410}
6411
6412
6413THREADED_TEST(GlobalObjectInstanceProperties) {
6414  v8::HandleScope handle_scope;
6415
6416  Local<Value> global_object;
6417
6418  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6419  t->InstanceTemplate()->SetNamedPropertyHandler(
6420      GlobalObjectInstancePropertiesGet);
6421  Local<ObjectTemplate> instance_template = t->InstanceTemplate();
6422  instance_template->Set(v8_str("x"), v8_num(42));
6423  instance_template->Set(v8_str("f"),
6424                         v8::FunctionTemplate::New(InstanceFunctionCallback));
6425
6426  // The script to check how Crankshaft compiles missing global function
6427  // invocations.  function g is not defined and should throw on call.
6428  const char* script =
6429      "function wrapper(call) {"
6430      "  var x = 0, y = 1;"
6431      "  for (var i = 0; i < 1000; i++) {"
6432      "    x += i * 100;"
6433      "    y += i * 100;"
6434      "  }"
6435      "  if (call) g();"
6436      "}"
6437      "for (var i = 0; i < 17; i++) wrapper(false);"
6438      "var thrown = 0;"
6439      "try { wrapper(true); } catch (e) { thrown = 1; };"
6440      "thrown";
6441
6442  {
6443    LocalContext env(NULL, instance_template);
6444    // Hold on to the global object so it can be used again in another
6445    // environment initialization.
6446    global_object = env->Global();
6447
6448    Local<Value> value = Script::Compile(v8_str("x"))->Run();
6449    CHECK_EQ(42, value->Int32Value());
6450    value = Script::Compile(v8_str("f()"))->Run();
6451    CHECK_EQ(12, value->Int32Value());
6452    value = Script::Compile(v8_str(script))->Run();
6453    CHECK_EQ(1, value->Int32Value());
6454  }
6455
6456  {
6457    // Create new environment reusing the global object.
6458    LocalContext env(NULL, instance_template, global_object);
6459    Local<Value> value = Script::Compile(v8_str("x"))->Run();
6460    CHECK_EQ(42, value->Int32Value());
6461    value = Script::Compile(v8_str("f()"))->Run();
6462    CHECK_EQ(12, value->Int32Value());
6463    value = Script::Compile(v8_str(script))->Run();
6464    CHECK_EQ(1, value->Int32Value());
6465  }
6466}
6467
6468
6469THREADED_TEST(CallKnownGlobalReceiver) {
6470  v8::HandleScope handle_scope;
6471
6472  Local<Value> global_object;
6473
6474  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6475  Local<ObjectTemplate> instance_template = t->InstanceTemplate();
6476
6477  // The script to check that we leave global object not
6478  // global object proxy on stack when we deoptimize from inside
6479  // arguments evaluation.
6480  // To provoke error we need to both force deoptimization
6481  // from arguments evaluation and to force CallIC to take
6482  // CallIC_Miss code path that can't cope with global proxy.
6483  const char* script =
6484      "function bar(x, y) { try { } finally { } }"
6485      "function baz(x) { try { } finally { } }"
6486      "function bom(x) { try { } finally { } }"
6487      "function foo(x) { bar([x], bom(2)); }"
6488      "for (var i = 0; i < 10000; i++) foo(1);"
6489      "foo";
6490
6491  Local<Value> foo;
6492  {
6493    LocalContext env(NULL, instance_template);
6494    // Hold on to the global object so it can be used again in another
6495    // environment initialization.
6496    global_object = env->Global();
6497    foo = Script::Compile(v8_str(script))->Run();
6498  }
6499
6500  {
6501    // Create new environment reusing the global object.
6502    LocalContext env(NULL, instance_template, global_object);
6503    env->Global()->Set(v8_str("foo"), foo);
6504    Local<Value> value = Script::Compile(v8_str("foo()"))->Run();
6505  }
6506}
6507
6508
6509static v8::Handle<Value> ShadowFunctionCallback(const v8::Arguments& args) {
6510  ApiTestFuzzer::Fuzz();
6511  return v8_num(42);
6512}
6513
6514
6515static int shadow_y;
6516static int shadow_y_setter_call_count;
6517static int shadow_y_getter_call_count;
6518
6519
6520static void ShadowYSetter(Local<String>, Local<Value>, const AccessorInfo&) {
6521  shadow_y_setter_call_count++;
6522  shadow_y = 42;
6523}
6524
6525
6526static v8::Handle<Value> ShadowYGetter(Local<String> name,
6527                                       const AccessorInfo& info) {
6528  ApiTestFuzzer::Fuzz();
6529  shadow_y_getter_call_count++;
6530  return v8_num(shadow_y);
6531}
6532
6533
6534static v8::Handle<Value> ShadowIndexedGet(uint32_t index,
6535                                          const AccessorInfo& info) {
6536  return v8::Handle<Value>();
6537}
6538
6539
6540static v8::Handle<Value> ShadowNamedGet(Local<String> key,
6541                                        const AccessorInfo&) {
6542  return v8::Handle<Value>();
6543}
6544
6545
6546THREADED_TEST(ShadowObject) {
6547  shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
6548  v8::HandleScope handle_scope;
6549
6550  Local<ObjectTemplate> global_template = v8::ObjectTemplate::New();
6551  LocalContext context(NULL, global_template);
6552
6553  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6554  t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
6555  t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
6556  Local<ObjectTemplate> proto = t->PrototypeTemplate();
6557  Local<ObjectTemplate> instance = t->InstanceTemplate();
6558
6559  // Only allow calls of f on instances of t.
6560  Local<v8::Signature> signature = v8::Signature::New(t);
6561  proto->Set(v8_str("f"),
6562             v8::FunctionTemplate::New(ShadowFunctionCallback,
6563                                       Local<Value>(),
6564                                       signature));
6565  proto->Set(v8_str("x"), v8_num(12));
6566
6567  instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
6568
6569  Local<Value> o = t->GetFunction()->NewInstance();
6570  context->Global()->Set(v8_str("__proto__"), o);
6571
6572  Local<Value> value =
6573      Script::Compile(v8_str("propertyIsEnumerable(0)"))->Run();
6574  CHECK(value->IsBoolean());
6575  CHECK(!value->BooleanValue());
6576
6577  value = Script::Compile(v8_str("x"))->Run();
6578  CHECK_EQ(12, value->Int32Value());
6579
6580  value = Script::Compile(v8_str("f()"))->Run();
6581  CHECK_EQ(42, value->Int32Value());
6582
6583  Script::Compile(v8_str("y = 42"))->Run();
6584  CHECK_EQ(1, shadow_y_setter_call_count);
6585  value = Script::Compile(v8_str("y"))->Run();
6586  CHECK_EQ(1, shadow_y_getter_call_count);
6587  CHECK_EQ(42, value->Int32Value());
6588}
6589
6590
6591THREADED_TEST(HiddenPrototype) {
6592  v8::HandleScope handle_scope;
6593  LocalContext context;
6594
6595  Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
6596  t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
6597  Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
6598  t1->SetHiddenPrototype(true);
6599  t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
6600  Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
6601  t2->SetHiddenPrototype(true);
6602  t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
6603  Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
6604  t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
6605
6606  Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
6607  Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
6608  Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
6609  Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
6610
6611  // Setting the prototype on an object skips hidden prototypes.
6612  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6613  o0->Set(v8_str("__proto__"), o1);
6614  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6615  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6616  o0->Set(v8_str("__proto__"), o2);
6617  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6618  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6619  CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
6620  o0->Set(v8_str("__proto__"), o3);
6621  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6622  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6623  CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
6624  CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
6625
6626  // Getting the prototype of o0 should get the first visible one
6627  // which is o3.  Therefore, z should not be defined on the prototype
6628  // object.
6629  Local<Value> proto = o0->Get(v8_str("__proto__"));
6630  CHECK(proto->IsObject());
6631  CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
6632}
6633
6634
6635THREADED_TEST(SetPrototype) {
6636  v8::HandleScope handle_scope;
6637  LocalContext context;
6638
6639  Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
6640  t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
6641  Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
6642  t1->SetHiddenPrototype(true);
6643  t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
6644  Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
6645  t2->SetHiddenPrototype(true);
6646  t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
6647  Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
6648  t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
6649
6650  Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
6651  Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
6652  Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
6653  Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
6654
6655  // Setting the prototype on an object does not skip hidden prototypes.
6656  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6657  CHECK(o0->SetPrototype(o1));
6658  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6659  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6660  CHECK(o1->SetPrototype(o2));
6661  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6662  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6663  CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
6664  CHECK(o2->SetPrototype(o3));
6665  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6666  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6667  CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
6668  CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
6669
6670  // Getting the prototype of o0 should get the first visible one
6671  // which is o3.  Therefore, z should not be defined on the prototype
6672  // object.
6673  Local<Value> proto = o0->Get(v8_str("__proto__"));
6674  CHECK(proto->IsObject());
6675  CHECK_EQ(proto.As<v8::Object>(), o3);
6676
6677  // However, Object::GetPrototype ignores hidden prototype.
6678  Local<Value> proto0 = o0->GetPrototype();
6679  CHECK(proto0->IsObject());
6680  CHECK_EQ(proto0.As<v8::Object>(), o1);
6681
6682  Local<Value> proto1 = o1->GetPrototype();
6683  CHECK(proto1->IsObject());
6684  CHECK_EQ(proto1.As<v8::Object>(), o2);
6685
6686  Local<Value> proto2 = o2->GetPrototype();
6687  CHECK(proto2->IsObject());
6688  CHECK_EQ(proto2.As<v8::Object>(), o3);
6689}
6690
6691
6692THREADED_TEST(SetPrototypeThrows) {
6693  v8::HandleScope handle_scope;
6694  LocalContext context;
6695
6696  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6697
6698  Local<v8::Object> o0 = t->GetFunction()->NewInstance();
6699  Local<v8::Object> o1 = t->GetFunction()->NewInstance();
6700
6701  CHECK(o0->SetPrototype(o1));
6702  // If setting the prototype leads to the cycle, SetPrototype should
6703  // return false and keep VM in sane state.
6704  v8::TryCatch try_catch;
6705  CHECK(!o1->SetPrototype(o0));
6706  CHECK(!try_catch.HasCaught());
6707  ASSERT(!i::Isolate::Current()->has_pending_exception());
6708
6709  CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
6710}
6711
6712
6713THREADED_TEST(GetterSetterExceptions) {
6714  v8::HandleScope handle_scope;
6715  LocalContext context;
6716  CompileRun(
6717    "function Foo() { };"
6718    "function Throw() { throw 5; };"
6719    "var x = { };"
6720    "x.__defineSetter__('set', Throw);"
6721    "x.__defineGetter__('get', Throw);");
6722  Local<v8::Object> x =
6723      Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
6724  v8::TryCatch try_catch;
6725  x->Set(v8_str("set"), v8::Integer::New(8));
6726  x->Get(v8_str("get"));
6727  x->Set(v8_str("set"), v8::Integer::New(8));
6728  x->Get(v8_str("get"));
6729  x->Set(v8_str("set"), v8::Integer::New(8));
6730  x->Get(v8_str("get"));
6731  x->Set(v8_str("set"), v8::Integer::New(8));
6732  x->Get(v8_str("get"));
6733}
6734
6735
6736THREADED_TEST(Constructor) {
6737  v8::HandleScope handle_scope;
6738  LocalContext context;
6739  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
6740  templ->SetClassName(v8_str("Fun"));
6741  Local<Function> cons = templ->GetFunction();
6742  context->Global()->Set(v8_str("Fun"), cons);
6743  Local<v8::Object> inst = cons->NewInstance();
6744  i::Handle<i::JSObject> obj = v8::Utils::OpenHandle(*inst);
6745  Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
6746  CHECK(value->BooleanValue());
6747}
6748
6749THREADED_TEST(FunctionDescriptorException) {
6750  v8::HandleScope handle_scope;
6751  LocalContext context;
6752  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
6753  templ->SetClassName(v8_str("Fun"));
6754  Local<Function> cons = templ->GetFunction();
6755  context->Global()->Set(v8_str("Fun"), cons);
6756  Local<Value> value = CompileRun(
6757    "function test() {"
6758    "  try {"
6759    "    (new Fun()).blah()"
6760    "  } catch (e) {"
6761    "    var str = String(e);"
6762    "    if (str.indexOf('TypeError') == -1) return 1;"
6763    "    if (str.indexOf('[object Fun]') != -1) return 2;"
6764    "    if (str.indexOf('#<Fun>') == -1) return 3;"
6765    "    return 0;"
6766    "  }"
6767    "  return 4;"
6768    "}"
6769    "test();");
6770  CHECK_EQ(0, value->Int32Value());
6771}
6772
6773
6774THREADED_TEST(EvalAliasedDynamic) {
6775  v8::HandleScope scope;
6776  LocalContext current;
6777
6778  // Tests where aliased eval can only be resolved dynamically.
6779  Local<Script> script =
6780      Script::Compile(v8_str("function f(x) { "
6781                             "  var foo = 2;"
6782                             "  with (x) { return eval('foo'); }"
6783                             "}"
6784                             "foo = 0;"
6785                             "result1 = f(new Object());"
6786                             "result2 = f(this);"
6787                             "var x = new Object();"
6788                             "x.eval = function(x) { return 1; };"
6789                             "result3 = f(x);"));
6790  script->Run();
6791  CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
6792  CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
6793  CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
6794
6795  v8::TryCatch try_catch;
6796  script =
6797    Script::Compile(v8_str("function f(x) { "
6798                           "  var bar = 2;"
6799                           "  with (x) { return eval('bar'); }"
6800                           "}"
6801                           "f(this)"));
6802  script->Run();
6803  CHECK(try_catch.HasCaught());
6804  try_catch.Reset();
6805}
6806
6807
6808THREADED_TEST(CrossEval) {
6809  v8::HandleScope scope;
6810  LocalContext other;
6811  LocalContext current;
6812
6813  Local<String> token = v8_str("<security token>");
6814  other->SetSecurityToken(token);
6815  current->SetSecurityToken(token);
6816
6817  // Setup reference from current to other.
6818  current->Global()->Set(v8_str("other"), other->Global());
6819
6820  // Check that new variables are introduced in other context.
6821  Local<Script> script =
6822      Script::Compile(v8_str("other.eval('var foo = 1234')"));
6823  script->Run();
6824  Local<Value> foo = other->Global()->Get(v8_str("foo"));
6825  CHECK_EQ(1234, foo->Int32Value());
6826  CHECK(!current->Global()->Has(v8_str("foo")));
6827
6828  // Check that writing to non-existing properties introduces them in
6829  // the other context.
6830  script =
6831      Script::Compile(v8_str("other.eval('na = 1234')"));
6832  script->Run();
6833  CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
6834  CHECK(!current->Global()->Has(v8_str("na")));
6835
6836  // Check that global variables in current context are not visible in other
6837  // context.
6838  v8::TryCatch try_catch;
6839  script =
6840      Script::Compile(v8_str("var bar = 42; other.eval('bar');"));
6841  Local<Value> result = script->Run();
6842  CHECK(try_catch.HasCaught());
6843  try_catch.Reset();
6844
6845  // Check that local variables in current context are not visible in other
6846  // context.
6847  script =
6848      Script::Compile(v8_str("(function() { "
6849                             "  var baz = 87;"
6850                             "  return other.eval('baz');"
6851                             "})();"));
6852  result = script->Run();
6853  CHECK(try_catch.HasCaught());
6854  try_catch.Reset();
6855
6856  // Check that global variables in the other environment are visible
6857  // when evaluting code.
6858  other->Global()->Set(v8_str("bis"), v8_num(1234));
6859  script = Script::Compile(v8_str("other.eval('bis')"));
6860  CHECK_EQ(1234, script->Run()->Int32Value());
6861  CHECK(!try_catch.HasCaught());
6862
6863  // Check that the 'this' pointer points to the global object evaluating
6864  // code.
6865  other->Global()->Set(v8_str("t"), other->Global());
6866  script = Script::Compile(v8_str("other.eval('this == t')"));
6867  result = script->Run();
6868  CHECK(result->IsTrue());
6869  CHECK(!try_catch.HasCaught());
6870
6871  // Check that variables introduced in with-statement are not visible in
6872  // other context.
6873  script =
6874      Script::Compile(v8_str("with({x:2}){other.eval('x')}"));
6875  result = script->Run();
6876  CHECK(try_catch.HasCaught());
6877  try_catch.Reset();
6878
6879  // Check that you cannot use 'eval.call' with another object than the
6880  // current global object.
6881  script =
6882      Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')"));
6883  result = script->Run();
6884  CHECK(try_catch.HasCaught());
6885}
6886
6887
6888// Test that calling eval in a context which has been detached from
6889// its global throws an exception.  This behavior is consistent with
6890// other JavaScript implementations.
6891THREADED_TEST(EvalInDetachedGlobal) {
6892  v8::HandleScope scope;
6893
6894  v8::Persistent<Context> context0 = Context::New();
6895  v8::Persistent<Context> context1 = Context::New();
6896
6897  // Setup function in context0 that uses eval from context0.
6898  context0->Enter();
6899  v8::Handle<v8::Value> fun =
6900      CompileRun("var x = 42;"
6901                 "(function() {"
6902                 "  var e = eval;"
6903                 "  return function(s) { return e(s); }"
6904                 "})()");
6905  context0->Exit();
6906
6907  // Put the function into context1 and call it before and after
6908  // detaching the global.  Before detaching, the call succeeds and
6909  // after detaching and exception is thrown.
6910  context1->Enter();
6911  context1->Global()->Set(v8_str("fun"), fun);
6912  v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
6913  CHECK_EQ(42, x_value->Int32Value());
6914  context0->DetachGlobal();
6915  v8::TryCatch catcher;
6916  x_value = CompileRun("fun('x')");
6917  CHECK(x_value.IsEmpty());
6918  CHECK(catcher.HasCaught());
6919  context1->Exit();
6920
6921  context1.Dispose();
6922  context0.Dispose();
6923}
6924
6925
6926THREADED_TEST(CrossLazyLoad) {
6927  v8::HandleScope scope;
6928  LocalContext other;
6929  LocalContext current;
6930
6931  Local<String> token = v8_str("<security token>");
6932  other->SetSecurityToken(token);
6933  current->SetSecurityToken(token);
6934
6935  // Setup reference from current to other.
6936  current->Global()->Set(v8_str("other"), other->Global());
6937
6938  // Trigger lazy loading in other context.
6939  Local<Script> script =
6940      Script::Compile(v8_str("other.eval('new Date(42)')"));
6941  Local<Value> value = script->Run();
6942  CHECK_EQ(42.0, value->NumberValue());
6943}
6944
6945
6946static v8::Handle<Value> call_as_function(const v8::Arguments& args) {
6947  ApiTestFuzzer::Fuzz();
6948  if (args.IsConstructCall()) {
6949    if (args[0]->IsInt32()) {
6950       return v8_num(-args[0]->Int32Value());
6951    }
6952  }
6953
6954  return args[0];
6955}
6956
6957
6958// Test that a call handler can be set for objects which will allow
6959// non-function objects created through the API to be called as
6960// functions.
6961THREADED_TEST(CallAsFunction) {
6962  v8::HandleScope scope;
6963  LocalContext context;
6964
6965  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6966  Local<ObjectTemplate> instance_template = t->InstanceTemplate();
6967  instance_template->SetCallAsFunctionHandler(call_as_function);
6968  Local<v8::Object> instance = t->GetFunction()->NewInstance();
6969  context->Global()->Set(v8_str("obj"), instance);
6970  v8::TryCatch try_catch;
6971  Local<Value> value;
6972  CHECK(!try_catch.HasCaught());
6973
6974  value = CompileRun("obj(42)");
6975  CHECK(!try_catch.HasCaught());
6976  CHECK_EQ(42, value->Int32Value());
6977
6978  value = CompileRun("(function(o){return o(49)})(obj)");
6979  CHECK(!try_catch.HasCaught());
6980  CHECK_EQ(49, value->Int32Value());
6981
6982  // test special case of call as function
6983  value = CompileRun("[obj]['0'](45)");
6984  CHECK(!try_catch.HasCaught());
6985  CHECK_EQ(45, value->Int32Value());
6986
6987  value = CompileRun("obj.call = Function.prototype.call;"
6988                     "obj.call(null, 87)");
6989  CHECK(!try_catch.HasCaught());
6990  CHECK_EQ(87, value->Int32Value());
6991
6992  // Regression tests for bug #1116356: Calling call through call/apply
6993  // must work for non-function receivers.
6994  const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
6995  value = CompileRun(apply_99);
6996  CHECK(!try_catch.HasCaught());
6997  CHECK_EQ(99, value->Int32Value());
6998
6999  const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
7000  value = CompileRun(call_17);
7001  CHECK(!try_catch.HasCaught());
7002  CHECK_EQ(17, value->Int32Value());
7003
7004  // Check that the call-as-function handler can be called through
7005  // new.
7006  value = CompileRun("new obj(43)");
7007  CHECK(!try_catch.HasCaught());
7008  CHECK_EQ(-43, value->Int32Value());
7009}
7010
7011
7012static int CountHandles() {
7013  return v8::HandleScope::NumberOfHandles();
7014}
7015
7016
7017static int Recurse(int depth, int iterations) {
7018  v8::HandleScope scope;
7019  if (depth == 0) return CountHandles();
7020  for (int i = 0; i < iterations; i++) {
7021    Local<v8::Number> n = v8::Integer::New(42);
7022  }
7023  return Recurse(depth - 1, iterations);
7024}
7025
7026
7027THREADED_TEST(HandleIteration) {
7028  static const int kIterations = 500;
7029  static const int kNesting = 200;
7030  CHECK_EQ(0, CountHandles());
7031  {
7032    v8::HandleScope scope1;
7033    CHECK_EQ(0, CountHandles());
7034    for (int i = 0; i < kIterations; i++) {
7035      Local<v8::Number> n = v8::Integer::New(42);
7036      CHECK_EQ(i + 1, CountHandles());
7037    }
7038
7039    CHECK_EQ(kIterations, CountHandles());
7040    {
7041      v8::HandleScope scope2;
7042      for (int j = 0; j < kIterations; j++) {
7043        Local<v8::Number> n = v8::Integer::New(42);
7044        CHECK_EQ(j + 1 + kIterations, CountHandles());
7045      }
7046    }
7047    CHECK_EQ(kIterations, CountHandles());
7048  }
7049  CHECK_EQ(0, CountHandles());
7050  CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations));
7051}
7052
7053
7054static v8::Handle<Value> InterceptorHasOwnPropertyGetter(
7055    Local<String> name,
7056    const AccessorInfo& info) {
7057  ApiTestFuzzer::Fuzz();
7058  return v8::Handle<Value>();
7059}
7060
7061
7062THREADED_TEST(InterceptorHasOwnProperty) {
7063  v8::HandleScope scope;
7064  LocalContext context;
7065  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7066  Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
7067  instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
7068  Local<Function> function = fun_templ->GetFunction();
7069  context->Global()->Set(v8_str("constructor"), function);
7070  v8::Handle<Value> value = CompileRun(
7071      "var o = new constructor();"
7072      "o.hasOwnProperty('ostehaps');");
7073  CHECK_EQ(false, value->BooleanValue());
7074  value = CompileRun(
7075      "o.ostehaps = 42;"
7076      "o.hasOwnProperty('ostehaps');");
7077  CHECK_EQ(true, value->BooleanValue());
7078  value = CompileRun(
7079      "var p = new constructor();"
7080      "p.hasOwnProperty('ostehaps');");
7081  CHECK_EQ(false, value->BooleanValue());
7082}
7083
7084
7085static v8::Handle<Value> InterceptorHasOwnPropertyGetterGC(
7086    Local<String> name,
7087    const AccessorInfo& info) {
7088  ApiTestFuzzer::Fuzz();
7089  HEAP->CollectAllGarbage(false);
7090  return v8::Handle<Value>();
7091}
7092
7093
7094THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
7095  v8::HandleScope scope;
7096  LocalContext context;
7097  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7098  Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
7099  instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
7100  Local<Function> function = fun_templ->GetFunction();
7101  context->Global()->Set(v8_str("constructor"), function);
7102  // Let's first make some stuff so we can be sure to get a good GC.
7103  CompileRun(
7104      "function makestr(size) {"
7105      "  switch (size) {"
7106      "    case 1: return 'f';"
7107      "    case 2: return 'fo';"
7108      "    case 3: return 'foo';"
7109      "  }"
7110      "  return makestr(size >> 1) + makestr((size + 1) >> 1);"
7111      "}"
7112      "var x = makestr(12345);"
7113      "x = makestr(31415);"
7114      "x = makestr(23456);");
7115  v8::Handle<Value> value = CompileRun(
7116      "var o = new constructor();"
7117      "o.__proto__ = new String(x);"
7118      "o.hasOwnProperty('ostehaps');");
7119  CHECK_EQ(false, value->BooleanValue());
7120}
7121
7122
7123typedef v8::Handle<Value> (*NamedPropertyGetter)(Local<String> property,
7124                                                 const AccessorInfo& info);
7125
7126
7127static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
7128                                   const char* source,
7129                                   int expected) {
7130  v8::HandleScope scope;
7131  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7132  templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
7133  LocalContext context;
7134  context->Global()->Set(v8_str("o"), templ->NewInstance());
7135  v8::Handle<Value> value = CompileRun(source);
7136  CHECK_EQ(expected, value->Int32Value());
7137}
7138
7139
7140static v8::Handle<Value> InterceptorLoadICGetter(Local<String> name,
7141                                                 const AccessorInfo& info) {
7142  ApiTestFuzzer::Fuzz();
7143  CHECK_EQ(v8_str("data"), info.Data());
7144  CHECK_EQ(v8_str("x"), name);
7145  return v8::Integer::New(42);
7146}
7147
7148
7149// This test should hit the load IC for the interceptor case.
7150THREADED_TEST(InterceptorLoadIC) {
7151  CheckInterceptorLoadIC(InterceptorLoadICGetter,
7152    "var result = 0;"
7153    "for (var i = 0; i < 1000; i++) {"
7154    "  result = o.x;"
7155    "}",
7156    42);
7157}
7158
7159
7160// Below go several tests which verify that JITing for various
7161// configurations of interceptor and explicit fields works fine
7162// (those cases are special cased to get better performance).
7163
7164static v8::Handle<Value> InterceptorLoadXICGetter(Local<String> name,
7165                                                 const AccessorInfo& info) {
7166  ApiTestFuzzer::Fuzz();
7167  return v8_str("x")->Equals(name)
7168      ? v8::Integer::New(42) : v8::Handle<v8::Value>();
7169}
7170
7171
7172THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
7173  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7174    "var result = 0;"
7175    "o.y = 239;"
7176    "for (var i = 0; i < 1000; i++) {"
7177    "  result = o.y;"
7178    "}",
7179    239);
7180}
7181
7182
7183THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
7184  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7185    "var result = 0;"
7186    "o.__proto__ = { 'y': 239 };"
7187    "for (var i = 0; i < 1000; i++) {"
7188    "  result = o.y + o.x;"
7189    "}",
7190    239 + 42);
7191}
7192
7193
7194THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
7195  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7196    "var result = 0;"
7197    "o.__proto__.y = 239;"
7198    "for (var i = 0; i < 1000; i++) {"
7199    "  result = o.y + o.x;"
7200    "}",
7201    239 + 42);
7202}
7203
7204
7205THREADED_TEST(InterceptorLoadICUndefined) {
7206  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7207    "var result = 0;"
7208    "for (var i = 0; i < 1000; i++) {"
7209    "  result = (o.y == undefined) ? 239 : 42;"
7210    "}",
7211    239);
7212}
7213
7214
7215THREADED_TEST(InterceptorLoadICWithOverride) {
7216  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7217    "fst = new Object();  fst.__proto__ = o;"
7218    "snd = new Object();  snd.__proto__ = fst;"
7219    "var result1 = 0;"
7220    "for (var i = 0; i < 1000;  i++) {"
7221    "  result1 = snd.x;"
7222    "}"
7223    "fst.x = 239;"
7224    "var result = 0;"
7225    "for (var i = 0; i < 1000; i++) {"
7226    "  result = snd.x;"
7227    "}"
7228    "result + result1",
7229    239 + 42);
7230}
7231
7232
7233// Test the case when we stored field into
7234// a stub, but interceptor produced value on its own.
7235THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
7236  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7237    "proto = new Object();"
7238    "o.__proto__ = proto;"
7239    "proto.x = 239;"
7240    "for (var i = 0; i < 1000; i++) {"
7241    "  o.x;"
7242    // Now it should be ICed and keep a reference to x defined on proto
7243    "}"
7244    "var result = 0;"
7245    "for (var i = 0; i < 1000; i++) {"
7246    "  result += o.x;"
7247    "}"
7248    "result;",
7249    42 * 1000);
7250}
7251
7252
7253// Test the case when we stored field into
7254// a stub, but it got invalidated later on.
7255THREADED_TEST(InterceptorLoadICInvalidatedField) {
7256  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7257    "proto1 = new Object();"
7258    "proto2 = new Object();"
7259    "o.__proto__ = proto1;"
7260    "proto1.__proto__ = proto2;"
7261    "proto2.y = 239;"
7262    "for (var i = 0; i < 1000; i++) {"
7263    "  o.y;"
7264    // Now it should be ICed and keep a reference to y defined on proto2
7265    "}"
7266    "proto1.y = 42;"
7267    "var result = 0;"
7268    "for (var i = 0; i < 1000; i++) {"
7269    "  result += o.y;"
7270    "}"
7271    "result;",
7272    42 * 1000);
7273}
7274
7275
7276static int interceptor_load_not_handled_calls = 0;
7277static v8::Handle<Value> InterceptorLoadNotHandled(Local<String> name,
7278                                                   const AccessorInfo& info) {
7279  ++interceptor_load_not_handled_calls;
7280  return v8::Handle<v8::Value>();
7281}
7282
7283
7284// Test how post-interceptor lookups are done in the non-cacheable
7285// case: the interceptor should not be invoked during this lookup.
7286THREADED_TEST(InterceptorLoadICPostInterceptor) {
7287  interceptor_load_not_handled_calls = 0;
7288  CheckInterceptorLoadIC(InterceptorLoadNotHandled,
7289    "receiver = new Object();"
7290    "receiver.__proto__ = o;"
7291    "proto = new Object();"
7292    "/* Make proto a slow-case object. */"
7293    "for (var i = 0; i < 1000; i++) {"
7294    "  proto[\"xxxxxxxx\" + i] = [];"
7295    "}"
7296    "proto.x = 17;"
7297    "o.__proto__ = proto;"
7298    "var result = 0;"
7299    "for (var i = 0; i < 1000; i++) {"
7300    "  result += receiver.x;"
7301    "}"
7302    "result;",
7303    17 * 1000);
7304  CHECK_EQ(1000, interceptor_load_not_handled_calls);
7305}
7306
7307
7308// Test the case when we stored field into
7309// a stub, but it got invalidated later on due to override on
7310// global object which is between interceptor and fields' holders.
7311THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
7312  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7313    "o.__proto__ = this;"  // set a global to be a proto of o.
7314    "this.__proto__.y = 239;"
7315    "for (var i = 0; i < 10; i++) {"
7316    "  if (o.y != 239) throw 'oops: ' + o.y;"
7317    // Now it should be ICed and keep a reference to y defined on field_holder.
7318    "}"
7319    "this.y = 42;"  // Assign on a global.
7320    "var result = 0;"
7321    "for (var i = 0; i < 10; i++) {"
7322    "  result += o.y;"
7323    "}"
7324    "result;",
7325    42 * 10);
7326}
7327
7328
7329static void SetOnThis(Local<String> name,
7330                      Local<Value> value,
7331                      const AccessorInfo& info) {
7332  info.This()->ForceSet(name, value);
7333}
7334
7335
7336THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
7337  v8::HandleScope scope;
7338  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7339  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
7340  templ->SetAccessor(v8_str("y"), Return239);
7341  LocalContext context;
7342  context->Global()->Set(v8_str("o"), templ->NewInstance());
7343
7344  // Check the case when receiver and interceptor's holder
7345  // are the same objects.
7346  v8::Handle<Value> value = CompileRun(
7347      "var result = 0;"
7348      "for (var i = 0; i < 7; i++) {"
7349      "  result = o.y;"
7350      "}");
7351  CHECK_EQ(239, value->Int32Value());
7352
7353  // Check the case when interceptor's holder is in proto chain
7354  // of receiver.
7355  value = CompileRun(
7356      "r = { __proto__: o };"
7357      "var result = 0;"
7358      "for (var i = 0; i < 7; i++) {"
7359      "  result = r.y;"
7360      "}");
7361  CHECK_EQ(239, value->Int32Value());
7362}
7363
7364
7365THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
7366  v8::HandleScope scope;
7367  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7368  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
7369  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
7370  templ_p->SetAccessor(v8_str("y"), Return239);
7371
7372  LocalContext context;
7373  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
7374  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
7375
7376  // Check the case when receiver and interceptor's holder
7377  // are the same objects.
7378  v8::Handle<Value> value = CompileRun(
7379      "o.__proto__ = p;"
7380      "var result = 0;"
7381      "for (var i = 0; i < 7; i++) {"
7382      "  result = o.x + o.y;"
7383      "}");
7384  CHECK_EQ(239 + 42, value->Int32Value());
7385
7386  // Check the case when interceptor's holder is in proto chain
7387  // of receiver.
7388  value = CompileRun(
7389      "r = { __proto__: o };"
7390      "var result = 0;"
7391      "for (var i = 0; i < 7; i++) {"
7392      "  result = r.x + r.y;"
7393      "}");
7394  CHECK_EQ(239 + 42, value->Int32Value());
7395}
7396
7397
7398THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
7399  v8::HandleScope scope;
7400  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7401  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
7402  templ->SetAccessor(v8_str("y"), Return239);
7403
7404  LocalContext context;
7405  context->Global()->Set(v8_str("o"), templ->NewInstance());
7406
7407  v8::Handle<Value> value = CompileRun(
7408    "fst = new Object();  fst.__proto__ = o;"
7409    "snd = new Object();  snd.__proto__ = fst;"
7410    "var result1 = 0;"
7411    "for (var i = 0; i < 7;  i++) {"
7412    "  result1 = snd.x;"
7413    "}"
7414    "fst.x = 239;"
7415    "var result = 0;"
7416    "for (var i = 0; i < 7; i++) {"
7417    "  result = snd.x;"
7418    "}"
7419    "result + result1");
7420  CHECK_EQ(239 + 42, value->Int32Value());
7421}
7422
7423
7424// Test the case when we stored callback into
7425// a stub, but interceptor produced value on its own.
7426THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
7427  v8::HandleScope scope;
7428  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7429  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
7430  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
7431  templ_p->SetAccessor(v8_str("y"), Return239);
7432
7433  LocalContext context;
7434  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
7435  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
7436
7437  v8::Handle<Value> value = CompileRun(
7438    "o.__proto__ = p;"
7439    "for (var i = 0; i < 7; i++) {"
7440    "  o.x;"
7441    // Now it should be ICed and keep a reference to x defined on p
7442    "}"
7443    "var result = 0;"
7444    "for (var i = 0; i < 7; i++) {"
7445    "  result += o.x;"
7446    "}"
7447    "result");
7448  CHECK_EQ(42 * 7, value->Int32Value());
7449}
7450
7451
7452// Test the case when we stored callback into
7453// a stub, but it got invalidated later on.
7454THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
7455  v8::HandleScope scope;
7456  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7457  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
7458  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
7459  templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
7460
7461  LocalContext context;
7462  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
7463  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
7464
7465  v8::Handle<Value> value = CompileRun(
7466    "inbetween = new Object();"
7467    "o.__proto__ = inbetween;"
7468    "inbetween.__proto__ = p;"
7469    "for (var i = 0; i < 10; i++) {"
7470    "  o.y;"
7471    // Now it should be ICed and keep a reference to y defined on p
7472    "}"
7473    "inbetween.y = 42;"
7474    "var result = 0;"
7475    "for (var i = 0; i < 10; i++) {"
7476    "  result += o.y;"
7477    "}"
7478    "result");
7479  CHECK_EQ(42 * 10, value->Int32Value());
7480}
7481
7482
7483// Test the case when we stored callback into
7484// a stub, but it got invalidated later on due to override on
7485// global object which is between interceptor and callbacks' holders.
7486THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
7487  v8::HandleScope scope;
7488  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7489  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
7490  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
7491  templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
7492
7493  LocalContext context;
7494  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
7495  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
7496
7497  v8::Handle<Value> value = CompileRun(
7498    "o.__proto__ = this;"
7499    "this.__proto__ = p;"
7500    "for (var i = 0; i < 10; i++) {"
7501    "  if (o.y != 239) throw 'oops: ' + o.y;"
7502    // Now it should be ICed and keep a reference to y defined on p
7503    "}"
7504    "this.y = 42;"
7505    "var result = 0;"
7506    "for (var i = 0; i < 10; i++) {"
7507    "  result += o.y;"
7508    "}"
7509    "result");
7510  CHECK_EQ(42 * 10, value->Int32Value());
7511}
7512
7513
7514static v8::Handle<Value> InterceptorLoadICGetter0(Local<String> name,
7515                                                  const AccessorInfo& info) {
7516  ApiTestFuzzer::Fuzz();
7517  CHECK(v8_str("x")->Equals(name));
7518  return v8::Integer::New(0);
7519}
7520
7521
7522THREADED_TEST(InterceptorReturningZero) {
7523  CheckInterceptorLoadIC(InterceptorLoadICGetter0,
7524     "o.x == undefined ? 1 : 0",
7525     0);
7526}
7527
7528
7529static v8::Handle<Value> InterceptorStoreICSetter(
7530    Local<String> key, Local<Value> value, const AccessorInfo&) {
7531  CHECK(v8_str("x")->Equals(key));
7532  CHECK_EQ(42, value->Int32Value());
7533  return value;
7534}
7535
7536
7537// This test should hit the store IC for the interceptor case.
7538THREADED_TEST(InterceptorStoreIC) {
7539  v8::HandleScope scope;
7540  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7541  templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
7542                                 InterceptorStoreICSetter,
7543                                 0, 0, 0, v8_str("data"));
7544  LocalContext context;
7545  context->Global()->Set(v8_str("o"), templ->NewInstance());
7546  v8::Handle<Value> value = CompileRun(
7547    "for (var i = 0; i < 1000; i++) {"
7548    "  o.x = 42;"
7549    "}");
7550}
7551
7552
7553THREADED_TEST(InterceptorStoreICWithNoSetter) {
7554  v8::HandleScope scope;
7555  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7556  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
7557  LocalContext context;
7558  context->Global()->Set(v8_str("o"), templ->NewInstance());
7559  v8::Handle<Value> value = CompileRun(
7560    "for (var i = 0; i < 1000; i++) {"
7561    "  o.y = 239;"
7562    "}"
7563    "42 + o.y");
7564  CHECK_EQ(239 + 42, value->Int32Value());
7565}
7566
7567
7568
7569
7570v8::Handle<Value> call_ic_function;
7571v8::Handle<Value> call_ic_function2;
7572v8::Handle<Value> call_ic_function3;
7573
7574static v8::Handle<Value> InterceptorCallICGetter(Local<String> name,
7575                                                 const AccessorInfo& info) {
7576  ApiTestFuzzer::Fuzz();
7577  CHECK(v8_str("x")->Equals(name));
7578  return call_ic_function;
7579}
7580
7581
7582// This test should hit the call IC for the interceptor case.
7583THREADED_TEST(InterceptorCallIC) {
7584  v8::HandleScope scope;
7585  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7586  templ->SetNamedPropertyHandler(InterceptorCallICGetter);
7587  LocalContext context;
7588  context->Global()->Set(v8_str("o"), templ->NewInstance());
7589  call_ic_function =
7590      v8_compile("function f(x) { return x + 1; }; f")->Run();
7591  v8::Handle<Value> value = CompileRun(
7592    "var result = 0;"
7593    "for (var i = 0; i < 1000; i++) {"
7594    "  result = o.x(41);"
7595    "}");
7596  CHECK_EQ(42, value->Int32Value());
7597}
7598
7599
7600// This test checks that if interceptor doesn't provide
7601// a value, we can fetch regular value.
7602THREADED_TEST(InterceptorCallICSeesOthers) {
7603  v8::HandleScope scope;
7604  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7605  templ->SetNamedPropertyHandler(NoBlockGetterX);
7606  LocalContext context;
7607  context->Global()->Set(v8_str("o"), templ->NewInstance());
7608  v8::Handle<Value> value = CompileRun(
7609    "o.x = function f(x) { return x + 1; };"
7610    "var result = 0;"
7611    "for (var i = 0; i < 7; i++) {"
7612    "  result = o.x(41);"
7613    "}");
7614  CHECK_EQ(42, value->Int32Value());
7615}
7616
7617
7618static v8::Handle<Value> call_ic_function4;
7619static v8::Handle<Value> InterceptorCallICGetter4(Local<String> name,
7620                                                  const AccessorInfo& info) {
7621  ApiTestFuzzer::Fuzz();
7622  CHECK(v8_str("x")->Equals(name));
7623  return call_ic_function4;
7624}
7625
7626
7627// This test checks that if interceptor provides a function,
7628// even if we cached shadowed variant, interceptor's function
7629// is invoked
7630THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
7631  v8::HandleScope scope;
7632  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7633  templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
7634  LocalContext context;
7635  context->Global()->Set(v8_str("o"), templ->NewInstance());
7636  call_ic_function4 =
7637      v8_compile("function f(x) { return x - 1; }; f")->Run();
7638  v8::Handle<Value> value = CompileRun(
7639    "o.__proto__.x = function(x) { return x + 1; };"
7640    "var result = 0;"
7641    "for (var i = 0; i < 1000; i++) {"
7642    "  result = o.x(42);"
7643    "}");
7644  CHECK_EQ(41, value->Int32Value());
7645}
7646
7647
7648// Test the case when we stored cacheable lookup into
7649// a stub, but it got invalidated later on
7650THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
7651  v8::HandleScope scope;
7652  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7653  templ->SetNamedPropertyHandler(NoBlockGetterX);
7654  LocalContext context;
7655  context->Global()->Set(v8_str("o"), templ->NewInstance());
7656  v8::Handle<Value> value = CompileRun(
7657    "proto1 = new Object();"
7658    "proto2 = new Object();"
7659    "o.__proto__ = proto1;"
7660    "proto1.__proto__ = proto2;"
7661    "proto2.y = function(x) { return x + 1; };"
7662    // Invoke it many times to compile a stub
7663    "for (var i = 0; i < 7; i++) {"
7664    "  o.y(42);"
7665    "}"
7666    "proto1.y = function(x) { return x - 1; };"
7667    "var result = 0;"
7668    "for (var i = 0; i < 7; i++) {"
7669    "  result += o.y(42);"
7670    "}");
7671  CHECK_EQ(41 * 7, value->Int32Value());
7672}
7673
7674
7675static v8::Handle<Value> call_ic_function5;
7676static v8::Handle<Value> InterceptorCallICGetter5(Local<String> name,
7677                                                  const AccessorInfo& info) {
7678  ApiTestFuzzer::Fuzz();
7679  if (v8_str("x")->Equals(name))
7680    return call_ic_function5;
7681  else
7682    return Local<Value>();
7683}
7684
7685
7686// This test checks that if interceptor doesn't provide a function,
7687// cached constant function is used
7688THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
7689  v8::HandleScope scope;
7690  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7691  templ->SetNamedPropertyHandler(NoBlockGetterX);
7692  LocalContext context;
7693  context->Global()->Set(v8_str("o"), templ->NewInstance());
7694  v8::Handle<Value> value = CompileRun(
7695    "function inc(x) { return x + 1; };"
7696    "inc(1);"
7697    "o.x = inc;"
7698    "var result = 0;"
7699    "for (var i = 0; i < 1000; i++) {"
7700    "  result = o.x(42);"
7701    "}");
7702  CHECK_EQ(43, value->Int32Value());
7703}
7704
7705
7706// This test checks that if interceptor provides a function,
7707// even if we cached constant function, interceptor's function
7708// is invoked
7709THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
7710  v8::HandleScope scope;
7711  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7712  templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
7713  LocalContext context;
7714  context->Global()->Set(v8_str("o"), templ->NewInstance());
7715  call_ic_function5 =
7716      v8_compile("function f(x) { return x - 1; }; f")->Run();
7717  v8::Handle<Value> value = CompileRun(
7718    "function inc(x) { return x + 1; };"
7719    "inc(1);"
7720    "o.x = inc;"
7721    "var result = 0;"
7722    "for (var i = 0; i < 1000; i++) {"
7723    "  result = o.x(42);"
7724    "}");
7725  CHECK_EQ(41, value->Int32Value());
7726}
7727
7728
7729// Test the case when we stored constant function into
7730// a stub, but it got invalidated later on
7731THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
7732  v8::HandleScope scope;
7733  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7734  templ->SetNamedPropertyHandler(NoBlockGetterX);
7735  LocalContext context;
7736  context->Global()->Set(v8_str("o"), templ->NewInstance());
7737  v8::Handle<Value> value = CompileRun(
7738    "function inc(x) { return x + 1; };"
7739    "inc(1);"
7740    "proto1 = new Object();"
7741    "proto2 = new Object();"
7742    "o.__proto__ = proto1;"
7743    "proto1.__proto__ = proto2;"
7744    "proto2.y = inc;"
7745    // Invoke it many times to compile a stub
7746    "for (var i = 0; i < 7; i++) {"
7747    "  o.y(42);"
7748    "}"
7749    "proto1.y = function(x) { return x - 1; };"
7750    "var result = 0;"
7751    "for (var i = 0; i < 7; i++) {"
7752    "  result += o.y(42);"
7753    "}");
7754  CHECK_EQ(41 * 7, value->Int32Value());
7755}
7756
7757
7758// Test the case when we stored constant function into
7759// a stub, but it got invalidated later on due to override on
7760// global object which is between interceptor and constant function' holders.
7761THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
7762  v8::HandleScope scope;
7763  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7764  templ->SetNamedPropertyHandler(NoBlockGetterX);
7765  LocalContext context;
7766  context->Global()->Set(v8_str("o"), templ->NewInstance());
7767  v8::Handle<Value> value = CompileRun(
7768    "function inc(x) { return x + 1; };"
7769    "inc(1);"
7770    "o.__proto__ = this;"
7771    "this.__proto__.y = inc;"
7772    // Invoke it many times to compile a stub
7773    "for (var i = 0; i < 7; i++) {"
7774    "  if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
7775    "}"
7776    "this.y = function(x) { return x - 1; };"
7777    "var result = 0;"
7778    "for (var i = 0; i < 7; i++) {"
7779    "  result += o.y(42);"
7780    "}");
7781  CHECK_EQ(41 * 7, value->Int32Value());
7782}
7783
7784
7785// Test the case when actual function to call sits on global object.
7786THREADED_TEST(InterceptorCallICCachedFromGlobal) {
7787  v8::HandleScope scope;
7788  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7789  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
7790
7791  LocalContext context;
7792  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
7793
7794  v8::Handle<Value> value = CompileRun(
7795    "try {"
7796    "  o.__proto__ = this;"
7797    "  for (var i = 0; i < 10; i++) {"
7798    "    var v = o.parseFloat('239');"
7799    "    if (v != 239) throw v;"
7800      // Now it should be ICed and keep a reference to parseFloat.
7801    "  }"
7802    "  var result = 0;"
7803    "  for (var i = 0; i < 10; i++) {"
7804    "    result += o.parseFloat('239');"
7805    "  }"
7806    "  result"
7807    "} catch(e) {"
7808    "  e"
7809    "};");
7810  CHECK_EQ(239 * 10, value->Int32Value());
7811}
7812
7813static v8::Handle<Value> InterceptorCallICFastApi(Local<String> name,
7814                                                  const AccessorInfo& info) {
7815  ApiTestFuzzer::Fuzz();
7816  int* call_count = reinterpret_cast<int*>(v8::External::Unwrap(info.Data()));
7817  ++(*call_count);
7818  if ((*call_count) % 20 == 0) {
7819    HEAP->CollectAllGarbage(true);
7820  }
7821  return v8::Handle<Value>();
7822}
7823
7824static v8::Handle<Value> FastApiCallback_TrivialSignature(
7825    const v8::Arguments& args) {
7826  ApiTestFuzzer::Fuzz();
7827  CHECK_EQ(args.This(), args.Holder());
7828  CHECK(args.Data()->Equals(v8_str("method_data")));
7829  return v8::Integer::New(args[0]->Int32Value() + 1);
7830}
7831
7832static v8::Handle<Value> FastApiCallback_SimpleSignature(
7833    const v8::Arguments& args) {
7834  ApiTestFuzzer::Fuzz();
7835  CHECK_EQ(args.This()->GetPrototype(), args.Holder());
7836  CHECK(args.Data()->Equals(v8_str("method_data")));
7837  // Note, we're using HasRealNamedProperty instead of Has to avoid
7838  // invoking the interceptor again.
7839  CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
7840  return v8::Integer::New(args[0]->Int32Value() + 1);
7841}
7842
7843// Helper to maximize the odds of object moving.
7844static void GenerateSomeGarbage() {
7845  CompileRun(
7846      "var garbage;"
7847      "for (var i = 0; i < 1000; i++) {"
7848      "  garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
7849      "}"
7850      "garbage = undefined;");
7851}
7852
7853
7854v8::Handle<v8::Value> DirectApiCallback(const v8::Arguments& args) {
7855  static int count = 0;
7856  if (count++ % 3 == 0) {
7857    HEAP->  CollectAllGarbage(true);  // This should move the stub
7858    GenerateSomeGarbage();  // This should ensure the old stub memory is flushed
7859  }
7860  return v8::Handle<v8::Value>();
7861}
7862
7863
7864THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
7865  v8::HandleScope scope;
7866  LocalContext context;
7867  v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
7868  nativeobject_templ->Set("callback",
7869                          v8::FunctionTemplate::New(DirectApiCallback));
7870  v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
7871  context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
7872  // call the api function multiple times to ensure direct call stub creation.
7873  CompileRun(
7874        "function f() {"
7875        "  for (var i = 1; i <= 30; i++) {"
7876        "    nativeobject.callback();"
7877        "  }"
7878        "}"
7879        "f();");
7880}
7881
7882
7883v8::Handle<v8::Value> ThrowingDirectApiCallback(const v8::Arguments& args) {
7884  return v8::ThrowException(v8_str("g"));
7885}
7886
7887
7888THREADED_TEST(CallICFastApi_DirectCall_Throw) {
7889  v8::HandleScope scope;
7890  LocalContext context;
7891  v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
7892  nativeobject_templ->Set("callback",
7893                          v8::FunctionTemplate::New(ThrowingDirectApiCallback));
7894  v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
7895  context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
7896  // call the api function multiple times to ensure direct call stub creation.
7897  v8::Handle<Value> result = CompileRun(
7898      "var result = '';"
7899      "function f() {"
7900      "  for (var i = 1; i <= 5; i++) {"
7901      "    try { nativeobject.callback(); } catch (e) { result += e; }"
7902      "  }"
7903      "}"
7904      "f(); result;");
7905  CHECK_EQ(v8_str("ggggg"), result);
7906}
7907
7908
7909v8::Handle<v8::Value> DirectGetterCallback(Local<String> name,
7910                                           const v8::AccessorInfo& info) {
7911  if (++p_getter_count % 3 == 0) {
7912    HEAP->CollectAllGarbage(true);
7913    GenerateSomeGarbage();
7914  }
7915  return v8::Handle<v8::Value>();
7916}
7917
7918
7919THREADED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
7920  v8::HandleScope scope;
7921  LocalContext context;
7922  v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
7923  obj->SetAccessor(v8_str("p1"), DirectGetterCallback);
7924  context->Global()->Set(v8_str("o1"), obj->NewInstance());
7925  p_getter_count = 0;
7926  CompileRun(
7927      "function f() {"
7928      "  for (var i = 0; i < 30; i++) o1.p1;"
7929      "}"
7930      "f();");
7931  CHECK_EQ(30, p_getter_count);
7932}
7933
7934
7935v8::Handle<v8::Value> ThrowingDirectGetterCallback(
7936    Local<String> name, const v8::AccessorInfo& info) {
7937  return v8::ThrowException(v8_str("g"));
7938}
7939
7940
7941THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
7942  v8::HandleScope scope;
7943  LocalContext context;
7944  v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
7945  obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
7946  context->Global()->Set(v8_str("o1"), obj->NewInstance());
7947  v8::Handle<Value> result = CompileRun(
7948      "var result = '';"
7949      "for (var i = 0; i < 5; i++) {"
7950      "    try { o1.p1; } catch (e) { result += e; }"
7951      "}"
7952      "result;");
7953  CHECK_EQ(v8_str("ggggg"), result);
7954}
7955
7956
7957THREADED_TEST(InterceptorCallICFastApi_TrivialSignature) {
7958  int interceptor_call_count = 0;
7959  v8::HandleScope scope;
7960  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7961  v8::Handle<v8::FunctionTemplate> method_templ =
7962      v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
7963                                v8_str("method_data"),
7964                                v8::Handle<v8::Signature>());
7965  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7966  proto_templ->Set(v8_str("method"), method_templ);
7967  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7968  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
7969                                 NULL, NULL, NULL, NULL,
7970                                 v8::External::Wrap(&interceptor_call_count));
7971  LocalContext context;
7972  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7973  GenerateSomeGarbage();
7974  context->Global()->Set(v8_str("o"), fun->NewInstance());
7975  v8::Handle<Value> value = CompileRun(
7976      "var result = 0;"
7977      "for (var i = 0; i < 100; i++) {"
7978      "  result = o.method(41);"
7979      "}");
7980  CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
7981  CHECK_EQ(100, interceptor_call_count);
7982}
7983
7984THREADED_TEST(InterceptorCallICFastApi_SimpleSignature) {
7985  int interceptor_call_count = 0;
7986  v8::HandleScope scope;
7987  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7988  v8::Handle<v8::FunctionTemplate> method_templ =
7989      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7990                                v8_str("method_data"),
7991                                v8::Signature::New(fun_templ));
7992  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7993  proto_templ->Set(v8_str("method"), method_templ);
7994  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7995  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
7996                                 NULL, NULL, NULL, NULL,
7997                                 v8::External::Wrap(&interceptor_call_count));
7998  LocalContext context;
7999  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8000  GenerateSomeGarbage();
8001  context->Global()->Set(v8_str("o"), fun->NewInstance());
8002  v8::Handle<Value> value = CompileRun(
8003      "o.foo = 17;"
8004      "var receiver = {};"
8005      "receiver.__proto__ = o;"
8006      "var result = 0;"
8007      "for (var i = 0; i < 100; i++) {"
8008      "  result = receiver.method(41);"
8009      "}");
8010  CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
8011  CHECK_EQ(100, interceptor_call_count);
8012}
8013
8014THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
8015  int interceptor_call_count = 0;
8016  v8::HandleScope scope;
8017  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8018  v8::Handle<v8::FunctionTemplate> method_templ =
8019      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8020                                v8_str("method_data"),
8021                                v8::Signature::New(fun_templ));
8022  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8023  proto_templ->Set(v8_str("method"), method_templ);
8024  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8025  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8026                                 NULL, NULL, NULL, NULL,
8027                                 v8::External::Wrap(&interceptor_call_count));
8028  LocalContext context;
8029  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8030  GenerateSomeGarbage();
8031  context->Global()->Set(v8_str("o"), fun->NewInstance());
8032  v8::Handle<Value> value = CompileRun(
8033      "o.foo = 17;"
8034      "var receiver = {};"
8035      "receiver.__proto__ = o;"
8036      "var result = 0;"
8037      "var saved_result = 0;"
8038      "for (var i = 0; i < 100; i++) {"
8039      "  result = receiver.method(41);"
8040      "  if (i == 50) {"
8041      "    saved_result = result;"
8042      "    receiver = {method: function(x) { return x - 1 }};"
8043      "  }"
8044      "}");
8045  CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
8046  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8047  CHECK_GE(interceptor_call_count, 50);
8048}
8049
8050THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
8051  int interceptor_call_count = 0;
8052  v8::HandleScope scope;
8053  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8054  v8::Handle<v8::FunctionTemplate> method_templ =
8055      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8056                                v8_str("method_data"),
8057                                v8::Signature::New(fun_templ));
8058  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8059  proto_templ->Set(v8_str("method"), method_templ);
8060  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8061  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8062                                 NULL, NULL, NULL, NULL,
8063                                 v8::External::Wrap(&interceptor_call_count));
8064  LocalContext context;
8065  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8066  GenerateSomeGarbage();
8067  context->Global()->Set(v8_str("o"), fun->NewInstance());
8068  v8::Handle<Value> value = CompileRun(
8069      "o.foo = 17;"
8070      "var receiver = {};"
8071      "receiver.__proto__ = o;"
8072      "var result = 0;"
8073      "var saved_result = 0;"
8074      "for (var i = 0; i < 100; i++) {"
8075      "  result = receiver.method(41);"
8076      "  if (i == 50) {"
8077      "    saved_result = result;"
8078      "    o.method = function(x) { return x - 1 };"
8079      "  }"
8080      "}");
8081  CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
8082  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8083  CHECK_GE(interceptor_call_count, 50);
8084}
8085
8086THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
8087  int interceptor_call_count = 0;
8088  v8::HandleScope scope;
8089  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8090  v8::Handle<v8::FunctionTemplate> method_templ =
8091      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8092                                v8_str("method_data"),
8093                                v8::Signature::New(fun_templ));
8094  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8095  proto_templ->Set(v8_str("method"), method_templ);
8096  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8097  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8098                                 NULL, NULL, NULL, NULL,
8099                                 v8::External::Wrap(&interceptor_call_count));
8100  LocalContext context;
8101  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8102  GenerateSomeGarbage();
8103  context->Global()->Set(v8_str("o"), fun->NewInstance());
8104  v8::TryCatch try_catch;
8105  v8::Handle<Value> value = CompileRun(
8106      "o.foo = 17;"
8107      "var receiver = {};"
8108      "receiver.__proto__ = o;"
8109      "var result = 0;"
8110      "var saved_result = 0;"
8111      "for (var i = 0; i < 100; i++) {"
8112      "  result = receiver.method(41);"
8113      "  if (i == 50) {"
8114      "    saved_result = result;"
8115      "    receiver = 333;"
8116      "  }"
8117      "}");
8118  CHECK(try_catch.HasCaught());
8119  CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
8120           try_catch.Exception()->ToString());
8121  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8122  CHECK_GE(interceptor_call_count, 50);
8123}
8124
8125THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
8126  int interceptor_call_count = 0;
8127  v8::HandleScope scope;
8128  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8129  v8::Handle<v8::FunctionTemplate> method_templ =
8130      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8131                                v8_str("method_data"),
8132                                v8::Signature::New(fun_templ));
8133  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8134  proto_templ->Set(v8_str("method"), method_templ);
8135  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8136  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8137                                 NULL, NULL, NULL, NULL,
8138                                 v8::External::Wrap(&interceptor_call_count));
8139  LocalContext context;
8140  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8141  GenerateSomeGarbage();
8142  context->Global()->Set(v8_str("o"), fun->NewInstance());
8143  v8::TryCatch try_catch;
8144  v8::Handle<Value> value = CompileRun(
8145      "o.foo = 17;"
8146      "var receiver = {};"
8147      "receiver.__proto__ = o;"
8148      "var result = 0;"
8149      "var saved_result = 0;"
8150      "for (var i = 0; i < 100; i++) {"
8151      "  result = receiver.method(41);"
8152      "  if (i == 50) {"
8153      "    saved_result = result;"
8154      "    receiver = {method: receiver.method};"
8155      "  }"
8156      "}");
8157  CHECK(try_catch.HasCaught());
8158  CHECK_EQ(v8_str("TypeError: Illegal invocation"),
8159           try_catch.Exception()->ToString());
8160  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8161  CHECK_GE(interceptor_call_count, 50);
8162}
8163
8164THREADED_TEST(CallICFastApi_TrivialSignature) {
8165  v8::HandleScope scope;
8166  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8167  v8::Handle<v8::FunctionTemplate> method_templ =
8168      v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
8169                                v8_str("method_data"),
8170                                v8::Handle<v8::Signature>());
8171  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8172  proto_templ->Set(v8_str("method"), method_templ);
8173  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8174  LocalContext context;
8175  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8176  GenerateSomeGarbage();
8177  context->Global()->Set(v8_str("o"), fun->NewInstance());
8178  v8::Handle<Value> value = CompileRun(
8179      "var result = 0;"
8180      "for (var i = 0; i < 100; i++) {"
8181      "  result = o.method(41);"
8182      "}");
8183
8184  CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
8185}
8186
8187THREADED_TEST(CallICFastApi_SimpleSignature) {
8188  v8::HandleScope scope;
8189  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8190  v8::Handle<v8::FunctionTemplate> method_templ =
8191      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8192                                v8_str("method_data"),
8193                                v8::Signature::New(fun_templ));
8194  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8195  proto_templ->Set(v8_str("method"), method_templ);
8196  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8197  LocalContext context;
8198  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8199  GenerateSomeGarbage();
8200  context->Global()->Set(v8_str("o"), fun->NewInstance());
8201  v8::Handle<Value> value = CompileRun(
8202      "o.foo = 17;"
8203      "var receiver = {};"
8204      "receiver.__proto__ = o;"
8205      "var result = 0;"
8206      "for (var i = 0; i < 100; i++) {"
8207      "  result = receiver.method(41);"
8208      "}");
8209
8210  CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
8211}
8212
8213THREADED_TEST(CallICFastApi_SimpleSignature_Miss1) {
8214  v8::HandleScope scope;
8215  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8216  v8::Handle<v8::FunctionTemplate> method_templ =
8217      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8218                                v8_str("method_data"),
8219                                v8::Signature::New(fun_templ));
8220  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8221  proto_templ->Set(v8_str("method"), method_templ);
8222  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8223  LocalContext context;
8224  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8225  GenerateSomeGarbage();
8226  context->Global()->Set(v8_str("o"), fun->NewInstance());
8227  v8::Handle<Value> value = CompileRun(
8228      "o.foo = 17;"
8229      "var receiver = {};"
8230      "receiver.__proto__ = o;"
8231      "var result = 0;"
8232      "var saved_result = 0;"
8233      "for (var i = 0; i < 100; i++) {"
8234      "  result = receiver.method(41);"
8235      "  if (i == 50) {"
8236      "    saved_result = result;"
8237      "    receiver = {method: function(x) { return x - 1 }};"
8238      "  }"
8239      "}");
8240  CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
8241  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8242}
8243
8244THREADED_TEST(CallICFastApi_SimpleSignature_Miss2) {
8245  v8::HandleScope scope;
8246  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8247  v8::Handle<v8::FunctionTemplate> method_templ =
8248      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8249                                v8_str("method_data"),
8250                                v8::Signature::New(fun_templ));
8251  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8252  proto_templ->Set(v8_str("method"), method_templ);
8253  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8254  LocalContext context;
8255  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8256  GenerateSomeGarbage();
8257  context->Global()->Set(v8_str("o"), fun->NewInstance());
8258  v8::TryCatch try_catch;
8259  v8::Handle<Value> value = CompileRun(
8260      "o.foo = 17;"
8261      "var receiver = {};"
8262      "receiver.__proto__ = o;"
8263      "var result = 0;"
8264      "var saved_result = 0;"
8265      "for (var i = 0; i < 100; i++) {"
8266      "  result = receiver.method(41);"
8267      "  if (i == 50) {"
8268      "    saved_result = result;"
8269      "    receiver = 333;"
8270      "  }"
8271      "}");
8272  CHECK(try_catch.HasCaught());
8273  CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
8274           try_catch.Exception()->ToString());
8275  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8276}
8277
8278
8279v8::Handle<Value> keyed_call_ic_function;
8280
8281static v8::Handle<Value> InterceptorKeyedCallICGetter(
8282    Local<String> name, const AccessorInfo& info) {
8283  ApiTestFuzzer::Fuzz();
8284  if (v8_str("x")->Equals(name)) {
8285    return keyed_call_ic_function;
8286  }
8287  return v8::Handle<Value>();
8288}
8289
8290
8291// Test the case when we stored cacheable lookup into
8292// a stub, but the function name changed (to another cacheable function).
8293THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
8294  v8::HandleScope scope;
8295  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8296  templ->SetNamedPropertyHandler(NoBlockGetterX);
8297  LocalContext context;
8298  context->Global()->Set(v8_str("o"), templ->NewInstance());
8299  v8::Handle<Value> value = CompileRun(
8300    "proto = new Object();"
8301    "proto.y = function(x) { return x + 1; };"
8302    "proto.z = function(x) { return x - 1; };"
8303    "o.__proto__ = proto;"
8304    "var result = 0;"
8305    "var method = 'y';"
8306    "for (var i = 0; i < 10; i++) {"
8307    "  if (i == 5) { method = 'z'; };"
8308    "  result += o[method](41);"
8309    "}");
8310  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
8311}
8312
8313
8314// Test the case when we stored cacheable lookup into
8315// a stub, but the function name changed (and the new function is present
8316// both before and after the interceptor in the prototype chain).
8317THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
8318  v8::HandleScope scope;
8319  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8320  templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
8321  LocalContext context;
8322  context->Global()->Set(v8_str("proto1"), templ->NewInstance());
8323  keyed_call_ic_function =
8324      v8_compile("function f(x) { return x - 1; }; f")->Run();
8325  v8::Handle<Value> value = CompileRun(
8326    "o = new Object();"
8327    "proto2 = new Object();"
8328    "o.y = function(x) { return x + 1; };"
8329    "proto2.y = function(x) { return x + 2; };"
8330    "o.__proto__ = proto1;"
8331    "proto1.__proto__ = proto2;"
8332    "var result = 0;"
8333    "var method = 'x';"
8334    "for (var i = 0; i < 10; i++) {"
8335    "  if (i == 5) { method = 'y'; };"
8336    "  result += o[method](41);"
8337    "}");
8338  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
8339}
8340
8341
8342// Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
8343// on the global object.
8344THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
8345  v8::HandleScope scope;
8346  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8347  templ->SetNamedPropertyHandler(NoBlockGetterX);
8348  LocalContext context;
8349  context->Global()->Set(v8_str("o"), templ->NewInstance());
8350  v8::Handle<Value> value = CompileRun(
8351    "function inc(x) { return x + 1; };"
8352    "inc(1);"
8353    "function dec(x) { return x - 1; };"
8354    "dec(1);"
8355    "o.__proto__ = this;"
8356    "this.__proto__.x = inc;"
8357    "this.__proto__.y = dec;"
8358    "var result = 0;"
8359    "var method = 'x';"
8360    "for (var i = 0; i < 10; i++) {"
8361    "  if (i == 5) { method = 'y'; };"
8362    "  result += o[method](41);"
8363    "}");
8364  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
8365}
8366
8367
8368// Test the case when actual function to call sits on global object.
8369THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
8370  v8::HandleScope scope;
8371  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8372  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
8373  LocalContext context;
8374  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8375
8376  v8::Handle<Value> value = CompileRun(
8377    "function len(x) { return x.length; };"
8378    "o.__proto__ = this;"
8379    "var m = 'parseFloat';"
8380    "var result = 0;"
8381    "for (var i = 0; i < 10; i++) {"
8382    "  if (i == 5) {"
8383    "    m = 'len';"
8384    "    saved_result = result;"
8385    "  };"
8386    "  result = o[m]('239');"
8387    "}");
8388  CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
8389  CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8390}
8391
8392// Test the map transition before the interceptor.
8393THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
8394  v8::HandleScope scope;
8395  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8396  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
8397  LocalContext context;
8398  context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
8399
8400  v8::Handle<Value> value = CompileRun(
8401    "var o = new Object();"
8402    "o.__proto__ = proto;"
8403    "o.method = function(x) { return x + 1; };"
8404    "var m = 'method';"
8405    "var result = 0;"
8406    "for (var i = 0; i < 10; i++) {"
8407    "  if (i == 5) { o.method = function(x) { return x - 1; }; };"
8408    "  result += o[m](41);"
8409    "}");
8410  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
8411}
8412
8413
8414// Test the map transition after the interceptor.
8415THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
8416  v8::HandleScope scope;
8417  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8418  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
8419  LocalContext context;
8420  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8421
8422  v8::Handle<Value> value = CompileRun(
8423    "var proto = new Object();"
8424    "o.__proto__ = proto;"
8425    "proto.method = function(x) { return x + 1; };"
8426    "var m = 'method';"
8427    "var result = 0;"
8428    "for (var i = 0; i < 10; i++) {"
8429    "  if (i == 5) { proto.method = function(x) { return x - 1; }; };"
8430    "  result += o[m](41);"
8431    "}");
8432  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
8433}
8434
8435
8436static int interceptor_call_count = 0;
8437
8438static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name,
8439                                                     const AccessorInfo& info) {
8440  ApiTestFuzzer::Fuzz();
8441  if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
8442    return call_ic_function2;
8443  }
8444  return v8::Handle<Value>();
8445}
8446
8447
8448// This test should hit load and call ICs for the interceptor case.
8449// Once in a while, the interceptor will reply that a property was not
8450// found in which case we should get a reference error.
8451THREADED_TEST(InterceptorICReferenceErrors) {
8452  v8::HandleScope scope;
8453  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8454  templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
8455  LocalContext context(0, templ, v8::Handle<Value>());
8456  call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
8457  v8::Handle<Value> value = CompileRun(
8458    "function f() {"
8459    "  for (var i = 0; i < 1000; i++) {"
8460    "    try { x; } catch(e) { return true; }"
8461    "  }"
8462    "  return false;"
8463    "};"
8464    "f();");
8465  CHECK_EQ(true, value->BooleanValue());
8466  interceptor_call_count = 0;
8467  value = CompileRun(
8468    "function g() {"
8469    "  for (var i = 0; i < 1000; i++) {"
8470    "    try { x(42); } catch(e) { return true; }"
8471    "  }"
8472    "  return false;"
8473    "};"
8474    "g();");
8475  CHECK_EQ(true, value->BooleanValue());
8476}
8477
8478
8479static int interceptor_ic_exception_get_count = 0;
8480
8481static v8::Handle<Value> InterceptorICExceptionGetter(
8482    Local<String> name,
8483    const AccessorInfo& info) {
8484  ApiTestFuzzer::Fuzz();
8485  if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
8486    return call_ic_function3;
8487  }
8488  if (interceptor_ic_exception_get_count == 20) {
8489    return v8::ThrowException(v8_num(42));
8490  }
8491  // Do not handle get for properties other than x.
8492  return v8::Handle<Value>();
8493}
8494
8495// Test interceptor load/call IC where the interceptor throws an
8496// exception once in a while.
8497THREADED_TEST(InterceptorICGetterExceptions) {
8498  interceptor_ic_exception_get_count = 0;
8499  v8::HandleScope scope;
8500  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8501  templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
8502  LocalContext context(0, templ, v8::Handle<Value>());
8503  call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
8504  v8::Handle<Value> value = CompileRun(
8505    "function f() {"
8506    "  for (var i = 0; i < 100; i++) {"
8507    "    try { x; } catch(e) { return true; }"
8508    "  }"
8509    "  return false;"
8510    "};"
8511    "f();");
8512  CHECK_EQ(true, value->BooleanValue());
8513  interceptor_ic_exception_get_count = 0;
8514  value = CompileRun(
8515    "function f() {"
8516    "  for (var i = 0; i < 100; i++) {"
8517    "    try { x(42); } catch(e) { return true; }"
8518    "  }"
8519    "  return false;"
8520    "};"
8521    "f();");
8522  CHECK_EQ(true, value->BooleanValue());
8523}
8524
8525
8526static int interceptor_ic_exception_set_count = 0;
8527
8528static v8::Handle<Value> InterceptorICExceptionSetter(
8529      Local<String> key, Local<Value> value, const AccessorInfo&) {
8530  ApiTestFuzzer::Fuzz();
8531  if (++interceptor_ic_exception_set_count > 20) {
8532    return v8::ThrowException(v8_num(42));
8533  }
8534  // Do not actually handle setting.
8535  return v8::Handle<Value>();
8536}
8537
8538// Test interceptor store IC where the interceptor throws an exception
8539// once in a while.
8540THREADED_TEST(InterceptorICSetterExceptions) {
8541  interceptor_ic_exception_set_count = 0;
8542  v8::HandleScope scope;
8543  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8544  templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
8545  LocalContext context(0, templ, v8::Handle<Value>());
8546  v8::Handle<Value> value = CompileRun(
8547    "function f() {"
8548    "  for (var i = 0; i < 100; i++) {"
8549    "    try { x = 42; } catch(e) { return true; }"
8550    "  }"
8551    "  return false;"
8552    "};"
8553    "f();");
8554  CHECK_EQ(true, value->BooleanValue());
8555}
8556
8557
8558// Test that we ignore null interceptors.
8559THREADED_TEST(NullNamedInterceptor) {
8560  v8::HandleScope scope;
8561  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8562  templ->SetNamedPropertyHandler(0);
8563  LocalContext context;
8564  templ->Set("x", v8_num(42));
8565  v8::Handle<v8::Object> obj = templ->NewInstance();
8566  context->Global()->Set(v8_str("obj"), obj);
8567  v8::Handle<Value> value = CompileRun("obj.x");
8568  CHECK(value->IsInt32());
8569  CHECK_EQ(42, value->Int32Value());
8570}
8571
8572
8573// Test that we ignore null interceptors.
8574THREADED_TEST(NullIndexedInterceptor) {
8575  v8::HandleScope scope;
8576  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8577  templ->SetIndexedPropertyHandler(0);
8578  LocalContext context;
8579  templ->Set("42", v8_num(42));
8580  v8::Handle<v8::Object> obj = templ->NewInstance();
8581  context->Global()->Set(v8_str("obj"), obj);
8582  v8::Handle<Value> value = CompileRun("obj[42]");
8583  CHECK(value->IsInt32());
8584  CHECK_EQ(42, value->Int32Value());
8585}
8586
8587
8588THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
8589  v8::HandleScope scope;
8590  v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
8591  templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8592  LocalContext env;
8593  env->Global()->Set(v8_str("obj"),
8594                     templ->GetFunction()->NewInstance());
8595  ExpectTrue("obj.x === 42");
8596  ExpectTrue("!obj.propertyIsEnumerable('x')");
8597}
8598
8599
8600static Handle<Value> ThrowingGetter(Local<String> name,
8601                                    const AccessorInfo& info) {
8602  ApiTestFuzzer::Fuzz();
8603  ThrowException(Handle<Value>());
8604  return Undefined();
8605}
8606
8607
8608THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
8609  HandleScope scope;
8610  LocalContext context;
8611
8612  Local<FunctionTemplate> templ = FunctionTemplate::New();
8613  Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
8614  instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
8615
8616  Local<Object> instance = templ->GetFunction()->NewInstance();
8617
8618  Local<Object> another = Object::New();
8619  another->SetPrototype(instance);
8620
8621  Local<Object> with_js_getter = CompileRun(
8622      "o = {};\n"
8623      "o.__defineGetter__('f', function() { throw undefined; });\n"
8624      "o\n").As<Object>();
8625  CHECK(!with_js_getter.IsEmpty());
8626
8627  TryCatch try_catch;
8628
8629  Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
8630  CHECK(try_catch.HasCaught());
8631  try_catch.Reset();
8632  CHECK(result.IsEmpty());
8633
8634  result = another->GetRealNamedProperty(v8_str("f"));
8635  CHECK(try_catch.HasCaught());
8636  try_catch.Reset();
8637  CHECK(result.IsEmpty());
8638
8639  result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
8640  CHECK(try_catch.HasCaught());
8641  try_catch.Reset();
8642  CHECK(result.IsEmpty());
8643
8644  result = another->Get(v8_str("f"));
8645  CHECK(try_catch.HasCaught());
8646  try_catch.Reset();
8647  CHECK(result.IsEmpty());
8648
8649  result = with_js_getter->GetRealNamedProperty(v8_str("f"));
8650  CHECK(try_catch.HasCaught());
8651  try_catch.Reset();
8652  CHECK(result.IsEmpty());
8653
8654  result = with_js_getter->Get(v8_str("f"));
8655  CHECK(try_catch.HasCaught());
8656  try_catch.Reset();
8657  CHECK(result.IsEmpty());
8658}
8659
8660
8661static Handle<Value> ThrowingCallbackWithTryCatch(const Arguments& args) {
8662  TryCatch try_catch;
8663  // Verboseness is important: it triggers message delivery which can call into
8664  // external code.
8665  try_catch.SetVerbose(true);
8666  CompileRun("throw 'from JS';");
8667  CHECK(try_catch.HasCaught());
8668  CHECK(!i::Isolate::Current()->has_pending_exception());
8669  CHECK(!i::Isolate::Current()->has_scheduled_exception());
8670  return Undefined();
8671}
8672
8673
8674static int call_depth;
8675
8676
8677static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
8678  TryCatch try_catch;
8679}
8680
8681
8682static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
8683  if (--call_depth) CompileRun("throw 'ThrowInJS';");
8684}
8685
8686
8687static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
8688  if (--call_depth) ThrowException(v8_str("ThrowViaApi"));
8689}
8690
8691
8692static void WebKitLike(Handle<Message> message, Handle<Value> data) {
8693  Handle<String> errorMessageString = message->Get();
8694  CHECK(!errorMessageString.IsEmpty());
8695  message->GetStackTrace();
8696  message->GetScriptResourceName();
8697}
8698
8699THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
8700  HandleScope scope;
8701  LocalContext context;
8702
8703  Local<Function> func =
8704      FunctionTemplate::New(ThrowingCallbackWithTryCatch)->GetFunction();
8705  context->Global()->Set(v8_str("func"), func);
8706
8707  MessageCallback callbacks[] =
8708      { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
8709  for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
8710    MessageCallback callback = callbacks[i];
8711    if (callback != NULL) {
8712      V8::AddMessageListener(callback);
8713    }
8714    call_depth = 5;
8715    ExpectFalse(
8716        "var thrown = false;\n"
8717        "try { func(); } catch(e) { thrown = true; }\n"
8718        "thrown\n");
8719    if (callback != NULL) {
8720      V8::RemoveMessageListeners(callback);
8721    }
8722  }
8723}
8724
8725
8726static v8::Handle<Value> ParentGetter(Local<String> name,
8727                                      const AccessorInfo& info) {
8728  ApiTestFuzzer::Fuzz();
8729  return v8_num(1);
8730}
8731
8732
8733static v8::Handle<Value> ChildGetter(Local<String> name,
8734                                     const AccessorInfo& info) {
8735  ApiTestFuzzer::Fuzz();
8736  return v8_num(42);
8737}
8738
8739
8740THREADED_TEST(Overriding) {
8741  v8::HandleScope scope;
8742  LocalContext context;
8743
8744  // Parent template.
8745  Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New();
8746  Local<ObjectTemplate> parent_instance_templ =
8747      parent_templ->InstanceTemplate();
8748  parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
8749
8750  // Template that inherits from the parent template.
8751  Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New();
8752  Local<ObjectTemplate> child_instance_templ =
8753      child_templ->InstanceTemplate();
8754  child_templ->Inherit(parent_templ);
8755  // Override 'f'.  The child version of 'f' should get called for child
8756  // instances.
8757  child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
8758  // Add 'g' twice.  The 'g' added last should get called for instances.
8759  child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
8760  child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
8761
8762  // Add 'h' as an accessor to the proto template with ReadOnly attributes
8763  // so 'h' can be shadowed on the instance object.
8764  Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
8765  child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
8766      v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
8767
8768  // Add 'i' as an accessor to the instance template with ReadOnly attributes
8769  // but the attribute does not have effect because it is duplicated with
8770  // NULL setter.
8771  child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
8772      v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
8773
8774
8775
8776  // Instantiate the child template.
8777  Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
8778
8779  // Check that the child function overrides the parent one.
8780  context->Global()->Set(v8_str("o"), instance);
8781  Local<Value> value = v8_compile("o.f")->Run();
8782  // Check that the 'g' that was added last is hit.
8783  CHECK_EQ(42, value->Int32Value());
8784  value = v8_compile("o.g")->Run();
8785  CHECK_EQ(42, value->Int32Value());
8786
8787  // Check 'h' can be shadowed.
8788  value = v8_compile("o.h = 3; o.h")->Run();
8789  CHECK_EQ(3, value->Int32Value());
8790
8791  // Check 'i' is cannot be shadowed or changed.
8792  value = v8_compile("o.i = 3; o.i")->Run();
8793  CHECK_EQ(42, value->Int32Value());
8794}
8795
8796
8797static v8::Handle<Value> IsConstructHandler(const v8::Arguments& args) {
8798  ApiTestFuzzer::Fuzz();
8799  if (args.IsConstructCall()) {
8800    return v8::Boolean::New(true);
8801  }
8802  return v8::Boolean::New(false);
8803}
8804
8805
8806THREADED_TEST(IsConstructCall) {
8807  v8::HandleScope scope;
8808
8809  // Function template with call handler.
8810  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
8811  templ->SetCallHandler(IsConstructHandler);
8812
8813  LocalContext context;
8814
8815  context->Global()->Set(v8_str("f"), templ->GetFunction());
8816  Local<Value> value = v8_compile("f()")->Run();
8817  CHECK(!value->BooleanValue());
8818  value = v8_compile("new f()")->Run();
8819  CHECK(value->BooleanValue());
8820}
8821
8822
8823THREADED_TEST(ObjectProtoToString) {
8824  v8::HandleScope scope;
8825  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
8826  templ->SetClassName(v8_str("MyClass"));
8827
8828  LocalContext context;
8829
8830  Local<String> customized_tostring = v8_str("customized toString");
8831
8832  // Replace Object.prototype.toString
8833  v8_compile("Object.prototype.toString = function() {"
8834                  "  return 'customized toString';"
8835                  "}")->Run();
8836
8837  // Normal ToString call should call replaced Object.prototype.toString
8838  Local<v8::Object> instance = templ->GetFunction()->NewInstance();
8839  Local<String> value = instance->ToString();
8840  CHECK(value->IsString() && value->Equals(customized_tostring));
8841
8842  // ObjectProtoToString should not call replace toString function.
8843  value = instance->ObjectProtoToString();
8844  CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
8845
8846  // Check global
8847  value = context->Global()->ObjectProtoToString();
8848  CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
8849
8850  // Check ordinary object
8851  Local<Value> object = v8_compile("new Object()")->Run();
8852  value = object.As<v8::Object>()->ObjectProtoToString();
8853  CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
8854}
8855
8856
8857THREADED_TEST(ObjectGetConstructorName) {
8858  v8::HandleScope scope;
8859  LocalContext context;
8860  v8_compile("function Parent() {};"
8861             "function Child() {};"
8862             "Child.prototype = new Parent();"
8863             "var outer = { inner: function() { } };"
8864             "var p = new Parent();"
8865             "var c = new Child();"
8866             "var x = new outer.inner();")->Run();
8867
8868  Local<v8::Value> p = context->Global()->Get(v8_str("p"));
8869  CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
8870      v8_str("Parent")));
8871
8872  Local<v8::Value> c = context->Global()->Get(v8_str("c"));
8873  CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
8874      v8_str("Child")));
8875
8876  Local<v8::Value> x = context->Global()->Get(v8_str("x"));
8877  CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
8878      v8_str("outer.inner")));
8879}
8880
8881
8882bool ApiTestFuzzer::fuzzing_ = false;
8883i::Semaphore* ApiTestFuzzer::all_tests_done_=
8884  i::OS::CreateSemaphore(0);
8885int ApiTestFuzzer::active_tests_;
8886int ApiTestFuzzer::tests_being_run_;
8887int ApiTestFuzzer::current_;
8888
8889
8890// We are in a callback and want to switch to another thread (if we
8891// are currently running the thread fuzzing test).
8892void ApiTestFuzzer::Fuzz() {
8893  if (!fuzzing_) return;
8894  ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
8895  test->ContextSwitch();
8896}
8897
8898
8899// Let the next thread go.  Since it is also waiting on the V8 lock it may
8900// not start immediately.
8901bool ApiTestFuzzer::NextThread() {
8902  int test_position = GetNextTestNumber();
8903  const char* test_name = RegisterThreadedTest::nth(current_)->name();
8904  if (test_position == current_) {
8905    if (kLogThreading)
8906      printf("Stay with %s\n", test_name);
8907    return false;
8908  }
8909  if (kLogThreading) {
8910    printf("Switch from %s to %s\n",
8911           test_name,
8912           RegisterThreadedTest::nth(test_position)->name());
8913  }
8914  current_ = test_position;
8915  RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal();
8916  return true;
8917}
8918
8919
8920void ApiTestFuzzer::Run() {
8921  // When it is our turn...
8922  gate_->Wait();
8923  {
8924    // ... get the V8 lock and start running the test.
8925    v8::Locker locker;
8926    CallTest();
8927  }
8928  // This test finished.
8929  active_ = false;
8930  active_tests_--;
8931  // If it was the last then signal that fact.
8932  if (active_tests_ == 0) {
8933    all_tests_done_->Signal();
8934  } else {
8935    // Otherwise select a new test and start that.
8936    NextThread();
8937  }
8938}
8939
8940
8941static unsigned linear_congruential_generator;
8942
8943
8944void ApiTestFuzzer::Setup(PartOfTest part) {
8945  linear_congruential_generator = i::FLAG_testing_prng_seed;
8946  fuzzing_ = true;
8947  int start = (part == FIRST_PART) ? 0 : (RegisterThreadedTest::count() >> 1);
8948  int end = (part == FIRST_PART)
8949      ? (RegisterThreadedTest::count() >> 1)
8950      : RegisterThreadedTest::count();
8951  active_tests_ = tests_being_run_ = end - start;
8952  for (int i = 0; i < tests_being_run_; i++) {
8953    RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(
8954        i::Isolate::Current(), i + start);
8955  }
8956  for (int i = 0; i < active_tests_; i++) {
8957    RegisterThreadedTest::nth(i)->fuzzer_->Start();
8958  }
8959}
8960
8961
8962static void CallTestNumber(int test_number) {
8963  (RegisterThreadedTest::nth(test_number)->callback())();
8964}
8965
8966
8967void ApiTestFuzzer::RunAllTests() {
8968  // Set off the first test.
8969  current_ = -1;
8970  NextThread();
8971  // Wait till they are all done.
8972  all_tests_done_->Wait();
8973}
8974
8975
8976int ApiTestFuzzer::GetNextTestNumber() {
8977  int next_test;
8978  do {
8979    next_test = (linear_congruential_generator >> 16) % tests_being_run_;
8980    linear_congruential_generator *= 1664525u;
8981    linear_congruential_generator += 1013904223u;
8982  } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
8983  return next_test;
8984}
8985
8986
8987void ApiTestFuzzer::ContextSwitch() {
8988  // If the new thread is the same as the current thread there is nothing to do.
8989  if (NextThread()) {
8990    // Now it can start.
8991    v8::Unlocker unlocker;
8992    // Wait till someone starts us again.
8993    gate_->Wait();
8994    // And we're off.
8995  }
8996}
8997
8998
8999void ApiTestFuzzer::TearDown() {
9000  fuzzing_ = false;
9001  for (int i = 0; i < RegisterThreadedTest::count(); i++) {
9002    ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
9003    if (fuzzer != NULL) fuzzer->Join();
9004  }
9005}
9006
9007
9008// Lets not be needlessly self-referential.
9009TEST(Threading) {
9010  ApiTestFuzzer::Setup(ApiTestFuzzer::FIRST_PART);
9011  ApiTestFuzzer::RunAllTests();
9012  ApiTestFuzzer::TearDown();
9013}
9014
9015TEST(Threading2) {
9016  ApiTestFuzzer::Setup(ApiTestFuzzer::SECOND_PART);
9017  ApiTestFuzzer::RunAllTests();
9018  ApiTestFuzzer::TearDown();
9019}
9020
9021
9022void ApiTestFuzzer::CallTest() {
9023  if (kLogThreading)
9024    printf("Start test %d\n", test_number_);
9025  CallTestNumber(test_number_);
9026  if (kLogThreading)
9027    printf("End test %d\n", test_number_);
9028}
9029
9030
9031static v8::Handle<Value> ThrowInJS(const v8::Arguments& args) {
9032  CHECK(v8::Locker::IsLocked());
9033  ApiTestFuzzer::Fuzz();
9034  v8::Unlocker unlocker;
9035  const char* code = "throw 7;";
9036  {
9037    v8::Locker nested_locker;
9038    v8::HandleScope scope;
9039    v8::Handle<Value> exception;
9040    { v8::TryCatch try_catch;
9041      v8::Handle<Value> value = CompileRun(code);
9042      CHECK(value.IsEmpty());
9043      CHECK(try_catch.HasCaught());
9044      // Make sure to wrap the exception in a new handle because
9045      // the handle returned from the TryCatch is destroyed
9046      // when the TryCatch is destroyed.
9047      exception = Local<Value>::New(try_catch.Exception());
9048    }
9049    return v8::ThrowException(exception);
9050  }
9051}
9052
9053
9054static v8::Handle<Value> ThrowInJSNoCatch(const v8::Arguments& args) {
9055  CHECK(v8::Locker::IsLocked());
9056  ApiTestFuzzer::Fuzz();
9057  v8::Unlocker unlocker;
9058  const char* code = "throw 7;";
9059  {
9060    v8::Locker nested_locker;
9061    v8::HandleScope scope;
9062    v8::Handle<Value> value = CompileRun(code);
9063    CHECK(value.IsEmpty());
9064    return v8_str("foo");
9065  }
9066}
9067
9068
9069// These are locking tests that don't need to be run again
9070// as part of the locking aggregation tests.
9071TEST(NestedLockers) {
9072  v8::Locker locker;
9073  CHECK(v8::Locker::IsLocked());
9074  v8::HandleScope scope;
9075  LocalContext env;
9076  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS);
9077  Local<Function> fun = fun_templ->GetFunction();
9078  env->Global()->Set(v8_str("throw_in_js"), fun);
9079  Local<Script> script = v8_compile("(function () {"
9080                                    "  try {"
9081                                    "    throw_in_js();"
9082                                    "    return 42;"
9083                                    "  } catch (e) {"
9084                                    "    return e * 13;"
9085                                    "  }"
9086                                    "})();");
9087  CHECK_EQ(91, script->Run()->Int32Value());
9088}
9089
9090
9091// These are locking tests that don't need to be run again
9092// as part of the locking aggregation tests.
9093TEST(NestedLockersNoTryCatch) {
9094  v8::Locker locker;
9095  v8::HandleScope scope;
9096  LocalContext env;
9097  Local<v8::FunctionTemplate> fun_templ =
9098      v8::FunctionTemplate::New(ThrowInJSNoCatch);
9099  Local<Function> fun = fun_templ->GetFunction();
9100  env->Global()->Set(v8_str("throw_in_js"), fun);
9101  Local<Script> script = v8_compile("(function () {"
9102                                    "  try {"
9103                                    "    throw_in_js();"
9104                                    "    return 42;"
9105                                    "  } catch (e) {"
9106                                    "    return e * 13;"
9107                                    "  }"
9108                                    "})();");
9109  CHECK_EQ(91, script->Run()->Int32Value());
9110}
9111
9112
9113THREADED_TEST(RecursiveLocking) {
9114  v8::Locker locker;
9115  {
9116    v8::Locker locker2;
9117    CHECK(v8::Locker::IsLocked());
9118  }
9119}
9120
9121
9122static v8::Handle<Value> UnlockForAMoment(const v8::Arguments& args) {
9123  ApiTestFuzzer::Fuzz();
9124  v8::Unlocker unlocker;
9125  return v8::Undefined();
9126}
9127
9128
9129THREADED_TEST(LockUnlockLock) {
9130  {
9131    v8::Locker locker;
9132    v8::HandleScope scope;
9133    LocalContext env;
9134    Local<v8::FunctionTemplate> fun_templ =
9135        v8::FunctionTemplate::New(UnlockForAMoment);
9136    Local<Function> fun = fun_templ->GetFunction();
9137    env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
9138    Local<Script> script = v8_compile("(function () {"
9139                                      "  unlock_for_a_moment();"
9140                                      "  return 42;"
9141                                      "})();");
9142    CHECK_EQ(42, script->Run()->Int32Value());
9143  }
9144  {
9145    v8::Locker locker;
9146    v8::HandleScope scope;
9147    LocalContext env;
9148    Local<v8::FunctionTemplate> fun_templ =
9149        v8::FunctionTemplate::New(UnlockForAMoment);
9150    Local<Function> fun = fun_templ->GetFunction();
9151    env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
9152    Local<Script> script = v8_compile("(function () {"
9153                                      "  unlock_for_a_moment();"
9154                                      "  return 42;"
9155                                      "})();");
9156    CHECK_EQ(42, script->Run()->Int32Value());
9157  }
9158}
9159
9160
9161static int GetGlobalObjectsCount() {
9162  int count = 0;
9163  i::HeapIterator it;
9164  for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
9165    if (object->IsJSGlobalObject()) count++;
9166  return count;
9167}
9168
9169
9170static void CheckSurvivingGlobalObjectsCount(int expected) {
9171  // We need to collect all garbage twice to be sure that everything
9172  // has been collected.  This is because inline caches are cleared in
9173  // the first garbage collection but some of the maps have already
9174  // been marked at that point.  Therefore some of the maps are not
9175  // collected until the second garbage collection.
9176  HEAP->CollectAllGarbage(false);
9177  HEAP->CollectAllGarbage(false);
9178  int count = GetGlobalObjectsCount();
9179#ifdef DEBUG
9180  if (count != expected) HEAP->TracePathToGlobal();
9181#endif
9182  CHECK_EQ(expected, count);
9183}
9184
9185
9186TEST(DontLeakGlobalObjects) {
9187  // Regression test for issues 1139850 and 1174891.
9188
9189  v8::V8::Initialize();
9190
9191  for (int i = 0; i < 5; i++) {
9192    { v8::HandleScope scope;
9193      LocalContext context;
9194    }
9195    CheckSurvivingGlobalObjectsCount(0);
9196
9197    { v8::HandleScope scope;
9198      LocalContext context;
9199      v8_compile("Date")->Run();
9200    }
9201    CheckSurvivingGlobalObjectsCount(0);
9202
9203    { v8::HandleScope scope;
9204      LocalContext context;
9205      v8_compile("/aaa/")->Run();
9206    }
9207    CheckSurvivingGlobalObjectsCount(0);
9208
9209    { v8::HandleScope scope;
9210      const char* extension_list[] = { "v8/gc" };
9211      v8::ExtensionConfiguration extensions(1, extension_list);
9212      LocalContext context(&extensions);
9213      v8_compile("gc();")->Run();
9214    }
9215    CheckSurvivingGlobalObjectsCount(0);
9216  }
9217}
9218
9219
9220v8::Persistent<v8::Object> some_object;
9221v8::Persistent<v8::Object> bad_handle;
9222
9223void NewPersistentHandleCallback(v8::Persistent<v8::Value> handle, void*) {
9224  v8::HandleScope scope;
9225  bad_handle = v8::Persistent<v8::Object>::New(some_object);
9226  handle.Dispose();
9227}
9228
9229
9230THREADED_TEST(NewPersistentHandleFromWeakCallback) {
9231  LocalContext context;
9232
9233  v8::Persistent<v8::Object> handle1, handle2;
9234  {
9235    v8::HandleScope scope;
9236    some_object = v8::Persistent<v8::Object>::New(v8::Object::New());
9237    handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
9238    handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
9239  }
9240  // Note: order is implementation dependent alas: currently
9241  // global handle nodes are processed by PostGarbageCollectionProcessing
9242  // in reverse allocation order, so if second allocated handle is deleted,
9243  // weak callback of the first handle would be able to 'reallocate' it.
9244  handle1.MakeWeak(NULL, NewPersistentHandleCallback);
9245  handle2.Dispose();
9246  HEAP->CollectAllGarbage(false);
9247}
9248
9249
9250v8::Persistent<v8::Object> to_be_disposed;
9251
9252void DisposeAndForceGcCallback(v8::Persistent<v8::Value> handle, void*) {
9253  to_be_disposed.Dispose();
9254  HEAP->CollectAllGarbage(false);
9255  handle.Dispose();
9256}
9257
9258
9259THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
9260  LocalContext context;
9261
9262  v8::Persistent<v8::Object> handle1, handle2;
9263  {
9264    v8::HandleScope scope;
9265    handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
9266    handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
9267  }
9268  handle1.MakeWeak(NULL, DisposeAndForceGcCallback);
9269  to_be_disposed = handle2;
9270  HEAP->CollectAllGarbage(false);
9271}
9272
9273void DisposingCallback(v8::Persistent<v8::Value> handle, void*) {
9274  handle.Dispose();
9275}
9276
9277void HandleCreatingCallback(v8::Persistent<v8::Value> handle, void*) {
9278  v8::HandleScope scope;
9279  v8::Persistent<v8::Object>::New(v8::Object::New());
9280  handle.Dispose();
9281}
9282
9283
9284THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
9285  LocalContext context;
9286
9287  v8::Persistent<v8::Object> handle1, handle2, handle3;
9288  {
9289    v8::HandleScope scope;
9290    handle3 = v8::Persistent<v8::Object>::New(v8::Object::New());
9291    handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
9292    handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
9293  }
9294  handle2.MakeWeak(NULL, DisposingCallback);
9295  handle3.MakeWeak(NULL, HandleCreatingCallback);
9296  HEAP->CollectAllGarbage(false);
9297}
9298
9299
9300THREADED_TEST(CheckForCrossContextObjectLiterals) {
9301  v8::V8::Initialize();
9302
9303  const int nof = 2;
9304  const char* sources[nof] = {
9305    "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
9306    "Object()"
9307  };
9308
9309  for (int i = 0; i < nof; i++) {
9310    const char* source = sources[i];
9311    { v8::HandleScope scope;
9312      LocalContext context;
9313      CompileRun(source);
9314    }
9315    { v8::HandleScope scope;
9316      LocalContext context;
9317      CompileRun(source);
9318    }
9319  }
9320}
9321
9322
9323static v8::Handle<Value> NestedScope(v8::Persistent<Context> env) {
9324  v8::HandleScope inner;
9325  env->Enter();
9326  v8::Handle<Value> three = v8_num(3);
9327  v8::Handle<Value> value = inner.Close(three);
9328  env->Exit();
9329  return value;
9330}
9331
9332
9333THREADED_TEST(NestedHandleScopeAndContexts) {
9334  v8::HandleScope outer;
9335  v8::Persistent<Context> env = Context::New();
9336  env->Enter();
9337  v8::Handle<Value> value = NestedScope(env);
9338  v8::Handle<String> str = value->ToString();
9339  env->Exit();
9340  env.Dispose();
9341}
9342
9343
9344THREADED_TEST(ExternalAllocatedMemory) {
9345  v8::HandleScope outer;
9346  v8::Persistent<Context> env = Context::New();
9347  const int kSize = 1024*1024;
9348  CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize), kSize);
9349  CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize), 0);
9350}
9351
9352
9353THREADED_TEST(DisposeEnteredContext) {
9354  v8::HandleScope scope;
9355  LocalContext outer;
9356  { v8::Persistent<v8::Context> inner = v8::Context::New();
9357    inner->Enter();
9358    inner.Dispose();
9359    inner.Clear();
9360    inner->Exit();
9361  }
9362}
9363
9364
9365// Regression test for issue 54, object templates with internal fields
9366// but no accessors or interceptors did not get their internal field
9367// count set on instances.
9368THREADED_TEST(Regress54) {
9369  v8::HandleScope outer;
9370  LocalContext context;
9371  static v8::Persistent<v8::ObjectTemplate> templ;
9372  if (templ.IsEmpty()) {
9373    v8::HandleScope inner;
9374    v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New();
9375    local->SetInternalFieldCount(1);
9376    templ = v8::Persistent<v8::ObjectTemplate>::New(inner.Close(local));
9377  }
9378  v8::Handle<v8::Object> result = templ->NewInstance();
9379  CHECK_EQ(1, result->InternalFieldCount());
9380}
9381
9382
9383// If part of the threaded tests, this test makes ThreadingTest fail
9384// on mac.
9385TEST(CatchStackOverflow) {
9386  v8::HandleScope scope;
9387  LocalContext context;
9388  v8::TryCatch try_catch;
9389  v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(
9390    "function f() {"
9391    "  return f();"
9392    "}"
9393    ""
9394    "f();"));
9395  v8::Handle<v8::Value> result = script->Run();
9396  CHECK(result.IsEmpty());
9397}
9398
9399
9400static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
9401                                    const char* resource_name,
9402                                    int line_offset) {
9403  v8::HandleScope scope;
9404  v8::TryCatch try_catch;
9405  v8::Handle<v8::Value> result = script->Run();
9406  CHECK(result.IsEmpty());
9407  CHECK(try_catch.HasCaught());
9408  v8::Handle<v8::Message> message = try_catch.Message();
9409  CHECK(!message.IsEmpty());
9410  CHECK_EQ(10 + line_offset, message->GetLineNumber());
9411  CHECK_EQ(91, message->GetStartPosition());
9412  CHECK_EQ(92, message->GetEndPosition());
9413  CHECK_EQ(2, message->GetStartColumn());
9414  CHECK_EQ(3, message->GetEndColumn());
9415  v8::String::AsciiValue line(message->GetSourceLine());
9416  CHECK_EQ("  throw 'nirk';", *line);
9417  v8::String::AsciiValue name(message->GetScriptResourceName());
9418  CHECK_EQ(resource_name, *name);
9419}
9420
9421
9422THREADED_TEST(TryCatchSourceInfo) {
9423  v8::HandleScope scope;
9424  LocalContext context;
9425  v8::Handle<v8::String> source = v8::String::New(
9426      "function Foo() {\n"
9427      "  return Bar();\n"
9428      "}\n"
9429      "\n"
9430      "function Bar() {\n"
9431      "  return Baz();\n"
9432      "}\n"
9433      "\n"
9434      "function Baz() {\n"
9435      "  throw 'nirk';\n"
9436      "}\n"
9437      "\n"
9438      "Foo();\n");
9439
9440  const char* resource_name;
9441  v8::Handle<v8::Script> script;
9442  resource_name = "test.js";
9443  script = v8::Script::Compile(source, v8::String::New(resource_name));
9444  CheckTryCatchSourceInfo(script, resource_name, 0);
9445
9446  resource_name = "test1.js";
9447  v8::ScriptOrigin origin1(v8::String::New(resource_name));
9448  script = v8::Script::Compile(source, &origin1);
9449  CheckTryCatchSourceInfo(script, resource_name, 0);
9450
9451  resource_name = "test2.js";
9452  v8::ScriptOrigin origin2(v8::String::New(resource_name), v8::Integer::New(7));
9453  script = v8::Script::Compile(source, &origin2);
9454  CheckTryCatchSourceInfo(script, resource_name, 7);
9455}
9456
9457
9458THREADED_TEST(CompilationCache) {
9459  v8::HandleScope scope;
9460  LocalContext context;
9461  v8::Handle<v8::String> source0 = v8::String::New("1234");
9462  v8::Handle<v8::String> source1 = v8::String::New("1234");
9463  v8::Handle<v8::Script> script0 =
9464      v8::Script::Compile(source0, v8::String::New("test.js"));
9465  v8::Handle<v8::Script> script1 =
9466      v8::Script::Compile(source1, v8::String::New("test.js"));
9467  v8::Handle<v8::Script> script2 =
9468      v8::Script::Compile(source0);  // different origin
9469  CHECK_EQ(1234, script0->Run()->Int32Value());
9470  CHECK_EQ(1234, script1->Run()->Int32Value());
9471  CHECK_EQ(1234, script2->Run()->Int32Value());
9472}
9473
9474
9475static v8::Handle<Value> FunctionNameCallback(const v8::Arguments& args) {
9476  ApiTestFuzzer::Fuzz();
9477  return v8_num(42);
9478}
9479
9480
9481THREADED_TEST(CallbackFunctionName) {
9482  v8::HandleScope scope;
9483  LocalContext context;
9484  Local<ObjectTemplate> t = ObjectTemplate::New();
9485  t->Set(v8_str("asdf"), v8::FunctionTemplate::New(FunctionNameCallback));
9486  context->Global()->Set(v8_str("obj"), t->NewInstance());
9487  v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
9488  CHECK(value->IsString());
9489  v8::String::AsciiValue name(value);
9490  CHECK_EQ("asdf", *name);
9491}
9492
9493
9494THREADED_TEST(DateAccess) {
9495  v8::HandleScope scope;
9496  LocalContext context;
9497  v8::Handle<v8::Value> date = v8::Date::New(1224744689038.0);
9498  CHECK(date->IsDate());
9499  CHECK_EQ(1224744689038.0, date.As<v8::Date>()->NumberValue());
9500}
9501
9502
9503void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) {
9504  v8::Handle<v8::Object> obj = val.As<v8::Object>();
9505  v8::Handle<v8::Array> props = obj->GetPropertyNames();
9506  CHECK_EQ(elmc, props->Length());
9507  for (int i = 0; i < elmc; i++) {
9508    v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
9509    CHECK_EQ(elmv[i], *elm);
9510  }
9511}
9512
9513
9514THREADED_TEST(PropertyEnumeration) {
9515  v8::HandleScope scope;
9516  LocalContext context;
9517  v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
9518      "var result = [];"
9519      "result[0] = {};"
9520      "result[1] = {a: 1, b: 2};"
9521      "result[2] = [1, 2, 3];"
9522      "var proto = {x: 1, y: 2, z: 3};"
9523      "var x = { __proto__: proto, w: 0, z: 1 };"
9524      "result[3] = x;"
9525      "result;"))->Run();
9526  v8::Handle<v8::Array> elms = obj.As<v8::Array>();
9527  CHECK_EQ(4, elms->Length());
9528  int elmc0 = 0;
9529  const char** elmv0 = NULL;
9530  CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
9531  int elmc1 = 2;
9532  const char* elmv1[] = {"a", "b"};
9533  CheckProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
9534  int elmc2 = 3;
9535  const char* elmv2[] = {"0", "1", "2"};
9536  CheckProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
9537  int elmc3 = 4;
9538  const char* elmv3[] = {"w", "z", "x", "y"};
9539  CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3);
9540}
9541
9542THREADED_TEST(PropertyEnumeration2) {
9543  v8::HandleScope scope;
9544  LocalContext context;
9545  v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
9546      "var result = [];"
9547      "result[0] = {};"
9548      "result[1] = {a: 1, b: 2};"
9549      "result[2] = [1, 2, 3];"
9550      "var proto = {x: 1, y: 2, z: 3};"
9551      "var x = { __proto__: proto, w: 0, z: 1 };"
9552      "result[3] = x;"
9553      "result;"))->Run();
9554  v8::Handle<v8::Array> elms = obj.As<v8::Array>();
9555  CHECK_EQ(4, elms->Length());
9556  int elmc0 = 0;
9557  const char** elmv0 = NULL;
9558  CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
9559
9560  v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(0));
9561  v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
9562  CHECK_EQ(0, props->Length());
9563  for (uint32_t i = 0; i < props->Length(); i++) {
9564    printf("p[%d]\n", i);
9565  }
9566}
9567
9568static bool NamedSetAccessBlocker(Local<v8::Object> obj,
9569                                  Local<Value> name,
9570                                  v8::AccessType type,
9571                                  Local<Value> data) {
9572  return type != v8::ACCESS_SET;
9573}
9574
9575
9576static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
9577                                    uint32_t key,
9578                                    v8::AccessType type,
9579                                    Local<Value> data) {
9580  return type != v8::ACCESS_SET;
9581}
9582
9583
9584THREADED_TEST(DisableAccessChecksWhileConfiguring) {
9585  v8::HandleScope scope;
9586  LocalContext context;
9587  Local<ObjectTemplate> templ = ObjectTemplate::New();
9588  templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
9589                                 IndexedSetAccessBlocker);
9590  templ->Set(v8_str("x"), v8::True());
9591  Local<v8::Object> instance = templ->NewInstance();
9592  context->Global()->Set(v8_str("obj"), instance);
9593  Local<Value> value = CompileRun("obj.x");
9594  CHECK(value->BooleanValue());
9595}
9596
9597
9598static bool NamedGetAccessBlocker(Local<v8::Object> obj,
9599                                  Local<Value> name,
9600                                  v8::AccessType type,
9601                                  Local<Value> data) {
9602  return false;
9603}
9604
9605
9606static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
9607                                    uint32_t key,
9608                                    v8::AccessType type,
9609                                    Local<Value> data) {
9610  return false;
9611}
9612
9613
9614
9615THREADED_TEST(AccessChecksReenabledCorrectly) {
9616  v8::HandleScope scope;
9617  LocalContext context;
9618  Local<ObjectTemplate> templ = ObjectTemplate::New();
9619  templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
9620                                 IndexedGetAccessBlocker);
9621  templ->Set(v8_str("a"), v8_str("a"));
9622  // Add more than 8 (see kMaxFastProperties) properties
9623  // so that the constructor will force copying map.
9624  // Cannot sprintf, gcc complains unsafety.
9625  char buf[4];
9626  for (char i = '0'; i <= '9' ; i++) {
9627    buf[0] = i;
9628    for (char j = '0'; j <= '9'; j++) {
9629      buf[1] = j;
9630      for (char k = '0'; k <= '9'; k++) {
9631        buf[2] = k;
9632        buf[3] = 0;
9633        templ->Set(v8_str(buf), v8::Number::New(k));
9634      }
9635    }
9636  }
9637
9638  Local<v8::Object> instance_1 = templ->NewInstance();
9639  context->Global()->Set(v8_str("obj_1"), instance_1);
9640
9641  Local<Value> value_1 = CompileRun("obj_1.a");
9642  CHECK(value_1->IsUndefined());
9643
9644  Local<v8::Object> instance_2 = templ->NewInstance();
9645  context->Global()->Set(v8_str("obj_2"), instance_2);
9646
9647  Local<Value> value_2 = CompileRun("obj_2.a");
9648  CHECK(value_2->IsUndefined());
9649}
9650
9651
9652// This tests that access check information remains on the global
9653// object template when creating contexts.
9654THREADED_TEST(AccessControlRepeatedContextCreation) {
9655  v8::HandleScope handle_scope;
9656  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
9657  global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
9658                                           IndexedSetAccessBlocker);
9659  i::Handle<i::ObjectTemplateInfo> internal_template =
9660      v8::Utils::OpenHandle(*global_template);
9661  CHECK(!internal_template->constructor()->IsUndefined());
9662  i::Handle<i::FunctionTemplateInfo> constructor(
9663      i::FunctionTemplateInfo::cast(internal_template->constructor()));
9664  CHECK(!constructor->access_check_info()->IsUndefined());
9665  v8::Persistent<Context> context0 = Context::New(NULL, global_template);
9666  CHECK(!constructor->access_check_info()->IsUndefined());
9667}
9668
9669
9670THREADED_TEST(TurnOnAccessCheck) {
9671  v8::HandleScope handle_scope;
9672
9673  // Create an environment with access check to the global object disabled by
9674  // default.
9675  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
9676  global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
9677                                           IndexedGetAccessBlocker,
9678                                           v8::Handle<v8::Value>(),
9679                                           false);
9680  v8::Persistent<Context> context = Context::New(NULL, global_template);
9681  Context::Scope context_scope(context);
9682
9683  // Set up a property and a number of functions.
9684  context->Global()->Set(v8_str("a"), v8_num(1));
9685  CompileRun("function f1() {return a;}"
9686             "function f2() {return a;}"
9687             "function g1() {return h();}"
9688             "function g2() {return h();}"
9689             "function h() {return 1;}");
9690  Local<Function> f1 =
9691      Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
9692  Local<Function> f2 =
9693      Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
9694  Local<Function> g1 =
9695      Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
9696  Local<Function> g2 =
9697      Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
9698  Local<Function> h =
9699      Local<Function>::Cast(context->Global()->Get(v8_str("h")));
9700
9701  // Get the global object.
9702  v8::Handle<v8::Object> global = context->Global();
9703
9704  // Call f1 one time and f2 a number of times. This will ensure that f1 still
9705  // uses the runtime system to retreive property a whereas f2 uses global load
9706  // inline cache.
9707  CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
9708  for (int i = 0; i < 4; i++) {
9709    CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
9710  }
9711
9712  // Same for g1 and g2.
9713  CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
9714  for (int i = 0; i < 4; i++) {
9715    CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
9716  }
9717
9718  // Detach the global and turn on access check.
9719  context->DetachGlobal();
9720  context->Global()->TurnOnAccessCheck();
9721
9722  // Failing access check to property get results in undefined.
9723  CHECK(f1->Call(global, 0, NULL)->IsUndefined());
9724  CHECK(f2->Call(global, 0, NULL)->IsUndefined());
9725
9726  // Failing access check to function call results in exception.
9727  CHECK(g1->Call(global, 0, NULL).IsEmpty());
9728  CHECK(g2->Call(global, 0, NULL).IsEmpty());
9729
9730  // No failing access check when just returning a constant.
9731  CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
9732}
9733
9734
9735v8::Handle<v8::String> a;
9736v8::Handle<v8::String> h;
9737
9738static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
9739                                       Local<Value> name,
9740                                       v8::AccessType type,
9741                                       Local<Value> data) {
9742  return !(name->Equals(a) || name->Equals(h));
9743}
9744
9745
9746THREADED_TEST(TurnOnAccessCheckAndRecompile) {
9747  v8::HandleScope handle_scope;
9748
9749  // Create an environment with access check to the global object disabled by
9750  // default. When the registered access checker will block access to properties
9751  // a and h
9752  a = v8_str("a");
9753  h = v8_str("h");
9754  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
9755  global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
9756                                           IndexedGetAccessBlocker,
9757                                           v8::Handle<v8::Value>(),
9758                                           false);
9759  v8::Persistent<Context> context = Context::New(NULL, global_template);
9760  Context::Scope context_scope(context);
9761
9762  // Set up a property and a number of functions.
9763  context->Global()->Set(v8_str("a"), v8_num(1));
9764  static const char* source = "function f1() {return a;}"
9765                              "function f2() {return a;}"
9766                              "function g1() {return h();}"
9767                              "function g2() {return h();}"
9768                              "function h() {return 1;}";
9769
9770  CompileRun(source);
9771  Local<Function> f1;
9772  Local<Function> f2;
9773  Local<Function> g1;
9774  Local<Function> g2;
9775  Local<Function> h;
9776  f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
9777  f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
9778  g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
9779  g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
9780  h =  Local<Function>::Cast(context->Global()->Get(v8_str("h")));
9781
9782  // Get the global object.
9783  v8::Handle<v8::Object> global = context->Global();
9784
9785  // Call f1 one time and f2 a number of times. This will ensure that f1 still
9786  // uses the runtime system to retreive property a whereas f2 uses global load
9787  // inline cache.
9788  CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
9789  for (int i = 0; i < 4; i++) {
9790    CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
9791  }
9792
9793  // Same for g1 and g2.
9794  CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
9795  for (int i = 0; i < 4; i++) {
9796    CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
9797  }
9798
9799  // Detach the global and turn on access check now blocking access to property
9800  // a and function h.
9801  context->DetachGlobal();
9802  context->Global()->TurnOnAccessCheck();
9803
9804  // Failing access check to property get results in undefined.
9805  CHECK(f1->Call(global, 0, NULL)->IsUndefined());
9806  CHECK(f2->Call(global, 0, NULL)->IsUndefined());
9807
9808  // Failing access check to function call results in exception.
9809  CHECK(g1->Call(global, 0, NULL).IsEmpty());
9810  CHECK(g2->Call(global, 0, NULL).IsEmpty());
9811
9812  // No failing access check when just returning a constant.
9813  CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
9814
9815  // Now compile the source again. And get the newly compiled functions, except
9816  // for h for which access is blocked.
9817  CompileRun(source);
9818  f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
9819  f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
9820  g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
9821  g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
9822  CHECK(context->Global()->Get(v8_str("h"))->IsUndefined());
9823
9824  // Failing access check to property get results in undefined.
9825  CHECK(f1->Call(global, 0, NULL)->IsUndefined());
9826  CHECK(f2->Call(global, 0, NULL)->IsUndefined());
9827
9828  // Failing access check to function call results in exception.
9829  CHECK(g1->Call(global, 0, NULL).IsEmpty());
9830  CHECK(g2->Call(global, 0, NULL).IsEmpty());
9831}
9832
9833
9834// This test verifies that pre-compilation (aka preparsing) can be called
9835// without initializing the whole VM. Thus we cannot run this test in a
9836// multi-threaded setup.
9837TEST(PreCompile) {
9838  // TODO(155): This test would break without the initialization of V8. This is
9839  // a workaround for now to make this test not fail.
9840  v8::V8::Initialize();
9841  const char* script = "function foo(a) { return a+1; }";
9842  v8::ScriptData* sd =
9843      v8::ScriptData::PreCompile(script, i::StrLength(script));
9844  CHECK_NE(sd->Length(), 0);
9845  CHECK_NE(sd->Data(), NULL);
9846  CHECK(!sd->HasError());
9847  delete sd;
9848}
9849
9850
9851TEST(PreCompileWithError) {
9852  v8::V8::Initialize();
9853  const char* script = "function foo(a) { return 1 * * 2; }";
9854  v8::ScriptData* sd =
9855      v8::ScriptData::PreCompile(script, i::StrLength(script));
9856  CHECK(sd->HasError());
9857  delete sd;
9858}
9859
9860
9861TEST(Regress31661) {
9862  v8::V8::Initialize();
9863  const char* script = " The Definintive Guide";
9864  v8::ScriptData* sd =
9865      v8::ScriptData::PreCompile(script, i::StrLength(script));
9866  CHECK(sd->HasError());
9867  delete sd;
9868}
9869
9870
9871// Tests that ScriptData can be serialized and deserialized.
9872TEST(PreCompileSerialization) {
9873  v8::V8::Initialize();
9874  const char* script = "function foo(a) { return a+1; }";
9875  v8::ScriptData* sd =
9876      v8::ScriptData::PreCompile(script, i::StrLength(script));
9877
9878  // Serialize.
9879  int serialized_data_length = sd->Length();
9880  char* serialized_data = i::NewArray<char>(serialized_data_length);
9881  memcpy(serialized_data, sd->Data(), serialized_data_length);
9882
9883  // Deserialize.
9884  v8::ScriptData* deserialized_sd =
9885      v8::ScriptData::New(serialized_data, serialized_data_length);
9886
9887  // Verify that the original is the same as the deserialized.
9888  CHECK_EQ(sd->Length(), deserialized_sd->Length());
9889  CHECK_EQ(0, memcmp(sd->Data(), deserialized_sd->Data(), sd->Length()));
9890  CHECK_EQ(sd->HasError(), deserialized_sd->HasError());
9891
9892  delete sd;
9893  delete deserialized_sd;
9894}
9895
9896
9897// Attempts to deserialize bad data.
9898TEST(PreCompileDeserializationError) {
9899  v8::V8::Initialize();
9900  const char* data = "DONT CARE";
9901  int invalid_size = 3;
9902  v8::ScriptData* sd = v8::ScriptData::New(data, invalid_size);
9903
9904  CHECK_EQ(0, sd->Length());
9905
9906  delete sd;
9907}
9908
9909
9910// Attempts to deserialize bad data.
9911TEST(PreCompileInvalidPreparseDataError) {
9912  v8::V8::Initialize();
9913  v8::HandleScope scope;
9914  LocalContext context;
9915
9916  const char* script = "function foo(){ return 5;}\n"
9917      "function bar(){ return 6 + 7;}  foo();";
9918  v8::ScriptData* sd =
9919      v8::ScriptData::PreCompile(script, i::StrLength(script));
9920  CHECK(!sd->HasError());
9921  // ScriptDataImpl private implementation details
9922  const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
9923  const int kFunctionEntrySize = i::FunctionEntry::kSize;
9924  const int kFunctionEntryStartOffset = 0;
9925  const int kFunctionEntryEndOffset = 1;
9926  unsigned* sd_data =
9927      reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
9928
9929  // Overwrite function bar's end position with 0.
9930  sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
9931  v8::TryCatch try_catch;
9932
9933  Local<String> source = String::New(script);
9934  Local<Script> compiled_script = Script::New(source, NULL, sd);
9935  CHECK(try_catch.HasCaught());
9936  String::AsciiValue exception_value(try_catch.Message()->Get());
9937  CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
9938           *exception_value);
9939
9940  try_catch.Reset();
9941  // Overwrite function bar's start position with 200.  The function entry
9942  // will not be found when searching for it by position.
9943  sd = v8::ScriptData::PreCompile(script, i::StrLength(script));
9944  sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
9945  sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
9946      200;
9947  compiled_script = Script::New(source, NULL, sd);
9948  CHECK(try_catch.HasCaught());
9949  String::AsciiValue second_exception_value(try_catch.Message()->Get());
9950  CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
9951           *second_exception_value);
9952
9953  delete sd;
9954}
9955
9956
9957// Verifies that the Handle<String> and const char* versions of the API produce
9958// the same results (at least for one trivial case).
9959TEST(PreCompileAPIVariationsAreSame) {
9960  v8::V8::Initialize();
9961  v8::HandleScope scope;
9962
9963  const char* cstring = "function foo(a) { return a+1; }";
9964
9965  v8::ScriptData* sd_from_cstring =
9966      v8::ScriptData::PreCompile(cstring, i::StrLength(cstring));
9967
9968  TestAsciiResource* resource = new TestAsciiResource(cstring);
9969  v8::ScriptData* sd_from_external_string = v8::ScriptData::PreCompile(
9970      v8::String::NewExternal(resource));
9971
9972  v8::ScriptData* sd_from_string = v8::ScriptData::PreCompile(
9973      v8::String::New(cstring));
9974
9975  CHECK_EQ(sd_from_cstring->Length(), sd_from_external_string->Length());
9976  CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
9977                     sd_from_external_string->Data(),
9978                     sd_from_cstring->Length()));
9979
9980  CHECK_EQ(sd_from_cstring->Length(), sd_from_string->Length());
9981  CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
9982                     sd_from_string->Data(),
9983                     sd_from_cstring->Length()));
9984
9985
9986  delete sd_from_cstring;
9987  delete sd_from_external_string;
9988  delete sd_from_string;
9989}
9990
9991
9992// This tests that we do not allow dictionary load/call inline caches
9993// to use functions that have not yet been compiled.  The potential
9994// problem of loading a function that has not yet been compiled can
9995// arise because we share code between contexts via the compilation
9996// cache.
9997THREADED_TEST(DictionaryICLoadedFunction) {
9998  v8::HandleScope scope;
9999  // Test LoadIC.
10000  for (int i = 0; i < 2; i++) {
10001    LocalContext context;
10002    context->Global()->Set(v8_str("tmp"), v8::True());
10003    context->Global()->Delete(v8_str("tmp"));
10004    CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
10005  }
10006  // Test CallIC.
10007  for (int i = 0; i < 2; i++) {
10008    LocalContext context;
10009    context->Global()->Set(v8_str("tmp"), v8::True());
10010    context->Global()->Delete(v8_str("tmp"));
10011    CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
10012  }
10013}
10014
10015
10016// Test that cross-context new calls use the context of the callee to
10017// create the new JavaScript object.
10018THREADED_TEST(CrossContextNew) {
10019  v8::HandleScope scope;
10020  v8::Persistent<Context> context0 = Context::New();
10021  v8::Persistent<Context> context1 = Context::New();
10022
10023  // Allow cross-domain access.
10024  Local<String> token = v8_str("<security token>");
10025  context0->SetSecurityToken(token);
10026  context1->SetSecurityToken(token);
10027
10028  // Set an 'x' property on the Object prototype and define a
10029  // constructor function in context0.
10030  context0->Enter();
10031  CompileRun("Object.prototype.x = 42; function C() {};");
10032  context0->Exit();
10033
10034  // Call the constructor function from context0 and check that the
10035  // result has the 'x' property.
10036  context1->Enter();
10037  context1->Global()->Set(v8_str("other"), context0->Global());
10038  Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
10039  CHECK(value->IsInt32());
10040  CHECK_EQ(42, value->Int32Value());
10041  context1->Exit();
10042
10043  // Dispose the contexts to allow them to be garbage collected.
10044  context0.Dispose();
10045  context1.Dispose();
10046}
10047
10048
10049class RegExpInterruptTest {
10050 public:
10051  RegExpInterruptTest() : block_(NULL) {}
10052  ~RegExpInterruptTest() { delete block_; }
10053  void RunTest() {
10054    block_ = i::OS::CreateSemaphore(0);
10055    gc_count_ = 0;
10056    gc_during_regexp_ = 0;
10057    regexp_success_ = false;
10058    gc_success_ = false;
10059    GCThread gc_thread(i::Isolate::Current(), this);
10060    gc_thread.Start();
10061    v8::Locker::StartPreemption(1);
10062
10063    LongRunningRegExp();
10064    {
10065      v8::Unlocker unlock;
10066      gc_thread.Join();
10067    }
10068    v8::Locker::StopPreemption();
10069    CHECK(regexp_success_);
10070    CHECK(gc_success_);
10071  }
10072 private:
10073  // Number of garbage collections required.
10074  static const int kRequiredGCs = 5;
10075
10076  class GCThread : public i::Thread {
10077   public:
10078    explicit GCThread(i::Isolate* isolate, RegExpInterruptTest* test)
10079        : Thread(isolate, "GCThread"), test_(test) {}
10080    virtual void Run() {
10081      test_->CollectGarbage();
10082    }
10083   private:
10084     RegExpInterruptTest* test_;
10085  };
10086
10087  void CollectGarbage() {
10088    block_->Wait();
10089    while (gc_during_regexp_ < kRequiredGCs) {
10090      {
10091        v8::Locker lock;
10092        // TODO(lrn): Perhaps create some garbage before collecting.
10093        HEAP->CollectAllGarbage(false);
10094        gc_count_++;
10095      }
10096      i::OS::Sleep(1);
10097    }
10098    gc_success_ = true;
10099  }
10100
10101  void LongRunningRegExp() {
10102    block_->Signal();  // Enable garbage collection thread on next preemption.
10103    int rounds = 0;
10104    while (gc_during_regexp_ < kRequiredGCs) {
10105      int gc_before = gc_count_;
10106      {
10107        // Match 15-30 "a"'s against 14 and a "b".
10108        const char* c_source =
10109            "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
10110            ".exec('aaaaaaaaaaaaaaab') === null";
10111        Local<String> source = String::New(c_source);
10112        Local<Script> script = Script::Compile(source);
10113        Local<Value> result = script->Run();
10114        if (!result->BooleanValue()) {
10115          gc_during_regexp_ = kRequiredGCs;  // Allow gc thread to exit.
10116          return;
10117        }
10118      }
10119      {
10120        // Match 15-30 "a"'s against 15 and a "b".
10121        const char* c_source =
10122            "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
10123            ".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'";
10124        Local<String> source = String::New(c_source);
10125        Local<Script> script = Script::Compile(source);
10126        Local<Value> result = script->Run();
10127        if (!result->BooleanValue()) {
10128          gc_during_regexp_ = kRequiredGCs;
10129          return;
10130        }
10131      }
10132      int gc_after = gc_count_;
10133      gc_during_regexp_ += gc_after - gc_before;
10134      rounds++;
10135      i::OS::Sleep(1);
10136    }
10137    regexp_success_ = true;
10138  }
10139
10140  i::Semaphore* block_;
10141  int gc_count_;
10142  int gc_during_regexp_;
10143  bool regexp_success_;
10144  bool gc_success_;
10145};
10146
10147
10148// Test that a regular expression execution can be interrupted and
10149// survive a garbage collection.
10150TEST(RegExpInterruption) {
10151  v8::Locker lock;
10152  v8::V8::Initialize();
10153  v8::HandleScope scope;
10154  Local<Context> local_env;
10155  {
10156    LocalContext env;
10157    local_env = env.local();
10158  }
10159
10160  // Local context should still be live.
10161  CHECK(!local_env.IsEmpty());
10162  local_env->Enter();
10163
10164  // Should complete without problems.
10165  RegExpInterruptTest().RunTest();
10166
10167  local_env->Exit();
10168}
10169
10170
10171class ApplyInterruptTest {
10172 public:
10173  ApplyInterruptTest() : block_(NULL) {}
10174  ~ApplyInterruptTest() { delete block_; }
10175  void RunTest() {
10176    block_ = i::OS::CreateSemaphore(0);
10177    gc_count_ = 0;
10178    gc_during_apply_ = 0;
10179    apply_success_ = false;
10180    gc_success_ = false;
10181    GCThread gc_thread(i::Isolate::Current(), this);
10182    gc_thread.Start();
10183    v8::Locker::StartPreemption(1);
10184
10185    LongRunningApply();
10186    {
10187      v8::Unlocker unlock;
10188      gc_thread.Join();
10189    }
10190    v8::Locker::StopPreemption();
10191    CHECK(apply_success_);
10192    CHECK(gc_success_);
10193  }
10194 private:
10195  // Number of garbage collections required.
10196  static const int kRequiredGCs = 2;
10197
10198  class GCThread : public i::Thread {
10199   public:
10200    explicit GCThread(i::Isolate* isolate, ApplyInterruptTest* test)
10201        : Thread(isolate, "GCThread"), test_(test) {}
10202    virtual void Run() {
10203      test_->CollectGarbage();
10204    }
10205   private:
10206     ApplyInterruptTest* test_;
10207  };
10208
10209  void CollectGarbage() {
10210    block_->Wait();
10211    while (gc_during_apply_ < kRequiredGCs) {
10212      {
10213        v8::Locker lock;
10214        HEAP->CollectAllGarbage(false);
10215        gc_count_++;
10216      }
10217      i::OS::Sleep(1);
10218    }
10219    gc_success_ = true;
10220  }
10221
10222  void LongRunningApply() {
10223    block_->Signal();
10224    int rounds = 0;
10225    while (gc_during_apply_ < kRequiredGCs) {
10226      int gc_before = gc_count_;
10227      {
10228        const char* c_source =
10229            "function do_very_little(bar) {"
10230            "  this.foo = bar;"
10231            "}"
10232            "for (var i = 0; i < 100000; i++) {"
10233            "  do_very_little.apply(this, ['bar']);"
10234            "}";
10235        Local<String> source = String::New(c_source);
10236        Local<Script> script = Script::Compile(source);
10237        Local<Value> result = script->Run();
10238        // Check that no exception was thrown.
10239        CHECK(!result.IsEmpty());
10240      }
10241      int gc_after = gc_count_;
10242      gc_during_apply_ += gc_after - gc_before;
10243      rounds++;
10244    }
10245    apply_success_ = true;
10246  }
10247
10248  i::Semaphore* block_;
10249  int gc_count_;
10250  int gc_during_apply_;
10251  bool apply_success_;
10252  bool gc_success_;
10253};
10254
10255
10256// Test that nothing bad happens if we get a preemption just when we were
10257// about to do an apply().
10258TEST(ApplyInterruption) {
10259  v8::Locker lock;
10260  v8::V8::Initialize();
10261  v8::HandleScope scope;
10262  Local<Context> local_env;
10263  {
10264    LocalContext env;
10265    local_env = env.local();
10266  }
10267
10268  // Local context should still be live.
10269  CHECK(!local_env.IsEmpty());
10270  local_env->Enter();
10271
10272  // Should complete without problems.
10273  ApplyInterruptTest().RunTest();
10274
10275  local_env->Exit();
10276}
10277
10278
10279// Verify that we can clone an object
10280TEST(ObjectClone) {
10281  v8::HandleScope scope;
10282  LocalContext env;
10283
10284  const char* sample =
10285    "var rv = {};"      \
10286    "rv.alpha = 'hello';" \
10287    "rv.beta = 123;"     \
10288    "rv;";
10289
10290  // Create an object, verify basics.
10291  Local<Value> val = CompileRun(sample);
10292  CHECK(val->IsObject());
10293  Local<v8::Object> obj = val.As<v8::Object>();
10294  obj->Set(v8_str("gamma"), v8_str("cloneme"));
10295
10296  CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
10297  CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
10298  CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
10299
10300  // Clone it.
10301  Local<v8::Object> clone = obj->Clone();
10302  CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
10303  CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta")));
10304  CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
10305
10306  // Set a property on the clone, verify each object.
10307  clone->Set(v8_str("beta"), v8::Integer::New(456));
10308  CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
10309  CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta")));
10310}
10311
10312
10313class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
10314 public:
10315  explicit AsciiVectorResource(i::Vector<const char> vector)
10316      : data_(vector) {}
10317  virtual ~AsciiVectorResource() {}
10318  virtual size_t length() const { return data_.length(); }
10319  virtual const char* data() const { return data_.start(); }
10320 private:
10321  i::Vector<const char> data_;
10322};
10323
10324
10325class UC16VectorResource : public v8::String::ExternalStringResource {
10326 public:
10327  explicit UC16VectorResource(i::Vector<const i::uc16> vector)
10328      : data_(vector) {}
10329  virtual ~UC16VectorResource() {}
10330  virtual size_t length() const { return data_.length(); }
10331  virtual const i::uc16* data() const { return data_.start(); }
10332 private:
10333  i::Vector<const i::uc16> data_;
10334};
10335
10336
10337static void MorphAString(i::String* string,
10338                         AsciiVectorResource* ascii_resource,
10339                         UC16VectorResource* uc16_resource) {
10340  CHECK(i::StringShape(string).IsExternal());
10341  if (string->IsAsciiRepresentation()) {
10342    // Check old map is not symbol or long.
10343    CHECK(string->map() == HEAP->external_ascii_string_map());
10344    // Morph external string to be TwoByte string.
10345    string->set_map(HEAP->external_string_map());
10346    i::ExternalTwoByteString* morphed =
10347         i::ExternalTwoByteString::cast(string);
10348    morphed->set_resource(uc16_resource);
10349  } else {
10350    // Check old map is not symbol or long.
10351    CHECK(string->map() == HEAP->external_string_map());
10352    // Morph external string to be ASCII string.
10353    string->set_map(HEAP->external_ascii_string_map());
10354    i::ExternalAsciiString* morphed =
10355         i::ExternalAsciiString::cast(string);
10356    morphed->set_resource(ascii_resource);
10357  }
10358}
10359
10360
10361// Test that we can still flatten a string if the components it is built up
10362// from have been turned into 16 bit strings in the mean time.
10363THREADED_TEST(MorphCompositeStringTest) {
10364  const char* c_string = "Now is the time for all good men"
10365                         " to come to the aid of the party";
10366  uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
10367  {
10368    v8::HandleScope scope;
10369    LocalContext env;
10370    AsciiVectorResource ascii_resource(
10371        i::Vector<const char>(c_string, i::StrLength(c_string)));
10372    UC16VectorResource uc16_resource(
10373        i::Vector<const uint16_t>(two_byte_string,
10374                                  i::StrLength(c_string)));
10375
10376    Local<String> lhs(v8::Utils::ToLocal(
10377        FACTORY->NewExternalStringFromAscii(&ascii_resource)));
10378    Local<String> rhs(v8::Utils::ToLocal(
10379        FACTORY->NewExternalStringFromAscii(&ascii_resource)));
10380
10381    env->Global()->Set(v8_str("lhs"), lhs);
10382    env->Global()->Set(v8_str("rhs"), rhs);
10383
10384    CompileRun(
10385        "var cons = lhs + rhs;"
10386        "var slice = lhs.substring(1, lhs.length - 1);"
10387        "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
10388
10389    MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
10390    MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
10391
10392    // Now do some stuff to make sure the strings are flattened, etc.
10393    CompileRun(
10394        "/[^a-z]/.test(cons);"
10395        "/[^a-z]/.test(slice);"
10396        "/[^a-z]/.test(slice_on_cons);");
10397    const char* expected_cons =
10398        "Now is the time for all good men to come to the aid of the party"
10399        "Now is the time for all good men to come to the aid of the party";
10400    const char* expected_slice =
10401        "ow is the time for all good men to come to the aid of the part";
10402    const char* expected_slice_on_cons =
10403        "ow is the time for all good men to come to the aid of the party"
10404        "Now is the time for all good men to come to the aid of the part";
10405    CHECK_EQ(String::New(expected_cons),
10406             env->Global()->Get(v8_str("cons")));
10407    CHECK_EQ(String::New(expected_slice),
10408             env->Global()->Get(v8_str("slice")));
10409    CHECK_EQ(String::New(expected_slice_on_cons),
10410             env->Global()->Get(v8_str("slice_on_cons")));
10411  }
10412  i::DeleteArray(two_byte_string);
10413}
10414
10415
10416TEST(CompileExternalTwoByteSource) {
10417  v8::HandleScope scope;
10418  LocalContext context;
10419
10420  // This is a very short list of sources, which currently is to check for a
10421  // regression caused by r2703.
10422  const char* ascii_sources[] = {
10423    "0.5",
10424    "-0.5",   // This mainly testes PushBack in the Scanner.
10425    "--0.5",  // This mainly testes PushBack in the Scanner.
10426    NULL
10427  };
10428
10429  // Compile the sources as external two byte strings.
10430  for (int i = 0; ascii_sources[i] != NULL; i++) {
10431    uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
10432    UC16VectorResource uc16_resource(
10433        i::Vector<const uint16_t>(two_byte_string,
10434                                  i::StrLength(ascii_sources[i])));
10435    v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource);
10436    v8::Script::Compile(source);
10437    i::DeleteArray(two_byte_string);
10438  }
10439}
10440
10441
10442class RegExpStringModificationTest {
10443 public:
10444  RegExpStringModificationTest()
10445      : block_(i::OS::CreateSemaphore(0)),
10446        morphs_(0),
10447        morphs_during_regexp_(0),
10448        ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)),
10449        uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {}
10450  ~RegExpStringModificationTest() { delete block_; }
10451  void RunTest() {
10452    regexp_success_ = false;
10453    morph_success_ = false;
10454
10455    // Initialize the contents of two_byte_content_ to be a uc16 representation
10456    // of "aaaaaaaaaaaaaab".
10457    for (int i = 0; i < 14; i++) {
10458      two_byte_content_[i] = 'a';
10459    }
10460    two_byte_content_[14] = 'b';
10461
10462    // Create the input string for the regexp - the one we are going to change
10463    // properties of.
10464    input_ = FACTORY->NewExternalStringFromAscii(&ascii_resource_);
10465
10466    // Inject the input as a global variable.
10467    i::Handle<i::String> input_name =
10468        FACTORY->NewStringFromAscii(i::Vector<const char>("input", 5));
10469    i::Isolate::Current()->global_context()->global()->SetProperty(
10470        *input_name,
10471        *input_,
10472        NONE,
10473        i::kNonStrictMode)->ToObjectChecked();
10474
10475    MorphThread morph_thread(i::Isolate::Current(), this);
10476    morph_thread.Start();
10477    v8::Locker::StartPreemption(1);
10478    LongRunningRegExp();
10479    {
10480      v8::Unlocker unlock;
10481      morph_thread.Join();
10482    }
10483    v8::Locker::StopPreemption();
10484    CHECK(regexp_success_);
10485    CHECK(morph_success_);
10486  }
10487 private:
10488
10489  // Number of string modifications required.
10490  static const int kRequiredModifications = 5;
10491  static const int kMaxModifications = 100;
10492
10493  class MorphThread : public i::Thread {
10494   public:
10495    explicit MorphThread(i::Isolate* isolate,
10496                         RegExpStringModificationTest* test)
10497        : Thread(isolate, "MorphThread"), test_(test) {}
10498    virtual void Run() {
10499      test_->MorphString();
10500    }
10501   private:
10502     RegExpStringModificationTest* test_;
10503  };
10504
10505  void MorphString() {
10506    block_->Wait();
10507    while (morphs_during_regexp_ < kRequiredModifications &&
10508           morphs_ < kMaxModifications) {
10509      {
10510        v8::Locker lock;
10511        // Swap string between ascii and two-byte representation.
10512        i::String* string = *input_;
10513        MorphAString(string, &ascii_resource_, &uc16_resource_);
10514        morphs_++;
10515      }
10516      i::OS::Sleep(1);
10517    }
10518    morph_success_ = true;
10519  }
10520
10521  void LongRunningRegExp() {
10522    block_->Signal();  // Enable morphing thread on next preemption.
10523    while (morphs_during_regexp_ < kRequiredModifications &&
10524           morphs_ < kMaxModifications) {
10525      int morphs_before = morphs_;
10526      {
10527        v8::HandleScope scope;
10528        // Match 15-30 "a"'s against 14 and a "b".
10529        const char* c_source =
10530            "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
10531            ".exec(input) === null";
10532        Local<String> source = String::New(c_source);
10533        Local<Script> script = Script::Compile(source);
10534        Local<Value> result = script->Run();
10535        CHECK(result->IsTrue());
10536      }
10537      int morphs_after = morphs_;
10538      morphs_during_regexp_ += morphs_after - morphs_before;
10539    }
10540    regexp_success_ = true;
10541  }
10542
10543  i::uc16 two_byte_content_[15];
10544  i::Semaphore* block_;
10545  int morphs_;
10546  int morphs_during_regexp_;
10547  bool regexp_success_;
10548  bool morph_success_;
10549  i::Handle<i::String> input_;
10550  AsciiVectorResource ascii_resource_;
10551  UC16VectorResource uc16_resource_;
10552};
10553
10554
10555// Test that a regular expression execution can be interrupted and
10556// the string changed without failing.
10557TEST(RegExpStringModification) {
10558  v8::Locker lock;
10559  v8::V8::Initialize();
10560  v8::HandleScope scope;
10561  Local<Context> local_env;
10562  {
10563    LocalContext env;
10564    local_env = env.local();
10565  }
10566
10567  // Local context should still be live.
10568  CHECK(!local_env.IsEmpty());
10569  local_env->Enter();
10570
10571  // Should complete without problems.
10572  RegExpStringModificationTest().RunTest();
10573
10574  local_env->Exit();
10575}
10576
10577
10578// Test that we can set a property on the global object even if there
10579// is a read-only property in the prototype chain.
10580TEST(ReadOnlyPropertyInGlobalProto) {
10581  v8::HandleScope scope;
10582  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
10583  LocalContext context(0, templ);
10584  v8::Handle<v8::Object> global = context->Global();
10585  v8::Handle<v8::Object> global_proto =
10586      v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
10587  global_proto->Set(v8_str("x"), v8::Integer::New(0), v8::ReadOnly);
10588  global_proto->Set(v8_str("y"), v8::Integer::New(0), v8::ReadOnly);
10589  // Check without 'eval' or 'with'.
10590  v8::Handle<v8::Value> res =
10591      CompileRun("function f() { x = 42; return x; }; f()");
10592  // Check with 'eval'.
10593  res = CompileRun("function f() { eval('1'); y = 42; return y; }; f()");
10594  CHECK_EQ(v8::Integer::New(42), res);
10595  // Check with 'with'.
10596  res = CompileRun("function f() { with (this) { y = 42 }; return y; }; f()");
10597  CHECK_EQ(v8::Integer::New(42), res);
10598}
10599
10600static int force_set_set_count = 0;
10601static int force_set_get_count = 0;
10602bool pass_on_get = false;
10603
10604static v8::Handle<v8::Value> ForceSetGetter(v8::Local<v8::String> name,
10605                                            const v8::AccessorInfo& info) {
10606  force_set_get_count++;
10607  if (pass_on_get) {
10608    return v8::Handle<v8::Value>();
10609  } else {
10610    return v8::Int32::New(3);
10611  }
10612}
10613
10614static void ForceSetSetter(v8::Local<v8::String> name,
10615                           v8::Local<v8::Value> value,
10616                           const v8::AccessorInfo& info) {
10617  force_set_set_count++;
10618}
10619
10620static v8::Handle<v8::Value> ForceSetInterceptSetter(
10621    v8::Local<v8::String> name,
10622    v8::Local<v8::Value> value,
10623    const v8::AccessorInfo& info) {
10624  force_set_set_count++;
10625  return v8::Undefined();
10626}
10627
10628TEST(ForceSet) {
10629  force_set_get_count = 0;
10630  force_set_set_count = 0;
10631  pass_on_get = false;
10632
10633  v8::HandleScope scope;
10634  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
10635  v8::Handle<v8::String> access_property = v8::String::New("a");
10636  templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
10637  LocalContext context(NULL, templ);
10638  v8::Handle<v8::Object> global = context->Global();
10639
10640  // Ordinary properties
10641  v8::Handle<v8::String> simple_property = v8::String::New("p");
10642  global->Set(simple_property, v8::Int32::New(4), v8::ReadOnly);
10643  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
10644  // This should fail because the property is read-only
10645  global->Set(simple_property, v8::Int32::New(5));
10646  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
10647  // This should succeed even though the property is read-only
10648  global->ForceSet(simple_property, v8::Int32::New(6));
10649  CHECK_EQ(6, global->Get(simple_property)->Int32Value());
10650
10651  // Accessors
10652  CHECK_EQ(0, force_set_set_count);
10653  CHECK_EQ(0, force_set_get_count);
10654  CHECK_EQ(3, global->Get(access_property)->Int32Value());
10655  // CHECK_EQ the property shouldn't override it, just call the setter
10656  // which in this case does nothing.
10657  global->Set(access_property, v8::Int32::New(7));
10658  CHECK_EQ(3, global->Get(access_property)->Int32Value());
10659  CHECK_EQ(1, force_set_set_count);
10660  CHECK_EQ(2, force_set_get_count);
10661  // Forcing the property to be set should override the accessor without
10662  // calling it
10663  global->ForceSet(access_property, v8::Int32::New(8));
10664  CHECK_EQ(8, global->Get(access_property)->Int32Value());
10665  CHECK_EQ(1, force_set_set_count);
10666  CHECK_EQ(2, force_set_get_count);
10667}
10668
10669TEST(ForceSetWithInterceptor) {
10670  force_set_get_count = 0;
10671  force_set_set_count = 0;
10672  pass_on_get = false;
10673
10674  v8::HandleScope scope;
10675  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
10676  templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
10677  LocalContext context(NULL, templ);
10678  v8::Handle<v8::Object> global = context->Global();
10679
10680  v8::Handle<v8::String> some_property = v8::String::New("a");
10681  CHECK_EQ(0, force_set_set_count);
10682  CHECK_EQ(0, force_set_get_count);
10683  CHECK_EQ(3, global->Get(some_property)->Int32Value());
10684  // Setting the property shouldn't override it, just call the setter
10685  // which in this case does nothing.
10686  global->Set(some_property, v8::Int32::New(7));
10687  CHECK_EQ(3, global->Get(some_property)->Int32Value());
10688  CHECK_EQ(1, force_set_set_count);
10689  CHECK_EQ(2, force_set_get_count);
10690  // Getting the property when the interceptor returns an empty handle
10691  // should yield undefined, since the property isn't present on the
10692  // object itself yet.
10693  pass_on_get = true;
10694  CHECK(global->Get(some_property)->IsUndefined());
10695  CHECK_EQ(1, force_set_set_count);
10696  CHECK_EQ(3, force_set_get_count);
10697  // Forcing the property to be set should cause the value to be
10698  // set locally without calling the interceptor.
10699  global->ForceSet(some_property, v8::Int32::New(8));
10700  CHECK_EQ(8, global->Get(some_property)->Int32Value());
10701  CHECK_EQ(1, force_set_set_count);
10702  CHECK_EQ(4, force_set_get_count);
10703  // Reenabling the interceptor should cause it to take precedence over
10704  // the property
10705  pass_on_get = false;
10706  CHECK_EQ(3, global->Get(some_property)->Int32Value());
10707  CHECK_EQ(1, force_set_set_count);
10708  CHECK_EQ(5, force_set_get_count);
10709  // The interceptor should also work for other properties
10710  CHECK_EQ(3, global->Get(v8::String::New("b"))->Int32Value());
10711  CHECK_EQ(1, force_set_set_count);
10712  CHECK_EQ(6, force_set_get_count);
10713}
10714
10715
10716THREADED_TEST(ForceDelete) {
10717  v8::HandleScope scope;
10718  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
10719  LocalContext context(NULL, templ);
10720  v8::Handle<v8::Object> global = context->Global();
10721
10722  // Ordinary properties
10723  v8::Handle<v8::String> simple_property = v8::String::New("p");
10724  global->Set(simple_property, v8::Int32::New(4), v8::DontDelete);
10725  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
10726  // This should fail because the property is dont-delete.
10727  CHECK(!global->Delete(simple_property));
10728  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
10729  // This should succeed even though the property is dont-delete.
10730  CHECK(global->ForceDelete(simple_property));
10731  CHECK(global->Get(simple_property)->IsUndefined());
10732}
10733
10734
10735static int force_delete_interceptor_count = 0;
10736static bool pass_on_delete = false;
10737
10738
10739static v8::Handle<v8::Boolean> ForceDeleteDeleter(
10740    v8::Local<v8::String> name,
10741    const v8::AccessorInfo& info) {
10742  force_delete_interceptor_count++;
10743  if (pass_on_delete) {
10744    return v8::Handle<v8::Boolean>();
10745  } else {
10746    return v8::True();
10747  }
10748}
10749
10750
10751THREADED_TEST(ForceDeleteWithInterceptor) {
10752  force_delete_interceptor_count = 0;
10753  pass_on_delete = false;
10754
10755  v8::HandleScope scope;
10756  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
10757  templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
10758  LocalContext context(NULL, templ);
10759  v8::Handle<v8::Object> global = context->Global();
10760
10761  v8::Handle<v8::String> some_property = v8::String::New("a");
10762  global->Set(some_property, v8::Integer::New(42), v8::DontDelete);
10763
10764  // Deleting a property should get intercepted and nothing should
10765  // happen.
10766  CHECK_EQ(0, force_delete_interceptor_count);
10767  CHECK(global->Delete(some_property));
10768  CHECK_EQ(1, force_delete_interceptor_count);
10769  CHECK_EQ(42, global->Get(some_property)->Int32Value());
10770  // Deleting the property when the interceptor returns an empty
10771  // handle should not delete the property since it is DontDelete.
10772  pass_on_delete = true;
10773  CHECK(!global->Delete(some_property));
10774  CHECK_EQ(2, force_delete_interceptor_count);
10775  CHECK_EQ(42, global->Get(some_property)->Int32Value());
10776  // Forcing the property to be deleted should delete the value
10777  // without calling the interceptor.
10778  CHECK(global->ForceDelete(some_property));
10779  CHECK(global->Get(some_property)->IsUndefined());
10780  CHECK_EQ(2, force_delete_interceptor_count);
10781}
10782
10783
10784// Make sure that forcing a delete invalidates any IC stubs, so we
10785// don't read the hole value.
10786THREADED_TEST(ForceDeleteIC) {
10787  v8::HandleScope scope;
10788  LocalContext context;
10789  // Create a DontDelete variable on the global object.
10790  CompileRun("this.__proto__ = { foo: 'horse' };"
10791             "var foo = 'fish';"
10792             "function f() { return foo.length; }");
10793  // Initialize the IC for foo in f.
10794  CompileRun("for (var i = 0; i < 4; i++) f();");
10795  // Make sure the value of foo is correct before the deletion.
10796  CHECK_EQ(4, CompileRun("f()")->Int32Value());
10797  // Force the deletion of foo.
10798  CHECK(context->Global()->ForceDelete(v8_str("foo")));
10799  // Make sure the value for foo is read from the prototype, and that
10800  // we don't get in trouble with reading the deleted cell value
10801  // sentinel.
10802  CHECK_EQ(5, CompileRun("f()")->Int32Value());
10803}
10804
10805
10806v8::Persistent<Context> calling_context0;
10807v8::Persistent<Context> calling_context1;
10808v8::Persistent<Context> calling_context2;
10809
10810
10811// Check that the call to the callback is initiated in
10812// calling_context2, the directly calling context is calling_context1
10813// and the callback itself is in calling_context0.
10814static v8::Handle<Value> GetCallingContextCallback(const v8::Arguments& args) {
10815  ApiTestFuzzer::Fuzz();
10816  CHECK(Context::GetCurrent() == calling_context0);
10817  CHECK(Context::GetCalling() == calling_context1);
10818  CHECK(Context::GetEntered() == calling_context2);
10819  return v8::Integer::New(42);
10820}
10821
10822
10823THREADED_TEST(GetCallingContext) {
10824  v8::HandleScope scope;
10825
10826  calling_context0 = Context::New();
10827  calling_context1 = Context::New();
10828  calling_context2 = Context::New();
10829
10830  // Allow cross-domain access.
10831  Local<String> token = v8_str("<security token>");
10832  calling_context0->SetSecurityToken(token);
10833  calling_context1->SetSecurityToken(token);
10834  calling_context2->SetSecurityToken(token);
10835
10836  // Create an object with a C++ callback in context0.
10837  calling_context0->Enter();
10838  Local<v8::FunctionTemplate> callback_templ =
10839      v8::FunctionTemplate::New(GetCallingContextCallback);
10840  calling_context0->Global()->Set(v8_str("callback"),
10841                                  callback_templ->GetFunction());
10842  calling_context0->Exit();
10843
10844  // Expose context0 in context1 and setup a function that calls the
10845  // callback function.
10846  calling_context1->Enter();
10847  calling_context1->Global()->Set(v8_str("context0"),
10848                                  calling_context0->Global());
10849  CompileRun("function f() { context0.callback() }");
10850  calling_context1->Exit();
10851
10852  // Expose context1 in context2 and call the callback function in
10853  // context0 indirectly through f in context1.
10854  calling_context2->Enter();
10855  calling_context2->Global()->Set(v8_str("context1"),
10856                                  calling_context1->Global());
10857  CompileRun("context1.f()");
10858  calling_context2->Exit();
10859
10860  // Dispose the contexts to allow them to be garbage collected.
10861  calling_context0.Dispose();
10862  calling_context1.Dispose();
10863  calling_context2.Dispose();
10864  calling_context0.Clear();
10865  calling_context1.Clear();
10866  calling_context2.Clear();
10867}
10868
10869
10870// Check that a variable declaration with no explicit initialization
10871// value does not shadow an existing property in the prototype chain.
10872//
10873// This is consistent with Firefox and Safari.
10874//
10875// See http://crbug.com/12548.
10876THREADED_TEST(InitGlobalVarInProtoChain) {
10877  v8::HandleScope scope;
10878  LocalContext context;
10879  // Introduce a variable in the prototype chain.
10880  CompileRun("__proto__.x = 42");
10881  v8::Handle<v8::Value> result = CompileRun("var x; x");
10882  CHECK(!result->IsUndefined());
10883  CHECK_EQ(42, result->Int32Value());
10884}
10885
10886
10887// Regression test for issue 398.
10888// If a function is added to an object, creating a constant function
10889// field, and the result is cloned, replacing the constant function on the
10890// original should not affect the clone.
10891// See http://code.google.com/p/v8/issues/detail?id=398
10892THREADED_TEST(ReplaceConstantFunction) {
10893  v8::HandleScope scope;
10894  LocalContext context;
10895  v8::Handle<v8::Object> obj = v8::Object::New();
10896  v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
10897  v8::Handle<v8::String> foo_string = v8::String::New("foo");
10898  obj->Set(foo_string, func_templ->GetFunction());
10899  v8::Handle<v8::Object> obj_clone = obj->Clone();
10900  obj_clone->Set(foo_string, v8::String::New("Hello"));
10901  CHECK(!obj->Get(foo_string)->IsUndefined());
10902}
10903
10904
10905// Regression test for http://crbug.com/16276.
10906THREADED_TEST(Regress16276) {
10907  v8::HandleScope scope;
10908  LocalContext context;
10909  // Force the IC in f to be a dictionary load IC.
10910  CompileRun("function f(obj) { return obj.x; }\n"
10911             "var obj = { x: { foo: 42 }, y: 87 };\n"
10912             "var x = obj.x;\n"
10913             "delete obj.y;\n"
10914             "for (var i = 0; i < 5; i++) f(obj);");
10915  // Detach the global object to make 'this' refer directly to the
10916  // global object (not the proxy), and make sure that the dictionary
10917  // load IC doesn't mess up loading directly from the global object.
10918  context->DetachGlobal();
10919  CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value());
10920}
10921
10922
10923THREADED_TEST(PixelArray) {
10924  v8::HandleScope scope;
10925  LocalContext context;
10926  const int kElementCount = 260;
10927  uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
10928  i::Handle<i::ExternalPixelArray> pixels =
10929      i::Handle<i::ExternalPixelArray>::cast(
10930          FACTORY->NewExternalArray(kElementCount,
10931                                       v8::kExternalPixelArray,
10932                                       pixel_data));
10933  HEAP->CollectAllGarbage(false);  // Force GC to trigger verification.
10934  for (int i = 0; i < kElementCount; i++) {
10935    pixels->set(i, i % 256);
10936  }
10937  HEAP->CollectAllGarbage(false);  // Force GC to trigger verification.
10938  for (int i = 0; i < kElementCount; i++) {
10939    CHECK_EQ(i % 256, pixels->get(i));
10940    CHECK_EQ(i % 256, pixel_data[i]);
10941  }
10942
10943  v8::Handle<v8::Object> obj = v8::Object::New();
10944  i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
10945  // Set the elements to be the pixels.
10946  // jsobj->set_elements(*pixels);
10947  obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
10948  CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
10949  obj->Set(v8_str("field"), v8::Int32::New(1503));
10950  context->Global()->Set(v8_str("pixels"), obj);
10951  v8::Handle<v8::Value> result = CompileRun("pixels.field");
10952  CHECK_EQ(1503, result->Int32Value());
10953  result = CompileRun("pixels[1]");
10954  CHECK_EQ(1, result->Int32Value());
10955
10956  result = CompileRun("var sum = 0;"
10957                      "for (var i = 0; i < 8; i++) {"
10958                      "  sum += pixels[i] = pixels[i] = -i;"
10959                      "}"
10960                      "sum;");
10961  CHECK_EQ(-28, result->Int32Value());
10962
10963  result = CompileRun("var sum = 0;"
10964                      "for (var i = 0; i < 8; i++) {"
10965                      "  sum += pixels[i] = pixels[i] = 0;"
10966                      "}"
10967                      "sum;");
10968  CHECK_EQ(0, result->Int32Value());
10969
10970  result = CompileRun("var sum = 0;"
10971                      "for (var i = 0; i < 8; i++) {"
10972                      "  sum += pixels[i] = pixels[i] = 255;"
10973                      "}"
10974                      "sum;");
10975  CHECK_EQ(8 * 255, result->Int32Value());
10976
10977  result = CompileRun("var sum = 0;"
10978                      "for (var i = 0; i < 8; i++) {"
10979                      "  sum += pixels[i] = pixels[i] = 256 + i;"
10980                      "}"
10981                      "sum;");
10982  CHECK_EQ(2076, result->Int32Value());
10983
10984  result = CompileRun("var sum = 0;"
10985                      "for (var i = 0; i < 8; i++) {"
10986                      "  sum += pixels[i] = pixels[i] = i;"
10987                      "}"
10988                      "sum;");
10989  CHECK_EQ(28, result->Int32Value());
10990
10991  result = CompileRun("var sum = 0;"
10992                      "for (var i = 0; i < 8; i++) {"
10993                      "  sum += pixels[i];"
10994                      "}"
10995                      "sum;");
10996  CHECK_EQ(28, result->Int32Value());
10997
10998  i::Handle<i::Smi> value(i::Smi::FromInt(2));
10999  i::SetElement(jsobj, 1, value, i::kNonStrictMode);
11000  CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
11001  *value.location() = i::Smi::FromInt(256);
11002  i::SetElement(jsobj, 1, value, i::kNonStrictMode);
11003  CHECK_EQ(255,
11004           i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
11005  *value.location() = i::Smi::FromInt(-1);
11006  i::SetElement(jsobj, 1, value, i::kNonStrictMode);
11007  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
11008
11009  result = CompileRun("for (var i = 0; i < 8; i++) {"
11010                      "  pixels[i] = (i * 65) - 109;"
11011                      "}"
11012                      "pixels[1] + pixels[6];");
11013  CHECK_EQ(255, result->Int32Value());
11014  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
11015  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
11016  CHECK_EQ(21,
11017           i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
11018  CHECK_EQ(86,
11019           i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
11020  CHECK_EQ(151,
11021           i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
11022  CHECK_EQ(216,
11023           i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
11024  CHECK_EQ(255,
11025           i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
11026  CHECK_EQ(255,
11027           i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
11028  result = CompileRun("var sum = 0;"
11029                      "for (var i = 0; i < 8; i++) {"
11030                      "  sum += pixels[i];"
11031                      "}"
11032                      "sum;");
11033  CHECK_EQ(984, result->Int32Value());
11034
11035  result = CompileRun("for (var i = 0; i < 8; i++) {"
11036                      "  pixels[i] = (i * 1.1);"
11037                      "}"
11038                      "pixels[1] + pixels[6];");
11039  CHECK_EQ(8, result->Int32Value());
11040  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
11041  CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
11042  CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
11043  CHECK_EQ(3, i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
11044  CHECK_EQ(4, i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
11045  CHECK_EQ(6, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
11046  CHECK_EQ(7, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
11047  CHECK_EQ(8, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
11048
11049  result = CompileRun("for (var i = 0; i < 8; i++) {"
11050                      "  pixels[7] = undefined;"
11051                      "}"
11052                      "pixels[7];");
11053  CHECK_EQ(0, result->Int32Value());
11054  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
11055
11056  result = CompileRun("for (var i = 0; i < 8; i++) {"
11057                      "  pixels[6] = '2.3';"
11058                      "}"
11059                      "pixels[6];");
11060  CHECK_EQ(2, result->Int32Value());
11061  CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
11062
11063  result = CompileRun("for (var i = 0; i < 8; i++) {"
11064                      "  pixels[5] = NaN;"
11065                      "}"
11066                      "pixels[5];");
11067  CHECK_EQ(0, result->Int32Value());
11068  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
11069
11070  result = CompileRun("for (var i = 0; i < 8; i++) {"
11071                      "  pixels[8] = Infinity;"
11072                      "}"
11073                      "pixels[8];");
11074  CHECK_EQ(255, result->Int32Value());
11075  CHECK_EQ(255,
11076           i::Smi::cast(jsobj->GetElement(8)->ToObjectChecked())->value());
11077
11078  result = CompileRun("for (var i = 0; i < 8; i++) {"
11079                      "  pixels[9] = -Infinity;"
11080                      "}"
11081                      "pixels[9];");
11082  CHECK_EQ(0, result->Int32Value());
11083  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(9)->ToObjectChecked())->value());
11084
11085  result = CompileRun("pixels[3] = 33;"
11086                      "delete pixels[3];"
11087                      "pixels[3];");
11088  CHECK_EQ(33, result->Int32Value());
11089
11090  result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
11091                      "pixels[2] = 12; pixels[3] = 13;"
11092                      "pixels.__defineGetter__('2',"
11093                      "function() { return 120; });"
11094                      "pixels[2];");
11095  CHECK_EQ(12, result->Int32Value());
11096
11097  result = CompileRun("var js_array = new Array(40);"
11098                      "js_array[0] = 77;"
11099                      "js_array;");
11100  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
11101
11102  result = CompileRun("pixels[1] = 23;"
11103                      "pixels.__proto__ = [];"
11104                      "js_array.__proto__ = pixels;"
11105                      "js_array.concat(pixels);");
11106  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
11107  CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
11108
11109  result = CompileRun("pixels[1] = 23;");
11110  CHECK_EQ(23, result->Int32Value());
11111
11112  // Test for index greater than 255.  Regression test for:
11113  // http://code.google.com/p/chromium/issues/detail?id=26337.
11114  result = CompileRun("pixels[256] = 255;");
11115  CHECK_EQ(255, result->Int32Value());
11116  result = CompileRun("var i = 0;"
11117                      "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
11118                      "i");
11119  CHECK_EQ(255, result->Int32Value());
11120
11121  // Make sure that pixel array ICs recognize when a non-pixel array
11122  // is passed to it.
11123  result = CompileRun("function pa_load(p) {"
11124                      "  var sum = 0;"
11125                      "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
11126                      "  return sum;"
11127                      "}"
11128                      "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
11129                      "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
11130                      "just_ints = new Object();"
11131                      "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
11132                      "for (var i = 0; i < 10; ++i) {"
11133                      "  result = pa_load(just_ints);"
11134                      "}"
11135                      "result");
11136  CHECK_EQ(32640, result->Int32Value());
11137
11138  // Make sure that pixel array ICs recognize out-of-bound accesses.
11139  result = CompileRun("function pa_load(p, start) {"
11140                      "  var sum = 0;"
11141                      "  for (var j = start; j < 256; j++) { sum += p[j]; }"
11142                      "  return sum;"
11143                      "}"
11144                      "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
11145                      "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
11146                      "for (var i = 0; i < 10; ++i) {"
11147                      "  result = pa_load(pixels,-10);"
11148                      "}"
11149                      "result");
11150  CHECK_EQ(0, result->Int32Value());
11151
11152  // Make sure that generic ICs properly handles a pixel array.
11153  result = CompileRun("function pa_load(p) {"
11154                      "  var sum = 0;"
11155                      "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
11156                      "  return sum;"
11157                      "}"
11158                      "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
11159                      "just_ints = new Object();"
11160                      "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
11161                      "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
11162                      "for (var i = 0; i < 10; ++i) {"
11163                      "  result = pa_load(pixels);"
11164                      "}"
11165                      "result");
11166  CHECK_EQ(32640, result->Int32Value());
11167
11168  // Make sure that generic load ICs recognize out-of-bound accesses in
11169  // pixel arrays.
11170  result = CompileRun("function pa_load(p, start) {"
11171                      "  var sum = 0;"
11172                      "  for (var j = start; j < 256; j++) { sum += p[j]; }"
11173                      "  return sum;"
11174                      "}"
11175                      "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
11176                      "just_ints = new Object();"
11177                      "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
11178                      "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
11179                      "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
11180                      "for (var i = 0; i < 10; ++i) {"
11181                      "  result = pa_load(pixels,-10);"
11182                      "}"
11183                      "result");
11184  CHECK_EQ(0, result->Int32Value());
11185
11186  // Make sure that generic ICs properly handles other types than pixel
11187  // arrays (that the inlined fast pixel array test leaves the right information
11188  // in the right registers).
11189  result = CompileRun("function pa_load(p) {"
11190                      "  var sum = 0;"
11191                      "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
11192                      "  return sum;"
11193                      "}"
11194                      "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
11195                      "just_ints = new Object();"
11196                      "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
11197                      "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
11198                      "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
11199                      "sparse_array = new Object();"
11200                      "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
11201                      "sparse_array[1000000] = 3;"
11202                      "for (var i = 0; i < 10; ++i) {"
11203                      "  result = pa_load(sparse_array);"
11204                      "}"
11205                      "result");
11206  CHECK_EQ(32640, result->Int32Value());
11207
11208  // Make sure that pixel array store ICs clamp values correctly.
11209  result = CompileRun("function pa_store(p) {"
11210                      "  for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
11211                      "}"
11212                      "pa_store(pixels);"
11213                      "var sum = 0;"
11214                      "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
11215                      "sum");
11216  CHECK_EQ(48896, result->Int32Value());
11217
11218  // Make sure that pixel array stores correctly handle accesses outside
11219  // of the pixel array..
11220  result = CompileRun("function pa_store(p,start) {"
11221                      "  for (var j = 0; j < 256; j++) {"
11222                      "    p[j+start] = j * 2;"
11223                      "  }"
11224                      "}"
11225                      "pa_store(pixels,0);"
11226                      "pa_store(pixels,-128);"
11227                      "var sum = 0;"
11228                      "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
11229                      "sum");
11230  CHECK_EQ(65280, result->Int32Value());
11231
11232  // Make sure that the generic store stub correctly handle accesses outside
11233  // of the pixel array..
11234  result = CompileRun("function pa_store(p,start) {"
11235                      "  for (var j = 0; j < 256; j++) {"
11236                      "    p[j+start] = j * 2;"
11237                      "  }"
11238                      "}"
11239                      "pa_store(pixels,0);"
11240                      "just_ints = new Object();"
11241                      "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
11242                      "pa_store(just_ints, 0);"
11243                      "pa_store(pixels,-128);"
11244                      "var sum = 0;"
11245                      "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
11246                      "sum");
11247  CHECK_EQ(65280, result->Int32Value());
11248
11249  // Make sure that the generic keyed store stub clamps pixel array values
11250  // correctly.
11251  result = CompileRun("function pa_store(p) {"
11252                      "  for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
11253                      "}"
11254                      "pa_store(pixels);"
11255                      "just_ints = new Object();"
11256                      "pa_store(just_ints);"
11257                      "pa_store(pixels);"
11258                      "var sum = 0;"
11259                      "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
11260                      "sum");
11261  CHECK_EQ(48896, result->Int32Value());
11262
11263  // Make sure that pixel array loads are optimized by crankshaft.
11264  result = CompileRun("function pa_load(p) {"
11265                      "  var sum = 0;"
11266                      "  for (var i=0; i<256; ++i) {"
11267                      "    sum += p[i];"
11268                      "  }"
11269                      "  return sum; "
11270                      "}"
11271                      "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
11272                      "for (var i = 0; i < 5000; ++i) {"
11273                      "  result = pa_load(pixels);"
11274                      "}"
11275                      "result");
11276  CHECK_EQ(32640, result->Int32Value());
11277
11278  // Make sure that pixel array stores are optimized by crankshaft.
11279  result = CompileRun("function pa_init(p) {"
11280                      "for (var i = 0; i < 256; ++i) { p[i] = i; }"
11281                      "}"
11282                      "function pa_load(p) {"
11283                      "  var sum = 0;"
11284                      "  for (var i=0; i<256; ++i) {"
11285                      "    sum += p[i];"
11286                      "  }"
11287                      "  return sum; "
11288                      "}"
11289                      "for (var i = 0; i < 5000; ++i) {"
11290                      "  pa_init(pixels);"
11291                      "}"
11292                      "result = pa_load(pixels);"
11293                      "result");
11294  CHECK_EQ(32640, result->Int32Value());
11295
11296  free(pixel_data);
11297}
11298
11299
11300THREADED_TEST(PixelArrayInfo) {
11301  v8::HandleScope scope;
11302  LocalContext context;
11303  for (int size = 0; size < 100; size += 10) {
11304    uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
11305    v8::Handle<v8::Object> obj = v8::Object::New();
11306    obj->SetIndexedPropertiesToPixelData(pixel_data, size);
11307    CHECK(obj->HasIndexedPropertiesInPixelData());
11308    CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
11309    CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
11310    free(pixel_data);
11311  }
11312}
11313
11314
11315static v8::Handle<Value> NotHandledIndexedPropertyGetter(
11316    uint32_t index,
11317    const AccessorInfo& info) {
11318  ApiTestFuzzer::Fuzz();
11319  return v8::Handle<Value>();
11320}
11321
11322
11323static v8::Handle<Value> NotHandledIndexedPropertySetter(
11324    uint32_t index,
11325    Local<Value> value,
11326    const AccessorInfo& info) {
11327  ApiTestFuzzer::Fuzz();
11328  return v8::Handle<Value>();
11329}
11330
11331
11332THREADED_TEST(PixelArrayWithInterceptor) {
11333  v8::HandleScope scope;
11334  LocalContext context;
11335  const int kElementCount = 260;
11336  uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
11337  i::Handle<i::ExternalPixelArray> pixels =
11338      i::Handle<i::ExternalPixelArray>::cast(
11339          FACTORY->NewExternalArray(kElementCount,
11340                                    v8::kExternalPixelArray,
11341                                    pixel_data));
11342  for (int i = 0; i < kElementCount; i++) {
11343    pixels->set(i, i % 256);
11344  }
11345  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11346  templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter,
11347                                   NotHandledIndexedPropertySetter);
11348  v8::Handle<v8::Object> obj = templ->NewInstance();
11349  obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
11350  context->Global()->Set(v8_str("pixels"), obj);
11351  v8::Handle<v8::Value> result = CompileRun("pixels[1]");
11352  CHECK_EQ(1, result->Int32Value());
11353  result = CompileRun("var sum = 0;"
11354                      "for (var i = 0; i < 8; i++) {"
11355                      "  sum += pixels[i] = pixels[i] = -i;"
11356                      "}"
11357                      "sum;");
11358  CHECK_EQ(-28, result->Int32Value());
11359  result = CompileRun("pixels.hasOwnProperty('1')");
11360  CHECK(result->BooleanValue());
11361  free(pixel_data);
11362}
11363
11364
11365static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
11366  switch (array_type) {
11367    case v8::kExternalByteArray:
11368    case v8::kExternalUnsignedByteArray:
11369    case v8::kExternalPixelArray:
11370      return 1;
11371      break;
11372    case v8::kExternalShortArray:
11373    case v8::kExternalUnsignedShortArray:
11374      return 2;
11375      break;
11376    case v8::kExternalIntArray:
11377    case v8::kExternalUnsignedIntArray:
11378    case v8::kExternalFloatArray:
11379      return 4;
11380      break;
11381    default:
11382      UNREACHABLE();
11383      return -1;
11384  }
11385  UNREACHABLE();
11386  return -1;
11387}
11388
11389
11390template <class ExternalArrayClass, class ElementType>
11391static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
11392                                    int64_t low,
11393                                    int64_t high) {
11394  v8::HandleScope scope;
11395  LocalContext context;
11396  const int kElementCount = 40;
11397  int element_size = ExternalArrayElementSize(array_type);
11398  ElementType* array_data =
11399      static_cast<ElementType*>(malloc(kElementCount * element_size));
11400  i::Handle<ExternalArrayClass> array =
11401      i::Handle<ExternalArrayClass>::cast(
11402          FACTORY->NewExternalArray(kElementCount, array_type, array_data));
11403  HEAP->CollectAllGarbage(false);  // Force GC to trigger verification.
11404  for (int i = 0; i < kElementCount; i++) {
11405    array->set(i, static_cast<ElementType>(i));
11406  }
11407  HEAP->CollectAllGarbage(false);  // Force GC to trigger verification.
11408  for (int i = 0; i < kElementCount; i++) {
11409    CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array->get(i)));
11410    CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
11411  }
11412
11413  v8::Handle<v8::Object> obj = v8::Object::New();
11414  i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
11415  // Set the elements to be the external array.
11416  obj->SetIndexedPropertiesToExternalArrayData(array_data,
11417                                               array_type,
11418                                               kElementCount);
11419  CHECK_EQ(
11420      1, static_cast<int>(jsobj->GetElement(1)->ToObjectChecked()->Number()));
11421  obj->Set(v8_str("field"), v8::Int32::New(1503));
11422  context->Global()->Set(v8_str("ext_array"), obj);
11423  v8::Handle<v8::Value> result = CompileRun("ext_array.field");
11424  CHECK_EQ(1503, result->Int32Value());
11425  result = CompileRun("ext_array[1]");
11426  CHECK_EQ(1, result->Int32Value());
11427
11428  // Check pass through of assigned smis
11429  result = CompileRun("var sum = 0;"
11430                      "for (var i = 0; i < 8; i++) {"
11431                      "  sum += ext_array[i] = ext_array[i] = -i;"
11432                      "}"
11433                      "sum;");
11434  CHECK_EQ(-28, result->Int32Value());
11435
11436  // Check assigned smis
11437  result = CompileRun("for (var i = 0; i < 8; i++) {"
11438                      "  ext_array[i] = i;"
11439                      "}"
11440                      "var sum = 0;"
11441                      "for (var i = 0; i < 8; i++) {"
11442                      "  sum += ext_array[i];"
11443                      "}"
11444                      "sum;");
11445  CHECK_EQ(28, result->Int32Value());
11446
11447  // Check assigned smis in reverse order
11448  result = CompileRun("for (var i = 8; --i >= 0; ) {"
11449                      "  ext_array[i] = i;"
11450                      "}"
11451                      "var sum = 0;"
11452                      "for (var i = 0; i < 8; i++) {"
11453                      "  sum += ext_array[i];"
11454                      "}"
11455                      "sum;");
11456  CHECK_EQ(28, result->Int32Value());
11457
11458  // Check pass through of assigned HeapNumbers
11459  result = CompileRun("var sum = 0;"
11460                      "for (var i = 0; i < 16; i+=2) {"
11461                      "  sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
11462                      "}"
11463                      "sum;");
11464  CHECK_EQ(-28, result->Int32Value());
11465
11466  // Check assigned HeapNumbers
11467  result = CompileRun("for (var i = 0; i < 16; i+=2) {"
11468                      "  ext_array[i] = (i * 0.5);"
11469                      "}"
11470                      "var sum = 0;"
11471                      "for (var i = 0; i < 16; i+=2) {"
11472                      "  sum += ext_array[i];"
11473                      "}"
11474                      "sum;");
11475  CHECK_EQ(28, result->Int32Value());
11476
11477  // Check assigned HeapNumbers in reverse order
11478  result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
11479                      "  ext_array[i] = (i * 0.5);"
11480                      "}"
11481                      "var sum = 0;"
11482                      "for (var i = 0; i < 16; i+=2) {"
11483                      "  sum += ext_array[i];"
11484                      "}"
11485                      "sum;");
11486  CHECK_EQ(28, result->Int32Value());
11487
11488  i::ScopedVector<char> test_buf(1024);
11489
11490  // Check legal boundary conditions.
11491  // The repeated loads and stores ensure the ICs are exercised.
11492  const char* boundary_program =
11493      "var res = 0;"
11494      "for (var i = 0; i < 16; i++) {"
11495      "  ext_array[i] = %lld;"
11496      "  if (i > 8) {"
11497      "    res = ext_array[i];"
11498      "  }"
11499      "}"
11500      "res;";
11501  i::OS::SNPrintF(test_buf,
11502                  boundary_program,
11503                  low);
11504  result = CompileRun(test_buf.start());
11505  CHECK_EQ(low, result->IntegerValue());
11506
11507  i::OS::SNPrintF(test_buf,
11508                  boundary_program,
11509                  high);
11510  result = CompileRun(test_buf.start());
11511  CHECK_EQ(high, result->IntegerValue());
11512
11513  // Check misprediction of type in IC.
11514  result = CompileRun("var tmp_array = ext_array;"
11515                      "var sum = 0;"
11516                      "for (var i = 0; i < 8; i++) {"
11517                      "  tmp_array[i] = i;"
11518                      "  sum += tmp_array[i];"
11519                      "  if (i == 4) {"
11520                      "    tmp_array = {};"
11521                      "  }"
11522                      "}"
11523                      "sum;");
11524  HEAP->CollectAllGarbage(false);  // Force GC to trigger verification.
11525  CHECK_EQ(28, result->Int32Value());
11526
11527  // Make sure out-of-range loads do not throw.
11528  i::OS::SNPrintF(test_buf,
11529                  "var caught_exception = false;"
11530                  "try {"
11531                  "  ext_array[%d];"
11532                  "} catch (e) {"
11533                  "  caught_exception = true;"
11534                  "}"
11535                  "caught_exception;",
11536                  kElementCount);
11537  result = CompileRun(test_buf.start());
11538  CHECK_EQ(false, result->BooleanValue());
11539
11540  // Make sure out-of-range stores do not throw.
11541  i::OS::SNPrintF(test_buf,
11542                  "var caught_exception = false;"
11543                  "try {"
11544                  "  ext_array[%d] = 1;"
11545                  "} catch (e) {"
11546                  "  caught_exception = true;"
11547                  "}"
11548                  "caught_exception;",
11549                  kElementCount);
11550  result = CompileRun(test_buf.start());
11551  CHECK_EQ(false, result->BooleanValue());
11552
11553  // Check other boundary conditions, values and operations.
11554  result = CompileRun("for (var i = 0; i < 8; i++) {"
11555                      "  ext_array[7] = undefined;"
11556                      "}"
11557                      "ext_array[7];");
11558  CHECK_EQ(0, result->Int32Value());
11559  CHECK_EQ(
11560      0, static_cast<int>(jsobj->GetElement(7)->ToObjectChecked()->Number()));
11561
11562  result = CompileRun("for (var i = 0; i < 8; i++) {"
11563                      "  ext_array[6] = '2.3';"
11564                      "}"
11565                      "ext_array[6];");
11566  CHECK_EQ(2, result->Int32Value());
11567  CHECK_EQ(
11568      2, static_cast<int>(jsobj->GetElement(6)->ToObjectChecked()->Number()));
11569
11570  if (array_type != v8::kExternalFloatArray) {
11571    // Though the specification doesn't state it, be explicit about
11572    // converting NaNs and +/-Infinity to zero.
11573    result = CompileRun("for (var i = 0; i < 8; i++) {"
11574                        "  ext_array[i] = 5;"
11575                        "}"
11576                        "for (var i = 0; i < 8; i++) {"
11577                        "  ext_array[i] = NaN;"
11578                        "}"
11579                        "ext_array[5];");
11580    CHECK_EQ(0, result->Int32Value());
11581    CHECK_EQ(0,
11582             i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
11583
11584    result = CompileRun("for (var i = 0; i < 8; i++) {"
11585                        "  ext_array[i] = 5;"
11586                        "}"
11587                        "for (var i = 0; i < 8; i++) {"
11588                        "  ext_array[i] = Infinity;"
11589                        "}"
11590                        "ext_array[5];");
11591    int expected_value =
11592        (array_type == v8::kExternalPixelArray) ? 255 : 0;
11593    CHECK_EQ(expected_value, result->Int32Value());
11594    CHECK_EQ(expected_value,
11595             i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
11596
11597    result = CompileRun("for (var i = 0; i < 8; i++) {"
11598                        "  ext_array[i] = 5;"
11599                        "}"
11600                        "for (var i = 0; i < 8; i++) {"
11601                        "  ext_array[i] = -Infinity;"
11602                        "}"
11603                        "ext_array[5];");
11604    CHECK_EQ(0, result->Int32Value());
11605    CHECK_EQ(0,
11606             i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
11607
11608    // Check truncation behavior of integral arrays.
11609    const char* unsigned_data =
11610        "var source_data = [0.6, 10.6];"
11611        "var expected_results = [0, 10];";
11612    const char* signed_data =
11613        "var source_data = [0.6, 10.6, -0.6, -10.6];"
11614        "var expected_results = [0, 10, 0, -10];";
11615    const char* pixel_data =
11616        "var source_data = [0.6, 10.6];"
11617        "var expected_results = [1, 11];";
11618    bool is_unsigned =
11619        (array_type == v8::kExternalUnsignedByteArray ||
11620         array_type == v8::kExternalUnsignedShortArray ||
11621         array_type == v8::kExternalUnsignedIntArray);
11622    bool is_pixel_data = array_type == v8::kExternalPixelArray;
11623
11624    i::OS::SNPrintF(test_buf,
11625                    "%s"
11626                    "var all_passed = true;"
11627                    "for (var i = 0; i < source_data.length; i++) {"
11628                    "  for (var j = 0; j < 8; j++) {"
11629                    "    ext_array[j] = source_data[i];"
11630                    "  }"
11631                    "  all_passed = all_passed &&"
11632                    "               (ext_array[5] == expected_results[i]);"
11633                    "}"
11634                    "all_passed;",
11635                    (is_unsigned ?
11636                         unsigned_data :
11637                         (is_pixel_data ? pixel_data : signed_data)));
11638    result = CompileRun(test_buf.start());
11639    CHECK_EQ(true, result->BooleanValue());
11640  }
11641
11642  // Test crankshaft external array loads
11643  for (int i = 0; i < kElementCount; i++) {
11644    array->set(i, static_cast<ElementType>(i));
11645  }
11646  result = CompileRun("function ee_load_test_func(sum) {"
11647                      " for (var i = 0; i < 40; ++i)"
11648                      "   sum += ext_array[i];"
11649                      " return sum;"
11650                      "}"
11651                      "sum=0;"
11652                      "for (var i=0;i<10000;++i) {"
11653                      "  sum=ee_load_test_func(sum);"
11654                      "}"
11655                      "sum;");
11656  CHECK_EQ(7800000, result->Int32Value());
11657
11658  // Test crankshaft external array stores
11659  result = CompileRun("function ee_store_test_func(sum) {"
11660                      " for (var i = 0; i < 40; ++i)"
11661                      "   sum += ext_array[i] = i;"
11662                      " return sum;"
11663                      "}"
11664                      "sum=0;"
11665                      "for (var i=0;i<10000;++i) {"
11666                      "  sum=ee_store_test_func(sum);"
11667                      "}"
11668                      "sum;");
11669  CHECK_EQ(7800000, result->Int32Value());
11670
11671  for (int i = 0; i < kElementCount; i++) {
11672    array->set(i, static_cast<ElementType>(i));
11673  }
11674  // Test complex assignments
11675  result = CompileRun("function ee_op_test_complex_func(sum) {"
11676                      " for (var i = 0; i < 40; ++i) {"
11677                      "   sum += (ext_array[i] += 1);"
11678                      "   sum += (ext_array[i] -= 1);"
11679                      " } "
11680                      " return sum;"
11681                      "}"
11682                      "sum=0;"
11683                      "for (var i=0;i<10000;++i) {"
11684                      "  sum=ee_op_test_complex_func(sum);"
11685                      "}"
11686                      "sum;");
11687  CHECK_EQ(16000000, result->Int32Value());
11688
11689  // Test count operations
11690  result = CompileRun("function ee_op_test_count_func(sum) {"
11691                      " for (var i = 0; i < 40; ++i) {"
11692                      "   sum += (++ext_array[i]);"
11693                      "   sum += (--ext_array[i]);"
11694                      " } "
11695                      " return sum;"
11696                      "}"
11697                      "sum=0;"
11698                      "for (var i=0;i<10000;++i) {"
11699                      "  sum=ee_op_test_count_func(sum);"
11700                      "}"
11701                      "sum;");
11702  CHECK_EQ(16000000, result->Int32Value());
11703
11704  result = CompileRun("ext_array[3] = 33;"
11705                      "delete ext_array[3];"
11706                      "ext_array[3];");
11707  CHECK_EQ(33, result->Int32Value());
11708
11709  result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
11710                      "ext_array[2] = 12; ext_array[3] = 13;"
11711                      "ext_array.__defineGetter__('2',"
11712                      "function() { return 120; });"
11713                      "ext_array[2];");
11714  CHECK_EQ(12, result->Int32Value());
11715
11716  result = CompileRun("var js_array = new Array(40);"
11717                      "js_array[0] = 77;"
11718                      "js_array;");
11719  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
11720
11721  result = CompileRun("ext_array[1] = 23;"
11722                      "ext_array.__proto__ = [];"
11723                      "js_array.__proto__ = ext_array;"
11724                      "js_array.concat(ext_array);");
11725  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
11726  CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
11727
11728  result = CompileRun("ext_array[1] = 23;");
11729  CHECK_EQ(23, result->Int32Value());
11730
11731  // Test more complex manipulations which cause eax to contain values
11732  // that won't be completely overwritten by loads from the arrays.
11733  // This catches bugs in the instructions used for the KeyedLoadIC
11734  // for byte and word types.
11735  {
11736    const int kXSize = 300;
11737    const int kYSize = 300;
11738    const int kLargeElementCount = kXSize * kYSize * 4;
11739    ElementType* large_array_data =
11740        static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
11741    i::Handle<ExternalArrayClass> large_array =
11742        i::Handle<ExternalArrayClass>::cast(
11743            FACTORY->NewExternalArray(kLargeElementCount,
11744                                         array_type,
11745                                         array_data));
11746    v8::Handle<v8::Object> large_obj = v8::Object::New();
11747    // Set the elements to be the external array.
11748    large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
11749                                                       array_type,
11750                                                       kLargeElementCount);
11751    context->Global()->Set(v8_str("large_array"), large_obj);
11752    // Initialize contents of a few rows.
11753    for (int x = 0; x < 300; x++) {
11754      int row = 0;
11755      int offset = row * 300 * 4;
11756      large_array_data[offset + 4 * x + 0] = (ElementType) 127;
11757      large_array_data[offset + 4 * x + 1] = (ElementType) 0;
11758      large_array_data[offset + 4 * x + 2] = (ElementType) 0;
11759      large_array_data[offset + 4 * x + 3] = (ElementType) 127;
11760      row = 150;
11761      offset = row * 300 * 4;
11762      large_array_data[offset + 4 * x + 0] = (ElementType) 127;
11763      large_array_data[offset + 4 * x + 1] = (ElementType) 0;
11764      large_array_data[offset + 4 * x + 2] = (ElementType) 0;
11765      large_array_data[offset + 4 * x + 3] = (ElementType) 127;
11766      row = 298;
11767      offset = row * 300 * 4;
11768      large_array_data[offset + 4 * x + 0] = (ElementType) 127;
11769      large_array_data[offset + 4 * x + 1] = (ElementType) 0;
11770      large_array_data[offset + 4 * x + 2] = (ElementType) 0;
11771      large_array_data[offset + 4 * x + 3] = (ElementType) 127;
11772    }
11773    // The goal of the code below is to make "offset" large enough
11774    // that the computation of the index (which goes into eax) has
11775    // high bits set which will not be overwritten by a byte or short
11776    // load.
11777    result = CompileRun("var failed = false;"
11778                        "var offset = 0;"
11779                        "for (var i = 0; i < 300; i++) {"
11780                        "  if (large_array[4 * i] != 127 ||"
11781                        "      large_array[4 * i + 1] != 0 ||"
11782                        "      large_array[4 * i + 2] != 0 ||"
11783                        "      large_array[4 * i + 3] != 127) {"
11784                        "    failed = true;"
11785                        "  }"
11786                        "}"
11787                        "offset = 150 * 300 * 4;"
11788                        "for (var i = 0; i < 300; i++) {"
11789                        "  if (large_array[offset + 4 * i] != 127 ||"
11790                        "      large_array[offset + 4 * i + 1] != 0 ||"
11791                        "      large_array[offset + 4 * i + 2] != 0 ||"
11792                        "      large_array[offset + 4 * i + 3] != 127) {"
11793                        "    failed = true;"
11794                        "  }"
11795                        "}"
11796                        "offset = 298 * 300 * 4;"
11797                        "for (var i = 0; i < 300; i++) {"
11798                        "  if (large_array[offset + 4 * i] != 127 ||"
11799                        "      large_array[offset + 4 * i + 1] != 0 ||"
11800                        "      large_array[offset + 4 * i + 2] != 0 ||"
11801                        "      large_array[offset + 4 * i + 3] != 127) {"
11802                        "    failed = true;"
11803                        "  }"
11804                        "}"
11805                        "!failed;");
11806    CHECK_EQ(true, result->BooleanValue());
11807    free(large_array_data);
11808  }
11809
11810  // The "" property descriptor is overloaded to store information about
11811  // the external array. Ensure that setting and accessing the "" property
11812  // works (it should overwrite the information cached about the external
11813  // array in the DescriptorArray) in various situations.
11814  result = CompileRun("ext_array[''] = 23; ext_array['']");
11815  CHECK_EQ(23, result->Int32Value());
11816
11817  // Property "" set after the external array is associated with the object.
11818  {
11819    v8::Handle<v8::Object> obj2 = v8::Object::New();
11820    obj2->Set(v8_str("ee_test_field"), v8::Int32::New(256));
11821    obj2->Set(v8_str(""), v8::Int32::New(1503));
11822    // Set the elements to be the external array.
11823    obj2->SetIndexedPropertiesToExternalArrayData(array_data,
11824                                                  array_type,
11825                                                  kElementCount);
11826    context->Global()->Set(v8_str("ext_array"), obj2);
11827    result = CompileRun("ext_array['']");
11828    CHECK_EQ(1503, result->Int32Value());
11829  }
11830
11831  // Property "" set after the external array is associated with the object.
11832  {
11833    v8::Handle<v8::Object> obj2 = v8::Object::New();
11834    obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
11835    // Set the elements to be the external array.
11836    obj2->SetIndexedPropertiesToExternalArrayData(array_data,
11837                                                  array_type,
11838                                                  kElementCount);
11839    obj2->Set(v8_str(""), v8::Int32::New(1503));
11840    context->Global()->Set(v8_str("ext_array"), obj2);
11841    result = CompileRun("ext_array['']");
11842    CHECK_EQ(1503, result->Int32Value());
11843  }
11844
11845  // Should reuse the map from previous test.
11846  {
11847    v8::Handle<v8::Object> obj2 = v8::Object::New();
11848    obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
11849    // Set the elements to be the external array. Should re-use the map
11850    // from previous test.
11851    obj2->SetIndexedPropertiesToExternalArrayData(array_data,
11852                                                  array_type,
11853                                                  kElementCount);
11854    context->Global()->Set(v8_str("ext_array"), obj2);
11855    result = CompileRun("ext_array['']");
11856  }
11857
11858  // Property "" is a constant function that shouldn't not be interfered with
11859  // when an external array is set.
11860  {
11861    v8::Handle<v8::Object> obj2 = v8::Object::New();
11862    // Start
11863    obj2->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
11864
11865    // Add a constant function to an object.
11866    context->Global()->Set(v8_str("ext_array"), obj2);
11867    result = CompileRun("ext_array[''] = function() {return 1503;};"
11868                        "ext_array['']();");
11869
11870    // Add an external array transition to the same map that
11871    // has the constant transition.
11872    v8::Handle<v8::Object> obj3 = v8::Object::New();
11873    obj3->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
11874    obj3->SetIndexedPropertiesToExternalArrayData(array_data,
11875                                                  array_type,
11876                                                  kElementCount);
11877    context->Global()->Set(v8_str("ext_array"), obj3);
11878  }
11879
11880  // If a external array transition is in the map, it should get clobbered
11881  // by a constant function.
11882  {
11883    // Add an external array transition.
11884    v8::Handle<v8::Object> obj3 = v8::Object::New();
11885    obj3->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
11886    obj3->SetIndexedPropertiesToExternalArrayData(array_data,
11887                                                  array_type,
11888                                                  kElementCount);
11889
11890    // Add a constant function to the same map that just got an external array
11891    // transition.
11892    v8::Handle<v8::Object> obj2 = v8::Object::New();
11893    obj2->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
11894    context->Global()->Set(v8_str("ext_array"), obj2);
11895    result = CompileRun("ext_array[''] = function() {return 1503;};"
11896                        "ext_array['']();");
11897  }
11898
11899  free(array_data);
11900}
11901
11902
11903THREADED_TEST(ExternalByteArray) {
11904  ExternalArrayTestHelper<i::ExternalByteArray, int8_t>(
11905      v8::kExternalByteArray,
11906      -128,
11907      127);
11908}
11909
11910
11911THREADED_TEST(ExternalUnsignedByteArray) {
11912  ExternalArrayTestHelper<i::ExternalUnsignedByteArray, uint8_t>(
11913      v8::kExternalUnsignedByteArray,
11914      0,
11915      255);
11916}
11917
11918
11919THREADED_TEST(ExternalPixelArray) {
11920  ExternalArrayTestHelper<i::ExternalPixelArray, uint8_t>(
11921      v8::kExternalPixelArray,
11922      0,
11923      255);
11924}
11925
11926
11927THREADED_TEST(ExternalShortArray) {
11928  ExternalArrayTestHelper<i::ExternalShortArray, int16_t>(
11929      v8::kExternalShortArray,
11930      -32768,
11931      32767);
11932}
11933
11934
11935THREADED_TEST(ExternalUnsignedShortArray) {
11936  ExternalArrayTestHelper<i::ExternalUnsignedShortArray, uint16_t>(
11937      v8::kExternalUnsignedShortArray,
11938      0,
11939      65535);
11940}
11941
11942
11943THREADED_TEST(ExternalIntArray) {
11944  ExternalArrayTestHelper<i::ExternalIntArray, int32_t>(
11945      v8::kExternalIntArray,
11946      INT_MIN,   // -2147483648
11947      INT_MAX);  //  2147483647
11948}
11949
11950
11951THREADED_TEST(ExternalUnsignedIntArray) {
11952  ExternalArrayTestHelper<i::ExternalUnsignedIntArray, uint32_t>(
11953      v8::kExternalUnsignedIntArray,
11954      0,
11955      UINT_MAX);  // 4294967295
11956}
11957
11958
11959THREADED_TEST(ExternalFloatArray) {
11960  ExternalArrayTestHelper<i::ExternalFloatArray, float>(
11961      v8::kExternalFloatArray,
11962      -500,
11963      500);
11964}
11965
11966
11967THREADED_TEST(ExternalArrays) {
11968  TestExternalByteArray();
11969  TestExternalUnsignedByteArray();
11970  TestExternalShortArray();
11971  TestExternalUnsignedShortArray();
11972  TestExternalIntArray();
11973  TestExternalUnsignedIntArray();
11974  TestExternalFloatArray();
11975}
11976
11977
11978void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
11979  v8::HandleScope scope;
11980  LocalContext context;
11981  for (int size = 0; size < 100; size += 10) {
11982    int element_size = ExternalArrayElementSize(array_type);
11983    void* external_data = malloc(size * element_size);
11984    v8::Handle<v8::Object> obj = v8::Object::New();
11985    obj->SetIndexedPropertiesToExternalArrayData(
11986        external_data, array_type, size);
11987    CHECK(obj->HasIndexedPropertiesInExternalArrayData());
11988    CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
11989    CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
11990    CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
11991    free(external_data);
11992  }
11993}
11994
11995
11996THREADED_TEST(ExternalArrayInfo) {
11997  ExternalArrayInfoTestHelper(v8::kExternalByteArray);
11998  ExternalArrayInfoTestHelper(v8::kExternalUnsignedByteArray);
11999  ExternalArrayInfoTestHelper(v8::kExternalShortArray);
12000  ExternalArrayInfoTestHelper(v8::kExternalUnsignedShortArray);
12001  ExternalArrayInfoTestHelper(v8::kExternalIntArray);
12002  ExternalArrayInfoTestHelper(v8::kExternalUnsignedIntArray);
12003  ExternalArrayInfoTestHelper(v8::kExternalFloatArray);
12004  ExternalArrayInfoTestHelper(v8::kExternalPixelArray);
12005}
12006
12007
12008THREADED_TEST(ScriptContextDependence) {
12009  v8::HandleScope scope;
12010  LocalContext c1;
12011  const char *source = "foo";
12012  v8::Handle<v8::Script> dep = v8::Script::Compile(v8::String::New(source));
12013  v8::Handle<v8::Script> indep = v8::Script::New(v8::String::New(source));
12014  c1->Global()->Set(v8::String::New("foo"), v8::Integer::New(100));
12015  CHECK_EQ(dep->Run()->Int32Value(), 100);
12016  CHECK_EQ(indep->Run()->Int32Value(), 100);
12017  LocalContext c2;
12018  c2->Global()->Set(v8::String::New("foo"), v8::Integer::New(101));
12019  CHECK_EQ(dep->Run()->Int32Value(), 100);
12020  CHECK_EQ(indep->Run()->Int32Value(), 101);
12021}
12022
12023
12024THREADED_TEST(StackTrace) {
12025  v8::HandleScope scope;
12026  LocalContext context;
12027  v8::TryCatch try_catch;
12028  const char *source = "function foo() { FAIL.FAIL; }; foo();";
12029  v8::Handle<v8::String> src = v8::String::New(source);
12030  v8::Handle<v8::String> origin = v8::String::New("stack-trace-test");
12031  v8::Script::New(src, origin)->Run();
12032  CHECK(try_catch.HasCaught());
12033  v8::String::Utf8Value stack(try_catch.StackTrace());
12034  CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
12035}
12036
12037
12038// Checks that a StackFrame has certain expected values.
12039void checkStackFrame(const char* expected_script_name,
12040    const char* expected_func_name, int expected_line_number,
12041    int expected_column, bool is_eval, bool is_constructor,
12042    v8::Handle<v8::StackFrame> frame) {
12043  v8::HandleScope scope;
12044  v8::String::Utf8Value func_name(frame->GetFunctionName());
12045  v8::String::Utf8Value script_name(frame->GetScriptName());
12046  if (*script_name == NULL) {
12047    // The situation where there is no associated script, like for evals.
12048    CHECK(expected_script_name == NULL);
12049  } else {
12050    CHECK(strstr(*script_name, expected_script_name) != NULL);
12051  }
12052  CHECK(strstr(*func_name, expected_func_name) != NULL);
12053  CHECK_EQ(expected_line_number, frame->GetLineNumber());
12054  CHECK_EQ(expected_column, frame->GetColumn());
12055  CHECK_EQ(is_eval, frame->IsEval());
12056  CHECK_EQ(is_constructor, frame->IsConstructor());
12057}
12058
12059
12060v8::Handle<Value> AnalyzeStackInNativeCode(const v8::Arguments& args) {
12061  v8::HandleScope scope;
12062  const char* origin = "capture-stack-trace-test";
12063  const int kOverviewTest = 1;
12064  const int kDetailedTest = 2;
12065
12066  ASSERT(args.Length() == 1);
12067
12068  int testGroup = args[0]->Int32Value();
12069  if (testGroup == kOverviewTest) {
12070    v8::Handle<v8::StackTrace> stackTrace =
12071        v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kOverview);
12072    CHECK_EQ(4, stackTrace->GetFrameCount());
12073    checkStackFrame(origin, "bar", 2, 10, false, false,
12074                    stackTrace->GetFrame(0));
12075    checkStackFrame(origin, "foo", 6, 3, false, false,
12076                    stackTrace->GetFrame(1));
12077    checkStackFrame(NULL, "", 1, 1, false, false,
12078                    stackTrace->GetFrame(2));
12079    // The last frame is an anonymous function that has the initial call.
12080    checkStackFrame(origin, "", 8, 7, false, false,
12081                    stackTrace->GetFrame(3));
12082
12083    CHECK(stackTrace->AsArray()->IsArray());
12084  } else if (testGroup == kDetailedTest) {
12085    v8::Handle<v8::StackTrace> stackTrace =
12086        v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
12087    CHECK_EQ(4, stackTrace->GetFrameCount());
12088    checkStackFrame(origin, "bat", 4, 22, false, false,
12089                    stackTrace->GetFrame(0));
12090    checkStackFrame(origin, "baz", 8, 3, false, true,
12091                    stackTrace->GetFrame(1));
12092#ifdef ENABLE_DEBUGGER_SUPPORT
12093    bool is_eval = true;
12094#else  // ENABLE_DEBUGGER_SUPPORT
12095    bool is_eval = false;
12096#endif  // ENABLE_DEBUGGER_SUPPORT
12097
12098    checkStackFrame(NULL, "", 1, 1, is_eval, false,
12099                    stackTrace->GetFrame(2));
12100    // The last frame is an anonymous function that has the initial call to foo.
12101    checkStackFrame(origin, "", 10, 1, false, false,
12102                    stackTrace->GetFrame(3));
12103
12104    CHECK(stackTrace->AsArray()->IsArray());
12105  }
12106  return v8::Undefined();
12107}
12108
12109
12110// Tests the C++ StackTrace API.
12111// TODO(3074796): Reenable this as a THREADED_TEST once it passes.
12112// THREADED_TEST(CaptureStackTrace) {
12113TEST(CaptureStackTrace) {
12114  v8::HandleScope scope;
12115  v8::Handle<v8::String> origin = v8::String::New("capture-stack-trace-test");
12116  Local<ObjectTemplate> templ = ObjectTemplate::New();
12117  templ->Set(v8_str("AnalyzeStackInNativeCode"),
12118             v8::FunctionTemplate::New(AnalyzeStackInNativeCode));
12119  LocalContext context(0, templ);
12120
12121  // Test getting OVERVIEW information. Should ignore information that is not
12122  // script name, function name, line number, and column offset.
12123  const char *overview_source =
12124    "function bar() {\n"
12125    "  var y; AnalyzeStackInNativeCode(1);\n"
12126    "}\n"
12127    "function foo() {\n"
12128    "\n"
12129    "  bar();\n"
12130    "}\n"
12131    "var x;eval('new foo();');";
12132  v8::Handle<v8::String> overview_src = v8::String::New(overview_source);
12133  v8::Handle<Value> overview_result =
12134      v8::Script::New(overview_src, origin)->Run();
12135  ASSERT(!overview_result.IsEmpty());
12136  ASSERT(overview_result->IsObject());
12137
12138  // Test getting DETAILED information.
12139  const char *detailed_source =
12140    "function bat() {AnalyzeStackInNativeCode(2);\n"
12141    "}\n"
12142    "\n"
12143    "function baz() {\n"
12144    "  bat();\n"
12145    "}\n"
12146    "eval('new baz();');";
12147  v8::Handle<v8::String> detailed_src = v8::String::New(detailed_source);
12148  // Make the script using a non-zero line and column offset.
12149  v8::Handle<v8::Integer> line_offset = v8::Integer::New(3);
12150  v8::Handle<v8::Integer> column_offset = v8::Integer::New(5);
12151  v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
12152  v8::Handle<v8::Script> detailed_script(
12153      v8::Script::New(detailed_src, &detailed_origin));
12154  v8::Handle<Value> detailed_result = detailed_script->Run();
12155  ASSERT(!detailed_result.IsEmpty());
12156  ASSERT(detailed_result->IsObject());
12157}
12158
12159
12160static void StackTraceForUncaughtExceptionListener(
12161    v8::Handle<v8::Message> message,
12162    v8::Handle<Value>) {
12163  v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
12164  CHECK_EQ(2, stack_trace->GetFrameCount());
12165  checkStackFrame("origin", "foo", 2, 3, false, false,
12166                  stack_trace->GetFrame(0));
12167  checkStackFrame("origin", "bar", 5, 3, false, false,
12168                  stack_trace->GetFrame(1));
12169}
12170
12171TEST(CaptureStackTraceForUncaughtException) {
12172  report_count = 0;
12173  v8::HandleScope scope;
12174  LocalContext env;
12175  v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
12176  v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
12177
12178  Script::Compile(v8_str("function foo() {\n"
12179                         "  throw 1;\n"
12180                         "};\n"
12181                         "function bar() {\n"
12182                         "  foo();\n"
12183                         "};"),
12184                  v8_str("origin"))->Run();
12185  v8::Local<v8::Object> global = env->Global();
12186  Local<Value> trouble = global->Get(v8_str("bar"));
12187  CHECK(trouble->IsFunction());
12188  Function::Cast(*trouble)->Call(global, 0, NULL);
12189  v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
12190  v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
12191}
12192
12193
12194TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
12195  v8::HandleScope scope;
12196  LocalContext env;
12197  v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
12198                                                    1024,
12199                                                    v8::StackTrace::kDetailed);
12200
12201  CompileRun(
12202      "var setters = ['column', 'lineNumber', 'scriptName',\n"
12203      "    'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
12204      "    'isConstructor'];\n"
12205      "for (var i = 0; i < setters.length; i++) {\n"
12206      "  var prop = setters[i];\n"
12207      "  Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
12208      "}\n");
12209  CompileRun("throw 'exception';");
12210  v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
12211}
12212
12213
12214v8::Handle<Value> AnalyzeStackOfEvalWithSourceURL(const v8::Arguments& args) {
12215  v8::HandleScope scope;
12216  v8::Handle<v8::StackTrace> stackTrace =
12217      v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
12218  CHECK_EQ(5, stackTrace->GetFrameCount());
12219  v8::Handle<v8::String> url = v8_str("eval_url");
12220  for (int i = 0; i < 3; i++) {
12221    v8::Handle<v8::String> name =
12222        stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
12223    CHECK(!name.IsEmpty());
12224    CHECK_EQ(url, name);
12225  }
12226  return v8::Undefined();
12227}
12228
12229
12230TEST(SourceURLInStackTrace) {
12231  v8::HandleScope scope;
12232  Local<ObjectTemplate> templ = ObjectTemplate::New();
12233  templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
12234             v8::FunctionTemplate::New(AnalyzeStackOfEvalWithSourceURL));
12235  LocalContext context(0, templ);
12236
12237  const char *source =
12238    "function outer() {\n"
12239    "function bar() {\n"
12240    "  AnalyzeStackOfEvalWithSourceURL();\n"
12241    "}\n"
12242    "function foo() {\n"
12243    "\n"
12244    "  bar();\n"
12245    "}\n"
12246    "foo();\n"
12247    "}\n"
12248    "eval('(' + outer +')()//@ sourceURL=eval_url');";
12249  CHECK(CompileRun(source)->IsUndefined());
12250}
12251
12252
12253// Test that idle notification can be handled and eventually returns true.
12254THREADED_TEST(IdleNotification) {
12255  bool rv = false;
12256  for (int i = 0; i < 100; i++) {
12257    rv = v8::V8::IdleNotification();
12258    if (rv)
12259      break;
12260  }
12261  CHECK(rv == true);
12262}
12263
12264
12265static uint32_t* stack_limit;
12266
12267static v8::Handle<Value> GetStackLimitCallback(const v8::Arguments& args) {
12268  stack_limit = reinterpret_cast<uint32_t*>(
12269      i::Isolate::Current()->stack_guard()->real_climit());
12270  return v8::Undefined();
12271}
12272
12273
12274// Uses the address of a local variable to determine the stack top now.
12275// Given a size, returns an address that is that far from the current
12276// top of stack.
12277static uint32_t* ComputeStackLimit(uint32_t size) {
12278  uint32_t* answer = &size - (size / sizeof(size));
12279  // If the size is very large and the stack is very near the bottom of
12280  // memory then the calculation above may wrap around and give an address
12281  // that is above the (downwards-growing) stack.  In that case we return
12282  // a very low address.
12283  if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
12284  return answer;
12285}
12286
12287
12288TEST(SetResourceConstraints) {
12289  static const int K = 1024;
12290  uint32_t* set_limit = ComputeStackLimit(128 * K);
12291
12292  // Set stack limit.
12293  v8::ResourceConstraints constraints;
12294  constraints.set_stack_limit(set_limit);
12295  CHECK(v8::SetResourceConstraints(&constraints));
12296
12297  // Execute a script.
12298  v8::HandleScope scope;
12299  LocalContext env;
12300  Local<v8::FunctionTemplate> fun_templ =
12301      v8::FunctionTemplate::New(GetStackLimitCallback);
12302  Local<Function> fun = fun_templ->GetFunction();
12303  env->Global()->Set(v8_str("get_stack_limit"), fun);
12304  CompileRun("get_stack_limit();");
12305
12306  CHECK(stack_limit == set_limit);
12307}
12308
12309
12310TEST(SetResourceConstraintsInThread) {
12311  uint32_t* set_limit;
12312  {
12313    v8::Locker locker;
12314    static const int K = 1024;
12315    set_limit = ComputeStackLimit(128 * K);
12316
12317    // Set stack limit.
12318    v8::ResourceConstraints constraints;
12319    constraints.set_stack_limit(set_limit);
12320    CHECK(v8::SetResourceConstraints(&constraints));
12321
12322    // Execute a script.
12323    v8::HandleScope scope;
12324    LocalContext env;
12325    Local<v8::FunctionTemplate> fun_templ =
12326        v8::FunctionTemplate::New(GetStackLimitCallback);
12327    Local<Function> fun = fun_templ->GetFunction();
12328    env->Global()->Set(v8_str("get_stack_limit"), fun);
12329    CompileRun("get_stack_limit();");
12330
12331    CHECK(stack_limit == set_limit);
12332  }
12333  {
12334    v8::Locker locker;
12335    CHECK(stack_limit == set_limit);
12336  }
12337}
12338
12339
12340THREADED_TEST(GetHeapStatistics) {
12341  v8::HandleScope scope;
12342  LocalContext c1;
12343  v8::HeapStatistics heap_statistics;
12344  CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
12345  CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
12346  v8::V8::GetHeapStatistics(&heap_statistics);
12347  CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
12348  CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
12349}
12350
12351
12352static double DoubleFromBits(uint64_t value) {
12353  double target;
12354  memcpy(&target, &value, sizeof(target));
12355  return target;
12356}
12357
12358
12359static uint64_t DoubleToBits(double value) {
12360  uint64_t target;
12361  memcpy(&target, &value, sizeof(target));
12362  return target;
12363}
12364
12365
12366static double DoubleToDateTime(double input) {
12367  double date_limit = 864e13;
12368  if (IsNaN(input) || input < -date_limit || input > date_limit) {
12369    return i::OS::nan_value();
12370  }
12371  return (input < 0) ? -(floor(-input)) : floor(input);
12372}
12373
12374// We don't have a consistent way to write 64-bit constants syntactically, so we
12375// split them into two 32-bit constants and combine them programmatically.
12376static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
12377  return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
12378}
12379
12380
12381THREADED_TEST(QuietSignalingNaNs) {
12382  v8::HandleScope scope;
12383  LocalContext context;
12384  v8::TryCatch try_catch;
12385
12386  // Special double values.
12387  double snan = DoubleFromBits(0x7ff00000, 0x00000001);
12388  double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
12389  double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
12390  double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
12391  double min_normal = DoubleFromBits(0x00100000, 0x00000000);
12392  double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
12393  double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
12394
12395  // Date values are capped at +/-100000000 days (times 864e5 ms per day)
12396  // on either side of the epoch.
12397  double date_limit = 864e13;
12398
12399  double test_values[] = {
12400      snan,
12401      qnan,
12402      infinity,
12403      max_normal,
12404      date_limit + 1,
12405      date_limit,
12406      min_normal,
12407      max_denormal,
12408      min_denormal,
12409      0,
12410      -0,
12411      -min_denormal,
12412      -max_denormal,
12413      -min_normal,
12414      -date_limit,
12415      -date_limit - 1,
12416      -max_normal,
12417      -infinity,
12418      -qnan,
12419      -snan
12420  };
12421  int num_test_values = 20;
12422
12423  for (int i = 0; i < num_test_values; i++) {
12424    double test_value = test_values[i];
12425
12426    // Check that Number::New preserves non-NaNs and quiets SNaNs.
12427    v8::Handle<v8::Value> number = v8::Number::New(test_value);
12428    double stored_number = number->NumberValue();
12429    if (!IsNaN(test_value)) {
12430      CHECK_EQ(test_value, stored_number);
12431    } else {
12432      uint64_t stored_bits = DoubleToBits(stored_number);
12433      // Check if quiet nan (bits 51..62 all set).
12434      CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
12435    }
12436
12437    // Check that Date::New preserves non-NaNs in the date range and
12438    // quiets SNaNs.
12439    v8::Handle<v8::Value> date = v8::Date::New(test_value);
12440    double expected_stored_date = DoubleToDateTime(test_value);
12441    double stored_date = date->NumberValue();
12442    if (!IsNaN(expected_stored_date)) {
12443      CHECK_EQ(expected_stored_date, stored_date);
12444    } else {
12445      uint64_t stored_bits = DoubleToBits(stored_date);
12446      // Check if quiet nan (bits 51..62 all set).
12447      CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
12448    }
12449  }
12450}
12451
12452
12453static v8::Handle<Value> SpaghettiIncident(const v8::Arguments& args) {
12454  v8::HandleScope scope;
12455  v8::TryCatch tc;
12456  v8::Handle<v8::String> str = args[0]->ToString();
12457  if (tc.HasCaught())
12458    return tc.ReThrow();
12459  return v8::Undefined();
12460}
12461
12462
12463// Test that an exception can be propagated down through a spaghetti
12464// stack using ReThrow.
12465THREADED_TEST(SpaghettiStackReThrow) {
12466  v8::HandleScope scope;
12467  LocalContext context;
12468  context->Global()->Set(
12469      v8::String::New("s"),
12470      v8::FunctionTemplate::New(SpaghettiIncident)->GetFunction());
12471  v8::TryCatch try_catch;
12472  CompileRun(
12473      "var i = 0;"
12474      "var o = {"
12475      "  toString: function () {"
12476      "    if (i == 10) {"
12477      "      throw 'Hey!';"
12478      "    } else {"
12479      "      i++;"
12480      "      return s(o);"
12481      "    }"
12482      "  }"
12483      "};"
12484      "s(o);");
12485  CHECK(try_catch.HasCaught());
12486  v8::String::Utf8Value value(try_catch.Exception());
12487  CHECK_EQ(0, strcmp(*value, "Hey!"));
12488}
12489
12490
12491TEST(Regress528) {
12492  v8::V8::Initialize();
12493
12494  v8::HandleScope scope;
12495  v8::Persistent<Context> context;
12496  v8::Persistent<Context> other_context;
12497  int gc_count;
12498
12499  // Create a context used to keep the code from aging in the compilation
12500  // cache.
12501  other_context = Context::New();
12502
12503  // Context-dependent context data creates reference from the compilation
12504  // cache to the global object.
12505  const char* source_simple = "1";
12506  context = Context::New();
12507  {
12508    v8::HandleScope scope;
12509
12510    context->Enter();
12511    Local<v8::String> obj = v8::String::New("");
12512    context->SetData(obj);
12513    CompileRun(source_simple);
12514    context->Exit();
12515  }
12516  context.Dispose();
12517  for (gc_count = 1; gc_count < 10; gc_count++) {
12518    other_context->Enter();
12519    CompileRun(source_simple);
12520    other_context->Exit();
12521    HEAP->CollectAllGarbage(false);
12522    if (GetGlobalObjectsCount() == 1) break;
12523  }
12524  CHECK_GE(2, gc_count);
12525  CHECK_EQ(1, GetGlobalObjectsCount());
12526
12527  // Eval in a function creates reference from the compilation cache to the
12528  // global object.
12529  const char* source_eval = "function f(){eval('1')}; f()";
12530  context = Context::New();
12531  {
12532    v8::HandleScope scope;
12533
12534    context->Enter();
12535    CompileRun(source_eval);
12536    context->Exit();
12537  }
12538  context.Dispose();
12539  for (gc_count = 1; gc_count < 10; gc_count++) {
12540    other_context->Enter();
12541    CompileRun(source_eval);
12542    other_context->Exit();
12543    HEAP->CollectAllGarbage(false);
12544    if (GetGlobalObjectsCount() == 1) break;
12545  }
12546  CHECK_GE(2, gc_count);
12547  CHECK_EQ(1, GetGlobalObjectsCount());
12548
12549  // Looking up the line number for an exception creates reference from the
12550  // compilation cache to the global object.
12551  const char* source_exception = "function f(){throw 1;} f()";
12552  context = Context::New();
12553  {
12554    v8::HandleScope scope;
12555
12556    context->Enter();
12557    v8::TryCatch try_catch;
12558    CompileRun(source_exception);
12559    CHECK(try_catch.HasCaught());
12560    v8::Handle<v8::Message> message = try_catch.Message();
12561    CHECK(!message.IsEmpty());
12562    CHECK_EQ(1, message->GetLineNumber());
12563    context->Exit();
12564  }
12565  context.Dispose();
12566  for (gc_count = 1; gc_count < 10; gc_count++) {
12567    other_context->Enter();
12568    CompileRun(source_exception);
12569    other_context->Exit();
12570    HEAP->CollectAllGarbage(false);
12571    if (GetGlobalObjectsCount() == 1) break;
12572  }
12573  CHECK_GE(2, gc_count);
12574  CHECK_EQ(1, GetGlobalObjectsCount());
12575
12576  other_context.Dispose();
12577}
12578
12579
12580THREADED_TEST(ScriptOrigin) {
12581  v8::HandleScope scope;
12582  LocalContext env;
12583  v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
12584  v8::Handle<v8::String> script = v8::String::New(
12585      "function f() {}\n\nfunction g() {}");
12586  v8::Script::Compile(script, &origin)->Run();
12587  v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
12588      env->Global()->Get(v8::String::New("f")));
12589  v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
12590      env->Global()->Get(v8::String::New("g")));
12591
12592  v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
12593  CHECK_EQ("test", *v8::String::AsciiValue(script_origin_f.ResourceName()));
12594  CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
12595
12596  v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
12597  CHECK_EQ("test", *v8::String::AsciiValue(script_origin_g.ResourceName()));
12598  CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
12599}
12600
12601
12602THREADED_TEST(ScriptLineNumber) {
12603  v8::HandleScope scope;
12604  LocalContext env;
12605  v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
12606  v8::Handle<v8::String> script = v8::String::New(
12607      "function f() {}\n\nfunction g() {}");
12608  v8::Script::Compile(script, &origin)->Run();
12609  v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
12610      env->Global()->Get(v8::String::New("f")));
12611  v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
12612      env->Global()->Get(v8::String::New("g")));
12613  CHECK_EQ(0, f->GetScriptLineNumber());
12614  CHECK_EQ(2, g->GetScriptLineNumber());
12615}
12616
12617
12618static v8::Handle<Value> GetterWhichReturns42(Local<String> name,
12619                                              const AccessorInfo& info) {
12620  return v8_num(42);
12621}
12622
12623
12624static void SetterWhichSetsYOnThisTo23(Local<String> name,
12625                                       Local<Value> value,
12626                                       const AccessorInfo& info) {
12627  info.This()->Set(v8_str("y"), v8_num(23));
12628}
12629
12630
12631TEST(SetterOnConstructorPrototype) {
12632  v8::HandleScope scope;
12633  Local<ObjectTemplate> templ = ObjectTemplate::New();
12634  templ->SetAccessor(v8_str("x"),
12635                     GetterWhichReturns42,
12636                     SetterWhichSetsYOnThisTo23);
12637  LocalContext context;
12638  context->Global()->Set(v8_str("P"), templ->NewInstance());
12639  CompileRun("function C1() {"
12640             "  this.x = 23;"
12641             "};"
12642             "C1.prototype = P;"
12643             "function C2() {"
12644             "  this.x = 23"
12645             "};"
12646             "C2.prototype = { };"
12647             "C2.prototype.__proto__ = P;");
12648
12649  v8::Local<v8::Script> script;
12650  script = v8::Script::Compile(v8_str("new C1();"));
12651  for (int i = 0; i < 10; i++) {
12652    v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
12653    CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
12654    CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
12655  }
12656
12657  script = v8::Script::Compile(v8_str("new C2();"));
12658  for (int i = 0; i < 10; i++) {
12659    v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
12660    CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
12661    CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
12662  }
12663}
12664
12665
12666static v8::Handle<Value> NamedPropertyGetterWhichReturns42(
12667    Local<String> name, const AccessorInfo& info) {
12668  return v8_num(42);
12669}
12670
12671
12672static v8::Handle<Value> NamedPropertySetterWhichSetsYOnThisTo23(
12673    Local<String> name, Local<Value> value, const AccessorInfo& info) {
12674  if (name->Equals(v8_str("x"))) {
12675    info.This()->Set(v8_str("y"), v8_num(23));
12676  }
12677  return v8::Handle<Value>();
12678}
12679
12680
12681THREADED_TEST(InterceptorOnConstructorPrototype) {
12682  v8::HandleScope scope;
12683  Local<ObjectTemplate> templ = ObjectTemplate::New();
12684  templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
12685                                 NamedPropertySetterWhichSetsYOnThisTo23);
12686  LocalContext context;
12687  context->Global()->Set(v8_str("P"), templ->NewInstance());
12688  CompileRun("function C1() {"
12689             "  this.x = 23;"
12690             "};"
12691             "C1.prototype = P;"
12692             "function C2() {"
12693             "  this.x = 23"
12694             "};"
12695             "C2.prototype = { };"
12696             "C2.prototype.__proto__ = P;");
12697
12698  v8::Local<v8::Script> script;
12699  script = v8::Script::Compile(v8_str("new C1();"));
12700  for (int i = 0; i < 10; i++) {
12701    v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
12702    CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
12703    CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
12704  }
12705
12706  script = v8::Script::Compile(v8_str("new C2();"));
12707  for (int i = 0; i < 10; i++) {
12708    v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
12709    CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
12710    CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
12711  }
12712}
12713
12714
12715TEST(Bug618) {
12716  const char* source = "function C1() {"
12717                       "  this.x = 23;"
12718                       "};"
12719                       "C1.prototype = P;";
12720
12721  v8::HandleScope scope;
12722  LocalContext context;
12723  v8::Local<v8::Script> script;
12724
12725  // Use a simple object as prototype.
12726  v8::Local<v8::Object> prototype = v8::Object::New();
12727  prototype->Set(v8_str("y"), v8_num(42));
12728  context->Global()->Set(v8_str("P"), prototype);
12729
12730  // This compile will add the code to the compilation cache.
12731  CompileRun(source);
12732
12733  script = v8::Script::Compile(v8_str("new C1();"));
12734  // Allow enough iterations for the inobject slack tracking logic
12735  // to finalize instance size and install the fast construct stub.
12736  for (int i = 0; i < 256; i++) {
12737    v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
12738    CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
12739    CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
12740  }
12741
12742  // Use an API object with accessors as prototype.
12743  Local<ObjectTemplate> templ = ObjectTemplate::New();
12744  templ->SetAccessor(v8_str("x"),
12745                     GetterWhichReturns42,
12746                     SetterWhichSetsYOnThisTo23);
12747  context->Global()->Set(v8_str("P"), templ->NewInstance());
12748
12749  // This compile will get the code from the compilation cache.
12750  CompileRun(source);
12751
12752  script = v8::Script::Compile(v8_str("new C1();"));
12753  for (int i = 0; i < 10; i++) {
12754    v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
12755    CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
12756    CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
12757  }
12758}
12759
12760int prologue_call_count = 0;
12761int epilogue_call_count = 0;
12762int prologue_call_count_second = 0;
12763int epilogue_call_count_second = 0;
12764
12765void PrologueCallback(v8::GCType, v8::GCCallbackFlags) {
12766  ++prologue_call_count;
12767}
12768
12769void EpilogueCallback(v8::GCType, v8::GCCallbackFlags) {
12770  ++epilogue_call_count;
12771}
12772
12773void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
12774  ++prologue_call_count_second;
12775}
12776
12777void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
12778  ++epilogue_call_count_second;
12779}
12780
12781TEST(GCCallbacks) {
12782  LocalContext context;
12783
12784  v8::V8::AddGCPrologueCallback(PrologueCallback);
12785  v8::V8::AddGCEpilogueCallback(EpilogueCallback);
12786  CHECK_EQ(0, prologue_call_count);
12787  CHECK_EQ(0, epilogue_call_count);
12788  HEAP->CollectAllGarbage(false);
12789  CHECK_EQ(1, prologue_call_count);
12790  CHECK_EQ(1, epilogue_call_count);
12791  v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
12792  v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
12793  HEAP->CollectAllGarbage(false);
12794  CHECK_EQ(2, prologue_call_count);
12795  CHECK_EQ(2, epilogue_call_count);
12796  CHECK_EQ(1, prologue_call_count_second);
12797  CHECK_EQ(1, epilogue_call_count_second);
12798  v8::V8::RemoveGCPrologueCallback(PrologueCallback);
12799  v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
12800  HEAP->CollectAllGarbage(false);
12801  CHECK_EQ(2, prologue_call_count);
12802  CHECK_EQ(2, epilogue_call_count);
12803  CHECK_EQ(2, prologue_call_count_second);
12804  CHECK_EQ(2, epilogue_call_count_second);
12805  v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
12806  v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
12807  HEAP->CollectAllGarbage(false);
12808  CHECK_EQ(2, prologue_call_count);
12809  CHECK_EQ(2, epilogue_call_count);
12810  CHECK_EQ(2, prologue_call_count_second);
12811  CHECK_EQ(2, epilogue_call_count_second);
12812}
12813
12814
12815THREADED_TEST(AddToJSFunctionResultCache) {
12816  i::FLAG_allow_natives_syntax = true;
12817  v8::HandleScope scope;
12818
12819  LocalContext context;
12820
12821  const char* code =
12822      "(function() {"
12823      "  var key0 = 'a';"
12824      "  var key1 = 'b';"
12825      "  var r0 = %_GetFromCache(0, key0);"
12826      "  var r1 = %_GetFromCache(0, key1);"
12827      "  var r0_ = %_GetFromCache(0, key0);"
12828      "  if (r0 !== r0_)"
12829      "    return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
12830      "  var r1_ = %_GetFromCache(0, key1);"
12831      "  if (r1 !== r1_)"
12832      "    return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
12833      "  return 'PASSED';"
12834      "})()";
12835  HEAP->ClearJSFunctionResultCaches();
12836  ExpectString(code, "PASSED");
12837}
12838
12839
12840static const int k0CacheSize = 16;
12841
12842THREADED_TEST(FillJSFunctionResultCache) {
12843  i::FLAG_allow_natives_syntax = true;
12844  v8::HandleScope scope;
12845
12846  LocalContext context;
12847
12848  const char* code =
12849      "(function() {"
12850      "  var k = 'a';"
12851      "  var r = %_GetFromCache(0, k);"
12852      "  for (var i = 0; i < 16; i++) {"
12853      "    %_GetFromCache(0, 'a' + i);"
12854      "  };"
12855      "  if (r === %_GetFromCache(0, k))"
12856      "    return 'FAILED: k0CacheSize is too small';"
12857      "  return 'PASSED';"
12858      "})()";
12859  HEAP->ClearJSFunctionResultCaches();
12860  ExpectString(code, "PASSED");
12861}
12862
12863
12864THREADED_TEST(RoundRobinGetFromCache) {
12865  i::FLAG_allow_natives_syntax = true;
12866  v8::HandleScope scope;
12867
12868  LocalContext context;
12869
12870  const char* code =
12871      "(function() {"
12872      "  var keys = [];"
12873      "  for (var i = 0; i < 16; i++) keys.push(i);"
12874      "  var values = [];"
12875      "  for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
12876      "  for (var i = 0; i < 16; i++) {"
12877      "    var v = %_GetFromCache(0, keys[i]);"
12878      "    if (v !== values[i])"
12879      "      return 'Wrong value for ' + "
12880      "          keys[i] + ': ' + v + ' vs. ' + values[i];"
12881      "  };"
12882      "  return 'PASSED';"
12883      "})()";
12884  HEAP->ClearJSFunctionResultCaches();
12885  ExpectString(code, "PASSED");
12886}
12887
12888
12889THREADED_TEST(ReverseGetFromCache) {
12890  i::FLAG_allow_natives_syntax = true;
12891  v8::HandleScope scope;
12892
12893  LocalContext context;
12894
12895  const char* code =
12896      "(function() {"
12897      "  var keys = [];"
12898      "  for (var i = 0; i < 16; i++) keys.push(i);"
12899      "  var values = [];"
12900      "  for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
12901      "  for (var i = 15; i >= 16; i--) {"
12902      "    var v = %_GetFromCache(0, keys[i]);"
12903      "    if (v !== values[i])"
12904      "      return 'Wrong value for ' + "
12905      "          keys[i] + ': ' + v + ' vs. ' + values[i];"
12906      "  };"
12907      "  return 'PASSED';"
12908      "})()";
12909  HEAP->ClearJSFunctionResultCaches();
12910  ExpectString(code, "PASSED");
12911}
12912
12913
12914THREADED_TEST(TestEviction) {
12915  i::FLAG_allow_natives_syntax = true;
12916  v8::HandleScope scope;
12917
12918  LocalContext context;
12919
12920  const char* code =
12921      "(function() {"
12922      "  for (var i = 0; i < 2*16; i++) {"
12923      "    %_GetFromCache(0, 'a' + i);"
12924      "  };"
12925      "  return 'PASSED';"
12926      "})()";
12927  HEAP->ClearJSFunctionResultCaches();
12928  ExpectString(code, "PASSED");
12929}
12930
12931
12932THREADED_TEST(TwoByteStringInAsciiCons) {
12933  // See Chromium issue 47824.
12934  v8::HandleScope scope;
12935
12936  LocalContext context;
12937  const char* init_code =
12938      "var str1 = 'abelspendabel';"
12939      "var str2 = str1 + str1 + str1;"
12940      "str2;";
12941  Local<Value> result = CompileRun(init_code);
12942
12943  CHECK(result->IsString());
12944  i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
12945  int length = string->length();
12946  CHECK(string->IsAsciiRepresentation());
12947
12948  FlattenString(string);
12949  i::Handle<i::String> flat_string = FlattenGetString(string);
12950
12951  CHECK(string->IsAsciiRepresentation());
12952  CHECK(flat_string->IsAsciiRepresentation());
12953
12954  // Create external resource.
12955  uint16_t* uc16_buffer = new uint16_t[length + 1];
12956
12957  i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
12958  uc16_buffer[length] = 0;
12959
12960  TestResource resource(uc16_buffer);
12961
12962  flat_string->MakeExternal(&resource);
12963
12964  CHECK(flat_string->IsTwoByteRepresentation());
12965
12966  // At this point, we should have a Cons string which is flat and ASCII,
12967  // with a first half that is a two-byte string (although it only contains
12968  // ASCII characters). This is a valid sequence of steps, and it can happen
12969  // in real pages.
12970
12971  CHECK(string->IsAsciiRepresentation());
12972  i::ConsString* cons = i::ConsString::cast(*string);
12973  CHECK_EQ(0, cons->second()->length());
12974  CHECK(cons->first()->IsTwoByteRepresentation());
12975
12976  // Check that some string operations work.
12977
12978  // Atom RegExp.
12979  Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
12980  CHECK_EQ(6, reresult->Int32Value());
12981
12982  // Nonatom RegExp.
12983  reresult = CompileRun("str2.match(/abe./g).length;");
12984  CHECK_EQ(6, reresult->Int32Value());
12985
12986  reresult = CompileRun("str2.search(/bel/g);");
12987  CHECK_EQ(1, reresult->Int32Value());
12988
12989  reresult = CompileRun("str2.search(/be./g);");
12990  CHECK_EQ(1, reresult->Int32Value());
12991
12992  ExpectTrue("/bel/g.test(str2);");
12993
12994  ExpectTrue("/be./g.test(str2);");
12995
12996  reresult = CompileRun("/bel/g.exec(str2);");
12997  CHECK(!reresult->IsNull());
12998
12999  reresult = CompileRun("/be./g.exec(str2);");
13000  CHECK(!reresult->IsNull());
13001
13002  ExpectString("str2.substring(2, 10);", "elspenda");
13003
13004  ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
13005
13006  ExpectString("str2.charAt(2);", "e");
13007
13008  reresult = CompileRun("str2.charCodeAt(2);");
13009  CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
13010}
13011
13012
13013// Failed access check callback that performs a GC on each invocation.
13014void FailedAccessCheckCallbackGC(Local<v8::Object> target,
13015                                 v8::AccessType type,
13016                                 Local<v8::Value> data) {
13017  HEAP->CollectAllGarbage(true);
13018}
13019
13020
13021TEST(GCInFailedAccessCheckCallback) {
13022  // Install a failed access check callback that performs a GC on each
13023  // invocation. Then force the callback to be called from va
13024
13025  v8::V8::Initialize();
13026  v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
13027
13028  v8::HandleScope scope;
13029
13030  // Create an ObjectTemplate for global objects and install access
13031  // check callbacks that will block access.
13032  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
13033  global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
13034                                           IndexedGetAccessBlocker,
13035                                           v8::Handle<v8::Value>(),
13036                                           false);
13037
13038  // Create a context and set an x property on it's global object.
13039  LocalContext context0(NULL, global_template);
13040  context0->Global()->Set(v8_str("x"), v8_num(42));
13041  v8::Handle<v8::Object> global0 = context0->Global();
13042
13043  // Create a context with a different security token so that the
13044  // failed access check callback will be called on each access.
13045  LocalContext context1(NULL, global_template);
13046  context1->Global()->Set(v8_str("other"), global0);
13047
13048  // Get property with failed access check.
13049  ExpectUndefined("other.x");
13050
13051  // Get element with failed access check.
13052  ExpectUndefined("other[0]");
13053
13054  // Set property with failed access check.
13055  v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
13056  CHECK(result->IsObject());
13057
13058  // Set element with failed access check.
13059  result = CompileRun("other[0] = new Object()");
13060  CHECK(result->IsObject());
13061
13062  // Get property attribute with failed access check.
13063  ExpectFalse("\'x\' in other");
13064
13065  // Get property attribute for element with failed access check.
13066  ExpectFalse("0 in other");
13067
13068  // Delete property.
13069  ExpectFalse("delete other.x");
13070
13071  // Delete element.
13072  CHECK_EQ(false, global0->Delete(0));
13073
13074  // DefineAccessor.
13075  CHECK_EQ(false,
13076           global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
13077
13078  // Define JavaScript accessor.
13079  ExpectUndefined("Object.prototype.__defineGetter__.call("
13080                  "    other, \'x\', function() { return 42; })");
13081
13082  // LookupAccessor.
13083  ExpectUndefined("Object.prototype.__lookupGetter__.call("
13084                  "    other, \'x\')");
13085
13086  // HasLocalElement.
13087  ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
13088
13089  CHECK_EQ(false, global0->HasRealIndexedProperty(0));
13090  CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
13091  CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
13092
13093  // Reset the failed access check callback so it does not influence
13094  // the other tests.
13095  v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
13096}
13097
13098TEST(DefaultIsolateGetCurrent) {
13099  CHECK(v8::Isolate::GetCurrent() != NULL);
13100  v8::Isolate* isolate = v8::Isolate::GetCurrent();
13101  CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
13102  printf("*** %s\n", "DefaultIsolateGetCurrent success");
13103}
13104
13105TEST(IsolateNewDispose) {
13106  v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
13107  v8::Isolate* isolate = v8::Isolate::New();
13108  CHECK(isolate != NULL);
13109  CHECK(!reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
13110  CHECK(current_isolate != isolate);
13111  CHECK(current_isolate == v8::Isolate::GetCurrent());
13112
13113  v8::V8::SetFatalErrorHandler(StoringErrorCallback);
13114  last_location = last_message = NULL;
13115  isolate->Dispose();
13116  CHECK_EQ(last_location, NULL);
13117  CHECK_EQ(last_message, NULL);
13118}
13119
13120TEST(IsolateEnterExitDefault) {
13121  v8::HandleScope scope;
13122  LocalContext context;
13123  v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
13124  CHECK(current_isolate != NULL);  // Default isolate.
13125  ExpectString("'hello'", "hello");
13126  current_isolate->Enter();
13127  ExpectString("'still working'", "still working");
13128  current_isolate->Exit();
13129  ExpectString("'still working 2'", "still working 2");
13130  current_isolate->Exit();
13131  // Default isolate is always, well, 'default current'.
13132  CHECK_EQ(v8::Isolate::GetCurrent(), current_isolate);
13133  // Still working since default isolate is auto-entering any thread
13134  // that has no isolate and attempts to execute V8 APIs.
13135  ExpectString("'still working 3'", "still working 3");
13136}
13137
13138TEST(DisposeDefaultIsolate) {
13139  v8::V8::SetFatalErrorHandler(StoringErrorCallback);
13140
13141  // Run some V8 code to trigger default isolate to become 'current'.
13142  v8::HandleScope scope;
13143  LocalContext context;
13144  ExpectString("'run some V8'", "run some V8");
13145
13146  v8::Isolate* isolate = v8::Isolate::GetCurrent();
13147  CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
13148  last_location = last_message = NULL;
13149  isolate->Dispose();
13150  // It is not possible to dispose default isolate via Isolate API.
13151  CHECK_NE(last_location, NULL);
13152  CHECK_NE(last_message, NULL);
13153}
13154
13155TEST(RunDefaultAndAnotherIsolate) {
13156  v8::HandleScope scope;
13157  LocalContext context;
13158
13159  // Enter new isolate.
13160  v8::Isolate* isolate = v8::Isolate::New();
13161  CHECK(isolate);
13162  isolate->Enter();
13163  { // Need this block because subsequent Exit() will deallocate Heap,
13164    // so we need all scope objects to be deconstructed when it happens.
13165    v8::HandleScope scope_new;
13166    LocalContext context_new;
13167
13168    // Run something in new isolate.
13169    CompileRun("var foo = 153;");
13170    ExpectTrue("function f() { return foo == 153; }; f()");
13171  }
13172  isolate->Exit();
13173
13174  // This runs automatically in default isolate.
13175  // Variables in another isolate should be not available.
13176  ExpectTrue("function f() {"
13177             "  try {"
13178             "    foo;"
13179             "    return false;"
13180             "  } catch(e) {"
13181             "    return true;"
13182             "  }"
13183             "};"
13184             "var bar = 371;"
13185             "f()");
13186
13187  v8::V8::SetFatalErrorHandler(StoringErrorCallback);
13188  last_location = last_message = NULL;
13189  isolate->Dispose();
13190  CHECK_EQ(last_location, NULL);
13191  CHECK_EQ(last_message, NULL);
13192
13193  // Check that default isolate still runs.
13194  ExpectTrue("function f() { return bar == 371; }; f()");
13195}
13196
13197TEST(DisposeIsolateWhenInUse) {
13198  v8::Isolate* isolate = v8::Isolate::New();
13199  CHECK(isolate);
13200  isolate->Enter();
13201  v8::HandleScope scope;
13202  LocalContext context;
13203  // Run something in this isolate.
13204  ExpectTrue("true");
13205  v8::V8::SetFatalErrorHandler(StoringErrorCallback);
13206  last_location = last_message = NULL;
13207  // Still entered, should fail.
13208  isolate->Dispose();
13209  CHECK_NE(last_location, NULL);
13210  CHECK_NE(last_message, NULL);
13211}
13212
13213TEST(RunTwoIsolatesOnSingleThread) {
13214  // Run isolate 1.
13215  v8::Isolate* isolate1 = v8::Isolate::New();
13216  isolate1->Enter();
13217  v8::Persistent<v8::Context> context1 = v8::Context::New();
13218
13219  {
13220    v8::Context::Scope cscope(context1);
13221    v8::HandleScope scope;
13222    // Run something in new isolate.
13223    CompileRun("var foo = 'isolate 1';");
13224    ExpectString("function f() { return foo; }; f()", "isolate 1");
13225  }
13226
13227  // Run isolate 2.
13228  v8::Isolate* isolate2 = v8::Isolate::New();
13229  v8::Persistent<v8::Context> context2;
13230
13231  {
13232    v8::Isolate::Scope iscope(isolate2);
13233    context2 = v8::Context::New();
13234    v8::Context::Scope cscope(context2);
13235    v8::HandleScope scope;
13236
13237    // Run something in new isolate.
13238    CompileRun("var foo = 'isolate 2';");
13239    ExpectString("function f() { return foo; }; f()", "isolate 2");
13240  }
13241
13242  {
13243    v8::Context::Scope cscope(context1);
13244    v8::HandleScope scope;
13245    // Now again in isolate 1
13246    ExpectString("function f() { return foo; }; f()", "isolate 1");
13247  }
13248
13249  isolate1->Exit();
13250
13251  // Run some stuff in default isolate.
13252  v8::Persistent<v8::Context> context_default = v8::Context::New();
13253
13254  {
13255    v8::Context::Scope cscope(context_default);
13256    v8::HandleScope scope;
13257    // Variables in other isolates should be not available, verify there
13258    // is an exception.
13259    ExpectTrue("function f() {"
13260               "  try {"
13261               "    foo;"
13262               "    return false;"
13263               "  } catch(e) {"
13264               "    return true;"
13265               "  }"
13266               "};"
13267               "var isDefaultIsolate = true;"
13268               "f()");
13269  }
13270
13271  isolate1->Enter();
13272
13273  {
13274    v8::Isolate::Scope iscope(isolate2);
13275    v8::Context::Scope cscope(context2);
13276    v8::HandleScope scope;
13277    ExpectString("function f() { return foo; }; f()", "isolate 2");
13278  }
13279
13280  {
13281    v8::Context::Scope cscope(context1);
13282    v8::HandleScope scope;
13283    ExpectString("function f() { return foo; }; f()", "isolate 1");
13284  }
13285
13286  {
13287    v8::Isolate::Scope iscope(isolate2);
13288    context2.Dispose();
13289  }
13290
13291  context1.Dispose();
13292  isolate1->Exit();
13293
13294  v8::V8::SetFatalErrorHandler(StoringErrorCallback);
13295  last_location = last_message = NULL;
13296
13297  isolate1->Dispose();
13298  CHECK_EQ(last_location, NULL);
13299  CHECK_EQ(last_message, NULL);
13300
13301  isolate2->Dispose();
13302  CHECK_EQ(last_location, NULL);
13303  CHECK_EQ(last_message, NULL);
13304
13305  // Check that default isolate still runs.
13306  {
13307    v8::Context::Scope cscope(context_default);
13308    v8::HandleScope scope;
13309    ExpectTrue("function f() { return isDefaultIsolate; }; f()");
13310  }
13311}
13312
13313static int CalcFibonacci(v8::Isolate* isolate, int limit) {
13314  v8::Isolate::Scope isolate_scope(isolate);
13315  v8::HandleScope scope;
13316  LocalContext context;
13317  i::ScopedVector<char> code(1024);
13318  i::OS::SNPrintF(code, "function fib(n) {"
13319                        "  if (n <= 2) return 1;"
13320                        "  return fib(n-1) + fib(n-2);"
13321                        "}"
13322                        "fib(%d)", limit);
13323  Local<Value> value = CompileRun(code.start());
13324  CHECK(value->IsNumber());
13325  return static_cast<int>(value->NumberValue());
13326}
13327
13328class IsolateThread : public v8::internal::Thread {
13329 public:
13330  explicit IsolateThread(v8::Isolate* isolate, int fib_limit)
13331      : Thread(NULL, "IsolateThread"),
13332        isolate_(isolate),
13333        fib_limit_(fib_limit),
13334        result_(0) { }
13335
13336  void Run() {
13337    result_ = CalcFibonacci(isolate_, fib_limit_);
13338  }
13339
13340  int result() { return result_; }
13341
13342 private:
13343  v8::Isolate* isolate_;
13344  int fib_limit_;
13345  int result_;
13346};
13347
13348TEST(MultipleIsolatesOnIndividualThreads) {
13349  v8::Isolate* isolate1 = v8::Isolate::New();
13350  v8::Isolate* isolate2 = v8::Isolate::New();
13351
13352  IsolateThread thread1(isolate1, 21);
13353  IsolateThread thread2(isolate2, 12);
13354
13355  // Compute some fibonacci numbers on 3 threads in 3 isolates.
13356  thread1.Start();
13357  thread2.Start();
13358
13359  int result1 = CalcFibonacci(v8::Isolate::GetCurrent(), 21);
13360  int result2 = CalcFibonacci(v8::Isolate::GetCurrent(), 12);
13361
13362  thread1.Join();
13363  thread2.Join();
13364
13365  // Compare results. The actual fibonacci numbers for 12 and 21 are taken
13366  // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
13367  CHECK_EQ(result1, 10946);
13368  CHECK_EQ(result2, 144);
13369  CHECK_EQ(result1, thread1.result());
13370  CHECK_EQ(result2, thread2.result());
13371
13372  isolate1->Dispose();
13373  isolate2->Dispose();
13374}
13375
13376
13377class InitDefaultIsolateThread : public v8::internal::Thread {
13378 public:
13379  enum TestCase {
13380    IgnoreOOM,
13381    SetResourceConstraints,
13382    SetFatalHandler,
13383    SetCounterFunction,
13384    SetCreateHistogramFunction,
13385    SetAddHistogramSampleFunction
13386  };
13387
13388  explicit InitDefaultIsolateThread(TestCase testCase)
13389      : Thread(NULL, "InitDefaultIsolateThread"),
13390        testCase_(testCase),
13391        result_(false) { }
13392
13393  void Run() {
13394    switch (testCase_) {
13395    case IgnoreOOM:
13396      v8::V8::IgnoreOutOfMemoryException();
13397      break;
13398
13399    case SetResourceConstraints: {
13400      static const int K = 1024;
13401      v8::ResourceConstraints constraints;
13402      constraints.set_max_young_space_size(256 * K);
13403      constraints.set_max_old_space_size(4 * K * K);
13404      v8::SetResourceConstraints(&constraints);
13405      break;
13406    }
13407
13408    case SetFatalHandler:
13409      v8::V8::SetFatalErrorHandler(NULL);
13410      break;
13411
13412    case SetCounterFunction:
13413      v8::V8::SetCounterFunction(NULL);
13414      break;
13415
13416    case SetCreateHistogramFunction:
13417      v8::V8::SetCreateHistogramFunction(NULL);
13418      break;
13419
13420    case SetAddHistogramSampleFunction:
13421      v8::V8::SetAddHistogramSampleFunction(NULL);
13422      break;
13423    }
13424    result_ = true;
13425  }
13426
13427  bool result() { return result_; }
13428
13429 private:
13430  TestCase testCase_;
13431  bool result_;
13432};
13433
13434
13435static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
13436  InitDefaultIsolateThread thread(testCase);
13437  thread.Start();
13438  thread.Join();
13439  CHECK_EQ(thread.result(), true);
13440}
13441
13442TEST(InitializeDefaultIsolateOnSecondaryThread1) {
13443  InitializeTestHelper(InitDefaultIsolateThread::IgnoreOOM);
13444}
13445
13446TEST(InitializeDefaultIsolateOnSecondaryThread2) {
13447  InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
13448}
13449
13450TEST(InitializeDefaultIsolateOnSecondaryThread3) {
13451  InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
13452}
13453
13454TEST(InitializeDefaultIsolateOnSecondaryThread4) {
13455  InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
13456}
13457
13458TEST(InitializeDefaultIsolateOnSecondaryThread5) {
13459  InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
13460}
13461
13462TEST(InitializeDefaultIsolateOnSecondaryThread6) {
13463  InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
13464}
13465
13466
13467TEST(StringCheckMultipleContexts) {
13468  const char* code =
13469      "(function() { return \"a\".charAt(0); })()";
13470
13471  {
13472    // Run the code twice in the first context to initialize the call IC.
13473    v8::HandleScope scope;
13474    LocalContext context1;
13475    ExpectString(code, "a");
13476    ExpectString(code, "a");
13477  }
13478
13479  {
13480    // Change the String.prototype in the second context and check
13481    // that the right function gets called.
13482    v8::HandleScope scope;
13483    LocalContext context2;
13484    CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
13485    ExpectString(code, "not a");
13486  }
13487}
13488
13489
13490TEST(NumberCheckMultipleContexts) {
13491  const char* code =
13492      "(function() { return (42).toString(); })()";
13493
13494  {
13495    // Run the code twice in the first context to initialize the call IC.
13496    v8::HandleScope scope;
13497    LocalContext context1;
13498    ExpectString(code, "42");
13499    ExpectString(code, "42");
13500  }
13501
13502  {
13503    // Change the Number.prototype in the second context and check
13504    // that the right function gets called.
13505    v8::HandleScope scope;
13506    LocalContext context2;
13507    CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
13508    ExpectString(code, "not 42");
13509  }
13510}
13511
13512
13513TEST(BooleanCheckMultipleContexts) {
13514  const char* code =
13515      "(function() { return true.toString(); })()";
13516
13517  {
13518    // Run the code twice in the first context to initialize the call IC.
13519    v8::HandleScope scope;
13520    LocalContext context1;
13521    ExpectString(code, "true");
13522    ExpectString(code, "true");
13523  }
13524
13525  {
13526    // Change the Boolean.prototype in the second context and check
13527    // that the right function gets called.
13528    v8::HandleScope scope;
13529    LocalContext context2;
13530    CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
13531    ExpectString(code, "");
13532  }
13533}
13534
13535
13536TEST(DontDeleteCellLoadIC) {
13537  const char* function_code =
13538      "function readCell() { while (true) { return cell; } }";
13539
13540  {
13541    // Run the code twice in the first context to initialize the load
13542    // IC for a don't delete cell.
13543    v8::HandleScope scope;
13544    LocalContext context1;
13545    CompileRun("var cell = \"first\";");
13546    ExpectBoolean("delete cell", false);
13547    CompileRun(function_code);
13548    ExpectString("readCell()", "first");
13549    ExpectString("readCell()", "first");
13550  }
13551
13552  {
13553    // Use a deletable cell in the second context.
13554    v8::HandleScope scope;
13555    LocalContext context2;
13556    CompileRun("cell = \"second\";");
13557    CompileRun(function_code);
13558    ExpectString("readCell()", "second");
13559    ExpectBoolean("delete cell", true);
13560    ExpectString("(function() {"
13561                 "  try {"
13562                 "    return readCell();"
13563                 "  } catch(e) {"
13564                 "    return e.toString();"
13565                 "  }"
13566                 "})()",
13567                 "ReferenceError: cell is not defined");
13568    CompileRun("cell = \"new_second\";");
13569    HEAP->CollectAllGarbage(true);
13570    ExpectString("readCell()", "new_second");
13571    ExpectString("readCell()", "new_second");
13572  }
13573}
13574
13575
13576TEST(DontDeleteCellLoadICForceDelete) {
13577  const char* function_code =
13578      "function readCell() { while (true) { return cell; } }";
13579
13580  // Run the code twice to initialize the load IC for a don't delete
13581  // cell.
13582  v8::HandleScope scope;
13583  LocalContext context;
13584  CompileRun("var cell = \"value\";");
13585  ExpectBoolean("delete cell", false);
13586  CompileRun(function_code);
13587  ExpectString("readCell()", "value");
13588  ExpectString("readCell()", "value");
13589
13590  // Delete the cell using the API and check the inlined code works
13591  // correctly.
13592  CHECK(context->Global()->ForceDelete(v8_str("cell")));
13593  ExpectString("(function() {"
13594               "  try {"
13595               "    return readCell();"
13596               "  } catch(e) {"
13597               "    return e.toString();"
13598               "  }"
13599               "})()",
13600               "ReferenceError: cell is not defined");
13601}
13602
13603
13604TEST(DontDeleteCellLoadICAPI) {
13605  const char* function_code =
13606      "function readCell() { while (true) { return cell; } }";
13607
13608  // Run the code twice to initialize the load IC for a don't delete
13609  // cell created using the API.
13610  v8::HandleScope scope;
13611  LocalContext context;
13612  context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete);
13613  ExpectBoolean("delete cell", false);
13614  CompileRun(function_code);
13615  ExpectString("readCell()", "value");
13616  ExpectString("readCell()", "value");
13617
13618  // Delete the cell using the API and check the inlined code works
13619  // correctly.
13620  CHECK(context->Global()->ForceDelete(v8_str("cell")));
13621  ExpectString("(function() {"
13622               "  try {"
13623               "    return readCell();"
13624               "  } catch(e) {"
13625               "    return e.toString();"
13626               "  }"
13627               "})()",
13628               "ReferenceError: cell is not defined");
13629}
13630
13631
13632TEST(GlobalLoadICGC) {
13633  const char* function_code =
13634      "function readCell() { while (true) { return cell; } }";
13635
13636  // Check inline load code for a don't delete cell is cleared during
13637  // GC.
13638  {
13639    v8::HandleScope scope;
13640    LocalContext context;
13641    CompileRun("var cell = \"value\";");
13642    ExpectBoolean("delete cell", false);
13643    CompileRun(function_code);
13644    ExpectString("readCell()", "value");
13645    ExpectString("readCell()", "value");
13646  }
13647  {
13648    v8::HandleScope scope;
13649    LocalContext context2;
13650    // Hold the code object in the second context.
13651    CompileRun(function_code);
13652    CheckSurvivingGlobalObjectsCount(1);
13653  }
13654
13655  // Check inline load code for a deletable cell is cleared during GC.
13656  {
13657    v8::HandleScope scope;
13658    LocalContext context;
13659    CompileRun("cell = \"value\";");
13660    CompileRun(function_code);
13661    ExpectString("readCell()", "value");
13662    ExpectString("readCell()", "value");
13663  }
13664  {
13665    v8::HandleScope scope;
13666    LocalContext context2;
13667    // Hold the code object in the second context.
13668    CompileRun(function_code);
13669    CheckSurvivingGlobalObjectsCount(1);
13670  }
13671}
13672
13673
13674TEST(RegExp) {
13675  v8::HandleScope scope;
13676  LocalContext context;
13677
13678  v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
13679  CHECK(re->IsRegExp());
13680  CHECK(re->GetSource()->Equals(v8_str("foo")));
13681  CHECK_EQ(re->GetFlags(), v8::RegExp::kNone);
13682
13683  re = v8::RegExp::New(v8_str("bar"),
13684                       static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
13685                                                      v8::RegExp::kGlobal));
13686  CHECK(re->IsRegExp());
13687  CHECK(re->GetSource()->Equals(v8_str("bar")));
13688  CHECK_EQ(static_cast<int>(re->GetFlags()),
13689           v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal);
13690
13691  re = v8::RegExp::New(v8_str("baz"),
13692                       static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
13693                                                      v8::RegExp::kMultiline));
13694  CHECK(re->IsRegExp());
13695  CHECK(re->GetSource()->Equals(v8_str("baz")));
13696  CHECK_EQ(static_cast<int>(re->GetFlags()),
13697           v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline);
13698
13699  re = CompileRun("/quux/").As<v8::RegExp>();
13700  CHECK(re->IsRegExp());
13701  CHECK(re->GetSource()->Equals(v8_str("quux")));
13702  CHECK_EQ(re->GetFlags(), v8::RegExp::kNone);
13703
13704  re = CompileRun("/quux/gm").As<v8::RegExp>();
13705  CHECK(re->IsRegExp());
13706  CHECK(re->GetSource()->Equals(v8_str("quux")));
13707  CHECK_EQ(static_cast<int>(re->GetFlags()),
13708           v8::RegExp::kGlobal | v8::RegExp::kMultiline);
13709
13710  // Override the RegExp constructor and check the API constructor
13711  // still works.
13712  CompileRun("RegExp = function() {}");
13713
13714  re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
13715  CHECK(re->IsRegExp());
13716  CHECK(re->GetSource()->Equals(v8_str("foobar")));
13717  CHECK_EQ(re->GetFlags(), v8::RegExp::kNone);
13718
13719  re = v8::RegExp::New(v8_str("foobarbaz"),
13720                       static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
13721                                                      v8::RegExp::kMultiline));
13722  CHECK(re->IsRegExp());
13723  CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
13724  CHECK_EQ(static_cast<int>(re->GetFlags()),
13725           v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline);
13726
13727  context->Global()->Set(v8_str("re"), re);
13728  ExpectTrue("re.test('FoobarbaZ')");
13729
13730  v8::TryCatch try_catch;
13731  re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
13732  CHECK(re.IsEmpty());
13733  CHECK(try_catch.HasCaught());
13734  context->Global()->Set(v8_str("ex"), try_catch.Exception());
13735  ExpectTrue("ex instanceof SyntaxError");
13736}
13737
13738
13739THREADED_TEST(Equals) {
13740  v8::HandleScope handleScope;
13741  LocalContext localContext;
13742
13743  v8::Handle<v8::Object> globalProxy = localContext->Global();
13744  v8::Handle<Value> global = globalProxy->GetPrototype();
13745
13746  CHECK(global->StrictEquals(global));
13747  CHECK(!global->StrictEquals(globalProxy));
13748  CHECK(!globalProxy->StrictEquals(global));
13749  CHECK(globalProxy->StrictEquals(globalProxy));
13750
13751  CHECK(global->Equals(global));
13752  CHECK(!global->Equals(globalProxy));
13753  CHECK(!globalProxy->Equals(global));
13754  CHECK(globalProxy->Equals(globalProxy));
13755}
13756
13757
13758static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
13759                                    const v8::AccessorInfo& info ) {
13760  return v8_str("42!");
13761}
13762
13763
13764static v8::Handle<v8::Array> Enumerator(const v8::AccessorInfo& info) {
13765  v8::Handle<v8::Array> result = v8::Array::New();
13766  result->Set(0, v8_str("universalAnswer"));
13767  return result;
13768}
13769
13770
13771TEST(NamedEnumeratorAndForIn) {
13772  v8::HandleScope handle_scope;
13773  LocalContext context;
13774  v8::Context::Scope context_scope(context.local());
13775
13776  v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New();
13777  tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
13778  context->Global()->Set(v8_str("o"), tmpl->NewInstance());
13779  v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
13780        "var result = []; for (var k in o) result.push(k); result"));
13781  CHECK_EQ(1, result->Length());
13782  CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
13783}
13784
13785
13786TEST(DefinePropertyPostDetach) {
13787  v8::HandleScope scope;
13788  LocalContext context;
13789  v8::Handle<v8::Object> proxy = context->Global();
13790  v8::Handle<v8::Function> define_property =
13791      CompileRun("(function() {"
13792                 "  Object.defineProperty("
13793                 "    this,"
13794                 "    1,"
13795                 "    { configurable: true, enumerable: true, value: 3 });"
13796                 "})").As<Function>();
13797  context->DetachGlobal();
13798  define_property->Call(proxy, 0, NULL);
13799}
13800
13801
13802static void InstallContextId(v8::Handle<Context> context, int id) {
13803  Context::Scope scope(context);
13804  CompileRun("Object.prototype").As<Object>()->
13805      Set(v8_str("context_id"), v8::Integer::New(id));
13806}
13807
13808
13809static void CheckContextId(v8::Handle<Object> object, int expected) {
13810  CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
13811}
13812
13813
13814THREADED_TEST(CreationContext) {
13815  HandleScope handle_scope;
13816  Persistent<Context> context1 = Context::New();
13817  InstallContextId(context1, 1);
13818  Persistent<Context> context2 = Context::New();
13819  InstallContextId(context2, 2);
13820  Persistent<Context> context3 = Context::New();
13821  InstallContextId(context3, 3);
13822
13823  Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New();
13824
13825  Local<Object> object1;
13826  Local<Function> func1;
13827  {
13828    Context::Scope scope(context1);
13829    object1 = Object::New();
13830    func1 = tmpl->GetFunction();
13831  }
13832
13833  Local<Object> object2;
13834  Local<Function> func2;
13835  {
13836    Context::Scope scope(context2);
13837    object2 = Object::New();
13838    func2 = tmpl->GetFunction();
13839  }
13840
13841  Local<Object> instance1;
13842  Local<Object> instance2;
13843
13844  {
13845    Context::Scope scope(context3);
13846    instance1 = func1->NewInstance();
13847    instance2 = func2->NewInstance();
13848  }
13849
13850  CHECK(object1->CreationContext() == context1);
13851  CheckContextId(object1, 1);
13852  CHECK(func1->CreationContext() == context1);
13853  CheckContextId(func1, 1);
13854  CHECK(instance1->CreationContext() == context1);
13855  CheckContextId(instance1, 1);
13856  CHECK(object2->CreationContext() == context2);
13857  CheckContextId(object2, 2);
13858  CHECK(func2->CreationContext() == context2);
13859  CheckContextId(func2, 2);
13860  CHECK(instance2->CreationContext() == context2);
13861  CheckContextId(instance2, 2);
13862
13863  {
13864    Context::Scope scope(context1);
13865    CHECK(object1->CreationContext() == context1);
13866    CheckContextId(object1, 1);
13867    CHECK(func1->CreationContext() == context1);
13868    CheckContextId(func1, 1);
13869    CHECK(instance1->CreationContext() == context1);
13870    CheckContextId(instance1, 1);
13871    CHECK(object2->CreationContext() == context2);
13872    CheckContextId(object2, 2);
13873    CHECK(func2->CreationContext() == context2);
13874    CheckContextId(func2, 2);
13875    CHECK(instance2->CreationContext() == context2);
13876    CheckContextId(instance2, 2);
13877  }
13878
13879  {
13880    Context::Scope scope(context2);
13881    CHECK(object1->CreationContext() == context1);
13882    CheckContextId(object1, 1);
13883    CHECK(func1->CreationContext() == context1);
13884    CheckContextId(func1, 1);
13885    CHECK(instance1->CreationContext() == context1);
13886    CheckContextId(instance1, 1);
13887    CHECK(object2->CreationContext() == context2);
13888    CheckContextId(object2, 2);
13889    CHECK(func2->CreationContext() == context2);
13890    CheckContextId(func2, 2);
13891    CHECK(instance2->CreationContext() == context2);
13892    CheckContextId(instance2, 2);
13893  }
13894
13895  context1.Dispose();
13896  context2.Dispose();
13897  context3.Dispose();
13898}
13899