Home | History | Annotate | Download | only in cctest
      1 // Copyright 2007-2009 the V8 project authors. All rights reserved.
      2 // Redistribution and use in source and binary forms, with or without
      3 // modification, are permitted provided that the following conditions are
      4 // met:
      5 //
      6 //     * Redistributions of source code must retain the above copyright
      7 //       notice, this list of conditions and the following disclaimer.
      8 //     * Redistributions in binary form must reproduce the above
      9 //       copyright notice, this list of conditions and the following
     10 //       disclaimer in the documentation and/or other materials provided
     11 //       with the distribution.
     12 //     * Neither the name of Google Inc. nor the names of its
     13 //       contributors may be used to endorse or promote products derived
     14 //       from this software without specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 
     28 #include <limits.h>
     29 
     30 #include "v8.h"
     31 
     32 #include "api.h"
     33 #include "compilation-cache.h"
     34 #include "execution.h"
     35 #include "snapshot.h"
     36 #include "platform.h"
     37 #include "top.h"
     38 #include "utils.h"
     39 #include "cctest.h"
     40 
     41 static const bool kLogThreading = true;
     42 
     43 static bool IsNaN(double x) {
     44 #ifdef WIN32
     45   return _isnan(x);
     46 #else
     47   return isnan(x);
     48 #endif
     49 }
     50 
     51 using ::v8::ObjectTemplate;
     52 using ::v8::Value;
     53 using ::v8::Context;
     54 using ::v8::Local;
     55 using ::v8::String;
     56 using ::v8::Script;
     57 using ::v8::Function;
     58 using ::v8::AccessorInfo;
     59 using ::v8::Extension;
     60 
     61 namespace i = ::v8::internal;
     62 
     63 
     64 static void ExpectString(const char* code, const char* expected) {
     65   Local<Value> result = CompileRun(code);
     66   CHECK(result->IsString());
     67   String::AsciiValue ascii(result);
     68   CHECK_EQ(expected, *ascii);
     69 }
     70 
     71 
     72 static void ExpectBoolean(const char* code, bool expected) {
     73   Local<Value> result = CompileRun(code);
     74   CHECK(result->IsBoolean());
     75   CHECK_EQ(expected, result->BooleanValue());
     76 }
     77 
     78 
     79 static void ExpectObject(const char* code, Local<Value> expected) {
     80   Local<Value> result = CompileRun(code);
     81   CHECK(result->Equals(expected));
     82 }
     83 
     84 
     85 static int signature_callback_count;
     86 static v8::Handle<Value> IncrementingSignatureCallback(
     87     const v8::Arguments& args) {
     88   ApiTestFuzzer::Fuzz();
     89   signature_callback_count++;
     90   v8::Handle<v8::Array> result = v8::Array::New(args.Length());
     91   for (int i = 0; i < args.Length(); i++)
     92     result->Set(v8::Integer::New(i), args[i]);
     93   return result;
     94 }
     95 
     96 
     97 static v8::Handle<Value> SignatureCallback(const v8::Arguments& args) {
     98   ApiTestFuzzer::Fuzz();
     99   v8::Handle<v8::Array> result = v8::Array::New(args.Length());
    100   for (int i = 0; i < args.Length(); i++) {
    101     result->Set(v8::Integer::New(i), args[i]);
    102   }
    103   return result;
    104 }
    105 
    106 
    107 THREADED_TEST(Handles) {
    108   v8::HandleScope scope;
    109   Local<Context> local_env;
    110   {
    111     LocalContext env;
    112     local_env = env.local();
    113   }
    114 
    115   // Local context should still be live.
    116   CHECK(!local_env.IsEmpty());
    117   local_env->Enter();
    118 
    119   v8::Handle<v8::Primitive> undef = v8::Undefined();
    120   CHECK(!undef.IsEmpty());
    121   CHECK(undef->IsUndefined());
    122 
    123   const char* c_source = "1 + 2 + 3";
    124   Local<String> source = String::New(c_source);
    125   Local<Script> script = Script::Compile(source);
    126   CHECK_EQ(6, script->Run()->Int32Value());
    127 
    128   local_env->Exit();
    129 }
    130 
    131 
    132 THREADED_TEST(ReceiverSignature) {
    133   v8::HandleScope scope;
    134   LocalContext env;
    135   v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
    136   v8::Handle<v8::Signature> sig = v8::Signature::New(fun);
    137   fun->PrototypeTemplate()->Set(
    138       v8_str("m"),
    139       v8::FunctionTemplate::New(IncrementingSignatureCallback,
    140                                 v8::Handle<Value>(),
    141                                 sig));
    142   env->Global()->Set(v8_str("Fun"), fun->GetFunction());
    143   signature_callback_count = 0;
    144   CompileRun(
    145       "var o = new Fun();"
    146       "o.m();");
    147   CHECK_EQ(1, signature_callback_count);
    148   v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New();
    149   sub_fun->Inherit(fun);
    150   env->Global()->Set(v8_str("SubFun"), sub_fun->GetFunction());
    151   CompileRun(
    152       "var o = new SubFun();"
    153       "o.m();");
    154   CHECK_EQ(2, signature_callback_count);
    155 
    156   v8::TryCatch try_catch;
    157   CompileRun(
    158       "var o = { };"
    159       "o.m = Fun.prototype.m;"
    160       "o.m();");
    161   CHECK_EQ(2, signature_callback_count);
    162   CHECK(try_catch.HasCaught());
    163   try_catch.Reset();
    164   v8::Handle<v8::FunctionTemplate> unrel_fun = v8::FunctionTemplate::New();
    165   sub_fun->Inherit(fun);
    166   env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
    167   CompileRun(
    168       "var o = new UnrelFun();"
    169       "o.m = Fun.prototype.m;"
    170       "o.m();");
    171   CHECK_EQ(2, signature_callback_count);
    172   CHECK(try_catch.HasCaught());
    173 }
    174 
    175 
    176 
    177 
    178 THREADED_TEST(ArgumentSignature) {
    179   v8::HandleScope scope;
    180   LocalContext env;
    181   v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New();
    182   cons->SetClassName(v8_str("Cons"));
    183   v8::Handle<v8::Signature> sig =
    184       v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 1, &cons);
    185   v8::Handle<v8::FunctionTemplate> fun =
    186       v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), sig);
    187   env->Global()->Set(v8_str("Cons"), cons->GetFunction());
    188   env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
    189 
    190   v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
    191   CHECK(value1->IsTrue());
    192 
    193   v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
    194   CHECK(value2->IsTrue());
    195 
    196   v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
    197   CHECK(value3->IsTrue());
    198 
    199   v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New();
    200   cons1->SetClassName(v8_str("Cons1"));
    201   v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New();
    202   cons2->SetClassName(v8_str("Cons2"));
    203   v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New();
    204   cons3->SetClassName(v8_str("Cons3"));
    205 
    206   v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
    207   v8::Handle<v8::Signature> wsig =
    208       v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 3, args);
    209   v8::Handle<v8::FunctionTemplate> fun2 =
    210       v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), wsig);
    211 
    212   env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
    213   env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
    214   env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
    215   env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
    216   v8::Handle<Value> value4 = CompileRun(
    217       "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
    218       "'[object Cons1],[object Cons2],[object Cons3]'");
    219   CHECK(value4->IsTrue());
    220 
    221   v8::Handle<Value> value5 = CompileRun(
    222       "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
    223   CHECK(value5->IsTrue());
    224 
    225   v8::Handle<Value> value6 = CompileRun(
    226       "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
    227   CHECK(value6->IsTrue());
    228 
    229   v8::Handle<Value> value7 = CompileRun(
    230       "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
    231       "'[object Cons1],[object Cons2],[object Cons3],d';");
    232   CHECK(value7->IsTrue());
    233 
    234   v8::Handle<Value> value8 = CompileRun(
    235       "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
    236   CHECK(value8->IsTrue());
    237 }
    238 
    239 
    240 THREADED_TEST(HulIgennem) {
    241   v8::HandleScope scope;
    242   LocalContext env;
    243   v8::Handle<v8::Primitive> undef = v8::Undefined();
    244   Local<String> undef_str = undef->ToString();
    245   char* value = i::NewArray<char>(undef_str->Length() + 1);
    246   undef_str->WriteAscii(value);
    247   CHECK_EQ(0, strcmp(value, "undefined"));
    248   i::DeleteArray(value);
    249 }
    250 
    251 
    252 THREADED_TEST(Access) {
    253   v8::HandleScope scope;
    254   LocalContext env;
    255   Local<v8::Object> obj = v8::Object::New();
    256   Local<Value> foo_before = obj->Get(v8_str("foo"));
    257   CHECK(foo_before->IsUndefined());
    258   Local<String> bar_str = v8_str("bar");
    259   obj->Set(v8_str("foo"), bar_str);
    260   Local<Value> foo_after = obj->Get(v8_str("foo"));
    261   CHECK(!foo_after->IsUndefined());
    262   CHECK(foo_after->IsString());
    263   CHECK_EQ(bar_str, foo_after);
    264 }
    265 
    266 
    267 THREADED_TEST(Script) {
    268   v8::HandleScope scope;
    269   LocalContext env;
    270   const char* c_source = "1 + 2 + 3";
    271   Local<String> source = String::New(c_source);
    272   Local<Script> script = Script::Compile(source);
    273   CHECK_EQ(6, script->Run()->Int32Value());
    274 }
    275 
    276 
    277 static uint16_t* AsciiToTwoByteString(const char* source) {
    278   int array_length = i::StrLength(source) + 1;
    279   uint16_t* converted = i::NewArray<uint16_t>(array_length);
    280   for (int i = 0; i < array_length; i++) converted[i] = source[i];
    281   return converted;
    282 }
    283 
    284 
    285 class TestResource: public String::ExternalStringResource {
    286  public:
    287   static int dispose_count;
    288 
    289   explicit TestResource(uint16_t* data)
    290       : data_(data), length_(0) {
    291     while (data[length_]) ++length_;
    292   }
    293 
    294   ~TestResource() {
    295     i::DeleteArray(data_);
    296     ++dispose_count;
    297   }
    298 
    299   const uint16_t* data() const {
    300     return data_;
    301   }
    302 
    303   size_t length() const {
    304     return length_;
    305   }
    306  private:
    307   uint16_t* data_;
    308   size_t length_;
    309 };
    310 
    311 
    312 int TestResource::dispose_count = 0;
    313 
    314 
    315 class TestAsciiResource: public String::ExternalAsciiStringResource {
    316  public:
    317   static int dispose_count;
    318 
    319   explicit TestAsciiResource(const char* data)
    320       : data_(data),
    321         length_(strlen(data)) { }
    322 
    323   ~TestAsciiResource() {
    324     i::DeleteArray(data_);
    325     ++dispose_count;
    326   }
    327 
    328   const char* data() const {
    329     return data_;
    330   }
    331 
    332   size_t length() const {
    333     return length_;
    334   }
    335  private:
    336   const char* data_;
    337   size_t length_;
    338 };
    339 
    340 
    341 int TestAsciiResource::dispose_count = 0;
    342 
    343 
    344 THREADED_TEST(ScriptUsingStringResource) {
    345   TestResource::dispose_count = 0;
    346   const char* c_source = "1 + 2 * 3";
    347   uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
    348   {
    349     v8::HandleScope scope;
    350     LocalContext env;
    351     TestResource* resource = new TestResource(two_byte_source);
    352     Local<String> source = String::NewExternal(resource);
    353     Local<Script> script = Script::Compile(source);
    354     Local<Value> value = script->Run();
    355     CHECK(value->IsNumber());
    356     CHECK_EQ(7, value->Int32Value());
    357     CHECK(source->IsExternal());
    358     CHECK_EQ(resource,
    359              static_cast<TestResource*>(source->GetExternalStringResource()));
    360     v8::internal::Heap::CollectAllGarbage(false);
    361     CHECK_EQ(0, TestResource::dispose_count);
    362   }
    363   v8::internal::CompilationCache::Clear();
    364   v8::internal::Heap::CollectAllGarbage(false);
    365   CHECK_EQ(1, TestResource::dispose_count);
    366 }
    367 
    368 
    369 THREADED_TEST(ScriptUsingAsciiStringResource) {
    370   TestAsciiResource::dispose_count = 0;
    371   const char* c_source = "1 + 2 * 3";
    372   {
    373     v8::HandleScope scope;
    374     LocalContext env;
    375     Local<String> source =
    376         String::NewExternal(new TestAsciiResource(i::StrDup(c_source)));
    377     Local<Script> script = Script::Compile(source);
    378     Local<Value> value = script->Run();
    379     CHECK(value->IsNumber());
    380     CHECK_EQ(7, value->Int32Value());
    381     v8::internal::Heap::CollectAllGarbage(false);
    382     CHECK_EQ(0, TestAsciiResource::dispose_count);
    383   }
    384   v8::internal::CompilationCache::Clear();
    385   v8::internal::Heap::CollectAllGarbage(false);
    386   CHECK_EQ(1, TestAsciiResource::dispose_count);
    387 }
    388 
    389 
    390 THREADED_TEST(ScriptMakingExternalString) {
    391   TestResource::dispose_count = 0;
    392   uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
    393   {
    394     v8::HandleScope scope;
    395     LocalContext env;
    396     Local<String> source = String::New(two_byte_source);
    397     // Trigger GCs so that the newly allocated string moves to old gen.
    398     i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in survivor space now
    399     i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in old gen now
    400     bool success = source->MakeExternal(new TestResource(two_byte_source));
    401     CHECK(success);
    402     Local<Script> script = Script::Compile(source);
    403     Local<Value> value = script->Run();
    404     CHECK(value->IsNumber());
    405     CHECK_EQ(7, value->Int32Value());
    406     v8::internal::Heap::CollectAllGarbage(false);
    407     CHECK_EQ(0, TestResource::dispose_count);
    408   }
    409   v8::internal::CompilationCache::Clear();
    410   v8::internal::Heap::CollectAllGarbage(false);
    411   CHECK_EQ(1, TestResource::dispose_count);
    412 }
    413 
    414 
    415 THREADED_TEST(ScriptMakingExternalAsciiString) {
    416   TestAsciiResource::dispose_count = 0;
    417   const char* c_source = "1 + 2 * 3";
    418   {
    419     v8::HandleScope scope;
    420     LocalContext env;
    421     Local<String> source = v8_str(c_source);
    422     // Trigger GCs so that the newly allocated string moves to old gen.
    423     i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in survivor space now
    424     i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in old gen now
    425     bool success = source->MakeExternal(
    426         new TestAsciiResource(i::StrDup(c_source)));
    427     CHECK(success);
    428     Local<Script> script = Script::Compile(source);
    429     Local<Value> value = script->Run();
    430     CHECK(value->IsNumber());
    431     CHECK_EQ(7, value->Int32Value());
    432     v8::internal::Heap::CollectAllGarbage(false);
    433     CHECK_EQ(0, TestAsciiResource::dispose_count);
    434   }
    435   v8::internal::CompilationCache::Clear();
    436   v8::internal::Heap::CollectAllGarbage(false);
    437   CHECK_EQ(1, TestAsciiResource::dispose_count);
    438 }
    439 
    440 
    441 TEST(MakingExternalStringConditions) {
    442   v8::HandleScope scope;
    443   LocalContext env;
    444 
    445   // Free some space in the new space so that we can check freshness.
    446   i::Heap::CollectGarbage(0, i::NEW_SPACE);
    447   i::Heap::CollectGarbage(0, i::NEW_SPACE);
    448 
    449   Local<String> small_string = String::New(AsciiToTwoByteString("small"));
    450   // We should refuse to externalize newly created small string.
    451   CHECK(!small_string->CanMakeExternal());
    452   // Trigger GCs so that the newly allocated string moves to old gen.
    453   i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in survivor space now
    454   i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in old gen now
    455   // Old space strings should be accepted.
    456   CHECK(small_string->CanMakeExternal());
    457 
    458   small_string = String::New(AsciiToTwoByteString("small 2"));
    459   // We should refuse externalizing newly created small string.
    460   CHECK(!small_string->CanMakeExternal());
    461   for (int i = 0; i < 100; i++) {
    462     String::Value value(small_string);
    463   }
    464   // Frequently used strings should be accepted.
    465   CHECK(small_string->CanMakeExternal());
    466 
    467   const int buf_size = 10 * 1024;
    468   char* buf = i::NewArray<char>(buf_size);
    469   memset(buf, 'a', buf_size);
    470   buf[buf_size - 1] = '\0';
    471   Local<String> large_string = String::New(AsciiToTwoByteString(buf));
    472   i::DeleteArray(buf);
    473   // Large strings should be immediately accepted.
    474   CHECK(large_string->CanMakeExternal());
    475 }
    476 
    477 
    478 TEST(MakingExternalAsciiStringConditions) {
    479   v8::HandleScope scope;
    480   LocalContext env;
    481 
    482   // Free some space in the new space so that we can check freshness.
    483   i::Heap::CollectGarbage(0, i::NEW_SPACE);
    484   i::Heap::CollectGarbage(0, i::NEW_SPACE);
    485 
    486   Local<String> small_string = String::New("small");
    487   // We should refuse to externalize newly created small string.
    488   CHECK(!small_string->CanMakeExternal());
    489   // Trigger GCs so that the newly allocated string moves to old gen.
    490   i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in survivor space now
    491   i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in old gen now
    492   // Old space strings should be accepted.
    493   CHECK(small_string->CanMakeExternal());
    494 
    495   small_string = String::New("small 2");
    496   // We should refuse externalizing newly created small string.
    497   CHECK(!small_string->CanMakeExternal());
    498   for (int i = 0; i < 100; i++) {
    499     String::Value value(small_string);
    500   }
    501   // Frequently used strings should be accepted.
    502   CHECK(small_string->CanMakeExternal());
    503 
    504   const int buf_size = 10 * 1024;
    505   char* buf = i::NewArray<char>(buf_size);
    506   memset(buf, 'a', buf_size);
    507   buf[buf_size - 1] = '\0';
    508   Local<String> large_string = String::New(buf);
    509   i::DeleteArray(buf);
    510   // Large strings should be immediately accepted.
    511   CHECK(large_string->CanMakeExternal());
    512 }
    513 
    514 
    515 THREADED_TEST(UsingExternalString) {
    516   {
    517     v8::HandleScope scope;
    518     uint16_t* two_byte_string = AsciiToTwoByteString("test string");
    519     Local<String> string =
    520         String::NewExternal(new TestResource(two_byte_string));
    521     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
    522     // Trigger GCs so that the newly allocated string moves to old gen.
    523     i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in survivor space now
    524     i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in old gen now
    525     i::Handle<i::String> isymbol = i::Factory::SymbolFromString(istring);
    526     CHECK(isymbol->IsSymbol());
    527   }
    528   i::Heap::CollectAllGarbage(false);
    529   i::Heap::CollectAllGarbage(false);
    530 }
    531 
    532 
    533 THREADED_TEST(UsingExternalAsciiString) {
    534   {
    535     v8::HandleScope scope;
    536     const char* one_byte_string = "test string";
    537     Local<String> string = String::NewExternal(
    538         new TestAsciiResource(i::StrDup(one_byte_string)));
    539     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
    540     // Trigger GCs so that the newly allocated string moves to old gen.
    541     i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in survivor space now
    542     i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in old gen now
    543     i::Handle<i::String> isymbol = i::Factory::SymbolFromString(istring);
    544     CHECK(isymbol->IsSymbol());
    545   }
    546   i::Heap::CollectAllGarbage(false);
    547   i::Heap::CollectAllGarbage(false);
    548 }
    549 
    550 
    551 THREADED_TEST(ScavengeExternalString) {
    552   TestResource::dispose_count = 0;
    553   {
    554     v8::HandleScope scope;
    555     uint16_t* two_byte_string = AsciiToTwoByteString("test string");
    556     Local<String> string =
    557         String::NewExternal(new TestResource(two_byte_string));
    558     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
    559     i::Heap::CollectGarbage(0, i::NEW_SPACE);
    560     CHECK(i::Heap::InNewSpace(*istring));
    561     CHECK_EQ(0, TestResource::dispose_count);
    562   }
    563   i::Heap::CollectGarbage(0, i::NEW_SPACE);
    564   CHECK_EQ(1, TestResource::dispose_count);
    565 }
    566 
    567 
    568 THREADED_TEST(ScavengeExternalAsciiString) {
    569   TestAsciiResource::dispose_count = 0;
    570   {
    571     v8::HandleScope scope;
    572     const char* one_byte_string = "test string";
    573     Local<String> string = String::NewExternal(
    574         new TestAsciiResource(i::StrDup(one_byte_string)));
    575     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
    576     i::Heap::CollectGarbage(0, i::NEW_SPACE);
    577     CHECK(i::Heap::InNewSpace(*istring));
    578     CHECK_EQ(0, TestAsciiResource::dispose_count);
    579   }
    580   i::Heap::CollectGarbage(0, i::NEW_SPACE);
    581   CHECK_EQ(1, TestAsciiResource::dispose_count);
    582 }
    583 
    584 
    585 THREADED_TEST(StringConcat) {
    586   {
    587     v8::HandleScope scope;
    588     LocalContext env;
    589     const char* one_byte_string_1 = "function a_times_t";
    590     const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
    591     const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
    592     const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
    593     const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
    594     const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
    595     const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
    596     Local<String> left = v8_str(one_byte_string_1);
    597     Local<String> right = String::New(AsciiToTwoByteString(two_byte_string_1));
    598     Local<String> source = String::Concat(left, right);
    599     right = String::NewExternal(
    600         new TestAsciiResource(i::StrDup(one_byte_extern_1)));
    601     source = String::Concat(source, right);
    602     right = String::NewExternal(
    603         new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
    604     source = String::Concat(source, right);
    605     right = v8_str(one_byte_string_2);
    606     source = String::Concat(source, right);
    607     right = String::New(AsciiToTwoByteString(two_byte_string_2));
    608     source = String::Concat(source, right);
    609     right = String::NewExternal(
    610         new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
    611     source = String::Concat(source, right);
    612     Local<Script> script = Script::Compile(source);
    613     Local<Value> value = script->Run();
    614     CHECK(value->IsNumber());
    615     CHECK_EQ(68, value->Int32Value());
    616   }
    617   v8::internal::CompilationCache::Clear();
    618   i::Heap::CollectAllGarbage(false);
    619   i::Heap::CollectAllGarbage(false);
    620 }
    621 
    622 
    623 THREADED_TEST(GlobalProperties) {
    624   v8::HandleScope scope;
    625   LocalContext env;
    626   v8::Handle<v8::Object> global = env->Global();
    627   global->Set(v8_str("pi"), v8_num(3.1415926));
    628   Local<Value> pi = global->Get(v8_str("pi"));
    629   CHECK_EQ(3.1415926, pi->NumberValue());
    630 }
    631 
    632 
    633 static v8::Handle<Value> handle_call(const v8::Arguments& args) {
    634   ApiTestFuzzer::Fuzz();
    635   return v8_num(102);
    636 }
    637 
    638 
    639 static v8::Handle<Value> construct_call(const v8::Arguments& args) {
    640   ApiTestFuzzer::Fuzz();
    641   args.This()->Set(v8_str("x"), v8_num(1));
    642   args.This()->Set(v8_str("y"), v8_num(2));
    643   return args.This();
    644 }
    645 
    646 THREADED_TEST(FunctionTemplate) {
    647   v8::HandleScope scope;
    648   LocalContext env;
    649   {
    650     Local<v8::FunctionTemplate> fun_templ =
    651         v8::FunctionTemplate::New(handle_call);
    652     Local<Function> fun = fun_templ->GetFunction();
    653     env->Global()->Set(v8_str("obj"), fun);
    654     Local<Script> script = v8_compile("obj()");
    655     CHECK_EQ(102, script->Run()->Int32Value());
    656   }
    657   // Use SetCallHandler to initialize a function template, should work like the
    658   // previous one.
    659   {
    660     Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
    661     fun_templ->SetCallHandler(handle_call);
    662     Local<Function> fun = fun_templ->GetFunction();
    663     env->Global()->Set(v8_str("obj"), fun);
    664     Local<Script> script = v8_compile("obj()");
    665     CHECK_EQ(102, script->Run()->Int32Value());
    666   }
    667   // Test constructor calls.
    668   {
    669     Local<v8::FunctionTemplate> fun_templ =
    670         v8::FunctionTemplate::New(construct_call);
    671     fun_templ->SetClassName(v8_str("funky"));
    672     Local<Function> fun = fun_templ->GetFunction();
    673     env->Global()->Set(v8_str("obj"), fun);
    674     Local<Script> script = v8_compile("var s = new obj(); s.x");
    675     CHECK_EQ(1, script->Run()->Int32Value());
    676 
    677     Local<Value> result = v8_compile("(new obj()).toString()")->Run();
    678     CHECK_EQ(v8_str("[object funky]"), result);
    679   }
    680 }
    681 
    682 
    683 THREADED_TEST(FindInstanceInPrototypeChain) {
    684   v8::HandleScope scope;
    685   LocalContext env;
    686 
    687   Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New();
    688   Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New();
    689   Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New();
    690   derived->Inherit(base);
    691 
    692   Local<v8::Function> base_function = base->GetFunction();
    693   Local<v8::Function> derived_function = derived->GetFunction();
    694   Local<v8::Function> other_function = other->GetFunction();
    695 
    696   Local<v8::Object> base_instance = base_function->NewInstance();
    697   Local<v8::Object> derived_instance = derived_function->NewInstance();
    698   Local<v8::Object> derived_instance2 = derived_function->NewInstance();
    699   Local<v8::Object> other_instance = other_function->NewInstance();
    700   derived_instance2->Set(v8_str("__proto__"), derived_instance);
    701   other_instance->Set(v8_str("__proto__"), derived_instance2);
    702 
    703   // base_instance is only an instance of base.
    704   CHECK_EQ(base_instance,
    705            base_instance->FindInstanceInPrototypeChain(base));
    706   CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
    707   CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
    708 
    709   // derived_instance is an instance of base and derived.
    710   CHECK_EQ(derived_instance,
    711            derived_instance->FindInstanceInPrototypeChain(base));
    712   CHECK_EQ(derived_instance,
    713            derived_instance->FindInstanceInPrototypeChain(derived));
    714   CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
    715 
    716   // other_instance is an instance of other and its immediate
    717   // prototype derived_instance2 is an instance of base and derived.
    718   // Note, derived_instance is an instance of base and derived too,
    719   // but it comes after derived_instance2 in the prototype chain of
    720   // other_instance.
    721   CHECK_EQ(derived_instance2,
    722            other_instance->FindInstanceInPrototypeChain(base));
    723   CHECK_EQ(derived_instance2,
    724            other_instance->FindInstanceInPrototypeChain(derived));
    725   CHECK_EQ(other_instance,
    726            other_instance->FindInstanceInPrototypeChain(other));
    727 }
    728 
    729 
    730 THREADED_TEST(TinyInteger) {
    731   v8::HandleScope scope;
    732   LocalContext env;
    733   int32_t value = 239;
    734   Local<v8::Integer> value_obj = v8::Integer::New(value);
    735   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
    736 }
    737 
    738 
    739 THREADED_TEST(BigSmiInteger) {
    740   v8::HandleScope scope;
    741   LocalContext env;
    742   int32_t value = i::Smi::kMaxValue;
    743   // We cannot add one to a Smi::kMaxValue without wrapping.
    744   if (i::kSmiValueSize < 32) {
    745     CHECK(i::Smi::IsValid(value));
    746     CHECK(!i::Smi::IsValid(value + 1));
    747     Local<v8::Integer> value_obj = v8::Integer::New(value);
    748     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
    749   }
    750 }
    751 
    752 
    753 THREADED_TEST(BigInteger) {
    754   v8::HandleScope scope;
    755   LocalContext env;
    756   // We cannot add one to a Smi::kMaxValue without wrapping.
    757   if (i::kSmiValueSize < 32) {
    758     // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
    759     // The code will not be run in that case, due to the "if" guard.
    760     int32_t value =
    761         static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
    762     CHECK(value > i::Smi::kMaxValue);
    763     CHECK(!i::Smi::IsValid(value));
    764     Local<v8::Integer> value_obj = v8::Integer::New(value);
    765     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
    766   }
    767 }
    768 
    769 
    770 THREADED_TEST(TinyUnsignedInteger) {
    771   v8::HandleScope scope;
    772   LocalContext env;
    773   uint32_t value = 239;
    774   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
    775   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
    776 }
    777 
    778 
    779 THREADED_TEST(BigUnsignedSmiInteger) {
    780   v8::HandleScope scope;
    781   LocalContext env;
    782   uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
    783   CHECK(i::Smi::IsValid(value));
    784   CHECK(!i::Smi::IsValid(value + 1));
    785   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
    786   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
    787 }
    788 
    789 
    790 THREADED_TEST(BigUnsignedInteger) {
    791   v8::HandleScope scope;
    792   LocalContext env;
    793   uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
    794   CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
    795   CHECK(!i::Smi::IsValid(value));
    796   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
    797   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
    798 }
    799 
    800 
    801 THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
    802   v8::HandleScope scope;
    803   LocalContext env;
    804   uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
    805   uint32_t value = INT32_MAX_AS_UINT + 1;
    806   CHECK(value > INT32_MAX_AS_UINT);  // No overflow.
    807   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
    808   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
    809 }
    810 
    811 
    812 THREADED_TEST(Number) {
    813   v8::HandleScope scope;
    814   LocalContext env;
    815   double PI = 3.1415926;
    816   Local<v8::Number> pi_obj = v8::Number::New(PI);
    817   CHECK_EQ(PI, pi_obj->NumberValue());
    818 }
    819 
    820 
    821 THREADED_TEST(ToNumber) {
    822   v8::HandleScope scope;
    823   LocalContext env;
    824   Local<String> str = v8_str("3.1415926");
    825   CHECK_EQ(3.1415926, str->NumberValue());
    826   v8::Handle<v8::Boolean> t = v8::True();
    827   CHECK_EQ(1.0, t->NumberValue());
    828   v8::Handle<v8::Boolean> f = v8::False();
    829   CHECK_EQ(0.0, f->NumberValue());
    830 }
    831 
    832 
    833 THREADED_TEST(Date) {
    834   v8::HandleScope scope;
    835   LocalContext env;
    836   double PI = 3.1415926;
    837   Local<Value> date_obj = v8::Date::New(PI);
    838   CHECK_EQ(3.0, date_obj->NumberValue());
    839 }
    840 
    841 
    842 THREADED_TEST(Boolean) {
    843   v8::HandleScope scope;
    844   LocalContext env;
    845   v8::Handle<v8::Boolean> t = v8::True();
    846   CHECK(t->Value());
    847   v8::Handle<v8::Boolean> f = v8::False();
    848   CHECK(!f->Value());
    849   v8::Handle<v8::Primitive> u = v8::Undefined();
    850   CHECK(!u->BooleanValue());
    851   v8::Handle<v8::Primitive> n = v8::Null();
    852   CHECK(!n->BooleanValue());
    853   v8::Handle<String> str1 = v8_str("");
    854   CHECK(!str1->BooleanValue());
    855   v8::Handle<String> str2 = v8_str("x");
    856   CHECK(str2->BooleanValue());
    857   CHECK(!v8::Number::New(0)->BooleanValue());
    858   CHECK(v8::Number::New(-1)->BooleanValue());
    859   CHECK(v8::Number::New(1)->BooleanValue());
    860   CHECK(v8::Number::New(42)->BooleanValue());
    861   CHECK(!v8_compile("NaN")->Run()->BooleanValue());
    862 }
    863 
    864 
    865 static v8::Handle<Value> DummyCallHandler(const v8::Arguments& args) {
    866   ApiTestFuzzer::Fuzz();
    867   return v8_num(13.4);
    868 }
    869 
    870 
    871 static v8::Handle<Value> GetM(Local<String> name, const AccessorInfo&) {
    872   ApiTestFuzzer::Fuzz();
    873   return v8_num(876);
    874 }
    875 
    876 
    877 THREADED_TEST(GlobalPrototype) {
    878   v8::HandleScope scope;
    879   v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
    880   func_templ->PrototypeTemplate()->Set(
    881       "dummy",
    882       v8::FunctionTemplate::New(DummyCallHandler));
    883   v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
    884   templ->Set("x", v8_num(200));
    885   templ->SetAccessor(v8_str("m"), GetM);
    886   LocalContext env(0, templ);
    887   v8::Handle<v8::Object> obj = env->Global();
    888   v8::Handle<Script> script = v8_compile("dummy()");
    889   v8::Handle<Value> result = script->Run();
    890   CHECK_EQ(13.4, result->NumberValue());
    891   CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
    892   CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
    893 }
    894 
    895 
    896 THREADED_TEST(ObjectTemplate) {
    897   v8::HandleScope scope;
    898   Local<ObjectTemplate> templ1 = ObjectTemplate::New();
    899   templ1->Set("x", v8_num(10));
    900   templ1->Set("y", v8_num(13));
    901   LocalContext env;
    902   Local<v8::Object> instance1 = templ1->NewInstance();
    903   env->Global()->Set(v8_str("p"), instance1);
    904   CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
    905   CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
    906   Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
    907   fun->PrototypeTemplate()->Set("nirk", v8_num(123));
    908   Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
    909   templ2->Set("a", v8_num(12));
    910   templ2->Set("b", templ1);
    911   Local<v8::Object> instance2 = templ2->NewInstance();
    912   env->Global()->Set(v8_str("q"), instance2);
    913   CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
    914   CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
    915   CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
    916   CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
    917 }
    918 
    919 
    920 static v8::Handle<Value> GetFlabby(const v8::Arguments& args) {
    921   ApiTestFuzzer::Fuzz();
    922   return v8_num(17.2);
    923 }
    924 
    925 
    926 static v8::Handle<Value> GetKnurd(Local<String> property, const AccessorInfo&) {
    927   ApiTestFuzzer::Fuzz();
    928   return v8_num(15.2);
    929 }
    930 
    931 
    932 THREADED_TEST(DescriptorInheritance) {
    933   v8::HandleScope scope;
    934   v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New();
    935   super->PrototypeTemplate()->Set("flabby",
    936                                   v8::FunctionTemplate::New(GetFlabby));
    937   super->PrototypeTemplate()->Set("PI", v8_num(3.14));
    938 
    939   super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
    940 
    941   v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New();
    942   base1->Inherit(super);
    943   base1->PrototypeTemplate()->Set("v1", v8_num(20.1));
    944 
    945   v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New();
    946   base2->Inherit(super);
    947   base2->PrototypeTemplate()->Set("v2", v8_num(10.1));
    948 
    949   LocalContext env;
    950 
    951   env->Global()->Set(v8_str("s"), super->GetFunction());
    952   env->Global()->Set(v8_str("base1"), base1->GetFunction());
    953   env->Global()->Set(v8_str("base2"), base2->GetFunction());
    954 
    955   // Checks right __proto__ chain.
    956   CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
    957   CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
    958 
    959   CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
    960 
    961   // Instance accessor should not be visible on function object or its prototype
    962   CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
    963   CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
    964   CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
    965 
    966   env->Global()->Set(v8_str("obj"),
    967                      base1->GetFunction()->NewInstance());
    968   CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
    969   CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
    970   CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
    971   CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
    972   CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
    973 
    974   env->Global()->Set(v8_str("obj2"),
    975                      base2->GetFunction()->NewInstance());
    976   CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
    977   CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
    978   CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
    979   CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
    980   CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
    981 
    982   // base1 and base2 cannot cross reference to each's prototype
    983   CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
    984   CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
    985 }
    986 
    987 
    988 int echo_named_call_count;
    989 
    990 
    991 static v8::Handle<Value> EchoNamedProperty(Local<String> name,
    992                                            const AccessorInfo& info) {
    993   ApiTestFuzzer::Fuzz();
    994   CHECK_EQ(v8_str("data"), info.Data());
    995   echo_named_call_count++;
    996   return name;
    997 }
    998 
    999 
   1000 THREADED_TEST(NamedPropertyHandlerGetter) {
   1001   echo_named_call_count = 0;
   1002   v8::HandleScope scope;
   1003   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
   1004   templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
   1005                                                      0, 0, 0, 0,
   1006                                                      v8_str("data"));
   1007   LocalContext env;
   1008   env->Global()->Set(v8_str("obj"),
   1009                      templ->GetFunction()->NewInstance());
   1010   CHECK_EQ(echo_named_call_count, 0);
   1011   v8_compile("obj.x")->Run();
   1012   CHECK_EQ(echo_named_call_count, 1);
   1013   const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
   1014   v8::Handle<Value> str = CompileRun(code);
   1015   String::AsciiValue value(str);
   1016   CHECK_EQ(*value, "oddlepoddle");
   1017   // Check default behavior
   1018   CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
   1019   CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
   1020   CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
   1021 }
   1022 
   1023 
   1024 int echo_indexed_call_count = 0;
   1025 
   1026 
   1027 static v8::Handle<Value> EchoIndexedProperty(uint32_t index,
   1028                                              const AccessorInfo& info) {
   1029   ApiTestFuzzer::Fuzz();
   1030   CHECK_EQ(v8_num(637), info.Data());
   1031   echo_indexed_call_count++;
   1032   return v8_num(index);
   1033 }
   1034 
   1035 
   1036 THREADED_TEST(IndexedPropertyHandlerGetter) {
   1037   v8::HandleScope scope;
   1038   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
   1039   templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
   1040                                                        0, 0, 0, 0,
   1041                                                        v8_num(637));
   1042   LocalContext env;
   1043   env->Global()->Set(v8_str("obj"),
   1044                      templ->GetFunction()->NewInstance());
   1045   Local<Script> script = v8_compile("obj[900]");
   1046   CHECK_EQ(script->Run()->Int32Value(), 900);
   1047 }
   1048 
   1049 
   1050 v8::Handle<v8::Object> bottom;
   1051 
   1052 static v8::Handle<Value> CheckThisIndexedPropertyHandler(
   1053     uint32_t index,
   1054     const AccessorInfo& info) {
   1055   ApiTestFuzzer::Fuzz();
   1056   CHECK(info.This()->Equals(bottom));
   1057   return v8::Handle<Value>();
   1058 }
   1059 
   1060 static v8::Handle<Value> CheckThisNamedPropertyHandler(
   1061     Local<String> name,
   1062     const AccessorInfo& info) {
   1063   ApiTestFuzzer::Fuzz();
   1064   CHECK(info.This()->Equals(bottom));
   1065   return v8::Handle<Value>();
   1066 }
   1067 
   1068 
   1069 v8::Handle<Value> CheckThisIndexedPropertySetter(uint32_t index,
   1070                                                  Local<Value> value,
   1071                                                  const AccessorInfo& info) {
   1072   ApiTestFuzzer::Fuzz();
   1073   CHECK(info.This()->Equals(bottom));
   1074   return v8::Handle<Value>();
   1075 }
   1076 
   1077 
   1078 v8::Handle<Value> CheckThisNamedPropertySetter(Local<String> property,
   1079                                                Local<Value> value,
   1080                                                const AccessorInfo& info) {
   1081   ApiTestFuzzer::Fuzz();
   1082   CHECK(info.This()->Equals(bottom));
   1083   return v8::Handle<Value>();
   1084 }
   1085 
   1086 v8::Handle<v8::Boolean> CheckThisIndexedPropertyQuery(
   1087     uint32_t index,
   1088     const AccessorInfo& info) {
   1089   ApiTestFuzzer::Fuzz();
   1090   CHECK(info.This()->Equals(bottom));
   1091   return v8::Handle<v8::Boolean>();
   1092 }
   1093 
   1094 
   1095 v8::Handle<v8::Boolean> CheckThisNamedPropertyQuery(Local<String> property,
   1096                                                     const AccessorInfo& info) {
   1097   ApiTestFuzzer::Fuzz();
   1098   CHECK(info.This()->Equals(bottom));
   1099   return v8::Handle<v8::Boolean>();
   1100 }
   1101 
   1102 
   1103 v8::Handle<v8::Boolean> CheckThisIndexedPropertyDeleter(
   1104     uint32_t index,
   1105     const AccessorInfo& info) {
   1106   ApiTestFuzzer::Fuzz();
   1107   CHECK(info.This()->Equals(bottom));
   1108   return v8::Handle<v8::Boolean>();
   1109 }
   1110 
   1111 
   1112 v8::Handle<v8::Boolean> CheckThisNamedPropertyDeleter(
   1113     Local<String> property,
   1114     const AccessorInfo& info) {
   1115   ApiTestFuzzer::Fuzz();
   1116   CHECK(info.This()->Equals(bottom));
   1117   return v8::Handle<v8::Boolean>();
   1118 }
   1119 
   1120 
   1121 v8::Handle<v8::Array> CheckThisIndexedPropertyEnumerator(
   1122     const AccessorInfo& info) {
   1123   ApiTestFuzzer::Fuzz();
   1124   CHECK(info.This()->Equals(bottom));
   1125   return v8::Handle<v8::Array>();
   1126 }
   1127 
   1128 
   1129 v8::Handle<v8::Array> CheckThisNamedPropertyEnumerator(
   1130     const AccessorInfo& info) {
   1131   ApiTestFuzzer::Fuzz();
   1132   CHECK(info.This()->Equals(bottom));
   1133   return v8::Handle<v8::Array>();
   1134 }
   1135 
   1136 
   1137 THREADED_TEST(PropertyHandlerInPrototype) {
   1138   v8::HandleScope scope;
   1139   LocalContext env;
   1140 
   1141   // Set up a prototype chain with three interceptors.
   1142   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
   1143   templ->InstanceTemplate()->SetIndexedPropertyHandler(
   1144       CheckThisIndexedPropertyHandler,
   1145       CheckThisIndexedPropertySetter,
   1146       CheckThisIndexedPropertyQuery,
   1147       CheckThisIndexedPropertyDeleter,
   1148       CheckThisIndexedPropertyEnumerator);
   1149 
   1150   templ->InstanceTemplate()->SetNamedPropertyHandler(
   1151       CheckThisNamedPropertyHandler,
   1152       CheckThisNamedPropertySetter,
   1153       CheckThisNamedPropertyQuery,
   1154       CheckThisNamedPropertyDeleter,
   1155       CheckThisNamedPropertyEnumerator);
   1156 
   1157   bottom = templ->GetFunction()->NewInstance();
   1158   Local<v8::Object> top = templ->GetFunction()->NewInstance();
   1159   Local<v8::Object> middle = templ->GetFunction()->NewInstance();
   1160 
   1161   bottom->Set(v8_str("__proto__"), middle);
   1162   middle->Set(v8_str("__proto__"), top);
   1163   env->Global()->Set(v8_str("obj"), bottom);
   1164 
   1165   // Indexed and named get.
   1166   Script::Compile(v8_str("obj[0]"))->Run();
   1167   Script::Compile(v8_str("obj.x"))->Run();
   1168 
   1169   // Indexed and named set.
   1170   Script::Compile(v8_str("obj[1] = 42"))->Run();
   1171   Script::Compile(v8_str("obj.y = 42"))->Run();
   1172 
   1173   // Indexed and named query.
   1174   Script::Compile(v8_str("0 in obj"))->Run();
   1175   Script::Compile(v8_str("'x' in obj"))->Run();
   1176 
   1177   // Indexed and named deleter.
   1178   Script::Compile(v8_str("delete obj[0]"))->Run();
   1179   Script::Compile(v8_str("delete obj.x"))->Run();
   1180 
   1181   // Enumerators.
   1182   Script::Compile(v8_str("for (var p in obj) ;"))->Run();
   1183 }
   1184 
   1185 
   1186 static v8::Handle<Value> PrePropertyHandlerGet(Local<String> key,
   1187                                                const AccessorInfo& info) {
   1188   ApiTestFuzzer::Fuzz();
   1189   if (v8_str("pre")->Equals(key)) {
   1190     return v8_str("PrePropertyHandler: pre");
   1191   }
   1192   return v8::Handle<String>();
   1193 }
   1194 
   1195 
   1196 static v8::Handle<v8::Boolean> PrePropertyHandlerHas(Local<String> key,
   1197                                                      const AccessorInfo&) {
   1198   if (v8_str("pre")->Equals(key)) {
   1199     return v8::True();
   1200   }
   1201 
   1202   return v8::Handle<v8::Boolean>();  // do not intercept the call
   1203 }
   1204 
   1205 
   1206 THREADED_TEST(PrePropertyHandler) {
   1207   v8::HandleScope scope;
   1208   v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
   1209   desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
   1210                                                     0,
   1211                                                     PrePropertyHandlerHas);
   1212   LocalContext env(NULL, desc->InstanceTemplate());
   1213   Script::Compile(v8_str(
   1214       "var pre = 'Object: pre'; var on = 'Object: on';"))->Run();
   1215   v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run();
   1216   CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
   1217   v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run();
   1218   CHECK_EQ(v8_str("Object: on"), result_on);
   1219   v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run();
   1220   CHECK(result_post.IsEmpty());
   1221 }
   1222 
   1223 
   1224 THREADED_TEST(UndefinedIsNotEnumerable) {
   1225   v8::HandleScope scope;
   1226   LocalContext env;
   1227   v8::Handle<Value> result = Script::Compile(v8_str(
   1228       "this.propertyIsEnumerable(undefined)"))->Run();
   1229   CHECK(result->IsFalse());
   1230 }
   1231 
   1232 
   1233 v8::Handle<Script> call_recursively_script;
   1234 static const int kTargetRecursionDepth = 200;  // near maximum
   1235 
   1236 
   1237 static v8::Handle<Value> CallScriptRecursivelyCall(const v8::Arguments& args) {
   1238   ApiTestFuzzer::Fuzz();
   1239   int depth = args.This()->Get(v8_str("depth"))->Int32Value();
   1240   if (depth == kTargetRecursionDepth) return v8::Undefined();
   1241   args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
   1242   return call_recursively_script->Run();
   1243 }
   1244 
   1245 
   1246 static v8::Handle<Value> CallFunctionRecursivelyCall(
   1247     const v8::Arguments& args) {
   1248   ApiTestFuzzer::Fuzz();
   1249   int depth = args.This()->Get(v8_str("depth"))->Int32Value();
   1250   if (depth == kTargetRecursionDepth) {
   1251     printf("[depth = %d]\n", depth);
   1252     return v8::Undefined();
   1253   }
   1254   args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
   1255   v8::Handle<Value> function =
   1256       args.This()->Get(v8_str("callFunctionRecursively"));
   1257   return v8::Handle<Function>::Cast(function)->Call(args.This(), 0, NULL);
   1258 }
   1259 
   1260 
   1261 THREADED_TEST(DeepCrossLanguageRecursion) {
   1262   v8::HandleScope scope;
   1263   v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
   1264   global->Set(v8_str("callScriptRecursively"),
   1265               v8::FunctionTemplate::New(CallScriptRecursivelyCall));
   1266   global->Set(v8_str("callFunctionRecursively"),
   1267               v8::FunctionTemplate::New(CallFunctionRecursivelyCall));
   1268   LocalContext env(NULL, global);
   1269 
   1270   env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
   1271   call_recursively_script = v8_compile("callScriptRecursively()");
   1272   v8::Handle<Value> result = call_recursively_script->Run();
   1273   call_recursively_script = v8::Handle<Script>();
   1274 
   1275   env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
   1276   Script::Compile(v8_str("callFunctionRecursively()"))->Run();
   1277 }
   1278 
   1279 
   1280 static v8::Handle<Value>
   1281     ThrowingPropertyHandlerGet(Local<String> key, const AccessorInfo&) {
   1282   ApiTestFuzzer::Fuzz();
   1283   return v8::ThrowException(key);
   1284 }
   1285 
   1286 
   1287 static v8::Handle<Value> ThrowingPropertyHandlerSet(Local<String> key,
   1288                                                     Local<Value>,
   1289                                                     const AccessorInfo&) {
   1290   v8::ThrowException(key);
   1291   return v8::Undefined();  // not the same as v8::Handle<v8::Value>()
   1292 }
   1293 
   1294 
   1295 THREADED_TEST(CallbackExceptionRegression) {
   1296   v8::HandleScope scope;
   1297   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
   1298   obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
   1299                                ThrowingPropertyHandlerSet);
   1300   LocalContext env;
   1301   env->Global()->Set(v8_str("obj"), obj->NewInstance());
   1302   v8::Handle<Value> otto = Script::Compile(v8_str(
   1303       "try { with (obj) { otto; } } catch (e) { e; }"))->Run();
   1304   CHECK_EQ(v8_str("otto"), otto);
   1305   v8::Handle<Value> netto = Script::Compile(v8_str(
   1306       "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run();
   1307   CHECK_EQ(v8_str("netto"), netto);
   1308 }
   1309 
   1310 
   1311 THREADED_TEST(FunctionPrototype) {
   1312   v8::HandleScope scope;
   1313   Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New();
   1314   Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
   1315   LocalContext env;
   1316   env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
   1317   Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak"));
   1318   CHECK_EQ(script->Run()->Int32Value(), 321);
   1319 }
   1320 
   1321 
   1322 THREADED_TEST(InternalFields) {
   1323   v8::HandleScope scope;
   1324   LocalContext env;
   1325 
   1326   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
   1327   Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
   1328   instance_templ->SetInternalFieldCount(1);
   1329   Local<v8::Object> obj = templ->GetFunction()->NewInstance();
   1330   CHECK_EQ(1, obj->InternalFieldCount());
   1331   CHECK(obj->GetInternalField(0)->IsUndefined());
   1332   obj->SetInternalField(0, v8_num(17));
   1333   CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
   1334 }
   1335 
   1336 
   1337 THREADED_TEST(InternalFieldsNativePointers) {
   1338   v8::HandleScope scope;
   1339   LocalContext env;
   1340 
   1341   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
   1342   Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
   1343   instance_templ->SetInternalFieldCount(1);
   1344   Local<v8::Object> obj = templ->GetFunction()->NewInstance();
   1345   CHECK_EQ(1, obj->InternalFieldCount());
   1346   CHECK(obj->GetPointerFromInternalField(0) == NULL);
   1347 
   1348   char* data = new char[100];
   1349 
   1350   void* aligned = data;
   1351   CHECK_EQ(0, reinterpret_cast<uintptr_t>(aligned) & 0x1);
   1352   void* unaligned = data + 1;
   1353   CHECK_EQ(1, reinterpret_cast<uintptr_t>(unaligned) & 0x1);
   1354 
   1355   // Check reading and writing aligned pointers.
   1356   obj->SetPointerInInternalField(0, aligned);
   1357   i::Heap::CollectAllGarbage(false);
   1358   CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
   1359 
   1360   // Check reading and writing unaligned pointers.
   1361   obj->SetPointerInInternalField(0, unaligned);
   1362   i::Heap::CollectAllGarbage(false);
   1363   CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
   1364 
   1365   delete[] data;
   1366 }
   1367 
   1368 
   1369 THREADED_TEST(InternalFieldsNativePointersAndExternal) {
   1370   v8::HandleScope scope;
   1371   LocalContext env;
   1372 
   1373   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
   1374   Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
   1375   instance_templ->SetInternalFieldCount(1);
   1376   Local<v8::Object> obj = templ->GetFunction()->NewInstance();
   1377   CHECK_EQ(1, obj->InternalFieldCount());
   1378   CHECK(obj->GetPointerFromInternalField(0) == NULL);
   1379 
   1380   char* data = new char[100];
   1381 
   1382   void* aligned = data;
   1383   CHECK_EQ(0, reinterpret_cast<uintptr_t>(aligned) & 0x1);
   1384   void* unaligned = data + 1;
   1385   CHECK_EQ(1, reinterpret_cast<uintptr_t>(unaligned) & 0x1);
   1386 
   1387   obj->SetPointerInInternalField(0, aligned);
   1388   i::Heap::CollectAllGarbage(false);
   1389   CHECK_EQ(aligned, v8::External::Unwrap(obj->GetInternalField(0)));
   1390 
   1391   obj->SetPointerInInternalField(0, unaligned);
   1392   i::Heap::CollectAllGarbage(false);
   1393   CHECK_EQ(unaligned, v8::External::Unwrap(obj->GetInternalField(0)));
   1394 
   1395   obj->SetInternalField(0, v8::External::Wrap(aligned));
   1396   i::Heap::CollectAllGarbage(false);
   1397   CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
   1398 
   1399   obj->SetInternalField(0, v8::External::Wrap(unaligned));
   1400   i::Heap::CollectAllGarbage(false);
   1401   CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
   1402 
   1403   delete[] data;
   1404 }
   1405 
   1406 
   1407 THREADED_TEST(IdentityHash) {
   1408   v8::HandleScope scope;
   1409   LocalContext env;
   1410 
   1411   // Ensure that the test starts with an fresh heap to test whether the hash
   1412   // code is based on the address.
   1413   i::Heap::CollectAllGarbage(false);
   1414   Local<v8::Object> obj = v8::Object::New();
   1415   int hash = obj->GetIdentityHash();
   1416   int hash1 = obj->GetIdentityHash();
   1417   CHECK_EQ(hash, hash1);
   1418   int hash2 = v8::Object::New()->GetIdentityHash();
   1419   // Since the identity hash is essentially a random number two consecutive
   1420   // objects should not be assigned the same hash code. If the test below fails
   1421   // the random number generator should be evaluated.
   1422   CHECK_NE(hash, hash2);
   1423   i::Heap::CollectAllGarbage(false);
   1424   int hash3 = v8::Object::New()->GetIdentityHash();
   1425   // Make sure that the identity hash is not based on the initial address of
   1426   // the object alone. If the test below fails the random number generator
   1427   // should be evaluated.
   1428   CHECK_NE(hash, hash3);
   1429   int hash4 = obj->GetIdentityHash();
   1430   CHECK_EQ(hash, hash4);
   1431 }
   1432 
   1433 
   1434 THREADED_TEST(HiddenProperties) {
   1435   v8::HandleScope scope;
   1436   LocalContext env;
   1437 
   1438   v8::Local<v8::Object> obj = v8::Object::New();
   1439   v8::Local<v8::String> key = v8_str("api-test::hidden-key");
   1440   v8::Local<v8::String> empty = v8_str("");
   1441   v8::Local<v8::String> prop_name = v8_str("prop_name");
   1442 
   1443   i::Heap::CollectAllGarbage(false);
   1444 
   1445   // Make sure delete of a non-existent hidden value works
   1446   CHECK(obj->DeleteHiddenValue(key));
   1447 
   1448   CHECK(obj->SetHiddenValue(key, v8::Integer::New(1503)));
   1449   CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
   1450   CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
   1451   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
   1452 
   1453   i::Heap::CollectAllGarbage(false);
   1454 
   1455   // Make sure we do not find the hidden property.
   1456   CHECK(!obj->Has(empty));
   1457   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
   1458   CHECK(obj->Get(empty)->IsUndefined());
   1459   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
   1460   CHECK(obj->Set(empty, v8::Integer::New(2003)));
   1461   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
   1462   CHECK_EQ(2003, obj->Get(empty)->Int32Value());
   1463 
   1464   i::Heap::CollectAllGarbage(false);
   1465 
   1466   // Add another property and delete it afterwards to force the object in
   1467   // slow case.
   1468   CHECK(obj->Set(prop_name, v8::Integer::New(2008)));
   1469   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
   1470   CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
   1471   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
   1472   CHECK(obj->Delete(prop_name));
   1473   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
   1474 
   1475   i::Heap::CollectAllGarbage(false);
   1476 
   1477   CHECK(obj->DeleteHiddenValue(key));
   1478   CHECK(obj->GetHiddenValue(key).IsEmpty());
   1479 }
   1480 
   1481 
   1482 static bool interceptor_for_hidden_properties_called;
   1483 static v8::Handle<Value> InterceptorForHiddenProperties(
   1484     Local<String> name, const AccessorInfo& info) {
   1485   interceptor_for_hidden_properties_called = true;
   1486   return v8::Handle<Value>();
   1487 }
   1488 
   1489 
   1490 THREADED_TEST(HiddenPropertiesWithInterceptors) {
   1491   v8::HandleScope scope;
   1492   LocalContext context;
   1493 
   1494   interceptor_for_hidden_properties_called = false;
   1495 
   1496   v8::Local<v8::String> key = v8_str("api-test::hidden-key");
   1497 
   1498   // Associate an interceptor with an object and start setting hidden values.
   1499   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
   1500   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
   1501   instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
   1502   Local<v8::Function> function = fun_templ->GetFunction();
   1503   Local<v8::Object> obj = function->NewInstance();
   1504   CHECK(obj->SetHiddenValue(key, v8::Integer::New(2302)));
   1505   CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
   1506   CHECK(!interceptor_for_hidden_properties_called);
   1507 }
   1508 
   1509 
   1510 THREADED_TEST(External) {
   1511   v8::HandleScope scope;
   1512   int x = 3;
   1513   Local<v8::External> ext = v8::External::New(&x);
   1514   LocalContext env;
   1515   env->Global()->Set(v8_str("ext"), ext);
   1516   Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
   1517   v8::Handle<v8::External> reext = v8::Handle<v8::External>::Cast(reext_obj);
   1518   int* ptr = static_cast<int*>(reext->Value());
   1519   CHECK_EQ(x, 3);
   1520   *ptr = 10;
   1521   CHECK_EQ(x, 10);
   1522 
   1523   // Make sure unaligned pointers are wrapped properly.
   1524   char* data = i::StrDup("0123456789");
   1525   Local<v8::Value> zero = v8::External::Wrap(&data[0]);
   1526   Local<v8::Value> one = v8::External::Wrap(&data[1]);
   1527   Local<v8::Value> two = v8::External::Wrap(&data[2]);
   1528   Local<v8::Value> three = v8::External::Wrap(&data[3]);
   1529 
   1530   char* char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(zero));
   1531   CHECK_EQ('0', *char_ptr);
   1532   char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(one));
   1533   CHECK_EQ('1', *char_ptr);
   1534   char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(two));
   1535   CHECK_EQ('2', *char_ptr);
   1536   char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(three));
   1537   CHECK_EQ('3', *char_ptr);
   1538   i::DeleteArray(data);
   1539 }
   1540 
   1541 
   1542 THREADED_TEST(GlobalHandle) {
   1543   v8::Persistent<String> global;
   1544   {
   1545     v8::HandleScope scope;
   1546     Local<String> str = v8_str("str");
   1547     global = v8::Persistent<String>::New(str);
   1548   }
   1549   CHECK_EQ(global->Length(), 3);
   1550   global.Dispose();
   1551 }
   1552 
   1553 
   1554 THREADED_TEST(ScriptException) {
   1555   v8::HandleScope scope;
   1556   LocalContext env;
   1557   Local<Script> script = Script::Compile(v8_str("throw 'panama!';"));
   1558   v8::TryCatch try_catch;
   1559   Local<Value> result = script->Run();
   1560   CHECK(result.IsEmpty());
   1561   CHECK(try_catch.HasCaught());
   1562   String::AsciiValue exception_value(try_catch.Exception());
   1563   CHECK_EQ(*exception_value, "panama!");
   1564 }
   1565 
   1566 
   1567 bool message_received;
   1568 
   1569 
   1570 static void check_message(v8::Handle<v8::Message> message,
   1571                           v8::Handle<Value> data) {
   1572   CHECK_EQ(5.76, data->NumberValue());
   1573   CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
   1574   CHECK_EQ(7.56, message->GetScriptData()->NumberValue());
   1575   message_received = true;
   1576 }
   1577 
   1578 
   1579 THREADED_TEST(MessageHandlerData) {
   1580   message_received = false;
   1581   v8::HandleScope scope;
   1582   CHECK(!message_received);
   1583   v8::V8::AddMessageListener(check_message, v8_num(5.76));
   1584   LocalContext context;
   1585   v8::ScriptOrigin origin =
   1586       v8::ScriptOrigin(v8_str("6.75"));
   1587   v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
   1588                                                   &origin);
   1589   script->SetData(v8_str("7.56"));
   1590   script->Run();
   1591   CHECK(message_received);
   1592   // clear out the message listener
   1593   v8::V8::RemoveMessageListeners(check_message);
   1594 }
   1595 
   1596 
   1597 THREADED_TEST(GetSetProperty) {
   1598   v8::HandleScope scope;
   1599   LocalContext context;
   1600   context->Global()->Set(v8_str("foo"), v8_num(14));
   1601   context->Global()->Set(v8_str("12"), v8_num(92));
   1602   context->Global()->Set(v8::Integer::New(16), v8_num(32));
   1603   context->Global()->Set(v8_num(13), v8_num(56));
   1604   Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run();
   1605   CHECK_EQ(14, foo->Int32Value());
   1606   Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run();
   1607   CHECK_EQ(92, twelve->Int32Value());
   1608   Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run();
   1609   CHECK_EQ(32, sixteen->Int32Value());
   1610   Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run();
   1611   CHECK_EQ(56, thirteen->Int32Value());
   1612   CHECK_EQ(92, context->Global()->Get(v8::Integer::New(12))->Int32Value());
   1613   CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
   1614   CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
   1615   CHECK_EQ(32, context->Global()->Get(v8::Integer::New(16))->Int32Value());
   1616   CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
   1617   CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
   1618   CHECK_EQ(56, context->Global()->Get(v8::Integer::New(13))->Int32Value());
   1619   CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
   1620   CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
   1621 }
   1622 
   1623 
   1624 THREADED_TEST(PropertyAttributes) {
   1625   v8::HandleScope scope;
   1626   LocalContext context;
   1627   // read-only
   1628   Local<String> prop = v8_str("read_only");
   1629   context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
   1630   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
   1631   Script::Compile(v8_str("read_only = 9"))->Run();
   1632   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
   1633   context->Global()->Set(prop, v8_num(10));
   1634   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
   1635   // dont-delete
   1636   prop = v8_str("dont_delete");
   1637   context->Global()->Set(prop, v8_num(13), v8::DontDelete);
   1638   CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
   1639   Script::Compile(v8_str("delete dont_delete"))->Run();
   1640   CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
   1641 }
   1642 
   1643 
   1644 THREADED_TEST(Array) {
   1645   v8::HandleScope scope;
   1646   LocalContext context;
   1647   Local<v8::Array> array = v8::Array::New();
   1648   CHECK_EQ(0, array->Length());
   1649   CHECK(array->Get(v8::Integer::New(0))->IsUndefined());
   1650   CHECK(!array->Has(0));
   1651   CHECK(array->Get(v8::Integer::New(100))->IsUndefined());
   1652   CHECK(!array->Has(100));
   1653   array->Set(v8::Integer::New(2), v8_num(7));
   1654   CHECK_EQ(3, array->Length());
   1655   CHECK(!array->Has(0));
   1656   CHECK(!array->Has(1));
   1657   CHECK(array->Has(2));
   1658   CHECK_EQ(7, array->Get(v8::Integer::New(2))->Int32Value());
   1659   Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
   1660   Local<v8::Array> arr = Local<v8::Array>::Cast(obj);
   1661   CHECK_EQ(3, arr->Length());
   1662   CHECK_EQ(1, arr->Get(v8::Integer::New(0))->Int32Value());
   1663   CHECK_EQ(2, arr->Get(v8::Integer::New(1))->Int32Value());
   1664   CHECK_EQ(3, arr->Get(v8::Integer::New(2))->Int32Value());
   1665 }
   1666 
   1667 
   1668 v8::Handle<Value> HandleF(const v8::Arguments& args) {
   1669   v8::HandleScope scope;
   1670   ApiTestFuzzer::Fuzz();
   1671   Local<v8::Array> result = v8::Array::New(args.Length());
   1672   for (int i = 0; i < args.Length(); i++)
   1673     result->Set(v8::Integer::New(i), args[i]);
   1674   return scope.Close(result);
   1675 }
   1676 
   1677 
   1678 THREADED_TEST(Vector) {
   1679   v8::HandleScope scope;
   1680   Local<ObjectTemplate> global = ObjectTemplate::New();
   1681   global->Set(v8_str("f"), v8::FunctionTemplate::New(HandleF));
   1682   LocalContext context(0, global);
   1683 
   1684   const char* fun = "f()";
   1685   Local<v8::Array> a0 =
   1686       Local<v8::Array>::Cast(Script::Compile(String::New(fun))->Run());
   1687   CHECK_EQ(0, a0->Length());
   1688 
   1689   const char* fun2 = "f(11)";
   1690   Local<v8::Array> a1 =
   1691       Local<v8::Array>::Cast(Script::Compile(String::New(fun2))->Run());
   1692   CHECK_EQ(1, a1->Length());
   1693   CHECK_EQ(11, a1->Get(v8::Integer::New(0))->Int32Value());
   1694 
   1695   const char* fun3 = "f(12, 13)";
   1696   Local<v8::Array> a2 =
   1697       Local<v8::Array>::Cast(Script::Compile(String::New(fun3))->Run());
   1698   CHECK_EQ(2, a2->Length());
   1699   CHECK_EQ(12, a2->Get(v8::Integer::New(0))->Int32Value());
   1700   CHECK_EQ(13, a2->Get(v8::Integer::New(1))->Int32Value());
   1701 
   1702   const char* fun4 = "f(14, 15, 16)";
   1703   Local<v8::Array> a3 =
   1704       Local<v8::Array>::Cast(Script::Compile(String::New(fun4))->Run());
   1705   CHECK_EQ(3, a3->Length());
   1706   CHECK_EQ(14, a3->Get(v8::Integer::New(0))->Int32Value());
   1707   CHECK_EQ(15, a3->Get(v8::Integer::New(1))->Int32Value());
   1708   CHECK_EQ(16, a3->Get(v8::Integer::New(2))->Int32Value());
   1709 
   1710   const char* fun5 = "f(17, 18, 19, 20)";
   1711   Local<v8::Array> a4 =
   1712       Local<v8::Array>::Cast(Script::Compile(String::New(fun5))->Run());
   1713   CHECK_EQ(4, a4->Length());
   1714   CHECK_EQ(17, a4->Get(v8::Integer::New(0))->Int32Value());
   1715   CHECK_EQ(18, a4->Get(v8::Integer::New(1))->Int32Value());
   1716   CHECK_EQ(19, a4->Get(v8::Integer::New(2))->Int32Value());
   1717   CHECK_EQ(20, a4->Get(v8::Integer::New(3))->Int32Value());
   1718 }
   1719 
   1720 
   1721 THREADED_TEST(FunctionCall) {
   1722   v8::HandleScope scope;
   1723   LocalContext context;
   1724   CompileRun(
   1725     "function Foo() {"
   1726     "  var result = [];"
   1727     "  for (var i = 0; i < arguments.length; i++) {"
   1728     "    result.push(arguments[i]);"
   1729     "  }"
   1730     "  return result;"
   1731     "}");
   1732   Local<Function> Foo =
   1733       Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
   1734 
   1735   v8::Handle<Value>* args0 = NULL;
   1736   Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
   1737   CHECK_EQ(0, a0->Length());
   1738 
   1739   v8::Handle<Value> args1[] = { v8_num(1.1) };
   1740   Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
   1741   CHECK_EQ(1, a1->Length());
   1742   CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
   1743 
   1744   v8::Handle<Value> args2[] = { v8_num(2.2),
   1745                                 v8_num(3.3) };
   1746   Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
   1747   CHECK_EQ(2, a2->Length());
   1748   CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
   1749   CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
   1750 
   1751   v8::Handle<Value> args3[] = { v8_num(4.4),
   1752                                 v8_num(5.5),
   1753                                 v8_num(6.6) };
   1754   Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
   1755   CHECK_EQ(3, a3->Length());
   1756   CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
   1757   CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
   1758   CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
   1759 
   1760   v8::Handle<Value> args4[] = { v8_num(7.7),
   1761                                 v8_num(8.8),
   1762                                 v8_num(9.9),
   1763                                 v8_num(10.11) };
   1764   Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
   1765   CHECK_EQ(4, a4->Length());
   1766   CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
   1767   CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
   1768   CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
   1769   CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
   1770 }
   1771 
   1772 
   1773 static const char* js_code_causing_out_of_memory =
   1774     "var a = new Array(); while(true) a.push(a);";
   1775 
   1776 
   1777 // These tests run for a long time and prevent us from running tests
   1778 // that come after them so they cannot run in parallel.
   1779 TEST(OutOfMemory) {
   1780   // It's not possible to read a snapshot into a heap with different dimensions.
   1781   if (v8::internal::Snapshot::IsEnabled()) return;
   1782   // Set heap limits.
   1783   static const int K = 1024;
   1784   v8::ResourceConstraints constraints;
   1785   constraints.set_max_young_space_size(256 * K);
   1786   constraints.set_max_old_space_size(4 * K * K);
   1787   v8::SetResourceConstraints(&constraints);
   1788 
   1789   // Execute a script that causes out of memory.
   1790   v8::HandleScope scope;
   1791   LocalContext context;
   1792   v8::V8::IgnoreOutOfMemoryException();
   1793   Local<Script> script =
   1794       Script::Compile(String::New(js_code_causing_out_of_memory));
   1795   Local<Value> result = script->Run();
   1796 
   1797   // Check for out of memory state.
   1798   CHECK(result.IsEmpty());
   1799   CHECK(context->HasOutOfMemoryException());
   1800 }
   1801 
   1802 
   1803 v8::Handle<Value> ProvokeOutOfMemory(const v8::Arguments& args) {
   1804   ApiTestFuzzer::Fuzz();
   1805 
   1806   v8::HandleScope scope;
   1807   LocalContext context;
   1808   Local<Script> script =
   1809       Script::Compile(String::New(js_code_causing_out_of_memory));
   1810   Local<Value> result = script->Run();
   1811 
   1812   // Check for out of memory state.
   1813   CHECK(result.IsEmpty());
   1814   CHECK(context->HasOutOfMemoryException());
   1815 
   1816   return result;
   1817 }
   1818 
   1819 
   1820 TEST(OutOfMemoryNested) {
   1821   // It's not possible to read a snapshot into a heap with different dimensions.
   1822   if (v8::internal::Snapshot::IsEnabled()) return;
   1823   // Set heap limits.
   1824   static const int K = 1024;
   1825   v8::ResourceConstraints constraints;
   1826   constraints.set_max_young_space_size(256 * K);
   1827   constraints.set_max_old_space_size(4 * K * K);
   1828   v8::SetResourceConstraints(&constraints);
   1829 
   1830   v8::HandleScope scope;
   1831   Local<ObjectTemplate> templ = ObjectTemplate::New();
   1832   templ->Set(v8_str("ProvokeOutOfMemory"),
   1833              v8::FunctionTemplate::New(ProvokeOutOfMemory));
   1834   LocalContext context(0, templ);
   1835   v8::V8::IgnoreOutOfMemoryException();
   1836   Local<Value> result = CompileRun(
   1837     "var thrown = false;"
   1838     "try {"
   1839     "  ProvokeOutOfMemory();"
   1840     "} catch (e) {"
   1841     "  thrown = true;"
   1842     "}");
   1843   // Check for out of memory state.
   1844   CHECK(result.IsEmpty());
   1845   CHECK(context->HasOutOfMemoryException());
   1846 }
   1847 
   1848 
   1849 TEST(HugeConsStringOutOfMemory) {
   1850   // It's not possible to read a snapshot into a heap with different dimensions.
   1851   if (v8::internal::Snapshot::IsEnabled()) return;
   1852   v8::HandleScope scope;
   1853   LocalContext context;
   1854   // Set heap limits.
   1855   static const int K = 1024;
   1856   v8::ResourceConstraints constraints;
   1857   constraints.set_max_young_space_size(256 * K);
   1858   constraints.set_max_old_space_size(2 * K * K);
   1859   v8::SetResourceConstraints(&constraints);
   1860 
   1861   // Execute a script that causes out of memory.
   1862   v8::V8::IgnoreOutOfMemoryException();
   1863 
   1864   // Build huge string. This should fail with out of memory exception.
   1865   Local<Value> result = CompileRun(
   1866     "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();"
   1867     "for (var i = 0; i < 22; i++) { str = str + str; }");
   1868 
   1869   // Check for out of memory state.
   1870   CHECK(result.IsEmpty());
   1871   CHECK(context->HasOutOfMemoryException());
   1872 }
   1873 
   1874 
   1875 THREADED_TEST(ConstructCall) {
   1876   v8::HandleScope scope;
   1877   LocalContext context;
   1878   CompileRun(
   1879     "function Foo() {"
   1880     "  var result = [];"
   1881     "  for (var i = 0; i < arguments.length; i++) {"
   1882     "    result.push(arguments[i]);"
   1883     "  }"
   1884     "  return result;"
   1885     "}");
   1886   Local<Function> Foo =
   1887       Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
   1888 
   1889   v8::Handle<Value>* args0 = NULL;
   1890   Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
   1891   CHECK_EQ(0, a0->Length());
   1892 
   1893   v8::Handle<Value> args1[] = { v8_num(1.1) };
   1894   Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
   1895   CHECK_EQ(1, a1->Length());
   1896   CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
   1897 
   1898   v8::Handle<Value> args2[] = { v8_num(2.2),
   1899                                 v8_num(3.3) };
   1900   Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
   1901   CHECK_EQ(2, a2->Length());
   1902   CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
   1903   CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
   1904 
   1905   v8::Handle<Value> args3[] = { v8_num(4.4),
   1906                                 v8_num(5.5),
   1907                                 v8_num(6.6) };
   1908   Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
   1909   CHECK_EQ(3, a3->Length());
   1910   CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
   1911   CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
   1912   CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
   1913 
   1914   v8::Handle<Value> args4[] = { v8_num(7.7),
   1915                                 v8_num(8.8),
   1916                                 v8_num(9.9),
   1917                                 v8_num(10.11) };
   1918   Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
   1919   CHECK_EQ(4, a4->Length());
   1920   CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
   1921   CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
   1922   CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
   1923   CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
   1924 }
   1925 
   1926 
   1927 static void CheckUncle(v8::TryCatch* try_catch) {
   1928   CHECK(try_catch->HasCaught());
   1929   String::AsciiValue str_value(try_catch->Exception());
   1930   CHECK_EQ(*str_value, "uncle?");
   1931   try_catch->Reset();
   1932 }
   1933 
   1934 
   1935 THREADED_TEST(ConversionException) {
   1936   v8::HandleScope scope;
   1937   LocalContext env;
   1938   CompileRun(
   1939     "function TestClass() { };"
   1940     "TestClass.prototype.toString = function () { throw 'uncle?'; };"
   1941     "var obj = new TestClass();");
   1942   Local<Value> obj = env->Global()->Get(v8_str("obj"));
   1943 
   1944   v8::TryCatch try_catch;
   1945 
   1946   Local<Value> to_string_result = obj->ToString();
   1947   CHECK(to_string_result.IsEmpty());
   1948   CheckUncle(&try_catch);
   1949 
   1950   Local<Value> to_number_result = obj->ToNumber();
   1951   CHECK(to_number_result.IsEmpty());
   1952   CheckUncle(&try_catch);
   1953 
   1954   Local<Value> to_integer_result = obj->ToInteger();
   1955   CHECK(to_integer_result.IsEmpty());
   1956   CheckUncle(&try_catch);
   1957 
   1958   Local<Value> to_uint32_result = obj->ToUint32();
   1959   CHECK(to_uint32_result.IsEmpty());
   1960   CheckUncle(&try_catch);
   1961 
   1962   Local<Value> to_int32_result = obj->ToInt32();
   1963   CHECK(to_int32_result.IsEmpty());
   1964   CheckUncle(&try_catch);
   1965 
   1966   Local<Value> to_object_result = v8::Undefined()->ToObject();
   1967   CHECK(to_object_result.IsEmpty());
   1968   CHECK(try_catch.HasCaught());
   1969   try_catch.Reset();
   1970 
   1971   int32_t int32_value = obj->Int32Value();
   1972   CHECK_EQ(0, int32_value);
   1973   CheckUncle(&try_catch);
   1974 
   1975   uint32_t uint32_value = obj->Uint32Value();
   1976   CHECK_EQ(0, uint32_value);
   1977   CheckUncle(&try_catch);
   1978 
   1979   double number_value = obj->NumberValue();
   1980   CHECK_NE(0, IsNaN(number_value));
   1981   CheckUncle(&try_catch);
   1982 
   1983   int64_t integer_value = obj->IntegerValue();
   1984   CHECK_EQ(0.0, static_cast<double>(integer_value));
   1985   CheckUncle(&try_catch);
   1986 }
   1987 
   1988 
   1989 v8::Handle<Value> ThrowFromC(const v8::Arguments& args) {
   1990   ApiTestFuzzer::Fuzz();
   1991   return v8::ThrowException(v8_str("konto"));
   1992 }
   1993 
   1994 
   1995 v8::Handle<Value> CCatcher(const v8::Arguments& args) {
   1996   if (args.Length() < 1) return v8::Boolean::New(false);
   1997   v8::HandleScope scope;
   1998   v8::TryCatch try_catch;
   1999   Local<Value> result = v8::Script::Compile(args[0]->ToString())->Run();
   2000   CHECK(!try_catch.HasCaught() || result.IsEmpty());
   2001   return v8::Boolean::New(try_catch.HasCaught());
   2002 }
   2003 
   2004 
   2005 THREADED_TEST(APICatch) {
   2006   v8::HandleScope scope;
   2007   Local<ObjectTemplate> templ = ObjectTemplate::New();
   2008   templ->Set(v8_str("ThrowFromC"),
   2009              v8::FunctionTemplate::New(ThrowFromC));
   2010   LocalContext context(0, templ);
   2011   CompileRun(
   2012     "var thrown = false;"
   2013     "try {"
   2014     "  ThrowFromC();"
   2015     "} catch (e) {"
   2016     "  thrown = true;"
   2017     "}");
   2018   Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
   2019   CHECK(thrown->BooleanValue());
   2020 }
   2021 
   2022 
   2023 THREADED_TEST(APIThrowTryCatch) {
   2024   v8::HandleScope scope;
   2025   Local<ObjectTemplate> templ = ObjectTemplate::New();
   2026   templ->Set(v8_str("ThrowFromC"),
   2027              v8::FunctionTemplate::New(ThrowFromC));
   2028   LocalContext context(0, templ);
   2029   v8::TryCatch try_catch;
   2030   CompileRun("ThrowFromC();");
   2031   CHECK(try_catch.HasCaught());
   2032 }
   2033 
   2034 
   2035 // Test that a try-finally block doesn't shadow a try-catch block
   2036 // when setting up an external handler.
   2037 //
   2038 // BUG(271): Some of the exception propagation does not work on the
   2039 // ARM simulator because the simulator separates the C++ stack and the
   2040 // JS stack.  This test therefore fails on the simulator.  The test is
   2041 // not threaded to allow the threading tests to run on the simulator.
   2042 TEST(TryCatchInTryFinally) {
   2043   v8::HandleScope scope;
   2044   Local<ObjectTemplate> templ = ObjectTemplate::New();
   2045   templ->Set(v8_str("CCatcher"),
   2046              v8::FunctionTemplate::New(CCatcher));
   2047   LocalContext context(0, templ);
   2048   Local<Value> result = CompileRun("try {"
   2049                                    "  try {"
   2050                                    "    CCatcher('throw 7;');"
   2051                                    "  } finally {"
   2052                                    "  }"
   2053                                    "} catch (e) {"
   2054                                    "}");
   2055   CHECK(result->IsTrue());
   2056 }
   2057 
   2058 
   2059 static void receive_message(v8::Handle<v8::Message> message,
   2060                             v8::Handle<v8::Value> data) {
   2061   message->Get();
   2062   message_received = true;
   2063 }
   2064 
   2065 
   2066 TEST(APIThrowMessage) {
   2067   message_received = false;
   2068   v8::HandleScope scope;
   2069   v8::V8::AddMessageListener(receive_message);
   2070   Local<ObjectTemplate> templ = ObjectTemplate::New();
   2071   templ->Set(v8_str("ThrowFromC"),
   2072              v8::FunctionTemplate::New(ThrowFromC));
   2073   LocalContext context(0, templ);
   2074   CompileRun("ThrowFromC();");
   2075   CHECK(message_received);
   2076   v8::V8::RemoveMessageListeners(check_message);
   2077 }
   2078 
   2079 
   2080 TEST(APIThrowMessageAndVerboseTryCatch) {
   2081   message_received = false;
   2082   v8::HandleScope scope;
   2083   v8::V8::AddMessageListener(receive_message);
   2084   Local<ObjectTemplate> templ = ObjectTemplate::New();
   2085   templ->Set(v8_str("ThrowFromC"),
   2086              v8::FunctionTemplate::New(ThrowFromC));
   2087   LocalContext context(0, templ);
   2088   v8::TryCatch try_catch;
   2089   try_catch.SetVerbose(true);
   2090   Local<Value> result = CompileRun("ThrowFromC();");
   2091   CHECK(try_catch.HasCaught());
   2092   CHECK(result.IsEmpty());
   2093   CHECK(message_received);
   2094   v8::V8::RemoveMessageListeners(check_message);
   2095 }
   2096 
   2097 
   2098 THREADED_TEST(ExternalScriptException) {
   2099   v8::HandleScope scope;
   2100   Local<ObjectTemplate> templ = ObjectTemplate::New();
   2101   templ->Set(v8_str("ThrowFromC"),
   2102              v8::FunctionTemplate::New(ThrowFromC));
   2103   LocalContext context(0, templ);
   2104 
   2105   v8::TryCatch try_catch;
   2106   Local<Script> script
   2107       = Script::Compile(v8_str("ThrowFromC(); throw 'panama';"));
   2108   Local<Value> result = script->Run();
   2109   CHECK(result.IsEmpty());
   2110   CHECK(try_catch.HasCaught());
   2111   String::AsciiValue exception_value(try_catch.Exception());
   2112   CHECK_EQ("konto", *exception_value);
   2113 }
   2114 
   2115 
   2116 
   2117 v8::Handle<Value> CThrowCountDown(const v8::Arguments& args) {
   2118   ApiTestFuzzer::Fuzz();
   2119   CHECK_EQ(4, args.Length());
   2120   int count = args[0]->Int32Value();
   2121   int cInterval = args[2]->Int32Value();
   2122   if (count == 0) {
   2123     return v8::ThrowException(v8_str("FromC"));
   2124   } else {
   2125     Local<v8::Object> global = Context::GetCurrent()->Global();
   2126     Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
   2127     v8::Handle<Value> argv[] = { v8_num(count - 1),
   2128                                  args[1],
   2129                                  args[2],
   2130                                  args[3] };
   2131     if (count % cInterval == 0) {
   2132       v8::TryCatch try_catch;
   2133       Local<Value> result =
   2134           v8::Handle<Function>::Cast(fun)->Call(global, 4, argv);
   2135       int expected = args[3]->Int32Value();
   2136       if (try_catch.HasCaught()) {
   2137         CHECK_EQ(expected, count);
   2138         CHECK(result.IsEmpty());
   2139         CHECK(!i::Top::has_scheduled_exception());
   2140       } else {
   2141         CHECK_NE(expected, count);
   2142       }
   2143       return result;
   2144     } else {
   2145       return v8::Handle<Function>::Cast(fun)->Call(global, 4, argv);
   2146     }
   2147   }
   2148 }
   2149 
   2150 
   2151 v8::Handle<Value> JSCheck(const v8::Arguments& args) {
   2152   ApiTestFuzzer::Fuzz();
   2153   CHECK_EQ(3, args.Length());
   2154   bool equality = args[0]->BooleanValue();
   2155   int count = args[1]->Int32Value();
   2156   int expected = args[2]->Int32Value();
   2157   if (equality) {
   2158     CHECK_EQ(count, expected);
   2159   } else {
   2160     CHECK_NE(count, expected);
   2161   }
   2162   return v8::Undefined();
   2163 }
   2164 
   2165 
   2166 THREADED_TEST(EvalInTryFinally) {
   2167   v8::HandleScope scope;
   2168   LocalContext context;
   2169   v8::TryCatch try_catch;
   2170   CompileRun("(function() {"
   2171              "  try {"
   2172              "    eval('asldkf (*&^&*^');"
   2173              "  } finally {"
   2174              "    return;"
   2175              "  }"
   2176              "})()");
   2177   CHECK(!try_catch.HasCaught());
   2178 }
   2179 
   2180 
   2181 // This test works by making a stack of alternating JavaScript and C
   2182 // activations.  These activations set up exception handlers with regular
   2183 // intervals, one interval for C activations and another for JavaScript
   2184 // activations.  When enough activations have been created an exception is
   2185 // thrown and we check that the right activation catches the exception and that
   2186 // no other activations do.  The right activation is always the topmost one with
   2187 // a handler, regardless of whether it is in JavaScript or C.
   2188 //
   2189 // The notation used to describe a test case looks like this:
   2190 //
   2191 //    *JS[4] *C[3] @JS[2] C[1] JS[0]
   2192 //
   2193 // Each entry is an activation, either JS or C.  The index is the count at that
   2194 // level.  Stars identify activations with exception handlers, the @ identifies
   2195 // the exception handler that should catch the exception.
   2196 //
   2197 // BUG(271): Some of the exception propagation does not work on the
   2198 // ARM simulator because the simulator separates the C++ stack and the
   2199 // JS stack.  This test therefore fails on the simulator.  The test is
   2200 // not threaded to allow the threading tests to run on the simulator.
   2201 TEST(ExceptionOrder) {
   2202   v8::HandleScope scope;
   2203   Local<ObjectTemplate> templ = ObjectTemplate::New();
   2204   templ->Set(v8_str("check"), v8::FunctionTemplate::New(JSCheck));
   2205   templ->Set(v8_str("CThrowCountDown"),
   2206              v8::FunctionTemplate::New(CThrowCountDown));
   2207   LocalContext context(0, templ);
   2208   CompileRun(
   2209     "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
   2210     "  if (count == 0) throw 'FromJS';"
   2211     "  if (count % jsInterval == 0) {"
   2212     "    try {"
   2213     "      var value = CThrowCountDown(count - 1,"
   2214     "                                  jsInterval,"
   2215     "                                  cInterval,"
   2216     "                                  expected);"
   2217     "      check(false, count, expected);"
   2218     "      return value;"
   2219     "    } catch (e) {"
   2220     "      check(true, count, expected);"
   2221     "    }"
   2222     "  } else {"
   2223     "    return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
   2224     "  }"
   2225     "}");
   2226   Local<Function> fun =
   2227       Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
   2228 
   2229   const int argc = 4;
   2230   //                             count      jsInterval cInterval  expected
   2231 
   2232   // *JS[4] *C[3] @JS[2] C[1] JS[0]
   2233   v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
   2234   fun->Call(fun, argc, a0);
   2235 
   2236   // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
   2237   v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
   2238   fun->Call(fun, argc, a1);
   2239 
   2240   // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
   2241   v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
   2242   fun->Call(fun, argc, a2);
   2243 
   2244   // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
   2245   v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
   2246   fun->Call(fun, argc, a3);
   2247 
   2248   // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
   2249   v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
   2250   fun->Call(fun, argc, a4);
   2251 
   2252   // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
   2253   v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
   2254   fun->Call(fun, argc, a5);
   2255 }
   2256 
   2257 
   2258 v8::Handle<Value> ThrowValue(const v8::Arguments& args) {
   2259   ApiTestFuzzer::Fuzz();
   2260   CHECK_EQ(1, args.Length());
   2261   return v8::ThrowException(args[0]);
   2262 }
   2263 
   2264 
   2265 THREADED_TEST(ThrowValues) {
   2266   v8::HandleScope scope;
   2267   Local<ObjectTemplate> templ = ObjectTemplate::New();
   2268   templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(ThrowValue));
   2269   LocalContext context(0, templ);
   2270   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
   2271     "function Run(obj) {"
   2272     "  try {"
   2273     "    Throw(obj);"
   2274     "  } catch (e) {"
   2275     "    return e;"
   2276     "  }"
   2277     "  return 'no exception';"
   2278     "}"
   2279     "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
   2280   CHECK_EQ(5, result->Length());
   2281   CHECK(result->Get(v8::Integer::New(0))->IsString());
   2282   CHECK(result->Get(v8::Integer::New(1))->IsNumber());
   2283   CHECK_EQ(1, result->Get(v8::Integer::New(1))->Int32Value());
   2284   CHECK(result->Get(v8::Integer::New(2))->IsNumber());
   2285   CHECK_EQ(0, result->Get(v8::Integer::New(2))->Int32Value());
   2286   CHECK(result->Get(v8::Integer::New(3))->IsNull());
   2287   CHECK(result->Get(v8::Integer::New(4))->IsUndefined());
   2288 }
   2289 
   2290 
   2291 THREADED_TEST(CatchZero) {
   2292   v8::HandleScope scope;
   2293   LocalContext context;
   2294   v8::TryCatch try_catch;
   2295   CHECK(!try_catch.HasCaught());
   2296   Script::Compile(v8_str("throw 10"))->Run();
   2297   CHECK(try_catch.HasCaught());
   2298   CHECK_EQ(10, try_catch.Exception()->Int32Value());
   2299   try_catch.Reset();
   2300   CHECK(!try_catch.HasCaught());
   2301   Script::Compile(v8_str("throw 0"))->Run();
   2302   CHECK(try_catch.HasCaught());
   2303   CHECK_EQ(0, try_catch.Exception()->Int32Value());
   2304 }
   2305 
   2306 
   2307 THREADED_TEST(CatchExceptionFromWith) {
   2308   v8::HandleScope scope;
   2309   LocalContext context;
   2310   v8::TryCatch try_catch;
   2311   CHECK(!try_catch.HasCaught());
   2312   Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run();
   2313   CHECK(try_catch.HasCaught());
   2314 }
   2315 
   2316 
   2317 THREADED_TEST(Equality) {
   2318   v8::HandleScope scope;
   2319   LocalContext context;
   2320   // Check that equality works at all before relying on CHECK_EQ
   2321   CHECK(v8_str("a")->Equals(v8_str("a")));
   2322   CHECK(!v8_str("a")->Equals(v8_str("b")));
   2323 
   2324   CHECK_EQ(v8_str("a"), v8_str("a"));
   2325   CHECK_NE(v8_str("a"), v8_str("b"));
   2326   CHECK_EQ(v8_num(1), v8_num(1));
   2327   CHECK_EQ(v8_num(1.00), v8_num(1));
   2328   CHECK_NE(v8_num(1), v8_num(2));
   2329 
   2330   // Assume String is not symbol.
   2331   CHECK(v8_str("a")->StrictEquals(v8_str("a")));
   2332   CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
   2333   CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
   2334   CHECK(v8_num(1)->StrictEquals(v8_num(1)));
   2335   CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
   2336   CHECK(v8_num(0)->StrictEquals(v8_num(-0)));
   2337   Local<Value> not_a_number = v8_num(i::OS::nan_value());
   2338   CHECK(!not_a_number->StrictEquals(not_a_number));
   2339   CHECK(v8::False()->StrictEquals(v8::False()));
   2340   CHECK(!v8::False()->StrictEquals(v8::Undefined()));
   2341 
   2342   v8::Handle<v8::Object> obj = v8::Object::New();
   2343   v8::Persistent<v8::Object> alias = v8::Persistent<v8::Object>::New(obj);
   2344   CHECK(alias->StrictEquals(obj));
   2345   alias.Dispose();
   2346 }
   2347 
   2348 
   2349 THREADED_TEST(MultiRun) {
   2350   v8::HandleScope scope;
   2351   LocalContext context;
   2352   Local<Script> script = Script::Compile(v8_str("x"));
   2353   for (int i = 0; i < 10; i++)
   2354     script->Run();
   2355 }
   2356 
   2357 
   2358 static v8::Handle<Value> GetXValue(Local<String> name,
   2359                                    const AccessorInfo& info) {
   2360   ApiTestFuzzer::Fuzz();
   2361   CHECK_EQ(info.Data(), v8_str("donut"));
   2362   CHECK_EQ(name, v8_str("x"));
   2363   return name;
   2364 }
   2365 
   2366 
   2367 THREADED_TEST(SimplePropertyRead) {
   2368   v8::HandleScope scope;
   2369   Local<ObjectTemplate> templ = ObjectTemplate::New();
   2370   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
   2371   LocalContext context;
   2372   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   2373   Local<Script> script = Script::Compile(v8_str("obj.x"));
   2374   for (int i = 0; i < 10; i++) {
   2375     Local<Value> result = script->Run();
   2376     CHECK_EQ(result, v8_str("x"));
   2377   }
   2378 }
   2379 
   2380 THREADED_TEST(DefinePropertyOnAPIAccessor) {
   2381   v8::HandleScope scope;
   2382   Local<ObjectTemplate> templ = ObjectTemplate::New();
   2383   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
   2384   LocalContext context;
   2385   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   2386 
   2387   // Uses getOwnPropertyDescriptor to check the configurable status
   2388   Local<Script> script_desc
   2389     = Script::Compile(v8_str("var prop =Object.getOwnPropertyDescriptor( "
   2390                              "obj, 'x');"
   2391                              "prop.configurable;"));
   2392   Local<Value> result = script_desc->Run();
   2393   CHECK_EQ(result->BooleanValue(), true);
   2394 
   2395   // Redefine get - but still configurable
   2396   Local<Script> script_define
   2397     = Script::Compile(v8_str("var desc = { get: function(){return 42; },"
   2398                              "            configurable: true };"
   2399                              "Object.defineProperty(obj, 'x', desc);"
   2400                              "obj.x"));
   2401   result = script_define->Run();
   2402   CHECK_EQ(result, v8_num(42));
   2403 
   2404   // Check that the accessor is still configurable
   2405   result = script_desc->Run();
   2406   CHECK_EQ(result->BooleanValue(), true);
   2407 
   2408   // Redefine to a non-configurable
   2409   script_define
   2410     = Script::Compile(v8_str("var desc = { get: function(){return 43; },"
   2411                              "             configurable: false };"
   2412                              "Object.defineProperty(obj, 'x', desc);"
   2413                              "obj.x"));
   2414   result = script_define->Run();
   2415   CHECK_EQ(result, v8_num(43));
   2416   result = script_desc->Run();
   2417   CHECK_EQ(result->BooleanValue(), false);
   2418 
   2419   // Make sure that it is not possible to redefine again
   2420   v8::TryCatch try_catch;
   2421   result = script_define->Run();
   2422   CHECK(try_catch.HasCaught());
   2423   String::AsciiValue exception_value(try_catch.Exception());
   2424   CHECK_EQ(*exception_value,
   2425            "TypeError: Cannot redefine property: defineProperty");
   2426 }
   2427 
   2428 THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
   2429   v8::HandleScope scope;
   2430   Local<ObjectTemplate> templ = ObjectTemplate::New();
   2431   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
   2432   LocalContext context;
   2433   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   2434 
   2435   Local<Script> script_desc = Script::Compile(v8_str("var prop ="
   2436                                     "Object.getOwnPropertyDescriptor( "
   2437                                     "obj, 'x');"
   2438                                     "prop.configurable;"));
   2439   Local<Value> result = script_desc->Run();
   2440   CHECK_EQ(result->BooleanValue(), true);
   2441 
   2442   Local<Script> script_define =
   2443     Script::Compile(v8_str("var desc = {get: function(){return 42; },"
   2444                            "            configurable: true };"
   2445                            "Object.defineProperty(obj, 'x', desc);"
   2446                            "obj.x"));
   2447   result = script_define->Run();
   2448   CHECK_EQ(result, v8_num(42));
   2449 
   2450 
   2451   result = script_desc->Run();
   2452   CHECK_EQ(result->BooleanValue(), true);
   2453 
   2454 
   2455   script_define =
   2456     Script::Compile(v8_str("var desc = {get: function(){return 43; },"
   2457                            "            configurable: false };"
   2458                            "Object.defineProperty(obj, 'x', desc);"
   2459                            "obj.x"));
   2460   result = script_define->Run();
   2461   CHECK_EQ(result, v8_num(43));
   2462   result = script_desc->Run();
   2463 
   2464   CHECK_EQ(result->BooleanValue(), false);
   2465 
   2466   v8::TryCatch try_catch;
   2467   result = script_define->Run();
   2468   CHECK(try_catch.HasCaught());
   2469   String::AsciiValue exception_value(try_catch.Exception());
   2470   CHECK_EQ(*exception_value,
   2471            "TypeError: Cannot redefine property: defineProperty");
   2472 }
   2473 
   2474 
   2475 
   2476 
   2477 
   2478 v8::Persistent<Value> xValue;
   2479 
   2480 
   2481 static void SetXValue(Local<String> name,
   2482                       Local<Value> value,
   2483                       const AccessorInfo& info) {
   2484   CHECK_EQ(value, v8_num(4));
   2485   CHECK_EQ(info.Data(), v8_str("donut"));
   2486   CHECK_EQ(name, v8_str("x"));
   2487   CHECK(xValue.IsEmpty());
   2488   xValue = v8::Persistent<Value>::New(value);
   2489 }
   2490 
   2491 
   2492 THREADED_TEST(SimplePropertyWrite) {
   2493   v8::HandleScope scope;
   2494   Local<ObjectTemplate> templ = ObjectTemplate::New();
   2495   templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
   2496   LocalContext context;
   2497   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   2498   Local<Script> script = Script::Compile(v8_str("obj.x = 4"));
   2499   for (int i = 0; i < 10; i++) {
   2500     CHECK(xValue.IsEmpty());
   2501     script->Run();
   2502     CHECK_EQ(v8_num(4), xValue);
   2503     xValue.Dispose();
   2504     xValue = v8::Persistent<Value>();
   2505   }
   2506 }
   2507 
   2508 
   2509 static v8::Handle<Value> XPropertyGetter(Local<String> property,
   2510                                          const AccessorInfo& info) {
   2511   ApiTestFuzzer::Fuzz();
   2512   CHECK(info.Data()->IsUndefined());
   2513   return property;
   2514 }
   2515 
   2516 
   2517 THREADED_TEST(NamedInterceptorPropertyRead) {
   2518   v8::HandleScope scope;
   2519   Local<ObjectTemplate> templ = ObjectTemplate::New();
   2520   templ->SetNamedPropertyHandler(XPropertyGetter);
   2521   LocalContext context;
   2522   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   2523   Local<Script> script = Script::Compile(v8_str("obj.x"));
   2524   for (int i = 0; i < 10; i++) {
   2525     Local<Value> result = script->Run();
   2526     CHECK_EQ(result, v8_str("x"));
   2527   }
   2528 }
   2529 
   2530 
   2531 static v8::Handle<Value> SetXOnPrototypeGetter(Local<String> property,
   2532                                                const AccessorInfo& info) {
   2533   // Set x on the prototype object and do not handle the get request.
   2534   v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
   2535   v8::Handle<v8::Object>::Cast(proto)->Set(v8_str("x"), v8::Integer::New(23));
   2536   return v8::Handle<Value>();
   2537 }
   2538 
   2539 
   2540 // This is a regression test for http://crbug.com/20104. Map
   2541 // transitions should not interfere with post interceptor lookup.
   2542 THREADED_TEST(NamedInterceptorMapTransitionRead) {
   2543   v8::HandleScope scope;
   2544   Local<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New();
   2545   Local<v8::ObjectTemplate> instance_template
   2546       = function_template->InstanceTemplate();
   2547   instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
   2548   LocalContext context;
   2549   context->Global()->Set(v8_str("F"), function_template->GetFunction());
   2550   // Create an instance of F and introduce a map transition for x.
   2551   CompileRun("var o = new F(); o.x = 23;");
   2552   // Create an instance of F and invoke the getter. The result should be 23.
   2553   Local<Value> result = CompileRun("o = new F(); o.x");
   2554   CHECK_EQ(result->Int32Value(), 23);
   2555 }
   2556 
   2557 
   2558 static v8::Handle<Value> IndexedPropertyGetter(uint32_t index,
   2559                                                const AccessorInfo& info) {
   2560   ApiTestFuzzer::Fuzz();
   2561   if (index == 37) {
   2562     return v8::Handle<Value>(v8_num(625));
   2563   }
   2564   return v8::Handle<Value>();
   2565 }
   2566 
   2567 
   2568 static v8::Handle<Value> IndexedPropertySetter(uint32_t index,
   2569                                                Local<Value> value,
   2570                                                const AccessorInfo& info) {
   2571   ApiTestFuzzer::Fuzz();
   2572   if (index == 39) {
   2573     return value;
   2574   }
   2575   return v8::Handle<Value>();
   2576 }
   2577 
   2578 
   2579 THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
   2580   v8::HandleScope scope;
   2581   Local<ObjectTemplate> templ = ObjectTemplate::New();
   2582   templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
   2583                                    IndexedPropertySetter);
   2584   LocalContext context;
   2585   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   2586   Local<Script> getter_script = Script::Compile(v8_str(
   2587       "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];"));
   2588   Local<Script> setter_script = Script::Compile(v8_str(
   2589       "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
   2590       "obj[17] = 23;"
   2591       "obj.foo;"));
   2592   Local<Script> interceptor_setter_script = Script::Compile(v8_str(
   2593       "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
   2594       "obj[39] = 47;"
   2595       "obj.foo;"));  // This setter should not run, due to the interceptor.
   2596   Local<Script> interceptor_getter_script = Script::Compile(v8_str(
   2597       "obj[37];"));
   2598   Local<Value> result = getter_script->Run();
   2599   CHECK_EQ(v8_num(5), result);
   2600   result = setter_script->Run();
   2601   CHECK_EQ(v8_num(23), result);
   2602   result = interceptor_setter_script->Run();
   2603   CHECK_EQ(v8_num(23), result);
   2604   result = interceptor_getter_script->Run();
   2605   CHECK_EQ(v8_num(625), result);
   2606 }
   2607 
   2608 
   2609 static v8::Handle<Value> IdentityIndexedPropertyGetter(
   2610     uint32_t index,
   2611     const AccessorInfo& info) {
   2612   return v8::Integer::New(index);
   2613 }
   2614 
   2615 
   2616 THREADED_TEST(IndexedInterceptorWithNoSetter) {
   2617   v8::HandleScope scope;
   2618   Local<ObjectTemplate> templ = ObjectTemplate::New();
   2619   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
   2620 
   2621   LocalContext context;
   2622   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   2623 
   2624   const char* code =
   2625       "try {"
   2626       "  obj[0] = 239;"
   2627       "  for (var i = 0; i < 100; i++) {"
   2628       "    var v = obj[0];"
   2629       "    if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
   2630       "  }"
   2631       "  'PASSED'"
   2632       "} catch(e) {"
   2633       "  e"
   2634       "}";
   2635   ExpectString(code, "PASSED");
   2636 }
   2637 
   2638 
   2639 THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
   2640   v8::HandleScope scope;
   2641   Local<ObjectTemplate> templ = ObjectTemplate::New();
   2642   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
   2643 
   2644   LocalContext context;
   2645   Local<v8::Object> obj = templ->NewInstance();
   2646   obj->TurnOnAccessCheck();
   2647   context->Global()->Set(v8_str("obj"), obj);
   2648 
   2649   const char* code =
   2650       "try {"
   2651       "  for (var i = 0; i < 100; i++) {"
   2652       "    var v = obj[0];"
   2653       "    if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
   2654       "  }"
   2655       "  'PASSED'"
   2656       "} catch(e) {"
   2657       "  e"
   2658       "}";
   2659   ExpectString(code, "PASSED");
   2660 }
   2661 
   2662 
   2663 THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
   2664   i::FLAG_allow_natives_syntax = true;
   2665   v8::HandleScope scope;
   2666   Local<ObjectTemplate> templ = ObjectTemplate::New();
   2667   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
   2668 
   2669   LocalContext context;
   2670   Local<v8::Object> obj = templ->NewInstance();
   2671   context->Global()->Set(v8_str("obj"), obj);
   2672 
   2673   const char* code =
   2674       "try {"
   2675       "  for (var i = 0; i < 100; i++) {"
   2676       "    var expected = i;"
   2677       "    if (i == 5) {"
   2678       "      %EnableAccessChecks(obj);"
   2679       "      expected = undefined;"
   2680       "    }"
   2681       "    var v = obj[i];"
   2682       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
   2683       "    if (i == 5) %DisableAccessChecks(obj);"
   2684       "  }"
   2685       "  'PASSED'"
   2686       "} catch(e) {"
   2687       "  e"
   2688       "}";
   2689   ExpectString(code, "PASSED");
   2690 }
   2691 
   2692 
   2693 THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
   2694   v8::HandleScope scope;
   2695   Local<ObjectTemplate> templ = ObjectTemplate::New();
   2696   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
   2697 
   2698   LocalContext context;
   2699   Local<v8::Object> obj = templ->NewInstance();
   2700   context->Global()->Set(v8_str("obj"), obj);
   2701 
   2702   const char* code =
   2703       "try {"
   2704       "  for (var i = 0; i < 100; i++) {"
   2705       "    var v = obj[i];"
   2706       "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
   2707       "  }"
   2708       "  'PASSED'"
   2709       "} catch(e) {"
   2710       "  e"
   2711       "}";
   2712   ExpectString(code, "PASSED");
   2713 }
   2714 
   2715 
   2716 THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
   2717   v8::HandleScope scope;
   2718   Local<ObjectTemplate> templ = ObjectTemplate::New();
   2719   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
   2720 
   2721   LocalContext context;
   2722   Local<v8::Object> obj = templ->NewInstance();
   2723   context->Global()->Set(v8_str("obj"), obj);
   2724 
   2725   const char* code =
   2726       "try {"
   2727       "  for (var i = 0; i < 100; i++) {"
   2728       "    var expected = i;"
   2729       "    if (i == 50) {"
   2730       "       i = 'foobar';"
   2731       "       expected = undefined;"
   2732       "    }"
   2733       "    var v = obj[i];"
   2734       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
   2735       "  }"
   2736       "  'PASSED'"
   2737       "} catch(e) {"
   2738       "  e"
   2739       "}";
   2740   ExpectString(code, "PASSED");
   2741 }
   2742 
   2743 
   2744 THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
   2745   v8::HandleScope scope;
   2746   Local<ObjectTemplate> templ = ObjectTemplate::New();
   2747   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
   2748 
   2749   LocalContext context;
   2750   Local<v8::Object> obj = templ->NewInstance();
   2751   context->Global()->Set(v8_str("obj"), obj);
   2752 
   2753   const char* code =
   2754       "var original = obj;"
   2755       "try {"
   2756       "  for (var i = 0; i < 100; i++) {"
   2757       "    var expected = i;"
   2758       "    if (i == 50) {"
   2759       "       obj = {50: 'foobar'};"
   2760       "       expected = 'foobar';"
   2761       "    }"
   2762       "    var v = obj[i];"
   2763       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
   2764       "    if (i == 50) obj = original;"
   2765       "  }"
   2766       "  'PASSED'"
   2767       "} catch(e) {"
   2768       "  e"
   2769       "}";
   2770   ExpectString(code, "PASSED");
   2771 }
   2772 
   2773 
   2774 THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
   2775   v8::HandleScope scope;
   2776   Local<ObjectTemplate> templ = ObjectTemplate::New();
   2777   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
   2778 
   2779   LocalContext context;
   2780   Local<v8::Object> obj = templ->NewInstance();
   2781   context->Global()->Set(v8_str("obj"), obj);
   2782 
   2783   const char* code =
   2784       "var original = obj;"
   2785       "try {"
   2786       "  for (var i = 0; i < 100; i++) {"
   2787       "    var expected = i;"
   2788       "    if (i == 5) {"
   2789       "       obj = 239;"
   2790       "       expected = undefined;"
   2791       "    }"
   2792       "    var v = obj[i];"
   2793       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
   2794       "    if (i == 5) obj = original;"
   2795       "  }"
   2796       "  'PASSED'"
   2797       "} catch(e) {"
   2798       "  e"
   2799       "}";
   2800   ExpectString(code, "PASSED");
   2801 }
   2802 
   2803 
   2804 THREADED_TEST(IndexedInterceptorOnProto) {
   2805   v8::HandleScope scope;
   2806   Local<ObjectTemplate> templ = ObjectTemplate::New();
   2807   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
   2808 
   2809   LocalContext context;
   2810   Local<v8::Object> obj = templ->NewInstance();
   2811   context->Global()->Set(v8_str("obj"), obj);
   2812 
   2813   const char* code =
   2814       "var o = {__proto__: obj};"
   2815       "try {"
   2816       "  for (var i = 0; i < 100; i++) {"
   2817       "    var v = o[i];"
   2818       "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
   2819       "  }"
   2820       "  'PASSED'"
   2821       "} catch(e) {"
   2822       "  e"
   2823       "}";
   2824   ExpectString(code, "PASSED");
   2825 }
   2826 
   2827 
   2828 THREADED_TEST(MultiContexts) {
   2829   v8::HandleScope scope;
   2830   v8::Handle<ObjectTemplate> templ = ObjectTemplate::New();
   2831   templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(DummyCallHandler));
   2832 
   2833   Local<String> password = v8_str("Password");
   2834 
   2835   // Create an environment
   2836   LocalContext context0(0, templ);
   2837   context0->SetSecurityToken(password);
   2838   v8::Handle<v8::Object> global0 = context0->Global();
   2839   global0->Set(v8_str("custom"), v8_num(1234));
   2840   CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
   2841 
   2842   // Create an independent environment
   2843   LocalContext context1(0, templ);
   2844   context1->SetSecurityToken(password);
   2845   v8::Handle<v8::Object> global1 = context1->Global();
   2846   global1->Set(v8_str("custom"), v8_num(1234));
   2847   CHECK_NE(global0, global1);
   2848   CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
   2849   CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
   2850 
   2851   // Now create a new context with the old global
   2852   LocalContext context2(0, templ, global1);
   2853   context2->SetSecurityToken(password);
   2854   v8::Handle<v8::Object> global2 = context2->Global();
   2855   CHECK_EQ(global1, global2);
   2856   CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
   2857   CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
   2858 }
   2859 
   2860 
   2861 THREADED_TEST(FunctionPrototypeAcrossContexts) {
   2862   // Make sure that functions created by cloning boilerplates cannot
   2863   // communicate through their __proto__ field.
   2864 
   2865   v8::HandleScope scope;
   2866 
   2867   LocalContext env0;
   2868   v8::Handle<v8::Object> global0 =
   2869       env0->Global();
   2870   v8::Handle<v8::Object> object0 =
   2871       v8::Handle<v8::Object>::Cast(global0->Get(v8_str("Object")));
   2872   v8::Handle<v8::Object> tostring0 =
   2873       v8::Handle<v8::Object>::Cast(object0->Get(v8_str("toString")));
   2874   v8::Handle<v8::Object> proto0 =
   2875       v8::Handle<v8::Object>::Cast(tostring0->Get(v8_str("__proto__")));
   2876   proto0->Set(v8_str("custom"), v8_num(1234));
   2877 
   2878   LocalContext env1;
   2879   v8::Handle<v8::Object> global1 =
   2880       env1->Global();
   2881   v8::Handle<v8::Object> object1 =
   2882       v8::Handle<v8::Object>::Cast(global1->Get(v8_str("Object")));
   2883   v8::Handle<v8::Object> tostring1 =
   2884       v8::Handle<v8::Object>::Cast(object1->Get(v8_str("toString")));
   2885   v8::Handle<v8::Object> proto1 =
   2886       v8::Handle<v8::Object>::Cast(tostring1->Get(v8_str("__proto__")));
   2887   CHECK(!proto1->Has(v8_str("custom")));
   2888 }
   2889 
   2890 
   2891 THREADED_TEST(Regress892105) {
   2892   // Make sure that object and array literals created by cloning
   2893   // boilerplates cannot communicate through their __proto__
   2894   // field. This is rather difficult to check, but we try to add stuff
   2895   // to Object.prototype and Array.prototype and create a new
   2896   // environment. This should succeed.
   2897 
   2898   v8::HandleScope scope;
   2899 
   2900   Local<String> source = v8_str("Object.prototype.obj = 1234;"
   2901                                 "Array.prototype.arr = 4567;"
   2902                                 "8901");
   2903 
   2904   LocalContext env0;
   2905   Local<Script> script0 = Script::Compile(source);
   2906   CHECK_EQ(8901.0, script0->Run()->NumberValue());
   2907 
   2908   LocalContext env1;
   2909   Local<Script> script1 = Script::Compile(source);
   2910   CHECK_EQ(8901.0, script1->Run()->NumberValue());
   2911 }
   2912 
   2913 
   2914 THREADED_TEST(UndetectableObject) {
   2915   v8::HandleScope scope;
   2916   LocalContext env;
   2917 
   2918   Local<v8::FunctionTemplate> desc =
   2919       v8::FunctionTemplate::New(0, v8::Handle<Value>());
   2920   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
   2921 
   2922   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
   2923   env->Global()->Set(v8_str("undetectable"), obj);
   2924 
   2925   ExpectString("undetectable.toString()", "[object Object]");
   2926   ExpectString("typeof undetectable", "undefined");
   2927   ExpectString("typeof(undetectable)", "undefined");
   2928   ExpectBoolean("typeof undetectable == 'undefined'", true);
   2929   ExpectBoolean("typeof undetectable == 'object'", false);
   2930   ExpectBoolean("if (undetectable) { true; } else { false; }", false);
   2931   ExpectBoolean("!undetectable", true);
   2932 
   2933   ExpectObject("true&&undetectable", obj);
   2934   ExpectBoolean("false&&undetectable", false);
   2935   ExpectBoolean("true||undetectable", true);
   2936   ExpectObject("false||undetectable", obj);
   2937 
   2938   ExpectObject("undetectable&&true", obj);
   2939   ExpectObject("undetectable&&false", obj);
   2940   ExpectBoolean("undetectable||true", true);
   2941   ExpectBoolean("undetectable||false", false);
   2942 
   2943   ExpectBoolean("undetectable==null", true);
   2944   ExpectBoolean("null==undetectable", true);
   2945   ExpectBoolean("undetectable==undefined", true);
   2946   ExpectBoolean("undefined==undetectable", true);
   2947   ExpectBoolean("undetectable==undetectable", true);
   2948 
   2949 
   2950   ExpectBoolean("undetectable===null", false);
   2951   ExpectBoolean("null===undetectable", false);
   2952   ExpectBoolean("undetectable===undefined", false);
   2953   ExpectBoolean("undefined===undetectable", false);
   2954   ExpectBoolean("undetectable===undetectable", true);
   2955 }
   2956 
   2957 
   2958 THREADED_TEST(UndetectableString) {
   2959   v8::HandleScope scope;
   2960   LocalContext env;
   2961 
   2962   Local<String> obj = String::NewUndetectable("foo");
   2963   env->Global()->Set(v8_str("undetectable"), obj);
   2964 
   2965   ExpectString("undetectable", "foo");
   2966   ExpectString("typeof undetectable", "undefined");
   2967   ExpectString("typeof(undetectable)", "undefined");
   2968   ExpectBoolean("typeof undetectable == 'undefined'", true);
   2969   ExpectBoolean("typeof undetectable == 'string'", false);
   2970   ExpectBoolean("if (undetectable) { true; } else { false; }", false);
   2971   ExpectBoolean("!undetectable", true);
   2972 
   2973   ExpectObject("true&&undetectable", obj);
   2974   ExpectBoolean("false&&undetectable", false);
   2975   ExpectBoolean("true||undetectable", true);
   2976   ExpectObject("false||undetectable", obj);
   2977 
   2978   ExpectObject("undetectable&&true", obj);
   2979   ExpectObject("undetectable&&false", obj);
   2980   ExpectBoolean("undetectable||true", true);
   2981   ExpectBoolean("undetectable||false", false);
   2982 
   2983   ExpectBoolean("undetectable==null", true);
   2984   ExpectBoolean("null==undetectable", true);
   2985   ExpectBoolean("undetectable==undefined", true);
   2986   ExpectBoolean("undefined==undetectable", true);
   2987   ExpectBoolean("undetectable==undetectable", true);
   2988 
   2989 
   2990   ExpectBoolean("undetectable===null", false);
   2991   ExpectBoolean("null===undetectable", false);
   2992   ExpectBoolean("undetectable===undefined", false);
   2993   ExpectBoolean("undefined===undetectable", false);
   2994   ExpectBoolean("undetectable===undetectable", true);
   2995 }
   2996 
   2997 
   2998 template <typename T> static void USE(T) { }
   2999 
   3000 
   3001 // This test is not intended to be run, just type checked.
   3002 static void PersistentHandles() {
   3003   USE(PersistentHandles);
   3004   Local<String> str = v8_str("foo");
   3005   v8::Persistent<String> p_str = v8::Persistent<String>::New(str);
   3006   USE(p_str);
   3007   Local<Script> scr = Script::Compile(v8_str(""));
   3008   v8::Persistent<Script> p_scr = v8::Persistent<Script>::New(scr);
   3009   USE(p_scr);
   3010   Local<ObjectTemplate> templ = ObjectTemplate::New();
   3011   v8::Persistent<ObjectTemplate> p_templ =
   3012     v8::Persistent<ObjectTemplate>::New(templ);
   3013   USE(p_templ);
   3014 }
   3015 
   3016 
   3017 static v8::Handle<Value> HandleLogDelegator(const v8::Arguments& args) {
   3018   ApiTestFuzzer::Fuzz();
   3019   return v8::Undefined();
   3020 }
   3021 
   3022 
   3023 THREADED_TEST(GlobalObjectTemplate) {
   3024   v8::HandleScope handle_scope;
   3025   Local<ObjectTemplate> global_template = ObjectTemplate::New();
   3026   global_template->Set(v8_str("JSNI_Log"),
   3027                        v8::FunctionTemplate::New(HandleLogDelegator));
   3028   v8::Persistent<Context> context = Context::New(0, global_template);
   3029   Context::Scope context_scope(context);
   3030   Script::Compile(v8_str("JSNI_Log('LOG')"))->Run();
   3031   context.Dispose();
   3032 }
   3033 
   3034 
   3035 static const char* kSimpleExtensionSource =
   3036   "function Foo() {"
   3037   "  return 4;"
   3038   "}";
   3039 
   3040 
   3041 THREADED_TEST(SimpleExtensions) {
   3042   v8::HandleScope handle_scope;
   3043   v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
   3044   const char* extension_names[] = { "simpletest" };
   3045   v8::ExtensionConfiguration extensions(1, extension_names);
   3046   v8::Handle<Context> context = Context::New(&extensions);
   3047   Context::Scope lock(context);
   3048   v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
   3049   CHECK_EQ(result, v8::Integer::New(4));
   3050 }
   3051 
   3052 
   3053 static const char* kEvalExtensionSource1 =
   3054   "function UseEval1() {"
   3055   "  var x = 42;"
   3056   "  return eval('x');"
   3057   "}";
   3058 
   3059 
   3060 static const char* kEvalExtensionSource2 =
   3061   "(function() {"
   3062   "  var x = 42;"
   3063   "  function e() {"
   3064   "    return eval('x');"
   3065   "  }"
   3066   "  this.UseEval2 = e;"
   3067   "})()";
   3068 
   3069 
   3070 THREADED_TEST(UseEvalFromExtension) {
   3071   v8::HandleScope handle_scope;
   3072   v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
   3073   v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
   3074   const char* extension_names[] = { "evaltest1", "evaltest2" };
   3075   v8::ExtensionConfiguration extensions(2, extension_names);
   3076   v8::Handle<Context> context = Context::New(&extensions);
   3077   Context::Scope lock(context);
   3078   v8::Handle<Value> result = Script::Compile(v8_str("UseEval1()"))->Run();
   3079   CHECK_EQ(result, v8::Integer::New(42));
   3080   result = Script::Compile(v8_str("UseEval2()"))->Run();
   3081   CHECK_EQ(result, v8::Integer::New(42));
   3082 }
   3083 
   3084 
   3085 static const char* kWithExtensionSource1 =
   3086   "function UseWith1() {"
   3087   "  var x = 42;"
   3088   "  with({x:87}) { return x; }"
   3089   "}";
   3090 
   3091 
   3092 
   3093 static const char* kWithExtensionSource2 =
   3094   "(function() {"
   3095   "  var x = 42;"
   3096   "  function e() {"
   3097   "    with ({x:87}) { return x; }"
   3098   "  }"
   3099   "  this.UseWith2 = e;"
   3100   "})()";
   3101 
   3102 
   3103 THREADED_TEST(UseWithFromExtension) {
   3104   v8::HandleScope handle_scope;
   3105   v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
   3106   v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
   3107   const char* extension_names[] = { "withtest1", "withtest2" };
   3108   v8::ExtensionConfiguration extensions(2, extension_names);
   3109   v8::Handle<Context> context = Context::New(&extensions);
   3110   Context::Scope lock(context);
   3111   v8::Handle<Value> result = Script::Compile(v8_str("UseWith1()"))->Run();
   3112   CHECK_EQ(result, v8::Integer::New(87));
   3113   result = Script::Compile(v8_str("UseWith2()"))->Run();
   3114   CHECK_EQ(result, v8::Integer::New(87));
   3115 }
   3116 
   3117 
   3118 THREADED_TEST(AutoExtensions) {
   3119   v8::HandleScope handle_scope;
   3120   Extension* extension = new Extension("autotest", kSimpleExtensionSource);
   3121   extension->set_auto_enable(true);
   3122   v8::RegisterExtension(extension);
   3123   v8::Handle<Context> context = Context::New();
   3124   Context::Scope lock(context);
   3125   v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
   3126   CHECK_EQ(result, v8::Integer::New(4));
   3127 }
   3128 
   3129 
   3130 static const char* kSyntaxErrorInExtensionSource =
   3131     "[";
   3132 
   3133 
   3134 // Test that a syntax error in an extension does not cause a fatal
   3135 // error but results in an empty context.
   3136 THREADED_TEST(SyntaxErrorExtensions) {
   3137   v8::HandleScope handle_scope;
   3138   v8::RegisterExtension(new Extension("syntaxerror",
   3139                                       kSyntaxErrorInExtensionSource));
   3140   const char* extension_names[] = { "syntaxerror" };
   3141   v8::ExtensionConfiguration extensions(1, extension_names);
   3142   v8::Handle<Context> context = Context::New(&extensions);
   3143   CHECK(context.IsEmpty());
   3144 }
   3145 
   3146 
   3147 static const char* kExceptionInExtensionSource =
   3148     "throw 42";
   3149 
   3150 
   3151 // Test that an exception when installing an extension does not cause
   3152 // a fatal error but results in an empty context.
   3153 THREADED_TEST(ExceptionExtensions) {
   3154   v8::HandleScope handle_scope;
   3155   v8::RegisterExtension(new Extension("exception",
   3156                                       kExceptionInExtensionSource));
   3157   const char* extension_names[] = { "exception" };
   3158   v8::ExtensionConfiguration extensions(1, extension_names);
   3159   v8::Handle<Context> context = Context::New(&extensions);
   3160   CHECK(context.IsEmpty());
   3161 }
   3162 
   3163 
   3164 static void CheckDependencies(const char* name, const char* expected) {
   3165   v8::HandleScope handle_scope;
   3166   v8::ExtensionConfiguration config(1, &name);
   3167   LocalContext context(&config);
   3168   CHECK_EQ(String::New(expected), context->Global()->Get(v8_str("loaded")));
   3169 }
   3170 
   3171 
   3172 /*
   3173  * Configuration:
   3174  *
   3175  *     /-- B <--\
   3176  * A <-          -- D <-- E
   3177  *     \-- C <--/
   3178  */
   3179 THREADED_TEST(ExtensionDependency) {
   3180   static const char* kEDeps[] = { "D" };
   3181   v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
   3182   static const char* kDDeps[] = { "B", "C" };
   3183   v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
   3184   static const char* kBCDeps[] = { "A" };
   3185   v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
   3186   v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
   3187   v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
   3188   CheckDependencies("A", "undefinedA");
   3189   CheckDependencies("B", "undefinedAB");
   3190   CheckDependencies("C", "undefinedAC");
   3191   CheckDependencies("D", "undefinedABCD");
   3192   CheckDependencies("E", "undefinedABCDE");
   3193   v8::HandleScope handle_scope;
   3194   static const char* exts[2] = { "C", "E" };
   3195   v8::ExtensionConfiguration config(2, exts);
   3196   LocalContext context(&config);
   3197   CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
   3198 }
   3199 
   3200 
   3201 static const char* kExtensionTestScript =
   3202   "native function A();"
   3203   "native function B();"
   3204   "native function C();"
   3205   "function Foo(i) {"
   3206   "  if (i == 0) return A();"
   3207   "  if (i == 1) return B();"
   3208   "  if (i == 2) return C();"
   3209   "}";
   3210 
   3211 
   3212 static v8::Handle<Value> CallFun(const v8::Arguments& args) {
   3213   ApiTestFuzzer::Fuzz();
   3214   if (args.IsConstructCall()) {
   3215     args.This()->Set(v8_str("data"), args.Data());
   3216     return v8::Null();
   3217   }
   3218   return args.Data();
   3219 }
   3220 
   3221 
   3222 class FunctionExtension : public Extension {
   3223  public:
   3224   FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
   3225   virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
   3226       v8::Handle<String> name);
   3227 };
   3228 
   3229 
   3230 static int lookup_count = 0;
   3231 v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunction(
   3232       v8::Handle<String> name) {
   3233   lookup_count++;
   3234   if (name->Equals(v8_str("A"))) {
   3235     return v8::FunctionTemplate::New(CallFun, v8::Integer::New(8));
   3236   } else if (name->Equals(v8_str("B"))) {
   3237     return v8::FunctionTemplate::New(CallFun, v8::Integer::New(7));
   3238   } else if (name->Equals(v8_str("C"))) {
   3239     return v8::FunctionTemplate::New(CallFun, v8::Integer::New(6));
   3240   } else {
   3241     return v8::Handle<v8::FunctionTemplate>();
   3242   }
   3243 }
   3244 
   3245 
   3246 THREADED_TEST(FunctionLookup) {
   3247   v8::RegisterExtension(new FunctionExtension());
   3248   v8::HandleScope handle_scope;
   3249   static const char* exts[1] = { "functiontest" };
   3250   v8::ExtensionConfiguration config(1, exts);
   3251   LocalContext context(&config);
   3252   CHECK_EQ(3, lookup_count);
   3253   CHECK_EQ(v8::Integer::New(8), Script::Compile(v8_str("Foo(0)"))->Run());
   3254   CHECK_EQ(v8::Integer::New(7), Script::Compile(v8_str("Foo(1)"))->Run());
   3255   CHECK_EQ(v8::Integer::New(6), Script::Compile(v8_str("Foo(2)"))->Run());
   3256 }
   3257 
   3258 
   3259 THREADED_TEST(NativeFunctionConstructCall) {
   3260   v8::RegisterExtension(new FunctionExtension());
   3261   v8::HandleScope handle_scope;
   3262   static const char* exts[1] = { "functiontest" };
   3263   v8::ExtensionConfiguration config(1, exts);
   3264   LocalContext context(&config);
   3265   for (int i = 0; i < 10; i++) {
   3266     // Run a few times to ensure that allocation of objects doesn't
   3267     // change behavior of a constructor function.
   3268     CHECK_EQ(v8::Integer::New(8),
   3269              Script::Compile(v8_str("(new A()).data"))->Run());
   3270     CHECK_EQ(v8::Integer::New(7),
   3271              Script::Compile(v8_str("(new B()).data"))->Run());
   3272     CHECK_EQ(v8::Integer::New(6),
   3273              Script::Compile(v8_str("(new C()).data"))->Run());
   3274   }
   3275 }
   3276 
   3277 
   3278 static const char* last_location;
   3279 static const char* last_message;
   3280 void StoringErrorCallback(const char* location, const char* message) {
   3281   if (last_location == NULL) {
   3282     last_location = location;
   3283     last_message = message;
   3284   }
   3285 }
   3286 
   3287 
   3288 // ErrorReporting creates a circular extensions configuration and
   3289 // tests that the fatal error handler gets called.  This renders V8
   3290 // unusable and therefore this test cannot be run in parallel.
   3291 TEST(ErrorReporting) {
   3292   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
   3293   static const char* aDeps[] = { "B" };
   3294   v8::RegisterExtension(new Extension("A", "", 1, aDeps));
   3295   static const char* bDeps[] = { "A" };
   3296   v8::RegisterExtension(new Extension("B", "", 1, bDeps));
   3297   last_location = NULL;
   3298   v8::ExtensionConfiguration config(1, bDeps);
   3299   v8::Handle<Context> context = Context::New(&config);
   3300   CHECK(context.IsEmpty());
   3301   CHECK_NE(last_location, NULL);
   3302 }
   3303 
   3304 
   3305 static const char* js_code_causing_huge_string_flattening =
   3306     "var str = 'X';"
   3307     "for (var i = 0; i < 30; i++) {"
   3308     "  str = str + str;"
   3309     "}"
   3310     "str.match(/X/);";
   3311 
   3312 
   3313 void OOMCallback(const char* location, const char* message) {
   3314   exit(0);
   3315 }
   3316 
   3317 
   3318 TEST(RegexpOutOfMemory) {
   3319   // Execute a script that causes out of memory when flattening a string.
   3320   v8::HandleScope scope;
   3321   v8::V8::SetFatalErrorHandler(OOMCallback);
   3322   LocalContext context;
   3323   Local<Script> script =
   3324       Script::Compile(String::New(js_code_causing_huge_string_flattening));
   3325   last_location = NULL;
   3326   Local<Value> result = script->Run();
   3327 
   3328   CHECK(false);  // Should not return.
   3329 }
   3330 
   3331 
   3332 static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
   3333                                              v8::Handle<Value> data) {
   3334   CHECK_EQ(v8::Undefined(), data);
   3335   CHECK(message->GetScriptResourceName()->IsUndefined());
   3336   CHECK_EQ(v8::Undefined(), message->GetScriptResourceName());
   3337   message->GetLineNumber();
   3338   message->GetSourceLine();
   3339 }
   3340 
   3341 
   3342 THREADED_TEST(ErrorWithMissingScriptInfo) {
   3343   v8::HandleScope scope;
   3344   LocalContext context;
   3345   v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
   3346   Script::Compile(v8_str("throw Error()"))->Run();
   3347   v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
   3348 }
   3349 
   3350 
   3351 int global_index = 0;
   3352 
   3353 class Snorkel {
   3354  public:
   3355   Snorkel() { index_ = global_index++; }
   3356   int index_;
   3357 };
   3358 
   3359 class Whammy {
   3360  public:
   3361   Whammy() {
   3362     cursor_ = 0;
   3363   }
   3364   ~Whammy() {
   3365     script_.Dispose();
   3366   }
   3367   v8::Handle<Script> getScript() {
   3368     if (script_.IsEmpty())
   3369       script_ = v8::Persistent<Script>::New(v8_compile("({}).blammo"));
   3370     return Local<Script>(*script_);
   3371   }
   3372 
   3373  public:
   3374   static const int kObjectCount = 256;
   3375   int cursor_;
   3376   v8::Persistent<v8::Object> objects_[kObjectCount];
   3377   v8::Persistent<Script> script_;
   3378 };
   3379 
   3380 static void HandleWeakReference(v8::Persistent<v8::Value> obj, void* data) {
   3381   Snorkel* snorkel = reinterpret_cast<Snorkel*>(data);
   3382   delete snorkel;
   3383   obj.ClearWeak();
   3384 }
   3385 
   3386 v8::Handle<Value> WhammyPropertyGetter(Local<String> name,
   3387                                        const AccessorInfo& info) {
   3388   Whammy* whammy =
   3389     static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
   3390 
   3391   v8::Persistent<v8::Object> prev = whammy->objects_[whammy->cursor_];
   3392 
   3393   v8::Handle<v8::Object> obj = v8::Object::New();
   3394   v8::Persistent<v8::Object> global = v8::Persistent<v8::Object>::New(obj);
   3395   if (!prev.IsEmpty()) {
   3396     prev->Set(v8_str("next"), obj);
   3397     prev.MakeWeak(new Snorkel(), &HandleWeakReference);
   3398     whammy->objects_[whammy->cursor_].Clear();
   3399   }
   3400   whammy->objects_[whammy->cursor_] = global;
   3401   whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount;
   3402   return whammy->getScript()->Run();
   3403 }
   3404 
   3405 THREADED_TEST(WeakReference) {
   3406   v8::HandleScope handle_scope;
   3407   v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New();
   3408   templ->SetNamedPropertyHandler(WhammyPropertyGetter,
   3409                                  0, 0, 0, 0,
   3410                                  v8::External::New(new Whammy()));
   3411   const char* extension_list[] = { "v8/gc" };
   3412   v8::ExtensionConfiguration extensions(1, extension_list);
   3413   v8::Persistent<Context> context = Context::New(&extensions);
   3414   Context::Scope context_scope(context);
   3415 
   3416   v8::Handle<v8::Object> interceptor = templ->NewInstance();
   3417   context->Global()->Set(v8_str("whammy"), interceptor);
   3418   const char* code =
   3419       "var last;"
   3420       "for (var i = 0; i < 10000; i++) {"
   3421       "  var obj = whammy.length;"
   3422       "  if (last) last.next = obj;"
   3423       "  last = obj;"
   3424       "}"
   3425       "gc();"
   3426       "4";
   3427   v8::Handle<Value> result = CompileRun(code);
   3428   CHECK_EQ(4.0, result->NumberValue());
   3429 
   3430   context.Dispose();
   3431 }
   3432 
   3433 
   3434 static bool in_scavenge = false;
   3435 static int last = -1;
   3436 
   3437 static void ForceScavenge(v8::Persistent<v8::Value> obj, void* data) {
   3438   CHECK_EQ(-1, last);
   3439   last = 0;
   3440   obj.Dispose();
   3441   obj.Clear();
   3442   in_scavenge = true;
   3443   i::Heap::PerformScavenge();
   3444   in_scavenge = false;
   3445   *(reinterpret_cast<bool*>(data)) = true;
   3446 }
   3447 
   3448 static void CheckIsNotInvokedInScavenge(v8::Persistent<v8::Value> obj,
   3449                                         void* data) {
   3450   CHECK_EQ(0, last);
   3451   last = 1;
   3452   *(reinterpret_cast<bool*>(data)) = in_scavenge;
   3453   obj.Dispose();
   3454   obj.Clear();
   3455 }
   3456 
   3457 THREADED_TEST(NoWeakRefCallbacksInScavenge) {
   3458   // Test verifies that scavenge cannot invoke WeakReferenceCallbacks.
   3459   // Calling callbacks from scavenges is unsafe as objects held by those
   3460   // handlers might have become strongly reachable, but scavenge doesn't
   3461   // check that.
   3462   v8::Persistent<Context> context = Context::New();
   3463   Context::Scope context_scope(context);
   3464 
   3465   v8::Persistent<v8::Object> object_a;
   3466   v8::Persistent<v8::Object> object_b;
   3467 
   3468   {
   3469     v8::HandleScope handle_scope;
   3470     object_b = v8::Persistent<v8::Object>::New(v8::Object::New());
   3471     object_a = v8::Persistent<v8::Object>::New(v8::Object::New());
   3472   }
   3473 
   3474   bool object_a_disposed = false;
   3475   object_a.MakeWeak(&object_a_disposed, &ForceScavenge);
   3476   bool released_in_scavenge = false;
   3477   object_b.MakeWeak(&released_in_scavenge, &CheckIsNotInvokedInScavenge);
   3478 
   3479   while (!object_a_disposed) {
   3480     i::Heap::CollectAllGarbage(false);
   3481   }
   3482   CHECK(!released_in_scavenge);
   3483 }
   3484 
   3485 
   3486 v8::Handle<Function> args_fun;
   3487 
   3488 
   3489 static v8::Handle<Value> ArgumentsTestCallback(const v8::Arguments& args) {
   3490   ApiTestFuzzer::Fuzz();
   3491   CHECK_EQ(args_fun, args.Callee());
   3492   CHECK_EQ(3, args.Length());
   3493   CHECK_EQ(v8::Integer::New(1), args[0]);
   3494   CHECK_EQ(v8::Integer::New(2), args[1]);
   3495   CHECK_EQ(v8::Integer::New(3), args[2]);
   3496   CHECK_EQ(v8::Undefined(), args[3]);
   3497   v8::HandleScope scope;
   3498   i::Heap::CollectAllGarbage(false);
   3499   return v8::Undefined();
   3500 }
   3501 
   3502 
   3503 THREADED_TEST(Arguments) {
   3504   v8::HandleScope scope;
   3505   v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
   3506   global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback));
   3507   LocalContext context(NULL, global);
   3508   args_fun = v8::Handle<Function>::Cast(context->Global()->Get(v8_str("f")));
   3509   v8_compile("f(1, 2, 3)")->Run();
   3510 }
   3511 
   3512 
   3513 static v8::Handle<Value> NoBlockGetterX(Local<String> name,
   3514                                         const AccessorInfo&) {
   3515   return v8::Handle<Value>();
   3516 }
   3517 
   3518 
   3519 static v8::Handle<Value> NoBlockGetterI(uint32_t index,
   3520                                         const AccessorInfo&) {
   3521   return v8::Handle<Value>();
   3522 }
   3523 
   3524 
   3525 static v8::Handle<v8::Boolean> PDeleter(Local<String> name,
   3526                                         const AccessorInfo&) {
   3527   if (!name->Equals(v8_str("foo"))) {
   3528     return v8::Handle<v8::Boolean>();  // not intercepted
   3529   }
   3530 
   3531   return v8::False();  // intercepted, and don't delete the property
   3532 }
   3533 
   3534 
   3535 static v8::Handle<v8::Boolean> IDeleter(uint32_t index, const AccessorInfo&) {
   3536   if (index != 2) {
   3537     return v8::Handle<v8::Boolean>();  // not intercepted
   3538   }
   3539 
   3540   return v8::False();  // intercepted, and don't delete the property
   3541 }
   3542 
   3543 
   3544 THREADED_TEST(Deleter) {
   3545   v8::HandleScope scope;
   3546   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
   3547   obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
   3548   obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
   3549   LocalContext context;
   3550   context->Global()->Set(v8_str("k"), obj->NewInstance());
   3551   CompileRun(
   3552     "k.foo = 'foo';"
   3553     "k.bar = 'bar';"
   3554     "k[2] = 2;"
   3555     "k[4] = 4;");
   3556   CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
   3557   CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
   3558 
   3559   CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
   3560   CHECK(v8_compile("k.bar")->Run()->IsUndefined());
   3561 
   3562   CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
   3563   CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
   3564 
   3565   CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
   3566   CHECK(v8_compile("k[4]")->Run()->IsUndefined());
   3567 }
   3568 
   3569 
   3570 static v8::Handle<Value> GetK(Local<String> name, const AccessorInfo&) {
   3571   ApiTestFuzzer::Fuzz();
   3572   if (name->Equals(v8_str("foo")) ||
   3573       name->Equals(v8_str("bar")) ||
   3574       name->Equals(v8_str("baz"))) {
   3575     return v8::Undefined();
   3576   }
   3577   return v8::Handle<Value>();
   3578 }
   3579 
   3580 
   3581 static v8::Handle<Value> IndexedGetK(uint32_t index, const AccessorInfo&) {
   3582   ApiTestFuzzer::Fuzz();
   3583   if (index == 0 || index == 1) return v8::Undefined();
   3584   return v8::Handle<Value>();
   3585 }
   3586 
   3587 
   3588 static v8::Handle<v8::Array> NamedEnum(const AccessorInfo&) {
   3589   ApiTestFuzzer::Fuzz();
   3590   v8::Handle<v8::Array> result = v8::Array::New(3);
   3591   result->Set(v8::Integer::New(0), v8_str("foo"));
   3592   result->Set(v8::Integer::New(1), v8_str("bar"));
   3593   result->Set(v8::Integer::New(2), v8_str("baz"));
   3594   return result;
   3595 }
   3596 
   3597 
   3598 static v8::Handle<v8::Array> IndexedEnum(const AccessorInfo&) {
   3599   ApiTestFuzzer::Fuzz();
   3600   v8::Handle<v8::Array> result = v8::Array::New(2);
   3601   result->Set(v8::Integer::New(0), v8_str("0"));
   3602   result->Set(v8::Integer::New(1), v8_str("1"));
   3603   return result;
   3604 }
   3605 
   3606 
   3607 THREADED_TEST(Enumerators) {
   3608   v8::HandleScope scope;
   3609   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
   3610   obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
   3611   obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
   3612   LocalContext context;
   3613   context->Global()->Set(v8_str("k"), obj->NewInstance());
   3614   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
   3615     "k[10] = 0;"
   3616     "k.a = 0;"
   3617     "k[5] = 0;"
   3618     "k.b = 0;"
   3619     "k[4294967295] = 0;"
   3620     "k.c = 0;"
   3621     "k[4294967296] = 0;"
   3622     "k.d = 0;"
   3623     "k[140000] = 0;"
   3624     "k.e = 0;"
   3625     "k[30000000000] = 0;"
   3626     "k.f = 0;"
   3627     "var result = [];"
   3628     "for (var prop in k) {"
   3629     "  result.push(prop);"
   3630     "}"
   3631     "result"));
   3632   // Check that we get all the property names returned including the
   3633   // ones from the enumerators in the right order: indexed properties
   3634   // in numerical order, indexed interceptor properties, named
   3635   // properties in insertion order, named interceptor properties.
   3636   // This order is not mandated by the spec, so this test is just
   3637   // documenting our behavior.
   3638   CHECK_EQ(17, result->Length());
   3639   // Indexed properties in numerical order.
   3640   CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(0)));
   3641   CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(1)));
   3642   CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(2)));
   3643   CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(3)));
   3644   // Indexed interceptor properties in the order they are returned
   3645   // from the enumerator interceptor.
   3646   CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(4)));
   3647   CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(5)));
   3648   // Named properties in insertion order.
   3649   CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(6)));
   3650   CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(7)));
   3651   CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(8)));
   3652   CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(9)));
   3653   CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(10)));
   3654   CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(11)));
   3655   CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(12)));
   3656   CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(13)));
   3657   // Named interceptor properties.
   3658   CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(14)));
   3659   CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(15)));
   3660   CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(16)));
   3661 }
   3662 
   3663 
   3664 int p_getter_count;
   3665 int p_getter_count2;
   3666 
   3667 
   3668 static v8::Handle<Value> PGetter(Local<String> name, const AccessorInfo& info) {
   3669   ApiTestFuzzer::Fuzz();
   3670   p_getter_count++;
   3671   v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
   3672   CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
   3673   if (name->Equals(v8_str("p1"))) {
   3674     CHECK_EQ(info.This(), global->Get(v8_str("o1")));
   3675   } else if (name->Equals(v8_str("p2"))) {
   3676     CHECK_EQ(info.This(), global->Get(v8_str("o2")));
   3677   } else if (name->Equals(v8_str("p3"))) {
   3678     CHECK_EQ(info.This(), global->Get(v8_str("o3")));
   3679   } else if (name->Equals(v8_str("p4"))) {
   3680     CHECK_EQ(info.This(), global->Get(v8_str("o4")));
   3681   }
   3682   return v8::Undefined();
   3683 }
   3684 
   3685 
   3686 static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
   3687   ApiTestFuzzer::Fuzz();
   3688   LocalContext context;
   3689   context->Global()->Set(v8_str("o1"), obj->NewInstance());
   3690   CompileRun(
   3691     "o1.__proto__ = { };"
   3692     "var o2 = { __proto__: o1 };"
   3693     "var o3 = { __proto__: o2 };"
   3694     "var o4 = { __proto__: o3 };"
   3695     "for (var i = 0; i < 10; i++) o4.p4;"
   3696     "for (var i = 0; i < 10; i++) o3.p3;"
   3697     "for (var i = 0; i < 10; i++) o2.p2;"
   3698     "for (var i = 0; i < 10; i++) o1.p1;");
   3699 }
   3700 
   3701 
   3702 static v8::Handle<Value> PGetter2(Local<String> name,
   3703                                   const AccessorInfo& info) {
   3704   ApiTestFuzzer::Fuzz();
   3705   p_getter_count2++;
   3706   v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
   3707   CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
   3708   if (name->Equals(v8_str("p1"))) {
   3709     CHECK_EQ(info.This(), global->Get(v8_str("o1")));
   3710   } else if (name->Equals(v8_str("p2"))) {
   3711     CHECK_EQ(info.This(), global->Get(v8_str("o2")));
   3712   } else if (name->Equals(v8_str("p3"))) {
   3713     CHECK_EQ(info.This(), global->Get(v8_str("o3")));
   3714   } else if (name->Equals(v8_str("p4"))) {
   3715     CHECK_EQ(info.This(), global->Get(v8_str("o4")));
   3716   }
   3717   return v8::Undefined();
   3718 }
   3719 
   3720 
   3721 THREADED_TEST(GetterHolders) {
   3722   v8::HandleScope scope;
   3723   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
   3724   obj->SetAccessor(v8_str("p1"), PGetter);
   3725   obj->SetAccessor(v8_str("p2"), PGetter);
   3726   obj->SetAccessor(v8_str("p3"), PGetter);
   3727   obj->SetAccessor(v8_str("p4"), PGetter);
   3728   p_getter_count = 0;
   3729   RunHolderTest(obj);
   3730   CHECK_EQ(40, p_getter_count);
   3731 }
   3732 
   3733 
   3734 THREADED_TEST(PreInterceptorHolders) {
   3735   v8::HandleScope scope;
   3736   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
   3737   obj->SetNamedPropertyHandler(PGetter2);
   3738   p_getter_count2 = 0;
   3739   RunHolderTest(obj);
   3740   CHECK_EQ(40, p_getter_count2);
   3741 }
   3742 
   3743 
   3744 THREADED_TEST(ObjectInstantiation) {
   3745   v8::HandleScope scope;
   3746   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
   3747   templ->SetAccessor(v8_str("t"), PGetter2);
   3748   LocalContext context;
   3749   context->Global()->Set(v8_str("o"), templ->NewInstance());
   3750   for (int i = 0; i < 100; i++) {
   3751     v8::HandleScope inner_scope;
   3752     v8::Handle<v8::Object> obj = templ->NewInstance();
   3753     CHECK_NE(obj, context->Global()->Get(v8_str("o")));
   3754     context->Global()->Set(v8_str("o2"), obj);
   3755     v8::Handle<Value> value =
   3756         Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run();
   3757     CHECK_EQ(v8::True(), value);
   3758     context->Global()->Set(v8_str("o"), obj);
   3759   }
   3760 }
   3761 
   3762 
   3763 THREADED_TEST(StringWrite) {
   3764   v8::HandleScope scope;
   3765   v8::Handle<String> str = v8_str("abcde");
   3766 
   3767   char buf[100];
   3768   int len;
   3769 
   3770   memset(buf, 0x1, sizeof(buf));
   3771   len = str->WriteAscii(buf);
   3772   CHECK_EQ(len, 5);
   3773   CHECK_EQ(strncmp("abcde\0", buf, 6), 0);
   3774 
   3775   memset(buf, 0x1, sizeof(buf));
   3776   len = str->WriteAscii(buf, 0, 4);
   3777   CHECK_EQ(len, 4);
   3778   CHECK_EQ(strncmp("abcd\1", buf, 5), 0);
   3779 
   3780   memset(buf, 0x1, sizeof(buf));
   3781   len = str->WriteAscii(buf, 0, 5);
   3782   CHECK_EQ(len, 5);
   3783   CHECK_EQ(strncmp("abcde\1", buf, 6), 0);
   3784 
   3785   memset(buf, 0x1, sizeof(buf));
   3786   len = str->WriteAscii(buf, 0, 6);
   3787   CHECK_EQ(len, 5);
   3788   CHECK_EQ(strncmp("abcde\0", buf, 6), 0);
   3789 
   3790   memset(buf, 0x1, sizeof(buf));
   3791   len = str->WriteAscii(buf, 4, -1);
   3792   CHECK_EQ(len, 1);
   3793   CHECK_EQ(strncmp("e\0", buf, 2), 0);
   3794 
   3795   memset(buf, 0x1, sizeof(buf));
   3796   len = str->WriteAscii(buf, 4, 6);
   3797   CHECK_EQ(len, 1);
   3798   CHECK_EQ(strncmp("e\0", buf, 2), 0);
   3799 
   3800   memset(buf, 0x1, sizeof(buf));
   3801   len = str->WriteAscii(buf, 4, 1);
   3802   CHECK_EQ(len, 1);
   3803   CHECK_EQ(strncmp("e\1", buf, 2), 0);
   3804 }
   3805 
   3806 
   3807 THREADED_TEST(ToArrayIndex) {
   3808   v8::HandleScope scope;
   3809   LocalContext context;
   3810 
   3811   v8::Handle<String> str = v8_str("42");
   3812   v8::Handle<v8::Uint32> index = str->ToArrayIndex();
   3813   CHECK(!index.IsEmpty());
   3814   CHECK_EQ(42.0, index->Uint32Value());
   3815   str = v8_str("42asdf");
   3816   index = str->ToArrayIndex();
   3817   CHECK(index.IsEmpty());
   3818   str = v8_str("-42");
   3819   index = str->ToArrayIndex();
   3820   CHECK(index.IsEmpty());
   3821   str = v8_str("4294967295");
   3822   index = str->ToArrayIndex();
   3823   CHECK(!index.IsEmpty());
   3824   CHECK_EQ(4294967295.0, index->Uint32Value());
   3825   v8::Handle<v8::Number> num = v8::Number::New(1);
   3826   index = num->ToArrayIndex();
   3827   CHECK(!index.IsEmpty());
   3828   CHECK_EQ(1.0, index->Uint32Value());
   3829   num = v8::Number::New(-1);
   3830   index = num->ToArrayIndex();
   3831   CHECK(index.IsEmpty());
   3832   v8::Handle<v8::Object> obj = v8::Object::New();
   3833   index = obj->ToArrayIndex();
   3834   CHECK(index.IsEmpty());
   3835 }
   3836 
   3837 
   3838 THREADED_TEST(ErrorConstruction) {
   3839   v8::HandleScope scope;
   3840   LocalContext context;
   3841 
   3842   v8::Handle<String> foo = v8_str("foo");
   3843   v8::Handle<String> message = v8_str("message");
   3844   v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
   3845   CHECK(range_error->IsObject());
   3846   v8::Handle<v8::Object> range_obj(v8::Handle<v8::Object>::Cast(range_error));
   3847   CHECK(v8::Handle<v8::Object>::Cast(range_error)->Get(message)->Equals(foo));
   3848   v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
   3849   CHECK(reference_error->IsObject());
   3850   CHECK(
   3851       v8::Handle<v8::Object>::Cast(reference_error)->Get(message)->Equals(foo));
   3852   v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
   3853   CHECK(syntax_error->IsObject());
   3854   CHECK(v8::Handle<v8::Object>::Cast(syntax_error)->Get(message)->Equals(foo));
   3855   v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
   3856   CHECK(type_error->IsObject());
   3857   CHECK(v8::Handle<v8::Object>::Cast(type_error)->Get(message)->Equals(foo));
   3858   v8::Handle<Value> error = v8::Exception::Error(foo);
   3859   CHECK(error->IsObject());
   3860   CHECK(v8::Handle<v8::Object>::Cast(error)->Get(message)->Equals(foo));
   3861 }
   3862 
   3863 
   3864 static v8::Handle<Value> YGetter(Local<String> name, const AccessorInfo& info) {
   3865   ApiTestFuzzer::Fuzz();
   3866   return v8_num(10);
   3867 }
   3868 
   3869 
   3870 static void YSetter(Local<String> name,
   3871                     Local<Value> value,
   3872                     const AccessorInfo& info) {
   3873   if (info.This()->Has(name)) {
   3874     info.This()->Delete(name);
   3875   }
   3876   info.This()->Set(name, value);
   3877 }
   3878 
   3879 
   3880 THREADED_TEST(DeleteAccessor) {
   3881   v8::HandleScope scope;
   3882   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
   3883   obj->SetAccessor(v8_str("y"), YGetter, YSetter);
   3884   LocalContext context;
   3885   v8::Handle<v8::Object> holder = obj->NewInstance();
   3886   context->Global()->Set(v8_str("holder"), holder);
   3887   v8::Handle<Value> result = CompileRun(
   3888       "holder.y = 11; holder.y = 12; holder.y");
   3889   CHECK_EQ(12, result->Uint32Value());
   3890 }
   3891 
   3892 
   3893 THREADED_TEST(TypeSwitch) {
   3894   v8::HandleScope scope;
   3895   v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New();
   3896   v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New();
   3897   v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New();
   3898   v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
   3899   v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
   3900   LocalContext context;
   3901   v8::Handle<v8::Object> obj0 = v8::Object::New();
   3902   v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
   3903   v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
   3904   v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
   3905   for (int i = 0; i < 10; i++) {
   3906     CHECK_EQ(0, type_switch->match(obj0));
   3907     CHECK_EQ(1, type_switch->match(obj1));
   3908     CHECK_EQ(2, type_switch->match(obj2));
   3909     CHECK_EQ(3, type_switch->match(obj3));
   3910     CHECK_EQ(3, type_switch->match(obj3));
   3911     CHECK_EQ(2, type_switch->match(obj2));
   3912     CHECK_EQ(1, type_switch->match(obj1));
   3913     CHECK_EQ(0, type_switch->match(obj0));
   3914   }
   3915 }
   3916 
   3917 
   3918 // For use within the TestSecurityHandler() test.
   3919 static bool g_security_callback_result = false;
   3920 static bool NamedSecurityTestCallback(Local<v8::Object> global,
   3921                                       Local<Value> name,
   3922                                       v8::AccessType type,
   3923                                       Local<Value> data) {
   3924   // Always allow read access.
   3925   if (type == v8::ACCESS_GET)
   3926     return true;
   3927 
   3928   // Sometimes allow other access.
   3929   return g_security_callback_result;
   3930 }
   3931 
   3932 
   3933 static bool IndexedSecurityTestCallback(Local<v8::Object> global,
   3934                                         uint32_t key,
   3935                                         v8::AccessType type,
   3936                                         Local<Value> data) {
   3937   // Always allow read access.
   3938   if (type == v8::ACCESS_GET)
   3939     return true;
   3940 
   3941   // Sometimes allow other access.
   3942   return g_security_callback_result;
   3943 }
   3944 
   3945 
   3946 static int trouble_nesting = 0;
   3947 static v8::Handle<Value> TroubleCallback(const v8::Arguments& args) {
   3948   ApiTestFuzzer::Fuzz();
   3949   trouble_nesting++;
   3950 
   3951   // Call a JS function that throws an uncaught exception.
   3952   Local<v8::Object> arg_this = Context::GetCurrent()->Global();
   3953   Local<Value> trouble_callee = (trouble_nesting == 3) ?
   3954     arg_this->Get(v8_str("trouble_callee")) :
   3955     arg_this->Get(v8_str("trouble_caller"));
   3956   CHECK(trouble_callee->IsFunction());
   3957   return Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL);
   3958 }
   3959 
   3960 
   3961 static int report_count = 0;
   3962 static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
   3963                                              v8::Handle<Value>) {
   3964   report_count++;
   3965 }
   3966 
   3967 
   3968 // Counts uncaught exceptions, but other tests running in parallel
   3969 // also have uncaught exceptions.
   3970 TEST(ApiUncaughtException) {
   3971   report_count = 0;
   3972   v8::HandleScope scope;
   3973   LocalContext env;
   3974   v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
   3975 
   3976   Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
   3977   v8::Local<v8::Object> global = env->Global();
   3978   global->Set(v8_str("trouble"), fun->GetFunction());
   3979 
   3980   Script::Compile(v8_str("function trouble_callee() {"
   3981                          "  var x = null;"
   3982                          "  return x.foo;"
   3983                          "};"
   3984                          "function trouble_caller() {"
   3985                          "  trouble();"
   3986                          "};"))->Run();
   3987   Local<Value> trouble = global->Get(v8_str("trouble"));
   3988   CHECK(trouble->IsFunction());
   3989   Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
   3990   CHECK(trouble_callee->IsFunction());
   3991   Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
   3992   CHECK(trouble_caller->IsFunction());
   3993   Function::Cast(*trouble_caller)->Call(global, 0, NULL);
   3994   CHECK_EQ(1, report_count);
   3995   v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
   3996 }
   3997 
   3998 static const char* script_resource_name = "ExceptionInNativeScript.js";
   3999 static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
   4000                                                 v8::Handle<Value>) {
   4001   v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
   4002   CHECK(!name_val.IsEmpty() && name_val->IsString());
   4003   v8::String::AsciiValue name(message->GetScriptResourceName());
   4004   CHECK_EQ(script_resource_name, *name);
   4005   CHECK_EQ(3, message->GetLineNumber());
   4006   v8::String::AsciiValue source_line(message->GetSourceLine());
   4007   CHECK_EQ("  new o.foo();", *source_line);
   4008 }
   4009 
   4010 TEST(ExceptionInNativeScript) {
   4011   v8::HandleScope scope;
   4012   LocalContext env;
   4013   v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
   4014 
   4015   Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
   4016   v8::Local<v8::Object> global = env->Global();
   4017   global->Set(v8_str("trouble"), fun->GetFunction());
   4018 
   4019   Script::Compile(v8_str("function trouble() {\n"
   4020                          "  var o = {};\n"
   4021                          "  new o.foo();\n"
   4022                          "};"), v8::String::New(script_resource_name))->Run();
   4023   Local<Value> trouble = global->Get(v8_str("trouble"));
   4024   CHECK(trouble->IsFunction());
   4025   Function::Cast(*trouble)->Call(global, 0, NULL);
   4026   v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
   4027 }
   4028 
   4029 
   4030 TEST(CompilationErrorUsingTryCatchHandler) {
   4031   v8::HandleScope scope;
   4032   LocalContext env;
   4033   v8::TryCatch try_catch;
   4034   Script::Compile(v8_str("This doesn't &*&@#$&*^ compile."));
   4035   CHECK_NE(NULL, *try_catch.Exception());
   4036   CHECK(try_catch.HasCaught());
   4037 }
   4038 
   4039 
   4040 TEST(TryCatchFinallyUsingTryCatchHandler) {
   4041   v8::HandleScope scope;
   4042   LocalContext env;
   4043   v8::TryCatch try_catch;
   4044   Script::Compile(v8_str("try { throw ''; } catch (e) {}"))->Run();
   4045   CHECK(!try_catch.HasCaught());
   4046   Script::Compile(v8_str("try { throw ''; } finally {}"))->Run();
   4047   CHECK(try_catch.HasCaught());
   4048   try_catch.Reset();
   4049   Script::Compile(v8_str("(function() {"
   4050                          "try { throw ''; } finally { return; }"
   4051                          "})()"))->Run();
   4052   CHECK(!try_catch.HasCaught());
   4053   Script::Compile(v8_str("(function()"
   4054                          "  { try { throw ''; } finally { throw 0; }"
   4055                          "})()"))->Run();
   4056   CHECK(try_catch.HasCaught());
   4057 }
   4058 
   4059 
   4060 // SecurityHandler can't be run twice
   4061 TEST(SecurityHandler) {
   4062   v8::HandleScope scope0;
   4063   v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
   4064   global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
   4065                                            IndexedSecurityTestCallback);
   4066   // Create an environment
   4067   v8::Persistent<Context> context0 =
   4068     Context::New(NULL, global_template);
   4069   context0->Enter();
   4070 
   4071   v8::Handle<v8::Object> global0 = context0->Global();
   4072   v8::Handle<Script> script0 = v8_compile("foo = 111");
   4073   script0->Run();
   4074   global0->Set(v8_str("0"), v8_num(999));
   4075   v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
   4076   CHECK_EQ(111, foo0->Int32Value());
   4077   v8::Handle<Value> z0 = global0->Get(v8_str("0"));
   4078   CHECK_EQ(999, z0->Int32Value());
   4079 
   4080   // Create another environment, should fail security checks.
   4081   v8::HandleScope scope1;
   4082 
   4083   v8::Persistent<Context> context1 =
   4084     Context::New(NULL, global_template);
   4085   context1->Enter();
   4086 
   4087   v8::Handle<v8::Object> global1 = context1->Global();
   4088   global1->Set(v8_str("othercontext"), global0);
   4089   // This set will fail the security check.
   4090   v8::Handle<Script> script1 =
   4091     v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
   4092   script1->Run();
   4093   // This read will pass the security check.
   4094   v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
   4095   CHECK_EQ(111, foo1->Int32Value());
   4096   // This read will pass the security check.
   4097   v8::Handle<Value> z1 = global0->Get(v8_str("0"));
   4098   CHECK_EQ(999, z1->Int32Value());
   4099 
   4100   // Create another environment, should pass security checks.
   4101   { g_security_callback_result = true;  // allow security handler to pass.
   4102     v8::HandleScope scope2;
   4103     LocalContext context2;
   4104     v8::Handle<v8::Object> global2 = context2->Global();
   4105     global2->Set(v8_str("othercontext"), global0);
   4106     v8::Handle<Script> script2 =
   4107         v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
   4108     script2->Run();
   4109     v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
   4110     CHECK_EQ(333, foo2->Int32Value());
   4111     v8::Handle<Value> z2 = global0->Get(v8_str("0"));
   4112     CHECK_EQ(888, z2->Int32Value());
   4113   }
   4114 
   4115   context1->Exit();
   4116   context1.Dispose();
   4117 
   4118   context0->Exit();
   4119   context0.Dispose();
   4120 }
   4121 
   4122 
   4123 THREADED_TEST(SecurityChecks) {
   4124   v8::HandleScope handle_scope;
   4125   LocalContext env1;
   4126   v8::Persistent<Context> env2 = Context::New();
   4127 
   4128   Local<Value> foo = v8_str("foo");
   4129   Local<Value> bar = v8_str("bar");
   4130 
   4131   // Set to the same domain.
   4132   env1->SetSecurityToken(foo);
   4133 
   4134   // Create a function in env1.
   4135   Script::Compile(v8_str("spy=function(){return spy;}"))->Run();
   4136   Local<Value> spy = env1->Global()->Get(v8_str("spy"));
   4137   CHECK(spy->IsFunction());
   4138 
   4139   // Create another function accessing global objects.
   4140   Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run();
   4141   Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
   4142   CHECK(spy2->IsFunction());
   4143 
   4144   // Switch to env2 in the same domain and invoke spy on env2.
   4145   {
   4146     env2->SetSecurityToken(foo);
   4147     // Enter env2
   4148     Context::Scope scope_env2(env2);
   4149     Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
   4150     CHECK(result->IsFunction());
   4151   }
   4152 
   4153   {
   4154     env2->SetSecurityToken(bar);
   4155     Context::Scope scope_env2(env2);
   4156 
   4157     // Call cross_domain_call, it should throw an exception
   4158     v8::TryCatch try_catch;
   4159     Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
   4160     CHECK(try_catch.HasCaught());
   4161   }
   4162 
   4163   env2.Dispose();
   4164 }
   4165 
   4166 
   4167 // Regression test case for issue 1183439.
   4168 THREADED_TEST(SecurityChecksForPrototypeChain) {
   4169   v8::HandleScope scope;
   4170   LocalContext current;
   4171   v8::Persistent<Context> other = Context::New();
   4172 
   4173   // Change context to be able to get to the Object function in the
   4174   // other context without hitting the security checks.
   4175   v8::Local<Value> other_object;
   4176   { Context::Scope scope(other);
   4177     other_object = other->Global()->Get(v8_str("Object"));
   4178     other->Global()->Set(v8_num(42), v8_num(87));
   4179   }
   4180 
   4181   current->Global()->Set(v8_str("other"), other->Global());
   4182   CHECK(v8_compile("other")->Run()->Equals(other->Global()));
   4183 
   4184   // Make sure the security check fails here and we get an undefined
   4185   // result instead of getting the Object function. Repeat in a loop
   4186   // to make sure to exercise the IC code.
   4187   v8::Local<Script> access_other0 = v8_compile("other.Object");
   4188   v8::Local<Script> access_other1 = v8_compile("other[42]");
   4189   for (int i = 0; i < 5; i++) {
   4190     CHECK(!access_other0->Run()->Equals(other_object));
   4191     CHECK(access_other0->Run()->IsUndefined());
   4192     CHECK(!access_other1->Run()->Equals(v8_num(87)));
   4193     CHECK(access_other1->Run()->IsUndefined());
   4194   }
   4195 
   4196   // Create an object that has 'other' in its prototype chain and make
   4197   // sure we cannot access the Object function indirectly through
   4198   // that. Repeat in a loop to make sure to exercise the IC code.
   4199   v8_compile("function F() { };"
   4200              "F.prototype = other;"
   4201              "var f = new F();")->Run();
   4202   v8::Local<Script> access_f0 = v8_compile("f.Object");
   4203   v8::Local<Script> access_f1 = v8_compile("f[42]");
   4204   for (int j = 0; j < 5; j++) {
   4205     CHECK(!access_f0->Run()->Equals(other_object));
   4206     CHECK(access_f0->Run()->IsUndefined());
   4207     CHECK(!access_f1->Run()->Equals(v8_num(87)));
   4208     CHECK(access_f1->Run()->IsUndefined());
   4209   }
   4210 
   4211   // Now it gets hairy: Set the prototype for the other global object
   4212   // to be the current global object. The prototype chain for 'f' now
   4213   // goes through 'other' but ends up in the current global object.
   4214   { Context::Scope scope(other);
   4215     other->Global()->Set(v8_str("__proto__"), current->Global());
   4216   }
   4217   // Set a named and an index property on the current global
   4218   // object. To force the lookup to go through the other global object,
   4219   // the properties must not exist in the other global object.
   4220   current->Global()->Set(v8_str("foo"), v8_num(100));
   4221   current->Global()->Set(v8_num(99), v8_num(101));
   4222   // Try to read the properties from f and make sure that the access
   4223   // gets stopped by the security checks on the other global object.
   4224   Local<Script> access_f2 = v8_compile("f.foo");
   4225   Local<Script> access_f3 = v8_compile("f[99]");
   4226   for (int k = 0; k < 5; k++) {
   4227     CHECK(!access_f2->Run()->Equals(v8_num(100)));
   4228     CHECK(access_f2->Run()->IsUndefined());
   4229     CHECK(!access_f3->Run()->Equals(v8_num(101)));
   4230     CHECK(access_f3->Run()->IsUndefined());
   4231   }
   4232   other.Dispose();
   4233 }
   4234 
   4235 
   4236 THREADED_TEST(CrossDomainDelete) {
   4237   v8::HandleScope handle_scope;
   4238   LocalContext env1;
   4239   v8::Persistent<Context> env2 = Context::New();
   4240 
   4241   Local<Value> foo = v8_str("foo");
   4242   Local<Value> bar = v8_str("bar");
   4243 
   4244   // Set to the same domain.
   4245   env1->SetSecurityToken(foo);
   4246   env2->SetSecurityToken(foo);
   4247 
   4248   env1->Global()->Set(v8_str("prop"), v8_num(3));
   4249   env2->Global()->Set(v8_str("env1"), env1->Global());
   4250 
   4251   // Change env2 to a different domain and delete env1.prop.
   4252   env2->SetSecurityToken(bar);
   4253   {
   4254     Context::Scope scope_env2(env2);
   4255     Local<Value> result =
   4256         Script::Compile(v8_str("delete env1.prop"))->Run();
   4257     CHECK(result->IsFalse());
   4258   }
   4259 
   4260   // Check that env1.prop still exists.
   4261   Local<Value> v = env1->Global()->Get(v8_str("prop"));
   4262   CHECK(v->IsNumber());
   4263   CHECK_EQ(3, v->Int32Value());
   4264 
   4265   env2.Dispose();
   4266 }
   4267 
   4268 
   4269 THREADED_TEST(CrossDomainIsPropertyEnumerable) {
   4270   v8::HandleScope handle_scope;
   4271   LocalContext env1;
   4272   v8::Persistent<Context> env2 = Context::New();
   4273 
   4274   Local<Value> foo = v8_str("foo");
   4275   Local<Value> bar = v8_str("bar");
   4276 
   4277   // Set to the same domain.
   4278   env1->SetSecurityToken(foo);
   4279   env2->SetSecurityToken(foo);
   4280 
   4281   env1->Global()->Set(v8_str("prop"), v8_num(3));
   4282   env2->Global()->Set(v8_str("env1"), env1->Global());
   4283 
   4284   // env1.prop is enumerable in env2.
   4285   Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
   4286   {
   4287     Context::Scope scope_env2(env2);
   4288     Local<Value> result = Script::Compile(test)->Run();
   4289     CHECK(result->IsTrue());
   4290   }
   4291 
   4292   // Change env2 to a different domain and test again.
   4293   env2->SetSecurityToken(bar);
   4294   {
   4295     Context::Scope scope_env2(env2);
   4296     Local<Value> result = Script::Compile(test)->Run();
   4297     CHECK(result->IsFalse());
   4298   }
   4299 
   4300   env2.Dispose();
   4301 }
   4302 
   4303 
   4304 THREADED_TEST(CrossDomainForIn) {
   4305   v8::HandleScope handle_scope;
   4306   LocalContext env1;
   4307   v8::Persistent<Context> env2 = Context::New();
   4308 
   4309   Local<Value> foo = v8_str("foo");
   4310   Local<Value> bar = v8_str("bar");
   4311 
   4312   // Set to the same domain.
   4313   env1->SetSecurityToken(foo);
   4314   env2->SetSecurityToken(foo);
   4315 
   4316   env1->Global()->Set(v8_str("prop"), v8_num(3));
   4317   env2->Global()->Set(v8_str("env1"), env1->Global());
   4318 
   4319   // Change env2 to a different domain and set env1's global object
   4320   // as the __proto__ of an object in env2 and enumerate properties
   4321   // in for-in. It shouldn't enumerate properties on env1's global
   4322   // object.
   4323   env2->SetSecurityToken(bar);
   4324   {
   4325     Context::Scope scope_env2(env2);
   4326     Local<Value> result =
   4327         CompileRun("(function(){var obj = {'__proto__':env1};"
   4328                    "for (var p in obj)"
   4329                    "   if (p == 'prop') return false;"
   4330                    "return true;})()");
   4331     CHECK(result->IsTrue());
   4332   }
   4333   env2.Dispose();
   4334 }
   4335 
   4336 
   4337 TEST(ContextDetachGlobal) {
   4338   v8::HandleScope handle_scope;
   4339   LocalContext env1;
   4340   v8::Persistent<Context> env2 = Context::New();
   4341 
   4342   Local<v8::Object> global1 = env1->Global();
   4343 
   4344   Local<Value> foo = v8_str("foo");
   4345 
   4346   // Set to the same domain.
   4347   env1->SetSecurityToken(foo);
   4348   env2->SetSecurityToken(foo);
   4349 
   4350   // Enter env2
   4351   env2->Enter();
   4352 
   4353   // Create a function in env2 and add a reference to it in env1.
   4354   Local<v8::Object> global2 = env2->Global();
   4355   global2->Set(v8_str("prop"), v8::Integer::New(1));
   4356   CompileRun("function getProp() {return prop;}");
   4357 
   4358   env1->Global()->Set(v8_str("getProp"),
   4359                       global2->Get(v8_str("getProp")));
   4360 
   4361   // Detach env2's global, and reuse the global object of env2
   4362   env2->Exit();
   4363   env2->DetachGlobal();
   4364   // env2 has a new global object.
   4365   CHECK(!env2->Global()->Equals(global2));
   4366 
   4367   v8::Persistent<Context> env3 =
   4368       Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
   4369   env3->SetSecurityToken(v8_str("bar"));
   4370   env3->Enter();
   4371 
   4372   Local<v8::Object> global3 = env3->Global();
   4373   CHECK_EQ(global2, global3);
   4374   CHECK(global3->Get(v8_str("prop"))->IsUndefined());
   4375   CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
   4376   global3->Set(v8_str("prop"), v8::Integer::New(-1));
   4377   global3->Set(v8_str("prop2"), v8::Integer::New(2));
   4378   env3->Exit();
   4379 
   4380   // Call getProp in env1, and it should return the value 1
   4381   {
   4382     Local<Value> get_prop = global1->Get(v8_str("getProp"));
   4383     CHECK(get_prop->IsFunction());
   4384     v8::TryCatch try_catch;
   4385     Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
   4386     CHECK(!try_catch.HasCaught());
   4387     CHECK_EQ(1, r->Int32Value());
   4388   }
   4389 
   4390   // Check that env3 is not accessible from env1
   4391   {
   4392     Local<Value> r = global3->Get(v8_str("prop2"));
   4393     CHECK(r->IsUndefined());
   4394   }
   4395 
   4396   env2.Dispose();
   4397   env3.Dispose();
   4398 }
   4399 
   4400 
   4401 TEST(DetachAndReattachGlobal) {
   4402   v8::HandleScope scope;
   4403   LocalContext env1;
   4404 
   4405   // Create second environment.
   4406   v8::Persistent<Context> env2 = Context::New();
   4407 
   4408   Local<Value> foo = v8_str("foo");
   4409 
   4410   // Set same security token for env1 and env2.
   4411   env1->SetSecurityToken(foo);
   4412   env2->SetSecurityToken(foo);
   4413 
   4414   // Create a property on the global object in env2.
   4415   {
   4416     v8::Context::Scope scope(env2);
   4417     env2->Global()->Set(v8_str("p"), v8::Integer::New(42));
   4418   }
   4419 
   4420   // Create a reference to env2 global from env1 global.
   4421   env1->Global()->Set(v8_str("other"), env2->Global());
   4422 
   4423   // Check that we have access to other.p in env2 from env1.
   4424   Local<Value> result = CompileRun("other.p");
   4425   CHECK(result->IsInt32());
   4426   CHECK_EQ(42, result->Int32Value());
   4427 
   4428   // Hold on to global from env2 and detach global from env2.
   4429   Local<v8::Object> global2 = env2->Global();
   4430   env2->DetachGlobal();
   4431 
   4432   // Check that the global has been detached. No other.p property can
   4433   // be found.
   4434   result = CompileRun("other.p");
   4435   CHECK(result->IsUndefined());
   4436 
   4437   // Reuse global2 for env3.
   4438   v8::Persistent<Context> env3 =
   4439       Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
   4440   CHECK_EQ(global2, env3->Global());
   4441 
   4442   // Start by using the same security token for env3 as for env1 and env2.
   4443   env3->SetSecurityToken(foo);
   4444 
   4445   // Create a property on the global object in env3.
   4446   {
   4447     v8::Context::Scope scope(env3);
   4448     env3->Global()->Set(v8_str("p"), v8::Integer::New(24));
   4449   }
   4450 
   4451   // Check that other.p is now the property in env3 and that we have access.
   4452   result = CompileRun("other.p");
   4453   CHECK(result->IsInt32());
   4454   CHECK_EQ(24, result->Int32Value());
   4455 
   4456   // Change security token for env3 to something different from env1 and env2.
   4457   env3->SetSecurityToken(v8_str("bar"));
   4458 
   4459   // Check that we do not have access to other.p in env1. |other| is now
   4460   // the global object for env3 which has a different security token,
   4461   // so access should be blocked.
   4462   result = CompileRun("other.p");
   4463   CHECK(result->IsUndefined());
   4464 
   4465   // Detach the global for env3 and reattach it to env2.
   4466   env3->DetachGlobal();
   4467   env2->ReattachGlobal(global2);
   4468 
   4469   // Check that we have access to other.p again in env1.  |other| is now
   4470   // the global object for env2 which has the same security token as env1.
   4471   result = CompileRun("other.p");
   4472   CHECK(result->IsInt32());
   4473   CHECK_EQ(42, result->Int32Value());
   4474 
   4475   env2.Dispose();
   4476   env3.Dispose();
   4477 }
   4478 
   4479 
   4480 static bool NamedAccessBlocker(Local<v8::Object> global,
   4481                                Local<Value> name,
   4482                                v8::AccessType type,
   4483                                Local<Value> data) {
   4484   return Context::GetCurrent()->Global()->Equals(global);
   4485 }
   4486 
   4487 
   4488 static bool IndexedAccessBlocker(Local<v8::Object> global,
   4489                                  uint32_t key,
   4490                                  v8::AccessType type,
   4491                                  Local<Value> data) {
   4492   return Context::GetCurrent()->Global()->Equals(global);
   4493 }
   4494 
   4495 
   4496 static int g_echo_value = -1;
   4497 static v8::Handle<Value> EchoGetter(Local<String> name,
   4498                                     const AccessorInfo& info) {
   4499   return v8_num(g_echo_value);
   4500 }
   4501 
   4502 
   4503 static void EchoSetter(Local<String> name,
   4504                        Local<Value> value,
   4505                        const AccessorInfo&) {
   4506   if (value->IsNumber())
   4507     g_echo_value = value->Int32Value();
   4508 }
   4509 
   4510 
   4511 static v8::Handle<Value> UnreachableGetter(Local<String> name,
   4512                                            const AccessorInfo& info) {
   4513   CHECK(false);  // This function should not be called..
   4514   return v8::Undefined();
   4515 }
   4516 
   4517 
   4518 static void UnreachableSetter(Local<String>, Local<Value>,
   4519                               const AccessorInfo&) {
   4520   CHECK(false);  // This function should nto be called.
   4521 }
   4522 
   4523 
   4524 THREADED_TEST(AccessControl) {
   4525   v8::HandleScope handle_scope;
   4526   v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
   4527 
   4528   global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
   4529                                            IndexedAccessBlocker);
   4530 
   4531   // Add an accessor accessible by cross-domain JS code.
   4532   global_template->SetAccessor(
   4533       v8_str("accessible_prop"),
   4534       EchoGetter, EchoSetter,
   4535       v8::Handle<Value>(),
   4536       v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
   4537 
   4538   // Add an accessor that is not accessible by cross-domain JS code.
   4539   global_template->SetAccessor(v8_str("blocked_prop"),
   4540                                UnreachableGetter, UnreachableSetter,
   4541                                v8::Handle<Value>(),
   4542                                v8::DEFAULT);
   4543 
   4544   // Create an environment
   4545   v8::Persistent<Context> context0 = Context::New(NULL, global_template);
   4546   context0->Enter();
   4547 
   4548   v8::Handle<v8::Object> global0 = context0->Global();
   4549 
   4550   v8::HandleScope scope1;
   4551 
   4552   v8::Persistent<Context> context1 = Context::New();
   4553   context1->Enter();
   4554 
   4555   v8::Handle<v8::Object> global1 = context1->Global();
   4556   global1->Set(v8_str("other"), global0);
   4557 
   4558   v8::Handle<Value> value;
   4559 
   4560   // Access blocked property
   4561   value = v8_compile("other.blocked_prop = 1")->Run();
   4562   value = v8_compile("other.blocked_prop")->Run();
   4563   CHECK(value->IsUndefined());
   4564 
   4565   value = v8_compile("propertyIsEnumerable.call(other, 'blocked_prop')")->Run();
   4566   CHECK(value->IsFalse());
   4567 
   4568   // Access accessible property
   4569   value = v8_compile("other.accessible_prop = 3")->Run();
   4570   CHECK(value->IsNumber());
   4571   CHECK_EQ(3, value->Int32Value());
   4572   CHECK_EQ(3, g_echo_value);
   4573 
   4574   value = v8_compile("other.accessible_prop")->Run();
   4575   CHECK(value->IsNumber());
   4576   CHECK_EQ(3, value->Int32Value());
   4577 
   4578   value =
   4579     v8_compile("propertyIsEnumerable.call(other, 'accessible_prop')")->Run();
   4580   CHECK(value->IsTrue());
   4581 
   4582   // Enumeration doesn't enumerate accessors from inaccessible objects in
   4583   // the prototype chain even if the accessors are in themselves accessible.
   4584   Local<Value> result =
   4585       CompileRun("(function(){var obj = {'__proto__':other};"
   4586                  "for (var p in obj)"
   4587                  "   if (p == 'accessible_prop' || p == 'blocked_prop') {"
   4588                  "     return false;"
   4589                  "   }"
   4590                  "return true;})()");
   4591   CHECK(result->IsTrue());
   4592 
   4593   context1->Exit();
   4594   context0->Exit();
   4595   context1.Dispose();
   4596   context0.Dispose();
   4597 }
   4598 
   4599 
   4600 static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
   4601                                             Local<Value> name,
   4602                                             v8::AccessType type,
   4603                                             Local<Value> data) {
   4604   return false;
   4605 }
   4606 
   4607 
   4608 static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
   4609                                               uint32_t key,
   4610                                               v8::AccessType type,
   4611                                               Local<Value> data) {
   4612   return false;
   4613 }
   4614 
   4615 
   4616 THREADED_TEST(AccessControlGetOwnPropertyNames) {
   4617   v8::HandleScope handle_scope;
   4618   v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
   4619 
   4620   obj_template->Set(v8_str("x"), v8::Integer::New(42));
   4621   obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
   4622                                         GetOwnPropertyNamesIndexedBlocker);
   4623 
   4624   // Create an environment
   4625   v8::Persistent<Context> context0 = Context::New(NULL, obj_template);
   4626   context0->Enter();
   4627 
   4628   v8::Handle<v8::Object> global0 = context0->Global();
   4629 
   4630   v8::HandleScope scope1;
   4631 
   4632   v8::Persistent<Context> context1 = Context::New();
   4633   context1->Enter();
   4634 
   4635   v8::Handle<v8::Object> global1 = context1->Global();
   4636   global1->Set(v8_str("other"), global0);
   4637   global1->Set(v8_str("object"), obj_template->NewInstance());
   4638 
   4639   v8::Handle<Value> value;
   4640 
   4641   // Attempt to get the property names of the other global object and
   4642   // of an object that requires access checks.  Accessing the other
   4643   // global object should be blocked by access checks on the global
   4644   // proxy object.  Accessing the object that requires access checks
   4645   // is blocked by the access checks on the object itself.
   4646   value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
   4647   CHECK(value->IsTrue());
   4648 
   4649   value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
   4650   CHECK(value->IsTrue());
   4651 
   4652   context1->Exit();
   4653   context0->Exit();
   4654   context1.Dispose();
   4655   context0.Dispose();
   4656 }
   4657 
   4658 
   4659 static v8::Handle<Value> ConstTenGetter(Local<String> name,
   4660                                         const AccessorInfo& info) {
   4661   return v8_num(10);
   4662 }
   4663 
   4664 
   4665 THREADED_TEST(CrossDomainAccessors) {
   4666   v8::HandleScope handle_scope;
   4667 
   4668   v8::Handle<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
   4669 
   4670   v8::Handle<v8::ObjectTemplate> global_template =
   4671       func_template->InstanceTemplate();
   4672 
   4673   v8::Handle<v8::ObjectTemplate> proto_template =
   4674       func_template->PrototypeTemplate();
   4675 
   4676   // Add an accessor to proto that's accessible by cross-domain JS code.
   4677   proto_template->SetAccessor(v8_str("accessible"),
   4678                               ConstTenGetter, 0,
   4679                               v8::Handle<Value>(),
   4680                               v8::ALL_CAN_READ);
   4681 
   4682   // Add an accessor that is not accessible by cross-domain JS code.
   4683   global_template->SetAccessor(v8_str("unreachable"),
   4684                                UnreachableGetter, 0,
   4685                                v8::Handle<Value>(),
   4686                                v8::DEFAULT);
   4687 
   4688   v8::Persistent<Context> context0 = Context::New(NULL, global_template);
   4689   context0->Enter();
   4690 
   4691   Local<v8::Object> global = context0->Global();
   4692   // Add a normal property that shadows 'accessible'
   4693   global->Set(v8_str("accessible"), v8_num(11));
   4694 
   4695   // Enter a new context.
   4696   v8::HandleScope scope1;
   4697   v8::Persistent<Context> context1 = Context::New();
   4698   context1->Enter();
   4699 
   4700   v8::Handle<v8::Object> global1 = context1->Global();
   4701   global1->Set(v8_str("other"), global);
   4702 
   4703   // Should return 10, instead of 11
   4704   v8::Handle<Value> value = v8_compile("other.accessible")->Run();
   4705   CHECK(value->IsNumber());
   4706   CHECK_EQ(10, value->Int32Value());
   4707 
   4708   value = v8_compile("other.unreachable")->Run();
   4709   CHECK(value->IsUndefined());
   4710 
   4711   context1->Exit();
   4712   context0->Exit();
   4713   context1.Dispose();
   4714   context0.Dispose();
   4715 }
   4716 
   4717 
   4718 static int named_access_count = 0;
   4719 static int indexed_access_count = 0;
   4720 
   4721 static bool NamedAccessCounter(Local<v8::Object> global,
   4722                                Local<Value> name,
   4723                                v8::AccessType type,
   4724                                Local<Value> data) {
   4725   named_access_count++;
   4726   return true;
   4727 }
   4728 
   4729 
   4730 static bool IndexedAccessCounter(Local<v8::Object> global,
   4731                                  uint32_t key,
   4732                                  v8::AccessType type,
   4733                                  Local<Value> data) {
   4734   indexed_access_count++;
   4735   return true;
   4736 }
   4737 
   4738 
   4739 // This one is too easily disturbed by other tests.
   4740 TEST(AccessControlIC) {
   4741   named_access_count = 0;
   4742   indexed_access_count = 0;
   4743 
   4744   v8::HandleScope handle_scope;
   4745 
   4746   // Create an environment.
   4747   v8::Persistent<Context> context0 = Context::New();
   4748   context0->Enter();
   4749 
   4750   // Create an object that requires access-check functions to be
   4751   // called for cross-domain access.
   4752   v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
   4753   object_template->SetAccessCheckCallbacks(NamedAccessCounter,
   4754                                            IndexedAccessCounter);
   4755   Local<v8::Object> object = object_template->NewInstance();
   4756 
   4757   v8::HandleScope scope1;
   4758 
   4759   // Create another environment.
   4760   v8::Persistent<Context> context1 = Context::New();
   4761   context1->Enter();
   4762 
   4763   // Make easy access to the object from the other environment.
   4764   v8::Handle<v8::Object> global1 = context1->Global();
   4765   global1->Set(v8_str("obj"), object);
   4766 
   4767   v8::Handle<Value> value;
   4768 
   4769   // Check that the named access-control function is called every time.
   4770   CompileRun("function testProp(obj) {"
   4771              "  for (var i = 0; i < 10; i++) obj.prop = 1;"
   4772              "  for (var j = 0; j < 10; j++) obj.prop;"
   4773              "  return obj.prop"
   4774              "}");
   4775   value = CompileRun("testProp(obj)");
   4776   CHECK(value->IsNumber());
   4777   CHECK_EQ(1, value->Int32Value());
   4778   CHECK_EQ(21, named_access_count);
   4779 
   4780   // Check that the named access-control function is called every time.
   4781   CompileRun("var p = 'prop';"
   4782              "function testKeyed(obj) {"
   4783              "  for (var i = 0; i < 10; i++) obj[p] = 1;"
   4784              "  for (var j = 0; j < 10; j++) obj[p];"
   4785              "  return obj[p];"
   4786              "}");
   4787   // Use obj which requires access checks.  No inline caching is used
   4788   // in that case.
   4789   value = CompileRun("testKeyed(obj)");
   4790   CHECK(value->IsNumber());
   4791   CHECK_EQ(1, value->Int32Value());
   4792   CHECK_EQ(42, named_access_count);
   4793   // Force the inline caches into generic state and try again.
   4794   CompileRun("testKeyed({ a: 0 })");
   4795   CompileRun("testKeyed({ b: 0 })");
   4796   value = CompileRun("testKeyed(obj)");
   4797   CHECK(value->IsNumber());
   4798   CHECK_EQ(1, value->Int32Value());
   4799   CHECK_EQ(63, named_access_count);
   4800 
   4801   // Check that the indexed access-control function is called every time.
   4802   CompileRun("function testIndexed(obj) {"
   4803              "  for (var i = 0; i < 10; i++) obj[0] = 1;"
   4804              "  for (var j = 0; j < 10; j++) obj[0];"
   4805              "  return obj[0]"
   4806              "}");
   4807   value = CompileRun("testIndexed(obj)");
   4808   CHECK(value->IsNumber());
   4809   CHECK_EQ(1, value->Int32Value());
   4810   CHECK_EQ(21, indexed_access_count);
   4811   // Force the inline caches into generic state.
   4812   CompileRun("testIndexed(new Array(1))");
   4813   // Test that the indexed access check is called.
   4814   value = CompileRun("testIndexed(obj)");
   4815   CHECK(value->IsNumber());
   4816   CHECK_EQ(1, value->Int32Value());
   4817   CHECK_EQ(42, indexed_access_count);
   4818 
   4819   // Check that the named access check is called when invoking
   4820   // functions on an object that requires access checks.
   4821   CompileRun("obj.f = function() {}");
   4822   CompileRun("function testCallNormal(obj) {"
   4823              "  for (var i = 0; i < 10; i++) obj.f();"
   4824              "}");
   4825   CompileRun("testCallNormal(obj)");
   4826   CHECK_EQ(74, named_access_count);
   4827 
   4828   // Force obj into slow case.
   4829   value = CompileRun("delete obj.prop");
   4830   CHECK(value->BooleanValue());
   4831   // Force inline caches into dictionary probing mode.
   4832   CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
   4833   // Test that the named access check is called.
   4834   value = CompileRun("testProp(obj);");
   4835   CHECK(value->IsNumber());
   4836   CHECK_EQ(1, value->Int32Value());
   4837   CHECK_EQ(96, named_access_count);
   4838 
   4839   // Force the call inline cache into dictionary probing mode.
   4840   CompileRun("o.f = function() {}; testCallNormal(o)");
   4841   // Test that the named access check is still called for each
   4842   // invocation of the function.
   4843   value = CompileRun("testCallNormal(obj)");
   4844   CHECK_EQ(106, named_access_count);
   4845 
   4846   context1->Exit();
   4847   context0->Exit();
   4848   context1.Dispose();
   4849   context0.Dispose();
   4850 }
   4851 
   4852 
   4853 static bool NamedAccessFlatten(Local<v8::Object> global,
   4854                                Local<Value> name,
   4855                                v8::AccessType type,
   4856                                Local<Value> data) {
   4857   char buf[100];
   4858   int len;
   4859 
   4860   CHECK(name->IsString());
   4861 
   4862   memset(buf, 0x1, sizeof(buf));
   4863   len = Local<String>::Cast(name)->WriteAscii(buf);
   4864   CHECK_EQ(4, len);
   4865 
   4866   uint16_t buf2[100];
   4867 
   4868   memset(buf, 0x1, sizeof(buf));
   4869   len = Local<String>::Cast(name)->Write(buf2);
   4870   CHECK_EQ(4, len);
   4871 
   4872   return true;
   4873 }
   4874 
   4875 
   4876 static bool IndexedAccessFlatten(Local<v8::Object> global,
   4877                                  uint32_t key,
   4878                                  v8::AccessType type,
   4879                                  Local<Value> data) {
   4880   return true;
   4881 }
   4882 
   4883 
   4884 // Regression test.  In access checks, operations that may cause
   4885 // garbage collection are not allowed.  It used to be the case that
   4886 // using the Write operation on a string could cause a garbage
   4887 // collection due to flattening of the string.  This is no longer the
   4888 // case.
   4889 THREADED_TEST(AccessControlFlatten) {
   4890   named_access_count = 0;
   4891   indexed_access_count = 0;
   4892 
   4893   v8::HandleScope handle_scope;
   4894 
   4895   // Create an environment.
   4896   v8::Persistent<Context> context0 = Context::New();
   4897   context0->Enter();
   4898 
   4899   // Create an object that requires access-check functions to be
   4900   // called for cross-domain access.
   4901   v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
   4902   object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
   4903                                            IndexedAccessFlatten);
   4904   Local<v8::Object> object = object_template->NewInstance();
   4905 
   4906   v8::HandleScope scope1;
   4907 
   4908   // Create another environment.
   4909   v8::Persistent<Context> context1 = Context::New();
   4910   context1->Enter();
   4911 
   4912   // Make easy access to the object from the other environment.
   4913   v8::Handle<v8::Object> global1 = context1->Global();
   4914   global1->Set(v8_str("obj"), object);
   4915 
   4916   v8::Handle<Value> value;
   4917 
   4918   value = v8_compile("var p = 'as' + 'df';")->Run();
   4919   value = v8_compile("obj[p];")->Run();
   4920 
   4921   context1->Exit();
   4922   context0->Exit();
   4923   context1.Dispose();
   4924   context0.Dispose();
   4925 }
   4926 
   4927 
   4928 static v8::Handle<Value> AccessControlNamedGetter(
   4929     Local<String>, const AccessorInfo&) {
   4930   return v8::Integer::New(42);
   4931 }
   4932 
   4933 
   4934 static v8::Handle<Value> AccessControlNamedSetter(
   4935     Local<String>, Local<Value> value, const AccessorInfo&) {
   4936   return value;
   4937 }
   4938 
   4939 
   4940 static v8::Handle<Value> AccessControlIndexedGetter(
   4941       uint32_t index,
   4942       const AccessorInfo& info) {
   4943   return v8_num(42);
   4944 }
   4945 
   4946 
   4947 static v8::Handle<Value> AccessControlIndexedSetter(
   4948     uint32_t, Local<Value> value, const AccessorInfo&) {
   4949   return value;
   4950 }
   4951 
   4952 
   4953 THREADED_TEST(AccessControlInterceptorIC) {
   4954   named_access_count = 0;
   4955   indexed_access_count = 0;
   4956 
   4957   v8::HandleScope handle_scope;
   4958 
   4959   // Create an environment.
   4960   v8::Persistent<Context> context0 = Context::New();
   4961   context0->Enter();
   4962 
   4963   // Create an object that requires access-check functions to be
   4964   // called for cross-domain access.  The object also has interceptors
   4965   // interceptor.
   4966   v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
   4967   object_template->SetAccessCheckCallbacks(NamedAccessCounter,
   4968                                            IndexedAccessCounter);
   4969   object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
   4970                                            AccessControlNamedSetter);
   4971   object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
   4972                                              AccessControlIndexedSetter);
   4973   Local<v8::Object> object = object_template->NewInstance();
   4974 
   4975   v8::HandleScope scope1;
   4976 
   4977   // Create another environment.
   4978   v8::Persistent<Context> context1 = Context::New();
   4979   context1->Enter();
   4980 
   4981   // Make easy access to the object from the other environment.
   4982   v8::Handle<v8::Object> global1 = context1->Global();
   4983   global1->Set(v8_str("obj"), object);
   4984 
   4985   v8::Handle<Value> value;
   4986 
   4987   // Check that the named access-control function is called every time
   4988   // eventhough there is an interceptor on the object.
   4989   value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
   4990   value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
   4991                      "obj.x")->Run();
   4992   CHECK(value->IsNumber());
   4993   CHECK_EQ(42, value->Int32Value());
   4994   CHECK_EQ(21, named_access_count);
   4995 
   4996   value = v8_compile("var p = 'x';")->Run();
   4997   value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
   4998   value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
   4999                      "obj[p]")->Run();
   5000   CHECK(value->IsNumber());
   5001   CHECK_EQ(42, value->Int32Value());
   5002   CHECK_EQ(42, named_access_count);
   5003 
   5004   // Check that the indexed access-control function is called every
   5005   // time eventhough there is an interceptor on the object.
   5006   value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
   5007   value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
   5008                      "obj[0]")->Run();
   5009   CHECK(value->IsNumber());
   5010   CHECK_EQ(42, value->Int32Value());
   5011   CHECK_EQ(21, indexed_access_count);
   5012 
   5013   context1->Exit();
   5014   context0->Exit();
   5015   context1.Dispose();
   5016   context0.Dispose();
   5017 }
   5018 
   5019 
   5020 THREADED_TEST(Version) {
   5021   v8::V8::GetVersion();
   5022 }
   5023 
   5024 
   5025 static v8::Handle<Value> InstanceFunctionCallback(const v8::Arguments& args) {
   5026   ApiTestFuzzer::Fuzz();
   5027   return v8_num(12);
   5028 }
   5029 
   5030 
   5031 THREADED_TEST(InstanceProperties) {
   5032   v8::HandleScope handle_scope;
   5033   LocalContext context;
   5034 
   5035   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
   5036   Local<ObjectTemplate> instance = t->InstanceTemplate();
   5037 
   5038   instance->Set(v8_str("x"), v8_num(42));
   5039   instance->Set(v8_str("f"),
   5040                 v8::FunctionTemplate::New(InstanceFunctionCallback));
   5041 
   5042   Local<Value> o = t->GetFunction()->NewInstance();
   5043 
   5044   context->Global()->Set(v8_str("i"), o);
   5045   Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
   5046   CHECK_EQ(42, value->Int32Value());
   5047 
   5048   value = Script::Compile(v8_str("i.f()"))->Run();
   5049   CHECK_EQ(12, value->Int32Value());
   5050 }
   5051 
   5052 
   5053 static v8::Handle<Value>
   5054 GlobalObjectInstancePropertiesGet(Local<String> key, const AccessorInfo&) {
   5055   ApiTestFuzzer::Fuzz();
   5056   return v8::Handle<Value>();
   5057 }
   5058 
   5059 
   5060 THREADED_TEST(GlobalObjectInstanceProperties) {
   5061   v8::HandleScope handle_scope;
   5062 
   5063   Local<Value> global_object;
   5064 
   5065   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
   5066   t->InstanceTemplate()->SetNamedPropertyHandler(
   5067       GlobalObjectInstancePropertiesGet);
   5068   Local<ObjectTemplate> instance_template = t->InstanceTemplate();
   5069   instance_template->Set(v8_str("x"), v8_num(42));
   5070   instance_template->Set(v8_str("f"),
   5071                          v8::FunctionTemplate::New(InstanceFunctionCallback));
   5072 
   5073   {
   5074     LocalContext env(NULL, instance_template);
   5075     // Hold on to the global object so it can be used again in another
   5076     // environment initialization.
   5077     global_object = env->Global();
   5078 
   5079     Local<Value> value = Script::Compile(v8_str("x"))->Run();
   5080     CHECK_EQ(42, value->Int32Value());
   5081     value = Script::Compile(v8_str("f()"))->Run();
   5082     CHECK_EQ(12, value->Int32Value());
   5083   }
   5084 
   5085   {
   5086     // Create new environment reusing the global object.
   5087     LocalContext env(NULL, instance_template, global_object);
   5088     Local<Value> value = Script::Compile(v8_str("x"))->Run();
   5089     CHECK_EQ(42, value->Int32Value());
   5090     value = Script::Compile(v8_str("f()"))->Run();
   5091     CHECK_EQ(12, value->Int32Value());
   5092   }
   5093 }
   5094 
   5095 
   5096 static v8::Handle<Value> ShadowFunctionCallback(const v8::Arguments& args) {
   5097   ApiTestFuzzer::Fuzz();
   5098   return v8_num(42);
   5099 }
   5100 
   5101 
   5102 static int shadow_y;
   5103 static int shadow_y_setter_call_count;
   5104 static int shadow_y_getter_call_count;
   5105 
   5106 
   5107 static void ShadowYSetter(Local<String>, Local<Value>, const AccessorInfo&) {
   5108   shadow_y_setter_call_count++;
   5109   shadow_y = 42;
   5110 }
   5111 
   5112 
   5113 static v8::Handle<Value> ShadowYGetter(Local<String> name,
   5114                                        const AccessorInfo& info) {
   5115   ApiTestFuzzer::Fuzz();
   5116   shadow_y_getter_call_count++;
   5117   return v8_num(shadow_y);
   5118 }
   5119 
   5120 
   5121 static v8::Handle<Value> ShadowIndexedGet(uint32_t index,
   5122                                           const AccessorInfo& info) {
   5123   return v8::Handle<Value>();
   5124 }
   5125 
   5126 
   5127 static v8::Handle<Value> ShadowNamedGet(Local<String> key,
   5128                                         const AccessorInfo&) {
   5129   return v8::Handle<Value>();
   5130 }
   5131 
   5132 
   5133 THREADED_TEST(ShadowObject) {
   5134   shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
   5135   v8::HandleScope handle_scope;
   5136 
   5137   Local<ObjectTemplate> global_template = v8::ObjectTemplate::New();
   5138   LocalContext context(NULL, global_template);
   5139 
   5140   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
   5141   t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
   5142   t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
   5143   Local<ObjectTemplate> proto = t->PrototypeTemplate();
   5144   Local<ObjectTemplate> instance = t->InstanceTemplate();
   5145 
   5146   // Only allow calls of f on instances of t.
   5147   Local<v8::Signature> signature = v8::Signature::New(t);
   5148   proto->Set(v8_str("f"),
   5149              v8::FunctionTemplate::New(ShadowFunctionCallback,
   5150                                        Local<Value>(),
   5151                                        signature));
   5152   proto->Set(v8_str("x"), v8_num(12));
   5153 
   5154   instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
   5155 
   5156   Local<Value> o = t->GetFunction()->NewInstance();
   5157   context->Global()->Set(v8_str("__proto__"), o);
   5158 
   5159   Local<Value> value =
   5160       Script::Compile(v8_str("propertyIsEnumerable(0)"))->Run();
   5161   CHECK(value->IsBoolean());
   5162   CHECK(!value->BooleanValue());
   5163 
   5164   value = Script::Compile(v8_str("x"))->Run();
   5165   CHECK_EQ(12, value->Int32Value());
   5166 
   5167   value = Script::Compile(v8_str("f()"))->Run();
   5168   CHECK_EQ(42, value->Int32Value());
   5169 
   5170   Script::Compile(v8_str("y = 42"))->Run();
   5171   CHECK_EQ(1, shadow_y_setter_call_count);
   5172   value = Script::Compile(v8_str("y"))->Run();
   5173   CHECK_EQ(1, shadow_y_getter_call_count);
   5174   CHECK_EQ(42, value->Int32Value());
   5175 }
   5176 
   5177 
   5178 THREADED_TEST(HiddenPrototype) {
   5179   v8::HandleScope handle_scope;
   5180   LocalContext context;
   5181 
   5182   Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
   5183   t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
   5184   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
   5185   t1->SetHiddenPrototype(true);
   5186   t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
   5187   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
   5188   t2->SetHiddenPrototype(true);
   5189   t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
   5190   Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
   5191   t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
   5192 
   5193   Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
   5194   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
   5195   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
   5196   Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
   5197 
   5198   // Setting the prototype on an object skips hidden prototypes.
   5199   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
   5200   o0->Set(v8_str("__proto__"), o1);
   5201   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
   5202   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
   5203   o0->Set(v8_str("__proto__"), o2);
   5204   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
   5205   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
   5206   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
   5207   o0->Set(v8_str("__proto__"), o3);
   5208   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
   5209   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
   5210   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
   5211   CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
   5212 
   5213   // Getting the prototype of o0 should get the first visible one
   5214   // which is o3.  Therefore, z should not be defined on the prototype
   5215   // object.
   5216   Local<Value> proto = o0->Get(v8_str("__proto__"));
   5217   CHECK(proto->IsObject());
   5218   CHECK(Local<v8::Object>::Cast(proto)->Get(v8_str("z"))->IsUndefined());
   5219 }
   5220 
   5221 
   5222 THREADED_TEST(SetPrototype) {
   5223   v8::HandleScope handle_scope;
   5224   LocalContext context;
   5225 
   5226   Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
   5227   t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
   5228   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
   5229   t1->SetHiddenPrototype(true);
   5230   t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
   5231   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
   5232   t2->SetHiddenPrototype(true);
   5233   t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
   5234   Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
   5235   t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
   5236 
   5237   Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
   5238   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
   5239   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
   5240   Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
   5241 
   5242   // Setting the prototype on an object does not skip hidden prototypes.
   5243   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
   5244   CHECK(o0->SetPrototype(o1));
   5245   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
   5246   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
   5247   CHECK(o1->SetPrototype(o2));
   5248   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
   5249   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
   5250   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
   5251   CHECK(o2->SetPrototype(o3));
   5252   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
   5253   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
   5254   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
   5255   CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
   5256 
   5257   // Getting the prototype of o0 should get the first visible one
   5258   // which is o3.  Therefore, z should not be defined on the prototype
   5259   // object.
   5260   Local<Value> proto = o0->Get(v8_str("__proto__"));
   5261   CHECK(proto->IsObject());
   5262   CHECK_EQ(v8::Handle<v8::Object>::Cast(proto), o3);
   5263 
   5264   // However, Object::GetPrototype ignores hidden prototype.
   5265   Local<Value> proto0 = o0->GetPrototype();
   5266   CHECK(proto0->IsObject());
   5267   CHECK_EQ(v8::Handle<v8::Object>::Cast(proto0), o1);
   5268 
   5269   Local<Value> proto1 = o1->GetPrototype();
   5270   CHECK(proto1->IsObject());
   5271   CHECK_EQ(v8::Handle<v8::Object>::Cast(proto1), o2);
   5272 
   5273   Local<Value> proto2 = o2->GetPrototype();
   5274   CHECK(proto2->IsObject());
   5275   CHECK_EQ(v8::Handle<v8::Object>::Cast(proto2), o3);
   5276 }
   5277 
   5278 
   5279 THREADED_TEST(SetPrototypeThrows) {
   5280   v8::HandleScope handle_scope;
   5281   LocalContext context;
   5282 
   5283   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
   5284 
   5285   Local<v8::Object> o0 = t->GetFunction()->NewInstance();
   5286   Local<v8::Object> o1 = t->GetFunction()->NewInstance();
   5287 
   5288   CHECK(o0->SetPrototype(o1));
   5289   // If setting the prototype leads to the cycle, SetPrototype should
   5290   // return false and keep VM in sane state.
   5291   v8::TryCatch try_catch;
   5292   CHECK(!o1->SetPrototype(o0));
   5293   CHECK(!try_catch.HasCaught());
   5294   ASSERT(!i::Top::has_pending_exception());
   5295 
   5296   CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
   5297 }
   5298 
   5299 
   5300 THREADED_TEST(GetterSetterExceptions) {
   5301   v8::HandleScope handle_scope;
   5302   LocalContext context;
   5303   CompileRun(
   5304     "function Foo() { };"
   5305     "function Throw() { throw 5; };"
   5306     "var x = { };"
   5307     "x.__defineSetter__('set', Throw);"
   5308     "x.__defineGetter__('get', Throw);");
   5309   Local<v8::Object> x =
   5310       Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
   5311   v8::TryCatch try_catch;
   5312   x->Set(v8_str("set"), v8::Integer::New(8));
   5313   x->Get(v8_str("get"));
   5314   x->Set(v8_str("set"), v8::Integer::New(8));
   5315   x->Get(v8_str("get"));
   5316   x->Set(v8_str("set"), v8::Integer::New(8));
   5317   x->Get(v8_str("get"));
   5318   x->Set(v8_str("set"), v8::Integer::New(8));
   5319   x->Get(v8_str("get"));
   5320 }
   5321 
   5322 
   5323 THREADED_TEST(Constructor) {
   5324   v8::HandleScope handle_scope;
   5325   LocalContext context;
   5326   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
   5327   templ->SetClassName(v8_str("Fun"));
   5328   Local<Function> cons = templ->GetFunction();
   5329   context->Global()->Set(v8_str("Fun"), cons);
   5330   Local<v8::Object> inst = cons->NewInstance();
   5331   i::Handle<i::JSObject> obj = v8::Utils::OpenHandle(*inst);
   5332   Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
   5333   CHECK(value->BooleanValue());
   5334 }
   5335 
   5336 THREADED_TEST(FunctionDescriptorException) {
   5337   v8::HandleScope handle_scope;
   5338   LocalContext context;
   5339   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
   5340   templ->SetClassName(v8_str("Fun"));
   5341   Local<Function> cons = templ->GetFunction();
   5342   context->Global()->Set(v8_str("Fun"), cons);
   5343   Local<Value> value = CompileRun(
   5344     "function test() {"
   5345     "  try {"
   5346     "    (new Fun()).blah()"
   5347     "  } catch (e) {"
   5348     "    var str = String(e);"
   5349     "    if (str.indexOf('TypeError') == -1) return 1;"
   5350     "    if (str.indexOf('[object Fun]') != -1) return 2;"
   5351     "    if (str.indexOf('#<a Fun>') == -1) return 3;"
   5352     "    return 0;"
   5353     "  }"
   5354     "  return 4;"
   5355     "}"
   5356     "test();");
   5357   CHECK_EQ(0, value->Int32Value());
   5358 }
   5359 
   5360 
   5361 THREADED_TEST(EvalAliasedDynamic) {
   5362   v8::HandleScope scope;
   5363   LocalContext current;
   5364 
   5365   // Tests where aliased eval can only be resolved dynamically.
   5366   Local<Script> script =
   5367       Script::Compile(v8_str("function f(x) { "
   5368                              "  var foo = 2;"
   5369                              "  with (x) { return eval('foo'); }"
   5370                              "}"
   5371                              "foo = 0;"
   5372                              "result1 = f(new Object());"
   5373                              "result2 = f(this);"
   5374                              "var x = new Object();"
   5375                              "x.eval = function(x) { return 1; };"
   5376                              "result3 = f(x);"));
   5377   script->Run();
   5378   CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
   5379   CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
   5380   CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
   5381 
   5382   v8::TryCatch try_catch;
   5383   script =
   5384     Script::Compile(v8_str("function f(x) { "
   5385                            "  var bar = 2;"
   5386                            "  with (x) { return eval('bar'); }"
   5387                            "}"
   5388                            "f(this)"));
   5389   script->Run();
   5390   CHECK(try_catch.HasCaught());
   5391   try_catch.Reset();
   5392 }
   5393 
   5394 
   5395 THREADED_TEST(CrossEval) {
   5396   v8::HandleScope scope;
   5397   LocalContext other;
   5398   LocalContext current;
   5399 
   5400   Local<String> token = v8_str("<security token>");
   5401   other->SetSecurityToken(token);
   5402   current->SetSecurityToken(token);
   5403 
   5404   // Setup reference from current to other.
   5405   current->Global()->Set(v8_str("other"), other->Global());
   5406 
   5407   // Check that new variables are introduced in other context.
   5408   Local<Script> script =
   5409       Script::Compile(v8_str("other.eval('var foo = 1234')"));
   5410   script->Run();
   5411   Local<Value> foo = other->Global()->Get(v8_str("foo"));
   5412   CHECK_EQ(1234, foo->Int32Value());
   5413   CHECK(!current->Global()->Has(v8_str("foo")));
   5414 
   5415   // Check that writing to non-existing properties introduces them in
   5416   // the other context.
   5417   script =
   5418       Script::Compile(v8_str("other.eval('na = 1234')"));
   5419   script->Run();
   5420   CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
   5421   CHECK(!current->Global()->Has(v8_str("na")));
   5422 
   5423   // Check that global variables in current context are not visible in other
   5424   // context.
   5425   v8::TryCatch try_catch;
   5426   script =
   5427       Script::Compile(v8_str("var bar = 42; other.eval('bar');"));
   5428   Local<Value> result = script->Run();
   5429   CHECK(try_catch.HasCaught());
   5430   try_catch.Reset();
   5431 
   5432   // Check that local variables in current context are not visible in other
   5433   // context.
   5434   script =
   5435       Script::Compile(v8_str("(function() { "
   5436                              "  var baz = 87;"
   5437                              "  return other.eval('baz');"
   5438                              "})();"));
   5439   result = script->Run();
   5440   CHECK(try_catch.HasCaught());
   5441   try_catch.Reset();
   5442 
   5443   // Check that global variables in the other environment are visible
   5444   // when evaluting code.
   5445   other->Global()->Set(v8_str("bis"), v8_num(1234));
   5446   script = Script::Compile(v8_str("other.eval('bis')"));
   5447   CHECK_EQ(1234, script->Run()->Int32Value());
   5448   CHECK(!try_catch.HasCaught());
   5449 
   5450   // Check that the 'this' pointer points to the global object evaluating
   5451   // code.
   5452   other->Global()->Set(v8_str("t"), other->Global());
   5453   script = Script::Compile(v8_str("other.eval('this == t')"));
   5454   result = script->Run();
   5455   CHECK(result->IsTrue());
   5456   CHECK(!try_catch.HasCaught());
   5457 
   5458   // Check that variables introduced in with-statement are not visible in
   5459   // other context.
   5460   script =
   5461       Script::Compile(v8_str("with({x:2}){other.eval('x')}"));
   5462   result = script->Run();
   5463   CHECK(try_catch.HasCaught());
   5464   try_catch.Reset();
   5465 
   5466   // Check that you cannot use 'eval.call' with another object than the
   5467   // current global object.
   5468   script =
   5469       Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')"));
   5470   result = script->Run();
   5471   CHECK(try_catch.HasCaught());
   5472 }
   5473 
   5474 
   5475 // Test that calling eval in a context which has been detached from
   5476 // its global throws an exception.  This behavior is consistent with
   5477 // other JavaScript implementations.
   5478 THREADED_TEST(EvalInDetachedGlobal) {
   5479   v8::HandleScope scope;
   5480 
   5481   v8::Persistent<Context> context0 = Context::New();
   5482   v8::Persistent<Context> context1 = Context::New();
   5483 
   5484   // Setup function in context0 that uses eval from context0.
   5485   context0->Enter();
   5486   v8::Handle<v8::Value> fun =
   5487       CompileRun("var x = 42;"
   5488                  "(function() {"
   5489                  "  var e = eval;"
   5490                  "  return function(s) { return e(s); }"
   5491                  "})()");
   5492   context0->Exit();
   5493 
   5494   // Put the function into context1 and call it before and after
   5495   // detaching the global.  Before detaching, the call succeeds and
   5496   // after detaching and exception is thrown.
   5497   context1->Enter();
   5498   context1->Global()->Set(v8_str("fun"), fun);
   5499   v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
   5500   CHECK_EQ(42, x_value->Int32Value());
   5501   context0->DetachGlobal();
   5502   v8::TryCatch catcher;
   5503   x_value = CompileRun("fun('x')");
   5504   CHECK(x_value.IsEmpty());
   5505   CHECK(catcher.HasCaught());
   5506   context1->Exit();
   5507 
   5508   context1.Dispose();
   5509   context0.Dispose();
   5510 }
   5511 
   5512 
   5513 THREADED_TEST(CrossLazyLoad) {
   5514   v8::HandleScope scope;
   5515   LocalContext other;
   5516   LocalContext current;
   5517 
   5518   Local<String> token = v8_str("<security token>");
   5519   other->SetSecurityToken(token);
   5520   current->SetSecurityToken(token);
   5521 
   5522   // Setup reference from current to other.
   5523   current->Global()->Set(v8_str("other"), other->Global());
   5524 
   5525   // Trigger lazy loading in other context.
   5526   Local<Script> script =
   5527       Script::Compile(v8_str("other.eval('new Date(42)')"));
   5528   Local<Value> value = script->Run();
   5529   CHECK_EQ(42.0, value->NumberValue());
   5530 }
   5531 
   5532 
   5533 static v8::Handle<Value> call_as_function(const v8::Arguments& args) {
   5534   ApiTestFuzzer::Fuzz();
   5535   if (args.IsConstructCall()) {
   5536     if (args[0]->IsInt32()) {
   5537        return v8_num(-args[0]->Int32Value());
   5538     }
   5539   }
   5540 
   5541   return args[0];
   5542 }
   5543 
   5544 
   5545 // Test that a call handler can be set for objects which will allow
   5546 // non-function objects created through the API to be called as
   5547 // functions.
   5548 THREADED_TEST(CallAsFunction) {
   5549   v8::HandleScope scope;
   5550   LocalContext context;
   5551 
   5552   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
   5553   Local<ObjectTemplate> instance_template = t->InstanceTemplate();
   5554   instance_template->SetCallAsFunctionHandler(call_as_function);
   5555   Local<v8::Object> instance = t->GetFunction()->NewInstance();
   5556   context->Global()->Set(v8_str("obj"), instance);
   5557   v8::TryCatch try_catch;
   5558   Local<Value> value;
   5559   CHECK(!try_catch.HasCaught());
   5560 
   5561   value = CompileRun("obj(42)");
   5562   CHECK(!try_catch.HasCaught());
   5563   CHECK_EQ(42, value->Int32Value());
   5564 
   5565   value = CompileRun("(function(o){return o(49)})(obj)");
   5566   CHECK(!try_catch.HasCaught());
   5567   CHECK_EQ(49, value->Int32Value());
   5568 
   5569   // test special case of call as function
   5570   value = CompileRun("[obj]['0'](45)");
   5571   CHECK(!try_catch.HasCaught());
   5572   CHECK_EQ(45, value->Int32Value());
   5573 
   5574   value = CompileRun("obj.call = Function.prototype.call;"
   5575                      "obj.call(null, 87)");
   5576   CHECK(!try_catch.HasCaught());
   5577   CHECK_EQ(87, value->Int32Value());
   5578 
   5579   // Regression tests for bug #1116356: Calling call through call/apply
   5580   // must work for non-function receivers.
   5581   const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
   5582   value = CompileRun(apply_99);
   5583   CHECK(!try_catch.HasCaught());
   5584   CHECK_EQ(99, value->Int32Value());
   5585 
   5586   const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
   5587   value = CompileRun(call_17);
   5588   CHECK(!try_catch.HasCaught());
   5589   CHECK_EQ(17, value->Int32Value());
   5590 
   5591   // Check that the call-as-function handler can be called through
   5592   // new.
   5593   value = CompileRun("new obj(43)");
   5594   CHECK(!try_catch.HasCaught());
   5595   CHECK_EQ(-43, value->Int32Value());
   5596 }
   5597 
   5598 
   5599 static int CountHandles() {
   5600   return v8::HandleScope::NumberOfHandles();
   5601 }
   5602 
   5603 
   5604 static int Recurse(int depth, int iterations) {
   5605   v8::HandleScope scope;
   5606   if (depth == 0) return CountHandles();
   5607   for (int i = 0; i < iterations; i++) {
   5608     Local<v8::Number> n = v8::Integer::New(42);
   5609   }
   5610   return Recurse(depth - 1, iterations);
   5611 }
   5612 
   5613 
   5614 THREADED_TEST(HandleIteration) {
   5615   static const int kIterations = 500;
   5616   static const int kNesting = 200;
   5617   CHECK_EQ(0, CountHandles());
   5618   {
   5619     v8::HandleScope scope1;
   5620     CHECK_EQ(0, CountHandles());
   5621     for (int i = 0; i < kIterations; i++) {
   5622       Local<v8::Number> n = v8::Integer::New(42);
   5623       CHECK_EQ(i + 1, CountHandles());
   5624     }
   5625 
   5626     CHECK_EQ(kIterations, CountHandles());
   5627     {
   5628       v8::HandleScope scope2;
   5629       for (int j = 0; j < kIterations; j++) {
   5630         Local<v8::Number> n = v8::Integer::New(42);
   5631         CHECK_EQ(j + 1 + kIterations, CountHandles());
   5632       }
   5633     }
   5634     CHECK_EQ(kIterations, CountHandles());
   5635   }
   5636   CHECK_EQ(0, CountHandles());
   5637   CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations));
   5638 }
   5639 
   5640 
   5641 static v8::Handle<Value> InterceptorHasOwnPropertyGetter(
   5642     Local<String> name,
   5643     const AccessorInfo& info) {
   5644   ApiTestFuzzer::Fuzz();
   5645   return v8::Handle<Value>();
   5646 }
   5647 
   5648 
   5649 THREADED_TEST(InterceptorHasOwnProperty) {
   5650   v8::HandleScope scope;
   5651   LocalContext context;
   5652   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
   5653   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
   5654   instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
   5655   Local<Function> function = fun_templ->GetFunction();
   5656   context->Global()->Set(v8_str("constructor"), function);
   5657   v8::Handle<Value> value = CompileRun(
   5658       "var o = new constructor();"
   5659       "o.hasOwnProperty('ostehaps');");
   5660   CHECK_EQ(false, value->BooleanValue());
   5661   value = CompileRun(
   5662       "o.ostehaps = 42;"
   5663       "o.hasOwnProperty('ostehaps');");
   5664   CHECK_EQ(true, value->BooleanValue());
   5665   value = CompileRun(
   5666       "var p = new constructor();"
   5667       "p.hasOwnProperty('ostehaps');");
   5668   CHECK_EQ(false, value->BooleanValue());
   5669 }
   5670 
   5671 
   5672 static v8::Handle<Value> InterceptorHasOwnPropertyGetterGC(
   5673     Local<String> name,
   5674     const AccessorInfo& info) {
   5675   ApiTestFuzzer::Fuzz();
   5676   i::Heap::CollectAllGarbage(false);
   5677   return v8::Handle<Value>();
   5678 }
   5679 
   5680 
   5681 THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
   5682   v8::HandleScope scope;
   5683   LocalContext context;
   5684   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
   5685   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
   5686   instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
   5687   Local<Function> function = fun_templ->GetFunction();
   5688   context->Global()->Set(v8_str("constructor"), function);
   5689   // Let's first make some stuff so we can be sure to get a good GC.
   5690   CompileRun(
   5691       "function makestr(size) {"
   5692       "  switch (size) {"
   5693       "    case 1: return 'f';"
   5694       "    case 2: return 'fo';"
   5695       "    case 3: return 'foo';"
   5696       "  }"
   5697       "  return makestr(size >> 1) + makestr((size + 1) >> 1);"
   5698       "}"
   5699       "var x = makestr(12345);"
   5700       "x = makestr(31415);"
   5701       "x = makestr(23456);");
   5702   v8::Handle<Value> value = CompileRun(
   5703       "var o = new constructor();"
   5704       "o.__proto__ = new String(x);"
   5705       "o.hasOwnProperty('ostehaps');");
   5706   CHECK_EQ(false, value->BooleanValue());
   5707 }
   5708 
   5709 
   5710 typedef v8::Handle<Value> (*NamedPropertyGetter)(Local<String> property,
   5711                                                  const AccessorInfo& info);
   5712 
   5713 
   5714 static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
   5715                                    const char* source,
   5716                                    int expected) {
   5717   v8::HandleScope scope;
   5718   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
   5719   templ->SetNamedPropertyHandler(getter);
   5720   LocalContext context;
   5721   context->Global()->Set(v8_str("o"), templ->NewInstance());
   5722   v8::Handle<Value> value = CompileRun(source);
   5723   CHECK_EQ(expected, value->Int32Value());
   5724 }
   5725 
   5726 
   5727 static v8::Handle<Value> InterceptorLoadICGetter(Local<String> name,
   5728                                                  const AccessorInfo& info) {
   5729   ApiTestFuzzer::Fuzz();
   5730   CHECK(v8_str("x")->Equals(name));
   5731   return v8::Integer::New(42);
   5732 }
   5733 
   5734 
   5735 // This test should hit the load IC for the interceptor case.
   5736 THREADED_TEST(InterceptorLoadIC) {
   5737   CheckInterceptorLoadIC(InterceptorLoadICGetter,
   5738     "var result = 0;"
   5739     "for (var i = 0; i < 1000; i++) {"
   5740     "  result = o.x;"
   5741     "}",
   5742     42);
   5743 }
   5744 
   5745 
   5746 // Below go several tests which verify that JITing for various
   5747 // configurations of interceptor and explicit fields works fine
   5748 // (those cases are special cased to get better performance).
   5749 
   5750 static v8::Handle<Value> InterceptorLoadXICGetter(Local<String> name,
   5751                                                  const AccessorInfo& info) {
   5752   ApiTestFuzzer::Fuzz();
   5753   return v8_str("x")->Equals(name)
   5754       ? v8::Integer::New(42) : v8::Handle<v8::Value>();
   5755 }
   5756 
   5757 
   5758 THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
   5759   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
   5760     "var result = 0;"
   5761     "o.y = 239;"
   5762     "for (var i = 0; i < 1000; i++) {"
   5763     "  result = o.y;"
   5764     "}",
   5765     239);
   5766 }
   5767 
   5768 
   5769 THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
   5770   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
   5771     "var result = 0;"
   5772     "o.__proto__ = { 'y': 239 };"
   5773     "for (var i = 0; i < 1000; i++) {"
   5774     "  result = o.y + o.x;"
   5775     "}",
   5776     239 + 42);
   5777 }
   5778 
   5779 
   5780 THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
   5781   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
   5782     "var result = 0;"
   5783     "o.__proto__.y = 239;"
   5784     "for (var i = 0; i < 1000; i++) {"
   5785     "  result = o.y + o.x;"
   5786     "}",
   5787     239 + 42);
   5788 }
   5789 
   5790 
   5791 THREADED_TEST(InterceptorLoadICUndefined) {
   5792   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
   5793     "var result = 0;"
   5794     "for (var i = 0; i < 1000; i++) {"
   5795     "  result = (o.y == undefined) ? 239 : 42;"
   5796     "}",
   5797     239);
   5798 }
   5799 
   5800 
   5801 THREADED_TEST(InterceptorLoadICWithOverride) {
   5802   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
   5803     "fst = new Object();  fst.__proto__ = o;"
   5804     "snd = new Object();  snd.__proto__ = fst;"
   5805     "var result1 = 0;"
   5806     "for (var i = 0; i < 1000;  i++) {"
   5807     "  result1 = snd.x;"
   5808     "}"
   5809     "fst.x = 239;"
   5810     "var result = 0;"
   5811     "for (var i = 0; i < 1000; i++) {"
   5812     "  result = snd.x;"
   5813     "}"
   5814     "result + result1",
   5815     239 + 42);
   5816 }
   5817 
   5818 
   5819 // Test the case when we stored field into
   5820 // a stub, but interceptor produced value on its own.
   5821 THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
   5822   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
   5823     "proto = new Object();"
   5824     "o.__proto__ = proto;"
   5825     "proto.x = 239;"
   5826     "for (var i = 0; i < 1000; i++) {"
   5827     "  o.x;"
   5828     // Now it should be ICed and keep a reference to x defined on proto
   5829     "}"
   5830     "var result = 0;"
   5831     "for (var i = 0; i < 1000; i++) {"
   5832     "  result += o.x;"
   5833     "}"
   5834     "result;",
   5835     42 * 1000);
   5836 }
   5837 
   5838 
   5839 // Test the case when we stored field into
   5840 // a stub, but it got invalidated later on.
   5841 THREADED_TEST(InterceptorLoadICInvalidatedField) {
   5842   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
   5843     "proto1 = new Object();"
   5844     "proto2 = new Object();"
   5845     "o.__proto__ = proto1;"
   5846     "proto1.__proto__ = proto2;"
   5847     "proto2.y = 239;"
   5848     "for (var i = 0; i < 1000; i++) {"
   5849     "  o.y;"
   5850     // Now it should be ICed and keep a reference to y defined on proto2
   5851     "}"
   5852     "proto1.y = 42;"
   5853     "var result = 0;"
   5854     "for (var i = 0; i < 1000; i++) {"
   5855     "  result += o.y;"
   5856     "}"
   5857     "result;",
   5858     42 * 1000);
   5859 }
   5860 
   5861 
   5862 // Test the case when we stored field into
   5863 // a stub, but it got invalidated later on due to override on
   5864 // global object which is between interceptor and fields' holders.
   5865 THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
   5866   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
   5867     "o.__proto__ = this;"  // set a global to be a proto of o.
   5868     "this.__proto__.y = 239;"
   5869     "for (var i = 0; i < 10; i++) {"
   5870     "  if (o.y != 239) throw 'oops: ' + o.y;"
   5871     // Now it should be ICed and keep a reference to y defined on field_holder.
   5872     "}"
   5873     "this.y = 42;"  // Assign on a global.
   5874     "var result = 0;"
   5875     "for (var i = 0; i < 10; i++) {"
   5876     "  result += o.y;"
   5877     "}"
   5878     "result;",
   5879     42 * 10);
   5880 }
   5881 
   5882 
   5883 static v8::Handle<Value> Return239(Local<String> name, const AccessorInfo&) {
   5884   ApiTestFuzzer::Fuzz();
   5885   return v8_num(239);
   5886 }
   5887 
   5888 
   5889 static void SetOnThis(Local<String> name,
   5890                       Local<Value> value,
   5891                       const AccessorInfo& info) {
   5892   info.This()->ForceSet(name, value);
   5893 }
   5894 
   5895 
   5896 THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
   5897   v8::HandleScope scope;
   5898   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
   5899   templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
   5900   templ->SetAccessor(v8_str("y"), Return239);
   5901   LocalContext context;
   5902   context->Global()->Set(v8_str("o"), templ->NewInstance());
   5903   v8::Handle<Value> value = CompileRun(
   5904       "var result = 0;"
   5905       "for (var i = 0; i < 7; i++) {"
   5906       "  result = o.y;"
   5907       "}");
   5908   CHECK_EQ(239, value->Int32Value());
   5909 }
   5910 
   5911 
   5912 THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
   5913   v8::HandleScope scope;
   5914   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
   5915   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
   5916   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
   5917   templ_p->SetAccessor(v8_str("y"), Return239);
   5918 
   5919   LocalContext context;
   5920   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
   5921   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
   5922 
   5923   v8::Handle<Value> value = CompileRun(
   5924       "o.__proto__ = p;"
   5925       "var result = 0;"
   5926       "for (var i = 0; i < 7; i++) {"
   5927       "  result = o.x + o.y;"
   5928       "}");
   5929   CHECK_EQ(239 + 42, value->Int32Value());
   5930 }
   5931 
   5932 
   5933 THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
   5934   v8::HandleScope scope;
   5935   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
   5936   templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
   5937   templ->SetAccessor(v8_str("y"), Return239);
   5938 
   5939   LocalContext context;
   5940   context->Global()->Set(v8_str("o"), templ->NewInstance());
   5941 
   5942   v8::Handle<Value> value = CompileRun(
   5943     "fst = new Object();  fst.__proto__ = o;"
   5944     "snd = new Object();  snd.__proto__ = fst;"
   5945     "var result1 = 0;"
   5946     "for (var i = 0; i < 7;  i++) {"
   5947     "  result1 = snd.x;"
   5948     "}"
   5949     "fst.x = 239;"
   5950     "var result = 0;"
   5951     "for (var i = 0; i < 7; i++) {"
   5952     "  result = snd.x;"
   5953     "}"
   5954     "result + result1");
   5955   CHECK_EQ(239 + 42, value->Int32Value());
   5956 }
   5957 
   5958 
   5959 // Test the case when we stored callback into
   5960 // a stub, but interceptor produced value on its own.
   5961 THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
   5962   v8::HandleScope scope;
   5963   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
   5964   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
   5965   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
   5966   templ_p->SetAccessor(v8_str("y"), Return239);
   5967 
   5968   LocalContext context;
   5969   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
   5970   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
   5971 
   5972   v8::Handle<Value> value = CompileRun(
   5973     "o.__proto__ = p;"
   5974     "for (var i = 0; i < 7; i++) {"
   5975     "  o.x;"
   5976     // Now it should be ICed and keep a reference to x defined on p
   5977     "}"
   5978     "var result = 0;"
   5979     "for (var i = 0; i < 7; i++) {"
   5980     "  result += o.x;"
   5981     "}"
   5982     "result");
   5983   CHECK_EQ(42 * 7, value->Int32Value());
   5984 }
   5985 
   5986 
   5987 // Test the case when we stored callback into
   5988 // a stub, but it got invalidated later on.
   5989 THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
   5990   v8::HandleScope scope;
   5991   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
   5992   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
   5993   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
   5994   templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
   5995 
   5996   LocalContext context;
   5997   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
   5998   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
   5999 
   6000   v8::Handle<Value> value = CompileRun(
   6001     "inbetween = new Object();"
   6002     "o.__proto__ = inbetween;"
   6003     "inbetween.__proto__ = p;"
   6004     "for (var i = 0; i < 10; i++) {"
   6005     "  o.y;"
   6006     // Now it should be ICed and keep a reference to y defined on p
   6007     "}"
   6008     "inbetween.y = 42;"
   6009     "var result = 0;"
   6010     "for (var i = 0; i < 10; i++) {"
   6011     "  result += o.y;"
   6012     "}"
   6013     "result");
   6014   CHECK_EQ(42 * 10, value->Int32Value());
   6015 }
   6016 
   6017 
   6018 // Test the case when we stored callback into
   6019 // a stub, but it got invalidated later on due to override on
   6020 // global object which is between interceptor and callbacks' holders.
   6021 THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
   6022   v8::HandleScope scope;
   6023   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
   6024   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
   6025   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
   6026   templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
   6027 
   6028   LocalContext context;
   6029   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
   6030   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
   6031 
   6032   v8::Handle<Value> value = CompileRun(
   6033     "o.__proto__ = this;"
   6034     "this.__proto__ = p;"
   6035     "for (var i = 0; i < 10; i++) {"
   6036     "  if (o.y != 239) throw 'oops: ' + o.y;"
   6037     // Now it should be ICed and keep a reference to y defined on p
   6038     "}"
   6039     "this.y = 42;"
   6040     "var result = 0;"
   6041     "for (var i = 0; i < 10; i++) {"
   6042     "  result += o.y;"
   6043     "}"
   6044     "result");
   6045   CHECK_EQ(42 * 10, value->Int32Value());
   6046 }
   6047 
   6048 
   6049 static v8::Handle<Value> InterceptorLoadICGetter0(Local<String> name,
   6050                                                   const AccessorInfo& info) {
   6051   ApiTestFuzzer::Fuzz();
   6052   CHECK(v8_str("x")->Equals(name));
   6053   return v8::Integer::New(0);
   6054 }
   6055 
   6056 
   6057 THREADED_TEST(InterceptorReturningZero) {
   6058   CheckInterceptorLoadIC(InterceptorLoadICGetter0,
   6059      "o.x == undefined ? 1 : 0",
   6060      0);
   6061 }
   6062 
   6063 
   6064 static v8::Handle<Value> InterceptorStoreICSetter(
   6065     Local<String> key, Local<Value> value, const AccessorInfo&) {
   6066   CHECK(v8_str("x")->Equals(key));
   6067   CHECK_EQ(42, value->Int32Value());
   6068   return value;
   6069 }
   6070 
   6071 
   6072 // This test should hit the store IC for the interceptor case.
   6073 THREADED_TEST(InterceptorStoreIC) {
   6074   v8::HandleScope scope;
   6075   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
   6076   templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
   6077                                  InterceptorStoreICSetter);
   6078   LocalContext context;
   6079   context->Global()->Set(v8_str("o"), templ->NewInstance());
   6080   v8::Handle<Value> value = CompileRun(
   6081     "for (var i = 0; i < 1000; i++) {"
   6082     "  o.x = 42;"
   6083     "}");
   6084 }
   6085 
   6086 
   6087 THREADED_TEST(InterceptorStoreICWithNoSetter) {
   6088   v8::HandleScope scope;
   6089   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
   6090   templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
   6091   LocalContext context;
   6092   context->Global()->Set(v8_str("o"), templ->NewInstance());
   6093   v8::Handle<Value> value = CompileRun(
   6094     "for (var i = 0; i < 1000; i++) {"
   6095     "  o.y = 239;"
   6096     "}"
   6097     "42 + o.y");
   6098   CHECK_EQ(239 + 42, value->Int32Value());
   6099 }
   6100 
   6101 
   6102 
   6103 
   6104 v8::Handle<Value> call_ic_function;
   6105 v8::Handle<Value> call_ic_function2;
   6106 v8::Handle<Value> call_ic_function3;
   6107 
   6108 static v8::Handle<Value> InterceptorCallICGetter(Local<String> name,
   6109                                                  const AccessorInfo& info) {
   6110   ApiTestFuzzer::Fuzz();
   6111   CHECK(v8_str("x")->Equals(name));
   6112   return call_ic_function;
   6113 }
   6114 
   6115 
   6116 // This test should hit the call IC for the interceptor case.
   6117 THREADED_TEST(InterceptorCallIC) {
   6118   v8::HandleScope scope;
   6119   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
   6120   templ->SetNamedPropertyHandler(InterceptorCallICGetter);
   6121   LocalContext context;
   6122   context->Global()->Set(v8_str("o"), templ->NewInstance());
   6123   call_ic_function =
   6124       v8_compile("function f(x) { return x + 1; }; f")->Run();
   6125   v8::Handle<Value> value = CompileRun(
   6126     "var result = 0;"
   6127     "for (var i = 0; i < 1000; i++) {"
   6128     "  result = o.x(41);"
   6129     "}");
   6130   CHECK_EQ(42, value->Int32Value());
   6131 }
   6132 
   6133 
   6134 // This test checks that if interceptor doesn't provide
   6135 // a value, we can fetch regular value.
   6136 THREADED_TEST(InterceptorCallICSeesOthers) {
   6137   v8::HandleScope scope;
   6138   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
   6139   templ->SetNamedPropertyHandler(NoBlockGetterX);
   6140   LocalContext context;
   6141   context->Global()->Set(v8_str("o"), templ->NewInstance());
   6142   v8::Handle<Value> value = CompileRun(
   6143     "o.x = function f(x) { return x + 1; };"
   6144     "var result = 0;"
   6145     "for (var i = 0; i < 7; i++) {"
   6146     "  result = o.x(41);"
   6147     "}");
   6148   CHECK_EQ(42, value->Int32Value());
   6149 }
   6150 
   6151 
   6152 static v8::Handle<Value> call_ic_function4;
   6153 static v8::Handle<Value> InterceptorCallICGetter4(Local<String> name,
   6154                                                   const AccessorInfo& info) {
   6155   ApiTestFuzzer::Fuzz();
   6156   CHECK(v8_str("x")->Equals(name));
   6157   return call_ic_function4;
   6158 }
   6159 
   6160 
   6161 // This test checks that if interceptor provides a function,
   6162 // even if we cached shadowed variant, interceptor's function
   6163 // is invoked
   6164 THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
   6165   v8::HandleScope scope;
   6166   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
   6167   templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
   6168   LocalContext context;
   6169   context->Global()->Set(v8_str("o"), templ->NewInstance());
   6170   call_ic_function4 =
   6171       v8_compile("function f(x) { return x - 1; }; f")->Run();
   6172   v8::Handle<Value> value = CompileRun(
   6173     "o.__proto__.x = function(x) { return x + 1; };"
   6174     "var result = 0;"
   6175     "for (var i = 0; i < 1000; i++) {"
   6176     "  result = o.x(42);"
   6177     "}");
   6178   CHECK_EQ(41, value->Int32Value());
   6179 }
   6180 
   6181 
   6182 // Test the case when we stored cacheable lookup into
   6183 // a stub, but it got invalidated later on
   6184 THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
   6185   v8::HandleScope scope;
   6186   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
   6187   templ->SetNamedPropertyHandler(NoBlockGetterX);
   6188   LocalContext context;
   6189   context->Global()->Set(v8_str("o"), templ->NewInstance());
   6190   v8::Handle<Value> value = CompileRun(
   6191     "proto1 = new Object();"
   6192     "proto2 = new Object();"
   6193     "o.__proto__ = proto1;"
   6194     "proto1.__proto__ = proto2;"
   6195     "proto2.y = function(x) { return x + 1; };"
   6196     // Invoke it many times to compile a stub
   6197     "for (var i = 0; i < 7; i++) {"
   6198     "  o.y(42);"
   6199     "}"
   6200     "proto1.y = function(x) { return x - 1; };"
   6201     "var result = 0;"
   6202     "for (var i = 0; i < 7; i++) {"
   6203     "  result += o.y(42);"
   6204     "}");
   6205   CHECK_EQ(41 * 7, value->Int32Value());
   6206 }
   6207 
   6208 
   6209 static v8::Handle<Value> call_ic_function5;
   6210 static v8::Handle<Value> InterceptorCallICGetter5(Local<String> name,
   6211                                                   const AccessorInfo& info) {
   6212   ApiTestFuzzer::Fuzz();
   6213   if (v8_str("x")->Equals(name))
   6214     return call_ic_function5;
   6215   else
   6216     return Local<Value>();
   6217 }
   6218 
   6219 
   6220 // This test checks that if interceptor doesn't provide a function,
   6221 // cached constant function is used
   6222 THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
   6223   v8::HandleScope scope;
   6224   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
   6225   templ->SetNamedPropertyHandler(NoBlockGetterX);
   6226   LocalContext context;
   6227   context->Global()->Set(v8_str("o"), templ->NewInstance());
   6228   v8::Handle<Value> value = CompileRun(
   6229     "function inc(x) { return x + 1; };"
   6230     "inc(1);"
   6231     "o.x = inc;"
   6232     "var result = 0;"
   6233     "for (var i = 0; i < 1000; i++) {"
   6234     "  result = o.x(42);"
   6235     "}");
   6236   CHECK_EQ(43, value->Int32Value());
   6237 }
   6238 
   6239 
   6240 // This test checks that if interceptor provides a function,
   6241 // even if we cached constant function, interceptor's function
   6242 // is invoked
   6243 THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
   6244   v8::HandleScope scope;
   6245   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
   6246   templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
   6247   LocalContext context;
   6248   context->Global()->Set(v8_str("o"), templ->NewInstance());
   6249   call_ic_function5 =
   6250       v8_compile("function f(x) { return x - 1; }; f")->Run();
   6251   v8::Handle<Value> value = CompileRun(
   6252     "function inc(x) { return x + 1; };"
   6253     "inc(1);"
   6254     "o.x = inc;"
   6255     "var result = 0;"
   6256     "for (var i = 0; i < 1000; i++) {"
   6257     "  result = o.x(42);"
   6258     "}");
   6259   CHECK_EQ(41, value->Int32Value());
   6260 }
   6261 
   6262 
   6263 // Test the case when we stored constant function into
   6264 // a stub, but it got invalidated later on
   6265 THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
   6266   v8::HandleScope scope;
   6267   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
   6268   templ->SetNamedPropertyHandler(NoBlockGetterX);
   6269   LocalContext context;
   6270   context->Global()->Set(v8_str("o"), templ->NewInstance());
   6271   v8::Handle<Value> value = CompileRun(
   6272     "function inc(x) { return x + 1; };"
   6273     "inc(1);"
   6274     "proto1 = new Object();"
   6275     "proto2 = new Object();"
   6276     "o.__proto__ = proto1;"
   6277     "proto1.__proto__ = proto2;"
   6278     "proto2.y = inc;"
   6279     // Invoke it many times to compile a stub
   6280     "for (var i = 0; i < 7; i++) {"
   6281     "  o.y(42);"
   6282     "}"
   6283     "proto1.y = function(x) { return x - 1; };"
   6284     "var result = 0;"
   6285     "for (var i = 0; i < 7; i++) {"
   6286     "  result += o.y(42);"
   6287     "}");
   6288   CHECK_EQ(41 * 7, value->Int32Value());
   6289 }
   6290 
   6291 
   6292 // Test the case when we stored constant function into
   6293 // a stub, but it got invalidated later on due to override on
   6294 // global object which is between interceptor and constant function' holders.
   6295 THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
   6296   v8::HandleScope scope;
   6297   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
   6298   templ->SetNamedPropertyHandler(NoBlockGetterX);
   6299   LocalContext context;
   6300   context->Global()->Set(v8_str("o"), templ->NewInstance());
   6301   v8::Handle<Value> value = CompileRun(
   6302     "function inc(x) { return x + 1; };"
   6303     "inc(1);"
   6304     "o.__proto__ = this;"
   6305     "this.__proto__.y = inc;"
   6306     // Invoke it many times to compile a stub
   6307     "for (var i = 0; i < 7; i++) {"
   6308     "  if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
   6309     "}"
   6310     "this.y = function(x) { return x - 1; };"
   6311     "var result = 0;"
   6312     "for (var i = 0; i < 7; i++) {"
   6313     "  result += o.y(42);"
   6314     "}");
   6315   CHECK_EQ(41 * 7, value->Int32Value());
   6316 }
   6317 
   6318 
   6319 // Test the case when actual function to call sits on global object.
   6320 THREADED_TEST(InterceptorCallICCachedFromGlobal) {
   6321   v8::HandleScope scope;
   6322   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
   6323   templ_o->SetNamedPropertyHandler(NoBlockGetterX);
   6324 
   6325   LocalContext context;
   6326   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
   6327 
   6328   v8::Handle<Value> value = CompileRun(
   6329     "try {"
   6330     "  o.__proto__ = this;"
   6331     "  for (var i = 0; i < 10; i++) {"
   6332     "    var v = o.parseFloat('239');"
   6333     "    if (v != 239) throw v;"
   6334       // Now it should be ICed and keep a reference to parseFloat.
   6335     "  }"
   6336     "  var result = 0;"
   6337     "  for (var i = 0; i < 10; i++) {"
   6338     "    result += o.parseFloat('239');"
   6339     "  }"
   6340     "  result"
   6341     "} catch(e) {"
   6342     "  e"
   6343     "};");
   6344   CHECK_EQ(239 * 10, value->Int32Value());
   6345 }
   6346 
   6347 static v8::Handle<Value> InterceptorCallICFastApi(Local<String> name,
   6348                                                   const AccessorInfo& info) {
   6349   ApiTestFuzzer::Fuzz();
   6350   int* call_count = reinterpret_cast<int*>(v8::External::Unwrap(info.Data()));
   6351   ++(*call_count);
   6352   if ((*call_count) % 20 == 0) {
   6353     v8::internal::Heap::CollectAllGarbage(true);
   6354   }
   6355   return v8::Handle<Value>();
   6356 }
   6357 
   6358 static v8::Handle<Value> FastApiCallback_TrivialSignature(
   6359     const v8::Arguments& args) {
   6360   ApiTestFuzzer::Fuzz();
   6361   CHECK_EQ(args.This(), args.Holder());
   6362   CHECK(args.Data()->Equals(v8_str("method_data")));
   6363   return v8::Integer::New(args[0]->Int32Value() + 1);
   6364 }
   6365 
   6366 static v8::Handle<Value> FastApiCallback_SimpleSignature(
   6367     const v8::Arguments& args) {
   6368   ApiTestFuzzer::Fuzz();
   6369   CHECK_EQ(args.This()->GetPrototype(), args.Holder());
   6370   CHECK(args.Data()->Equals(v8_str("method_data")));
   6371   // Note, we're using HasRealNamedProperty instead of Has to avoid
   6372   // invoking the interceptor again.
   6373   CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
   6374   return v8::Integer::New(args[0]->Int32Value() + 1);
   6375 }
   6376 
   6377 // Helper to maximize the odds of object moving.
   6378 static void GenerateSomeGarbage() {
   6379   CompileRun(
   6380       "var garbage;"
   6381       "for (var i = 0; i < 1000; i++) {"
   6382       "  garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
   6383       "}"
   6384       "garbage = undefined;");
   6385 }
   6386 
   6387 THREADED_TEST(InterceptorCallICFastApi_TrivialSignature) {
   6388   int interceptor_call_count = 0;
   6389   v8::HandleScope scope;
   6390   v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
   6391   v8::Handle<v8::FunctionTemplate> method_templ =
   6392       v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
   6393                                 v8_str("method_data"),
   6394                                 v8::Handle<v8::Signature>());
   6395   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
   6396   proto_templ->Set(v8_str("method"), method_templ);
   6397   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
   6398   templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
   6399                                  NULL, NULL, NULL, NULL,
   6400                                  v8::External::Wrap(&interceptor_call_count));
   6401   LocalContext context;
   6402   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
   6403   GenerateSomeGarbage();
   6404   context->Global()->Set(v8_str("o"), fun->NewInstance());
   6405   v8::Handle<Value> value = CompileRun(
   6406       "var result = 0;"
   6407       "for (var i = 0; i < 100; i++) {"
   6408       "  result = o.method(41);"
   6409       "}");
   6410   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
   6411   CHECK_EQ(100, interceptor_call_count);
   6412 }
   6413 
   6414 THREADED_TEST(InterceptorCallICFastApi_SimpleSignature) {
   6415   int interceptor_call_count = 0;
   6416   v8::HandleScope scope;
   6417   v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
   6418   v8::Handle<v8::FunctionTemplate> method_templ =
   6419       v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
   6420                                 v8_str("method_data"),
   6421                                 v8::Signature::New(fun_templ));
   6422   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
   6423   proto_templ->Set(v8_str("method"), method_templ);
   6424   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
   6425   templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
   6426                                  NULL, NULL, NULL, NULL,
   6427                                  v8::External::Wrap(&interceptor_call_count));
   6428   LocalContext context;
   6429   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
   6430   GenerateSomeGarbage();
   6431   context->Global()->Set(v8_str("o"), fun->NewInstance());
   6432   v8::Handle<Value> value = CompileRun(
   6433       "o.foo = 17;"
   6434       "var receiver = {};"
   6435       "receiver.__proto__ = o;"
   6436       "var result = 0;"
   6437       "for (var i = 0; i < 100; i++) {"
   6438       "  result = receiver.method(41);"
   6439       "}");
   6440   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
   6441   CHECK_EQ(100, interceptor_call_count);
   6442 }
   6443 
   6444 THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
   6445   int interceptor_call_count = 0;
   6446   v8::HandleScope scope;
   6447   v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
   6448   v8::Handle<v8::FunctionTemplate> method_templ =
   6449       v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
   6450                                 v8_str("method_data"),
   6451                                 v8::Signature::New(fun_templ));
   6452   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
   6453   proto_templ->Set(v8_str("method"), method_templ);
   6454   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
   6455   templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
   6456                                  NULL, NULL, NULL, NULL,
   6457                                  v8::External::Wrap(&interceptor_call_count));
   6458   LocalContext context;
   6459   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
   6460   GenerateSomeGarbage();
   6461   context->Global()->Set(v8_str("o"), fun->NewInstance());
   6462   v8::Handle<Value> value = CompileRun(
   6463       "o.foo = 17;"
   6464       "var receiver = {};"
   6465       "receiver.__proto__ = o;"
   6466       "var result = 0;"
   6467       "var saved_result = 0;"
   6468       "for (var i = 0; i < 100; i++) {"
   6469       "  result = receiver.method(41);"
   6470       "  if (i == 50) {"
   6471       "    saved_result = result;"
   6472       "    receiver = {method: function(x) { return x - 1 }};"
   6473       "  }"
   6474       "}");
   6475   CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
   6476   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
   6477   CHECK_GE(interceptor_call_count, 50);
   6478 }
   6479 
   6480 THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
   6481   int interceptor_call_count = 0;
   6482   v8::HandleScope scope;
   6483   v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
   6484   v8::Handle<v8::FunctionTemplate> method_templ =
   6485       v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
   6486                                 v8_str("method_data"),
   6487                                 v8::Signature::New(fun_templ));
   6488   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
   6489   proto_templ->Set(v8_str("method"), method_templ);
   6490   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
   6491   templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
   6492                                  NULL, NULL, NULL, NULL,
   6493                                  v8::External::Wrap(&interceptor_call_count));
   6494   LocalContext context;
   6495   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
   6496   GenerateSomeGarbage();
   6497   context->Global()->Set(v8_str("o"), fun->NewInstance());
   6498   v8::Handle<Value> value = CompileRun(
   6499       "o.foo = 17;"
   6500       "var receiver = {};"
   6501       "receiver.__proto__ = o;"
   6502       "var result = 0;"
   6503       "var saved_result = 0;"
   6504       "for (var i = 0; i < 100; i++) {"
   6505       "  result = receiver.method(41);"
   6506       "  if (i == 50) {"
   6507       "    saved_result = result;"
   6508       "    o.method = function(x) { return x - 1 };"
   6509       "  }"
   6510       "}");
   6511   CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
   6512   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
   6513   CHECK_GE(interceptor_call_count, 50);
   6514 }
   6515 
   6516 THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
   6517   int interceptor_call_count = 0;
   6518   v8::HandleScope scope;
   6519   v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
   6520   v8::Handle<v8::FunctionTemplate> method_templ =
   6521       v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
   6522                                 v8_str("method_data"),
   6523                                 v8::Signature::New(fun_templ));
   6524   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
   6525   proto_templ->Set(v8_str("method"), method_templ);
   6526   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
   6527   templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
   6528                                  NULL, NULL, NULL, NULL,
   6529                                  v8::External::Wrap(&interceptor_call_count));
   6530   LocalContext context;
   6531   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
   6532   GenerateSomeGarbage();
   6533   context->Global()->Set(v8_str("o"), fun->NewInstance());
   6534   v8::TryCatch try_catch;
   6535   v8::Handle<Value> value = CompileRun(
   6536       "o.foo = 17;"
   6537       "var receiver = {};"
   6538       "receiver.__proto__ = o;"
   6539       "var result = 0;"
   6540       "var saved_result = 0;"
   6541       "for (var i = 0; i < 100; i++) {"
   6542       "  result = receiver.method(41);"
   6543       "  if (i == 50) {"
   6544       "    saved_result = result;"
   6545       "    receiver = {method: receiver.method};"
   6546       "  }"
   6547       "}");
   6548   CHECK(try_catch.HasCaught());
   6549   CHECK_EQ(v8_str("TypeError: Illegal invocation"),
   6550            try_catch.Exception()->ToString());
   6551   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
   6552   CHECK_GE(interceptor_call_count, 50);
   6553 }
   6554 
   6555 THREADED_TEST(CallICFastApi_TrivialSignature) {
   6556   v8::HandleScope scope;
   6557   v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
   6558   v8::Handle<v8::FunctionTemplate> method_templ =
   6559       v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
   6560                                 v8_str("method_data"),
   6561                                 v8::Handle<v8::Signature>());
   6562   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
   6563   proto_templ->Set(v8_str("method"), method_templ);
   6564   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
   6565   LocalContext context;
   6566   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
   6567   GenerateSomeGarbage();
   6568   context->Global()->Set(v8_str("o"), fun->NewInstance());
   6569   v8::Handle<Value> value = CompileRun(
   6570       "var result = 0;"
   6571       "for (var i = 0; i < 100; i++) {"
   6572       "  result = o.method(41);"
   6573       "}");
   6574 
   6575   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
   6576 }
   6577 
   6578 THREADED_TEST(CallICFastApi_SimpleSignature) {
   6579   v8::HandleScope scope;
   6580   v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
   6581   v8::Handle<v8::FunctionTemplate> method_templ =
   6582       v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
   6583                                 v8_str("method_data"),
   6584                                 v8::Signature::New(fun_templ));
   6585   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
   6586   proto_templ->Set(v8_str("method"), method_templ);
   6587   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
   6588   LocalContext context;
   6589   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
   6590   GenerateSomeGarbage();
   6591   context->Global()->Set(v8_str("o"), fun->NewInstance());
   6592   v8::Handle<Value> value = CompileRun(
   6593       "o.foo = 17;"
   6594       "var receiver = {};"
   6595       "receiver.__proto__ = o;"
   6596       "var result = 0;"
   6597       "for (var i = 0; i < 100; i++) {"
   6598       "  result = receiver.method(41);"
   6599       "}");
   6600 
   6601   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
   6602 }
   6603 
   6604 THREADED_TEST(CallICFastApi_SimpleSignature_Miss) {
   6605   v8::HandleScope scope;
   6606   v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
   6607   v8::Handle<v8::FunctionTemplate> method_templ =
   6608       v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
   6609                                 v8_str("method_data"),
   6610                                 v8::Signature::New(fun_templ));
   6611   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
   6612   proto_templ->Set(v8_str("method"), method_templ);
   6613   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
   6614   LocalContext context;
   6615   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
   6616   GenerateSomeGarbage();
   6617   context->Global()->Set(v8_str("o"), fun->NewInstance());
   6618   v8::Handle<Value> value = CompileRun(
   6619       "o.foo = 17;"
   6620       "var receiver = {};"
   6621       "receiver.__proto__ = o;"
   6622       "var result = 0;"
   6623       "var saved_result = 0;"
   6624       "for (var i = 0; i < 100; i++) {"
   6625       "  result = receiver.method(41);"
   6626       "  if (i == 50) {"
   6627       "    saved_result = result;"
   6628       "    receiver = {method: function(x) { return x - 1 }};"
   6629       "  }"
   6630       "}");
   6631   CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
   6632   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
   6633 }
   6634 
   6635 
   6636 static int interceptor_call_count = 0;
   6637 
   6638 static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name,
   6639                                                      const AccessorInfo& info) {
   6640   ApiTestFuzzer::Fuzz();
   6641   if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
   6642     return call_ic_function2;
   6643   }
   6644   return v8::Handle<Value>();
   6645 }
   6646 
   6647 
   6648 // This test should hit load and call ICs for the interceptor case.
   6649 // Once in a while, the interceptor will reply that a property was not
   6650 // found in which case we should get a reference error.
   6651 THREADED_TEST(InterceptorICReferenceErrors) {
   6652   v8::HandleScope scope;
   6653   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
   6654   templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
   6655   LocalContext context(0, templ, v8::Handle<Value>());
   6656   call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
   6657   v8::Handle<Value> value = CompileRun(
   6658     "function f() {"
   6659     "  for (var i = 0; i < 1000; i++) {"
   6660     "    try { x; } catch(e) { return true; }"
   6661     "  }"
   6662     "  return false;"
   6663     "};"
   6664     "f();");
   6665   CHECK_EQ(true, value->BooleanValue());
   6666   interceptor_call_count = 0;
   6667   value = CompileRun(
   6668     "function g() {"
   6669     "  for (var i = 0; i < 1000; i++) {"
   6670     "    try { x(42); } catch(e) { return true; }"
   6671     "  }"
   6672     "  return false;"
   6673     "};"
   6674     "g();");
   6675   CHECK_EQ(true, value->BooleanValue());
   6676 }
   6677 
   6678 
   6679 static int interceptor_ic_exception_get_count = 0;
   6680 
   6681 static v8::Handle<Value> InterceptorICExceptionGetter(
   6682     Local<String> name,
   6683     const AccessorInfo& info) {
   6684   ApiTestFuzzer::Fuzz();
   6685   if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
   6686     return call_ic_function3;
   6687   }
   6688   if (interceptor_ic_exception_get_count == 20) {
   6689     return v8::ThrowException(v8_num(42));
   6690   }
   6691   // Do not handle get for properties other than x.
   6692   return v8::Handle<Value>();
   6693 }
   6694 
   6695 // Test interceptor load/call IC where the interceptor throws an
   6696 // exception once in a while.
   6697 THREADED_TEST(InterceptorICGetterExceptions) {
   6698   interceptor_ic_exception_get_count = 0;
   6699   v8::HandleScope scope;
   6700   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
   6701   templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
   6702   LocalContext context(0, templ, v8::Handle<Value>());
   6703   call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
   6704   v8::Handle<Value> value = CompileRun(
   6705     "function f() {"
   6706     "  for (var i = 0; i < 100; i++) {"
   6707     "    try { x; } catch(e) { return true; }"
   6708     "  }"
   6709     "  return false;"
   6710     "};"
   6711     "f();");
   6712   CHECK_EQ(true, value->BooleanValue());
   6713   interceptor_ic_exception_get_count = 0;
   6714   value = CompileRun(
   6715     "function f() {"
   6716     "  for (var i = 0; i < 100; i++) {"
   6717     "    try { x(42); } catch(e) { return true; }"
   6718     "  }"
   6719     "  return false;"
   6720     "};"
   6721     "f();");
   6722   CHECK_EQ(true, value->BooleanValue());
   6723 }
   6724 
   6725 
   6726 static int interceptor_ic_exception_set_count = 0;
   6727 
   6728 static v8::Handle<Value> InterceptorICExceptionSetter(
   6729       Local<String> key, Local<Value> value, const AccessorInfo&) {
   6730   ApiTestFuzzer::Fuzz();
   6731   if (++interceptor_ic_exception_set_count > 20) {
   6732     return v8::ThrowException(v8_num(42));
   6733   }
   6734   // Do not actually handle setting.
   6735   return v8::Handle<Value>();
   6736 }
   6737 
   6738 // Test interceptor store IC where the interceptor throws an exception
   6739 // once in a while.
   6740 THREADED_TEST(InterceptorICSetterExceptions) {
   6741   interceptor_ic_exception_set_count = 0;
   6742   v8::HandleScope scope;
   6743   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
   6744   templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
   6745   LocalContext context(0, templ, v8::Handle<Value>());
   6746   v8::Handle<Value> value = CompileRun(
   6747     "function f() {"
   6748     "  for (var i = 0; i < 100; i++) {"
   6749     "    try { x = 42; } catch(e) { return true; }"
   6750     "  }"
   6751     "  return false;"
   6752     "};"
   6753     "f();");
   6754   CHECK_EQ(true, value->BooleanValue());
   6755 }
   6756 
   6757 
   6758 // Test that we ignore null interceptors.
   6759 THREADED_TEST(NullNamedInterceptor) {
   6760   v8::HandleScope scope;
   6761   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
   6762   templ->SetNamedPropertyHandler(0);
   6763   LocalContext context;
   6764   templ->Set("x", v8_num(42));
   6765   v8::Handle<v8::Object> obj = templ->NewInstance();
   6766   context->Global()->Set(v8_str("obj"), obj);
   6767   v8::Handle<Value> value = CompileRun("obj.x");
   6768   CHECK(value->IsInt32());
   6769   CHECK_EQ(42, value->Int32Value());
   6770 }
   6771 
   6772 
   6773 // Test that we ignore null interceptors.
   6774 THREADED_TEST(NullIndexedInterceptor) {
   6775   v8::HandleScope scope;
   6776   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
   6777   templ->SetIndexedPropertyHandler(0);
   6778   LocalContext context;
   6779   templ->Set("42", v8_num(42));
   6780   v8::Handle<v8::Object> obj = templ->NewInstance();
   6781   context->Global()->Set(v8_str("obj"), obj);
   6782   v8::Handle<Value> value = CompileRun("obj[42]");
   6783   CHECK(value->IsInt32());
   6784   CHECK_EQ(42, value->Int32Value());
   6785 }
   6786 
   6787 
   6788 static v8::Handle<Value> ParentGetter(Local<String> name,
   6789                                       const AccessorInfo& info) {
   6790   ApiTestFuzzer::Fuzz();
   6791   return v8_num(1);
   6792 }
   6793 
   6794 
   6795 static v8::Handle<Value> ChildGetter(Local<String> name,
   6796                                      const AccessorInfo& info) {
   6797   ApiTestFuzzer::Fuzz();
   6798   return v8_num(42);
   6799 }
   6800 
   6801 
   6802 THREADED_TEST(Overriding) {
   6803   v8::HandleScope scope;
   6804   LocalContext context;
   6805 
   6806   // Parent template.
   6807   Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New();
   6808   Local<ObjectTemplate> parent_instance_templ =
   6809       parent_templ->InstanceTemplate();
   6810   parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
   6811 
   6812   // Template that inherits from the parent template.
   6813   Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New();
   6814   Local<ObjectTemplate> child_instance_templ =
   6815       child_templ->InstanceTemplate();
   6816   child_templ->Inherit(parent_templ);
   6817   // Override 'f'.  The child version of 'f' should get called for child
   6818   // instances.
   6819   child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
   6820   // Add 'g' twice.  The 'g' added last should get called for instances.
   6821   child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
   6822   child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
   6823 
   6824   // Add 'h' as an accessor to the proto template with ReadOnly attributes
   6825   // so 'h' can be shadowed on the instance object.
   6826   Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
   6827   child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
   6828       v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
   6829 
   6830   // Add 'i' as an accessor to the instance template with ReadOnly attributes
   6831   // but the attribute does not have effect because it is duplicated with
   6832   // NULL setter.
   6833   child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
   6834       v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
   6835 
   6836 
   6837 
   6838   // Instantiate the child template.
   6839   Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
   6840 
   6841   // Check that the child function overrides the parent one.
   6842   context->Global()->Set(v8_str("o"), instance);
   6843   Local<Value> value = v8_compile("o.f")->Run();
   6844   // Check that the 'g' that was added last is hit.
   6845   CHECK_EQ(42, value->Int32Value());
   6846   value = v8_compile("o.g")->Run();
   6847   CHECK_EQ(42, value->Int32Value());
   6848 
   6849   // Check 'h' can be shadowed.
   6850   value = v8_compile("o.h = 3; o.h")->Run();
   6851   CHECK_EQ(3, value->Int32Value());
   6852 
   6853   // Check 'i' is cannot be shadowed or changed.
   6854   value = v8_compile("o.i = 3; o.i")->Run();
   6855   CHECK_EQ(42, value->Int32Value());
   6856 }
   6857 
   6858 
   6859 static v8::Handle<Value> IsConstructHandler(const v8::Arguments& args) {
   6860   ApiTestFuzzer::Fuzz();
   6861   if (args.IsConstructCall()) {
   6862     return v8::Boolean::New(true);
   6863   }
   6864   return v8::Boolean::New(false);
   6865 }
   6866 
   6867 
   6868 THREADED_TEST(IsConstructCall) {
   6869   v8::HandleScope scope;
   6870 
   6871   // Function template with call handler.
   6872   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
   6873   templ->SetCallHandler(IsConstructHandler);
   6874 
   6875   LocalContext context;
   6876 
   6877   context->Global()->Set(v8_str("f"), templ->GetFunction());
   6878   Local<Value> value = v8_compile("f()")->Run();
   6879   CHECK(!value->BooleanValue());
   6880   value = v8_compile("new f()")->Run();
   6881   CHECK(value->BooleanValue());
   6882 }
   6883 
   6884 
   6885 THREADED_TEST(ObjectProtoToString) {
   6886   v8::HandleScope scope;
   6887   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
   6888   templ->SetClassName(v8_str("MyClass"));
   6889 
   6890   LocalContext context;
   6891 
   6892   Local<String> customized_tostring = v8_str("customized toString");
   6893 
   6894   // Replace Object.prototype.toString
   6895   v8_compile("Object.prototype.toString = function() {"
   6896                   "  return 'customized toString';"
   6897                   "}")->Run();
   6898 
   6899   // Normal ToString call should call replaced Object.prototype.toString
   6900   Local<v8::Object> instance = templ->GetFunction()->NewInstance();
   6901   Local<String> value = instance->ToString();
   6902   CHECK(value->IsString() && value->Equals(customized_tostring));
   6903 
   6904   // ObjectProtoToString should not call replace toString function.
   6905   value = instance->ObjectProtoToString();
   6906   CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
   6907 
   6908   // Check global
   6909   value = context->Global()->ObjectProtoToString();
   6910   CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
   6911 
   6912   // Check ordinary object
   6913   Local<Value> object = v8_compile("new Object()")->Run();
   6914   value = Local<v8::Object>::Cast(object)->ObjectProtoToString();
   6915   CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
   6916 }
   6917 
   6918 
   6919 bool ApiTestFuzzer::fuzzing_ = false;
   6920 v8::internal::Semaphore* ApiTestFuzzer::all_tests_done_=
   6921   v8::internal::OS::CreateSemaphore(0);
   6922 int ApiTestFuzzer::active_tests_;
   6923 int ApiTestFuzzer::tests_being_run_;
   6924 int ApiTestFuzzer::current_;
   6925 
   6926 
   6927 // We are in a callback and want to switch to another thread (if we
   6928 // are currently running the thread fuzzing test).
   6929 void ApiTestFuzzer::Fuzz() {
   6930   if (!fuzzing_) return;
   6931   ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
   6932   test->ContextSwitch();
   6933 }
   6934 
   6935 
   6936 // Let the next thread go.  Since it is also waiting on the V8 lock it may
   6937 // not start immediately.
   6938 bool ApiTestFuzzer::NextThread() {
   6939   int test_position = GetNextTestNumber();
   6940   const char* test_name = RegisterThreadedTest::nth(current_)->name();
   6941   if (test_position == current_) {
   6942     if (kLogThreading)
   6943       printf("Stay with %s\n", test_name);
   6944     return false;
   6945   }
   6946   if (kLogThreading) {
   6947     printf("Switch from %s to %s\n",
   6948            test_name,
   6949            RegisterThreadedTest::nth(test_position)->name());
   6950   }
   6951   current_ = test_position;
   6952   RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal();
   6953   return true;
   6954 }
   6955 
   6956 
   6957 void ApiTestFuzzer::Run() {
   6958   // When it is our turn...
   6959   gate_->Wait();
   6960   {
   6961     // ... get the V8 lock and start running the test.
   6962     v8::Locker locker;
   6963     CallTest();
   6964   }
   6965   // This test finished.
   6966   active_ = false;
   6967   active_tests_--;
   6968   // If it was the last then signal that fact.
   6969   if (active_tests_ == 0) {
   6970     all_tests_done_->Signal();
   6971   } else {
   6972     // Otherwise select a new test and start that.
   6973     NextThread();
   6974   }
   6975 }
   6976 
   6977 
   6978 static unsigned linear_congruential_generator;
   6979 
   6980 
   6981 void ApiTestFuzzer::Setup(PartOfTest part) {
   6982   linear_congruential_generator = i::FLAG_testing_prng_seed;
   6983   fuzzing_ = true;
   6984   int start = (part == FIRST_PART) ? 0 : (RegisterThreadedTest::count() >> 1);
   6985   int end = (part == FIRST_PART)
   6986       ? (RegisterThreadedTest::count() >> 1)
   6987       : RegisterThreadedTest::count();
   6988   active_tests_ = tests_being_run_ = end - start;
   6989   for (int i = 0; i < tests_being_run_; i++) {
   6990     RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
   6991   }
   6992   for (int i = 0; i < active_tests_; i++) {
   6993     RegisterThreadedTest::nth(i)->fuzzer_->Start();
   6994   }
   6995 }
   6996 
   6997 
   6998 static void CallTestNumber(int test_number) {
   6999   (RegisterThreadedTest::nth(test_number)->callback())();
   7000 }
   7001 
   7002 
   7003 void ApiTestFuzzer::RunAllTests() {
   7004   // Set off the first test.
   7005   current_ = -1;
   7006   NextThread();
   7007   // Wait till they are all done.
   7008   all_tests_done_->Wait();
   7009 }
   7010 
   7011 
   7012 int ApiTestFuzzer::GetNextTestNumber() {
   7013   int next_test;
   7014   do {
   7015     next_test = (linear_congruential_generator >> 16) % tests_being_run_;
   7016     linear_congruential_generator *= 1664525u;
   7017     linear_congruential_generator += 1013904223u;
   7018   } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
   7019   return next_test;
   7020 }
   7021 
   7022 
   7023 void ApiTestFuzzer::ContextSwitch() {
   7024   // If the new thread is the same as the current thread there is nothing to do.
   7025   if (NextThread()) {
   7026     // Now it can start.
   7027     v8::Unlocker unlocker;
   7028     // Wait till someone starts us again.
   7029     gate_->Wait();
   7030     // And we're off.
   7031   }
   7032 }
   7033 
   7034 
   7035 void ApiTestFuzzer::TearDown() {
   7036   fuzzing_ = false;
   7037   for (int i = 0; i < RegisterThreadedTest::count(); i++) {
   7038     ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
   7039     if (fuzzer != NULL) fuzzer->Join();
   7040   }
   7041 }
   7042 
   7043 
   7044 // Lets not be needlessly self-referential.
   7045 TEST(Threading) {
   7046   ApiTestFuzzer::Setup(ApiTestFuzzer::FIRST_PART);
   7047   ApiTestFuzzer::RunAllTests();
   7048   ApiTestFuzzer::TearDown();
   7049 }
   7050 
   7051 TEST(Threading2) {
   7052   ApiTestFuzzer::Setup(ApiTestFuzzer::SECOND_PART);
   7053   ApiTestFuzzer::RunAllTests();
   7054   ApiTestFuzzer::TearDown();
   7055 }
   7056 
   7057 
   7058 void ApiTestFuzzer::CallTest() {
   7059   if (kLogThreading)
   7060     printf("Start test %d\n", test_number_);
   7061   CallTestNumber(test_number_);
   7062   if (kLogThreading)
   7063     printf("End test %d\n", test_number_);
   7064 }
   7065 
   7066 
   7067 static v8::Handle<Value> ThrowInJS(const v8::Arguments& args) {
   7068   CHECK(v8::Locker::IsLocked());
   7069   ApiTestFuzzer::Fuzz();
   7070   v8::Unlocker unlocker;
   7071   const char* code = "throw 7;";
   7072   {
   7073     v8::Locker nested_locker;
   7074     v8::HandleScope scope;
   7075     v8::Handle<Value> exception;
   7076     { v8::TryCatch try_catch;
   7077       v8::Handle<Value> value = CompileRun(code);
   7078       CHECK(value.IsEmpty());
   7079       CHECK(try_catch.HasCaught());
   7080       // Make sure to wrap the exception in a new handle because
   7081       // the handle returned from the TryCatch is destroyed
   7082       // when the TryCatch is destroyed.
   7083       exception = Local<Value>::New(try_catch.Exception());
   7084     }
   7085     return v8::ThrowException(exception);
   7086   }
   7087 }
   7088 
   7089 
   7090 static v8::Handle<Value> ThrowInJSNoCatch(const v8::Arguments& args) {
   7091   CHECK(v8::Locker::IsLocked());
   7092   ApiTestFuzzer::Fuzz();
   7093   v8::Unlocker unlocker;
   7094   const char* code = "throw 7;";
   7095   {
   7096     v8::Locker nested_locker;
   7097     v8::HandleScope scope;
   7098     v8::Handle<Value> value = CompileRun(code);
   7099     CHECK(value.IsEmpty());
   7100     return v8_str("foo");
   7101   }
   7102 }
   7103 
   7104 
   7105 // These are locking tests that don't need to be run again
   7106 // as part of the locking aggregation tests.
   7107 TEST(NestedLockers) {
   7108   v8::Locker locker;
   7109   CHECK(v8::Locker::IsLocked());
   7110   v8::HandleScope scope;
   7111   LocalContext env;
   7112   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS);
   7113   Local<Function> fun = fun_templ->GetFunction();
   7114   env->Global()->Set(v8_str("throw_in_js"), fun);
   7115   Local<Script> script = v8_compile("(function () {"
   7116                                     "  try {"
   7117                                     "    throw_in_js();"
   7118                                     "    return 42;"
   7119                                     "  } catch (e) {"
   7120                                     "    return e * 13;"
   7121                                     "  }"
   7122                                     "})();");
   7123   CHECK_EQ(91, script->Run()->Int32Value());
   7124 }
   7125 
   7126 
   7127 // These are locking tests that don't need to be run again
   7128 // as part of the locking aggregation tests.
   7129 TEST(NestedLockersNoTryCatch) {
   7130   v8::Locker locker;
   7131   v8::HandleScope scope;
   7132   LocalContext env;
   7133   Local<v8::FunctionTemplate> fun_templ =
   7134       v8::FunctionTemplate::New(ThrowInJSNoCatch);
   7135   Local<Function> fun = fun_templ->GetFunction();
   7136   env->Global()->Set(v8_str("throw_in_js"), fun);
   7137   Local<Script> script = v8_compile("(function () {"
   7138                                     "  try {"
   7139                                     "    throw_in_js();"
   7140                                     "    return 42;"
   7141                                     "  } catch (e) {"
   7142                                     "    return e * 13;"
   7143                                     "  }"
   7144                                     "})();");
   7145   CHECK_EQ(91, script->Run()->Int32Value());
   7146 }
   7147 
   7148 
   7149 THREADED_TEST(RecursiveLocking) {
   7150   v8::Locker locker;
   7151   {
   7152     v8::Locker locker2;
   7153     CHECK(v8::Locker::IsLocked());
   7154   }
   7155 }
   7156 
   7157 
   7158 static v8::Handle<Value> UnlockForAMoment(const v8::Arguments& args) {
   7159   ApiTestFuzzer::Fuzz();
   7160   v8::Unlocker unlocker;
   7161   return v8::Undefined();
   7162 }
   7163 
   7164 
   7165 THREADED_TEST(LockUnlockLock) {
   7166   {
   7167     v8::Locker locker;
   7168     v8::HandleScope scope;
   7169     LocalContext env;
   7170     Local<v8::FunctionTemplate> fun_templ =
   7171         v8::FunctionTemplate::New(UnlockForAMoment);
   7172     Local<Function> fun = fun_templ->GetFunction();
   7173     env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
   7174     Local<Script> script = v8_compile("(function () {"
   7175                                       "  unlock_for_a_moment();"
   7176                                       "  return 42;"
   7177                                       "})();");
   7178     CHECK_EQ(42, script->Run()->Int32Value());
   7179   }
   7180   {
   7181     v8::Locker locker;
   7182     v8::HandleScope scope;
   7183     LocalContext env;
   7184     Local<v8::FunctionTemplate> fun_templ =
   7185         v8::FunctionTemplate::New(UnlockForAMoment);
   7186     Local<Function> fun = fun_templ->GetFunction();
   7187     env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
   7188     Local<Script> script = v8_compile("(function () {"
   7189                                       "  unlock_for_a_moment();"
   7190                                       "  return 42;"
   7191                                       "})();");
   7192     CHECK_EQ(42, script->Run()->Int32Value());
   7193   }
   7194 }
   7195 
   7196 
   7197 static int GetGlobalObjectsCount() {
   7198   int count = 0;
   7199   v8::internal::HeapIterator it;
   7200   for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
   7201     if (object->IsJSGlobalObject()) count++;
   7202   return count;
   7203 }
   7204 
   7205 
   7206 static int GetSurvivingGlobalObjectsCount() {
   7207   // We need to collect all garbage twice to be sure that everything
   7208   // has been collected.  This is because inline caches are cleared in
   7209   // the first garbage collection but some of the maps have already
   7210   // been marked at that point.  Therefore some of the maps are not
   7211   // collected until the second garbage collection.
   7212   v8::internal::Heap::CollectAllGarbage(false);
   7213   v8::internal::Heap::CollectAllGarbage(false);
   7214   int count = GetGlobalObjectsCount();
   7215 #ifdef DEBUG
   7216   if (count > 0) v8::internal::Heap::TracePathToGlobal();
   7217 #endif
   7218   return count;
   7219 }
   7220 
   7221 
   7222 TEST(DontLeakGlobalObjects) {
   7223   // Regression test for issues 1139850 and 1174891.
   7224 
   7225   v8::V8::Initialize();
   7226 
   7227   int count = GetSurvivingGlobalObjectsCount();
   7228 
   7229   for (int i = 0; i < 5; i++) {
   7230     { v8::HandleScope scope;
   7231       LocalContext context;
   7232     }
   7233     CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
   7234 
   7235     { v8::HandleScope scope;
   7236       LocalContext context;
   7237       v8_compile("Date")->Run();
   7238     }
   7239     CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
   7240 
   7241     { v8::HandleScope scope;
   7242       LocalContext context;
   7243       v8_compile("/aaa/")->Run();
   7244     }
   7245     CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
   7246 
   7247     { v8::HandleScope scope;
   7248       const char* extension_list[] = { "v8/gc" };
   7249       v8::ExtensionConfiguration extensions(1, extension_list);
   7250       LocalContext context(&extensions);
   7251       v8_compile("gc();")->Run();
   7252     }
   7253     CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
   7254   }
   7255 }
   7256 
   7257 
   7258 v8::Persistent<v8::Object> some_object;
   7259 v8::Persistent<v8::Object> bad_handle;
   7260 
   7261 void NewPersistentHandleCallback(v8::Persistent<v8::Value>, void*) {
   7262   v8::HandleScope scope;
   7263   bad_handle = v8::Persistent<v8::Object>::New(some_object);
   7264 }
   7265 
   7266 
   7267 THREADED_TEST(NewPersistentHandleFromWeakCallback) {
   7268   LocalContext context;
   7269 
   7270   v8::Persistent<v8::Object> handle1, handle2;
   7271   {
   7272     v8::HandleScope scope;
   7273     some_object = v8::Persistent<v8::Object>::New(v8::Object::New());
   7274     handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
   7275     handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
   7276   }
   7277   // Note: order is implementation dependent alas: currently
   7278   // global handle nodes are processed by PostGarbageCollectionProcessing
   7279   // in reverse allocation order, so if second allocated handle is deleted,
   7280   // weak callback of the first handle would be able to 'reallocate' it.
   7281   handle1.MakeWeak(NULL, NewPersistentHandleCallback);
   7282   handle2.Dispose();
   7283   i::Heap::CollectAllGarbage(false);
   7284 }
   7285 
   7286 
   7287 v8::Persistent<v8::Object> to_be_disposed;
   7288 
   7289 void DisposeAndForceGcCallback(v8::Persistent<v8::Value> handle, void*) {
   7290   to_be_disposed.Dispose();
   7291   i::Heap::CollectAllGarbage(false);
   7292 }
   7293 
   7294 
   7295 THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
   7296   LocalContext context;
   7297 
   7298   v8::Persistent<v8::Object> handle1, handle2;
   7299   {
   7300     v8::HandleScope scope;
   7301     handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
   7302     handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
   7303   }
   7304   handle1.MakeWeak(NULL, DisposeAndForceGcCallback);
   7305   to_be_disposed = handle2;
   7306   i::Heap::CollectAllGarbage(false);
   7307 }
   7308 
   7309 void DisposingCallback(v8::Persistent<v8::Value> handle, void*) {
   7310   handle.Dispose();
   7311 }
   7312 
   7313 void HandleCreatingCallback(v8::Persistent<v8::Value> handle, void*) {
   7314   v8::HandleScope scope;
   7315   v8::Persistent<v8::Object>::New(v8::Object::New());
   7316 }
   7317 
   7318 
   7319 THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
   7320   LocalContext context;
   7321 
   7322   v8::Persistent<v8::Object> handle1, handle2, handle3;
   7323   {
   7324     v8::HandleScope scope;
   7325     handle3 = v8::Persistent<v8::Object>::New(v8::Object::New());
   7326     handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
   7327     handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
   7328   }
   7329   handle2.MakeWeak(NULL, DisposingCallback);
   7330   handle3.MakeWeak(NULL, HandleCreatingCallback);
   7331   i::Heap::CollectAllGarbage(false);
   7332 }
   7333 
   7334 
   7335 THREADED_TEST(CheckForCrossContextObjectLiterals) {
   7336   v8::V8::Initialize();
   7337 
   7338   const int nof = 2;
   7339   const char* sources[nof] = {
   7340     "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
   7341     "Object()"
   7342   };
   7343 
   7344   for (int i = 0; i < nof; i++) {
   7345     const char* source = sources[i];
   7346     { v8::HandleScope scope;
   7347       LocalContext context;
   7348       CompileRun(source);
   7349     }
   7350     { v8::HandleScope scope;
   7351       LocalContext context;
   7352       CompileRun(source);
   7353     }
   7354   }
   7355 }
   7356 
   7357 
   7358 static v8::Handle<Value> NestedScope(v8::Persistent<Context> env) {
   7359   v8::HandleScope inner;
   7360   env->Enter();
   7361   v8::Handle<Value> three = v8_num(3);
   7362   v8::Handle<Value> value = inner.Close(three);
   7363   env->Exit();
   7364   return value;
   7365 }
   7366 
   7367 
   7368 THREADED_TEST(NestedHandleScopeAndContexts) {
   7369   v8::HandleScope outer;
   7370   v8::Persistent<Context> env = Context::New();
   7371   env->Enter();
   7372   v8::Handle<Value> value = NestedScope(env);
   7373   v8::Handle<String> str = value->ToString();
   7374   env->Exit();
   7375   env.Dispose();
   7376 }
   7377 
   7378 
   7379 THREADED_TEST(ExternalAllocatedMemory) {
   7380   v8::HandleScope outer;
   7381   v8::Persistent<Context> env = Context::New();
   7382   const int kSize = 1024*1024;
   7383   CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize), kSize);
   7384   CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize), 0);
   7385 }
   7386 
   7387 
   7388 THREADED_TEST(DisposeEnteredContext) {
   7389   v8::HandleScope scope;
   7390   LocalContext outer;
   7391   { v8::Persistent<v8::Context> inner = v8::Context::New();
   7392     inner->Enter();
   7393     inner.Dispose();
   7394     inner.Clear();
   7395     inner->Exit();
   7396   }
   7397 }
   7398 
   7399 
   7400 // Regression test for issue 54, object templates with internal fields
   7401 // but no accessors or interceptors did not get their internal field
   7402 // count set on instances.
   7403 THREADED_TEST(Regress54) {
   7404   v8::HandleScope outer;
   7405   LocalContext context;
   7406   static v8::Persistent<v8::ObjectTemplate> templ;
   7407   if (templ.IsEmpty()) {
   7408     v8::HandleScope inner;
   7409     v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New();
   7410     local->SetInternalFieldCount(1);
   7411     templ = v8::Persistent<v8::ObjectTemplate>::New(inner.Close(local));
   7412   }
   7413   v8::Handle<v8::Object> result = templ->NewInstance();
   7414   CHECK_EQ(1, result->InternalFieldCount());
   7415 }
   7416 
   7417 
   7418 // If part of the threaded tests, this test makes ThreadingTest fail
   7419 // on mac.
   7420 TEST(CatchStackOverflow) {
   7421   v8::HandleScope scope;
   7422   LocalContext context;
   7423   v8::TryCatch try_catch;
   7424   v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(
   7425     "function f() {"
   7426     "  return f();"
   7427     "}"
   7428     ""
   7429     "f();"));
   7430   v8::Handle<v8::Value> result = script->Run();
   7431   CHECK(result.IsEmpty());
   7432 }
   7433 
   7434 
   7435 static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
   7436                                     const char* resource_name,
   7437                                     int line_offset) {
   7438   v8::HandleScope scope;
   7439   v8::TryCatch try_catch;
   7440   v8::Handle<v8::Value> result = script->Run();
   7441   CHECK(result.IsEmpty());
   7442   CHECK(try_catch.HasCaught());
   7443   v8::Handle<v8::Message> message = try_catch.Message();
   7444   CHECK(!message.IsEmpty());
   7445   CHECK_EQ(10 + line_offset, message->GetLineNumber());
   7446   CHECK_EQ(91, message->GetStartPosition());
   7447   CHECK_EQ(92, message->GetEndPosition());
   7448   CHECK_EQ(2, message->GetStartColumn());
   7449   CHECK_EQ(3, message->GetEndColumn());
   7450   v8::String::AsciiValue line(message->GetSourceLine());
   7451   CHECK_EQ("  throw 'nirk';", *line);
   7452   v8::String::AsciiValue name(message->GetScriptResourceName());
   7453   CHECK_EQ(resource_name, *name);
   7454 }
   7455 
   7456 
   7457 THREADED_TEST(TryCatchSourceInfo) {
   7458   v8::HandleScope scope;
   7459   LocalContext context;
   7460   v8::Handle<v8::String> source = v8::String::New(
   7461       "function Foo() {\n"
   7462       "  return Bar();\n"
   7463       "}\n"
   7464       "\n"
   7465       "function Bar() {\n"
   7466       "  return Baz();\n"
   7467       "}\n"
   7468       "\n"
   7469       "function Baz() {\n"
   7470       "  throw 'nirk';\n"
   7471       "}\n"
   7472       "\n"
   7473       "Foo();\n");
   7474 
   7475   const char* resource_name;
   7476   v8::Handle<v8::Script> script;
   7477   resource_name = "test.js";
   7478   script = v8::Script::Compile(source, v8::String::New(resource_name));
   7479   CheckTryCatchSourceInfo(script, resource_name, 0);
   7480 
   7481   resource_name = "test1.js";
   7482   v8::ScriptOrigin origin1(v8::String::New(resource_name));
   7483   script = v8::Script::Compile(source, &origin1);
   7484   CheckTryCatchSourceInfo(script, resource_name, 0);
   7485 
   7486   resource_name = "test2.js";
   7487   v8::ScriptOrigin origin2(v8::String::New(resource_name), v8::Integer::New(7));
   7488   script = v8::Script::Compile(source, &origin2);
   7489   CheckTryCatchSourceInfo(script, resource_name, 7);
   7490 }
   7491 
   7492 
   7493 THREADED_TEST(CompilationCache) {
   7494   v8::HandleScope scope;
   7495   LocalContext context;
   7496   v8::Handle<v8::String> source0 = v8::String::New("1234");
   7497   v8::Handle<v8::String> source1 = v8::String::New("1234");
   7498   v8::Handle<v8::Script> script0 =
   7499       v8::Script::Compile(source0, v8::String::New("test.js"));
   7500   v8::Handle<v8::Script> script1 =
   7501       v8::Script::Compile(source1, v8::String::New("test.js"));
   7502   v8::Handle<v8::Script> script2 =
   7503       v8::Script::Compile(source0);  // different origin
   7504   CHECK_EQ(1234, script0->Run()->Int32Value());
   7505   CHECK_EQ(1234, script1->Run()->Int32Value());
   7506   CHECK_EQ(1234, script2->Run()->Int32Value());
   7507 }
   7508 
   7509 
   7510 static v8::Handle<Value> FunctionNameCallback(const v8::Arguments& args) {
   7511   ApiTestFuzzer::Fuzz();
   7512   return v8_num(42);
   7513 }
   7514 
   7515 
   7516 THREADED_TEST(CallbackFunctionName) {
   7517   v8::HandleScope scope;
   7518   LocalContext context;
   7519   Local<ObjectTemplate> t = ObjectTemplate::New();
   7520   t->Set(v8_str("asdf"), v8::FunctionTemplate::New(FunctionNameCallback));
   7521   context->Global()->Set(v8_str("obj"), t->NewInstance());
   7522   v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
   7523   CHECK(value->IsString());
   7524   v8::String::AsciiValue name(value);
   7525   CHECK_EQ("asdf", *name);
   7526 }
   7527 
   7528 
   7529 THREADED_TEST(DateAccess) {
   7530   v8::HandleScope scope;
   7531   LocalContext context;
   7532   v8::Handle<v8::Value> date = v8::Date::New(1224744689038.0);
   7533   CHECK(date->IsDate());
   7534   CHECK_EQ(1224744689038.0, v8::Handle<v8::Date>::Cast(date)->NumberValue());
   7535 }
   7536 
   7537 
   7538 void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) {
   7539   v8::Handle<v8::Object> obj = v8::Handle<v8::Object>::Cast(val);
   7540   v8::Handle<v8::Array> props = obj->GetPropertyNames();
   7541   CHECK_EQ(elmc, props->Length());
   7542   for (int i = 0; i < elmc; i++) {
   7543     v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
   7544     CHECK_EQ(elmv[i], *elm);
   7545   }
   7546 }
   7547 
   7548 
   7549 THREADED_TEST(PropertyEnumeration) {
   7550   v8::HandleScope scope;
   7551   LocalContext context;
   7552   v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
   7553       "var result = [];"
   7554       "result[0] = {};"
   7555       "result[1] = {a: 1, b: 2};"
   7556       "result[2] = [1, 2, 3];"
   7557       "var proto = {x: 1, y: 2, z: 3};"
   7558       "var x = { __proto__: proto, w: 0, z: 1 };"
   7559       "result[3] = x;"
   7560       "result;"))->Run();
   7561   v8::Handle<v8::Array> elms = v8::Handle<v8::Array>::Cast(obj);
   7562   CHECK_EQ(4, elms->Length());
   7563   int elmc0 = 0;
   7564   const char** elmv0 = NULL;
   7565   CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
   7566   int elmc1 = 2;
   7567   const char* elmv1[] = {"a", "b"};
   7568   CheckProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
   7569   int elmc2 = 3;
   7570   const char* elmv2[] = {"0", "1", "2"};
   7571   CheckProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
   7572   int elmc3 = 4;
   7573   const char* elmv3[] = {"w", "z", "x", "y"};
   7574   CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3);
   7575 }
   7576 
   7577 
   7578 static bool NamedSetAccessBlocker(Local<v8::Object> obj,
   7579                                   Local<Value> name,
   7580                                   v8::AccessType type,
   7581                                   Local<Value> data) {
   7582   return type != v8::ACCESS_SET;
   7583 }
   7584 
   7585 
   7586 static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
   7587                                     uint32_t key,
   7588                                     v8::AccessType type,
   7589                                     Local<Value> data) {
   7590   return type != v8::ACCESS_SET;
   7591 }
   7592 
   7593 
   7594 THREADED_TEST(DisableAccessChecksWhileConfiguring) {
   7595   v8::HandleScope scope;
   7596   LocalContext context;
   7597   Local<ObjectTemplate> templ = ObjectTemplate::New();
   7598   templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
   7599                                  IndexedSetAccessBlocker);
   7600   templ->Set(v8_str("x"), v8::True());
   7601   Local<v8::Object> instance = templ->NewInstance();
   7602   context->Global()->Set(v8_str("obj"), instance);
   7603   Local<Value> value = CompileRun("obj.x");
   7604   CHECK(value->BooleanValue());
   7605 }
   7606 
   7607 
   7608 static bool NamedGetAccessBlocker(Local<v8::Object> obj,
   7609                                   Local<Value> name,
   7610                                   v8::AccessType type,
   7611                                   Local<Value> data) {
   7612   return false;
   7613 }
   7614 
   7615 
   7616 static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
   7617                                     uint32_t key,
   7618                                     v8::AccessType type,
   7619                                     Local<Value> data) {
   7620   return false;
   7621 }
   7622 
   7623 
   7624 
   7625 THREADED_TEST(AccessChecksReenabledCorrectly) {
   7626   v8::HandleScope scope;
   7627   LocalContext context;
   7628   Local<ObjectTemplate> templ = ObjectTemplate::New();
   7629   templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
   7630                                  IndexedGetAccessBlocker);
   7631   templ->Set(v8_str("a"), v8_str("a"));
   7632   // Add more than 8 (see kMaxFastProperties) properties
   7633   // so that the constructor will force copying map.
   7634   // Cannot sprintf, gcc complains unsafety.
   7635   char buf[4];
   7636   for (char i = '0'; i <= '9' ; i++) {
   7637     buf[0] = i;
   7638     for (char j = '0'; j <= '9'; j++) {
   7639       buf[1] = j;
   7640       for (char k = '0'; k <= '9'; k++) {
   7641         buf[2] = k;
   7642         buf[3] = 0;
   7643         templ->Set(v8_str(buf), v8::Number::New(k));
   7644       }
   7645     }
   7646   }
   7647 
   7648   Local<v8::Object> instance_1 = templ->NewInstance();
   7649   context->Global()->Set(v8_str("obj_1"), instance_1);
   7650 
   7651   Local<Value> value_1 = CompileRun("obj_1.a");
   7652   CHECK(value_1->IsUndefined());
   7653 
   7654   Local<v8::Object> instance_2 = templ->NewInstance();
   7655   context->Global()->Set(v8_str("obj_2"), instance_2);
   7656 
   7657   Local<Value> value_2 = CompileRun("obj_2.a");
   7658   CHECK(value_2->IsUndefined());
   7659 }
   7660 
   7661 
   7662 // This tests that access check information remains on the global
   7663 // object template when creating contexts.
   7664 THREADED_TEST(AccessControlRepeatedContextCreation) {
   7665   v8::HandleScope handle_scope;
   7666   v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
   7667   global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
   7668                                            IndexedSetAccessBlocker);
   7669   i::Handle<i::ObjectTemplateInfo> internal_template =
   7670       v8::Utils::OpenHandle(*global_template);
   7671   CHECK(!internal_template->constructor()->IsUndefined());
   7672   i::Handle<i::FunctionTemplateInfo> constructor(
   7673       i::FunctionTemplateInfo::cast(internal_template->constructor()));
   7674   CHECK(!constructor->access_check_info()->IsUndefined());
   7675   v8::Persistent<Context> context0 = Context::New(NULL, global_template);
   7676   CHECK(!constructor->access_check_info()->IsUndefined());
   7677 }
   7678 
   7679 
   7680 THREADED_TEST(TurnOnAccessCheck) {
   7681   v8::HandleScope handle_scope;
   7682 
   7683   // Create an environment with access check to the global object disabled by
   7684   // default.
   7685   v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
   7686   global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
   7687                                            IndexedGetAccessBlocker,
   7688                                            v8::Handle<v8::Value>(),
   7689                                            false);
   7690   v8::Persistent<Context> context = Context::New(NULL, global_template);
   7691   Context::Scope context_scope(context);
   7692 
   7693   // Set up a property and a number of functions.
   7694   context->Global()->Set(v8_str("a"), v8_num(1));
   7695   CompileRun("function f1() {return a;}"
   7696              "function f2() {return a;}"
   7697              "function g1() {return h();}"
   7698              "function g2() {return h();}"
   7699              "function h() {return 1;}");
   7700   Local<Function> f1 =
   7701       Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
   7702   Local<Function> f2 =
   7703       Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
   7704   Local<Function> g1 =
   7705       Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
   7706   Local<Function> g2 =
   7707       Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
   7708   Local<Function> h =
   7709       Local<Function>::Cast(context->Global()->Get(v8_str("h")));
   7710 
   7711   // Get the global object.
   7712   v8::Handle<v8::Object> global = context->Global();
   7713 
   7714   // Call f1 one time and f2 a number of times. This will ensure that f1 still
   7715   // uses the runtime system to retreive property a whereas f2 uses global load
   7716   // inline cache.
   7717   CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
   7718   for (int i = 0; i < 4; i++) {
   7719     CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
   7720   }
   7721 
   7722   // Same for g1 and g2.
   7723   CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
   7724   for (int i = 0; i < 4; i++) {
   7725     CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
   7726   }
   7727 
   7728   // Detach the global and turn on access check.
   7729   context->DetachGlobal();
   7730   context->Global()->TurnOnAccessCheck();
   7731 
   7732   // Failing access check to property get results in undefined.
   7733   CHECK(f1->Call(global, 0, NULL)->IsUndefined());
   7734   CHECK(f2->Call(global, 0, NULL)->IsUndefined());
   7735 
   7736   // Failing access check to function call results in exception.
   7737   CHECK(g1->Call(global, 0, NULL).IsEmpty());
   7738   CHECK(g2->Call(global, 0, NULL).IsEmpty());
   7739 
   7740   // No failing access check when just returning a constant.
   7741   CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
   7742 }
   7743 
   7744 
   7745 // This test verifies that pre-compilation (aka preparsing) can be called
   7746 // without initializing the whole VM. Thus we cannot run this test in a
   7747 // multi-threaded setup.
   7748 TEST(PreCompile) {
   7749   // TODO(155): This test would break without the initialization of V8. This is
   7750   // a workaround for now to make this test not fail.
   7751   v8::V8::Initialize();
   7752   const char *script = "function foo(a) { return a+1; }";
   7753   v8::ScriptData *sd =
   7754       v8::ScriptData::PreCompile(script, i::StrLength(script));
   7755   CHECK_NE(sd->Length(), 0);
   7756   CHECK_NE(sd->Data(), NULL);
   7757   CHECK(!sd->HasError());
   7758   delete sd;
   7759 }
   7760 
   7761 
   7762 TEST(PreCompileWithError) {
   7763   v8::V8::Initialize();
   7764   const char *script = "function foo(a) { return 1 * * 2; }";
   7765   v8::ScriptData *sd =
   7766       v8::ScriptData::PreCompile(script, i::StrLength(script));
   7767   CHECK(sd->HasError());
   7768   delete sd;
   7769 }
   7770 
   7771 
   7772 TEST(Regress31661) {
   7773   v8::V8::Initialize();
   7774   const char *script = " The Definintive Guide";
   7775   v8::ScriptData *sd =
   7776       v8::ScriptData::PreCompile(script, i::StrLength(script));
   7777   CHECK(sd->HasError());
   7778   delete sd;
   7779 }
   7780 
   7781 
   7782 // This tests that we do not allow dictionary load/call inline caches
   7783 // to use functions that have not yet been compiled.  The potential
   7784 // problem of loading a function that has not yet been compiled can
   7785 // arise because we share code between contexts via the compilation
   7786 // cache.
   7787 THREADED_TEST(DictionaryICLoadedFunction) {
   7788   v8::HandleScope scope;
   7789   // Test LoadIC.
   7790   for (int i = 0; i < 2; i++) {
   7791     LocalContext context;
   7792     context->Global()->Set(v8_str("tmp"), v8::True());
   7793     context->Global()->Delete(v8_str("tmp"));
   7794     CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
   7795   }
   7796   // Test CallIC.
   7797   for (int i = 0; i < 2; i++) {
   7798     LocalContext context;
   7799     context->Global()->Set(v8_str("tmp"), v8::True());
   7800     context->Global()->Delete(v8_str("tmp"));
   7801     CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
   7802   }
   7803 }
   7804 
   7805 
   7806 // Test that cross-context new calls use the context of the callee to
   7807 // create the new JavaScript object.
   7808 THREADED_TEST(CrossContextNew) {
   7809   v8::HandleScope scope;
   7810   v8::Persistent<Context> context0 = Context::New();
   7811   v8::Persistent<Context> context1 = Context::New();
   7812 
   7813   // Allow cross-domain access.
   7814   Local<String> token = v8_str("<security token>");
   7815   context0->SetSecurityToken(token);
   7816   context1->SetSecurityToken(token);
   7817 
   7818   // Set an 'x' property on the Object prototype and define a
   7819   // constructor function in context0.
   7820   context0->Enter();
   7821   CompileRun("Object.prototype.x = 42; function C() {};");
   7822   context0->Exit();
   7823 
   7824   // Call the constructor function from context0 and check that the
   7825   // result has the 'x' property.
   7826   context1->Enter();
   7827   context1->Global()->Set(v8_str("other"), context0->Global());
   7828   Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
   7829   CHECK(value->IsInt32());
   7830   CHECK_EQ(42, value->Int32Value());
   7831   context1->Exit();
   7832 
   7833   // Dispose the contexts to allow them to be garbage collected.
   7834   context0.Dispose();
   7835   context1.Dispose();
   7836 }
   7837 
   7838 
   7839 class RegExpInterruptTest {
   7840  public:
   7841   RegExpInterruptTest() : block_(NULL) {}
   7842   ~RegExpInterruptTest() { delete block_; }
   7843   void RunTest() {
   7844     block_ = i::OS::CreateSemaphore(0);
   7845     gc_count_ = 0;
   7846     gc_during_regexp_ = 0;
   7847     regexp_success_ = false;
   7848     gc_success_ = false;
   7849     GCThread gc_thread(this);
   7850     gc_thread.Start();
   7851     v8::Locker::StartPreemption(1);
   7852 
   7853     LongRunningRegExp();
   7854     {
   7855       v8::Unlocker unlock;
   7856       gc_thread.Join();
   7857     }
   7858     v8::Locker::StopPreemption();
   7859     CHECK(regexp_success_);
   7860     CHECK(gc_success_);
   7861   }
   7862  private:
   7863   // Number of garbage collections required.
   7864   static const int kRequiredGCs = 5;
   7865 
   7866   class GCThread : public i::Thread {
   7867    public:
   7868     explicit GCThread(RegExpInterruptTest* test)
   7869         : test_(test) {}
   7870     virtual void Run() {
   7871       test_->CollectGarbage();
   7872     }
   7873    private:
   7874      RegExpInterruptTest* test_;
   7875   };
   7876 
   7877   void CollectGarbage() {
   7878     block_->Wait();
   7879     while (gc_during_regexp_ < kRequiredGCs) {
   7880       {
   7881         v8::Locker lock;
   7882         // TODO(lrn): Perhaps create some garbage before collecting.
   7883         i::Heap::CollectAllGarbage(false);
   7884         gc_count_++;
   7885       }
   7886       i::OS::Sleep(1);
   7887     }
   7888     gc_success_ = true;
   7889   }
   7890 
   7891   void LongRunningRegExp() {
   7892     block_->Signal();  // Enable garbage collection thread on next preemption.
   7893     int rounds = 0;
   7894     while (gc_during_regexp_ < kRequiredGCs) {
   7895       int gc_before = gc_count_;
   7896       {
   7897         // Match 15-30 "a"'s against 14 and a "b".
   7898         const char* c_source =
   7899             "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
   7900             ".exec('aaaaaaaaaaaaaaab') === null";
   7901         Local<String> source = String::New(c_source);
   7902         Local<Script> script = Script::Compile(source);
   7903         Local<Value> result = script->Run();
   7904         if (!result->BooleanValue()) {
   7905           gc_during_regexp_ = kRequiredGCs;  // Allow gc thread to exit.
   7906           return;
   7907         }
   7908       }
   7909       {
   7910         // Match 15-30 "a"'s against 15 and a "b".
   7911         const char* c_source =
   7912             "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
   7913             ".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'";
   7914         Local<String> source = String::New(c_source);
   7915         Local<Script> script = Script::Compile(source);
   7916         Local<Value> result = script->Run();
   7917         if (!result->BooleanValue()) {
   7918           gc_during_regexp_ = kRequiredGCs;
   7919           return;
   7920         }
   7921       }
   7922       int gc_after = gc_count_;
   7923       gc_during_regexp_ += gc_after - gc_before;
   7924       rounds++;
   7925       i::OS::Sleep(1);
   7926     }
   7927     regexp_success_ = true;
   7928   }
   7929 
   7930   i::Semaphore* block_;
   7931   int gc_count_;
   7932   int gc_during_regexp_;
   7933   bool regexp_success_;
   7934   bool gc_success_;
   7935 };
   7936 
   7937 
   7938 // Test that a regular expression execution can be interrupted and
   7939 // survive a garbage collection.
   7940 TEST(RegExpInterruption) {
   7941   v8::Locker lock;
   7942   v8::V8::Initialize();
   7943   v8::HandleScope scope;
   7944   Local<Context> local_env;
   7945   {
   7946     LocalContext env;
   7947     local_env = env.local();
   7948   }
   7949 
   7950   // Local context should still be live.
   7951   CHECK(!local_env.IsEmpty());
   7952   local_env->Enter();
   7953 
   7954   // Should complete without problems.
   7955   RegExpInterruptTest().RunTest();
   7956 
   7957   local_env->Exit();
   7958 }
   7959 
   7960 
   7961 class ApplyInterruptTest {
   7962  public:
   7963   ApplyInterruptTest() : block_(NULL) {}
   7964   ~ApplyInterruptTest() { delete block_; }
   7965   void RunTest() {
   7966     block_ = i::OS::CreateSemaphore(0);
   7967     gc_count_ = 0;
   7968     gc_during_apply_ = 0;
   7969     apply_success_ = false;
   7970     gc_success_ = false;
   7971     GCThread gc_thread(this);
   7972     gc_thread.Start();
   7973     v8::Locker::StartPreemption(1);
   7974 
   7975     LongRunningApply();
   7976     {
   7977       v8::Unlocker unlock;
   7978       gc_thread.Join();
   7979     }
   7980     v8::Locker::StopPreemption();
   7981     CHECK(apply_success_);
   7982     CHECK(gc_success_);
   7983   }
   7984  private:
   7985   // Number of garbage collections required.
   7986   static const int kRequiredGCs = 2;
   7987 
   7988   class GCThread : public i::Thread {
   7989    public:
   7990     explicit GCThread(ApplyInterruptTest* test)
   7991         : test_(test) {}
   7992     virtual void Run() {
   7993       test_->CollectGarbage();
   7994     }
   7995    private:
   7996      ApplyInterruptTest* test_;
   7997   };
   7998 
   7999   void CollectGarbage() {
   8000     block_->Wait();
   8001     while (gc_during_apply_ < kRequiredGCs) {
   8002       {
   8003         v8::Locker lock;
   8004         i::Heap::CollectAllGarbage(false);
   8005         gc_count_++;
   8006       }
   8007       i::OS::Sleep(1);
   8008     }
   8009     gc_success_ = true;
   8010   }
   8011 
   8012   void LongRunningApply() {
   8013     block_->Signal();
   8014     int rounds = 0;
   8015     while (gc_during_apply_ < kRequiredGCs) {
   8016       int gc_before = gc_count_;
   8017       {
   8018         const char* c_source =
   8019             "function do_very_little(bar) {"
   8020             "  this.foo = bar;"
   8021             "}"
   8022             "for (var i = 0; i < 100000; i++) {"
   8023             "  do_very_little.apply(this, ['bar']);"
   8024             "}";
   8025         Local<String> source = String::New(c_source);
   8026         Local<Script> script = Script::Compile(source);
   8027         Local<Value> result = script->Run();
   8028         // Check that no exception was thrown.
   8029         CHECK(!result.IsEmpty());
   8030       }
   8031       int gc_after = gc_count_;
   8032       gc_during_apply_ += gc_after - gc_before;
   8033       rounds++;
   8034     }
   8035     apply_success_ = true;
   8036   }
   8037 
   8038   i::Semaphore* block_;
   8039   int gc_count_;
   8040   int gc_during_apply_;
   8041   bool apply_success_;
   8042   bool gc_success_;
   8043 };
   8044 
   8045 
   8046 // Test that nothing bad happens if we get a preemption just when we were
   8047 // about to do an apply().
   8048 TEST(ApplyInterruption) {
   8049   v8::Locker lock;
   8050   v8::V8::Initialize();
   8051   v8::HandleScope scope;
   8052   Local<Context> local_env;
   8053   {
   8054     LocalContext env;
   8055     local_env = env.local();
   8056   }
   8057 
   8058   // Local context should still be live.
   8059   CHECK(!local_env.IsEmpty());
   8060   local_env->Enter();
   8061 
   8062   // Should complete without problems.
   8063   ApplyInterruptTest().RunTest();
   8064 
   8065   local_env->Exit();
   8066 }
   8067 
   8068 
   8069 // Verify that we can clone an object
   8070 TEST(ObjectClone) {
   8071   v8::HandleScope scope;
   8072   LocalContext env;
   8073 
   8074   const char* sample =
   8075     "var rv = {};"      \
   8076     "rv.alpha = 'hello';" \
   8077     "rv.beta = 123;"     \
   8078     "rv;";
   8079 
   8080   // Create an object, verify basics.
   8081   Local<Value> val = CompileRun(sample);
   8082   CHECK(val->IsObject());
   8083   Local<v8::Object> obj = Local<v8::Object>::Cast(val);
   8084   obj->Set(v8_str("gamma"), v8_str("cloneme"));
   8085 
   8086   CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
   8087   CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
   8088   CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
   8089 
   8090   // Clone it.
   8091   Local<v8::Object> clone = obj->Clone();
   8092   CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
   8093   CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta")));
   8094   CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
   8095 
   8096   // Set a property on the clone, verify each object.
   8097   clone->Set(v8_str("beta"), v8::Integer::New(456));
   8098   CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
   8099   CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta")));
   8100 }
   8101 
   8102 
   8103 class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
   8104  public:
   8105   explicit AsciiVectorResource(i::Vector<const char> vector)
   8106       : data_(vector) {}
   8107   virtual ~AsciiVectorResource() {}
   8108   virtual size_t length() const { return data_.length(); }
   8109   virtual const char* data() const { return data_.start(); }
   8110  private:
   8111   i::Vector<const char> data_;
   8112 };
   8113 
   8114 
   8115 class UC16VectorResource : public v8::String::ExternalStringResource {
   8116  public:
   8117   explicit UC16VectorResource(i::Vector<const i::uc16> vector)
   8118       : data_(vector) {}
   8119   virtual ~UC16VectorResource() {}
   8120   virtual size_t length() const { return data_.length(); }
   8121   virtual const i::uc16* data() const { return data_.start(); }
   8122  private:
   8123   i::Vector<const i::uc16> data_;
   8124 };
   8125 
   8126 
   8127 static void MorphAString(i::String* string,
   8128                          AsciiVectorResource* ascii_resource,
   8129                          UC16VectorResource* uc16_resource) {
   8130   CHECK(i::StringShape(string).IsExternal());
   8131   if (string->IsAsciiRepresentation()) {
   8132     // Check old map is not symbol or long.
   8133     CHECK(string->map() == i::Heap::external_ascii_string_map());
   8134     // Morph external string to be TwoByte string.
   8135     string->set_map(i::Heap::external_string_map());
   8136     i::ExternalTwoByteString* morphed =
   8137          i::ExternalTwoByteString::cast(string);
   8138     morphed->set_resource(uc16_resource);
   8139   } else {
   8140     // Check old map is not symbol or long.
   8141     CHECK(string->map() == i::Heap::external_string_map());
   8142     // Morph external string to be ASCII string.
   8143     string->set_map(i::Heap::external_ascii_string_map());
   8144     i::ExternalAsciiString* morphed =
   8145          i::ExternalAsciiString::cast(string);
   8146     morphed->set_resource(ascii_resource);
   8147   }
   8148 }
   8149 
   8150 
   8151 // Test that we can still flatten a string if the components it is built up
   8152 // from have been turned into 16 bit strings in the mean time.
   8153 THREADED_TEST(MorphCompositeStringTest) {
   8154   const char* c_string = "Now is the time for all good men"
   8155                          " to come to the aid of the party";
   8156   uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
   8157   {
   8158     v8::HandleScope scope;
   8159     LocalContext env;
   8160     AsciiVectorResource ascii_resource(
   8161         i::Vector<const char>(c_string, i::StrLength(c_string)));
   8162     UC16VectorResource uc16_resource(
   8163         i::Vector<const uint16_t>(two_byte_string,
   8164                                   i::StrLength(c_string)));
   8165 
   8166     Local<String> lhs(v8::Utils::ToLocal(
   8167         i::Factory::NewExternalStringFromAscii(&ascii_resource)));
   8168     Local<String> rhs(v8::Utils::ToLocal(
   8169         i::Factory::NewExternalStringFromAscii(&ascii_resource)));
   8170 
   8171     env->Global()->Set(v8_str("lhs"), lhs);
   8172     env->Global()->Set(v8_str("rhs"), rhs);
   8173 
   8174     CompileRun(
   8175         "var cons = lhs + rhs;"
   8176         "var slice = lhs.substring(1, lhs.length - 1);"
   8177         "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
   8178 
   8179     MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
   8180     MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
   8181 
   8182     // Now do some stuff to make sure the strings are flattened, etc.
   8183     CompileRun(
   8184         "/[^a-z]/.test(cons);"
   8185         "/[^a-z]/.test(slice);"
   8186         "/[^a-z]/.test(slice_on_cons);");
   8187     const char* expected_cons =
   8188         "Now is the time for all good men to come to the aid of the party"
   8189         "Now is the time for all good men to come to the aid of the party";
   8190     const char* expected_slice =
   8191         "ow is the time for all good men to come to the aid of the part";
   8192     const char* expected_slice_on_cons =
   8193         "ow is the time for all good men to come to the aid of the party"
   8194         "Now is the time for all good men to come to the aid of the part";
   8195     CHECK_EQ(String::New(expected_cons),
   8196              env->Global()->Get(v8_str("cons")));
   8197     CHECK_EQ(String::New(expected_slice),
   8198              env->Global()->Get(v8_str("slice")));
   8199     CHECK_EQ(String::New(expected_slice_on_cons),
   8200              env->Global()->Get(v8_str("slice_on_cons")));
   8201   }
   8202 }
   8203 
   8204 
   8205 TEST(CompileExternalTwoByteSource) {
   8206   v8::HandleScope scope;
   8207   LocalContext context;
   8208 
   8209   // This is a very short list of sources, which currently is to check for a
   8210   // regression caused by r2703.
   8211   const char* ascii_sources[] = {
   8212     "0.5",
   8213     "-0.5",   // This mainly testes PushBack in the Scanner.
   8214     "--0.5",  // This mainly testes PushBack in the Scanner.
   8215     NULL
   8216   };
   8217 
   8218   // Compile the sources as external two byte strings.
   8219   for (int i = 0; ascii_sources[i] != NULL; i++) {
   8220     uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
   8221     UC16VectorResource uc16_resource(
   8222         i::Vector<const uint16_t>(two_byte_string,
   8223                                   i::StrLength(ascii_sources[i])));
   8224     v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource);
   8225     v8::Script::Compile(source);
   8226   }
   8227 }
   8228 
   8229 
   8230 class RegExpStringModificationTest {
   8231  public:
   8232   RegExpStringModificationTest()
   8233       : block_(i::OS::CreateSemaphore(0)),
   8234         morphs_(0),
   8235         morphs_during_regexp_(0),
   8236         ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)),
   8237         uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {}
   8238   ~RegExpStringModificationTest() { delete block_; }
   8239   void RunTest() {
   8240     regexp_success_ = false;
   8241     morph_success_ = false;
   8242 
   8243     // Initialize the contents of two_byte_content_ to be a uc16 representation
   8244     // of "aaaaaaaaaaaaaab".
   8245     for (int i = 0; i < 14; i++) {
   8246       two_byte_content_[i] = 'a';
   8247     }
   8248     two_byte_content_[14] = 'b';
   8249 
   8250     // Create the input string for the regexp - the one we are going to change
   8251     // properties of.
   8252     input_ = i::Factory::NewExternalStringFromAscii(&ascii_resource_);
   8253 
   8254     // Inject the input as a global variable.
   8255     i::Handle<i::String> input_name =
   8256         i::Factory::NewStringFromAscii(i::Vector<const char>("input", 5));
   8257     i::Top::global_context()->global()->SetProperty(*input_name, *input_, NONE);
   8258 
   8259 
   8260     MorphThread morph_thread(this);
   8261     morph_thread.Start();
   8262     v8::Locker::StartPreemption(1);
   8263     LongRunningRegExp();
   8264     {
   8265       v8::Unlocker unlock;
   8266       morph_thread.Join();
   8267     }
   8268     v8::Locker::StopPreemption();
   8269     CHECK(regexp_success_);
   8270     CHECK(morph_success_);
   8271   }
   8272  private:
   8273 
   8274   // Number of string modifications required.
   8275   static const int kRequiredModifications = 5;
   8276   static const int kMaxModifications = 100;
   8277 
   8278   class MorphThread : public i::Thread {
   8279    public:
   8280     explicit MorphThread(RegExpStringModificationTest* test)
   8281         : test_(test) {}
   8282     virtual void Run() {
   8283       test_->MorphString();
   8284     }
   8285    private:
   8286      RegExpStringModificationTest* test_;
   8287   };
   8288 
   8289   void MorphString() {
   8290     block_->Wait();
   8291     while (morphs_during_regexp_ < kRequiredModifications &&
   8292            morphs_ < kMaxModifications) {
   8293       {
   8294         v8::Locker lock;
   8295         // Swap string between ascii and two-byte representation.
   8296         i::String* string = *input_;
   8297         MorphAString(string, &ascii_resource_, &uc16_resource_);
   8298         morphs_++;
   8299       }
   8300       i::OS::Sleep(1);
   8301     }
   8302     morph_success_ = true;
   8303   }
   8304 
   8305   void LongRunningRegExp() {
   8306     block_->Signal();  // Enable morphing thread on next preemption.
   8307     while (morphs_during_regexp_ < kRequiredModifications &&
   8308            morphs_ < kMaxModifications) {
   8309       int morphs_before = morphs_;
   8310       {
   8311         // Match 15-30 "a"'s against 14 and a "b".
   8312         const char* c_source =
   8313             "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
   8314             ".exec(input) === null";
   8315         Local<String> source = String::New(c_source);
   8316         Local<Script> script = Script::Compile(source);
   8317         Local<Value> result = script->Run();
   8318         CHECK(result->IsTrue());
   8319       }
   8320       int morphs_after = morphs_;
   8321       morphs_during_regexp_ += morphs_after - morphs_before;
   8322     }
   8323     regexp_success_ = true;
   8324   }
   8325 
   8326   i::uc16 two_byte_content_[15];
   8327   i::Semaphore* block_;
   8328   int morphs_;
   8329   int morphs_during_regexp_;
   8330   bool regexp_success_;
   8331   bool morph_success_;
   8332   i::Handle<i::String> input_;
   8333   AsciiVectorResource ascii_resource_;
   8334   UC16VectorResource uc16_resource_;
   8335 };
   8336 
   8337 
   8338 // Test that a regular expression execution can be interrupted and
   8339 // the string changed without failing.
   8340 TEST(RegExpStringModification) {
   8341   v8::Locker lock;
   8342   v8::V8::Initialize();
   8343   v8::HandleScope scope;
   8344   Local<Context> local_env;
   8345   {
   8346     LocalContext env;
   8347     local_env = env.local();
   8348   }
   8349 
   8350   // Local context should still be live.
   8351   CHECK(!local_env.IsEmpty());
   8352   local_env->Enter();
   8353 
   8354   // Should complete without problems.
   8355   RegExpStringModificationTest().RunTest();
   8356 
   8357   local_env->Exit();
   8358 }
   8359 
   8360 
   8361 // Test that we can set a property on the global object even if there
   8362 // is a read-only property in the prototype chain.
   8363 TEST(ReadOnlyPropertyInGlobalProto) {
   8364   v8::HandleScope scope;
   8365   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
   8366   LocalContext context(0, templ);
   8367   v8::Handle<v8::Object> global = context->Global();
   8368   v8::Handle<v8::Object> global_proto =
   8369       v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
   8370   global_proto->Set(v8_str("x"), v8::Integer::New(0), v8::ReadOnly);
   8371   global_proto->Set(v8_str("y"), v8::Integer::New(0), v8::ReadOnly);
   8372   // Check without 'eval' or 'with'.
   8373   v8::Handle<v8::Value> res =
   8374       CompileRun("function f() { x = 42; return x; }; f()");
   8375   // Check with 'eval'.
   8376   res = CompileRun("function f() { eval('1'); y = 42; return y; }; f()");
   8377   CHECK_EQ(v8::Integer::New(42), res);
   8378   // Check with 'with'.
   8379   res = CompileRun("function f() { with (this) { y = 42 }; return y; }; f()");
   8380   CHECK_EQ(v8::Integer::New(42), res);
   8381 }
   8382 
   8383 static int force_set_set_count = 0;
   8384 static int force_set_get_count = 0;
   8385 bool pass_on_get = false;
   8386 
   8387 static v8::Handle<v8::Value> ForceSetGetter(v8::Local<v8::String> name,
   8388                                             const v8::AccessorInfo& info) {
   8389   force_set_get_count++;
   8390   if (pass_on_get) {
   8391     return v8::Handle<v8::Value>();
   8392   } else {
   8393     return v8::Int32::New(3);
   8394   }
   8395 }
   8396 
   8397 static void ForceSetSetter(v8::Local<v8::String> name,
   8398                            v8::Local<v8::Value> value,
   8399                            const v8::AccessorInfo& info) {
   8400   force_set_set_count++;
   8401 }
   8402 
   8403 static v8::Handle<v8::Value> ForceSetInterceptSetter(
   8404     v8::Local<v8::String> name,
   8405     v8::Local<v8::Value> value,
   8406     const v8::AccessorInfo& info) {
   8407   force_set_set_count++;
   8408   return v8::Undefined();
   8409 }
   8410 
   8411 TEST(ForceSet) {
   8412   force_set_get_count = 0;
   8413   force_set_set_count = 0;
   8414   pass_on_get = false;
   8415 
   8416   v8::HandleScope scope;
   8417   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
   8418   v8::Handle<v8::String> access_property = v8::String::New("a");
   8419   templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
   8420   LocalContext context(NULL, templ);
   8421   v8::Handle<v8::Object> global = context->Global();
   8422 
   8423   // Ordinary properties
   8424   v8::Handle<v8::String> simple_property = v8::String::New("p");
   8425   global->Set(simple_property, v8::Int32::New(4), v8::ReadOnly);
   8426   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
   8427   // This should fail because the property is read-only
   8428   global->Set(simple_property, v8::Int32::New(5));
   8429   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
   8430   // This should succeed even though the property is read-only
   8431   global->ForceSet(simple_property, v8::Int32::New(6));
   8432   CHECK_EQ(6, global->Get(simple_property)->Int32Value());
   8433 
   8434   // Accessors
   8435   CHECK_EQ(0, force_set_set_count);
   8436   CHECK_EQ(0, force_set_get_count);
   8437   CHECK_EQ(3, global->Get(access_property)->Int32Value());
   8438   // CHECK_EQ the property shouldn't override it, just call the setter
   8439   // which in this case does nothing.
   8440   global->Set(access_property, v8::Int32::New(7));
   8441   CHECK_EQ(3, global->Get(access_property)->Int32Value());
   8442   CHECK_EQ(1, force_set_set_count);
   8443   CHECK_EQ(2, force_set_get_count);
   8444   // Forcing the property to be set should override the accessor without
   8445   // calling it
   8446   global->ForceSet(access_property, v8::Int32::New(8));
   8447   CHECK_EQ(8, global->Get(access_property)->Int32Value());
   8448   CHECK_EQ(1, force_set_set_count);
   8449   CHECK_EQ(2, force_set_get_count);
   8450 }
   8451 
   8452 TEST(ForceSetWithInterceptor) {
   8453   force_set_get_count = 0;
   8454   force_set_set_count = 0;
   8455   pass_on_get = false;
   8456 
   8457   v8::HandleScope scope;
   8458   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
   8459   templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
   8460   LocalContext context(NULL, templ);
   8461   v8::Handle<v8::Object> global = context->Global();
   8462 
   8463   v8::Handle<v8::String> some_property = v8::String::New("a");
   8464   CHECK_EQ(0, force_set_set_count);
   8465   CHECK_EQ(0, force_set_get_count);
   8466   CHECK_EQ(3, global->Get(some_property)->Int32Value());
   8467   // Setting the property shouldn't override it, just call the setter
   8468   // which in this case does nothing.
   8469   global->Set(some_property, v8::Int32::New(7));
   8470   CHECK_EQ(3, global->Get(some_property)->Int32Value());
   8471   CHECK_EQ(1, force_set_set_count);
   8472   CHECK_EQ(2, force_set_get_count);
   8473   // Getting the property when the interceptor returns an empty handle
   8474   // should yield undefined, since the property isn't present on the
   8475   // object itself yet.
   8476   pass_on_get = true;
   8477   CHECK(global->Get(some_property)->IsUndefined());
   8478   CHECK_EQ(1, force_set_set_count);
   8479   CHECK_EQ(3, force_set_get_count);
   8480   // Forcing the property to be set should cause the value to be
   8481   // set locally without calling the interceptor.
   8482   global->ForceSet(some_property, v8::Int32::New(8));
   8483   CHECK_EQ(8, global->Get(some_property)->Int32Value());
   8484   CHECK_EQ(1, force_set_set_count);
   8485   CHECK_EQ(4, force_set_get_count);
   8486   // Reenabling the interceptor should cause it to take precedence over
   8487   // the property
   8488   pass_on_get = false;
   8489   CHECK_EQ(3, global->Get(some_property)->Int32Value());
   8490   CHECK_EQ(1, force_set_set_count);
   8491   CHECK_EQ(5, force_set_get_count);
   8492   // The interceptor should also work for other properties
   8493   CHECK_EQ(3, global->Get(v8::String::New("b"))->Int32Value());
   8494   CHECK_EQ(1, force_set_set_count);
   8495   CHECK_EQ(6, force_set_get_count);
   8496 }
   8497 
   8498 
   8499 THREADED_TEST(ForceDelete) {
   8500   v8::HandleScope scope;
   8501   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
   8502   LocalContext context(NULL, templ);
   8503   v8::Handle<v8::Object> global = context->Global();
   8504 
   8505   // Ordinary properties
   8506   v8::Handle<v8::String> simple_property = v8::String::New("p");
   8507   global->Set(simple_property, v8::Int32::New(4), v8::DontDelete);
   8508   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
   8509   // This should fail because the property is dont-delete.
   8510   CHECK(!global->Delete(simple_property));
   8511   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
   8512   // This should succeed even though the property is dont-delete.
   8513   CHECK(global->ForceDelete(simple_property));
   8514   CHECK(global->Get(simple_property)->IsUndefined());
   8515 }
   8516 
   8517 
   8518 static int force_delete_interceptor_count = 0;
   8519 static bool pass_on_delete = false;
   8520 
   8521 
   8522 static v8::Handle<v8::Boolean> ForceDeleteDeleter(
   8523     v8::Local<v8::String> name,
   8524     const v8::AccessorInfo& info) {
   8525   force_delete_interceptor_count++;
   8526   if (pass_on_delete) {
   8527     return v8::Handle<v8::Boolean>();
   8528   } else {
   8529     return v8::True();
   8530   }
   8531 }
   8532 
   8533 
   8534 THREADED_TEST(ForceDeleteWithInterceptor) {
   8535   force_delete_interceptor_count = 0;
   8536   pass_on_delete = false;
   8537 
   8538   v8::HandleScope scope;
   8539   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
   8540   templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
   8541   LocalContext context(NULL, templ);
   8542   v8::Handle<v8::Object> global = context->Global();
   8543 
   8544   v8::Handle<v8::String> some_property = v8::String::New("a");
   8545   global->Set(some_property, v8::Integer::New(42), v8::DontDelete);
   8546 
   8547   // Deleting a property should get intercepted and nothing should
   8548   // happen.
   8549   CHECK_EQ(0, force_delete_interceptor_count);
   8550   CHECK(global->Delete(some_property));
   8551   CHECK_EQ(1, force_delete_interceptor_count);
   8552   CHECK_EQ(42, global->Get(some_property)->Int32Value());
   8553   // Deleting the property when the interceptor returns an empty
   8554   // handle should not delete the property since it is DontDelete.
   8555   pass_on_delete = true;
   8556   CHECK(!global->Delete(some_property));
   8557   CHECK_EQ(2, force_delete_interceptor_count);
   8558   CHECK_EQ(42, global->Get(some_property)->Int32Value());
   8559   // Forcing the property to be deleted should delete the value
   8560   // without calling the interceptor.
   8561   CHECK(global->ForceDelete(some_property));
   8562   CHECK(global->Get(some_property)->IsUndefined());
   8563   CHECK_EQ(2, force_delete_interceptor_count);
   8564 }
   8565 
   8566 
   8567 // Make sure that forcing a delete invalidates any IC stubs, so we
   8568 // don't read the hole value.
   8569 THREADED_TEST(ForceDeleteIC) {
   8570   v8::HandleScope scope;
   8571   LocalContext context;
   8572   // Create a DontDelete variable on the global object.
   8573   CompileRun("this.__proto__ = { foo: 'horse' };"
   8574              "var foo = 'fish';"
   8575              "function f() { return foo.length; }");
   8576   // Initialize the IC for foo in f.
   8577   CompileRun("for (var i = 0; i < 4; i++) f();");
   8578   // Make sure the value of foo is correct before the deletion.
   8579   CHECK_EQ(4, CompileRun("f()")->Int32Value());
   8580   // Force the deletion of foo.
   8581   CHECK(context->Global()->ForceDelete(v8_str("foo")));
   8582   // Make sure the value for foo is read from the prototype, and that
   8583   // we don't get in trouble with reading the deleted cell value
   8584   // sentinel.
   8585   CHECK_EQ(5, CompileRun("f()")->Int32Value());
   8586 }
   8587 
   8588 
   8589 v8::Persistent<Context> calling_context0;
   8590 v8::Persistent<Context> calling_context1;
   8591 v8::Persistent<Context> calling_context2;
   8592 
   8593 
   8594 // Check that the call to the callback is initiated in
   8595 // calling_context2, the directly calling context is calling_context1
   8596 // and the callback itself is in calling_context0.
   8597 static v8::Handle<Value> GetCallingContextCallback(const v8::Arguments& args) {
   8598   ApiTestFuzzer::Fuzz();
   8599   CHECK(Context::GetCurrent() == calling_context0);
   8600   CHECK(Context::GetCalling() == calling_context1);
   8601   CHECK(Context::GetEntered() == calling_context2);
   8602   return v8::Integer::New(42);
   8603 }
   8604 
   8605 
   8606 THREADED_TEST(GetCallingContext) {
   8607   v8::HandleScope scope;
   8608 
   8609   calling_context0 = Context::New();
   8610   calling_context1 = Context::New();
   8611   calling_context2 = Context::New();
   8612 
   8613   // Allow cross-domain access.
   8614   Local<String> token = v8_str("<security token>");
   8615   calling_context0->SetSecurityToken(token);
   8616   calling_context1->SetSecurityToken(token);
   8617   calling_context2->SetSecurityToken(token);
   8618 
   8619   // Create an object with a C++ callback in context0.
   8620   calling_context0->Enter();
   8621   Local<v8::FunctionTemplate> callback_templ =
   8622       v8::FunctionTemplate::New(GetCallingContextCallback);
   8623   calling_context0->Global()->Set(v8_str("callback"),
   8624                                   callback_templ->GetFunction());
   8625   calling_context0->Exit();
   8626 
   8627   // Expose context0 in context1 and setup a function that calls the
   8628   // callback function.
   8629   calling_context1->Enter();
   8630   calling_context1->Global()->Set(v8_str("context0"),
   8631                                   calling_context0->Global());
   8632   CompileRun("function f() { context0.callback() }");
   8633   calling_context1->Exit();
   8634 
   8635   // Expose context1 in context2 and call the callback function in
   8636   // context0 indirectly through f in context1.
   8637   calling_context2->Enter();
   8638   calling_context2->Global()->Set(v8_str("context1"),
   8639                                   calling_context1->Global());
   8640   CompileRun("context1.f()");
   8641   calling_context2->Exit();
   8642 
   8643   // Dispose the contexts to allow them to be garbage collected.
   8644   calling_context0.Dispose();
   8645   calling_context1.Dispose();
   8646   calling_context2.Dispose();
   8647   calling_context0.Clear();
   8648   calling_context1.Clear();
   8649   calling_context2.Clear();
   8650 }
   8651 
   8652 
   8653 // Check that a variable declaration with no explicit initialization
   8654 // value does not shadow an existing property in the prototype chain.
   8655 //
   8656 // This is consistent with Firefox and Safari.
   8657 //
   8658 // See http://crbug.com/12548.
   8659 THREADED_TEST(InitGlobalVarInProtoChain) {
   8660   v8::HandleScope scope;
   8661   LocalContext context;
   8662   // Introduce a variable in the prototype chain.
   8663   CompileRun("__proto__.x = 42");
   8664   v8::Handle<v8::Value> result = CompileRun("var x; x");
   8665   CHECK(!result->IsUndefined());
   8666   CHECK_EQ(42, result->Int32Value());
   8667 }
   8668 
   8669 
   8670 // Regression test for issue 398.
   8671 // If a function is added to an object, creating a constant function
   8672 // field, and the result is cloned, replacing the constant function on the
   8673 // original should not affect the clone.
   8674 // See http://code.google.com/p/v8/issues/detail?id=398
   8675 THREADED_TEST(ReplaceConstantFunction) {
   8676   v8::HandleScope scope;
   8677   LocalContext context;
   8678   v8::Handle<v8::Object> obj = v8::Object::New();
   8679   v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
   8680   v8::Handle<v8::String> foo_string = v8::String::New("foo");
   8681   obj->Set(foo_string, func_templ->GetFunction());
   8682   v8::Handle<v8::Object> obj_clone = obj->Clone();
   8683   obj_clone->Set(foo_string, v8::String::New("Hello"));
   8684   CHECK(!obj->Get(foo_string)->IsUndefined());
   8685 }
   8686 
   8687 
   8688 // Regression test for http://crbug.com/16276.
   8689 THREADED_TEST(Regress16276) {
   8690   v8::HandleScope scope;
   8691   LocalContext context;
   8692   // Force the IC in f to be a dictionary load IC.
   8693   CompileRun("function f(obj) { return obj.x; }\n"
   8694              "var obj = { x: { foo: 42 }, y: 87 };\n"
   8695              "var x = obj.x;\n"
   8696              "delete obj.y;\n"
   8697              "for (var i = 0; i < 5; i++) f(obj);");
   8698   // Detach the global object to make 'this' refer directly to the
   8699   // global object (not the proxy), and make sure that the dictionary
   8700   // load IC doesn't mess up loading directly from the global object.
   8701   context->DetachGlobal();
   8702   CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value());
   8703 }
   8704 
   8705 
   8706 THREADED_TEST(PixelArray) {
   8707   v8::HandleScope scope;
   8708   LocalContext context;
   8709   const int kElementCount = 260;
   8710   uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
   8711   i::Handle<i::PixelArray> pixels = i::Factory::NewPixelArray(kElementCount,
   8712                                                               pixel_data);
   8713   i::Heap::CollectAllGarbage(false);  // Force GC to trigger verification.
   8714   for (int i = 0; i < kElementCount; i++) {
   8715     pixels->set(i, i % 256);
   8716   }
   8717   i::Heap::CollectAllGarbage(false);  // Force GC to trigger verification.
   8718   for (int i = 0; i < kElementCount; i++) {
   8719     CHECK_EQ(i % 256, pixels->get(i));
   8720     CHECK_EQ(i % 256, pixel_data[i]);
   8721   }
   8722 
   8723   v8::Handle<v8::Object> obj = v8::Object::New();
   8724   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
   8725   // Set the elements to be the pixels.
   8726   // jsobj->set_elements(*pixels);
   8727   obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
   8728   CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1))->value());
   8729   obj->Set(v8_str("field"), v8::Int32::New(1503));
   8730   context->Global()->Set(v8_str("pixels"), obj);
   8731   v8::Handle<v8::Value> result = CompileRun("pixels.field");
   8732   CHECK_EQ(1503, result->Int32Value());
   8733   result = CompileRun("pixels[1]");
   8734   CHECK_EQ(1, result->Int32Value());
   8735 
   8736   result = CompileRun("var sum = 0;"
   8737                       "for (var i = 0; i < 8; i++) {"
   8738                       "  sum += pixels[i] = pixels[i] = -i;"
   8739                       "}"
   8740                       "sum;");
   8741   CHECK_EQ(-28, result->Int32Value());
   8742 
   8743   result = CompileRun("var sum = 0;"
   8744                       "for (var i = 0; i < 8; i++) {"
   8745                       "  sum += pixels[i] = pixels[i] = 0;"
   8746                       "}"
   8747                       "sum;");
   8748   CHECK_EQ(0, result->Int32Value());
   8749 
   8750   result = CompileRun("var sum = 0;"
   8751                       "for (var i = 0; i < 8; i++) {"
   8752                       "  sum += pixels[i] = pixels[i] = 255;"
   8753                       "}"
   8754                       "sum;");
   8755   CHECK_EQ(8 * 255, result->Int32Value());
   8756 
   8757   result = CompileRun("var sum = 0;"
   8758                       "for (var i = 0; i < 8; i++) {"
   8759                       "  sum += pixels[i] = pixels[i] = 256 + i;"
   8760                       "}"
   8761                       "sum;");
   8762   CHECK_EQ(2076, result->Int32Value());
   8763 
   8764   result = CompileRun("var sum = 0;"
   8765                       "for (var i = 0; i < 8; i++) {"
   8766                       "  sum += pixels[i] = pixels[i] = i;"
   8767                       "}"
   8768                       "sum;");
   8769   CHECK_EQ(28, result->Int32Value());
   8770 
   8771   result = CompileRun("var sum = 0;"
   8772                       "for (var i = 0; i < 8; i++) {"
   8773                       "  sum += pixels[i];"
   8774                       "}"
   8775                       "sum;");
   8776   CHECK_EQ(28, result->Int32Value());
   8777 
   8778   i::Handle<i::Smi> value(i::Smi::FromInt(2));
   8779   i::SetElement(jsobj, 1, value);
   8780   CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(1))->value());
   8781   *value.location() = i::Smi::FromInt(256);
   8782   i::SetElement(jsobj, 1, value);
   8783   CHECK_EQ(255, i::Smi::cast(jsobj->GetElement(1))->value());
   8784   *value.location() = i::Smi::FromInt(-1);
   8785   i::SetElement(jsobj, 1, value);
   8786   CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1))->value());
   8787 
   8788   result = CompileRun("for (var i = 0; i < 8; i++) {"
   8789                       "  pixels[i] = (i * 65) - 109;"
   8790                       "}"
   8791                       "pixels[1] + pixels[6];");
   8792   CHECK_EQ(255, result->Int32Value());
   8793   CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0))->value());
   8794   CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1))->value());
   8795   CHECK_EQ(21, i::Smi::cast(jsobj->GetElement(2))->value());
   8796   CHECK_EQ(86, i::Smi::cast(jsobj->GetElement(3))->value());
   8797   CHECK_EQ(151, i::Smi::cast(jsobj->GetElement(4))->value());
   8798   CHECK_EQ(216, i::Smi::cast(jsobj->GetElement(5))->value());
   8799   CHECK_EQ(255, i::Smi::cast(jsobj->GetElement(6))->value());
   8800   CHECK_EQ(255, i::Smi::cast(jsobj->GetElement(7))->value());
   8801   result = CompileRun("var sum = 0;"
   8802                       "for (var i = 0; i < 8; i++) {"
   8803                       "  sum += pixels[i];"
   8804                       "}"
   8805                       "sum;");
   8806   CHECK_EQ(984, result->Int32Value());
   8807 
   8808   result = CompileRun("for (var i = 0; i < 8; i++) {"
   8809                       "  pixels[i] = (i * 1.1);"
   8810                       "}"
   8811                       "pixels[1] + pixels[6];");
   8812   CHECK_EQ(8, result->Int32Value());
   8813   CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0))->value());
   8814   CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1))->value());
   8815   CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(2))->value());
   8816   CHECK_EQ(3, i::Smi::cast(jsobj->GetElement(3))->value());
   8817   CHECK_EQ(4, i::Smi::cast(jsobj->GetElement(4))->value());
   8818   CHECK_EQ(6, i::Smi::cast(jsobj->GetElement(5))->value());
   8819   CHECK_EQ(7, i::Smi::cast(jsobj->GetElement(6))->value());
   8820   CHECK_EQ(8, i::Smi::cast(jsobj->GetElement(7))->value());
   8821 
   8822   result = CompileRun("for (var i = 0; i < 8; i++) {"
   8823                       "  pixels[7] = undefined;"
   8824                       "}"
   8825                       "pixels[7];");
   8826   CHECK_EQ(0, result->Int32Value());
   8827   CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(7))->value());
   8828 
   8829   result = CompileRun("for (var i = 0; i < 8; i++) {"
   8830                       "  pixels[6] = '2.3';"
   8831                       "}"
   8832                       "pixels[6];");
   8833   CHECK_EQ(2, result->Int32Value());
   8834   CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(6))->value());
   8835 
   8836   result = CompileRun("for (var i = 0; i < 8; i++) {"
   8837                       "  pixels[5] = NaN;"
   8838                       "}"
   8839                       "pixels[5];");
   8840   CHECK_EQ(0, result->Int32Value());
   8841   CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5))->value());
   8842 
   8843   result = CompileRun("for (var i = 0; i < 8; i++) {"
   8844                       "  pixels[8] = Infinity;"
   8845                       "}"
   8846                       "pixels[8];");
   8847   CHECK_EQ(255, result->Int32Value());
   8848   CHECK_EQ(255, i::Smi::cast(jsobj->GetElement(8))->value());
   8849 
   8850   result = CompileRun("for (var i = 0; i < 8; i++) {"
   8851                       "  pixels[9] = -Infinity;"
   8852                       "}"
   8853                       "pixels[9];");
   8854   CHECK_EQ(0, result->Int32Value());
   8855   CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(9))->value());
   8856 
   8857   result = CompileRun("pixels[3] = 33;"
   8858                       "delete pixels[3];"
   8859                       "pixels[3];");
   8860   CHECK_EQ(33, result->Int32Value());
   8861 
   8862   result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
   8863                       "pixels[2] = 12; pixels[3] = 13;"
   8864                       "pixels.__defineGetter__('2',"
   8865                       "function() { return 120; });"
   8866                       "pixels[2];");
   8867   CHECK_EQ(12, result->Int32Value());
   8868 
   8869   result = CompileRun("var js_array = new Array(40);"
   8870                       "js_array[0] = 77;"
   8871                       "js_array;");
   8872   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
   8873 
   8874   result = CompileRun("pixels[1] = 23;"
   8875                       "pixels.__proto__ = [];"
   8876                       "js_array.__proto__ = pixels;"
   8877                       "js_array.concat(pixels);");
   8878   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
   8879   CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
   8880 
   8881   result = CompileRun("pixels[1] = 23;");
   8882   CHECK_EQ(23, result->Int32Value());
   8883 
   8884   // Test for index greater than 255.  Regression test for:
   8885   // http://code.google.com/p/chromium/issues/detail?id=26337.
   8886   result = CompileRun("pixels[256] = 255;");
   8887   CHECK_EQ(255, result->Int32Value());
   8888   result = CompileRun("var i = 0;"
   8889                       "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
   8890                       "i");
   8891   CHECK_EQ(255, result->Int32Value());
   8892 
   8893   free(pixel_data);
   8894 }
   8895 
   8896 
   8897 template <class ExternalArrayClass, class ElementType>
   8898 static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
   8899                                     int64_t low,
   8900                                     int64_t high) {
   8901   v8::HandleScope scope;
   8902   LocalContext context;
   8903   const int kElementCount = 40;
   8904   int element_size = 0;
   8905   switch (array_type) {
   8906     case v8::kExternalByteArray:
   8907     case v8::kExternalUnsignedByteArray:
   8908       element_size = 1;
   8909       break;
   8910     case v8::kExternalShortArray:
   8911     case v8::kExternalUnsignedShortArray:
   8912       element_size = 2;
   8913       break;
   8914     case v8::kExternalIntArray:
   8915     case v8::kExternalUnsignedIntArray:
   8916     case v8::kExternalFloatArray:
   8917       element_size = 4;
   8918       break;
   8919     default:
   8920       UNREACHABLE();
   8921       break;
   8922   }
   8923   ElementType* array_data =
   8924       static_cast<ElementType*>(malloc(kElementCount * element_size));
   8925   i::Handle<ExternalArrayClass> array =
   8926       i::Handle<ExternalArrayClass>::cast(
   8927           i::Factory::NewExternalArray(kElementCount, array_type, array_data));
   8928   i::Heap::CollectAllGarbage(false);  // Force GC to trigger verification.
   8929   for (int i = 0; i < kElementCount; i++) {
   8930     array->set(i, static_cast<ElementType>(i));
   8931   }
   8932   i::Heap::CollectAllGarbage(false);  // Force GC to trigger verification.
   8933   for (int i = 0; i < kElementCount; i++) {
   8934     CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array->get(i)));
   8935     CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
   8936   }
   8937 
   8938   v8::Handle<v8::Object> obj = v8::Object::New();
   8939   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
   8940   // Set the elements to be the external array.
   8941   obj->SetIndexedPropertiesToExternalArrayData(array_data,
   8942                                                array_type,
   8943                                                kElementCount);
   8944   CHECK_EQ(1, static_cast<int>(jsobj->GetElement(1)->Number()));
   8945   obj->Set(v8_str("field"), v8::Int32::New(1503));
   8946   context->Global()->Set(v8_str("ext_array"), obj);
   8947   v8::Handle<v8::Value> result = CompileRun("ext_array.field");
   8948   CHECK_EQ(1503, result->Int32Value());
   8949   result = CompileRun("ext_array[1]");
   8950   CHECK_EQ(1, result->Int32Value());
   8951 
   8952   // Check pass through of assigned smis
   8953   result = CompileRun("var sum = 0;"
   8954                       "for (var i = 0; i < 8; i++) {"
   8955                       "  sum += ext_array[i] = ext_array[i] = -i;"
   8956                       "}"
   8957                       "sum;");
   8958   CHECK_EQ(-28, result->Int32Value());
   8959 
   8960   // Check assigned smis
   8961   result = CompileRun("for (var i = 0; i < 8; i++) {"
   8962                       "  ext_array[i] = i;"
   8963                       "}"
   8964                       "var sum = 0;"
   8965                       "for (var i = 0; i < 8; i++) {"
   8966                       "  sum += ext_array[i];"
   8967                       "}"
   8968                       "sum;");
   8969   CHECK_EQ(28, result->Int32Value());
   8970 
   8971   // Check assigned smis in reverse order
   8972   result = CompileRun("for (var i = 8; --i >= 0; ) {"
   8973                       "  ext_array[i] = i;"
   8974                       "}"
   8975                       "var sum = 0;"
   8976                       "for (var i = 0; i < 8; i++) {"
   8977                       "  sum += ext_array[i];"
   8978                       "}"
   8979                       "sum;");
   8980   CHECK_EQ(28, result->Int32Value());
   8981 
   8982   // Check pass through of assigned HeapNumbers
   8983   result = CompileRun("var sum = 0;"
   8984                       "for (var i = 0; i < 16; i+=2) {"
   8985                       "  sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
   8986                       "}"
   8987                       "sum;");
   8988   CHECK_EQ(-28, result->Int32Value());
   8989 
   8990   // Check assigned HeapNumbers
   8991   result = CompileRun("for (var i = 0; i < 16; i+=2) {"
   8992                       "  ext_array[i] = (i * 0.5);"
   8993                       "}"
   8994                       "var sum = 0;"
   8995                       "for (var i = 0; i < 16; i+=2) {"
   8996                       "  sum += ext_array[i];"
   8997                       "}"
   8998                       "sum;");
   8999   CHECK_EQ(28, result->Int32Value());
   9000 
   9001   // Check assigned HeapNumbers in reverse order
   9002   result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
   9003                       "  ext_array[i] = (i * 0.5);"
   9004                       "}"
   9005                       "var sum = 0;"
   9006                       "for (var i = 0; i < 16; i+=2) {"
   9007                       "  sum += ext_array[i];"
   9008                       "}"
   9009                       "sum;");
   9010   CHECK_EQ(28, result->Int32Value());
   9011 
   9012   i::ScopedVector<char> test_buf(1024);
   9013 
   9014   // Check legal boundary conditions.
   9015   // The repeated loads and stores ensure the ICs are exercised.
   9016   const char* boundary_program =
   9017       "var res = 0;"
   9018       "for (var i = 0; i < 16; i++) {"
   9019       "  ext_array[i] = %lld;"
   9020       "  if (i > 8) {"
   9021       "    res = ext_array[i];"
   9022       "  }"
   9023       "}"
   9024       "res;";
   9025   i::OS::SNPrintF(test_buf,
   9026                   boundary_program,
   9027                   low);
   9028   result = CompileRun(test_buf.start());
   9029   CHECK_EQ(low, result->IntegerValue());
   9030 
   9031   i::OS::SNPrintF(test_buf,
   9032                   boundary_program,
   9033                   high);
   9034   result = CompileRun(test_buf.start());
   9035   CHECK_EQ(high, result->IntegerValue());
   9036 
   9037   // Check misprediction of type in IC.
   9038   result = CompileRun("var tmp_array = ext_array;"
   9039                       "var sum = 0;"
   9040                       "for (var i = 0; i < 8; i++) {"
   9041                       "  tmp_array[i] = i;"
   9042                       "  sum += tmp_array[i];"
   9043                       "  if (i == 4) {"
   9044                       "    tmp_array = {};"
   9045                       "  }"
   9046                       "}"
   9047                       "sum;");
   9048   i::Heap::CollectAllGarbage(false);  // Force GC to trigger verification.
   9049   CHECK_EQ(28, result->Int32Value());
   9050 
   9051   // Make sure out-of-range loads do not throw.
   9052   i::OS::SNPrintF(test_buf,
   9053                   "var caught_exception = false;"
   9054                   "try {"
   9055                   "  ext_array[%d];"
   9056                   "} catch (e) {"
   9057                   "  caught_exception = true;"
   9058                   "}"
   9059                   "caught_exception;",
   9060                   kElementCount);
   9061   result = CompileRun(test_buf.start());
   9062   CHECK_EQ(false, result->BooleanValue());
   9063 
   9064   // Make sure out-of-range stores do not throw.
   9065   i::OS::SNPrintF(test_buf,
   9066                   "var caught_exception = false;"
   9067                   "try {"
   9068                   "  ext_array[%d] = 1;"
   9069                   "} catch (e) {"
   9070                   "  caught_exception = true;"
   9071                   "}"
   9072                   "caught_exception;",
   9073                   kElementCount);
   9074   result = CompileRun(test_buf.start());
   9075   CHECK_EQ(false, result->BooleanValue());
   9076 
   9077   // Check other boundary conditions, values and operations.
   9078   result = CompileRun("for (var i = 0; i < 8; i++) {"
   9079                       "  ext_array[7] = undefined;"
   9080                       "}"
   9081                       "ext_array[7];");
   9082   CHECK_EQ(0, result->Int32Value());
   9083   CHECK_EQ(0, static_cast<int>(jsobj->GetElement(7)->Number()));
   9084 
   9085   result = CompileRun("for (var i = 0; i < 8; i++) {"
   9086                       "  ext_array[6] = '2.3';"
   9087                       "}"
   9088                       "ext_array[6];");
   9089   CHECK_EQ(2, result->Int32Value());
   9090   CHECK_EQ(2, static_cast<int>(jsobj->GetElement(6)->Number()));
   9091 
   9092   if (array_type != v8::kExternalFloatArray) {
   9093     // Though the specification doesn't state it, be explicit about
   9094     // converting NaNs and +/-Infinity to zero.
   9095     result = CompileRun("for (var i = 0; i < 8; i++) {"
   9096                         "  ext_array[i] = 5;"
   9097                         "}"
   9098                         "for (var i = 0; i < 8; i++) {"
   9099                         "  ext_array[i] = NaN;"
   9100                         "}"
   9101                         "ext_array[5];");
   9102     CHECK_EQ(0, result->Int32Value());
   9103     CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5))->value());
   9104 
   9105     result = CompileRun("for (var i = 0; i < 8; i++) {"
   9106                         "  ext_array[i] = 5;"
   9107                         "}"
   9108                         "for (var i = 0; i < 8; i++) {"
   9109                         "  ext_array[i] = Infinity;"
   9110                         "}"
   9111                         "ext_array[5];");
   9112     CHECK_EQ(0, result->Int32Value());
   9113     CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5))->value());
   9114 
   9115     result = CompileRun("for (var i = 0; i < 8; i++) {"
   9116                         "  ext_array[i] = 5;"
   9117                         "}"
   9118                         "for (var i = 0; i < 8; i++) {"
   9119                         "  ext_array[i] = -Infinity;"
   9120                         "}"
   9121                         "ext_array[5];");
   9122     CHECK_EQ(0, result->Int32Value());
   9123     CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5))->value());
   9124   }
   9125 
   9126   result = CompileRun("ext_array[3] = 33;"
   9127                       "delete ext_array[3];"
   9128                       "ext_array[3];");
   9129   CHECK_EQ(33, result->Int32Value());
   9130 
   9131   result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
   9132                       "ext_array[2] = 12; ext_array[3] = 13;"
   9133                       "ext_array.__defineGetter__('2',"
   9134                       "function() { return 120; });"
   9135                       "ext_array[2];");
   9136   CHECK_EQ(12, result->Int32Value());
   9137 
   9138   result = CompileRun("var js_array = new Array(40);"
   9139                       "js_array[0] = 77;"
   9140                       "js_array;");
   9141   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
   9142 
   9143   result = CompileRun("ext_array[1] = 23;"
   9144                       "ext_array.__proto__ = [];"
   9145                       "js_array.__proto__ = ext_array;"
   9146                       "js_array.concat(ext_array);");
   9147   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
   9148   CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
   9149 
   9150   result = CompileRun("ext_array[1] = 23;");
   9151   CHECK_EQ(23, result->Int32Value());
   9152 
   9153   // Test more complex manipulations which cause eax to contain values
   9154   // that won't be completely overwritten by loads from the arrays.
   9155   // This catches bugs in the instructions used for the KeyedLoadIC
   9156   // for byte and word types.
   9157   {
   9158     const int kXSize = 300;
   9159     const int kYSize = 300;
   9160     const int kLargeElementCount = kXSize * kYSize * 4;
   9161     ElementType* large_array_data =
   9162         static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
   9163     i::Handle<ExternalArrayClass> large_array =
   9164         i::Handle<ExternalArrayClass>::cast(
   9165             i::Factory::NewExternalArray(kLargeElementCount,
   9166                                          array_type,
   9167                                          array_data));
   9168     v8::Handle<v8::Object> large_obj = v8::Object::New();
   9169     // Set the elements to be the external array.
   9170     large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
   9171                                                        array_type,
   9172                                                        kLargeElementCount);
   9173     context->Global()->Set(v8_str("large_array"), large_obj);
   9174     // Initialize contents of a few rows.
   9175     for (int x = 0; x < 300; x++) {
   9176       int row = 0;
   9177       int offset = row * 300 * 4;
   9178       large_array_data[offset + 4 * x + 0] = (ElementType) 127;
   9179       large_array_data[offset + 4 * x + 1] = (ElementType) 0;
   9180       large_array_data[offset + 4 * x + 2] = (ElementType) 0;
   9181       large_array_data[offset + 4 * x + 3] = (ElementType) 127;
   9182       row = 150;
   9183       offset = row * 300 * 4;
   9184       large_array_data[offset + 4 * x + 0] = (ElementType) 127;
   9185       large_array_data[offset + 4 * x + 1] = (ElementType) 0;
   9186       large_array_data[offset + 4 * x + 2] = (ElementType) 0;
   9187       large_array_data[offset + 4 * x + 3] = (ElementType) 127;
   9188       row = 298;
   9189       offset = row * 300 * 4;
   9190       large_array_data[offset + 4 * x + 0] = (ElementType) 127;
   9191       large_array_data[offset + 4 * x + 1] = (ElementType) 0;
   9192       large_array_data[offset + 4 * x + 2] = (ElementType) 0;
   9193       large_array_data[offset + 4 * x + 3] = (ElementType) 127;
   9194     }
   9195     // The goal of the code below is to make "offset" large enough
   9196     // that the computation of the index (which goes into eax) has
   9197     // high bits set which will not be overwritten by a byte or short
   9198     // load.
   9199     result = CompileRun("var failed = false;"
   9200                         "var offset = 0;"
   9201                         "for (var i = 0; i < 300; i++) {"
   9202                         "  if (large_array[4 * i] != 127 ||"
   9203                         "      large_array[4 * i + 1] != 0 ||"
   9204                         "      large_array[4 * i + 2] != 0 ||"
   9205                         "      large_array[4 * i + 3] != 127) {"
   9206                         "    failed = true;"
   9207                         "  }"
   9208                         "}"
   9209                         "offset = 150 * 300 * 4;"
   9210                         "for (var i = 0; i < 300; i++) {"
   9211                         "  if (large_array[offset + 4 * i] != 127 ||"
   9212                         "      large_array[offset + 4 * i + 1] != 0 ||"
   9213                         "      large_array[offset + 4 * i + 2] != 0 ||"
   9214                         "      large_array[offset + 4 * i + 3] != 127) {"
   9215                         "    failed = true;"
   9216                         "  }"
   9217                         "}"
   9218                         "offset = 298 * 300 * 4;"
   9219                         "for (var i = 0; i < 300; i++) {"
   9220                         "  if (large_array[offset + 4 * i] != 127 ||"
   9221                         "      large_array[offset + 4 * i + 1] != 0 ||"
   9222                         "      large_array[offset + 4 * i + 2] != 0 ||"
   9223                         "      large_array[offset + 4 * i + 3] != 127) {"
   9224                         "    failed = true;"
   9225                         "  }"
   9226                         "}"
   9227                         "!failed;");
   9228     CHECK_EQ(true, result->BooleanValue());
   9229     free(large_array_data);
   9230   }
   9231 
   9232   free(array_data);
   9233 }
   9234 
   9235 
   9236 THREADED_TEST(ExternalByteArray) {
   9237   ExternalArrayTestHelper<v8::internal::ExternalByteArray, int8_t>(
   9238       v8::kExternalByteArray,
   9239       -128,
   9240       127);
   9241 }
   9242 
   9243 
   9244 THREADED_TEST(ExternalUnsignedByteArray) {
   9245   ExternalArrayTestHelper<v8::internal::ExternalUnsignedByteArray, uint8_t>(
   9246       v8::kExternalUnsignedByteArray,
   9247       0,
   9248       255);
   9249 }
   9250 
   9251 
   9252 THREADED_TEST(ExternalShortArray) {
   9253   ExternalArrayTestHelper<v8::internal::ExternalShortArray, int16_t>(
   9254       v8::kExternalShortArray,
   9255       -32768,
   9256       32767);
   9257 }
   9258 
   9259 
   9260 THREADED_TEST(ExternalUnsignedShortArray) {
   9261   ExternalArrayTestHelper<v8::internal::ExternalUnsignedShortArray, uint16_t>(
   9262       v8::kExternalUnsignedShortArray,
   9263       0,
   9264       65535);
   9265 }
   9266 
   9267 
   9268 THREADED_TEST(ExternalIntArray) {
   9269   ExternalArrayTestHelper<v8::internal::ExternalIntArray, int32_t>(
   9270       v8::kExternalIntArray,
   9271       INT_MIN,   // -2147483648
   9272       INT_MAX);  //  2147483647
   9273 }
   9274 
   9275 
   9276 THREADED_TEST(ExternalUnsignedIntArray) {
   9277   ExternalArrayTestHelper<v8::internal::ExternalUnsignedIntArray, uint32_t>(
   9278       v8::kExternalUnsignedIntArray,
   9279       0,
   9280       UINT_MAX);  // 4294967295
   9281 }
   9282 
   9283 
   9284 THREADED_TEST(ExternalFloatArray) {
   9285   ExternalArrayTestHelper<v8::internal::ExternalFloatArray, float>(
   9286       v8::kExternalFloatArray,
   9287       -500,
   9288       500);
   9289 }
   9290 
   9291 
   9292 THREADED_TEST(ExternalArrays) {
   9293   TestExternalByteArray();
   9294   TestExternalUnsignedByteArray();
   9295   TestExternalShortArray();
   9296   TestExternalUnsignedShortArray();
   9297   TestExternalIntArray();
   9298   TestExternalUnsignedIntArray();
   9299   TestExternalFloatArray();
   9300 }
   9301 
   9302 
   9303 THREADED_TEST(ScriptContextDependence) {
   9304   v8::HandleScope scope;
   9305   LocalContext c1;
   9306   const char *source = "foo";
   9307   v8::Handle<v8::Script> dep = v8::Script::Compile(v8::String::New(source));
   9308   v8::Handle<v8::Script> indep = v8::Script::New(v8::String::New(source));
   9309   c1->Global()->Set(v8::String::New("foo"), v8::Integer::New(100));
   9310   CHECK_EQ(dep->Run()->Int32Value(), 100);
   9311   CHECK_EQ(indep->Run()->Int32Value(), 100);
   9312   LocalContext c2;
   9313   c2->Global()->Set(v8::String::New("foo"), v8::Integer::New(101));
   9314   CHECK_EQ(dep->Run()->Int32Value(), 100);
   9315   CHECK_EQ(indep->Run()->Int32Value(), 101);
   9316 }
   9317 
   9318 
   9319 THREADED_TEST(StackTrace) {
   9320   v8::HandleScope scope;
   9321   LocalContext context;
   9322   v8::TryCatch try_catch;
   9323   const char *source = "function foo() { FAIL.FAIL; }; foo();";
   9324   v8::Handle<v8::String> src = v8::String::New(source);
   9325   v8::Handle<v8::String> origin = v8::String::New("stack-trace-test");
   9326   v8::Script::New(src, origin)->Run();
   9327   CHECK(try_catch.HasCaught());
   9328   v8::String::Utf8Value stack(try_catch.StackTrace());
   9329   CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
   9330 }
   9331 
   9332 
   9333 // Test that idle notification can be handled and eventually returns true.
   9334 THREADED_TEST(IdleNotification) {
   9335   bool rv = false;
   9336   for (int i = 0; i < 100; i++) {
   9337     rv = v8::V8::IdleNotification();
   9338     if (rv)
   9339       break;
   9340   }
   9341   CHECK(rv == true);
   9342 }
   9343 
   9344 
   9345 static uint32_t* stack_limit;
   9346 
   9347 static v8::Handle<Value> GetStackLimitCallback(const v8::Arguments& args) {
   9348   stack_limit = reinterpret_cast<uint32_t*>(i::StackGuard::climit());
   9349   return v8::Undefined();
   9350 }
   9351 
   9352 
   9353 // Uses the address of a local variable to determine the stack top now.
   9354 // Given a size, returns an address that is that far from the current
   9355 // top of stack.
   9356 static uint32_t* ComputeStackLimit(uint32_t size) {
   9357   uint32_t* answer = &size - (size / sizeof(size));
   9358   // If the size is very large and the stack is very near the bottom of
   9359   // memory then the calculation above may wrap around and give an address
   9360   // that is above the (downwards-growing) stack.  In that case we return
   9361   // a very low address.
   9362   if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
   9363   return answer;
   9364 }
   9365 
   9366 
   9367 TEST(SetResourceConstraints) {
   9368   static const int K = 1024;
   9369   uint32_t* set_limit = ComputeStackLimit(128 * K);
   9370 
   9371   // Set stack limit.
   9372   v8::ResourceConstraints constraints;
   9373   constraints.set_stack_limit(set_limit);
   9374   CHECK(v8::SetResourceConstraints(&constraints));
   9375 
   9376   // Execute a script.
   9377   v8::HandleScope scope;
   9378   LocalContext env;
   9379   Local<v8::FunctionTemplate> fun_templ =
   9380       v8::FunctionTemplate::New(GetStackLimitCallback);
   9381   Local<Function> fun = fun_templ->GetFunction();
   9382   env->Global()->Set(v8_str("get_stack_limit"), fun);
   9383   CompileRun("get_stack_limit();");
   9384 
   9385   CHECK(stack_limit == set_limit);
   9386 }
   9387 
   9388 
   9389 TEST(SetResourceConstraintsInThread) {
   9390   uint32_t* set_limit;
   9391   {
   9392     v8::Locker locker;
   9393     static const int K = 1024;
   9394     set_limit = ComputeStackLimit(128 * K);
   9395 
   9396     // Set stack limit.
   9397     v8::ResourceConstraints constraints;
   9398     constraints.set_stack_limit(set_limit);
   9399     CHECK(v8::SetResourceConstraints(&constraints));
   9400 
   9401     // Execute a script.
   9402     v8::HandleScope scope;
   9403     LocalContext env;
   9404     Local<v8::FunctionTemplate> fun_templ =
   9405         v8::FunctionTemplate::New(GetStackLimitCallback);
   9406     Local<Function> fun = fun_templ->GetFunction();
   9407     env->Global()->Set(v8_str("get_stack_limit"), fun);
   9408     CompileRun("get_stack_limit();");
   9409 
   9410     CHECK(stack_limit == set_limit);
   9411   }
   9412   {
   9413     v8::Locker locker;
   9414     CHECK(stack_limit == set_limit);
   9415   }
   9416 }
   9417 
   9418 
   9419 THREADED_TEST(GetHeapStatistics) {
   9420   v8::HandleScope scope;
   9421   LocalContext c1;
   9422   v8::HeapStatistics heap_statistics;
   9423   CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
   9424   CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
   9425   v8::V8::GetHeapStatistics(&heap_statistics);
   9426   CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
   9427   CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
   9428 }
   9429 
   9430 
   9431 static double DoubleFromBits(uint64_t value) {
   9432   double target;
   9433 #ifdef BIG_ENDIAN_FLOATING_POINT
   9434   const int kIntSize = 4;
   9435   // Somebody swapped the lower and higher half of doubles.
   9436   memcpy(&target, reinterpret_cast<char*>(&value) + kIntSize, kIntSize);
   9437   memcpy(reinterpret_cast<char*>(&target) + kIntSize, &value, kIntSize);
   9438 #else
   9439   memcpy(&target, &value, sizeof(target));
   9440 #endif
   9441   return target;
   9442 }
   9443 
   9444 
   9445 static uint64_t DoubleToBits(double value) {
   9446   uint64_t target;
   9447 #ifdef BIG_ENDIAN_FLOATING_POINT
   9448   const int kIntSize = 4;
   9449   // Somebody swapped the lower and higher half of doubles.
   9450   memcpy(&target, reinterpret_cast<char*>(&value) + kIntSize, kIntSize);
   9451   memcpy(reinterpret_cast<char*>(&target) + kIntSize, &value, kIntSize);
   9452 #else
   9453   memcpy(&target, &value, sizeof(target));
   9454 #endif
   9455   return target;
   9456 }
   9457 
   9458 
   9459 static double DoubleToDateTime(double input) {
   9460   double date_limit = 864e13;
   9461   if (IsNaN(input) || input < -date_limit || input > date_limit) {
   9462     return i::OS::nan_value();
   9463   }
   9464   return (input < 0) ? -(floor(-input)) : floor(input);
   9465 }
   9466 
   9467 // We don't have a consistent way to write 64-bit constants syntactically, so we
   9468 // split them into two 32-bit constants and combine them programmatically.
   9469 static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
   9470   return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
   9471 }
   9472 
   9473 
   9474 THREADED_TEST(QuietSignalingNaNs) {
   9475   v8::HandleScope scope;
   9476   LocalContext context;
   9477   v8::TryCatch try_catch;
   9478 
   9479   // Special double values.
   9480   double snan = DoubleFromBits(0x7ff00000, 0x00000001);
   9481   double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
   9482   double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
   9483   double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
   9484   double min_normal = DoubleFromBits(0x00100000, 0x00000000);
   9485   double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
   9486   double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
   9487 
   9488   // Date values are capped at +/-100000000 days (times 864e5 ms per day)
   9489   // on either side of the epoch.
   9490   double date_limit = 864e13;
   9491 
   9492   double test_values[] = {
   9493       snan,
   9494       qnan,
   9495       infinity,
   9496       max_normal,
   9497       date_limit + 1,
   9498       date_limit,
   9499       min_normal,
   9500       max_denormal,
   9501       min_denormal,
   9502       0,
   9503       -0,
   9504       -min_denormal,
   9505       -max_denormal,
   9506       -min_normal,
   9507       -date_limit,
   9508       -date_limit - 1,
   9509       -max_normal,
   9510       -infinity,
   9511       -qnan,
   9512       -snan
   9513   };
   9514   int num_test_values = 20;
   9515 
   9516   for (int i = 0; i < num_test_values; i++) {
   9517     double test_value = test_values[i];
   9518 
   9519     // Check that Number::New preserves non-NaNs and quiets SNaNs.
   9520     v8::Handle<v8::Value> number = v8::Number::New(test_value);
   9521     double stored_number = number->NumberValue();
   9522     if (!IsNaN(test_value)) {
   9523       CHECK_EQ(test_value, stored_number);
   9524     } else {
   9525       uint64_t stored_bits = DoubleToBits(stored_number);
   9526       // Check if quiet nan (bits 51..62 all set).
   9527       CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
   9528     }
   9529 
   9530     // Check that Date::New preserves non-NaNs in the date range and
   9531     // quiets SNaNs.
   9532     v8::Handle<v8::Value> date = v8::Date::New(test_value);
   9533     double expected_stored_date = DoubleToDateTime(test_value);
   9534     double stored_date = date->NumberValue();
   9535     if (!IsNaN(expected_stored_date)) {
   9536       CHECK_EQ(expected_stored_date, stored_date);
   9537     } else {
   9538       uint64_t stored_bits = DoubleToBits(stored_date);
   9539       // Check if quiet nan (bits 51..62 all set).
   9540       CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
   9541     }
   9542   }
   9543 }
   9544 
   9545 
   9546 static v8::Handle<Value> SpaghettiIncident(const v8::Arguments& args) {
   9547   v8::HandleScope scope;
   9548   v8::TryCatch tc;
   9549   v8::Handle<v8::String> str = args[0]->ToString();
   9550   if (tc.HasCaught())
   9551     return tc.ReThrow();
   9552   return v8::Undefined();
   9553 }
   9554 
   9555 
   9556 // Test that an exception can be propagated down through a spaghetti
   9557 // stack using ReThrow.
   9558 THREADED_TEST(SpaghettiStackReThrow) {
   9559   v8::HandleScope scope;
   9560   LocalContext context;
   9561   context->Global()->Set(
   9562       v8::String::New("s"),
   9563       v8::FunctionTemplate::New(SpaghettiIncident)->GetFunction());
   9564   v8::TryCatch try_catch;
   9565   CompileRun(
   9566       "var i = 0;"
   9567       "var o = {"
   9568       "  toString: function () {"
   9569       "    if (i == 10) {"
   9570       "      throw 'Hey!';"
   9571       "    } else {"
   9572       "      i++;"
   9573       "      return s(o);"
   9574       "    }"
   9575       "  }"
   9576       "};"
   9577       "s(o);");
   9578   CHECK(try_catch.HasCaught());
   9579   v8::String::Utf8Value value(try_catch.Exception());
   9580   CHECK_EQ(0, strcmp(*value, "Hey!"));
   9581 }
   9582 
   9583 
   9584 TEST(Regress528) {
   9585   v8::V8::Initialize();
   9586 
   9587   v8::HandleScope scope;
   9588   v8::Persistent<Context> context;
   9589   v8::Persistent<Context> other_context;
   9590   int gc_count;
   9591 
   9592   // Create a context used to keep the code from aging in the compilation
   9593   // cache.
   9594   other_context = Context::New();
   9595 
   9596   // Context-dependent context data creates reference from the compilation
   9597   // cache to the global object.
   9598   const char* source_simple = "1";
   9599   context = Context::New();
   9600   {
   9601     v8::HandleScope scope;
   9602 
   9603     context->Enter();
   9604     Local<v8::String> obj = v8::String::New("");
   9605     context->SetData(obj);
   9606     CompileRun(source_simple);
   9607     context->Exit();
   9608   }
   9609   context.Dispose();
   9610   for (gc_count = 1; gc_count < 10; gc_count++) {
   9611     other_context->Enter();
   9612     CompileRun(source_simple);
   9613     other_context->Exit();
   9614     v8::internal::Heap::CollectAllGarbage(false);
   9615     if (GetGlobalObjectsCount() == 1) break;
   9616   }
   9617   CHECK_GE(2, gc_count);
   9618   CHECK_EQ(1, GetGlobalObjectsCount());
   9619 
   9620   // Eval in a function creates reference from the compilation cache to the
   9621   // global object.
   9622   const char* source_eval = "function f(){eval('1')}; f()";
   9623   context = Context::New();
   9624   {
   9625     v8::HandleScope scope;
   9626 
   9627     context->Enter();
   9628     CompileRun(source_eval);
   9629     context->Exit();
   9630   }
   9631   context.Dispose();
   9632   for (gc_count = 1; gc_count < 10; gc_count++) {
   9633     other_context->Enter();
   9634     CompileRun(source_eval);
   9635     other_context->Exit();
   9636     v8::internal::Heap::CollectAllGarbage(false);
   9637     if (GetGlobalObjectsCount() == 1) break;
   9638   }
   9639   CHECK_GE(2, gc_count);
   9640   CHECK_EQ(1, GetGlobalObjectsCount());
   9641 
   9642   // Looking up the line number for an exception creates reference from the
   9643   // compilation cache to the global object.
   9644   const char* source_exception = "function f(){throw 1;} f()";
   9645   context = Context::New();
   9646   {
   9647     v8::HandleScope scope;
   9648 
   9649     context->Enter();
   9650     v8::TryCatch try_catch;
   9651     CompileRun(source_exception);
   9652     CHECK(try_catch.HasCaught());
   9653     v8::Handle<v8::Message> message = try_catch.Message();
   9654     CHECK(!message.IsEmpty());
   9655     CHECK_EQ(1, message->GetLineNumber());
   9656     context->Exit();
   9657   }
   9658   context.Dispose();
   9659   for (gc_count = 1; gc_count < 10; gc_count++) {
   9660     other_context->Enter();
   9661     CompileRun(source_exception);
   9662     other_context->Exit();
   9663     v8::internal::Heap::CollectAllGarbage(false);
   9664     if (GetGlobalObjectsCount() == 1) break;
   9665   }
   9666   CHECK_GE(2, gc_count);
   9667   CHECK_EQ(1, GetGlobalObjectsCount());
   9668 
   9669   other_context.Dispose();
   9670 }
   9671 
   9672 
   9673 THREADED_TEST(ScriptOrigin) {
   9674   v8::HandleScope scope;
   9675   LocalContext env;
   9676   v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
   9677   v8::Handle<v8::String> script = v8::String::New(
   9678       "function f() {}\n\nfunction g() {}");
   9679   v8::Script::Compile(script, &origin)->Run();
   9680   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
   9681       env->Global()->Get(v8::String::New("f")));
   9682   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
   9683       env->Global()->Get(v8::String::New("g")));
   9684 
   9685   v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
   9686   CHECK_EQ("test", *v8::String::AsciiValue(script_origin_f.ResourceName()));
   9687   CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
   9688 
   9689   v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
   9690   CHECK_EQ("test", *v8::String::AsciiValue(script_origin_g.ResourceName()));
   9691   CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
   9692 }
   9693 
   9694 
   9695 THREADED_TEST(ScriptLineNumber) {
   9696   v8::HandleScope scope;
   9697   LocalContext env;
   9698   v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
   9699   v8::Handle<v8::String> script = v8::String::New(
   9700       "function f() {}\n\nfunction g() {}");
   9701   v8::Script::Compile(script, &origin)->Run();
   9702   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
   9703       env->Global()->Get(v8::String::New("f")));
   9704   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
   9705       env->Global()->Get(v8::String::New("g")));
   9706   CHECK_EQ(0, f->GetScriptLineNumber());
   9707   CHECK_EQ(2, g->GetScriptLineNumber());
   9708 }
   9709 
   9710 
   9711 static v8::Handle<Value> GetterWhichReturns42(Local<String> name,
   9712                                               const AccessorInfo& info) {
   9713   return v8_num(42);
   9714 }
   9715 
   9716 
   9717 static void SetterWhichSetsYOnThisTo23(Local<String> name,
   9718                                        Local<Value> value,
   9719                                        const AccessorInfo& info) {
   9720   info.This()->Set(v8_str("y"), v8_num(23));
   9721 }
   9722 
   9723 
   9724 THREADED_TEST(SetterOnConstructorPrototype) {
   9725   v8::HandleScope scope;
   9726   Local<ObjectTemplate> templ = ObjectTemplate::New();
   9727   templ->SetAccessor(v8_str("x"),
   9728                      GetterWhichReturns42,
   9729                      SetterWhichSetsYOnThisTo23);
   9730   LocalContext context;
   9731   context->Global()->Set(v8_str("P"), templ->NewInstance());
   9732   CompileRun("function C1() {"
   9733              "  this.x = 23;"
   9734              "};"
   9735              "C1.prototype = P;"
   9736              "function C2() {"
   9737              "  this.x = 23"
   9738              "};"
   9739              "C2.prototype = { };"
   9740              "C2.prototype.__proto__ = P;");
   9741 
   9742   v8::Local<v8::Script> script;
   9743   script = v8::Script::Compile(v8_str("new C1();"));
   9744   for (int i = 0; i < 10; i++) {
   9745     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
   9746     CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
   9747     CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
   9748   }
   9749 
   9750   script = v8::Script::Compile(v8_str("new C2();"));
   9751   for (int i = 0; i < 10; i++) {
   9752     v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
   9753     CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
   9754     CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
   9755   }
   9756 }
   9757 
   9758 
   9759 static v8::Handle<Value> NamedPropertyGetterWhichReturns42(
   9760     Local<String> name, const AccessorInfo& info) {
   9761   return v8_num(42);
   9762 }
   9763 
   9764 
   9765 static v8::Handle<Value> NamedPropertySetterWhichSetsYOnThisTo23(
   9766     Local<String> name, Local<Value> value, const AccessorInfo& info) {
   9767   if (name->Equals(v8_str("x"))) {
   9768     info.This()->Set(v8_str("y"), v8_num(23));
   9769   }
   9770   return v8::Handle<Value>();
   9771 }
   9772 
   9773 
   9774 THREADED_TEST(InterceptorOnConstructorPrototype) {
   9775   v8::HandleScope scope;
   9776   Local<ObjectTemplate> templ = ObjectTemplate::New();
   9777   templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
   9778                                  NamedPropertySetterWhichSetsYOnThisTo23);
   9779   LocalContext context;
   9780   context->Global()->Set(v8_str("P"), templ->NewInstance());
   9781   CompileRun("function C1() {"
   9782              "  this.x = 23;"
   9783              "};"
   9784              "C1.prototype = P;"
   9785              "function C2() {"
   9786              "  this.x = 23"
   9787              "};"
   9788              "C2.prototype = { };"
   9789              "C2.prototype.__proto__ = P;");
   9790 
   9791   v8::Local<v8::Script> script;
   9792   script = v8::Script::Compile(v8_str("new C1();"));
   9793   for (int i = 0; i < 10; i++) {
   9794     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
   9795     CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
   9796     CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
   9797   }
   9798 
   9799   script = v8::Script::Compile(v8_str("new C2();"));
   9800   for (int i = 0; i < 10; i++) {
   9801     v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
   9802     CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
   9803     CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
   9804   }
   9805 }
   9806