Home | History | Annotate | Download | only in cctest
      1 // Copyright 2012 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 "isolate.h"
     34 #include "compilation-cache.h"
     35 #include "execution.h"
     36 #include "snapshot.h"
     37 #include "platform.h"
     38 #include "utils.h"
     39 #include "cctest.h"
     40 #include "parser.h"
     41 #include "unicode-inl.h"
     42 
     43 static const bool kLogThreading = false;
     44 
     45 static bool IsNaN(double x) {
     46 #ifdef WIN32
     47   return _isnan(x);
     48 #else
     49   return isnan(x);
     50 #endif
     51 }
     52 
     53 using ::v8::AccessorInfo;
     54 using ::v8::Arguments;
     55 using ::v8::Context;
     56 using ::v8::Extension;
     57 using ::v8::Function;
     58 using ::v8::FunctionTemplate;
     59 using ::v8::Handle;
     60 using ::v8::HandleScope;
     61 using ::v8::Local;
     62 using ::v8::Message;
     63 using ::v8::MessageCallback;
     64 using ::v8::Object;
     65 using ::v8::ObjectTemplate;
     66 using ::v8::Persistent;
     67 using ::v8::Script;
     68 using ::v8::StackTrace;
     69 using ::v8::String;
     70 using ::v8::TryCatch;
     71 using ::v8::Undefined;
     72 using ::v8::V8;
     73 using ::v8::Value;
     74 
     75 
     76 static void ExpectString(const char* code, const char* expected) {
     77   Local<Value> result = CompileRun(code);
     78   CHECK(result->IsString());
     79   String::AsciiValue ascii(result);
     80   CHECK_EQ(expected, *ascii);
     81 }
     82 
     83 static void ExpectInt32(const char* code, int expected) {
     84   Local<Value> result = CompileRun(code);
     85   CHECK(result->IsInt32());
     86   CHECK_EQ(expected, result->Int32Value());
     87 }
     88 
     89 static void ExpectBoolean(const char* code, bool expected) {
     90   Local<Value> result = CompileRun(code);
     91   CHECK(result->IsBoolean());
     92   CHECK_EQ(expected, result->BooleanValue());
     93 }
     94 
     95 
     96 static void ExpectTrue(const char* code) {
     97   ExpectBoolean(code, true);
     98 }
     99 
    100 
    101 static void ExpectFalse(const char* code) {
    102   ExpectBoolean(code, false);
    103 }
    104 
    105 
    106 static void ExpectObject(const char* code, Local<Value> expected) {
    107   Local<Value> result = CompileRun(code);
    108   CHECK(result->Equals(expected));
    109 }
    110 
    111 
    112 static void ExpectUndefined(const char* code) {
    113   Local<Value> result = CompileRun(code);
    114   CHECK(result->IsUndefined());
    115 }
    116 
    117 
    118 static int signature_callback_count;
    119 static v8::Handle<Value> IncrementingSignatureCallback(
    120     const v8::Arguments& args) {
    121   ApiTestFuzzer::Fuzz();
    122   signature_callback_count++;
    123   v8::Handle<v8::Array> result = v8::Array::New(args.Length());
    124   for (int i = 0; i < args.Length(); i++)
    125     result->Set(v8::Integer::New(i), args[i]);
    126   return result;
    127 }
    128 
    129 
    130 static v8::Handle<Value> SignatureCallback(const v8::Arguments& args) {
    131   ApiTestFuzzer::Fuzz();
    132   v8::Handle<v8::Array> result = v8::Array::New(args.Length());
    133   for (int i = 0; i < args.Length(); i++) {
    134     result->Set(v8::Integer::New(i), args[i]);
    135   }
    136   return result;
    137 }
    138 
    139 
    140 THREADED_TEST(Handles) {
    141   v8::HandleScope scope;
    142   Local<Context> local_env;
    143   {
    144     LocalContext env;
    145     local_env = env.local();
    146   }
    147 
    148   // Local context should still be live.
    149   CHECK(!local_env.IsEmpty());
    150   local_env->Enter();
    151 
    152   v8::Handle<v8::Primitive> undef = v8::Undefined();
    153   CHECK(!undef.IsEmpty());
    154   CHECK(undef->IsUndefined());
    155 
    156   const char* c_source = "1 + 2 + 3";
    157   Local<String> source = String::New(c_source);
    158   Local<Script> script = Script::Compile(source);
    159   CHECK_EQ(6, script->Run()->Int32Value());
    160 
    161   local_env->Exit();
    162 }
    163 
    164 
    165 THREADED_TEST(ReceiverSignature) {
    166   v8::HandleScope scope;
    167   LocalContext env;
    168   v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
    169   v8::Handle<v8::Signature> sig = v8::Signature::New(fun);
    170   fun->PrototypeTemplate()->Set(
    171       v8_str("m"),
    172       v8::FunctionTemplate::New(IncrementingSignatureCallback,
    173                                 v8::Handle<Value>(),
    174                                 sig));
    175   env->Global()->Set(v8_str("Fun"), fun->GetFunction());
    176   signature_callback_count = 0;
    177   CompileRun(
    178       "var o = new Fun();"
    179       "o.m();");
    180   CHECK_EQ(1, signature_callback_count);
    181   v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New();
    182   sub_fun->Inherit(fun);
    183   env->Global()->Set(v8_str("SubFun"), sub_fun->GetFunction());
    184   CompileRun(
    185       "var o = new SubFun();"
    186       "o.m();");
    187   CHECK_EQ(2, signature_callback_count);
    188 
    189   v8::TryCatch try_catch;
    190   CompileRun(
    191       "var o = { };"
    192       "o.m = Fun.prototype.m;"
    193       "o.m();");
    194   CHECK_EQ(2, signature_callback_count);
    195   CHECK(try_catch.HasCaught());
    196   try_catch.Reset();
    197   v8::Handle<v8::FunctionTemplate> unrel_fun = v8::FunctionTemplate::New();
    198   sub_fun->Inherit(fun);
    199   env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
    200   CompileRun(
    201       "var o = new UnrelFun();"
    202       "o.m = Fun.prototype.m;"
    203       "o.m();");
    204   CHECK_EQ(2, signature_callback_count);
    205   CHECK(try_catch.HasCaught());
    206 }
    207 
    208 
    209 THREADED_TEST(ArgumentSignature) {
    210   v8::HandleScope scope;
    211   LocalContext env;
    212   v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New();
    213   cons->SetClassName(v8_str("Cons"));
    214   v8::Handle<v8::Signature> sig =
    215       v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 1, &cons);
    216   v8::Handle<v8::FunctionTemplate> fun =
    217       v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), sig);
    218   env->Global()->Set(v8_str("Cons"), cons->GetFunction());
    219   env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
    220 
    221   v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
    222   CHECK(value1->IsTrue());
    223 
    224   v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
    225   CHECK(value2->IsTrue());
    226 
    227   v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
    228   CHECK(value3->IsTrue());
    229 
    230   v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New();
    231   cons1->SetClassName(v8_str("Cons1"));
    232   v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New();
    233   cons2->SetClassName(v8_str("Cons2"));
    234   v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New();
    235   cons3->SetClassName(v8_str("Cons3"));
    236 
    237   v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
    238   v8::Handle<v8::Signature> wsig =
    239       v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 3, args);
    240   v8::Handle<v8::FunctionTemplate> fun2 =
    241       v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), wsig);
    242 
    243   env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
    244   env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
    245   env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
    246   env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
    247   v8::Handle<Value> value4 = CompileRun(
    248       "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
    249       "'[object Cons1],[object Cons2],[object Cons3]'");
    250   CHECK(value4->IsTrue());
    251 
    252   v8::Handle<Value> value5 = CompileRun(
    253       "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
    254   CHECK(value5->IsTrue());
    255 
    256   v8::Handle<Value> value6 = CompileRun(
    257       "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
    258   CHECK(value6->IsTrue());
    259 
    260   v8::Handle<Value> value7 = CompileRun(
    261       "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
    262       "'[object Cons1],[object Cons2],[object Cons3],d';");
    263   CHECK(value7->IsTrue());
    264 
    265   v8::Handle<Value> value8 = CompileRun(
    266       "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
    267   CHECK(value8->IsTrue());
    268 }
    269 
    270 
    271 THREADED_TEST(HulIgennem) {
    272   v8::HandleScope scope;
    273   LocalContext env;
    274   v8::Handle<v8::Primitive> undef = v8::Undefined();
    275   Local<String> undef_str = undef->ToString();
    276   char* value = i::NewArray<char>(undef_str->Length() + 1);
    277   undef_str->WriteAscii(value);
    278   CHECK_EQ(0, strcmp(value, "undefined"));
    279   i::DeleteArray(value);
    280 }
    281 
    282 
    283 THREADED_TEST(Access) {
    284   v8::HandleScope scope;
    285   LocalContext env;
    286   Local<v8::Object> obj = v8::Object::New();
    287   Local<Value> foo_before = obj->Get(v8_str("foo"));
    288   CHECK(foo_before->IsUndefined());
    289   Local<String> bar_str = v8_str("bar");
    290   obj->Set(v8_str("foo"), bar_str);
    291   Local<Value> foo_after = obj->Get(v8_str("foo"));
    292   CHECK(!foo_after->IsUndefined());
    293   CHECK(foo_after->IsString());
    294   CHECK_EQ(bar_str, foo_after);
    295 }
    296 
    297 
    298 THREADED_TEST(AccessElement) {
    299   v8::HandleScope scope;
    300   LocalContext env;
    301   Local<v8::Object> obj = v8::Object::New();
    302   Local<Value> before = obj->Get(1);
    303   CHECK(before->IsUndefined());
    304   Local<String> bar_str = v8_str("bar");
    305   obj->Set(1, bar_str);
    306   Local<Value> after = obj->Get(1);
    307   CHECK(!after->IsUndefined());
    308   CHECK(after->IsString());
    309   CHECK_EQ(bar_str, after);
    310 
    311   Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
    312   CHECK_EQ(v8_str("a"), value->Get(0));
    313   CHECK_EQ(v8_str("b"), value->Get(1));
    314 }
    315 
    316 
    317 THREADED_TEST(Script) {
    318   v8::HandleScope scope;
    319   LocalContext env;
    320   const char* c_source = "1 + 2 + 3";
    321   Local<String> source = String::New(c_source);
    322   Local<Script> script = Script::Compile(source);
    323   CHECK_EQ(6, script->Run()->Int32Value());
    324 }
    325 
    326 
    327 static uint16_t* AsciiToTwoByteString(const char* source) {
    328   int array_length = i::StrLength(source) + 1;
    329   uint16_t* converted = i::NewArray<uint16_t>(array_length);
    330   for (int i = 0; i < array_length; i++) converted[i] = source[i];
    331   return converted;
    332 }
    333 
    334 
    335 class TestResource: public String::ExternalStringResource {
    336  public:
    337   explicit TestResource(uint16_t* data, int* counter = NULL)
    338     : data_(data), length_(0), counter_(counter) {
    339     while (data[length_]) ++length_;
    340   }
    341 
    342   ~TestResource() {
    343     i::DeleteArray(data_);
    344     if (counter_ != NULL) ++*counter_;
    345   }
    346 
    347   const uint16_t* data() const {
    348     return data_;
    349   }
    350 
    351   size_t length() const {
    352     return length_;
    353   }
    354  private:
    355   uint16_t* data_;
    356   size_t length_;
    357   int* counter_;
    358 };
    359 
    360 
    361 class TestAsciiResource: public String::ExternalAsciiStringResource {
    362  public:
    363   explicit TestAsciiResource(const char* data, int* counter = NULL)
    364     : data_(data), length_(strlen(data)), counter_(counter) { }
    365 
    366   ~TestAsciiResource() {
    367     i::DeleteArray(data_);
    368     if (counter_ != NULL) ++*counter_;
    369   }
    370 
    371   const char* data() const {
    372     return data_;
    373   }
    374 
    375   size_t length() const {
    376     return length_;
    377   }
    378  private:
    379   const char* data_;
    380   size_t length_;
    381   int* counter_;
    382 };
    383 
    384 
    385 THREADED_TEST(ScriptUsingStringResource) {
    386   int dispose_count = 0;
    387   const char* c_source = "1 + 2 * 3";
    388   uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
    389   {
    390     v8::HandleScope scope;
    391     LocalContext env;
    392     TestResource* resource = new TestResource(two_byte_source, &dispose_count);
    393     Local<String> source = String::NewExternal(resource);
    394     Local<Script> script = Script::Compile(source);
    395     Local<Value> value = script->Run();
    396     CHECK(value->IsNumber());
    397     CHECK_EQ(7, value->Int32Value());
    398     CHECK(source->IsExternal());
    399     CHECK_EQ(resource,
    400              static_cast<TestResource*>(source->GetExternalStringResource()));
    401     HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
    402     CHECK_EQ(0, dispose_count);
    403   }
    404   v8::internal::Isolate::Current()->compilation_cache()->Clear();
    405   HEAP->CollectAllAvailableGarbage();
    406   CHECK_EQ(1, dispose_count);
    407 }
    408 
    409 
    410 THREADED_TEST(ScriptUsingAsciiStringResource) {
    411   int dispose_count = 0;
    412   const char* c_source = "1 + 2 * 3";
    413   {
    414     v8::HandleScope scope;
    415     LocalContext env;
    416     Local<String> source =
    417         String::NewExternal(new TestAsciiResource(i::StrDup(c_source),
    418                                                   &dispose_count));
    419     Local<Script> script = Script::Compile(source);
    420     Local<Value> value = script->Run();
    421     CHECK(value->IsNumber());
    422     CHECK_EQ(7, value->Int32Value());
    423     HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
    424     CHECK_EQ(0, dispose_count);
    425   }
    426   i::Isolate::Current()->compilation_cache()->Clear();
    427   HEAP->CollectAllAvailableGarbage();
    428   CHECK_EQ(1, dispose_count);
    429 }
    430 
    431 
    432 THREADED_TEST(ScriptMakingExternalString) {
    433   int dispose_count = 0;
    434   uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
    435   {
    436     v8::HandleScope scope;
    437     LocalContext env;
    438     Local<String> source = String::New(two_byte_source);
    439     // Trigger GCs so that the newly allocated string moves to old gen.
    440     HEAP->CollectGarbage(i::NEW_SPACE);  // in survivor space now
    441     HEAP->CollectGarbage(i::NEW_SPACE);  // in old gen now
    442     bool success = source->MakeExternal(new TestResource(two_byte_source,
    443                                                          &dispose_count));
    444     CHECK(success);
    445     Local<Script> script = Script::Compile(source);
    446     Local<Value> value = script->Run();
    447     CHECK(value->IsNumber());
    448     CHECK_EQ(7, value->Int32Value());
    449     HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
    450     CHECK_EQ(0, dispose_count);
    451   }
    452   i::Isolate::Current()->compilation_cache()->Clear();
    453   HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
    454   CHECK_EQ(1, dispose_count);
    455 }
    456 
    457 
    458 THREADED_TEST(ScriptMakingExternalAsciiString) {
    459   int dispose_count = 0;
    460   const char* c_source = "1 + 2 * 3";
    461   {
    462     v8::HandleScope scope;
    463     LocalContext env;
    464     Local<String> source = v8_str(c_source);
    465     // Trigger GCs so that the newly allocated string moves to old gen.
    466     HEAP->CollectGarbage(i::NEW_SPACE);  // in survivor space now
    467     HEAP->CollectGarbage(i::NEW_SPACE);  // in old gen now
    468     bool success = source->MakeExternal(
    469         new TestAsciiResource(i::StrDup(c_source), &dispose_count));
    470     CHECK(success);
    471     Local<Script> script = Script::Compile(source);
    472     Local<Value> value = script->Run();
    473     CHECK(value->IsNumber());
    474     CHECK_EQ(7, value->Int32Value());
    475     HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
    476     CHECK_EQ(0, dispose_count);
    477   }
    478   i::Isolate::Current()->compilation_cache()->Clear();
    479   HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
    480   CHECK_EQ(1, dispose_count);
    481 }
    482 
    483 
    484 TEST(MakingExternalStringConditions) {
    485   v8::HandleScope scope;
    486   LocalContext env;
    487 
    488   // Free some space in the new space so that we can check freshness.
    489   HEAP->CollectGarbage(i::NEW_SPACE);
    490   HEAP->CollectGarbage(i::NEW_SPACE);
    491 
    492   uint16_t* two_byte_string = AsciiToTwoByteString("s1");
    493   Local<String> small_string = String::New(two_byte_string);
    494   i::DeleteArray(two_byte_string);
    495 
    496   // We should refuse to externalize newly created small string.
    497   CHECK(!small_string->CanMakeExternal());
    498   // Trigger GCs so that the newly allocated string moves to old gen.
    499   HEAP->CollectGarbage(i::NEW_SPACE);  // in survivor space now
    500   HEAP->CollectGarbage(i::NEW_SPACE);  // in old gen now
    501   // Old space strings should be accepted.
    502   CHECK(small_string->CanMakeExternal());
    503 
    504   two_byte_string = AsciiToTwoByteString("small string 2");
    505   small_string = String::New(two_byte_string);
    506   i::DeleteArray(two_byte_string);
    507 
    508   // We should refuse externalizing newly created small string.
    509   CHECK(!small_string->CanMakeExternal());
    510   for (int i = 0; i < 100; i++) {
    511     String::Value value(small_string);
    512   }
    513   // Frequently used strings should be accepted.
    514   CHECK(small_string->CanMakeExternal());
    515 
    516   const int buf_size = 10 * 1024;
    517   char* buf = i::NewArray<char>(buf_size);
    518   memset(buf, 'a', buf_size);
    519   buf[buf_size - 1] = '\0';
    520 
    521   two_byte_string = AsciiToTwoByteString(buf);
    522   Local<String> large_string = String::New(two_byte_string);
    523   i::DeleteArray(buf);
    524   i::DeleteArray(two_byte_string);
    525   // Large strings should be immediately accepted.
    526   CHECK(large_string->CanMakeExternal());
    527 }
    528 
    529 
    530 TEST(MakingExternalAsciiStringConditions) {
    531   v8::HandleScope scope;
    532   LocalContext env;
    533 
    534   // Free some space in the new space so that we can check freshness.
    535   HEAP->CollectGarbage(i::NEW_SPACE);
    536   HEAP->CollectGarbage(i::NEW_SPACE);
    537 
    538   Local<String> small_string = String::New("s1");
    539   // We should refuse to externalize newly created small string.
    540   CHECK(!small_string->CanMakeExternal());
    541   // Trigger GCs so that the newly allocated string moves to old gen.
    542   HEAP->CollectGarbage(i::NEW_SPACE);  // in survivor space now
    543   HEAP->CollectGarbage(i::NEW_SPACE);  // in old gen now
    544   // Old space strings should be accepted.
    545   CHECK(small_string->CanMakeExternal());
    546 
    547   small_string = String::New("small string 2");
    548   // We should refuse externalizing newly created small string.
    549   CHECK(!small_string->CanMakeExternal());
    550   for (int i = 0; i < 100; i++) {
    551     String::Value value(small_string);
    552   }
    553   // Frequently used strings should be accepted.
    554   CHECK(small_string->CanMakeExternal());
    555 
    556   const int buf_size = 10 * 1024;
    557   char* buf = i::NewArray<char>(buf_size);
    558   memset(buf, 'a', buf_size);
    559   buf[buf_size - 1] = '\0';
    560   Local<String> large_string = String::New(buf);
    561   i::DeleteArray(buf);
    562   // Large strings should be immediately accepted.
    563   CHECK(large_string->CanMakeExternal());
    564 }
    565 
    566 
    567 THREADED_TEST(UsingExternalString) {
    568   {
    569     v8::HandleScope scope;
    570     uint16_t* two_byte_string = AsciiToTwoByteString("test string");
    571     Local<String> string =
    572         String::NewExternal(new TestResource(two_byte_string));
    573     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
    574     // Trigger GCs so that the newly allocated string moves to old gen.
    575     HEAP->CollectGarbage(i::NEW_SPACE);  // in survivor space now
    576     HEAP->CollectGarbage(i::NEW_SPACE);  // in old gen now
    577     i::Handle<i::String> isymbol = FACTORY->SymbolFromString(istring);
    578     CHECK(isymbol->IsSymbol());
    579   }
    580   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
    581   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
    582 }
    583 
    584 
    585 THREADED_TEST(UsingExternalAsciiString) {
    586   {
    587     v8::HandleScope scope;
    588     const char* one_byte_string = "test string";
    589     Local<String> string = String::NewExternal(
    590         new TestAsciiResource(i::StrDup(one_byte_string)));
    591     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
    592     // Trigger GCs so that the newly allocated string moves to old gen.
    593     HEAP->CollectGarbage(i::NEW_SPACE);  // in survivor space now
    594     HEAP->CollectGarbage(i::NEW_SPACE);  // in old gen now
    595     i::Handle<i::String> isymbol = FACTORY->SymbolFromString(istring);
    596     CHECK(isymbol->IsSymbol());
    597   }
    598   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
    599   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
    600 }
    601 
    602 
    603 THREADED_TEST(ScavengeExternalString) {
    604   int dispose_count = 0;
    605   bool in_new_space = false;
    606   {
    607     v8::HandleScope scope;
    608     uint16_t* two_byte_string = AsciiToTwoByteString("test string");
    609     Local<String> string =
    610       String::NewExternal(new TestResource(two_byte_string,
    611                                            &dispose_count));
    612     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
    613     HEAP->CollectGarbage(i::NEW_SPACE);
    614     in_new_space = HEAP->InNewSpace(*istring);
    615     CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
    616     CHECK_EQ(0, dispose_count);
    617   }
    618   HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
    619   CHECK_EQ(1, dispose_count);
    620 }
    621 
    622 
    623 THREADED_TEST(ScavengeExternalAsciiString) {
    624   int dispose_count = 0;
    625   bool in_new_space = false;
    626   {
    627     v8::HandleScope scope;
    628     const char* one_byte_string = "test string";
    629     Local<String> string = String::NewExternal(
    630         new TestAsciiResource(i::StrDup(one_byte_string), &dispose_count));
    631     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
    632     HEAP->CollectGarbage(i::NEW_SPACE);
    633     in_new_space = HEAP->InNewSpace(*istring);
    634     CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
    635     CHECK_EQ(0, dispose_count);
    636   }
    637   HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
    638   CHECK_EQ(1, dispose_count);
    639 }
    640 
    641 
    642 class TestAsciiResourceWithDisposeControl: public TestAsciiResource {
    643  public:
    644   // Only used by non-threaded tests, so it can use static fields.
    645   static int dispose_calls;
    646   static int dispose_count;
    647 
    648   TestAsciiResourceWithDisposeControl(const char* data, bool dispose)
    649       : TestAsciiResource(data, &dispose_count),
    650         dispose_(dispose) { }
    651 
    652   void Dispose() {
    653     ++dispose_calls;
    654     if (dispose_) delete this;
    655   }
    656  private:
    657   bool dispose_;
    658 };
    659 
    660 
    661 int TestAsciiResourceWithDisposeControl::dispose_count = 0;
    662 int TestAsciiResourceWithDisposeControl::dispose_calls = 0;
    663 
    664 
    665 TEST(ExternalStringWithDisposeHandling) {
    666   const char* c_source = "1 + 2 * 3";
    667 
    668   // Use a stack allocated external string resource allocated object.
    669   TestAsciiResourceWithDisposeControl::dispose_count = 0;
    670   TestAsciiResourceWithDisposeControl::dispose_calls = 0;
    671   TestAsciiResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
    672   {
    673     v8::HandleScope scope;
    674     LocalContext env;
    675     Local<String> source =  String::NewExternal(&res_stack);
    676     Local<Script> script = Script::Compile(source);
    677     Local<Value> value = script->Run();
    678     CHECK(value->IsNumber());
    679     CHECK_EQ(7, value->Int32Value());
    680     HEAP->CollectAllAvailableGarbage();
    681     CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
    682   }
    683   i::Isolate::Current()->compilation_cache()->Clear();
    684   HEAP->CollectAllAvailableGarbage();
    685   CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
    686   CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
    687 
    688   // Use a heap allocated external string resource allocated object.
    689   TestAsciiResourceWithDisposeControl::dispose_count = 0;
    690   TestAsciiResourceWithDisposeControl::dispose_calls = 0;
    691   TestAsciiResource* res_heap =
    692       new TestAsciiResourceWithDisposeControl(i::StrDup(c_source), true);
    693   {
    694     v8::HandleScope scope;
    695     LocalContext env;
    696     Local<String> source =  String::NewExternal(res_heap);
    697     Local<Script> script = Script::Compile(source);
    698     Local<Value> value = script->Run();
    699     CHECK(value->IsNumber());
    700     CHECK_EQ(7, value->Int32Value());
    701     HEAP->CollectAllAvailableGarbage();
    702     CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
    703   }
    704   i::Isolate::Current()->compilation_cache()->Clear();
    705   HEAP->CollectAllAvailableGarbage();
    706   CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
    707   CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_count);
    708 }
    709 
    710 
    711 THREADED_TEST(StringConcat) {
    712   {
    713     v8::HandleScope scope;
    714     LocalContext env;
    715     const char* one_byte_string_1 = "function a_times_t";
    716     const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
    717     const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
    718     const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
    719     const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
    720     const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
    721     const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
    722     Local<String> left = v8_str(one_byte_string_1);
    723 
    724     uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
    725     Local<String> right = String::New(two_byte_source);
    726     i::DeleteArray(two_byte_source);
    727 
    728     Local<String> source = String::Concat(left, right);
    729     right = String::NewExternal(
    730         new TestAsciiResource(i::StrDup(one_byte_extern_1)));
    731     source = String::Concat(source, right);
    732     right = String::NewExternal(
    733         new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
    734     source = String::Concat(source, right);
    735     right = v8_str(one_byte_string_2);
    736     source = String::Concat(source, right);
    737 
    738     two_byte_source = AsciiToTwoByteString(two_byte_string_2);
    739     right = String::New(two_byte_source);
    740     i::DeleteArray(two_byte_source);
    741 
    742     source = String::Concat(source, right);
    743     right = String::NewExternal(
    744         new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
    745     source = String::Concat(source, right);
    746     Local<Script> script = Script::Compile(source);
    747     Local<Value> value = script->Run();
    748     CHECK(value->IsNumber());
    749     CHECK_EQ(68, value->Int32Value());
    750   }
    751   i::Isolate::Current()->compilation_cache()->Clear();
    752   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
    753   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
    754 }
    755 
    756 
    757 THREADED_TEST(GlobalProperties) {
    758   v8::HandleScope scope;
    759   LocalContext env;
    760   v8::Handle<v8::Object> global = env->Global();
    761   global->Set(v8_str("pi"), v8_num(3.1415926));
    762   Local<Value> pi = global->Get(v8_str("pi"));
    763   CHECK_EQ(3.1415926, pi->NumberValue());
    764 }
    765 
    766 
    767 static v8::Handle<Value> handle_call(const v8::Arguments& args) {
    768   ApiTestFuzzer::Fuzz();
    769   return v8_num(102);
    770 }
    771 
    772 
    773 static v8::Handle<Value> construct_call(const v8::Arguments& args) {
    774   ApiTestFuzzer::Fuzz();
    775   args.This()->Set(v8_str("x"), v8_num(1));
    776   args.This()->Set(v8_str("y"), v8_num(2));
    777   return args.This();
    778 }
    779 
    780 static v8::Handle<Value> Return239(Local<String> name, const AccessorInfo&) {
    781   ApiTestFuzzer::Fuzz();
    782   return v8_num(239);
    783 }
    784 
    785 
    786 THREADED_TEST(FunctionTemplate) {
    787   v8::HandleScope scope;
    788   LocalContext env;
    789   {
    790     Local<v8::FunctionTemplate> fun_templ =
    791         v8::FunctionTemplate::New(handle_call);
    792     Local<Function> fun = fun_templ->GetFunction();
    793     env->Global()->Set(v8_str("obj"), fun);
    794     Local<Script> script = v8_compile("obj()");
    795     CHECK_EQ(102, script->Run()->Int32Value());
    796   }
    797   // Use SetCallHandler to initialize a function template, should work like the
    798   // previous one.
    799   {
    800     Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
    801     fun_templ->SetCallHandler(handle_call);
    802     Local<Function> fun = fun_templ->GetFunction();
    803     env->Global()->Set(v8_str("obj"), fun);
    804     Local<Script> script = v8_compile("obj()");
    805     CHECK_EQ(102, script->Run()->Int32Value());
    806   }
    807   // Test constructor calls.
    808   {
    809     Local<v8::FunctionTemplate> fun_templ =
    810         v8::FunctionTemplate::New(construct_call);
    811     fun_templ->SetClassName(v8_str("funky"));
    812     fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), Return239);
    813     Local<Function> fun = fun_templ->GetFunction();
    814     env->Global()->Set(v8_str("obj"), fun);
    815     Local<Script> script = v8_compile("var s = new obj(); s.x");
    816     CHECK_EQ(1, script->Run()->Int32Value());
    817 
    818     Local<Value> result = v8_compile("(new obj()).toString()")->Run();
    819     CHECK_EQ(v8_str("[object funky]"), result);
    820 
    821     result = v8_compile("(new obj()).m")->Run();
    822     CHECK_EQ(239, result->Int32Value());
    823   }
    824 }
    825 
    826 
    827 static void* expected_ptr;
    828 static v8::Handle<v8::Value> callback(const v8::Arguments& args) {
    829   void* ptr = v8::External::Unwrap(args.Data());
    830   CHECK_EQ(expected_ptr, ptr);
    831   return v8::True();
    832 }
    833 
    834 
    835 static void TestExternalPointerWrapping() {
    836   v8::HandleScope scope;
    837   LocalContext env;
    838 
    839   v8::Handle<v8::Value> data = v8::External::Wrap(expected_ptr);
    840 
    841   v8::Handle<v8::Object> obj = v8::Object::New();
    842   obj->Set(v8_str("func"),
    843            v8::FunctionTemplate::New(callback, data)->GetFunction());
    844   env->Global()->Set(v8_str("obj"), obj);
    845 
    846   CHECK(CompileRun(
    847         "function foo() {\n"
    848         "  for (var i = 0; i < 13; i++) obj.func();\n"
    849         "}\n"
    850         "foo(), true")->BooleanValue());
    851 }
    852 
    853 
    854 THREADED_TEST(ExternalWrap) {
    855   // Check heap allocated object.
    856   int* ptr = new int;
    857   expected_ptr = ptr;
    858   TestExternalPointerWrapping();
    859   delete ptr;
    860 
    861   // Check stack allocated object.
    862   int foo;
    863   expected_ptr = &foo;
    864   TestExternalPointerWrapping();
    865 
    866   // Check not aligned addresses.
    867   const int n = 100;
    868   char* s = new char[n];
    869   for (int i = 0; i < n; i++) {
    870     expected_ptr = s + i;
    871     TestExternalPointerWrapping();
    872   }
    873 
    874   delete[] s;
    875 
    876   // Check several invalid addresses.
    877   expected_ptr = reinterpret_cast<void*>(1);
    878   TestExternalPointerWrapping();
    879 
    880   expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
    881   TestExternalPointerWrapping();
    882 
    883   expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
    884   TestExternalPointerWrapping();
    885 
    886 #if defined(V8_HOST_ARCH_X64)
    887   // Check a value with a leading 1 bit in x64 Smi encoding.
    888   expected_ptr = reinterpret_cast<void*>(0x400000000);
    889   TestExternalPointerWrapping();
    890 
    891   expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
    892   TestExternalPointerWrapping();
    893 
    894   expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
    895   TestExternalPointerWrapping();
    896 #endif
    897 }
    898 
    899 
    900 THREADED_TEST(FindInstanceInPrototypeChain) {
    901   v8::HandleScope scope;
    902   LocalContext env;
    903 
    904   Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New();
    905   Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New();
    906   Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New();
    907   derived->Inherit(base);
    908 
    909   Local<v8::Function> base_function = base->GetFunction();
    910   Local<v8::Function> derived_function = derived->GetFunction();
    911   Local<v8::Function> other_function = other->GetFunction();
    912 
    913   Local<v8::Object> base_instance = base_function->NewInstance();
    914   Local<v8::Object> derived_instance = derived_function->NewInstance();
    915   Local<v8::Object> derived_instance2 = derived_function->NewInstance();
    916   Local<v8::Object> other_instance = other_function->NewInstance();
    917   derived_instance2->Set(v8_str("__proto__"), derived_instance);
    918   other_instance->Set(v8_str("__proto__"), derived_instance2);
    919 
    920   // base_instance is only an instance of base.
    921   CHECK_EQ(base_instance,
    922            base_instance->FindInstanceInPrototypeChain(base));
    923   CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
    924   CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
    925 
    926   // derived_instance is an instance of base and derived.
    927   CHECK_EQ(derived_instance,
    928            derived_instance->FindInstanceInPrototypeChain(base));
    929   CHECK_EQ(derived_instance,
    930            derived_instance->FindInstanceInPrototypeChain(derived));
    931   CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
    932 
    933   // other_instance is an instance of other and its immediate
    934   // prototype derived_instance2 is an instance of base and derived.
    935   // Note, derived_instance is an instance of base and derived too,
    936   // but it comes after derived_instance2 in the prototype chain of
    937   // other_instance.
    938   CHECK_EQ(derived_instance2,
    939            other_instance->FindInstanceInPrototypeChain(base));
    940   CHECK_EQ(derived_instance2,
    941            other_instance->FindInstanceInPrototypeChain(derived));
    942   CHECK_EQ(other_instance,
    943            other_instance->FindInstanceInPrototypeChain(other));
    944 }
    945 
    946 
    947 THREADED_TEST(TinyInteger) {
    948   v8::HandleScope scope;
    949   LocalContext env;
    950   int32_t value = 239;
    951   Local<v8::Integer> value_obj = v8::Integer::New(value);
    952   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
    953 }
    954 
    955 
    956 THREADED_TEST(BigSmiInteger) {
    957   v8::HandleScope scope;
    958   LocalContext env;
    959   int32_t value = i::Smi::kMaxValue;
    960   // We cannot add one to a Smi::kMaxValue without wrapping.
    961   if (i::kSmiValueSize < 32) {
    962     CHECK(i::Smi::IsValid(value));
    963     CHECK(!i::Smi::IsValid(value + 1));
    964     Local<v8::Integer> value_obj = v8::Integer::New(value);
    965     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
    966   }
    967 }
    968 
    969 
    970 THREADED_TEST(BigInteger) {
    971   v8::HandleScope scope;
    972   LocalContext env;
    973   // We cannot add one to a Smi::kMaxValue without wrapping.
    974   if (i::kSmiValueSize < 32) {
    975     // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
    976     // The code will not be run in that case, due to the "if" guard.
    977     int32_t value =
    978         static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
    979     CHECK(value > i::Smi::kMaxValue);
    980     CHECK(!i::Smi::IsValid(value));
    981     Local<v8::Integer> value_obj = v8::Integer::New(value);
    982     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
    983   }
    984 }
    985 
    986 
    987 THREADED_TEST(TinyUnsignedInteger) {
    988   v8::HandleScope scope;
    989   LocalContext env;
    990   uint32_t value = 239;
    991   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
    992   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
    993 }
    994 
    995 
    996 THREADED_TEST(BigUnsignedSmiInteger) {
    997   v8::HandleScope scope;
    998   LocalContext env;
    999   uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
   1000   CHECK(i::Smi::IsValid(value));
   1001   CHECK(!i::Smi::IsValid(value + 1));
   1002   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
   1003   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
   1004 }
   1005 
   1006 
   1007 THREADED_TEST(BigUnsignedInteger) {
   1008   v8::HandleScope scope;
   1009   LocalContext env;
   1010   uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
   1011   CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
   1012   CHECK(!i::Smi::IsValid(value));
   1013   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
   1014   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
   1015 }
   1016 
   1017 
   1018 THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
   1019   v8::HandleScope scope;
   1020   LocalContext env;
   1021   uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
   1022   uint32_t value = INT32_MAX_AS_UINT + 1;
   1023   CHECK(value > INT32_MAX_AS_UINT);  // No overflow.
   1024   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
   1025   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
   1026 }
   1027 
   1028 
   1029 THREADED_TEST(IsNativeError) {
   1030   v8::HandleScope scope;
   1031   LocalContext env;
   1032   v8::Handle<Value> syntax_error = CompileRun(
   1033       "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
   1034   CHECK(syntax_error->IsNativeError());
   1035   v8::Handle<Value> not_error = CompileRun("{a:42}");
   1036   CHECK(!not_error->IsNativeError());
   1037   v8::Handle<Value> not_object = CompileRun("42");
   1038   CHECK(!not_object->IsNativeError());
   1039 }
   1040 
   1041 
   1042 THREADED_TEST(StringObject) {
   1043   v8::HandleScope scope;
   1044   LocalContext env;
   1045   v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")");
   1046   CHECK(boxed_string->IsStringObject());
   1047   v8::Handle<Value> unboxed_string = CompileRun("\"test\"");
   1048   CHECK(!unboxed_string->IsStringObject());
   1049   v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)");
   1050   CHECK(!boxed_not_string->IsStringObject());
   1051   v8::Handle<Value> not_object = CompileRun("0");
   1052   CHECK(!not_object->IsStringObject());
   1053   v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
   1054   CHECK(!as_boxed.IsEmpty());
   1055   Local<v8::String> the_string = as_boxed->StringValue();
   1056   CHECK(!the_string.IsEmpty());
   1057   ExpectObject("\"test\"", the_string);
   1058   v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string);
   1059   CHECK(new_boxed_string->IsStringObject());
   1060   as_boxed = new_boxed_string.As<v8::StringObject>();
   1061   the_string = as_boxed->StringValue();
   1062   CHECK(!the_string.IsEmpty());
   1063   ExpectObject("\"test\"", the_string);
   1064 }
   1065 
   1066 
   1067 THREADED_TEST(NumberObject) {
   1068   v8::HandleScope scope;
   1069   LocalContext env;
   1070   v8::Handle<Value> boxed_number = CompileRun("new Number(42)");
   1071   CHECK(boxed_number->IsNumberObject());
   1072   v8::Handle<Value> unboxed_number = CompileRun("42");
   1073   CHECK(!unboxed_number->IsNumberObject());
   1074   v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)");
   1075   CHECK(!boxed_not_number->IsNumberObject());
   1076   v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
   1077   CHECK(!as_boxed.IsEmpty());
   1078   double the_number = as_boxed->NumberValue();
   1079   CHECK_EQ(42.0, the_number);
   1080   v8::Handle<v8::Value> new_boxed_number = v8::NumberObject::New(43);
   1081   CHECK(new_boxed_number->IsNumberObject());
   1082   as_boxed = new_boxed_number.As<v8::NumberObject>();
   1083   the_number = as_boxed->NumberValue();
   1084   CHECK_EQ(43.0, the_number);
   1085 }
   1086 
   1087 
   1088 THREADED_TEST(BooleanObject) {
   1089   v8::HandleScope scope;
   1090   LocalContext env;
   1091   v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)");
   1092   CHECK(boxed_boolean->IsBooleanObject());
   1093   v8::Handle<Value> unboxed_boolean = CompileRun("true");
   1094   CHECK(!unboxed_boolean->IsBooleanObject());
   1095   v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)");
   1096   CHECK(!boxed_not_boolean->IsBooleanObject());
   1097   v8::Handle<v8::BooleanObject> as_boxed =
   1098       boxed_boolean.As<v8::BooleanObject>();
   1099   CHECK(!as_boxed.IsEmpty());
   1100   bool the_boolean = as_boxed->BooleanValue();
   1101   CHECK_EQ(true, the_boolean);
   1102   v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true);
   1103   v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false);
   1104   CHECK(boxed_true->IsBooleanObject());
   1105   CHECK(boxed_false->IsBooleanObject());
   1106   as_boxed = boxed_true.As<v8::BooleanObject>();
   1107   CHECK_EQ(true, as_boxed->BooleanValue());
   1108   as_boxed = boxed_false.As<v8::BooleanObject>();
   1109   CHECK_EQ(false, as_boxed->BooleanValue());
   1110 }
   1111 
   1112 
   1113 THREADED_TEST(Number) {
   1114   v8::HandleScope scope;
   1115   LocalContext env;
   1116   double PI = 3.1415926;
   1117   Local<v8::Number> pi_obj = v8::Number::New(PI);
   1118   CHECK_EQ(PI, pi_obj->NumberValue());
   1119 }
   1120 
   1121 
   1122 THREADED_TEST(ToNumber) {
   1123   v8::HandleScope scope;
   1124   LocalContext env;
   1125   Local<String> str = v8_str("3.1415926");
   1126   CHECK_EQ(3.1415926, str->NumberValue());
   1127   v8::Handle<v8::Boolean> t = v8::True();
   1128   CHECK_EQ(1.0, t->NumberValue());
   1129   v8::Handle<v8::Boolean> f = v8::False();
   1130   CHECK_EQ(0.0, f->NumberValue());
   1131 }
   1132 
   1133 
   1134 THREADED_TEST(Date) {
   1135   v8::HandleScope scope;
   1136   LocalContext env;
   1137   double PI = 3.1415926;
   1138   Local<Value> date = v8::Date::New(PI);
   1139   CHECK_EQ(3.0, date->NumberValue());
   1140   date.As<v8::Date>()->Set(v8_str("property"), v8::Integer::New(42));
   1141   CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value());
   1142 }
   1143 
   1144 
   1145 THREADED_TEST(Boolean) {
   1146   v8::HandleScope scope;
   1147   LocalContext env;
   1148   v8::Handle<v8::Boolean> t = v8::True();
   1149   CHECK(t->Value());
   1150   v8::Handle<v8::Boolean> f = v8::False();
   1151   CHECK(!f->Value());
   1152   v8::Handle<v8::Primitive> u = v8::Undefined();
   1153   CHECK(!u->BooleanValue());
   1154   v8::Handle<v8::Primitive> n = v8::Null();
   1155   CHECK(!n->BooleanValue());
   1156   v8::Handle<String> str1 = v8_str("");
   1157   CHECK(!str1->BooleanValue());
   1158   v8::Handle<String> str2 = v8_str("x");
   1159   CHECK(str2->BooleanValue());
   1160   CHECK(!v8::Number::New(0)->BooleanValue());
   1161   CHECK(v8::Number::New(-1)->BooleanValue());
   1162   CHECK(v8::Number::New(1)->BooleanValue());
   1163   CHECK(v8::Number::New(42)->BooleanValue());
   1164   CHECK(!v8_compile("NaN")->Run()->BooleanValue());
   1165 }
   1166 
   1167 
   1168 static v8::Handle<Value> DummyCallHandler(const v8::Arguments& args) {
   1169   ApiTestFuzzer::Fuzz();
   1170   return v8_num(13.4);
   1171 }
   1172 
   1173 
   1174 static v8::Handle<Value> GetM(Local<String> name, const AccessorInfo&) {
   1175   ApiTestFuzzer::Fuzz();
   1176   return v8_num(876);
   1177 }
   1178 
   1179 
   1180 THREADED_TEST(GlobalPrototype) {
   1181   v8::HandleScope scope;
   1182   v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
   1183   func_templ->PrototypeTemplate()->Set(
   1184       "dummy",
   1185       v8::FunctionTemplate::New(DummyCallHandler));
   1186   v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
   1187   templ->Set("x", v8_num(200));
   1188   templ->SetAccessor(v8_str("m"), GetM);
   1189   LocalContext env(0, templ);
   1190   v8::Handle<Script> script(v8_compile("dummy()"));
   1191   v8::Handle<Value> result(script->Run());
   1192   CHECK_EQ(13.4, result->NumberValue());
   1193   CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
   1194   CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
   1195 }
   1196 
   1197 
   1198 THREADED_TEST(ObjectTemplate) {
   1199   v8::HandleScope scope;
   1200   Local<ObjectTemplate> templ1 = ObjectTemplate::New();
   1201   templ1->Set("x", v8_num(10));
   1202   templ1->Set("y", v8_num(13));
   1203   LocalContext env;
   1204   Local<v8::Object> instance1 = templ1->NewInstance();
   1205   env->Global()->Set(v8_str("p"), instance1);
   1206   CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
   1207   CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
   1208   Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
   1209   fun->PrototypeTemplate()->Set("nirk", v8_num(123));
   1210   Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
   1211   templ2->Set("a", v8_num(12));
   1212   templ2->Set("b", templ1);
   1213   Local<v8::Object> instance2 = templ2->NewInstance();
   1214   env->Global()->Set(v8_str("q"), instance2);
   1215   CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
   1216   CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
   1217   CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
   1218   CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
   1219 }
   1220 
   1221 
   1222 static v8::Handle<Value> GetFlabby(const v8::Arguments& args) {
   1223   ApiTestFuzzer::Fuzz();
   1224   return v8_num(17.2);
   1225 }
   1226 
   1227 
   1228 static v8::Handle<Value> GetKnurd(Local<String> property, const AccessorInfo&) {
   1229   ApiTestFuzzer::Fuzz();
   1230   return v8_num(15.2);
   1231 }
   1232 
   1233 
   1234 THREADED_TEST(DescriptorInheritance) {
   1235   v8::HandleScope scope;
   1236   v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New();
   1237   super->PrototypeTemplate()->Set("flabby",
   1238                                   v8::FunctionTemplate::New(GetFlabby));
   1239   super->PrototypeTemplate()->Set("PI", v8_num(3.14));
   1240 
   1241   super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
   1242 
   1243   v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New();
   1244   base1->Inherit(super);
   1245   base1->PrototypeTemplate()->Set("v1", v8_num(20.1));
   1246 
   1247   v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New();
   1248   base2->Inherit(super);
   1249   base2->PrototypeTemplate()->Set("v2", v8_num(10.1));
   1250 
   1251   LocalContext env;
   1252 
   1253   env->Global()->Set(v8_str("s"), super->GetFunction());
   1254   env->Global()->Set(v8_str("base1"), base1->GetFunction());
   1255   env->Global()->Set(v8_str("base2"), base2->GetFunction());
   1256 
   1257   // Checks right __proto__ chain.
   1258   CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
   1259   CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
   1260 
   1261   CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
   1262 
   1263   // Instance accessor should not be visible on function object or its prototype
   1264   CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
   1265   CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
   1266   CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
   1267 
   1268   env->Global()->Set(v8_str("obj"),
   1269                      base1->GetFunction()->NewInstance());
   1270   CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
   1271   CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
   1272   CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
   1273   CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
   1274   CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
   1275 
   1276   env->Global()->Set(v8_str("obj2"),
   1277                      base2->GetFunction()->NewInstance());
   1278   CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
   1279   CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
   1280   CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
   1281   CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
   1282   CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
   1283 
   1284   // base1 and base2 cannot cross reference to each's prototype
   1285   CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
   1286   CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
   1287 }
   1288 
   1289 
   1290 int echo_named_call_count;
   1291 
   1292 
   1293 static v8::Handle<Value> EchoNamedProperty(Local<String> name,
   1294                                            const AccessorInfo& info) {
   1295   ApiTestFuzzer::Fuzz();
   1296   CHECK_EQ(v8_str("data"), info.Data());
   1297   echo_named_call_count++;
   1298   return name;
   1299 }
   1300 
   1301 // Helper functions for Interceptor/Accessor interaction tests
   1302 
   1303 Handle<Value> SimpleAccessorGetter(Local<String> name,
   1304                                    const AccessorInfo& info) {
   1305   Handle<Object> self = info.This();
   1306   return self->Get(String::Concat(v8_str("accessor_"), name));
   1307 }
   1308 
   1309 void SimpleAccessorSetter(Local<String> name, Local<Value> value,
   1310                           const AccessorInfo& info) {
   1311   Handle<Object> self = info.This();
   1312   self->Set(String::Concat(v8_str("accessor_"), name), value);
   1313 }
   1314 
   1315 Handle<Value> EmptyInterceptorGetter(Local<String> name,
   1316                                      const AccessorInfo& info) {
   1317   return Handle<Value>();
   1318 }
   1319 
   1320 Handle<Value> EmptyInterceptorSetter(Local<String> name,
   1321                                      Local<Value> value,
   1322                                      const AccessorInfo& info) {
   1323   return Handle<Value>();
   1324 }
   1325 
   1326 Handle<Value> InterceptorGetter(Local<String> name,
   1327                                 const AccessorInfo& info) {
   1328   // Intercept names that start with 'interceptor_'.
   1329   String::AsciiValue ascii(name);
   1330   char* name_str = *ascii;
   1331   char prefix[] = "interceptor_";
   1332   int i;
   1333   for (i = 0; name_str[i] && prefix[i]; ++i) {
   1334     if (name_str[i] != prefix[i]) return Handle<Value>();
   1335   }
   1336   Handle<Object> self = info.This();
   1337   return self->GetHiddenValue(v8_str(name_str + i));
   1338 }
   1339 
   1340 Handle<Value> InterceptorSetter(Local<String> name,
   1341                                 Local<Value> value,
   1342                                 const AccessorInfo& info) {
   1343   // Intercept accesses that set certain integer values.
   1344   if (value->IsInt32() && value->Int32Value() < 10000) {
   1345     Handle<Object> self = info.This();
   1346     self->SetHiddenValue(name, value);
   1347     return value;
   1348   }
   1349   return Handle<Value>();
   1350 }
   1351 
   1352 void AddAccessor(Handle<FunctionTemplate> templ,
   1353                  Handle<String> name,
   1354                  v8::AccessorGetter getter,
   1355                  v8::AccessorSetter setter) {
   1356   templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
   1357 }
   1358 
   1359 void AddInterceptor(Handle<FunctionTemplate> templ,
   1360                     v8::NamedPropertyGetter getter,
   1361                     v8::NamedPropertySetter setter) {
   1362   templ->InstanceTemplate()->SetNamedPropertyHandler(getter, setter);
   1363 }
   1364 
   1365 THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
   1366   v8::HandleScope scope;
   1367   Handle<FunctionTemplate> parent = FunctionTemplate::New();
   1368   Handle<FunctionTemplate> child = FunctionTemplate::New();
   1369   child->Inherit(parent);
   1370   AddAccessor(parent, v8_str("age"),
   1371               SimpleAccessorGetter, SimpleAccessorSetter);
   1372   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
   1373   LocalContext env;
   1374   env->Global()->Set(v8_str("Child"), child->GetFunction());
   1375   CompileRun("var child = new Child;"
   1376              "child.age = 10;");
   1377   ExpectBoolean("child.hasOwnProperty('age')", false);
   1378   ExpectInt32("child.age", 10);
   1379   ExpectInt32("child.accessor_age", 10);
   1380 }
   1381 
   1382 THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) {
   1383   v8::HandleScope scope;
   1384   Handle<FunctionTemplate> parent = FunctionTemplate::New();
   1385   Handle<FunctionTemplate> child = FunctionTemplate::New();
   1386   child->Inherit(parent);
   1387   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
   1388   LocalContext env;
   1389   env->Global()->Set(v8_str("Child"), child->GetFunction());
   1390   CompileRun("var child = new Child;"
   1391              "var parent = child.__proto__;"
   1392              "Object.defineProperty(parent, 'age', "
   1393              "  {get: function(){ return this.accessor_age; }, "
   1394              "   set: function(v){ this.accessor_age = v; }, "
   1395              "   enumerable: true, configurable: true});"
   1396              "child.age = 10;");
   1397   ExpectBoolean("child.hasOwnProperty('age')", false);
   1398   ExpectInt32("child.age", 10);
   1399   ExpectInt32("child.accessor_age", 10);
   1400 }
   1401 
   1402 THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) {
   1403   v8::HandleScope scope;
   1404   Handle<FunctionTemplate> parent = FunctionTemplate::New();
   1405   Handle<FunctionTemplate> child = FunctionTemplate::New();
   1406   child->Inherit(parent);
   1407   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
   1408   LocalContext env;
   1409   env->Global()->Set(v8_str("Child"), child->GetFunction());
   1410   CompileRun("var child = new Child;"
   1411              "var parent = child.__proto__;"
   1412              "parent.name = 'Alice';");
   1413   ExpectBoolean("child.hasOwnProperty('name')", false);
   1414   ExpectString("child.name", "Alice");
   1415   CompileRun("child.name = 'Bob';");
   1416   ExpectString("child.name", "Bob");
   1417   ExpectBoolean("child.hasOwnProperty('name')", true);
   1418   ExpectString("parent.name", "Alice");
   1419 }
   1420 
   1421 THREADED_TEST(SwitchFromInterceptorToAccessor) {
   1422   v8::HandleScope scope;
   1423   Handle<FunctionTemplate> templ = FunctionTemplate::New();
   1424   AddAccessor(templ, v8_str("age"),
   1425               SimpleAccessorGetter, SimpleAccessorSetter);
   1426   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
   1427   LocalContext env;
   1428   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
   1429   CompileRun("var obj = new Obj;"
   1430              "function setAge(i){ obj.age = i; };"
   1431              "for(var i = 0; i <= 10000; i++) setAge(i);");
   1432   // All i < 10000 go to the interceptor.
   1433   ExpectInt32("obj.interceptor_age", 9999);
   1434   // The last i goes to the accessor.
   1435   ExpectInt32("obj.accessor_age", 10000);
   1436 }
   1437 
   1438 THREADED_TEST(SwitchFromAccessorToInterceptor) {
   1439   v8::HandleScope scope;
   1440   Handle<FunctionTemplate> templ = FunctionTemplate::New();
   1441   AddAccessor(templ, v8_str("age"),
   1442               SimpleAccessorGetter, SimpleAccessorSetter);
   1443   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
   1444   LocalContext env;
   1445   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
   1446   CompileRun("var obj = new Obj;"
   1447              "function setAge(i){ obj.age = i; };"
   1448              "for(var i = 20000; i >= 9999; i--) setAge(i);");
   1449   // All i >= 10000 go to the accessor.
   1450   ExpectInt32("obj.accessor_age", 10000);
   1451   // The last i goes to the interceptor.
   1452   ExpectInt32("obj.interceptor_age", 9999);
   1453 }
   1454 
   1455 THREADED_TEST(SwitchFromInterceptorToAccessorWithInheritance) {
   1456   v8::HandleScope scope;
   1457   Handle<FunctionTemplate> parent = FunctionTemplate::New();
   1458   Handle<FunctionTemplate> child = FunctionTemplate::New();
   1459   child->Inherit(parent);
   1460   AddAccessor(parent, v8_str("age"),
   1461               SimpleAccessorGetter, SimpleAccessorSetter);
   1462   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
   1463   LocalContext env;
   1464   env->Global()->Set(v8_str("Child"), child->GetFunction());
   1465   CompileRun("var child = new Child;"
   1466              "function setAge(i){ child.age = i; };"
   1467              "for(var i = 0; i <= 10000; i++) setAge(i);");
   1468   // All i < 10000 go to the interceptor.
   1469   ExpectInt32("child.interceptor_age", 9999);
   1470   // The last i goes to the accessor.
   1471   ExpectInt32("child.accessor_age", 10000);
   1472 }
   1473 
   1474 THREADED_TEST(SwitchFromAccessorToInterceptorWithInheritance) {
   1475   v8::HandleScope scope;
   1476   Handle<FunctionTemplate> parent = FunctionTemplate::New();
   1477   Handle<FunctionTemplate> child = FunctionTemplate::New();
   1478   child->Inherit(parent);
   1479   AddAccessor(parent, v8_str("age"),
   1480               SimpleAccessorGetter, SimpleAccessorSetter);
   1481   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
   1482   LocalContext env;
   1483   env->Global()->Set(v8_str("Child"), child->GetFunction());
   1484   CompileRun("var child = new Child;"
   1485              "function setAge(i){ child.age = i; };"
   1486              "for(var i = 20000; i >= 9999; i--) setAge(i);");
   1487   // All i >= 10000 go to the accessor.
   1488   ExpectInt32("child.accessor_age", 10000);
   1489   // The last i goes to the interceptor.
   1490   ExpectInt32("child.interceptor_age", 9999);
   1491 }
   1492 
   1493 THREADED_TEST(SwitchFromInterceptorToJSAccessor) {
   1494   v8::HandleScope scope;
   1495   Handle<FunctionTemplate> templ = FunctionTemplate::New();
   1496   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
   1497   LocalContext env;
   1498   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
   1499   CompileRun("var obj = new Obj;"
   1500              "function setter(i) { this.accessor_age = i; };"
   1501              "function getter() { return this.accessor_age; };"
   1502              "function setAge(i) { obj.age = i; };"
   1503              "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
   1504              "for(var i = 0; i <= 10000; i++) setAge(i);");
   1505   // All i < 10000 go to the interceptor.
   1506   ExpectInt32("obj.interceptor_age", 9999);
   1507   // The last i goes to the JavaScript accessor.
   1508   ExpectInt32("obj.accessor_age", 10000);
   1509   // The installed JavaScript getter is still intact.
   1510   // This last part is a regression test for issue 1651 and relies on the fact
   1511   // that both interceptor and accessor are being installed on the same object.
   1512   ExpectInt32("obj.age", 10000);
   1513   ExpectBoolean("obj.hasOwnProperty('age')", true);
   1514   ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
   1515 }
   1516 
   1517 THREADED_TEST(SwitchFromJSAccessorToInterceptor) {
   1518   v8::HandleScope scope;
   1519   Handle<FunctionTemplate> templ = FunctionTemplate::New();
   1520   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
   1521   LocalContext env;
   1522   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
   1523   CompileRun("var obj = new Obj;"
   1524              "function setter(i) { this.accessor_age = i; };"
   1525              "function getter() { return this.accessor_age; };"
   1526              "function setAge(i) { obj.age = i; };"
   1527              "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
   1528              "for(var i = 20000; i >= 9999; i--) setAge(i);");
   1529   // All i >= 10000 go to the accessor.
   1530   ExpectInt32("obj.accessor_age", 10000);
   1531   // The last i goes to the interceptor.
   1532   ExpectInt32("obj.interceptor_age", 9999);
   1533   // The installed JavaScript getter is still intact.
   1534   // This last part is a regression test for issue 1651 and relies on the fact
   1535   // that both interceptor and accessor are being installed on the same object.
   1536   ExpectInt32("obj.age", 10000);
   1537   ExpectBoolean("obj.hasOwnProperty('age')", true);
   1538   ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
   1539 }
   1540 
   1541 THREADED_TEST(SwitchFromInterceptorToProperty) {
   1542   v8::HandleScope scope;
   1543   Handle<FunctionTemplate> parent = FunctionTemplate::New();
   1544   Handle<FunctionTemplate> child = FunctionTemplate::New();
   1545   child->Inherit(parent);
   1546   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
   1547   LocalContext env;
   1548   env->Global()->Set(v8_str("Child"), child->GetFunction());
   1549   CompileRun("var child = new Child;"
   1550              "function setAge(i){ child.age = i; };"
   1551              "for(var i = 0; i <= 10000; i++) setAge(i);");
   1552   // All i < 10000 go to the interceptor.
   1553   ExpectInt32("child.interceptor_age", 9999);
   1554   // The last i goes to child's own property.
   1555   ExpectInt32("child.age", 10000);
   1556 }
   1557 
   1558 THREADED_TEST(SwitchFromPropertyToInterceptor) {
   1559   v8::HandleScope scope;
   1560   Handle<FunctionTemplate> parent = FunctionTemplate::New();
   1561   Handle<FunctionTemplate> child = FunctionTemplate::New();
   1562   child->Inherit(parent);
   1563   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
   1564   LocalContext env;
   1565   env->Global()->Set(v8_str("Child"), child->GetFunction());
   1566   CompileRun("var child = new Child;"
   1567              "function setAge(i){ child.age = i; };"
   1568              "for(var i = 20000; i >= 9999; i--) setAge(i);");
   1569   // All i >= 10000 go to child's own property.
   1570   ExpectInt32("child.age", 10000);
   1571   // The last i goes to the interceptor.
   1572   ExpectInt32("child.interceptor_age", 9999);
   1573 }
   1574 
   1575 THREADED_TEST(NamedPropertyHandlerGetter) {
   1576   echo_named_call_count = 0;
   1577   v8::HandleScope scope;
   1578   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
   1579   templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
   1580                                                      0, 0, 0, 0,
   1581                                                      v8_str("data"));
   1582   LocalContext env;
   1583   env->Global()->Set(v8_str("obj"),
   1584                      templ->GetFunction()->NewInstance());
   1585   CHECK_EQ(echo_named_call_count, 0);
   1586   v8_compile("obj.x")->Run();
   1587   CHECK_EQ(echo_named_call_count, 1);
   1588   const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
   1589   v8::Handle<Value> str = CompileRun(code);
   1590   String::AsciiValue value(str);
   1591   CHECK_EQ(*value, "oddlepoddle");
   1592   // Check default behavior
   1593   CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
   1594   CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
   1595   CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
   1596 }
   1597 
   1598 
   1599 int echo_indexed_call_count = 0;
   1600 
   1601 
   1602 static v8::Handle<Value> EchoIndexedProperty(uint32_t index,
   1603                                              const AccessorInfo& info) {
   1604   ApiTestFuzzer::Fuzz();
   1605   CHECK_EQ(v8_num(637), info.Data());
   1606   echo_indexed_call_count++;
   1607   return v8_num(index);
   1608 }
   1609 
   1610 
   1611 THREADED_TEST(IndexedPropertyHandlerGetter) {
   1612   v8::HandleScope scope;
   1613   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
   1614   templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
   1615                                                        0, 0, 0, 0,
   1616                                                        v8_num(637));
   1617   LocalContext env;
   1618   env->Global()->Set(v8_str("obj"),
   1619                      templ->GetFunction()->NewInstance());
   1620   Local<Script> script = v8_compile("obj[900]");
   1621   CHECK_EQ(script->Run()->Int32Value(), 900);
   1622 }
   1623 
   1624 
   1625 v8::Handle<v8::Object> bottom;
   1626 
   1627 static v8::Handle<Value> CheckThisIndexedPropertyHandler(
   1628     uint32_t index,
   1629     const AccessorInfo& info) {
   1630   ApiTestFuzzer::Fuzz();
   1631   CHECK(info.This()->Equals(bottom));
   1632   return v8::Handle<Value>();
   1633 }
   1634 
   1635 static v8::Handle<Value> CheckThisNamedPropertyHandler(
   1636     Local<String> name,
   1637     const AccessorInfo& info) {
   1638   ApiTestFuzzer::Fuzz();
   1639   CHECK(info.This()->Equals(bottom));
   1640   return v8::Handle<Value>();
   1641 }
   1642 
   1643 
   1644 v8::Handle<Value> CheckThisIndexedPropertySetter(uint32_t index,
   1645                                                  Local<Value> value,
   1646                                                  const AccessorInfo& info) {
   1647   ApiTestFuzzer::Fuzz();
   1648   CHECK(info.This()->Equals(bottom));
   1649   return v8::Handle<Value>();
   1650 }
   1651 
   1652 
   1653 v8::Handle<Value> CheckThisNamedPropertySetter(Local<String> property,
   1654                                                Local<Value> value,
   1655                                                const AccessorInfo& info) {
   1656   ApiTestFuzzer::Fuzz();
   1657   CHECK(info.This()->Equals(bottom));
   1658   return v8::Handle<Value>();
   1659 }
   1660 
   1661 v8::Handle<v8::Integer> CheckThisIndexedPropertyQuery(
   1662     uint32_t index,
   1663     const AccessorInfo& info) {
   1664   ApiTestFuzzer::Fuzz();
   1665   CHECK(info.This()->Equals(bottom));
   1666   return v8::Handle<v8::Integer>();
   1667 }
   1668 
   1669 
   1670 v8::Handle<v8::Integer> CheckThisNamedPropertyQuery(Local<String> property,
   1671                                                     const AccessorInfo& info) {
   1672   ApiTestFuzzer::Fuzz();
   1673   CHECK(info.This()->Equals(bottom));
   1674   return v8::Handle<v8::Integer>();
   1675 }
   1676 
   1677 
   1678 v8::Handle<v8::Boolean> CheckThisIndexedPropertyDeleter(
   1679     uint32_t index,
   1680     const AccessorInfo& info) {
   1681   ApiTestFuzzer::Fuzz();
   1682   CHECK(info.This()->Equals(bottom));
   1683   return v8::Handle<v8::Boolean>();
   1684 }
   1685 
   1686 
   1687 v8::Handle<v8::Boolean> CheckThisNamedPropertyDeleter(
   1688     Local<String> property,
   1689     const AccessorInfo& info) {
   1690   ApiTestFuzzer::Fuzz();
   1691   CHECK(info.This()->Equals(bottom));
   1692   return v8::Handle<v8::Boolean>();
   1693 }
   1694 
   1695 
   1696 v8::Handle<v8::Array> CheckThisIndexedPropertyEnumerator(
   1697     const AccessorInfo& info) {
   1698   ApiTestFuzzer::Fuzz();
   1699   CHECK(info.This()->Equals(bottom));
   1700   return v8::Handle<v8::Array>();
   1701 }
   1702 
   1703 
   1704 v8::Handle<v8::Array> CheckThisNamedPropertyEnumerator(
   1705     const AccessorInfo& info) {
   1706   ApiTestFuzzer::Fuzz();
   1707   CHECK(info.This()->Equals(bottom));
   1708   return v8::Handle<v8::Array>();
   1709 }
   1710 
   1711 
   1712 THREADED_TEST(PropertyHandlerInPrototype) {
   1713   v8::HandleScope scope;
   1714   LocalContext env;
   1715 
   1716   // Set up a prototype chain with three interceptors.
   1717   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
   1718   templ->InstanceTemplate()->SetIndexedPropertyHandler(
   1719       CheckThisIndexedPropertyHandler,
   1720       CheckThisIndexedPropertySetter,
   1721       CheckThisIndexedPropertyQuery,
   1722       CheckThisIndexedPropertyDeleter,
   1723       CheckThisIndexedPropertyEnumerator);
   1724 
   1725   templ->InstanceTemplate()->SetNamedPropertyHandler(
   1726       CheckThisNamedPropertyHandler,
   1727       CheckThisNamedPropertySetter,
   1728       CheckThisNamedPropertyQuery,
   1729       CheckThisNamedPropertyDeleter,
   1730       CheckThisNamedPropertyEnumerator);
   1731 
   1732   bottom = templ->GetFunction()->NewInstance();
   1733   Local<v8::Object> top = templ->GetFunction()->NewInstance();
   1734   Local<v8::Object> middle = templ->GetFunction()->NewInstance();
   1735 
   1736   bottom->Set(v8_str("__proto__"), middle);
   1737   middle->Set(v8_str("__proto__"), top);
   1738   env->Global()->Set(v8_str("obj"), bottom);
   1739 
   1740   // Indexed and named get.
   1741   Script::Compile(v8_str("obj[0]"))->Run();
   1742   Script::Compile(v8_str("obj.x"))->Run();
   1743 
   1744   // Indexed and named set.
   1745   Script::Compile(v8_str("obj[1] = 42"))->Run();
   1746   Script::Compile(v8_str("obj.y = 42"))->Run();
   1747 
   1748   // Indexed and named query.
   1749   Script::Compile(v8_str("0 in obj"))->Run();
   1750   Script::Compile(v8_str("'x' in obj"))->Run();
   1751 
   1752   // Indexed and named deleter.
   1753   Script::Compile(v8_str("delete obj[0]"))->Run();
   1754   Script::Compile(v8_str("delete obj.x"))->Run();
   1755 
   1756   // Enumerators.
   1757   Script::Compile(v8_str("for (var p in obj) ;"))->Run();
   1758 }
   1759 
   1760 
   1761 static v8::Handle<Value> PrePropertyHandlerGet(Local<String> key,
   1762                                                const AccessorInfo& info) {
   1763   ApiTestFuzzer::Fuzz();
   1764   if (v8_str("pre")->Equals(key)) {
   1765     return v8_str("PrePropertyHandler: pre");
   1766   }
   1767   return v8::Handle<String>();
   1768 }
   1769 
   1770 
   1771 static v8::Handle<v8::Integer> PrePropertyHandlerQuery(Local<String> key,
   1772                                                        const AccessorInfo&) {
   1773   if (v8_str("pre")->Equals(key)) {
   1774     return v8::Integer::New(v8::None);
   1775   }
   1776 
   1777   return v8::Handle<v8::Integer>();  // do not intercept the call
   1778 }
   1779 
   1780 
   1781 THREADED_TEST(PrePropertyHandler) {
   1782   v8::HandleScope scope;
   1783   v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
   1784   desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
   1785                                                     0,
   1786                                                     PrePropertyHandlerQuery);
   1787   LocalContext env(NULL, desc->InstanceTemplate());
   1788   Script::Compile(v8_str(
   1789       "var pre = 'Object: pre'; var on = 'Object: on';"))->Run();
   1790   v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run();
   1791   CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
   1792   v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run();
   1793   CHECK_EQ(v8_str("Object: on"), result_on);
   1794   v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run();
   1795   CHECK(result_post.IsEmpty());
   1796 }
   1797 
   1798 
   1799 THREADED_TEST(UndefinedIsNotEnumerable) {
   1800   v8::HandleScope scope;
   1801   LocalContext env;
   1802   v8::Handle<Value> result = Script::Compile(v8_str(
   1803       "this.propertyIsEnumerable(undefined)"))->Run();
   1804   CHECK(result->IsFalse());
   1805 }
   1806 
   1807 
   1808 v8::Handle<Script> call_recursively_script;
   1809 static const int kTargetRecursionDepth = 200;  // near maximum
   1810 
   1811 
   1812 static v8::Handle<Value> CallScriptRecursivelyCall(const v8::Arguments& args) {
   1813   ApiTestFuzzer::Fuzz();
   1814   int depth = args.This()->Get(v8_str("depth"))->Int32Value();
   1815   if (depth == kTargetRecursionDepth) return v8::Undefined();
   1816   args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
   1817   return call_recursively_script->Run();
   1818 }
   1819 
   1820 
   1821 static v8::Handle<Value> CallFunctionRecursivelyCall(
   1822     const v8::Arguments& args) {
   1823   ApiTestFuzzer::Fuzz();
   1824   int depth = args.This()->Get(v8_str("depth"))->Int32Value();
   1825   if (depth == kTargetRecursionDepth) {
   1826     printf("[depth = %d]\n", depth);
   1827     return v8::Undefined();
   1828   }
   1829   args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
   1830   v8::Handle<Value> function =
   1831       args.This()->Get(v8_str("callFunctionRecursively"));
   1832   return function.As<Function>()->Call(args.This(), 0, NULL);
   1833 }
   1834 
   1835 
   1836 THREADED_TEST(DeepCrossLanguageRecursion) {
   1837   v8::HandleScope scope;
   1838   v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
   1839   global->Set(v8_str("callScriptRecursively"),
   1840               v8::FunctionTemplate::New(CallScriptRecursivelyCall));
   1841   global->Set(v8_str("callFunctionRecursively"),
   1842               v8::FunctionTemplate::New(CallFunctionRecursivelyCall));
   1843   LocalContext env(NULL, global);
   1844 
   1845   env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
   1846   call_recursively_script = v8_compile("callScriptRecursively()");
   1847   call_recursively_script->Run();
   1848   call_recursively_script = v8::Handle<Script>();
   1849 
   1850   env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
   1851   Script::Compile(v8_str("callFunctionRecursively()"))->Run();
   1852 }
   1853 
   1854 
   1855 static v8::Handle<Value>
   1856     ThrowingPropertyHandlerGet(Local<String> key, const AccessorInfo&) {
   1857   ApiTestFuzzer::Fuzz();
   1858   return v8::ThrowException(key);
   1859 }
   1860 
   1861 
   1862 static v8::Handle<Value> ThrowingPropertyHandlerSet(Local<String> key,
   1863                                                     Local<Value>,
   1864                                                     const AccessorInfo&) {
   1865   v8::ThrowException(key);
   1866   return v8::Undefined();  // not the same as v8::Handle<v8::Value>()
   1867 }
   1868 
   1869 
   1870 THREADED_TEST(CallbackExceptionRegression) {
   1871   v8::HandleScope scope;
   1872   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
   1873   obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
   1874                                ThrowingPropertyHandlerSet);
   1875   LocalContext env;
   1876   env->Global()->Set(v8_str("obj"), obj->NewInstance());
   1877   v8::Handle<Value> otto = Script::Compile(v8_str(
   1878       "try { with (obj) { otto; } } catch (e) { e; }"))->Run();
   1879   CHECK_EQ(v8_str("otto"), otto);
   1880   v8::Handle<Value> netto = Script::Compile(v8_str(
   1881       "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run();
   1882   CHECK_EQ(v8_str("netto"), netto);
   1883 }
   1884 
   1885 
   1886 THREADED_TEST(FunctionPrototype) {
   1887   v8::HandleScope scope;
   1888   Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New();
   1889   Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
   1890   LocalContext env;
   1891   env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
   1892   Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak"));
   1893   CHECK_EQ(script->Run()->Int32Value(), 321);
   1894 }
   1895 
   1896 
   1897 THREADED_TEST(InternalFields) {
   1898   v8::HandleScope scope;
   1899   LocalContext env;
   1900 
   1901   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
   1902   Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
   1903   instance_templ->SetInternalFieldCount(1);
   1904   Local<v8::Object> obj = templ->GetFunction()->NewInstance();
   1905   CHECK_EQ(1, obj->InternalFieldCount());
   1906   CHECK(obj->GetInternalField(0)->IsUndefined());
   1907   obj->SetInternalField(0, v8_num(17));
   1908   CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
   1909 }
   1910 
   1911 
   1912 THREADED_TEST(GlobalObjectInternalFields) {
   1913   v8::HandleScope scope;
   1914   Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
   1915   global_template->SetInternalFieldCount(1);
   1916   LocalContext env(NULL, global_template);
   1917   v8::Handle<v8::Object> global_proxy = env->Global();
   1918   v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
   1919   CHECK_EQ(1, global->InternalFieldCount());
   1920   CHECK(global->GetInternalField(0)->IsUndefined());
   1921   global->SetInternalField(0, v8_num(17));
   1922   CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
   1923 }
   1924 
   1925 
   1926 THREADED_TEST(InternalFieldsNativePointers) {
   1927   v8::HandleScope scope;
   1928   LocalContext env;
   1929 
   1930   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
   1931   Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
   1932   instance_templ->SetInternalFieldCount(1);
   1933   Local<v8::Object> obj = templ->GetFunction()->NewInstance();
   1934   CHECK_EQ(1, obj->InternalFieldCount());
   1935   CHECK(obj->GetPointerFromInternalField(0) == NULL);
   1936 
   1937   char* data = new char[100];
   1938 
   1939   void* aligned = data;
   1940   CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
   1941   void* unaligned = data + 1;
   1942   CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
   1943 
   1944   // Check reading and writing aligned pointers.
   1945   obj->SetPointerInInternalField(0, aligned);
   1946   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
   1947   CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
   1948 
   1949   // Check reading and writing unaligned pointers.
   1950   obj->SetPointerInInternalField(0, unaligned);
   1951   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
   1952   CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
   1953 
   1954   delete[] data;
   1955 }
   1956 
   1957 
   1958 THREADED_TEST(InternalFieldsNativePointersAndExternal) {
   1959   v8::HandleScope scope;
   1960   LocalContext env;
   1961 
   1962   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
   1963   Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
   1964   instance_templ->SetInternalFieldCount(1);
   1965   Local<v8::Object> obj = templ->GetFunction()->NewInstance();
   1966   CHECK_EQ(1, obj->InternalFieldCount());
   1967   CHECK(obj->GetPointerFromInternalField(0) == NULL);
   1968 
   1969   char* data = new char[100];
   1970 
   1971   void* aligned = data;
   1972   CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
   1973   void* unaligned = data + 1;
   1974   CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
   1975 
   1976   obj->SetPointerInInternalField(0, aligned);
   1977   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
   1978   CHECK_EQ(aligned, v8::External::Unwrap(obj->GetInternalField(0)));
   1979 
   1980   obj->SetPointerInInternalField(0, unaligned);
   1981   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
   1982   CHECK_EQ(unaligned, v8::External::Unwrap(obj->GetInternalField(0)));
   1983 
   1984   obj->SetInternalField(0, v8::External::Wrap(aligned));
   1985   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
   1986   CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
   1987 
   1988   obj->SetInternalField(0, v8::External::Wrap(unaligned));
   1989   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
   1990   CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
   1991 
   1992   delete[] data;
   1993 }
   1994 
   1995 
   1996 THREADED_TEST(IdentityHash) {
   1997   v8::HandleScope scope;
   1998   LocalContext env;
   1999 
   2000   // Ensure that the test starts with an fresh heap to test whether the hash
   2001   // code is based on the address.
   2002   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
   2003   Local<v8::Object> obj = v8::Object::New();
   2004   int hash = obj->GetIdentityHash();
   2005   int hash1 = obj->GetIdentityHash();
   2006   CHECK_EQ(hash, hash1);
   2007   int hash2 = v8::Object::New()->GetIdentityHash();
   2008   // Since the identity hash is essentially a random number two consecutive
   2009   // objects should not be assigned the same hash code. If the test below fails
   2010   // the random number generator should be evaluated.
   2011   CHECK_NE(hash, hash2);
   2012   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
   2013   int hash3 = v8::Object::New()->GetIdentityHash();
   2014   // Make sure that the identity hash is not based on the initial address of
   2015   // the object alone. If the test below fails the random number generator
   2016   // should be evaluated.
   2017   CHECK_NE(hash, hash3);
   2018   int hash4 = obj->GetIdentityHash();
   2019   CHECK_EQ(hash, hash4);
   2020 
   2021   // Check identity hashes behaviour in the presence of JS accessors.
   2022   // Put a getter for 'v8::IdentityHash' on the Object's prototype:
   2023   {
   2024     CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
   2025     Local<v8::Object> o1 = v8::Object::New();
   2026     Local<v8::Object> o2 = v8::Object::New();
   2027     CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
   2028   }
   2029   {
   2030     CompileRun(
   2031         "function cnst() { return 42; };\n"
   2032         "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
   2033     Local<v8::Object> o1 = v8::Object::New();
   2034     Local<v8::Object> o2 = v8::Object::New();
   2035     CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
   2036   }
   2037 }
   2038 
   2039 
   2040 THREADED_TEST(HiddenProperties) {
   2041   v8::HandleScope scope;
   2042   LocalContext env;
   2043 
   2044   v8::Local<v8::Object> obj = v8::Object::New();
   2045   v8::Local<v8::String> key = v8_str("api-test::hidden-key");
   2046   v8::Local<v8::String> empty = v8_str("");
   2047   v8::Local<v8::String> prop_name = v8_str("prop_name");
   2048 
   2049   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
   2050 
   2051   // Make sure delete of a non-existent hidden value works
   2052   CHECK(obj->DeleteHiddenValue(key));
   2053 
   2054   CHECK(obj->SetHiddenValue(key, v8::Integer::New(1503)));
   2055   CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
   2056   CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
   2057   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
   2058 
   2059   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
   2060 
   2061   // Make sure we do not find the hidden property.
   2062   CHECK(!obj->Has(empty));
   2063   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
   2064   CHECK(obj->Get(empty)->IsUndefined());
   2065   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
   2066   CHECK(obj->Set(empty, v8::Integer::New(2003)));
   2067   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
   2068   CHECK_EQ(2003, obj->Get(empty)->Int32Value());
   2069 
   2070   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
   2071 
   2072   // Add another property and delete it afterwards to force the object in
   2073   // slow case.
   2074   CHECK(obj->Set(prop_name, v8::Integer::New(2008)));
   2075   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
   2076   CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
   2077   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
   2078   CHECK(obj->Delete(prop_name));
   2079   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
   2080 
   2081   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
   2082 
   2083   CHECK(obj->DeleteHiddenValue(key));
   2084   CHECK(obj->GetHiddenValue(key).IsEmpty());
   2085 }
   2086 
   2087 
   2088 THREADED_TEST(Regress97784) {
   2089   // Regression test for crbug.com/97784
   2090   // Messing with the Object.prototype should not have effect on
   2091   // hidden properties.
   2092   v8::HandleScope scope;
   2093   LocalContext env;
   2094 
   2095   v8::Local<v8::Object> obj = v8::Object::New();
   2096   v8::Local<v8::String> key = v8_str("hidden");
   2097 
   2098   CompileRun(
   2099       "set_called = false;"
   2100       "Object.defineProperty("
   2101       "    Object.prototype,"
   2102       "    'hidden',"
   2103       "    {get: function() { return 45; },"
   2104       "     set: function() { set_called = true; }})");
   2105 
   2106   CHECK(obj->GetHiddenValue(key).IsEmpty());
   2107   // Make sure that the getter and setter from Object.prototype is not invoked.
   2108   // If it did we would have full access to the hidden properties in
   2109   // the accessor.
   2110   CHECK(obj->SetHiddenValue(key, v8::Integer::New(42)));
   2111   ExpectFalse("set_called");
   2112   CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value());
   2113 }
   2114 
   2115 
   2116 static bool interceptor_for_hidden_properties_called;
   2117 static v8::Handle<Value> InterceptorForHiddenProperties(
   2118     Local<String> name, const AccessorInfo& info) {
   2119   interceptor_for_hidden_properties_called = true;
   2120   return v8::Handle<Value>();
   2121 }
   2122 
   2123 
   2124 THREADED_TEST(HiddenPropertiesWithInterceptors) {
   2125   v8::HandleScope scope;
   2126   LocalContext context;
   2127 
   2128   interceptor_for_hidden_properties_called = false;
   2129 
   2130   v8::Local<v8::String> key = v8_str("api-test::hidden-key");
   2131 
   2132   // Associate an interceptor with an object and start setting hidden values.
   2133   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
   2134   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
   2135   instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
   2136   Local<v8::Function> function = fun_templ->GetFunction();
   2137   Local<v8::Object> obj = function->NewInstance();
   2138   CHECK(obj->SetHiddenValue(key, v8::Integer::New(2302)));
   2139   CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
   2140   CHECK(!interceptor_for_hidden_properties_called);
   2141 }
   2142 
   2143 
   2144 THREADED_TEST(External) {
   2145   v8::HandleScope scope;
   2146   int x = 3;
   2147   Local<v8::External> ext = v8::External::New(&x);
   2148   LocalContext env;
   2149   env->Global()->Set(v8_str("ext"), ext);
   2150   Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
   2151   v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
   2152   int* ptr = static_cast<int*>(reext->Value());
   2153   CHECK_EQ(x, 3);
   2154   *ptr = 10;
   2155   CHECK_EQ(x, 10);
   2156 
   2157   // Make sure unaligned pointers are wrapped properly.
   2158   char* data = i::StrDup("0123456789");
   2159   Local<v8::Value> zero = v8::External::Wrap(&data[0]);
   2160   Local<v8::Value> one = v8::External::Wrap(&data[1]);
   2161   Local<v8::Value> two = v8::External::Wrap(&data[2]);
   2162   Local<v8::Value> three = v8::External::Wrap(&data[3]);
   2163 
   2164   char* char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(zero));
   2165   CHECK_EQ('0', *char_ptr);
   2166   char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(one));
   2167   CHECK_EQ('1', *char_ptr);
   2168   char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(two));
   2169   CHECK_EQ('2', *char_ptr);
   2170   char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(three));
   2171   CHECK_EQ('3', *char_ptr);
   2172   i::DeleteArray(data);
   2173 }
   2174 
   2175 
   2176 THREADED_TEST(GlobalHandle) {
   2177   v8::Persistent<String> global;
   2178   {
   2179     v8::HandleScope scope;
   2180     Local<String> str = v8_str("str");
   2181     global = v8::Persistent<String>::New(str);
   2182   }
   2183   CHECK_EQ(global->Length(), 3);
   2184   global.Dispose();
   2185 }
   2186 
   2187 
   2188 class WeakCallCounter {
   2189  public:
   2190   explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) { }
   2191   int id() { return id_; }
   2192   void increment() { number_of_weak_calls_++; }
   2193   int NumberOfWeakCalls() { return number_of_weak_calls_; }
   2194  private:
   2195   int id_;
   2196   int number_of_weak_calls_;
   2197 };
   2198 
   2199 
   2200 static void WeakPointerCallback(Persistent<Value> handle, void* id) {
   2201   WeakCallCounter* counter = reinterpret_cast<WeakCallCounter*>(id);
   2202   CHECK_EQ(1234, counter->id());
   2203   counter->increment();
   2204   handle.Dispose();
   2205 }
   2206 
   2207 
   2208 THREADED_TEST(ApiObjectGroups) {
   2209   HandleScope scope;
   2210   LocalContext env;
   2211 
   2212   Persistent<Object> g1s1;
   2213   Persistent<Object> g1s2;
   2214   Persistent<Object> g1c1;
   2215   Persistent<Object> g2s1;
   2216   Persistent<Object> g2s2;
   2217   Persistent<Object> g2c1;
   2218 
   2219   WeakCallCounter counter(1234);
   2220 
   2221   {
   2222     HandleScope scope;
   2223     g1s1 = Persistent<Object>::New(Object::New());
   2224     g1s2 = Persistent<Object>::New(Object::New());
   2225     g1c1 = Persistent<Object>::New(Object::New());
   2226     g1s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
   2227     g1s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
   2228     g1c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
   2229 
   2230     g2s1 = Persistent<Object>::New(Object::New());
   2231     g2s2 = Persistent<Object>::New(Object::New());
   2232     g2c1 = Persistent<Object>::New(Object::New());
   2233     g2s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
   2234     g2s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
   2235     g2c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
   2236   }
   2237 
   2238   Persistent<Object> root = Persistent<Object>::New(g1s1);  // make a root.
   2239 
   2240   // Connect group 1 and 2, make a cycle.
   2241   CHECK(g1s2->Set(0, g2s2));
   2242   CHECK(g2s1->Set(0, g1s1));
   2243 
   2244   {
   2245     Persistent<Value> g1_objects[] = { g1s1, g1s2 };
   2246     Persistent<Value> g1_children[] = { g1c1 };
   2247     Persistent<Value> g2_objects[] = { g2s1, g2s2 };
   2248     Persistent<Value> g2_children[] = { g2c1 };
   2249     V8::AddObjectGroup(g1_objects, 2);
   2250     V8::AddImplicitReferences(g1s1, g1_children, 1);
   2251     V8::AddObjectGroup(g2_objects, 2);
   2252     V8::AddImplicitReferences(g2s2, g2_children, 1);
   2253   }
   2254   // Do a single full GC, ensure incremental marking is stopped.
   2255   HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
   2256 
   2257   // All object should be alive.
   2258   CHECK_EQ(0, counter.NumberOfWeakCalls());
   2259 
   2260   // Weaken the root.
   2261   root.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
   2262   // But make children strong roots---all the objects (except for children)
   2263   // should be collectable now.
   2264   g1c1.ClearWeak();
   2265   g2c1.ClearWeak();
   2266 
   2267   // Groups are deleted, rebuild groups.
   2268   {
   2269     Persistent<Value> g1_objects[] = { g1s1, g1s2 };
   2270     Persistent<Value> g1_children[] = { g1c1 };
   2271     Persistent<Value> g2_objects[] = { g2s1, g2s2 };
   2272     Persistent<Value> g2_children[] = { g2c1 };
   2273     V8::AddObjectGroup(g1_objects, 2);
   2274     V8::AddImplicitReferences(g1s1, g1_children, 1);
   2275     V8::AddObjectGroup(g2_objects, 2);
   2276     V8::AddImplicitReferences(g2s2, g2_children, 1);
   2277   }
   2278 
   2279   HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
   2280 
   2281   // All objects should be gone. 5 global handles in total.
   2282   CHECK_EQ(5, counter.NumberOfWeakCalls());
   2283 
   2284   // And now make children weak again and collect them.
   2285   g1c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
   2286   g2c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
   2287 
   2288   HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
   2289   CHECK_EQ(7, counter.NumberOfWeakCalls());
   2290 }
   2291 
   2292 
   2293 THREADED_TEST(ApiObjectGroupsCycle) {
   2294   HandleScope scope;
   2295   LocalContext env;
   2296 
   2297   WeakCallCounter counter(1234);
   2298 
   2299   Persistent<Object> g1s1;
   2300   Persistent<Object> g1s2;
   2301   Persistent<Object> g2s1;
   2302   Persistent<Object> g2s2;
   2303   Persistent<Object> g3s1;
   2304   Persistent<Object> g3s2;
   2305 
   2306   {
   2307     HandleScope scope;
   2308     g1s1 = Persistent<Object>::New(Object::New());
   2309     g1s2 = Persistent<Object>::New(Object::New());
   2310     g1s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
   2311     g1s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
   2312 
   2313     g2s1 = Persistent<Object>::New(Object::New());
   2314     g2s2 = Persistent<Object>::New(Object::New());
   2315     g2s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
   2316     g2s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
   2317 
   2318     g3s1 = Persistent<Object>::New(Object::New());
   2319     g3s2 = Persistent<Object>::New(Object::New());
   2320     g3s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
   2321     g3s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
   2322   }
   2323 
   2324   Persistent<Object> root = Persistent<Object>::New(g1s1);  // make a root.
   2325 
   2326   // Connect groups.  We're building the following cycle:
   2327   // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
   2328   // groups.
   2329   {
   2330     Persistent<Value> g1_objects[] = { g1s1, g1s2 };
   2331     Persistent<Value> g1_children[] = { g2s1 };
   2332     Persistent<Value> g2_objects[] = { g2s1, g2s2 };
   2333     Persistent<Value> g2_children[] = { g3s1 };
   2334     Persistent<Value> g3_objects[] = { g3s1, g3s2 };
   2335     Persistent<Value> g3_children[] = { g1s1 };
   2336     V8::AddObjectGroup(g1_objects, 2);
   2337     V8::AddImplicitReferences(g1s1, g1_children, 1);
   2338     V8::AddObjectGroup(g2_objects, 2);
   2339     V8::AddImplicitReferences(g2s1, g2_children, 1);
   2340     V8::AddObjectGroup(g3_objects, 2);
   2341     V8::AddImplicitReferences(g3s1, g3_children, 1);
   2342   }
   2343   // Do a single full GC
   2344   HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
   2345 
   2346   // All object should be alive.
   2347   CHECK_EQ(0, counter.NumberOfWeakCalls());
   2348 
   2349   // Weaken the root.
   2350   root.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
   2351 
   2352   // Groups are deleted, rebuild groups.
   2353   {
   2354     Persistent<Value> g1_objects[] = { g1s1, g1s2 };
   2355     Persistent<Value> g1_children[] = { g2s1 };
   2356     Persistent<Value> g2_objects[] = { g2s1, g2s2 };
   2357     Persistent<Value> g2_children[] = { g3s1 };
   2358     Persistent<Value> g3_objects[] = { g3s1, g3s2 };
   2359     Persistent<Value> g3_children[] = { g1s1 };
   2360     V8::AddObjectGroup(g1_objects, 2);
   2361     V8::AddImplicitReferences(g1s1, g1_children, 1);
   2362     V8::AddObjectGroup(g2_objects, 2);
   2363     V8::AddImplicitReferences(g2s1, g2_children, 1);
   2364     V8::AddObjectGroup(g3_objects, 2);
   2365     V8::AddImplicitReferences(g3s1, g3_children, 1);
   2366   }
   2367 
   2368   HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
   2369 
   2370   // All objects should be gone. 7 global handles in total.
   2371   CHECK_EQ(7, counter.NumberOfWeakCalls());
   2372 }
   2373 
   2374 
   2375 THREADED_TEST(ScriptException) {
   2376   v8::HandleScope scope;
   2377   LocalContext env;
   2378   Local<Script> script = Script::Compile(v8_str("throw 'panama!';"));
   2379   v8::TryCatch try_catch;
   2380   Local<Value> result = script->Run();
   2381   CHECK(result.IsEmpty());
   2382   CHECK(try_catch.HasCaught());
   2383   String::AsciiValue exception_value(try_catch.Exception());
   2384   CHECK_EQ(*exception_value, "panama!");
   2385 }
   2386 
   2387 
   2388 bool message_received;
   2389 
   2390 
   2391 static void check_message(v8::Handle<v8::Message> message,
   2392                           v8::Handle<Value> data) {
   2393   CHECK_EQ(5.76, data->NumberValue());
   2394   CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
   2395   CHECK_EQ(7.56, message->GetScriptData()->NumberValue());
   2396   message_received = true;
   2397 }
   2398 
   2399 
   2400 THREADED_TEST(MessageHandlerData) {
   2401   message_received = false;
   2402   v8::HandleScope scope;
   2403   CHECK(!message_received);
   2404   v8::V8::AddMessageListener(check_message, v8_num(5.76));
   2405   LocalContext context;
   2406   v8::ScriptOrigin origin =
   2407       v8::ScriptOrigin(v8_str("6.75"));
   2408   v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
   2409                                                   &origin);
   2410   script->SetData(v8_str("7.56"));
   2411   script->Run();
   2412   CHECK(message_received);
   2413   // clear out the message listener
   2414   v8::V8::RemoveMessageListeners(check_message);
   2415 }
   2416 
   2417 
   2418 THREADED_TEST(GetSetProperty) {
   2419   v8::HandleScope scope;
   2420   LocalContext context;
   2421   context->Global()->Set(v8_str("foo"), v8_num(14));
   2422   context->Global()->Set(v8_str("12"), v8_num(92));
   2423   context->Global()->Set(v8::Integer::New(16), v8_num(32));
   2424   context->Global()->Set(v8_num(13), v8_num(56));
   2425   Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run();
   2426   CHECK_EQ(14, foo->Int32Value());
   2427   Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run();
   2428   CHECK_EQ(92, twelve->Int32Value());
   2429   Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run();
   2430   CHECK_EQ(32, sixteen->Int32Value());
   2431   Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run();
   2432   CHECK_EQ(56, thirteen->Int32Value());
   2433   CHECK_EQ(92, context->Global()->Get(v8::Integer::New(12))->Int32Value());
   2434   CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
   2435   CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
   2436   CHECK_EQ(32, context->Global()->Get(v8::Integer::New(16))->Int32Value());
   2437   CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
   2438   CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
   2439   CHECK_EQ(56, context->Global()->Get(v8::Integer::New(13))->Int32Value());
   2440   CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
   2441   CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
   2442 }
   2443 
   2444 
   2445 THREADED_TEST(PropertyAttributes) {
   2446   v8::HandleScope scope;
   2447   LocalContext context;
   2448   // none
   2449   Local<String> prop = v8_str("none");
   2450   context->Global()->Set(prop, v8_num(7));
   2451   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
   2452   // read-only
   2453   prop = v8_str("read_only");
   2454   context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
   2455   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
   2456   CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
   2457   Script::Compile(v8_str("read_only = 9"))->Run();
   2458   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
   2459   context->Global()->Set(prop, v8_num(10));
   2460   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
   2461   // dont-delete
   2462   prop = v8_str("dont_delete");
   2463   context->Global()->Set(prop, v8_num(13), v8::DontDelete);
   2464   CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
   2465   Script::Compile(v8_str("delete dont_delete"))->Run();
   2466   CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
   2467   CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
   2468   // dont-enum
   2469   prop = v8_str("dont_enum");
   2470   context->Global()->Set(prop, v8_num(28), v8::DontEnum);
   2471   CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
   2472   // absent
   2473   prop = v8_str("absent");
   2474   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
   2475   Local<Value> fake_prop = v8_num(1);
   2476   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
   2477   // exception
   2478   TryCatch try_catch;
   2479   Local<Value> exception =
   2480       CompileRun("({ toString: function() { throw 'exception';} })");
   2481   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
   2482   CHECK(try_catch.HasCaught());
   2483   String::AsciiValue exception_value(try_catch.Exception());
   2484   CHECK_EQ("exception", *exception_value);
   2485   try_catch.Reset();
   2486 }
   2487 
   2488 
   2489 THREADED_TEST(Array) {
   2490   v8::HandleScope scope;
   2491   LocalContext context;
   2492   Local<v8::Array> array = v8::Array::New();
   2493   CHECK_EQ(0, array->Length());
   2494   CHECK(array->Get(0)->IsUndefined());
   2495   CHECK(!array->Has(0));
   2496   CHECK(array->Get(100)->IsUndefined());
   2497   CHECK(!array->Has(100));
   2498   array->Set(2, v8_num(7));
   2499   CHECK_EQ(3, array->Length());
   2500   CHECK(!array->Has(0));
   2501   CHECK(!array->Has(1));
   2502   CHECK(array->Has(2));
   2503   CHECK_EQ(7, array->Get(2)->Int32Value());
   2504   Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
   2505   Local<v8::Array> arr = obj.As<v8::Array>();
   2506   CHECK_EQ(3, arr->Length());
   2507   CHECK_EQ(1, arr->Get(0)->Int32Value());
   2508   CHECK_EQ(2, arr->Get(1)->Int32Value());
   2509   CHECK_EQ(3, arr->Get(2)->Int32Value());
   2510   array = v8::Array::New(27);
   2511   CHECK_EQ(27, array->Length());
   2512   array = v8::Array::New(-27);
   2513   CHECK_EQ(0, array->Length());
   2514 }
   2515 
   2516 
   2517 v8::Handle<Value> HandleF(const v8::Arguments& args) {
   2518   v8::HandleScope scope;
   2519   ApiTestFuzzer::Fuzz();
   2520   Local<v8::Array> result = v8::Array::New(args.Length());
   2521   for (int i = 0; i < args.Length(); i++)
   2522     result->Set(i, args[i]);
   2523   return scope.Close(result);
   2524 }
   2525 
   2526 
   2527 THREADED_TEST(Vector) {
   2528   v8::HandleScope scope;
   2529   Local<ObjectTemplate> global = ObjectTemplate::New();
   2530   global->Set(v8_str("f"), v8::FunctionTemplate::New(HandleF));
   2531   LocalContext context(0, global);
   2532 
   2533   const char* fun = "f()";
   2534   Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
   2535   CHECK_EQ(0, a0->Length());
   2536 
   2537   const char* fun2 = "f(11)";
   2538   Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
   2539   CHECK_EQ(1, a1->Length());
   2540   CHECK_EQ(11, a1->Get(0)->Int32Value());
   2541 
   2542   const char* fun3 = "f(12, 13)";
   2543   Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
   2544   CHECK_EQ(2, a2->Length());
   2545   CHECK_EQ(12, a2->Get(0)->Int32Value());
   2546   CHECK_EQ(13, a2->Get(1)->Int32Value());
   2547 
   2548   const char* fun4 = "f(14, 15, 16)";
   2549   Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
   2550   CHECK_EQ(3, a3->Length());
   2551   CHECK_EQ(14, a3->Get(0)->Int32Value());
   2552   CHECK_EQ(15, a3->Get(1)->Int32Value());
   2553   CHECK_EQ(16, a3->Get(2)->Int32Value());
   2554 
   2555   const char* fun5 = "f(17, 18, 19, 20)";
   2556   Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
   2557   CHECK_EQ(4, a4->Length());
   2558   CHECK_EQ(17, a4->Get(0)->Int32Value());
   2559   CHECK_EQ(18, a4->Get(1)->Int32Value());
   2560   CHECK_EQ(19, a4->Get(2)->Int32Value());
   2561   CHECK_EQ(20, a4->Get(3)->Int32Value());
   2562 }
   2563 
   2564 
   2565 THREADED_TEST(FunctionCall) {
   2566   v8::HandleScope scope;
   2567   LocalContext context;
   2568   CompileRun(
   2569     "function Foo() {"
   2570     "  var result = [];"
   2571     "  for (var i = 0; i < arguments.length; i++) {"
   2572     "    result.push(arguments[i]);"
   2573     "  }"
   2574     "  return result;"
   2575     "}");
   2576   Local<Function> Foo =
   2577       Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
   2578 
   2579   v8::Handle<Value>* args0 = NULL;
   2580   Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
   2581   CHECK_EQ(0, a0->Length());
   2582 
   2583   v8::Handle<Value> args1[] = { v8_num(1.1) };
   2584   Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
   2585   CHECK_EQ(1, a1->Length());
   2586   CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
   2587 
   2588   v8::Handle<Value> args2[] = { v8_num(2.2),
   2589                                 v8_num(3.3) };
   2590   Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
   2591   CHECK_EQ(2, a2->Length());
   2592   CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
   2593   CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
   2594 
   2595   v8::Handle<Value> args3[] = { v8_num(4.4),
   2596                                 v8_num(5.5),
   2597                                 v8_num(6.6) };
   2598   Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
   2599   CHECK_EQ(3, a3->Length());
   2600   CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
   2601   CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
   2602   CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
   2603 
   2604   v8::Handle<Value> args4[] = { v8_num(7.7),
   2605                                 v8_num(8.8),
   2606                                 v8_num(9.9),
   2607                                 v8_num(10.11) };
   2608   Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
   2609   CHECK_EQ(4, a4->Length());
   2610   CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
   2611   CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
   2612   CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
   2613   CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
   2614 }
   2615 
   2616 
   2617 static const char* js_code_causing_out_of_memory =
   2618     "var a = new Array(); while(true) a.push(a);";
   2619 
   2620 
   2621 // These tests run for a long time and prevent us from running tests
   2622 // that come after them so they cannot run in parallel.
   2623 TEST(OutOfMemory) {
   2624   // It's not possible to read a snapshot into a heap with different dimensions.
   2625   if (i::Snapshot::IsEnabled()) return;
   2626   // Set heap limits.
   2627   static const int K = 1024;
   2628   v8::ResourceConstraints constraints;
   2629   constraints.set_max_young_space_size(256 * K);
   2630   constraints.set_max_old_space_size(4 * K * K);
   2631   v8::SetResourceConstraints(&constraints);
   2632 
   2633   // Execute a script that causes out of memory.
   2634   v8::HandleScope scope;
   2635   LocalContext context;
   2636   v8::V8::IgnoreOutOfMemoryException();
   2637   Local<Script> script =
   2638       Script::Compile(String::New(js_code_causing_out_of_memory));
   2639   Local<Value> result = script->Run();
   2640 
   2641   // Check for out of memory state.
   2642   CHECK(result.IsEmpty());
   2643   CHECK(context->HasOutOfMemoryException());
   2644 }
   2645 
   2646 
   2647 v8::Handle<Value> ProvokeOutOfMemory(const v8::Arguments& args) {
   2648   ApiTestFuzzer::Fuzz();
   2649 
   2650   v8::HandleScope scope;
   2651   LocalContext context;
   2652   Local<Script> script =
   2653       Script::Compile(String::New(js_code_causing_out_of_memory));
   2654   Local<Value> result = script->Run();
   2655 
   2656   // Check for out of memory state.
   2657   CHECK(result.IsEmpty());
   2658   CHECK(context->HasOutOfMemoryException());
   2659 
   2660   return result;
   2661 }
   2662 
   2663 
   2664 TEST(OutOfMemoryNested) {
   2665   // It's not possible to read a snapshot into a heap with different dimensions.
   2666   if (i::Snapshot::IsEnabled()) return;
   2667   // Set heap limits.
   2668   static const int K = 1024;
   2669   v8::ResourceConstraints constraints;
   2670   constraints.set_max_young_space_size(256 * K);
   2671   constraints.set_max_old_space_size(4 * K * K);
   2672   v8::SetResourceConstraints(&constraints);
   2673 
   2674   v8::HandleScope scope;
   2675   Local<ObjectTemplate> templ = ObjectTemplate::New();
   2676   templ->Set(v8_str("ProvokeOutOfMemory"),
   2677              v8::FunctionTemplate::New(ProvokeOutOfMemory));
   2678   LocalContext context(0, templ);
   2679   v8::V8::IgnoreOutOfMemoryException();
   2680   Local<Value> result = CompileRun(
   2681     "var thrown = false;"
   2682     "try {"
   2683     "  ProvokeOutOfMemory();"
   2684     "} catch (e) {"
   2685     "  thrown = true;"
   2686     "}");
   2687   // Check for out of memory state.
   2688   CHECK(result.IsEmpty());
   2689   CHECK(context->HasOutOfMemoryException());
   2690 }
   2691 
   2692 
   2693 TEST(HugeConsStringOutOfMemory) {
   2694   // It's not possible to read a snapshot into a heap with different dimensions.
   2695   if (i::Snapshot::IsEnabled()) return;
   2696   // Set heap limits.
   2697   static const int K = 1024;
   2698   v8::ResourceConstraints constraints;
   2699   constraints.set_max_young_space_size(256 * K);
   2700   constraints.set_max_old_space_size(2 * K * K);
   2701   v8::SetResourceConstraints(&constraints);
   2702 
   2703   // Execute a script that causes out of memory.
   2704   v8::V8::IgnoreOutOfMemoryException();
   2705 
   2706   v8::HandleScope scope;
   2707   LocalContext context;
   2708 
   2709   // Build huge string. This should fail with out of memory exception.
   2710   Local<Value> result = CompileRun(
   2711     "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();"
   2712     "for (var i = 0; i < 22; i++) { str = str + str; }");
   2713 
   2714   // Check for out of memory state.
   2715   CHECK(result.IsEmpty());
   2716   CHECK(context->HasOutOfMemoryException());
   2717 }
   2718 
   2719 
   2720 THREADED_TEST(ConstructCall) {
   2721   v8::HandleScope scope;
   2722   LocalContext context;
   2723   CompileRun(
   2724     "function Foo() {"
   2725     "  var result = [];"
   2726     "  for (var i = 0; i < arguments.length; i++) {"
   2727     "    result.push(arguments[i]);"
   2728     "  }"
   2729     "  return result;"
   2730     "}");
   2731   Local<Function> Foo =
   2732       Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
   2733 
   2734   v8::Handle<Value>* args0 = NULL;
   2735   Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
   2736   CHECK_EQ(0, a0->Length());
   2737 
   2738   v8::Handle<Value> args1[] = { v8_num(1.1) };
   2739   Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
   2740   CHECK_EQ(1, a1->Length());
   2741   CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
   2742 
   2743   v8::Handle<Value> args2[] = { v8_num(2.2),
   2744                                 v8_num(3.3) };
   2745   Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
   2746   CHECK_EQ(2, a2->Length());
   2747   CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
   2748   CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
   2749 
   2750   v8::Handle<Value> args3[] = { v8_num(4.4),
   2751                                 v8_num(5.5),
   2752                                 v8_num(6.6) };
   2753   Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
   2754   CHECK_EQ(3, a3->Length());
   2755   CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
   2756   CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
   2757   CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
   2758 
   2759   v8::Handle<Value> args4[] = { v8_num(7.7),
   2760                                 v8_num(8.8),
   2761                                 v8_num(9.9),
   2762                                 v8_num(10.11) };
   2763   Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
   2764   CHECK_EQ(4, a4->Length());
   2765   CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
   2766   CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
   2767   CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
   2768   CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
   2769 }
   2770 
   2771 
   2772 static void CheckUncle(v8::TryCatch* try_catch) {
   2773   CHECK(try_catch->HasCaught());
   2774   String::AsciiValue str_value(try_catch->Exception());
   2775   CHECK_EQ(*str_value, "uncle?");
   2776   try_catch->Reset();
   2777 }
   2778 
   2779 
   2780 THREADED_TEST(ConversionNumber) {
   2781   v8::HandleScope scope;
   2782   LocalContext env;
   2783   // Very large number.
   2784   CompileRun("var obj = Math.pow(2,32) * 1237;");
   2785   Local<Value> obj = env->Global()->Get(v8_str("obj"));
   2786   CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
   2787   CHECK_EQ(0, obj->ToInt32()->Value());
   2788   CHECK(0u == obj->ToUint32()->Value());  // NOLINT - no CHECK_EQ for unsigned.
   2789   // Large number.
   2790   CompileRun("var obj = -1234567890123;");
   2791   obj = env->Global()->Get(v8_str("obj"));
   2792   CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
   2793   CHECK_EQ(-1912276171, obj->ToInt32()->Value());
   2794   CHECK(2382691125u == obj->ToUint32()->Value());  // NOLINT
   2795   // Small positive integer.
   2796   CompileRun("var obj = 42;");
   2797   obj = env->Global()->Get(v8_str("obj"));
   2798   CHECK_EQ(42.0, obj->ToNumber()->Value());
   2799   CHECK_EQ(42, obj->ToInt32()->Value());
   2800   CHECK(42u == obj->ToUint32()->Value());  // NOLINT
   2801   // Negative integer.
   2802   CompileRun("var obj = -37;");
   2803   obj = env->Global()->Get(v8_str("obj"));
   2804   CHECK_EQ(-37.0, obj->ToNumber()->Value());
   2805   CHECK_EQ(-37, obj->ToInt32()->Value());
   2806   CHECK(4294967259u == obj->ToUint32()->Value());  // NOLINT
   2807   // Positive non-int32 integer.
   2808   CompileRun("var obj = 0x81234567;");
   2809   obj = env->Global()->Get(v8_str("obj"));
   2810   CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
   2811   CHECK_EQ(-2128394905, obj->ToInt32()->Value());
   2812   CHECK(2166572391u == obj->ToUint32()->Value());  // NOLINT
   2813   // Fraction.
   2814   CompileRun("var obj = 42.3;");
   2815   obj = env->Global()->Get(v8_str("obj"));
   2816   CHECK_EQ(42.3, obj->ToNumber()->Value());
   2817   CHECK_EQ(42, obj->ToInt32()->Value());
   2818   CHECK(42u == obj->ToUint32()->Value());  // NOLINT
   2819   // Large negative fraction.
   2820   CompileRun("var obj = -5726623061.75;");
   2821   obj = env->Global()->Get(v8_str("obj"));
   2822   CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
   2823   CHECK_EQ(-1431655765, obj->ToInt32()->Value());
   2824   CHECK(2863311531u == obj->ToUint32()->Value());  // NOLINT
   2825 }
   2826 
   2827 
   2828 THREADED_TEST(isNumberType) {
   2829   v8::HandleScope scope;
   2830   LocalContext env;
   2831   // Very large number.
   2832   CompileRun("var obj = Math.pow(2,32) * 1237;");
   2833   Local<Value> obj = env->Global()->Get(v8_str("obj"));
   2834   CHECK(!obj->IsInt32());
   2835   CHECK(!obj->IsUint32());
   2836   // Large negative number.
   2837   CompileRun("var obj = -1234567890123;");
   2838   obj = env->Global()->Get(v8_str("obj"));
   2839   CHECK(!obj->IsInt32());
   2840   CHECK(!obj->IsUint32());
   2841   // Small positive integer.
   2842   CompileRun("var obj = 42;");
   2843   obj = env->Global()->Get(v8_str("obj"));
   2844   CHECK(obj->IsInt32());
   2845   CHECK(obj->IsUint32());
   2846   // Negative integer.
   2847   CompileRun("var obj = -37;");
   2848   obj = env->Global()->Get(v8_str("obj"));
   2849   CHECK(obj->IsInt32());
   2850   CHECK(!obj->IsUint32());
   2851   // Positive non-int32 integer.
   2852   CompileRun("var obj = 0x81234567;");
   2853   obj = env->Global()->Get(v8_str("obj"));
   2854   CHECK(!obj->IsInt32());
   2855   CHECK(obj->IsUint32());
   2856   // Fraction.
   2857   CompileRun("var obj = 42.3;");
   2858   obj = env->Global()->Get(v8_str("obj"));
   2859   CHECK(!obj->IsInt32());
   2860   CHECK(!obj->IsUint32());
   2861   // Large negative fraction.
   2862   CompileRun("var obj = -5726623061.75;");
   2863   obj = env->Global()->Get(v8_str("obj"));
   2864   CHECK(!obj->IsInt32());
   2865   CHECK(!obj->IsUint32());
   2866   // Positive zero
   2867   CompileRun("var obj = 0.0;");
   2868   obj = env->Global()->Get(v8_str("obj"));
   2869   CHECK(obj->IsInt32());
   2870   CHECK(obj->IsUint32());
   2871   // Positive zero
   2872   CompileRun("var obj = -0.0;");
   2873   obj = env->Global()->Get(v8_str("obj"));
   2874   CHECK(!obj->IsInt32());
   2875   CHECK(!obj->IsUint32());
   2876 }
   2877 
   2878 
   2879 THREADED_TEST(ConversionException) {
   2880   v8::HandleScope scope;
   2881   LocalContext env;
   2882   CompileRun(
   2883     "function TestClass() { };"
   2884     "TestClass.prototype.toString = function () { throw 'uncle?'; };"
   2885     "var obj = new TestClass();");
   2886   Local<Value> obj = env->Global()->Get(v8_str("obj"));
   2887 
   2888   v8::TryCatch try_catch;
   2889 
   2890   Local<Value> to_string_result = obj->ToString();
   2891   CHECK(to_string_result.IsEmpty());
   2892   CheckUncle(&try_catch);
   2893 
   2894   Local<Value> to_number_result = obj->ToNumber();
   2895   CHECK(to_number_result.IsEmpty());
   2896   CheckUncle(&try_catch);
   2897 
   2898   Local<Value> to_integer_result = obj->ToInteger();
   2899   CHECK(to_integer_result.IsEmpty());
   2900   CheckUncle(&try_catch);
   2901 
   2902   Local<Value> to_uint32_result = obj->ToUint32();
   2903   CHECK(to_uint32_result.IsEmpty());
   2904   CheckUncle(&try_catch);
   2905 
   2906   Local<Value> to_int32_result = obj->ToInt32();
   2907   CHECK(to_int32_result.IsEmpty());
   2908   CheckUncle(&try_catch);
   2909 
   2910   Local<Value> to_object_result = v8::Undefined()->ToObject();
   2911   CHECK(to_object_result.IsEmpty());
   2912   CHECK(try_catch.HasCaught());
   2913   try_catch.Reset();
   2914 
   2915   int32_t int32_value = obj->Int32Value();
   2916   CHECK_EQ(0, int32_value);
   2917   CheckUncle(&try_catch);
   2918 
   2919   uint32_t uint32_value = obj->Uint32Value();
   2920   CHECK_EQ(0, uint32_value);
   2921   CheckUncle(&try_catch);
   2922 
   2923   double number_value = obj->NumberValue();
   2924   CHECK_NE(0, IsNaN(number_value));
   2925   CheckUncle(&try_catch);
   2926 
   2927   int64_t integer_value = obj->IntegerValue();
   2928   CHECK_EQ(0.0, static_cast<double>(integer_value));
   2929   CheckUncle(&try_catch);
   2930 }
   2931 
   2932 
   2933 v8::Handle<Value> ThrowFromC(const v8::Arguments& args) {
   2934   ApiTestFuzzer::Fuzz();
   2935   return v8::ThrowException(v8_str("konto"));
   2936 }
   2937 
   2938 
   2939 v8::Handle<Value> CCatcher(const v8::Arguments& args) {
   2940   if (args.Length() < 1) return v8::False();
   2941   v8::HandleScope scope;
   2942   v8::TryCatch try_catch;
   2943   Local<Value> result = v8::Script::Compile(args[0]->ToString())->Run();
   2944   CHECK(!try_catch.HasCaught() || result.IsEmpty());
   2945   return v8::Boolean::New(try_catch.HasCaught());
   2946 }
   2947 
   2948 
   2949 THREADED_TEST(APICatch) {
   2950   v8::HandleScope scope;
   2951   Local<ObjectTemplate> templ = ObjectTemplate::New();
   2952   templ->Set(v8_str("ThrowFromC"),
   2953              v8::FunctionTemplate::New(ThrowFromC));
   2954   LocalContext context(0, templ);
   2955   CompileRun(
   2956     "var thrown = false;"
   2957     "try {"
   2958     "  ThrowFromC();"
   2959     "} catch (e) {"
   2960     "  thrown = true;"
   2961     "}");
   2962   Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
   2963   CHECK(thrown->BooleanValue());
   2964 }
   2965 
   2966 
   2967 THREADED_TEST(APIThrowTryCatch) {
   2968   v8::HandleScope scope;
   2969   Local<ObjectTemplate> templ = ObjectTemplate::New();
   2970   templ->Set(v8_str("ThrowFromC"),
   2971              v8::FunctionTemplate::New(ThrowFromC));
   2972   LocalContext context(0, templ);
   2973   v8::TryCatch try_catch;
   2974   CompileRun("ThrowFromC();");
   2975   CHECK(try_catch.HasCaught());
   2976 }
   2977 
   2978 
   2979 // Test that a try-finally block doesn't shadow a try-catch block
   2980 // when setting up an external handler.
   2981 //
   2982 // BUG(271): Some of the exception propagation does not work on the
   2983 // ARM simulator because the simulator separates the C++ stack and the
   2984 // JS stack.  This test therefore fails on the simulator.  The test is
   2985 // not threaded to allow the threading tests to run on the simulator.
   2986 TEST(TryCatchInTryFinally) {
   2987   v8::HandleScope scope;
   2988   Local<ObjectTemplate> templ = ObjectTemplate::New();
   2989   templ->Set(v8_str("CCatcher"),
   2990              v8::FunctionTemplate::New(CCatcher));
   2991   LocalContext context(0, templ);
   2992   Local<Value> result = CompileRun("try {"
   2993                                    "  try {"
   2994                                    "    CCatcher('throw 7;');"
   2995                                    "  } finally {"
   2996                                    "  }"
   2997                                    "} catch (e) {"
   2998                                    "}");
   2999   CHECK(result->IsTrue());
   3000 }
   3001 
   3002 
   3003 static void check_reference_error_message(
   3004     v8::Handle<v8::Message> message,
   3005     v8::Handle<v8::Value> data) {
   3006   const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
   3007   CHECK(message->Get()->Equals(v8_str(reference_error)));
   3008 }
   3009 
   3010 
   3011 static v8::Handle<Value> Fail(const v8::Arguments& args) {
   3012   ApiTestFuzzer::Fuzz();
   3013   CHECK(false);
   3014   return v8::Undefined();
   3015 }
   3016 
   3017 
   3018 // Test that overwritten methods are not invoked on uncaught exception
   3019 // formatting. However, they are invoked when performing normal error
   3020 // string conversions.
   3021 TEST(APIThrowMessageOverwrittenToString) {
   3022   v8::HandleScope scope;
   3023   v8::V8::AddMessageListener(check_reference_error_message);
   3024   Local<ObjectTemplate> templ = ObjectTemplate::New();
   3025   templ->Set(v8_str("fail"), v8::FunctionTemplate::New(Fail));
   3026   LocalContext context(NULL, templ);
   3027   CompileRun("asdf;");
   3028   CompileRun("var limit = {};"
   3029              "limit.valueOf = fail;"
   3030              "Error.stackTraceLimit = limit;");
   3031   CompileRun("asdf");
   3032   CompileRun("Array.prototype.pop = fail;");
   3033   CompileRun("Object.prototype.hasOwnProperty = fail;");
   3034   CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
   3035   CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
   3036   CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
   3037   CompileRun("ReferenceError.prototype.toString ="
   3038              "  function() { return 'Whoops' }");
   3039   CompileRun("asdf;");
   3040   CompileRun("ReferenceError.prototype.constructor.name = void 0;");
   3041   CompileRun("asdf;");
   3042   CompileRun("ReferenceError.prototype.constructor = void 0;");
   3043   CompileRun("asdf;");
   3044   CompileRun("ReferenceError.prototype.__proto__ = new Object();");
   3045   CompileRun("asdf;");
   3046   CompileRun("ReferenceError.prototype = new Object();");
   3047   CompileRun("asdf;");
   3048   v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
   3049   CHECK(string->Equals(v8_str("Whoops")));
   3050   CompileRun("ReferenceError.prototype.constructor = new Object();"
   3051              "ReferenceError.prototype.constructor.name = 1;"
   3052              "Number.prototype.toString = function() { return 'Whoops'; };"
   3053              "ReferenceError.prototype.toString = Object.prototype.toString;");
   3054   CompileRun("asdf;");
   3055   v8::V8::RemoveMessageListeners(check_message);
   3056 }
   3057 
   3058 
   3059 static void receive_message(v8::Handle<v8::Message> message,
   3060                             v8::Handle<v8::Value> data) {
   3061   message->Get();
   3062   message_received = true;
   3063 }
   3064 
   3065 
   3066 TEST(APIThrowMessage) {
   3067   message_received = false;
   3068   v8::HandleScope scope;
   3069   v8::V8::AddMessageListener(receive_message);
   3070   Local<ObjectTemplate> templ = ObjectTemplate::New();
   3071   templ->Set(v8_str("ThrowFromC"),
   3072              v8::FunctionTemplate::New(ThrowFromC));
   3073   LocalContext context(0, templ);
   3074   CompileRun("ThrowFromC();");
   3075   CHECK(message_received);
   3076   v8::V8::RemoveMessageListeners(check_message);
   3077 }
   3078 
   3079 
   3080 TEST(APIThrowMessageAndVerboseTryCatch) {
   3081   message_received = false;
   3082   v8::HandleScope scope;
   3083   v8::V8::AddMessageListener(receive_message);
   3084   Local<ObjectTemplate> templ = ObjectTemplate::New();
   3085   templ->Set(v8_str("ThrowFromC"),
   3086              v8::FunctionTemplate::New(ThrowFromC));
   3087   LocalContext context(0, templ);
   3088   v8::TryCatch try_catch;
   3089   try_catch.SetVerbose(true);
   3090   Local<Value> result = CompileRun("ThrowFromC();");
   3091   CHECK(try_catch.HasCaught());
   3092   CHECK(result.IsEmpty());
   3093   CHECK(message_received);
   3094   v8::V8::RemoveMessageListeners(check_message);
   3095 }
   3096 
   3097 
   3098 TEST(APIStackOverflowAndVerboseTryCatch) {
   3099   message_received = false;
   3100   v8::HandleScope scope;
   3101   v8::V8::AddMessageListener(receive_message);
   3102   LocalContext context;
   3103   v8::TryCatch try_catch;
   3104   try_catch.SetVerbose(true);
   3105   Local<Value> result = CompileRun("function foo() { foo(); } foo();");
   3106   CHECK(try_catch.HasCaught());
   3107   CHECK(result.IsEmpty());
   3108   CHECK(message_received);
   3109   v8::V8::RemoveMessageListeners(receive_message);
   3110 }
   3111 
   3112 
   3113 THREADED_TEST(ExternalScriptException) {
   3114   v8::HandleScope scope;
   3115   Local<ObjectTemplate> templ = ObjectTemplate::New();
   3116   templ->Set(v8_str("ThrowFromC"),
   3117              v8::FunctionTemplate::New(ThrowFromC));
   3118   LocalContext context(0, templ);
   3119 
   3120   v8::TryCatch try_catch;
   3121   Local<Script> script
   3122       = Script::Compile(v8_str("ThrowFromC(); throw 'panama';"));
   3123   Local<Value> result = script->Run();
   3124   CHECK(result.IsEmpty());
   3125   CHECK(try_catch.HasCaught());
   3126   String::AsciiValue exception_value(try_catch.Exception());
   3127   CHECK_EQ("konto", *exception_value);
   3128 }
   3129 
   3130 
   3131 
   3132 v8::Handle<Value> CThrowCountDown(const v8::Arguments& args) {
   3133   ApiTestFuzzer::Fuzz();
   3134   CHECK_EQ(4, args.Length());
   3135   int count = args[0]->Int32Value();
   3136   int cInterval = args[2]->Int32Value();
   3137   if (count == 0) {
   3138     return v8::ThrowException(v8_str("FromC"));
   3139   } else {
   3140     Local<v8::Object> global = Context::GetCurrent()->Global();
   3141     Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
   3142     v8::Handle<Value> argv[] = { v8_num(count - 1),
   3143                                  args[1],
   3144                                  args[2],
   3145                                  args[3] };
   3146     if (count % cInterval == 0) {
   3147       v8::TryCatch try_catch;
   3148       Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
   3149       int expected = args[3]->Int32Value();
   3150       if (try_catch.HasCaught()) {
   3151         CHECK_EQ(expected, count);
   3152         CHECK(result.IsEmpty());
   3153         CHECK(!i::Isolate::Current()->has_scheduled_exception());
   3154       } else {
   3155         CHECK_NE(expected, count);
   3156       }
   3157       return result;
   3158     } else {
   3159       return fun.As<Function>()->Call(global, 4, argv);
   3160     }
   3161   }
   3162 }
   3163 
   3164 
   3165 v8::Handle<Value> JSCheck(const v8::Arguments& args) {
   3166   ApiTestFuzzer::Fuzz();
   3167   CHECK_EQ(3, args.Length());
   3168   bool equality = args[0]->BooleanValue();
   3169   int count = args[1]->Int32Value();
   3170   int expected = args[2]->Int32Value();
   3171   if (equality) {
   3172     CHECK_EQ(count, expected);
   3173   } else {
   3174     CHECK_NE(count, expected);
   3175   }
   3176   return v8::Undefined();
   3177 }
   3178 
   3179 
   3180 THREADED_TEST(EvalInTryFinally) {
   3181   v8::HandleScope scope;
   3182   LocalContext context;
   3183   v8::TryCatch try_catch;
   3184   CompileRun("(function() {"
   3185              "  try {"
   3186              "    eval('asldkf (*&^&*^');"
   3187              "  } finally {"
   3188              "    return;"
   3189              "  }"
   3190              "})()");
   3191   CHECK(!try_catch.HasCaught());
   3192 }
   3193 
   3194 
   3195 // This test works by making a stack of alternating JavaScript and C
   3196 // activations.  These activations set up exception handlers with regular
   3197 // intervals, one interval for C activations and another for JavaScript
   3198 // activations.  When enough activations have been created an exception is
   3199 // thrown and we check that the right activation catches the exception and that
   3200 // no other activations do.  The right activation is always the topmost one with
   3201 // a handler, regardless of whether it is in JavaScript or C.
   3202 //
   3203 // The notation used to describe a test case looks like this:
   3204 //
   3205 //    *JS[4] *C[3] @JS[2] C[1] JS[0]
   3206 //
   3207 // Each entry is an activation, either JS or C.  The index is the count at that
   3208 // level.  Stars identify activations with exception handlers, the @ identifies
   3209 // the exception handler that should catch the exception.
   3210 //
   3211 // BUG(271): Some of the exception propagation does not work on the
   3212 // ARM simulator because the simulator separates the C++ stack and the
   3213 // JS stack.  This test therefore fails on the simulator.  The test is
   3214 // not threaded to allow the threading tests to run on the simulator.
   3215 TEST(ExceptionOrder) {
   3216   v8::HandleScope scope;
   3217   Local<ObjectTemplate> templ = ObjectTemplate::New();
   3218   templ->Set(v8_str("check"), v8::FunctionTemplate::New(JSCheck));
   3219   templ->Set(v8_str("CThrowCountDown"),
   3220              v8::FunctionTemplate::New(CThrowCountDown));
   3221   LocalContext context(0, templ);
   3222   CompileRun(
   3223     "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
   3224     "  if (count == 0) throw 'FromJS';"
   3225     "  if (count % jsInterval == 0) {"
   3226     "    try {"
   3227     "      var value = CThrowCountDown(count - 1,"
   3228     "                                  jsInterval,"
   3229     "                                  cInterval,"
   3230     "                                  expected);"
   3231     "      check(false, count, expected);"
   3232     "      return value;"
   3233     "    } catch (e) {"
   3234     "      check(true, count, expected);"
   3235     "    }"
   3236     "  } else {"
   3237     "    return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
   3238     "  }"
   3239     "}");
   3240   Local<Function> fun =
   3241       Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
   3242 
   3243   const int argc = 4;
   3244   //                             count      jsInterval cInterval  expected
   3245 
   3246   // *JS[4] *C[3] @JS[2] C[1] JS[0]
   3247   v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
   3248   fun->Call(fun, argc, a0);
   3249 
   3250   // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
   3251   v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
   3252   fun->Call(fun, argc, a1);
   3253 
   3254   // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
   3255   v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
   3256   fun->Call(fun, argc, a2);
   3257 
   3258   // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
   3259   v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
   3260   fun->Call(fun, argc, a3);
   3261 
   3262   // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
   3263   v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
   3264   fun->Call(fun, argc, a4);
   3265 
   3266   // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
   3267   v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
   3268   fun->Call(fun, argc, a5);
   3269 }
   3270 
   3271 
   3272 v8::Handle<Value> ThrowValue(const v8::Arguments& args) {
   3273   ApiTestFuzzer::Fuzz();
   3274   CHECK_EQ(1, args.Length());
   3275   return v8::ThrowException(args[0]);
   3276 }
   3277 
   3278 
   3279 THREADED_TEST(ThrowValues) {
   3280   v8::HandleScope scope;
   3281   Local<ObjectTemplate> templ = ObjectTemplate::New();
   3282   templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(ThrowValue));
   3283   LocalContext context(0, templ);
   3284   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
   3285     "function Run(obj) {"
   3286     "  try {"
   3287     "    Throw(obj);"
   3288     "  } catch (e) {"
   3289     "    return e;"
   3290     "  }"
   3291     "  return 'no exception';"
   3292     "}"
   3293     "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
   3294   CHECK_EQ(5, result->Length());
   3295   CHECK(result->Get(v8::Integer::New(0))->IsString());
   3296   CHECK(result->Get(v8::Integer::New(1))->IsNumber());
   3297   CHECK_EQ(1, result->Get(v8::Integer::New(1))->Int32Value());
   3298   CHECK(result->Get(v8::Integer::New(2))->IsNumber());
   3299   CHECK_EQ(0, result->Get(v8::Integer::New(2))->Int32Value());
   3300   CHECK(result->Get(v8::Integer::New(3))->IsNull());
   3301   CHECK(result->Get(v8::Integer::New(4))->IsUndefined());
   3302 }
   3303 
   3304 
   3305 THREADED_TEST(CatchZero) {
   3306   v8::HandleScope scope;
   3307   LocalContext context;
   3308   v8::TryCatch try_catch;
   3309   CHECK(!try_catch.HasCaught());
   3310   Script::Compile(v8_str("throw 10"))->Run();
   3311   CHECK(try_catch.HasCaught());
   3312   CHECK_EQ(10, try_catch.Exception()->Int32Value());
   3313   try_catch.Reset();
   3314   CHECK(!try_catch.HasCaught());
   3315   Script::Compile(v8_str("throw 0"))->Run();
   3316   CHECK(try_catch.HasCaught());
   3317   CHECK_EQ(0, try_catch.Exception()->Int32Value());
   3318 }
   3319 
   3320 
   3321 THREADED_TEST(CatchExceptionFromWith) {
   3322   v8::HandleScope scope;
   3323   LocalContext context;
   3324   v8::TryCatch try_catch;
   3325   CHECK(!try_catch.HasCaught());
   3326   Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run();
   3327   CHECK(try_catch.HasCaught());
   3328 }
   3329 
   3330 
   3331 THREADED_TEST(TryCatchAndFinallyHidingException) {
   3332   v8::HandleScope scope;
   3333   LocalContext context;
   3334   v8::TryCatch try_catch;
   3335   CHECK(!try_catch.HasCaught());
   3336   CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
   3337   CompileRun("f({toString: function() { throw 42; }});");
   3338   CHECK(!try_catch.HasCaught());
   3339 }
   3340 
   3341 
   3342 v8::Handle<v8::Value> WithTryCatch(const v8::Arguments& args) {
   3343   v8::TryCatch try_catch;
   3344   return v8::Undefined();
   3345 }
   3346 
   3347 
   3348 THREADED_TEST(TryCatchAndFinally) {
   3349   v8::HandleScope scope;
   3350   LocalContext context;
   3351   context->Global()->Set(
   3352       v8_str("native_with_try_catch"),
   3353       v8::FunctionTemplate::New(WithTryCatch)->GetFunction());
   3354   v8::TryCatch try_catch;
   3355   CHECK(!try_catch.HasCaught());
   3356   CompileRun(
   3357       "try {\n"
   3358       "  throw new Error('a');\n"
   3359       "} finally {\n"
   3360       "  native_with_try_catch();\n"
   3361       "}\n");
   3362   CHECK(try_catch.HasCaught());
   3363 }
   3364 
   3365 
   3366 THREADED_TEST(Equality) {
   3367   v8::HandleScope scope;
   3368   LocalContext context;
   3369   // Check that equality works at all before relying on CHECK_EQ
   3370   CHECK(v8_str("a")->Equals(v8_str("a")));
   3371   CHECK(!v8_str("a")->Equals(v8_str("b")));
   3372 
   3373   CHECK_EQ(v8_str("a"), v8_str("a"));
   3374   CHECK_NE(v8_str("a"), v8_str("b"));
   3375   CHECK_EQ(v8_num(1), v8_num(1));
   3376   CHECK_EQ(v8_num(1.00), v8_num(1));
   3377   CHECK_NE(v8_num(1), v8_num(2));
   3378 
   3379   // Assume String is not symbol.
   3380   CHECK(v8_str("a")->StrictEquals(v8_str("a")));
   3381   CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
   3382   CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
   3383   CHECK(v8_num(1)->StrictEquals(v8_num(1)));
   3384   CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
   3385   CHECK(v8_num(0)->StrictEquals(v8_num(-0)));
   3386   Local<Value> not_a_number = v8_num(i::OS::nan_value());
   3387   CHECK(!not_a_number->StrictEquals(not_a_number));
   3388   CHECK(v8::False()->StrictEquals(v8::False()));
   3389   CHECK(!v8::False()->StrictEquals(v8::Undefined()));
   3390 
   3391   v8::Handle<v8::Object> obj = v8::Object::New();
   3392   v8::Persistent<v8::Object> alias = v8::Persistent<v8::Object>::New(obj);
   3393   CHECK(alias->StrictEquals(obj));
   3394   alias.Dispose();
   3395 }
   3396 
   3397 
   3398 THREADED_TEST(MultiRun) {
   3399   v8::HandleScope scope;
   3400   LocalContext context;
   3401   Local<Script> script = Script::Compile(v8_str("x"));
   3402   for (int i = 0; i < 10; i++)
   3403     script->Run();
   3404 }
   3405 
   3406 
   3407 static v8::Handle<Value> GetXValue(Local<String> name,
   3408                                    const AccessorInfo& info) {
   3409   ApiTestFuzzer::Fuzz();
   3410   CHECK_EQ(info.Data(), v8_str("donut"));
   3411   CHECK_EQ(name, v8_str("x"));
   3412   return name;
   3413 }
   3414 
   3415 
   3416 THREADED_TEST(SimplePropertyRead) {
   3417   v8::HandleScope scope;
   3418   Local<ObjectTemplate> templ = ObjectTemplate::New();
   3419   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
   3420   LocalContext context;
   3421   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   3422   Local<Script> script = Script::Compile(v8_str("obj.x"));
   3423   for (int i = 0; i < 10; i++) {
   3424     Local<Value> result = script->Run();
   3425     CHECK_EQ(result, v8_str("x"));
   3426   }
   3427 }
   3428 
   3429 THREADED_TEST(DefinePropertyOnAPIAccessor) {
   3430   v8::HandleScope scope;
   3431   Local<ObjectTemplate> templ = ObjectTemplate::New();
   3432   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
   3433   LocalContext context;
   3434   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   3435 
   3436   // Uses getOwnPropertyDescriptor to check the configurable status
   3437   Local<Script> script_desc
   3438     = Script::Compile(v8_str("var prop = Object.getOwnPropertyDescriptor( "
   3439                              "obj, 'x');"
   3440                              "prop.configurable;"));
   3441   Local<Value> result = script_desc->Run();
   3442   CHECK_EQ(result->BooleanValue(), true);
   3443 
   3444   // Redefine get - but still configurable
   3445   Local<Script> script_define
   3446     = Script::Compile(v8_str("var desc = { get: function(){return 42; },"
   3447                              "            configurable: true };"
   3448                              "Object.defineProperty(obj, 'x', desc);"
   3449                              "obj.x"));
   3450   result = script_define->Run();
   3451   CHECK_EQ(result, v8_num(42));
   3452 
   3453   // Check that the accessor is still configurable
   3454   result = script_desc->Run();
   3455   CHECK_EQ(result->BooleanValue(), true);
   3456 
   3457   // Redefine to a non-configurable
   3458   script_define
   3459     = Script::Compile(v8_str("var desc = { get: function(){return 43; },"
   3460                              "             configurable: false };"
   3461                              "Object.defineProperty(obj, 'x', desc);"
   3462                              "obj.x"));
   3463   result = script_define->Run();
   3464   CHECK_EQ(result, v8_num(43));
   3465   result = script_desc->Run();
   3466   CHECK_EQ(result->BooleanValue(), false);
   3467 
   3468   // Make sure that it is not possible to redefine again
   3469   v8::TryCatch try_catch;
   3470   result = script_define->Run();
   3471   CHECK(try_catch.HasCaught());
   3472   String::AsciiValue exception_value(try_catch.Exception());
   3473   CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
   3474 }
   3475 
   3476 THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
   3477   v8::HandleScope scope;
   3478   Local<ObjectTemplate> templ = ObjectTemplate::New();
   3479   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
   3480   LocalContext context;
   3481   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   3482 
   3483   Local<Script> script_desc = Script::Compile(v8_str("var prop ="
   3484                                     "Object.getOwnPropertyDescriptor( "
   3485                                     "obj, 'x');"
   3486                                     "prop.configurable;"));
   3487   Local<Value> result = script_desc->Run();
   3488   CHECK_EQ(result->BooleanValue(), true);
   3489 
   3490   Local<Script> script_define =
   3491     Script::Compile(v8_str("var desc = {get: function(){return 42; },"
   3492                            "            configurable: true };"
   3493                            "Object.defineProperty(obj, 'x', desc);"
   3494                            "obj.x"));
   3495   result = script_define->Run();
   3496   CHECK_EQ(result, v8_num(42));
   3497 
   3498 
   3499   result = script_desc->Run();
   3500   CHECK_EQ(result->BooleanValue(), true);
   3501 
   3502 
   3503   script_define =
   3504     Script::Compile(v8_str("var desc = {get: function(){return 43; },"
   3505                            "            configurable: false };"
   3506                            "Object.defineProperty(obj, 'x', desc);"
   3507                            "obj.x"));
   3508   result = script_define->Run();
   3509   CHECK_EQ(result, v8_num(43));
   3510   result = script_desc->Run();
   3511 
   3512   CHECK_EQ(result->BooleanValue(), false);
   3513 
   3514   v8::TryCatch try_catch;
   3515   result = script_define->Run();
   3516   CHECK(try_catch.HasCaught());
   3517   String::AsciiValue exception_value(try_catch.Exception());
   3518   CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
   3519 }
   3520 
   3521 
   3522 static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
   3523                                                 char const* name) {
   3524   return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
   3525 }
   3526 
   3527 
   3528 THREADED_TEST(DefineAPIAccessorOnObject) {
   3529   v8::HandleScope scope;
   3530   Local<ObjectTemplate> templ = ObjectTemplate::New();
   3531   LocalContext context;
   3532 
   3533   context->Global()->Set(v8_str("obj1"), templ->NewInstance());
   3534   CompileRun("var obj2 = {};");
   3535 
   3536   CHECK(CompileRun("obj1.x")->IsUndefined());
   3537   CHECK(CompileRun("obj2.x")->IsUndefined());
   3538 
   3539   CHECK(GetGlobalProperty(&context, "obj1")->
   3540       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
   3541 
   3542   ExpectString("obj1.x", "x");
   3543   CHECK(CompileRun("obj2.x")->IsUndefined());
   3544 
   3545   CHECK(GetGlobalProperty(&context, "obj2")->
   3546       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
   3547 
   3548   ExpectString("obj1.x", "x");
   3549   ExpectString("obj2.x", "x");
   3550 
   3551   ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
   3552   ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
   3553 
   3554   CompileRun("Object.defineProperty(obj1, 'x',"
   3555              "{ get: function() { return 'y'; }, configurable: true })");
   3556 
   3557   ExpectString("obj1.x", "y");
   3558   ExpectString("obj2.x", "x");
   3559 
   3560   CompileRun("Object.defineProperty(obj2, 'x',"
   3561              "{ get: function() { return 'y'; }, configurable: true })");
   3562 
   3563   ExpectString("obj1.x", "y");
   3564   ExpectString("obj2.x", "y");
   3565 
   3566   ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
   3567   ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
   3568 
   3569   CHECK(GetGlobalProperty(&context, "obj1")->
   3570       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
   3571   CHECK(GetGlobalProperty(&context, "obj2")->
   3572       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
   3573 
   3574   ExpectString("obj1.x", "x");
   3575   ExpectString("obj2.x", "x");
   3576 
   3577   ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
   3578   ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
   3579 
   3580   // Define getters/setters, but now make them not configurable.
   3581   CompileRun("Object.defineProperty(obj1, 'x',"
   3582              "{ get: function() { return 'z'; }, configurable: false })");
   3583   CompileRun("Object.defineProperty(obj2, 'x',"
   3584              "{ get: function() { return 'z'; }, configurable: false })");
   3585 
   3586   ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
   3587   ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
   3588 
   3589   ExpectString("obj1.x", "z");
   3590   ExpectString("obj2.x", "z");
   3591 
   3592   CHECK(!GetGlobalProperty(&context, "obj1")->
   3593       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
   3594   CHECK(!GetGlobalProperty(&context, "obj2")->
   3595       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
   3596 
   3597   ExpectString("obj1.x", "z");
   3598   ExpectString("obj2.x", "z");
   3599 }
   3600 
   3601 
   3602 THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
   3603   v8::HandleScope scope;
   3604   Local<ObjectTemplate> templ = ObjectTemplate::New();
   3605   LocalContext context;
   3606 
   3607   context->Global()->Set(v8_str("obj1"), templ->NewInstance());
   3608   CompileRun("var obj2 = {};");
   3609 
   3610   CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
   3611         v8_str("x"),
   3612         GetXValue, NULL,
   3613         v8_str("donut"), v8::DEFAULT, v8::DontDelete));
   3614   CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
   3615         v8_str("x"),
   3616         GetXValue, NULL,
   3617         v8_str("donut"), v8::DEFAULT, v8::DontDelete));
   3618 
   3619   ExpectString("obj1.x", "x");
   3620   ExpectString("obj2.x", "x");
   3621 
   3622   ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
   3623   ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
   3624 
   3625   CHECK(!GetGlobalProperty(&context, "obj1")->
   3626       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
   3627   CHECK(!GetGlobalProperty(&context, "obj2")->
   3628       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
   3629 
   3630   {
   3631     v8::TryCatch try_catch;
   3632     CompileRun("Object.defineProperty(obj1, 'x',"
   3633         "{get: function() { return 'func'; }})");
   3634     CHECK(try_catch.HasCaught());
   3635     String::AsciiValue exception_value(try_catch.Exception());
   3636     CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
   3637   }
   3638   {
   3639     v8::TryCatch try_catch;
   3640     CompileRun("Object.defineProperty(obj2, 'x',"
   3641         "{get: function() { return 'func'; }})");
   3642     CHECK(try_catch.HasCaught());
   3643     String::AsciiValue exception_value(try_catch.Exception());
   3644     CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
   3645   }
   3646 }
   3647 
   3648 
   3649 static v8::Handle<Value> Get239Value(Local<String> name,
   3650                                      const AccessorInfo& info) {
   3651   ApiTestFuzzer::Fuzz();
   3652   CHECK_EQ(info.Data(), v8_str("donut"));
   3653   CHECK_EQ(name, v8_str("239"));
   3654   return name;
   3655 }
   3656 
   3657 
   3658 THREADED_TEST(ElementAPIAccessor) {
   3659   v8::HandleScope scope;
   3660   Local<ObjectTemplate> templ = ObjectTemplate::New();
   3661   LocalContext context;
   3662 
   3663   context->Global()->Set(v8_str("obj1"), templ->NewInstance());
   3664   CompileRun("var obj2 = {};");
   3665 
   3666   CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
   3667         v8_str("239"),
   3668         Get239Value, NULL,
   3669         v8_str("donut")));
   3670   CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
   3671         v8_str("239"),
   3672         Get239Value, NULL,
   3673         v8_str("donut")));
   3674 
   3675   ExpectString("obj1[239]", "239");
   3676   ExpectString("obj2[239]", "239");
   3677   ExpectString("obj1['239']", "239");
   3678   ExpectString("obj2['239']", "239");
   3679 }
   3680 
   3681 
   3682 v8::Persistent<Value> xValue;
   3683 
   3684 
   3685 static void SetXValue(Local<String> name,
   3686                       Local<Value> value,
   3687                       const AccessorInfo& info) {
   3688   CHECK_EQ(value, v8_num(4));
   3689   CHECK_EQ(info.Data(), v8_str("donut"));
   3690   CHECK_EQ(name, v8_str("x"));
   3691   CHECK(xValue.IsEmpty());
   3692   xValue = v8::Persistent<Value>::New(value);
   3693 }
   3694 
   3695 
   3696 THREADED_TEST(SimplePropertyWrite) {
   3697   v8::HandleScope scope;
   3698   Local<ObjectTemplate> templ = ObjectTemplate::New();
   3699   templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
   3700   LocalContext context;
   3701   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   3702   Local<Script> script = Script::Compile(v8_str("obj.x = 4"));
   3703   for (int i = 0; i < 10; i++) {
   3704     CHECK(xValue.IsEmpty());
   3705     script->Run();
   3706     CHECK_EQ(v8_num(4), xValue);
   3707     xValue.Dispose();
   3708     xValue = v8::Persistent<Value>();
   3709   }
   3710 }
   3711 
   3712 
   3713 static v8::Handle<Value> XPropertyGetter(Local<String> property,
   3714                                          const AccessorInfo& info) {
   3715   ApiTestFuzzer::Fuzz();
   3716   CHECK(info.Data()->IsUndefined());
   3717   return property;
   3718 }
   3719 
   3720 
   3721 THREADED_TEST(NamedInterceptorPropertyRead) {
   3722   v8::HandleScope scope;
   3723   Local<ObjectTemplate> templ = ObjectTemplate::New();
   3724   templ->SetNamedPropertyHandler(XPropertyGetter);
   3725   LocalContext context;
   3726   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   3727   Local<Script> script = Script::Compile(v8_str("obj.x"));
   3728   for (int i = 0; i < 10; i++) {
   3729     Local<Value> result = script->Run();
   3730     CHECK_EQ(result, v8_str("x"));
   3731   }
   3732 }
   3733 
   3734 
   3735 THREADED_TEST(NamedInterceptorDictionaryIC) {
   3736   v8::HandleScope scope;
   3737   Local<ObjectTemplate> templ = ObjectTemplate::New();
   3738   templ->SetNamedPropertyHandler(XPropertyGetter);
   3739   LocalContext context;
   3740   // Create an object with a named interceptor.
   3741   context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
   3742   Local<Script> script = Script::Compile(v8_str("interceptor_obj.x"));
   3743   for (int i = 0; i < 10; i++) {
   3744     Local<Value> result = script->Run();
   3745     CHECK_EQ(result, v8_str("x"));
   3746   }
   3747   // Create a slow case object and a function accessing a property in
   3748   // that slow case object (with dictionary probing in generated
   3749   // code). Then force object with a named interceptor into slow-case,
   3750   // pass it to the function, and check that the interceptor is called
   3751   // instead of accessing the local property.
   3752   Local<Value> result =
   3753       CompileRun("function get_x(o) { return o.x; };"
   3754                  "var obj = { x : 42, y : 0 };"
   3755                  "delete obj.y;"
   3756                  "for (var i = 0; i < 10; i++) get_x(obj);"
   3757                  "interceptor_obj.x = 42;"
   3758                  "interceptor_obj.y = 10;"
   3759                  "delete interceptor_obj.y;"
   3760                  "get_x(interceptor_obj)");
   3761   CHECK_EQ(result, v8_str("x"));
   3762 }
   3763 
   3764 
   3765 THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
   3766   v8::HandleScope scope;
   3767 
   3768   v8::Persistent<Context> context1 = Context::New();
   3769 
   3770   context1->Enter();
   3771   Local<ObjectTemplate> templ = ObjectTemplate::New();
   3772   templ->SetNamedPropertyHandler(XPropertyGetter);
   3773   // Create an object with a named interceptor.
   3774   v8::Local<v8::Object> object = templ->NewInstance();
   3775   context1->Global()->Set(v8_str("interceptor_obj"), object);
   3776 
   3777   // Force the object into the slow case.
   3778   CompileRun("interceptor_obj.y = 0;"
   3779              "delete interceptor_obj.y;");
   3780   context1->Exit();
   3781 
   3782   {
   3783     // Introduce the object into a different context.
   3784     // Repeat named loads to exercise ICs.
   3785     LocalContext context2;
   3786     context2->Global()->Set(v8_str("interceptor_obj"), object);
   3787     Local<Value> result =
   3788       CompileRun("function get_x(o) { return o.x; }"
   3789                  "interceptor_obj.x = 42;"
   3790                  "for (var i=0; i != 10; i++) {"
   3791                  "  get_x(interceptor_obj);"
   3792                  "}"
   3793                  "get_x(interceptor_obj)");
   3794     // Check that the interceptor was actually invoked.
   3795     CHECK_EQ(result, v8_str("x"));
   3796   }
   3797 
   3798   // Return to the original context and force some object to the slow case
   3799   // to cause the NormalizedMapCache to verify.
   3800   context1->Enter();
   3801   CompileRun("var obj = { x : 0 }; delete obj.x;");
   3802   context1->Exit();
   3803 
   3804   context1.Dispose();
   3805 }
   3806 
   3807 
   3808 static v8::Handle<Value> SetXOnPrototypeGetter(Local<String> property,
   3809                                                const AccessorInfo& info) {
   3810   // Set x on the prototype object and do not handle the get request.
   3811   v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
   3812   proto.As<v8::Object>()->Set(v8_str("x"), v8::Integer::New(23));
   3813   return v8::Handle<Value>();
   3814 }
   3815 
   3816 
   3817 // This is a regression test for http://crbug.com/20104. Map
   3818 // transitions should not interfere with post interceptor lookup.
   3819 THREADED_TEST(NamedInterceptorMapTransitionRead) {
   3820   v8::HandleScope scope;
   3821   Local<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New();
   3822   Local<v8::ObjectTemplate> instance_template
   3823       = function_template->InstanceTemplate();
   3824   instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
   3825   LocalContext context;
   3826   context->Global()->Set(v8_str("F"), function_template->GetFunction());
   3827   // Create an instance of F and introduce a map transition for x.
   3828   CompileRun("var o = new F(); o.x = 23;");
   3829   // Create an instance of F and invoke the getter. The result should be 23.
   3830   Local<Value> result = CompileRun("o = new F(); o.x");
   3831   CHECK_EQ(result->Int32Value(), 23);
   3832 }
   3833 
   3834 
   3835 static v8::Handle<Value> IndexedPropertyGetter(uint32_t index,
   3836                                                const AccessorInfo& info) {
   3837   ApiTestFuzzer::Fuzz();
   3838   if (index == 37) {
   3839     return v8::Handle<Value>(v8_num(625));
   3840   }
   3841   return v8::Handle<Value>();
   3842 }
   3843 
   3844 
   3845 static v8::Handle<Value> IndexedPropertySetter(uint32_t index,
   3846                                                Local<Value> value,
   3847                                                const AccessorInfo& info) {
   3848   ApiTestFuzzer::Fuzz();
   3849   if (index == 39) {
   3850     return value;
   3851   }
   3852   return v8::Handle<Value>();
   3853 }
   3854 
   3855 
   3856 THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
   3857   v8::HandleScope scope;
   3858   Local<ObjectTemplate> templ = ObjectTemplate::New();
   3859   templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
   3860                                    IndexedPropertySetter);
   3861   LocalContext context;
   3862   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   3863   Local<Script> getter_script = Script::Compile(v8_str(
   3864       "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];"));
   3865   Local<Script> setter_script = Script::Compile(v8_str(
   3866       "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
   3867       "obj[17] = 23;"
   3868       "obj.foo;"));
   3869   Local<Script> interceptor_setter_script = Script::Compile(v8_str(
   3870       "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
   3871       "obj[39] = 47;"
   3872       "obj.foo;"));  // This setter should not run, due to the interceptor.
   3873   Local<Script> interceptor_getter_script = Script::Compile(v8_str(
   3874       "obj[37];"));
   3875   Local<Value> result = getter_script->Run();
   3876   CHECK_EQ(v8_num(5), result);
   3877   result = setter_script->Run();
   3878   CHECK_EQ(v8_num(23), result);
   3879   result = interceptor_setter_script->Run();
   3880   CHECK_EQ(v8_num(23), result);
   3881   result = interceptor_getter_script->Run();
   3882   CHECK_EQ(v8_num(625), result);
   3883 }
   3884 
   3885 
   3886 static v8::Handle<Value> UnboxedDoubleIndexedPropertyGetter(
   3887     uint32_t index,
   3888     const AccessorInfo& info) {
   3889   ApiTestFuzzer::Fuzz();
   3890   if (index < 25) {
   3891     return v8::Handle<Value>(v8_num(index));
   3892   }
   3893   return v8::Handle<Value>();
   3894 }
   3895 
   3896 
   3897 static v8::Handle<Value> UnboxedDoubleIndexedPropertySetter(
   3898     uint32_t index,
   3899     Local<Value> value,
   3900     const AccessorInfo& info) {
   3901   ApiTestFuzzer::Fuzz();
   3902   if (index < 25) {
   3903     return v8::Handle<Value>(v8_num(index));
   3904   }
   3905   return v8::Handle<Value>();
   3906 }
   3907 
   3908 
   3909 Handle<v8::Array> UnboxedDoubleIndexedPropertyEnumerator(
   3910     const AccessorInfo& info) {
   3911   // Force the list of returned keys to be stored in a FastDoubleArray.
   3912   Local<Script> indexed_property_names_script = Script::Compile(v8_str(
   3913       "keys = new Array(); keys[125000] = 1;"
   3914       "for(i = 0; i < 80000; i++) { keys[i] = i; };"
   3915       "keys.length = 25; keys;"));
   3916   Local<Value> result = indexed_property_names_script->Run();
   3917   return Local<v8::Array>(::v8::Array::Cast(*result));
   3918 }
   3919 
   3920 
   3921 // Make sure that the the interceptor code in the runtime properly handles
   3922 // merging property name lists for double-array-backed arrays.
   3923 THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
   3924   v8::HandleScope scope;
   3925   Local<ObjectTemplate> templ = ObjectTemplate::New();
   3926   templ->SetIndexedPropertyHandler(UnboxedDoubleIndexedPropertyGetter,
   3927                                    UnboxedDoubleIndexedPropertySetter,
   3928                                    0,
   3929                                    0,
   3930                                    UnboxedDoubleIndexedPropertyEnumerator);
   3931   LocalContext context;
   3932   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   3933   // When obj is created, force it to be Stored in a FastDoubleArray.
   3934   Local<Script> create_unboxed_double_script = Script::Compile(v8_str(
   3935       "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
   3936       "key_count = 0; "
   3937       "for (x in obj) {key_count++;};"
   3938       "obj;"));
   3939   Local<Value> result = create_unboxed_double_script->Run();
   3940   CHECK(result->ToObject()->HasRealIndexedProperty(2000));
   3941   Local<Script> key_count_check = Script::Compile(v8_str(
   3942       "key_count;"));
   3943   result = key_count_check->Run();
   3944   CHECK_EQ(v8_num(40013), result);
   3945 }
   3946 
   3947 
   3948 Handle<v8::Array> NonStrictArgsIndexedPropertyEnumerator(
   3949     const AccessorInfo& info) {
   3950   // Force the list of returned keys to be stored in a Arguments object.
   3951   Local<Script> indexed_property_names_script = Script::Compile(v8_str(
   3952       "function f(w,x) {"
   3953       " return arguments;"
   3954       "}"
   3955       "keys = f(0, 1, 2, 3);"
   3956       "keys;"));
   3957   Local<Value> result = indexed_property_names_script->Run();
   3958   return Local<v8::Array>(static_cast<v8::Array*>(::v8::Object::Cast(*result)));
   3959 }
   3960 
   3961 
   3962 static v8::Handle<Value> NonStrictIndexedPropertyGetter(
   3963     uint32_t index,
   3964     const AccessorInfo& info) {
   3965   ApiTestFuzzer::Fuzz();
   3966   if (index < 4) {
   3967     return v8::Handle<Value>(v8_num(index));
   3968   }
   3969   return v8::Handle<Value>();
   3970 }
   3971 
   3972 
   3973 // Make sure that the the interceptor code in the runtime properly handles
   3974 // merging property name lists for non-string arguments arrays.
   3975 THREADED_TEST(IndexedInterceptorNonStrictArgsWithIndexedAccessor) {
   3976   v8::HandleScope scope;
   3977   Local<ObjectTemplate> templ = ObjectTemplate::New();
   3978   templ->SetIndexedPropertyHandler(NonStrictIndexedPropertyGetter,
   3979                                    0,
   3980                                    0,
   3981                                    0,
   3982                                    NonStrictArgsIndexedPropertyEnumerator);
   3983   LocalContext context;
   3984   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   3985   Local<Script> create_args_script =
   3986       Script::Compile(v8_str(
   3987           "var key_count = 0;"
   3988           "for (x in obj) {key_count++;} key_count;"));
   3989   Local<Value> result = create_args_script->Run();
   3990   CHECK_EQ(v8_num(4), result);
   3991 }
   3992 
   3993 
   3994 static v8::Handle<Value> IdentityIndexedPropertyGetter(
   3995     uint32_t index,
   3996     const AccessorInfo& info) {
   3997   return v8::Integer::NewFromUnsigned(index);
   3998 }
   3999 
   4000 
   4001 THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
   4002   v8::HandleScope scope;
   4003   Local<ObjectTemplate> templ = ObjectTemplate::New();
   4004   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
   4005 
   4006   LocalContext context;
   4007   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   4008 
   4009   // Check fast object case.
   4010   const char* fast_case_code =
   4011       "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
   4012   ExpectString(fast_case_code, "0");
   4013 
   4014   // Check slow case.
   4015   const char* slow_case_code =
   4016       "obj.x = 1; delete obj.x;"
   4017       "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
   4018   ExpectString(slow_case_code, "1");
   4019 }
   4020 
   4021 
   4022 THREADED_TEST(IndexedInterceptorWithNoSetter) {
   4023   v8::HandleScope scope;
   4024   Local<ObjectTemplate> templ = ObjectTemplate::New();
   4025   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
   4026 
   4027   LocalContext context;
   4028   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   4029 
   4030   const char* code =
   4031       "try {"
   4032       "  obj[0] = 239;"
   4033       "  for (var i = 0; i < 100; i++) {"
   4034       "    var v = obj[0];"
   4035       "    if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
   4036       "  }"
   4037       "  'PASSED'"
   4038       "} catch(e) {"
   4039       "  e"
   4040       "}";
   4041   ExpectString(code, "PASSED");
   4042 }
   4043 
   4044 
   4045 THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
   4046   v8::HandleScope scope;
   4047   Local<ObjectTemplate> templ = ObjectTemplate::New();
   4048   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
   4049 
   4050   LocalContext context;
   4051   Local<v8::Object> obj = templ->NewInstance();
   4052   obj->TurnOnAccessCheck();
   4053   context->Global()->Set(v8_str("obj"), obj);
   4054 
   4055   const char* code =
   4056       "try {"
   4057       "  for (var i = 0; i < 100; i++) {"
   4058       "    var v = obj[0];"
   4059       "    if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
   4060       "  }"
   4061       "  'PASSED'"
   4062       "} catch(e) {"
   4063       "  e"
   4064       "}";
   4065   ExpectString(code, "PASSED");
   4066 }
   4067 
   4068 
   4069 THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
   4070   i::FLAG_allow_natives_syntax = true;
   4071   v8::HandleScope scope;
   4072   Local<ObjectTemplate> templ = ObjectTemplate::New();
   4073   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
   4074 
   4075   LocalContext context;
   4076   Local<v8::Object> obj = templ->NewInstance();
   4077   context->Global()->Set(v8_str("obj"), obj);
   4078 
   4079   const char* code =
   4080       "try {"
   4081       "  for (var i = 0; i < 100; i++) {"
   4082       "    var expected = i;"
   4083       "    if (i == 5) {"
   4084       "      %EnableAccessChecks(obj);"
   4085       "      expected = undefined;"
   4086       "    }"
   4087       "    var v = obj[i];"
   4088       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
   4089       "    if (i == 5) %DisableAccessChecks(obj);"
   4090       "  }"
   4091       "  'PASSED'"
   4092       "} catch(e) {"
   4093       "  e"
   4094       "}";
   4095   ExpectString(code, "PASSED");
   4096 }
   4097 
   4098 
   4099 THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
   4100   v8::HandleScope scope;
   4101   Local<ObjectTemplate> templ = ObjectTemplate::New();
   4102   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
   4103 
   4104   LocalContext context;
   4105   Local<v8::Object> obj = templ->NewInstance();
   4106   context->Global()->Set(v8_str("obj"), obj);
   4107 
   4108   const char* code =
   4109       "try {"
   4110       "  for (var i = 0; i < 100; i++) {"
   4111       "    var v = obj[i];"
   4112       "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
   4113       "  }"
   4114       "  'PASSED'"
   4115       "} catch(e) {"
   4116       "  e"
   4117       "}";
   4118   ExpectString(code, "PASSED");
   4119 }
   4120 
   4121 
   4122 THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
   4123   v8::HandleScope scope;
   4124   Local<ObjectTemplate> templ = ObjectTemplate::New();
   4125   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
   4126 
   4127   LocalContext context;
   4128   Local<v8::Object> obj = templ->NewInstance();
   4129   context->Global()->Set(v8_str("obj"), obj);
   4130 
   4131   const char* code =
   4132       "try {"
   4133       "  for (var i = 0; i < 100; i++) {"
   4134       "    var expected = i;"
   4135       "    var key = i;"
   4136       "    if (i == 25) {"
   4137       "       key = -1;"
   4138       "       expected = undefined;"
   4139       "    }"
   4140       "    if (i == 50) {"
   4141       "       /* probe minimal Smi number on 32-bit platforms */"
   4142       "       key = -(1 << 30);"
   4143       "       expected = undefined;"
   4144       "    }"
   4145       "    if (i == 75) {"
   4146       "       /* probe minimal Smi number on 64-bit platforms */"
   4147       "       key = 1 << 31;"
   4148       "       expected = undefined;"
   4149       "    }"
   4150       "    var v = obj[key];"
   4151       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
   4152       "  }"
   4153       "  'PASSED'"
   4154       "} catch(e) {"
   4155       "  e"
   4156       "}";
   4157   ExpectString(code, "PASSED");
   4158 }
   4159 
   4160 
   4161 THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
   4162   v8::HandleScope scope;
   4163   Local<ObjectTemplate> templ = ObjectTemplate::New();
   4164   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
   4165 
   4166   LocalContext context;
   4167   Local<v8::Object> obj = templ->NewInstance();
   4168   context->Global()->Set(v8_str("obj"), obj);
   4169 
   4170   const char* code =
   4171       "try {"
   4172       "  for (var i = 0; i < 100; i++) {"
   4173       "    var expected = i;"
   4174       "    var key = i;"
   4175       "    if (i == 50) {"
   4176       "       key = 'foobar';"
   4177       "       expected = undefined;"
   4178       "    }"
   4179       "    var v = obj[key];"
   4180       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
   4181       "  }"
   4182       "  'PASSED'"
   4183       "} catch(e) {"
   4184       "  e"
   4185       "}";
   4186   ExpectString(code, "PASSED");
   4187 }
   4188 
   4189 
   4190 THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
   4191   v8::HandleScope scope;
   4192   Local<ObjectTemplate> templ = ObjectTemplate::New();
   4193   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
   4194 
   4195   LocalContext context;
   4196   Local<v8::Object> obj = templ->NewInstance();
   4197   context->Global()->Set(v8_str("obj"), obj);
   4198 
   4199   const char* code =
   4200       "var original = obj;"
   4201       "try {"
   4202       "  for (var i = 0; i < 100; i++) {"
   4203       "    var expected = i;"
   4204       "    if (i == 50) {"
   4205       "       obj = {50: 'foobar'};"
   4206       "       expected = 'foobar';"
   4207       "    }"
   4208       "    var v = obj[i];"
   4209       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
   4210       "    if (i == 50) obj = original;"
   4211       "  }"
   4212       "  'PASSED'"
   4213       "} catch(e) {"
   4214       "  e"
   4215       "}";
   4216   ExpectString(code, "PASSED");
   4217 }
   4218 
   4219 
   4220 THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
   4221   v8::HandleScope scope;
   4222   Local<ObjectTemplate> templ = ObjectTemplate::New();
   4223   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
   4224 
   4225   LocalContext context;
   4226   Local<v8::Object> obj = templ->NewInstance();
   4227   context->Global()->Set(v8_str("obj"), obj);
   4228 
   4229   const char* code =
   4230       "var original = obj;"
   4231       "try {"
   4232       "  for (var i = 0; i < 100; i++) {"
   4233       "    var expected = i;"
   4234       "    if (i == 5) {"
   4235       "       obj = 239;"
   4236       "       expected = undefined;"
   4237       "    }"
   4238       "    var v = obj[i];"
   4239       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
   4240       "    if (i == 5) obj = original;"
   4241       "  }"
   4242       "  'PASSED'"
   4243       "} catch(e) {"
   4244       "  e"
   4245       "}";
   4246   ExpectString(code, "PASSED");
   4247 }
   4248 
   4249 
   4250 THREADED_TEST(IndexedInterceptorOnProto) {
   4251   v8::HandleScope scope;
   4252   Local<ObjectTemplate> templ = ObjectTemplate::New();
   4253   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
   4254 
   4255   LocalContext context;
   4256   Local<v8::Object> obj = templ->NewInstance();
   4257   context->Global()->Set(v8_str("obj"), obj);
   4258 
   4259   const char* code =
   4260       "var o = {__proto__: obj};"
   4261       "try {"
   4262       "  for (var i = 0; i < 100; i++) {"
   4263       "    var v = o[i];"
   4264       "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
   4265       "  }"
   4266       "  'PASSED'"
   4267       "} catch(e) {"
   4268       "  e"
   4269       "}";
   4270   ExpectString(code, "PASSED");
   4271 }
   4272 
   4273 
   4274 THREADED_TEST(MultiContexts) {
   4275   v8::HandleScope scope;
   4276   v8::Handle<ObjectTemplate> templ = ObjectTemplate::New();
   4277   templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(DummyCallHandler));
   4278 
   4279   Local<String> password = v8_str("Password");
   4280 
   4281   // Create an environment
   4282   LocalContext context0(0, templ);
   4283   context0->SetSecurityToken(password);
   4284   v8::Handle<v8::Object> global0 = context0->Global();
   4285   global0->Set(v8_str("custom"), v8_num(1234));
   4286   CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
   4287 
   4288   // Create an independent environment
   4289   LocalContext context1(0, templ);
   4290   context1->SetSecurityToken(password);
   4291   v8::Handle<v8::Object> global1 = context1->Global();
   4292   global1->Set(v8_str("custom"), v8_num(1234));
   4293   CHECK_NE(global0, global1);
   4294   CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
   4295   CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
   4296 
   4297   // Now create a new context with the old global
   4298   LocalContext context2(0, templ, global1);
   4299   context2->SetSecurityToken(password);
   4300   v8::Handle<v8::Object> global2 = context2->Global();
   4301   CHECK_EQ(global1, global2);
   4302   CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
   4303   CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
   4304 }
   4305 
   4306 
   4307 THREADED_TEST(FunctionPrototypeAcrossContexts) {
   4308   // Make sure that functions created by cloning boilerplates cannot
   4309   // communicate through their __proto__ field.
   4310 
   4311   v8::HandleScope scope;
   4312 
   4313   LocalContext env0;
   4314   v8::Handle<v8::Object> global0 =
   4315       env0->Global();
   4316   v8::Handle<v8::Object> object0 =
   4317       global0->Get(v8_str("Object")).As<v8::Object>();
   4318   v8::Handle<v8::Object> tostring0 =
   4319       object0->Get(v8_str("toString")).As<v8::Object>();
   4320   v8::Handle<v8::Object> proto0 =
   4321       tostring0->Get(v8_str("__proto__")).As<v8::Object>();
   4322   proto0->Set(v8_str("custom"), v8_num(1234));
   4323 
   4324   LocalContext env1;
   4325   v8::Handle<v8::Object> global1 =
   4326       env1->Global();
   4327   v8::Handle<v8::Object> object1 =
   4328       global1->Get(v8_str("Object")).As<v8::Object>();
   4329   v8::Handle<v8::Object> tostring1 =
   4330       object1->Get(v8_str("toString")).As<v8::Object>();
   4331   v8::Handle<v8::Object> proto1 =
   4332       tostring1->Get(v8_str("__proto__")).As<v8::Object>();
   4333   CHECK(!proto1->Has(v8_str("custom")));
   4334 }
   4335 
   4336 
   4337 THREADED_TEST(Regress892105) {
   4338   // Make sure that object and array literals created by cloning
   4339   // boilerplates cannot communicate through their __proto__
   4340   // field. This is rather difficult to check, but we try to add stuff
   4341   // to Object.prototype and Array.prototype and create a new
   4342   // environment. This should succeed.
   4343 
   4344   v8::HandleScope scope;
   4345 
   4346   Local<String> source = v8_str("Object.prototype.obj = 1234;"
   4347                                 "Array.prototype.arr = 4567;"
   4348                                 "8901");
   4349 
   4350   LocalContext env0;
   4351   Local<Script> script0 = Script::Compile(source);
   4352   CHECK_EQ(8901.0, script0->Run()->NumberValue());
   4353 
   4354   LocalContext env1;
   4355   Local<Script> script1 = Script::Compile(source);
   4356   CHECK_EQ(8901.0, script1->Run()->NumberValue());
   4357 }
   4358 
   4359 
   4360 THREADED_TEST(UndetectableObject) {
   4361   v8::HandleScope scope;
   4362   LocalContext env;
   4363 
   4364   Local<v8::FunctionTemplate> desc =
   4365       v8::FunctionTemplate::New(0, v8::Handle<Value>());
   4366   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
   4367 
   4368   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
   4369   env->Global()->Set(v8_str("undetectable"), obj);
   4370 
   4371   ExpectString("undetectable.toString()", "[object Object]");
   4372   ExpectString("typeof undetectable", "undefined");
   4373   ExpectString("typeof(undetectable)", "undefined");
   4374   ExpectBoolean("typeof undetectable == 'undefined'", true);
   4375   ExpectBoolean("typeof undetectable == 'object'", false);
   4376   ExpectBoolean("if (undetectable) { true; } else { false; }", false);
   4377   ExpectBoolean("!undetectable", true);
   4378 
   4379   ExpectObject("true&&undetectable", obj);
   4380   ExpectBoolean("false&&undetectable", false);
   4381   ExpectBoolean("true||undetectable", true);
   4382   ExpectObject("false||undetectable", obj);
   4383 
   4384   ExpectObject("undetectable&&true", obj);
   4385   ExpectObject("undetectable&&false", obj);
   4386   ExpectBoolean("undetectable||true", true);
   4387   ExpectBoolean("undetectable||false", false);
   4388 
   4389   ExpectBoolean("undetectable==null", true);
   4390   ExpectBoolean("null==undetectable", true);
   4391   ExpectBoolean("undetectable==undefined", true);
   4392   ExpectBoolean("undefined==undetectable", true);
   4393   ExpectBoolean("undetectable==undetectable", true);
   4394 
   4395 
   4396   ExpectBoolean("undetectable===null", false);
   4397   ExpectBoolean("null===undetectable", false);
   4398   ExpectBoolean("undetectable===undefined", false);
   4399   ExpectBoolean("undefined===undetectable", false);
   4400   ExpectBoolean("undetectable===undetectable", true);
   4401 }
   4402 
   4403 
   4404 THREADED_TEST(VoidLiteral) {
   4405   v8::HandleScope scope;
   4406   LocalContext env;
   4407 
   4408   Local<v8::FunctionTemplate> desc =
   4409       v8::FunctionTemplate::New(0, v8::Handle<Value>());
   4410   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
   4411 
   4412   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
   4413   env->Global()->Set(v8_str("undetectable"), obj);
   4414 
   4415   ExpectBoolean("undefined == void 0", true);
   4416   ExpectBoolean("undetectable == void 0", true);
   4417   ExpectBoolean("null == void 0", true);
   4418   ExpectBoolean("undefined === void 0", true);
   4419   ExpectBoolean("undetectable === void 0", false);
   4420   ExpectBoolean("null === void 0", false);
   4421 
   4422   ExpectBoolean("void 0 == undefined", true);
   4423   ExpectBoolean("void 0 == undetectable", true);
   4424   ExpectBoolean("void 0 == null", true);
   4425   ExpectBoolean("void 0 === undefined", true);
   4426   ExpectBoolean("void 0 === undetectable", false);
   4427   ExpectBoolean("void 0 === null", false);
   4428 
   4429   ExpectString("(function() {"
   4430                "  try {"
   4431                "    return x === void 0;"
   4432                "  } catch(e) {"
   4433                "    return e.toString();"
   4434                "  }"
   4435                "})()",
   4436                "ReferenceError: x is not defined");
   4437   ExpectString("(function() {"
   4438                "  try {"
   4439                "    return void 0 === x;"
   4440                "  } catch(e) {"
   4441                "    return e.toString();"
   4442                "  }"
   4443                "})()",
   4444                "ReferenceError: x is not defined");
   4445 }
   4446 
   4447 
   4448 THREADED_TEST(ExtensibleOnUndetectable) {
   4449   v8::HandleScope scope;
   4450   LocalContext env;
   4451 
   4452   Local<v8::FunctionTemplate> desc =
   4453       v8::FunctionTemplate::New(0, v8::Handle<Value>());
   4454   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
   4455 
   4456   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
   4457   env->Global()->Set(v8_str("undetectable"), obj);
   4458 
   4459   Local<String> source = v8_str("undetectable.x = 42;"
   4460                                 "undetectable.x");
   4461 
   4462   Local<Script> script = Script::Compile(source);
   4463 
   4464   CHECK_EQ(v8::Integer::New(42), script->Run());
   4465 
   4466   ExpectBoolean("Object.isExtensible(undetectable)", true);
   4467 
   4468   source = v8_str("Object.preventExtensions(undetectable);");
   4469   script = Script::Compile(source);
   4470   script->Run();
   4471   ExpectBoolean("Object.isExtensible(undetectable)", false);
   4472 
   4473   source = v8_str("undetectable.y = 2000;");
   4474   script = Script::Compile(source);
   4475   script->Run();
   4476   ExpectBoolean("undetectable.y == undefined", true);
   4477 }
   4478 
   4479 
   4480 
   4481 THREADED_TEST(UndetectableString) {
   4482   v8::HandleScope scope;
   4483   LocalContext env;
   4484 
   4485   Local<String> obj = String::NewUndetectable("foo");
   4486   env->Global()->Set(v8_str("undetectable"), obj);
   4487 
   4488   ExpectString("undetectable", "foo");
   4489   ExpectString("typeof undetectable", "undefined");
   4490   ExpectString("typeof(undetectable)", "undefined");
   4491   ExpectBoolean("typeof undetectable == 'undefined'", true);
   4492   ExpectBoolean("typeof undetectable == 'string'", false);
   4493   ExpectBoolean("if (undetectable) { true; } else { false; }", false);
   4494   ExpectBoolean("!undetectable", true);
   4495 
   4496   ExpectObject("true&&undetectable", obj);
   4497   ExpectBoolean("false&&undetectable", false);
   4498   ExpectBoolean("true||undetectable", true);
   4499   ExpectObject("false||undetectable", obj);
   4500 
   4501   ExpectObject("undetectable&&true", obj);
   4502   ExpectObject("undetectable&&false", obj);
   4503   ExpectBoolean("undetectable||true", true);
   4504   ExpectBoolean("undetectable||false", false);
   4505 
   4506   ExpectBoolean("undetectable==null", true);
   4507   ExpectBoolean("null==undetectable", true);
   4508   ExpectBoolean("undetectable==undefined", true);
   4509   ExpectBoolean("undefined==undetectable", true);
   4510   ExpectBoolean("undetectable==undetectable", true);
   4511 
   4512 
   4513   ExpectBoolean("undetectable===null", false);
   4514   ExpectBoolean("null===undetectable", false);
   4515   ExpectBoolean("undetectable===undefined", false);
   4516   ExpectBoolean("undefined===undetectable", false);
   4517   ExpectBoolean("undetectable===undetectable", true);
   4518 }
   4519 
   4520 
   4521 TEST(UndetectableOptimized) {
   4522   i::FLAG_allow_natives_syntax = true;
   4523   v8::HandleScope scope;
   4524   LocalContext env;
   4525 
   4526   Local<String> obj = String::NewUndetectable("foo");
   4527   env->Global()->Set(v8_str("undetectable"), obj);
   4528   env->Global()->Set(v8_str("detectable"), v8_str("bar"));
   4529 
   4530   ExpectString(
   4531       "function testBranch() {"
   4532       "  if (!%_IsUndetectableObject(undetectable)) throw 1;"
   4533       "  if (%_IsUndetectableObject(detectable)) throw 2;"
   4534       "}\n"
   4535       "function testBool() {"
   4536       "  var b1 = !%_IsUndetectableObject(undetectable);"
   4537       "  var b2 = %_IsUndetectableObject(detectable);"
   4538       "  if (b1) throw 3;"
   4539       "  if (b2) throw 4;"
   4540       "  return b1 == b2;"
   4541       "}\n"
   4542       "%OptimizeFunctionOnNextCall(testBranch);"
   4543       "%OptimizeFunctionOnNextCall(testBool);"
   4544       "for (var i = 0; i < 10; i++) {"
   4545       "  testBranch();"
   4546       "  testBool();"
   4547       "}\n"
   4548       "\"PASS\"",
   4549       "PASS");
   4550 }
   4551 
   4552 
   4553 template <typename T> static void USE(T) { }
   4554 
   4555 
   4556 // This test is not intended to be run, just type checked.
   4557 static inline void PersistentHandles() {
   4558   USE(PersistentHandles);
   4559   Local<String> str = v8_str("foo");
   4560   v8::Persistent<String> p_str = v8::Persistent<String>::New(str);
   4561   USE(p_str);
   4562   Local<Script> scr = Script::Compile(v8_str(""));
   4563   v8::Persistent<Script> p_scr = v8::Persistent<Script>::New(scr);
   4564   USE(p_scr);
   4565   Local<ObjectTemplate> templ = ObjectTemplate::New();
   4566   v8::Persistent<ObjectTemplate> p_templ =
   4567     v8::Persistent<ObjectTemplate>::New(templ);
   4568   USE(p_templ);
   4569 }
   4570 
   4571 
   4572 static v8::Handle<Value> HandleLogDelegator(const v8::Arguments& args) {
   4573   ApiTestFuzzer::Fuzz();
   4574   return v8::Undefined();
   4575 }
   4576 
   4577 
   4578 THREADED_TEST(GlobalObjectTemplate) {
   4579   v8::HandleScope handle_scope;
   4580   Local<ObjectTemplate> global_template = ObjectTemplate::New();
   4581   global_template->Set(v8_str("JSNI_Log"),
   4582                        v8::FunctionTemplate::New(HandleLogDelegator));
   4583   v8::Persistent<Context> context = Context::New(0, global_template);
   4584   Context::Scope context_scope(context);
   4585   Script::Compile(v8_str("JSNI_Log('LOG')"))->Run();
   4586   context.Dispose();
   4587 }
   4588 
   4589 
   4590 static const char* kSimpleExtensionSource =
   4591   "function Foo() {"
   4592   "  return 4;"
   4593   "}";
   4594 
   4595 
   4596 THREADED_TEST(SimpleExtensions) {
   4597   v8::HandleScope handle_scope;
   4598   v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
   4599   const char* extension_names[] = { "simpletest" };
   4600   v8::ExtensionConfiguration extensions(1, extension_names);
   4601   v8::Handle<Context> context = Context::New(&extensions);
   4602   Context::Scope lock(context);
   4603   v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
   4604   CHECK_EQ(result, v8::Integer::New(4));
   4605 }
   4606 
   4607 
   4608 static const char* kEmbeddedExtensionSource =
   4609     "function Ret54321(){return 54321;}~~@@$"
   4610     "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS.";
   4611 static const int kEmbeddedExtensionSourceValidLen = 34;
   4612 
   4613 
   4614 THREADED_TEST(ExtensionMissingSourceLength) {
   4615   v8::HandleScope handle_scope;
   4616   v8::RegisterExtension(new Extension("srclentest_fail",
   4617                                       kEmbeddedExtensionSource));
   4618   const char* extension_names[] = { "srclentest_fail" };
   4619   v8::ExtensionConfiguration extensions(1, extension_names);
   4620   v8::Handle<Context> context = Context::New(&extensions);
   4621   CHECK_EQ(0, *context);
   4622 }
   4623 
   4624 
   4625 THREADED_TEST(ExtensionWithSourceLength) {
   4626   for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
   4627        source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
   4628     v8::HandleScope handle_scope;
   4629     i::ScopedVector<char> extension_name(32);
   4630     i::OS::SNPrintF(extension_name, "ext #%d", source_len);
   4631     v8::RegisterExtension(new Extension(extension_name.start(),
   4632                                         kEmbeddedExtensionSource, 0, 0,
   4633                                         source_len));
   4634     const char* extension_names[1] = { extension_name.start() };
   4635     v8::ExtensionConfiguration extensions(1, extension_names);
   4636     v8::Handle<Context> context = Context::New(&extensions);
   4637     if (source_len == kEmbeddedExtensionSourceValidLen) {
   4638       Context::Scope lock(context);
   4639       v8::Handle<Value> result = Script::Compile(v8_str("Ret54321()"))->Run();
   4640       CHECK_EQ(v8::Integer::New(54321), result);
   4641     } else {
   4642       // Anything but exactly the right length should fail to compile.
   4643       CHECK_EQ(0, *context);
   4644     }
   4645   }
   4646 }
   4647 
   4648 
   4649 static const char* kEvalExtensionSource1 =
   4650   "function UseEval1() {"
   4651   "  var x = 42;"
   4652   "  return eval('x');"
   4653   "}";
   4654 
   4655 
   4656 static const char* kEvalExtensionSource2 =
   4657   "(function() {"
   4658   "  var x = 42;"
   4659   "  function e() {"
   4660   "    return eval('x');"
   4661   "  }"
   4662   "  this.UseEval2 = e;"
   4663   "})()";
   4664 
   4665 
   4666 THREADED_TEST(UseEvalFromExtension) {
   4667   v8::HandleScope handle_scope;
   4668   v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
   4669   v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
   4670   const char* extension_names[] = { "evaltest1", "evaltest2" };
   4671   v8::ExtensionConfiguration extensions(2, extension_names);
   4672   v8::Handle<Context> context = Context::New(&extensions);
   4673   Context::Scope lock(context);
   4674   v8::Handle<Value> result = Script::Compile(v8_str("UseEval1()"))->Run();
   4675   CHECK_EQ(result, v8::Integer::New(42));
   4676   result = Script::Compile(v8_str("UseEval2()"))->Run();
   4677   CHECK_EQ(result, v8::Integer::New(42));
   4678 }
   4679 
   4680 
   4681 static const char* kWithExtensionSource1 =
   4682   "function UseWith1() {"
   4683   "  var x = 42;"
   4684   "  with({x:87}) { return x; }"
   4685   "}";
   4686 
   4687 
   4688 
   4689 static const char* kWithExtensionSource2 =
   4690   "(function() {"
   4691   "  var x = 42;"
   4692   "  function e() {"
   4693   "    with ({x:87}) { return x; }"
   4694   "  }"
   4695   "  this.UseWith2 = e;"
   4696   "})()";
   4697 
   4698 
   4699 THREADED_TEST(UseWithFromExtension) {
   4700   v8::HandleScope handle_scope;
   4701   v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
   4702   v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
   4703   const char* extension_names[] = { "withtest1", "withtest2" };
   4704   v8::ExtensionConfiguration extensions(2, extension_names);
   4705   v8::Handle<Context> context = Context::New(&extensions);
   4706   Context::Scope lock(context);
   4707   v8::Handle<Value> result = Script::Compile(v8_str("UseWith1()"))->Run();
   4708   CHECK_EQ(result, v8::Integer::New(87));
   4709   result = Script::Compile(v8_str("UseWith2()"))->Run();
   4710   CHECK_EQ(result, v8::Integer::New(87));
   4711 }
   4712 
   4713 
   4714 THREADED_TEST(AutoExtensions) {
   4715   v8::HandleScope handle_scope;
   4716   Extension* extension = new Extension("autotest", kSimpleExtensionSource);
   4717   extension->set_auto_enable(true);
   4718   v8::RegisterExtension(extension);
   4719   v8::Handle<Context> context = Context::New();
   4720   Context::Scope lock(context);
   4721   v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
   4722   CHECK_EQ(result, v8::Integer::New(4));
   4723 }
   4724 
   4725 
   4726 static const char* kSyntaxErrorInExtensionSource =
   4727     "[";
   4728 
   4729 
   4730 // Test that a syntax error in an extension does not cause a fatal
   4731 // error but results in an empty context.
   4732 THREADED_TEST(SyntaxErrorExtensions) {
   4733   v8::HandleScope handle_scope;
   4734   v8::RegisterExtension(new Extension("syntaxerror",
   4735                                       kSyntaxErrorInExtensionSource));
   4736   const char* extension_names[] = { "syntaxerror" };
   4737   v8::ExtensionConfiguration extensions(1, extension_names);
   4738   v8::Handle<Context> context = Context::New(&extensions);
   4739   CHECK(context.IsEmpty());
   4740 }
   4741 
   4742 
   4743 static const char* kExceptionInExtensionSource =
   4744     "throw 42";
   4745 
   4746 
   4747 // Test that an exception when installing an extension does not cause
   4748 // a fatal error but results in an empty context.
   4749 THREADED_TEST(ExceptionExtensions) {
   4750   v8::HandleScope handle_scope;
   4751   v8::RegisterExtension(new Extension("exception",
   4752                                       kExceptionInExtensionSource));
   4753   const char* extension_names[] = { "exception" };
   4754   v8::ExtensionConfiguration extensions(1, extension_names);
   4755   v8::Handle<Context> context = Context::New(&extensions);
   4756   CHECK(context.IsEmpty());
   4757 }
   4758 
   4759 
   4760 static const char* kNativeCallInExtensionSource =
   4761     "function call_runtime_last_index_of(x) {"
   4762     "  return %StringLastIndexOf(x, 'bob', 10);"
   4763     "}";
   4764 
   4765 
   4766 static const char* kNativeCallTest =
   4767     "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
   4768 
   4769 // Test that a native runtime calls are supported in extensions.
   4770 THREADED_TEST(NativeCallInExtensions) {
   4771   v8::HandleScope handle_scope;
   4772   v8::RegisterExtension(new Extension("nativecall",
   4773                                       kNativeCallInExtensionSource));
   4774   const char* extension_names[] = { "nativecall" };
   4775   v8::ExtensionConfiguration extensions(1, extension_names);
   4776   v8::Handle<Context> context = Context::New(&extensions);
   4777   Context::Scope lock(context);
   4778   v8::Handle<Value> result = Script::Compile(v8_str(kNativeCallTest))->Run();
   4779   CHECK_EQ(result, v8::Integer::New(3));
   4780 }
   4781 
   4782 
   4783 class NativeFunctionExtension : public Extension {
   4784  public:
   4785   NativeFunctionExtension(const char* name,
   4786                           const char* source,
   4787                           v8::InvocationCallback fun = &Echo)
   4788       : Extension(name, source),
   4789         function_(fun) { }
   4790 
   4791   virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
   4792       v8::Handle<v8::String> name) {
   4793     return v8::FunctionTemplate::New(function_);
   4794   }
   4795 
   4796   static v8::Handle<v8::Value> Echo(const v8::Arguments& args) {
   4797     if (args.Length() >= 1) return (args[0]);
   4798     return v8::Undefined();
   4799   }
   4800  private:
   4801   v8::InvocationCallback function_;
   4802 };
   4803 
   4804 
   4805 THREADED_TEST(NativeFunctionDeclaration) {
   4806   v8::HandleScope handle_scope;
   4807   const char* name = "nativedecl";
   4808   v8::RegisterExtension(new NativeFunctionExtension(name,
   4809                                                     "native function foo();"));
   4810   const char* extension_names[] = { name };
   4811   v8::ExtensionConfiguration extensions(1, extension_names);
   4812   v8::Handle<Context> context = Context::New(&extensions);
   4813   Context::Scope lock(context);
   4814   v8::Handle<Value> result = Script::Compile(v8_str("foo(42);"))->Run();
   4815   CHECK_EQ(result, v8::Integer::New(42));
   4816 }
   4817 
   4818 
   4819 THREADED_TEST(NativeFunctionDeclarationError) {
   4820   v8::HandleScope handle_scope;
   4821   const char* name = "nativedeclerr";
   4822   // Syntax error in extension code.
   4823   v8::RegisterExtension(new NativeFunctionExtension(name,
   4824                                                     "native\nfunction foo();"));
   4825   const char* extension_names[] = { name };
   4826   v8::ExtensionConfiguration extensions(1, extension_names);
   4827   v8::Handle<Context> context(Context::New(&extensions));
   4828   CHECK(context.IsEmpty());
   4829 }
   4830 
   4831 
   4832 THREADED_TEST(NativeFunctionDeclarationErrorEscape) {
   4833   v8::HandleScope handle_scope;
   4834   const char* name = "nativedeclerresc";
   4835   // Syntax error in extension code - escape code in "native" means that
   4836   // it's not treated as a keyword.
   4837   v8::RegisterExtension(new NativeFunctionExtension(
   4838       name,
   4839       "nativ\\u0065 function foo();"));
   4840   const char* extension_names[] = { name };
   4841   v8::ExtensionConfiguration extensions(1, extension_names);
   4842   v8::Handle<Context> context(Context::New(&extensions));
   4843   CHECK(context.IsEmpty());
   4844 }
   4845 
   4846 
   4847 static void CheckDependencies(const char* name, const char* expected) {
   4848   v8::HandleScope handle_scope;
   4849   v8::ExtensionConfiguration config(1, &name);
   4850   LocalContext context(&config);
   4851   CHECK_EQ(String::New(expected), context->Global()->Get(v8_str("loaded")));
   4852 }
   4853 
   4854 
   4855 /*
   4856  * Configuration:
   4857  *
   4858  *     /-- B <--\
   4859  * A <-          -- D <-- E
   4860  *     \-- C <--/
   4861  */
   4862 THREADED_TEST(ExtensionDependency) {
   4863   static const char* kEDeps[] = { "D" };
   4864   v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
   4865   static const char* kDDeps[] = { "B", "C" };
   4866   v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
   4867   static const char* kBCDeps[] = { "A" };
   4868   v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
   4869   v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
   4870   v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
   4871   CheckDependencies("A", "undefinedA");
   4872   CheckDependencies("B", "undefinedAB");
   4873   CheckDependencies("C", "undefinedAC");
   4874   CheckDependencies("D", "undefinedABCD");
   4875   CheckDependencies("E", "undefinedABCDE");
   4876   v8::HandleScope handle_scope;
   4877   static const char* exts[2] = { "C", "E" };
   4878   v8::ExtensionConfiguration config(2, exts);
   4879   LocalContext context(&config);
   4880   CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
   4881 }
   4882 
   4883 
   4884 static const char* kExtensionTestScript =
   4885   "native function A();"
   4886   "native function B();"
   4887   "native function C();"
   4888   "function Foo(i) {"
   4889   "  if (i == 0) return A();"
   4890   "  if (i == 1) return B();"
   4891   "  if (i == 2) return C();"
   4892   "}";
   4893 
   4894 
   4895 static v8::Handle<Value> CallFun(const v8::Arguments& args) {
   4896   ApiTestFuzzer::Fuzz();
   4897   if (args.IsConstructCall()) {
   4898     args.This()->Set(v8_str("data"), args.Data());
   4899     return v8::Null();
   4900   }
   4901   return args.Data();
   4902 }
   4903 
   4904 
   4905 class FunctionExtension : public Extension {
   4906  public:
   4907   FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
   4908   virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
   4909       v8::Handle<String> name);
   4910 };
   4911 
   4912 
   4913 static int lookup_count = 0;
   4914 v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunction(
   4915       v8::Handle<String> name) {
   4916   lookup_count++;
   4917   if (name->Equals(v8_str("A"))) {
   4918     return v8::FunctionTemplate::New(CallFun, v8::Integer::New(8));
   4919   } else if (name->Equals(v8_str("B"))) {
   4920     return v8::FunctionTemplate::New(CallFun, v8::Integer::New(7));
   4921   } else if (name->Equals(v8_str("C"))) {
   4922     return v8::FunctionTemplate::New(CallFun, v8::Integer::New(6));
   4923   } else {
   4924     return v8::Handle<v8::FunctionTemplate>();
   4925   }
   4926 }
   4927 
   4928 
   4929 THREADED_TEST(FunctionLookup) {
   4930   v8::RegisterExtension(new FunctionExtension());
   4931   v8::HandleScope handle_scope;
   4932   static const char* exts[1] = { "functiontest" };
   4933   v8::ExtensionConfiguration config(1, exts);
   4934   LocalContext context(&config);
   4935   CHECK_EQ(3, lookup_count);
   4936   CHECK_EQ(v8::Integer::New(8), Script::Compile(v8_str("Foo(0)"))->Run());
   4937   CHECK_EQ(v8::Integer::New(7), Script::Compile(v8_str("Foo(1)"))->Run());
   4938   CHECK_EQ(v8::Integer::New(6), Script::Compile(v8_str("Foo(2)"))->Run());
   4939 }
   4940 
   4941 
   4942 THREADED_TEST(NativeFunctionConstructCall) {
   4943   v8::RegisterExtension(new FunctionExtension());
   4944   v8::HandleScope handle_scope;
   4945   static const char* exts[1] = { "functiontest" };
   4946   v8::ExtensionConfiguration config(1, exts);
   4947   LocalContext context(&config);
   4948   for (int i = 0; i < 10; i++) {
   4949     // Run a few times to ensure that allocation of objects doesn't
   4950     // change behavior of a constructor function.
   4951     CHECK_EQ(v8::Integer::New(8),
   4952              Script::Compile(v8_str("(new A()).data"))->Run());
   4953     CHECK_EQ(v8::Integer::New(7),
   4954              Script::Compile(v8_str("(new B()).data"))->Run());
   4955     CHECK_EQ(v8::Integer::New(6),
   4956              Script::Compile(v8_str("(new C()).data"))->Run());
   4957   }
   4958 }
   4959 
   4960 
   4961 static const char* last_location;
   4962 static const char* last_message;
   4963 void StoringErrorCallback(const char* location, const char* message) {
   4964   if (last_location == NULL) {
   4965     last_location = location;
   4966     last_message = message;
   4967   }
   4968 }
   4969 
   4970 
   4971 // ErrorReporting creates a circular extensions configuration and
   4972 // tests that the fatal error handler gets called.  This renders V8
   4973 // unusable and therefore this test cannot be run in parallel.
   4974 TEST(ErrorReporting) {
   4975   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
   4976   static const char* aDeps[] = { "B" };
   4977   v8::RegisterExtension(new Extension("A", "", 1, aDeps));
   4978   static const char* bDeps[] = { "A" };
   4979   v8::RegisterExtension(new Extension("B", "", 1, bDeps));
   4980   last_location = NULL;
   4981   v8::ExtensionConfiguration config(1, bDeps);
   4982   v8::Handle<Context> context = Context::New(&config);
   4983   CHECK(context.IsEmpty());
   4984   CHECK_NE(last_location, NULL);
   4985 }
   4986 
   4987 
   4988 static const char* js_code_causing_huge_string_flattening =
   4989     "var str = 'X';"
   4990     "for (var i = 0; i < 30; i++) {"
   4991     "  str = str + str;"
   4992     "}"
   4993     "str.match(/X/);";
   4994 
   4995 
   4996 void OOMCallback(const char* location, const char* message) {
   4997   exit(0);
   4998 }
   4999 
   5000 
   5001 TEST(RegexpOutOfMemory) {
   5002   // Execute a script that causes out of memory when flattening a string.
   5003   v8::HandleScope scope;
   5004   v8::V8::SetFatalErrorHandler(OOMCallback);
   5005   LocalContext context;
   5006   Local<Script> script =
   5007       Script::Compile(String::New(js_code_causing_huge_string_flattening));
   5008   last_location = NULL;
   5009   script->Run();
   5010 
   5011   CHECK(false);  // Should not return.
   5012 }
   5013 
   5014 
   5015 static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
   5016                                              v8::Handle<Value> data) {
   5017   CHECK_EQ(v8::Undefined(), data);
   5018   CHECK(message->GetScriptResourceName()->IsUndefined());
   5019   CHECK_EQ(v8::Undefined(), message->GetScriptResourceName());
   5020   message->GetLineNumber();
   5021   message->GetSourceLine();
   5022 }
   5023 
   5024 
   5025 THREADED_TEST(ErrorWithMissingScriptInfo) {
   5026   v8::HandleScope scope;
   5027   LocalContext context;
   5028   v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
   5029   Script::Compile(v8_str("throw Error()"))->Run();
   5030   v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
   5031 }
   5032 
   5033 
   5034 int global_index = 0;
   5035 
   5036 class Snorkel {
   5037  public:
   5038   Snorkel() { index_ = global_index++; }
   5039   int index_;
   5040 };
   5041 
   5042 class Whammy {
   5043  public:
   5044   Whammy() {
   5045     cursor_ = 0;
   5046   }
   5047   ~Whammy() {
   5048     script_.Dispose();
   5049   }
   5050   v8::Handle<Script> getScript() {
   5051     if (script_.IsEmpty())
   5052       script_ = v8::Persistent<Script>::New(v8_compile("({}).blammo"));
   5053     return Local<Script>(*script_);
   5054   }
   5055 
   5056  public:
   5057   static const int kObjectCount = 256;
   5058   int cursor_;
   5059   v8::Persistent<v8::Object> objects_[kObjectCount];
   5060   v8::Persistent<Script> script_;
   5061 };
   5062 
   5063 static void HandleWeakReference(v8::Persistent<v8::Value> obj, void* data) {
   5064   Snorkel* snorkel = reinterpret_cast<Snorkel*>(data);
   5065   delete snorkel;
   5066   obj.ClearWeak();
   5067 }
   5068 
   5069 v8::Handle<Value> WhammyPropertyGetter(Local<String> name,
   5070                                        const AccessorInfo& info) {
   5071   Whammy* whammy =
   5072     static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
   5073 
   5074   v8::Persistent<v8::Object> prev = whammy->objects_[whammy->cursor_];
   5075 
   5076   v8::Handle<v8::Object> obj = v8::Object::New();
   5077   v8::Persistent<v8::Object> global = v8::Persistent<v8::Object>::New(obj);
   5078   if (!prev.IsEmpty()) {
   5079     prev->Set(v8_str("next"), obj);
   5080     prev.MakeWeak(new Snorkel(), &HandleWeakReference);
   5081     whammy->objects_[whammy->cursor_].Clear();
   5082   }
   5083   whammy->objects_[whammy->cursor_] = global;
   5084   whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount;
   5085   return whammy->getScript()->Run();
   5086 }
   5087 
   5088 THREADED_TEST(WeakReference) {
   5089   v8::HandleScope handle_scope;
   5090   v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New();
   5091   Whammy* whammy = new Whammy();
   5092   templ->SetNamedPropertyHandler(WhammyPropertyGetter,
   5093                                  0, 0, 0, 0,
   5094                                  v8::External::New(whammy));
   5095   const char* extension_list[] = { "v8/gc" };
   5096   v8::ExtensionConfiguration extensions(1, extension_list);
   5097   v8::Persistent<Context> context = Context::New(&extensions);
   5098   Context::Scope context_scope(context);
   5099 
   5100   v8::Handle<v8::Object> interceptor = templ->NewInstance();
   5101   context->Global()->Set(v8_str("whammy"), interceptor);
   5102   const char* code =
   5103       "var last;"
   5104       "for (var i = 0; i < 10000; i++) {"
   5105       "  var obj = whammy.length;"
   5106       "  if (last) last.next = obj;"
   5107       "  last = obj;"
   5108       "}"
   5109       "gc();"
   5110       "4";
   5111   v8::Handle<Value> result = CompileRun(code);
   5112   CHECK_EQ(4.0, result->NumberValue());
   5113   delete whammy;
   5114   context.Dispose();
   5115 }
   5116 
   5117 
   5118 static void DisposeAndSetFlag(v8::Persistent<v8::Value> obj, void* data) {
   5119   obj.Dispose();
   5120   obj.Clear();
   5121   *(reinterpret_cast<bool*>(data)) = true;
   5122 }
   5123 
   5124 
   5125 THREADED_TEST(IndependentWeakHandle) {
   5126   v8::Persistent<Context> context = Context::New();
   5127   Context::Scope context_scope(context);
   5128 
   5129   v8::Persistent<v8::Object> object_a;
   5130 
   5131   {
   5132     v8::HandleScope handle_scope;
   5133     object_a = v8::Persistent<v8::Object>::New(v8::Object::New());
   5134   }
   5135 
   5136   bool object_a_disposed = false;
   5137   object_a.MakeWeak(&object_a_disposed, &DisposeAndSetFlag);
   5138   object_a.MarkIndependent();
   5139   HEAP->PerformScavenge();
   5140   CHECK(object_a_disposed);
   5141 }
   5142 
   5143 
   5144 static void InvokeScavenge() {
   5145   HEAP->PerformScavenge();
   5146 }
   5147 
   5148 
   5149 static void InvokeMarkSweep() {
   5150   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
   5151 }
   5152 
   5153 
   5154 static void ForceScavenge(v8::Persistent<v8::Value> obj, void* data) {
   5155   obj.Dispose();
   5156   obj.Clear();
   5157   *(reinterpret_cast<bool*>(data)) = true;
   5158   InvokeScavenge();
   5159 }
   5160 
   5161 
   5162 static void ForceMarkSweep(v8::Persistent<v8::Value> obj, void* data) {
   5163   obj.Dispose();
   5164   obj.Clear();
   5165   *(reinterpret_cast<bool*>(data)) = true;
   5166   InvokeMarkSweep();
   5167 }
   5168 
   5169 
   5170 THREADED_TEST(GCFromWeakCallbacks) {
   5171   v8::Persistent<Context> context = Context::New();
   5172   Context::Scope context_scope(context);
   5173 
   5174   static const int kNumberOfGCTypes = 2;
   5175   v8::WeakReferenceCallback gc_forcing_callback[kNumberOfGCTypes] =
   5176       {&ForceScavenge, &ForceMarkSweep};
   5177 
   5178   typedef void (*GCInvoker)();
   5179   GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
   5180 
   5181   for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
   5182     for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
   5183       v8::Persistent<v8::Object> object;
   5184       {
   5185         v8::HandleScope handle_scope;
   5186         object = v8::Persistent<v8::Object>::New(v8::Object::New());
   5187       }
   5188       bool disposed = false;
   5189       object.MakeWeak(&disposed, gc_forcing_callback[inner_gc]);
   5190       object.MarkIndependent();
   5191       invoke_gc[outer_gc]();
   5192       CHECK(disposed);
   5193     }
   5194   }
   5195 }
   5196 
   5197 
   5198 static void RevivingCallback(v8::Persistent<v8::Value> obj, void* data) {
   5199   obj.ClearWeak();
   5200   *(reinterpret_cast<bool*>(data)) = true;
   5201 }
   5202 
   5203 
   5204 THREADED_TEST(IndependentHandleRevival) {
   5205   v8::Persistent<Context> context = Context::New();
   5206   Context::Scope context_scope(context);
   5207 
   5208   v8::Persistent<v8::Object> object;
   5209   {
   5210     v8::HandleScope handle_scope;
   5211     object = v8::Persistent<v8::Object>::New(v8::Object::New());
   5212     object->Set(v8_str("x"), v8::Integer::New(1));
   5213     v8::Local<String> y_str = v8_str("y");
   5214     object->Set(y_str, y_str);
   5215   }
   5216   bool revived = false;
   5217   object.MakeWeak(&revived, &RevivingCallback);
   5218   object.MarkIndependent();
   5219   HEAP->PerformScavenge();
   5220   CHECK(revived);
   5221   HEAP->CollectAllGarbage(true);
   5222   {
   5223     v8::HandleScope handle_scope;
   5224     v8::Local<String> y_str = v8_str("y");
   5225     CHECK_EQ(v8::Integer::New(1), object->Get(v8_str("x")));
   5226     CHECK(object->Get(y_str)->Equals(y_str));
   5227   }
   5228 }
   5229 
   5230 
   5231 v8::Handle<Function> args_fun;
   5232 
   5233 
   5234 static v8::Handle<Value> ArgumentsTestCallback(const v8::Arguments& args) {
   5235   ApiTestFuzzer::Fuzz();
   5236   CHECK_EQ(args_fun, args.Callee());
   5237   CHECK_EQ(3, args.Length());
   5238   CHECK_EQ(v8::Integer::New(1), args[0]);
   5239   CHECK_EQ(v8::Integer::New(2), args[1]);
   5240   CHECK_EQ(v8::Integer::New(3), args[2]);
   5241   CHECK_EQ(v8::Undefined(), args[3]);
   5242   v8::HandleScope scope;
   5243   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
   5244   return v8::Undefined();
   5245 }
   5246 
   5247 
   5248 THREADED_TEST(Arguments) {
   5249   v8::HandleScope scope;
   5250   v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
   5251   global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback));
   5252   LocalContext context(NULL, global);
   5253   args_fun = context->Global()->Get(v8_str("f")).As<Function>();
   5254   v8_compile("f(1, 2, 3)")->Run();
   5255 }
   5256 
   5257 
   5258 static v8::Handle<Value> NoBlockGetterX(Local<String> name,
   5259                                         const AccessorInfo&) {
   5260   return v8::Handle<Value>();
   5261 }
   5262 
   5263 
   5264 static v8::Handle<Value> NoBlockGetterI(uint32_t index,
   5265                                         const AccessorInfo&) {
   5266   return v8::Handle<Value>();
   5267 }
   5268 
   5269 
   5270 static v8::Handle<v8::Boolean> PDeleter(Local<String> name,
   5271                                         const AccessorInfo&) {
   5272   if (!name->Equals(v8_str("foo"))) {
   5273     return v8::Handle<v8::Boolean>();  // not intercepted
   5274   }
   5275 
   5276   return v8::False();  // intercepted, and don't delete the property
   5277 }
   5278 
   5279 
   5280 static v8::Handle<v8::Boolean> IDeleter(uint32_t index, const AccessorInfo&) {
   5281   if (index != 2) {
   5282     return v8::Handle<v8::Boolean>();  // not intercepted
   5283   }
   5284 
   5285   return v8::False();  // intercepted, and don't delete the property
   5286 }
   5287 
   5288 
   5289 THREADED_TEST(Deleter) {
   5290   v8::HandleScope scope;
   5291   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
   5292   obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
   5293   obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
   5294   LocalContext context;
   5295   context->Global()->Set(v8_str("k"), obj->NewInstance());
   5296   CompileRun(
   5297     "k.foo = 'foo';"
   5298     "k.bar = 'bar';"
   5299     "k[2] = 2;"
   5300     "k[4] = 4;");
   5301   CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
   5302   CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
   5303 
   5304   CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
   5305   CHECK(v8_compile("k.bar")->Run()->IsUndefined());
   5306 
   5307   CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
   5308   CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
   5309 
   5310   CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
   5311   CHECK(v8_compile("k[4]")->Run()->IsUndefined());
   5312 }
   5313 
   5314 
   5315 static v8::Handle<Value> GetK(Local<String> name, const AccessorInfo&) {
   5316   ApiTestFuzzer::Fuzz();
   5317   if (name->Equals(v8_str("foo")) ||
   5318       name->Equals(v8_str("bar")) ||
   5319       name->Equals(v8_str("baz"))) {
   5320     return v8::Undefined();
   5321   }
   5322   return v8::Handle<Value>();
   5323 }
   5324 
   5325 
   5326 static v8::Handle<Value> IndexedGetK(uint32_t index, const AccessorInfo&) {
   5327   ApiTestFuzzer::Fuzz();
   5328   if (index == 0 || index == 1) return v8::Undefined();
   5329   return v8::Handle<Value>();
   5330 }
   5331 
   5332 
   5333 static v8::Handle<v8::Array> NamedEnum(const AccessorInfo&) {
   5334   ApiTestFuzzer::Fuzz();
   5335   v8::Handle<v8::Array> result = v8::Array::New(3);
   5336   result->Set(v8::Integer::New(0), v8_str("foo"));
   5337   result->Set(v8::Integer::New(1), v8_str("bar"));
   5338   result->Set(v8::Integer::New(2), v8_str("baz"));
   5339   return result;
   5340 }
   5341 
   5342 
   5343 static v8::Handle<v8::Array> IndexedEnum(const AccessorInfo&) {
   5344   ApiTestFuzzer::Fuzz();
   5345   v8::Handle<v8::Array> result = v8::Array::New(2);
   5346   result->Set(v8::Integer::New(0), v8_str("0"));
   5347   result->Set(v8::Integer::New(1), v8_str("1"));
   5348   return result;
   5349 }
   5350 
   5351 
   5352 THREADED_TEST(Enumerators) {
   5353   v8::HandleScope scope;
   5354   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
   5355   obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
   5356   obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
   5357   LocalContext context;
   5358   context->Global()->Set(v8_str("k"), obj->NewInstance());
   5359   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
   5360     "k[10] = 0;"
   5361     "k.a = 0;"
   5362     "k[5] = 0;"
   5363     "k.b = 0;"
   5364     "k[4294967295] = 0;"
   5365     "k.c = 0;"
   5366     "k[4294967296] = 0;"
   5367     "k.d = 0;"
   5368     "k[140000] = 0;"
   5369     "k.e = 0;"
   5370     "k[30000000000] = 0;"
   5371     "k.f = 0;"
   5372     "var result = [];"
   5373     "for (var prop in k) {"
   5374     "  result.push(prop);"
   5375     "}"
   5376     "result"));
   5377   // Check that we get all the property names returned including the
   5378   // ones from the enumerators in the right order: indexed properties
   5379   // in numerical order, indexed interceptor properties, named
   5380   // properties in insertion order, named interceptor properties.
   5381   // This order is not mandated by the spec, so this test is just
   5382   // documenting our behavior.
   5383   CHECK_EQ(17, result->Length());
   5384   // Indexed properties in numerical order.
   5385   CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(0)));
   5386   CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(1)));
   5387   CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(2)));
   5388   CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(3)));
   5389   // Indexed interceptor properties in the order they are returned
   5390   // from the enumerator interceptor.
   5391   CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(4)));
   5392   CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(5)));
   5393   // Named properties in insertion order.
   5394   CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(6)));
   5395   CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(7)));
   5396   CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(8)));
   5397   CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(9)));
   5398   CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(10)));
   5399   CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(11)));
   5400   CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(12)));
   5401   CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(13)));
   5402   // Named interceptor properties.
   5403   CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(14)));
   5404   CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(15)));
   5405   CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(16)));
   5406 }
   5407 
   5408 
   5409 int p_getter_count;
   5410 int p_getter_count2;
   5411 
   5412 
   5413 static v8::Handle<Value> PGetter(Local<String> name, const AccessorInfo& info) {
   5414   ApiTestFuzzer::Fuzz();
   5415   p_getter_count++;
   5416   v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
   5417   CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
   5418   if (name->Equals(v8_str("p1"))) {
   5419     CHECK_EQ(info.This(), global->Get(v8_str("o1")));
   5420   } else if (name->Equals(v8_str("p2"))) {
   5421     CHECK_EQ(info.This(), global->Get(v8_str("o2")));
   5422   } else if (name->Equals(v8_str("p3"))) {
   5423     CHECK_EQ(info.This(), global->Get(v8_str("o3")));
   5424   } else if (name->Equals(v8_str("p4"))) {
   5425     CHECK_EQ(info.This(), global->Get(v8_str("o4")));
   5426   }
   5427   return v8::Undefined();
   5428 }
   5429 
   5430 
   5431 static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
   5432   ApiTestFuzzer::Fuzz();
   5433   LocalContext context;
   5434   context->Global()->Set(v8_str("o1"), obj->NewInstance());
   5435   CompileRun(
   5436     "o1.__proto__ = { };"
   5437     "var o2 = { __proto__: o1 };"
   5438     "var o3 = { __proto__: o2 };"
   5439     "var o4 = { __proto__: o3 };"
   5440     "for (var i = 0; i < 10; i++) o4.p4;"
   5441     "for (var i = 0; i < 10; i++) o3.p3;"
   5442     "for (var i = 0; i < 10; i++) o2.p2;"
   5443     "for (var i = 0; i < 10; i++) o1.p1;");
   5444 }
   5445 
   5446 
   5447 static v8::Handle<Value> PGetter2(Local<String> name,
   5448                                   const AccessorInfo& info) {
   5449   ApiTestFuzzer::Fuzz();
   5450   p_getter_count2++;
   5451   v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
   5452   CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
   5453   if (name->Equals(v8_str("p1"))) {
   5454     CHECK_EQ(info.This(), global->Get(v8_str("o1")));
   5455   } else if (name->Equals(v8_str("p2"))) {
   5456     CHECK_EQ(info.This(), global->Get(v8_str("o2")));
   5457   } else if (name->Equals(v8_str("p3"))) {
   5458     CHECK_EQ(info.This(), global->Get(v8_str("o3")));
   5459   } else if (name->Equals(v8_str("p4"))) {
   5460     CHECK_EQ(info.This(), global->Get(v8_str("o4")));
   5461   }
   5462   return v8::Undefined();
   5463 }
   5464 
   5465 
   5466 THREADED_TEST(GetterHolders) {
   5467   v8::HandleScope scope;
   5468   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
   5469   obj->SetAccessor(v8_str("p1"), PGetter);
   5470   obj->SetAccessor(v8_str("p2"), PGetter);
   5471   obj->SetAccessor(v8_str("p3"), PGetter);
   5472   obj->SetAccessor(v8_str("p4"), PGetter);
   5473   p_getter_count = 0;
   5474   RunHolderTest(obj);
   5475   CHECK_EQ(40, p_getter_count);
   5476 }
   5477 
   5478 
   5479 THREADED_TEST(PreInterceptorHolders) {
   5480   v8::HandleScope scope;
   5481   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
   5482   obj->SetNamedPropertyHandler(PGetter2);
   5483   p_getter_count2 = 0;
   5484   RunHolderTest(obj);
   5485   CHECK_EQ(40, p_getter_count2);
   5486 }
   5487 
   5488 
   5489 THREADED_TEST(ObjectInstantiation) {
   5490   v8::HandleScope scope;
   5491   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
   5492   templ->SetAccessor(v8_str("t"), PGetter2);
   5493   LocalContext context;
   5494   context->Global()->Set(v8_str("o"), templ->NewInstance());
   5495   for (int i = 0; i < 100; i++) {
   5496     v8::HandleScope inner_scope;
   5497     v8::Handle<v8::Object> obj = templ->NewInstance();
   5498     CHECK_NE(obj, context->Global()->Get(v8_str("o")));
   5499     context->Global()->Set(v8_str("o2"), obj);
   5500     v8::Handle<Value> value =
   5501         Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run();
   5502     CHECK_EQ(v8::True(), value);
   5503     context->Global()->Set(v8_str("o"), obj);
   5504   }
   5505 }
   5506 
   5507 
   5508 static int StrCmp16(uint16_t* a, uint16_t* b) {
   5509   while (true) {
   5510     if (*a == 0 && *b == 0) return 0;
   5511     if (*a != *b) return 0 + *a - *b;
   5512     a++;
   5513     b++;
   5514   }
   5515 }
   5516 
   5517 
   5518 static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
   5519   while (true) {
   5520     if (n-- == 0) return 0;
   5521     if (*a == 0 && *b == 0) return 0;
   5522     if (*a != *b) return 0 + *a - *b;
   5523     a++;
   5524     b++;
   5525   }
   5526 }
   5527 
   5528 
   5529 int GetUtf8Length(Handle<String> str) {
   5530   int len = str->Utf8Length();
   5531   if (len < 0) {
   5532     i::Handle<i::String> istr(v8::Utils::OpenHandle(*str));
   5533     i::FlattenString(istr);
   5534     len = str->Utf8Length();
   5535   }
   5536   return len;
   5537 }
   5538 
   5539 
   5540 THREADED_TEST(StringWrite) {
   5541   LocalContext context;
   5542   v8::HandleScope scope;
   5543   v8::Handle<String> str = v8_str("abcde");
   5544   // abc<Icelandic eth><Unicode snowman>.
   5545   v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
   5546   const int kStride = 4;  // Must match stride in for loops in JS below.
   5547   CompileRun(
   5548       "var left = '';"
   5549       "for (var i = 0; i < 0xd800; i += 4) {"
   5550       "  left = left + String.fromCharCode(i);"
   5551       "}");
   5552   CompileRun(
   5553       "var right = '';"
   5554       "for (var i = 0; i < 0xd800; i += 4) {"
   5555       "  right = String.fromCharCode(i) + right;"
   5556       "}");
   5557   v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
   5558   Handle<String> left_tree = global->Get(v8_str("left")).As<String>();
   5559   Handle<String> right_tree = global->Get(v8_str("right")).As<String>();
   5560 
   5561   CHECK_EQ(5, str2->Length());
   5562   CHECK_EQ(0xd800 / kStride, left_tree->Length());
   5563   CHECK_EQ(0xd800 / kStride, right_tree->Length());
   5564 
   5565   char buf[100];
   5566   char utf8buf[0xd800 * 3];
   5567   uint16_t wbuf[100];
   5568   int len;
   5569   int charlen;
   5570 
   5571   memset(utf8buf, 0x1, 1000);
   5572   len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
   5573   CHECK_EQ(9, len);
   5574   CHECK_EQ(5, charlen);
   5575   CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
   5576 
   5577   memset(utf8buf, 0x1, 1000);
   5578   len = str2->WriteUtf8(utf8buf, 8, &charlen);
   5579   CHECK_EQ(8, len);
   5580   CHECK_EQ(5, charlen);
   5581   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
   5582 
   5583   memset(utf8buf, 0x1, 1000);
   5584   len = str2->WriteUtf8(utf8buf, 7, &charlen);
   5585   CHECK_EQ(5, len);
   5586   CHECK_EQ(4, charlen);
   5587   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
   5588 
   5589   memset(utf8buf, 0x1, 1000);
   5590   len = str2->WriteUtf8(utf8buf, 6, &charlen);
   5591   CHECK_EQ(5, len);
   5592   CHECK_EQ(4, charlen);
   5593   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
   5594 
   5595   memset(utf8buf, 0x1, 1000);
   5596   len = str2->WriteUtf8(utf8buf, 5, &charlen);
   5597   CHECK_EQ(5, len);
   5598   CHECK_EQ(4, charlen);
   5599   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
   5600 
   5601   memset(utf8buf, 0x1, 1000);
   5602   len = str2->WriteUtf8(utf8buf, 4, &charlen);
   5603   CHECK_EQ(3, len);
   5604   CHECK_EQ(3, charlen);
   5605   CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
   5606 
   5607   memset(utf8buf, 0x1, 1000);
   5608   len = str2->WriteUtf8(utf8buf, 3, &charlen);
   5609   CHECK_EQ(3, len);
   5610   CHECK_EQ(3, charlen);
   5611   CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
   5612 
   5613   memset(utf8buf, 0x1, 1000);
   5614   len = str2->WriteUtf8(utf8buf, 2, &charlen);
   5615   CHECK_EQ(2, len);
   5616   CHECK_EQ(2, charlen);
   5617   CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
   5618 
   5619   memset(utf8buf, 0x1, sizeof(utf8buf));
   5620   len = GetUtf8Length(left_tree);
   5621   int utf8_expected =
   5622       (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride;
   5623   CHECK_EQ(utf8_expected, len);
   5624   len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
   5625   CHECK_EQ(utf8_expected, len);
   5626   CHECK_EQ(0xd800 / kStride, charlen);
   5627   CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3]));
   5628   CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2]));
   5629   CHECK_EQ(0xc0 - kStride,
   5630            static_cast<unsigned char>(utf8buf[utf8_expected - 1]));
   5631   CHECK_EQ(1, utf8buf[utf8_expected]);
   5632 
   5633   memset(utf8buf, 0x1, sizeof(utf8buf));
   5634   len = GetUtf8Length(right_tree);
   5635   CHECK_EQ(utf8_expected, len);
   5636   len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
   5637   CHECK_EQ(utf8_expected, len);
   5638   CHECK_EQ(0xd800 / kStride, charlen);
   5639   CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0]));
   5640   CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1]));
   5641   CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2]));
   5642   CHECK_EQ(1, utf8buf[utf8_expected]);
   5643 
   5644   memset(buf, 0x1, sizeof(buf));
   5645   memset(wbuf, 0x1, sizeof(wbuf));
   5646   len = str->WriteAscii(buf);
   5647   CHECK_EQ(5, len);
   5648   len = str->Write(wbuf);
   5649   CHECK_EQ(5, len);
   5650   CHECK_EQ(0, strcmp("abcde", buf));
   5651   uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
   5652   CHECK_EQ(0, StrCmp16(answer1, wbuf));
   5653 
   5654   memset(buf, 0x1, sizeof(buf));
   5655   memset(wbuf, 0x1, sizeof(wbuf));
   5656   len = str->WriteAscii(buf, 0, 4);
   5657   CHECK_EQ(4, len);
   5658   len = str->Write(wbuf, 0, 4);
   5659   CHECK_EQ(4, len);
   5660   CHECK_EQ(0, strncmp("abcd\1", buf, 5));
   5661   uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
   5662   CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
   5663 
   5664   memset(buf, 0x1, sizeof(buf));
   5665   memset(wbuf, 0x1, sizeof(wbuf));
   5666   len = str->WriteAscii(buf, 0, 5);
   5667   CHECK_EQ(5, len);
   5668   len = str->Write(wbuf, 0, 5);
   5669   CHECK_EQ(5, len);
   5670   CHECK_EQ(0, strncmp("abcde\1", buf, 6));
   5671   uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
   5672   CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
   5673 
   5674   memset(buf, 0x1, sizeof(buf));
   5675   memset(wbuf, 0x1, sizeof(wbuf));
   5676   len = str->WriteAscii(buf, 0, 6);
   5677   CHECK_EQ(5, len);
   5678   len = str->Write(wbuf, 0, 6);
   5679   CHECK_EQ(5, len);
   5680   CHECK_EQ(0, strcmp("abcde", buf));
   5681   uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
   5682   CHECK_EQ(0, StrCmp16(answer4, wbuf));
   5683 
   5684   memset(buf, 0x1, sizeof(buf));
   5685   memset(wbuf, 0x1, sizeof(wbuf));
   5686   len = str->WriteAscii(buf, 4, -1);
   5687   CHECK_EQ(1, len);
   5688   len = str->Write(wbuf, 4, -1);
   5689   CHECK_EQ(1, len);
   5690   CHECK_EQ(0, strcmp("e", buf));
   5691   uint16_t answer5[] = {'e', '\0'};
   5692   CHECK_EQ(0, StrCmp16(answer5, wbuf));
   5693 
   5694   memset(buf, 0x1, sizeof(buf));
   5695   memset(wbuf, 0x1, sizeof(wbuf));
   5696   len = str->WriteAscii(buf, 4, 6);
   5697   CHECK_EQ(1, len);
   5698   len = str->Write(wbuf, 4, 6);
   5699   CHECK_EQ(1, len);
   5700   CHECK_EQ(0, strcmp("e", buf));
   5701   CHECK_EQ(0, StrCmp16(answer5, wbuf));
   5702 
   5703   memset(buf, 0x1, sizeof(buf));
   5704   memset(wbuf, 0x1, sizeof(wbuf));
   5705   len = str->WriteAscii(buf, 4, 1);
   5706   CHECK_EQ(1, len);
   5707   len = str->Write(wbuf, 4, 1);
   5708   CHECK_EQ(1, len);
   5709   CHECK_EQ(0, strncmp("e\1", buf, 2));
   5710   uint16_t answer6[] = {'e', 0x101};
   5711   CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
   5712 
   5713   memset(buf, 0x1, sizeof(buf));
   5714   memset(wbuf, 0x1, sizeof(wbuf));
   5715   len = str->WriteAscii(buf, 3, 1);
   5716   CHECK_EQ(1, len);
   5717   len = str->Write(wbuf, 3, 1);
   5718   CHECK_EQ(1, len);
   5719   CHECK_EQ(0, strncmp("d\1", buf, 2));
   5720   uint16_t answer7[] = {'d', 0x101};
   5721   CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
   5722 
   5723   memset(wbuf, 0x1, sizeof(wbuf));
   5724   wbuf[5] = 'X';
   5725   len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION);
   5726   CHECK_EQ(5, len);
   5727   CHECK_EQ('X', wbuf[5]);
   5728   uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'};
   5729   uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'};
   5730   CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5));
   5731   CHECK_NE(0, StrCmp16(answer8b, wbuf));
   5732   wbuf[5] = '\0';
   5733   CHECK_EQ(0, StrCmp16(answer8b, wbuf));
   5734 
   5735   memset(buf, 0x1, sizeof(buf));
   5736   buf[5] = 'X';
   5737   len = str->WriteAscii(buf, 0, 6, String::NO_NULL_TERMINATION);
   5738   CHECK_EQ(5, len);
   5739   CHECK_EQ('X', buf[5]);
   5740   CHECK_EQ(0, strncmp("abcde", buf, 5));
   5741   CHECK_NE(0, strcmp("abcde", buf));
   5742   buf[5] = '\0';
   5743   CHECK_EQ(0, strcmp("abcde", buf));
   5744 
   5745   memset(utf8buf, 0x1, sizeof(utf8buf));
   5746   utf8buf[8] = 'X';
   5747   len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
   5748                         String::NO_NULL_TERMINATION);
   5749   CHECK_EQ(8, len);
   5750   CHECK_EQ('X', utf8buf[8]);
   5751   CHECK_EQ(5, charlen);
   5752   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8));
   5753   CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
   5754   utf8buf[8] = '\0';
   5755   CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
   5756 }
   5757 
   5758 
   5759 static void Utf16Helper(
   5760     LocalContext& context,
   5761     const char* name,
   5762     const char* lengths_name,
   5763     int len) {
   5764   Local<v8::Array> a =
   5765       Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
   5766   Local<v8::Array> alens =
   5767       Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
   5768   for (int i = 0; i < len; i++) {
   5769     Local<v8::String> string =
   5770       Local<v8::String>::Cast(a->Get(i));
   5771     Local<v8::Number> expected_len =
   5772       Local<v8::Number>::Cast(alens->Get(i));
   5773     CHECK_EQ(expected_len->Value() != string->Length(),
   5774              string->MayContainNonAscii());
   5775     int length = GetUtf8Length(string);
   5776     CHECK_EQ(static_cast<int>(expected_len->Value()), length);
   5777   }
   5778 }
   5779 
   5780 
   5781 static uint16_t StringGet(Handle<String> str, int index) {
   5782   i::Handle<i::String> istring =
   5783       v8::Utils::OpenHandle(String::Cast(*str));
   5784   return istring->Get(index);
   5785 }
   5786 
   5787 
   5788 static void WriteUtf8Helper(
   5789     LocalContext& context,
   5790     const char* name,
   5791     const char* lengths_name,
   5792     int len) {
   5793   Local<v8::Array> b =
   5794       Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
   5795   Local<v8::Array> alens =
   5796       Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
   5797   char buffer[1000];
   5798   char buffer2[1000];
   5799   for (int i = 0; i < len; i++) {
   5800     Local<v8::String> string =
   5801       Local<v8::String>::Cast(b->Get(i));
   5802     Local<v8::Number> expected_len =
   5803       Local<v8::Number>::Cast(alens->Get(i));
   5804     int utf8_length = static_cast<int>(expected_len->Value());
   5805     for (int j = utf8_length + 1; j >= 0; j--) {
   5806       memset(reinterpret_cast<void*>(&buffer), 42, sizeof(buffer));
   5807       memset(reinterpret_cast<void*>(&buffer2), 42, sizeof(buffer2));
   5808       int nchars;
   5809       int utf8_written =
   5810           string->WriteUtf8(buffer, j, &nchars, String::NO_OPTIONS);
   5811       int utf8_written2 =
   5812           string->WriteUtf8(buffer2, j, &nchars, String::NO_NULL_TERMINATION);
   5813       CHECK_GE(utf8_length + 1, utf8_written);
   5814       CHECK_GE(utf8_length, utf8_written2);
   5815       for (int k = 0; k < utf8_written2; k++) {
   5816         CHECK_EQ(buffer[k], buffer2[k]);
   5817       }
   5818       CHECK(nchars * 3 >= utf8_written - 1);
   5819       CHECK(nchars <= utf8_written);
   5820       if (j == utf8_length + 1) {
   5821         CHECK_EQ(utf8_written2, utf8_length);
   5822         CHECK_EQ(utf8_written2 + 1, utf8_written);
   5823       }
   5824       CHECK_EQ(buffer[utf8_written], 42);
   5825       if (j > utf8_length) {
   5826         if (utf8_written != 0) CHECK_EQ(buffer[utf8_written - 1], 0);
   5827         if (utf8_written > 1) CHECK_NE(buffer[utf8_written - 2], 42);
   5828         Handle<String> roundtrip = v8_str(buffer);
   5829         CHECK(roundtrip->Equals(string));
   5830       } else {
   5831         if (utf8_written != 0) CHECK_NE(buffer[utf8_written - 1], 42);
   5832       }
   5833       if (utf8_written2 != 0) CHECK_NE(buffer[utf8_written - 1], 42);
   5834       if (nchars >= 2) {
   5835         uint16_t trail = StringGet(string, nchars - 1);
   5836         uint16_t lead = StringGet(string, nchars - 2);
   5837         if (((lead & 0xfc00) == 0xd800) &&
   5838             ((trail & 0xfc00) == 0xdc00)) {
   5839           unsigned char u1 = buffer2[utf8_written2 - 4];
   5840           unsigned char u2 = buffer2[utf8_written2 - 3];
   5841           unsigned char u3 = buffer2[utf8_written2 - 2];
   5842           unsigned char u4 = buffer2[utf8_written2 - 1];
   5843           CHECK_EQ((u1 & 0xf8), 0xf0);
   5844           CHECK_EQ((u2 & 0xc0), 0x80);
   5845           CHECK_EQ((u3 & 0xc0), 0x80);
   5846           CHECK_EQ((u4 & 0xc0), 0x80);
   5847           uint32_t c = 0x10000 + ((lead & 0x3ff) << 10) + (trail & 0x3ff);
   5848           CHECK_EQ((u4 & 0x3f), (c & 0x3f));
   5849           CHECK_EQ((u3 & 0x3f), ((c >> 6) & 0x3f));
   5850           CHECK_EQ((u2 & 0x3f), ((c >> 12) & 0x3f));
   5851           CHECK_EQ((u1 & 0x3), c >> 18);
   5852         }
   5853       }
   5854     }
   5855   }
   5856 }
   5857 
   5858 
   5859 THREADED_TEST(Utf16) {
   5860   LocalContext context;
   5861   v8::HandleScope scope;
   5862   CompileRun(
   5863       "var pad = '01234567890123456789';"
   5864       "var p = [];"
   5865       "var plens = [20, 3, 3];"
   5866       "p.push('01234567890123456789');"
   5867       "var lead = 0xd800;"
   5868       "var trail = 0xdc00;"
   5869       "p.push(String.fromCharCode(0xd800));"
   5870       "p.push(String.fromCharCode(0xdc00));"
   5871       "var a = [];"
   5872       "var b = [];"
   5873       "var c = [];"
   5874       "var alens = [];"
   5875       "for (var i = 0; i < 3; i++) {"
   5876       "  p[1] = String.fromCharCode(lead++);"
   5877       "  for (var j = 0; j < 3; j++) {"
   5878       "    p[2] = String.fromCharCode(trail++);"
   5879       "    a.push(p[i] + p[j]);"
   5880       "    b.push(p[i] + p[j]);"
   5881       "    c.push(p[i] + p[j]);"
   5882       "    alens.push(plens[i] + plens[j]);"
   5883       "  }"
   5884       "}"
   5885       "alens[5] -= 2;"  // Here the surrogate pairs match up.
   5886       "var a2 = [];"
   5887       "var b2 = [];"
   5888       "var c2 = [];"
   5889       "var a2lens = [];"
   5890       "for (var m = 0; m < 9; m++) {"
   5891       "  for (var n = 0; n < 9; n++) {"
   5892       "    a2.push(a[m] + a[n]);"
   5893       "    b2.push(b[m] + b[n]);"
   5894       "    var newc = 'x' + c[m] + c[n] + 'y';"
   5895       "    c2.push(newc.substring(1, newc.length - 1));"
   5896       "    var utf = alens[m] + alens[n];"  // And here.
   5897            // The 'n's that start with 0xdc.. are 6-8
   5898            // The 'm's that end with 0xd8.. are 1, 4 and 7
   5899       "    if ((m % 3) == 1 && n >= 6) utf -= 2;"
   5900       "    a2lens.push(utf);"
   5901       "  }"
   5902       "}");
   5903   Utf16Helper(context, "a", "alens", 9);
   5904   Utf16Helper(context, "a2", "a2lens", 81);
   5905   WriteUtf8Helper(context, "b", "alens", 9);
   5906   WriteUtf8Helper(context, "b2", "a2lens", 81);
   5907   WriteUtf8Helper(context, "c2", "a2lens", 81);
   5908 }
   5909 
   5910 
   5911 static bool SameSymbol(Handle<String> s1, Handle<String> s2) {
   5912   i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1));
   5913   i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2));
   5914   return *is1 == *is2;
   5915 }
   5916 
   5917 
   5918 static void SameSymbolHelper(const char* a, const char* b) {
   5919   Handle<String> symbol1 = v8::String::NewSymbol(a);
   5920   Handle<String> symbol2 = v8::String::NewSymbol(b);
   5921   CHECK(SameSymbol(symbol1, symbol2));
   5922 }
   5923 
   5924 
   5925 THREADED_TEST(Utf16Symbol) {
   5926   LocalContext context;
   5927   v8::HandleScope scope;
   5928 
   5929   Handle<String> symbol1 = v8::String::NewSymbol("abc");
   5930   Handle<String> symbol2 = v8::String::NewSymbol("abc");
   5931   CHECK(SameSymbol(symbol1, symbol2));
   5932 
   5933   SameSymbolHelper("\360\220\220\205",  // 4 byte encoding.
   5934                    "\355\240\201\355\260\205");  // 2 3-byte surrogates.
   5935   SameSymbolHelper("\355\240\201\355\260\206",  // 2 3-byte surrogates.
   5936                    "\360\220\220\206");  // 4 byte encoding.
   5937   SameSymbolHelper("x\360\220\220\205",  // 4 byte encoding.
   5938                    "x\355\240\201\355\260\205");  // 2 3-byte surrogates.
   5939   SameSymbolHelper("x\355\240\201\355\260\206",  // 2 3-byte surrogates.
   5940                    "x\360\220\220\206");  // 4 byte encoding.
   5941   CompileRun(
   5942       "var sym0 = 'benedictus';"
   5943       "var sym0b = 'S\303\270ren';"
   5944       "var sym1 = '\355\240\201\355\260\207';"
   5945       "var sym2 = '\360\220\220\210';"
   5946       "var sym3 = 'x\355\240\201\355\260\207';"
   5947       "var sym4 = 'x\360\220\220\210';"
   5948       "if (sym1.length != 2) throw sym1;"
   5949       "if (sym1.charCodeAt(1) != 0xdc07) throw sym1.charCodeAt(1);"
   5950       "if (sym2.length != 2) throw sym2;"
   5951       "if (sym2.charCodeAt(1) != 0xdc08) throw sym2.charCodeAt(2);"
   5952       "if (sym3.length != 3) throw sym3;"
   5953       "if (sym3.charCodeAt(2) != 0xdc07) throw sym1.charCodeAt(2);"
   5954       "if (sym4.length != 3) throw sym4;"
   5955       "if (sym4.charCodeAt(2) != 0xdc08) throw sym2.charCodeAt(2);");
   5956   Handle<String> sym0 = v8::String::NewSymbol("benedictus");
   5957   Handle<String> sym0b = v8::String::NewSymbol("S\303\270ren");
   5958   Handle<String> sym1 = v8::String::NewSymbol("\355\240\201\355\260\207");
   5959   Handle<String> sym2 = v8::String::NewSymbol("\360\220\220\210");
   5960   Handle<String> sym3 = v8::String::NewSymbol("x\355\240\201\355\260\207");
   5961   Handle<String> sym4 = v8::String::NewSymbol("x\360\220\220\210");
   5962   v8::Local<v8::Object> global = context->Global();
   5963   Local<Value> s0 = global->Get(v8_str("sym0"));
   5964   Local<Value> s0b = global->Get(v8_str("sym0b"));
   5965   Local<Value> s1 = global->Get(v8_str("sym1"));
   5966   Local<Value> s2 = global->Get(v8_str("sym2"));
   5967   Local<Value> s3 = global->Get(v8_str("sym3"));
   5968   Local<Value> s4 = global->Get(v8_str("sym4"));
   5969   CHECK(SameSymbol(sym0, Handle<String>(String::Cast(*s0))));
   5970   CHECK(SameSymbol(sym0b, Handle<String>(String::Cast(*s0b))));
   5971   CHECK(SameSymbol(sym1, Handle<String>(String::Cast(*s1))));
   5972   CHECK(SameSymbol(sym2, Handle<String>(String::Cast(*s2))));
   5973   CHECK(SameSymbol(sym3, Handle<String>(String::Cast(*s3))));
   5974   CHECK(SameSymbol(sym4, Handle<String>(String::Cast(*s4))));
   5975 }
   5976 
   5977 
   5978 THREADED_TEST(ToArrayIndex) {
   5979   v8::HandleScope scope;
   5980   LocalContext context;
   5981 
   5982   v8::Handle<String> str = v8_str("42");
   5983   v8::Handle<v8::Uint32> index = str->ToArrayIndex();
   5984   CHECK(!index.IsEmpty());
   5985   CHECK_EQ(42.0, index->Uint32Value());
   5986   str = v8_str("42asdf");
   5987   index = str->ToArrayIndex();
   5988   CHECK(index.IsEmpty());
   5989   str = v8_str("-42");
   5990   index = str->ToArrayIndex();
   5991   CHECK(index.IsEmpty());
   5992   str = v8_str("4294967295");
   5993   index = str->ToArrayIndex();
   5994   CHECK(!index.IsEmpty());
   5995   CHECK_EQ(4294967295.0, index->Uint32Value());
   5996   v8::Handle<v8::Number> num = v8::Number::New(1);
   5997   index = num->ToArrayIndex();
   5998   CHECK(!index.IsEmpty());
   5999   CHECK_EQ(1.0, index->Uint32Value());
   6000   num = v8::Number::New(-1);
   6001   index = num->ToArrayIndex();
   6002   CHECK(index.IsEmpty());
   6003   v8::Handle<v8::Object> obj = v8::Object::New();
   6004   index = obj->ToArrayIndex();
   6005   CHECK(index.IsEmpty());
   6006 }
   6007 
   6008 
   6009 THREADED_TEST(ErrorConstruction) {
   6010   v8::HandleScope scope;
   6011   LocalContext context;
   6012 
   6013   v8::Handle<String> foo = v8_str("foo");
   6014   v8::Handle<String> message = v8_str("message");
   6015   v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
   6016   CHECK(range_error->IsObject());
   6017   CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
   6018   v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
   6019   CHECK(reference_error->IsObject());
   6020   CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
   6021   v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
   6022   CHECK(syntax_error->IsObject());
   6023   CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
   6024   v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
   6025   CHECK(type_error->IsObject());
   6026   CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
   6027   v8::Handle<Value> error = v8::Exception::Error(foo);
   6028   CHECK(error->IsObject());
   6029   CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
   6030 }
   6031 
   6032 
   6033 static v8::Handle<Value> YGetter(Local<String> name, const AccessorInfo& info) {
   6034   ApiTestFuzzer::Fuzz();
   6035   return v8_num(10);
   6036 }
   6037 
   6038 
   6039 static void YSetter(Local<String> name,
   6040                     Local<Value> value,
   6041                     const AccessorInfo& info) {
   6042   if (info.This()->Has(name)) {
   6043     info.This()->Delete(name);
   6044   }
   6045   info.This()->Set(name, value);
   6046 }
   6047 
   6048 
   6049 THREADED_TEST(DeleteAccessor) {
   6050   v8::HandleScope scope;
   6051   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
   6052   obj->SetAccessor(v8_str("y"), YGetter, YSetter);
   6053   LocalContext context;
   6054   v8::Handle<v8::Object> holder = obj->NewInstance();
   6055   context->Global()->Set(v8_str("holder"), holder);
   6056   v8::Handle<Value> result = CompileRun(
   6057       "holder.y = 11; holder.y = 12; holder.y");
   6058   CHECK_EQ(12, result->Uint32Value());
   6059 }
   6060 
   6061 
   6062 THREADED_TEST(TypeSwitch) {
   6063   v8::HandleScope scope;
   6064   v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New();
   6065   v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New();
   6066   v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New();
   6067   v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
   6068   v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
   6069   LocalContext context;
   6070   v8::Handle<v8::Object> obj0 = v8::Object::New();
   6071   v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
   6072   v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
   6073   v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
   6074   for (int i = 0; i < 10; i++) {
   6075     CHECK_EQ(0, type_switch->match(obj0));
   6076     CHECK_EQ(1, type_switch->match(obj1));
   6077     CHECK_EQ(2, type_switch->match(obj2));
   6078     CHECK_EQ(3, type_switch->match(obj3));
   6079     CHECK_EQ(3, type_switch->match(obj3));
   6080     CHECK_EQ(2, type_switch->match(obj2));
   6081     CHECK_EQ(1, type_switch->match(obj1));
   6082     CHECK_EQ(0, type_switch->match(obj0));
   6083   }
   6084 }
   6085 
   6086 
   6087 // For use within the TestSecurityHandler() test.
   6088 static bool g_security_callback_result = false;
   6089 static bool NamedSecurityTestCallback(Local<v8::Object> global,
   6090                                       Local<Value> name,
   6091                                       v8::AccessType type,
   6092                                       Local<Value> data) {
   6093   // Always allow read access.
   6094   if (type == v8::ACCESS_GET)
   6095     return true;
   6096 
   6097   // Sometimes allow other access.
   6098   return g_security_callback_result;
   6099 }
   6100 
   6101 
   6102 static bool IndexedSecurityTestCallback(Local<v8::Object> global,
   6103                                         uint32_t key,
   6104                                         v8::AccessType type,
   6105                                         Local<Value> data) {
   6106   // Always allow read access.
   6107   if (type == v8::ACCESS_GET)
   6108     return true;
   6109 
   6110   // Sometimes allow other access.
   6111   return g_security_callback_result;
   6112 }
   6113 
   6114 
   6115 static int trouble_nesting = 0;
   6116 static v8::Handle<Value> TroubleCallback(const v8::Arguments& args) {
   6117   ApiTestFuzzer::Fuzz();
   6118   trouble_nesting++;
   6119 
   6120   // Call a JS function that throws an uncaught exception.
   6121   Local<v8::Object> arg_this = Context::GetCurrent()->Global();
   6122   Local<Value> trouble_callee = (trouble_nesting == 3) ?
   6123     arg_this->Get(v8_str("trouble_callee")) :
   6124     arg_this->Get(v8_str("trouble_caller"));
   6125   CHECK(trouble_callee->IsFunction());
   6126   return Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL);
   6127 }
   6128 
   6129 
   6130 static int report_count = 0;
   6131 static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
   6132                                              v8::Handle<Value>) {
   6133   report_count++;
   6134 }
   6135 
   6136 
   6137 // Counts uncaught exceptions, but other tests running in parallel
   6138 // also have uncaught exceptions.
   6139 TEST(ApiUncaughtException) {
   6140   report_count = 0;
   6141   v8::HandleScope scope;
   6142   LocalContext env;
   6143   v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
   6144 
   6145   Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
   6146   v8::Local<v8::Object> global = env->Global();
   6147   global->Set(v8_str("trouble"), fun->GetFunction());
   6148 
   6149   Script::Compile(v8_str("function trouble_callee() {"
   6150                          "  var x = null;"
   6151                          "  return x.foo;"
   6152                          "};"
   6153                          "function trouble_caller() {"
   6154                          "  trouble();"
   6155                          "};"))->Run();
   6156   Local<Value> trouble = global->Get(v8_str("trouble"));
   6157   CHECK(trouble->IsFunction());
   6158   Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
   6159   CHECK(trouble_callee->IsFunction());
   6160   Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
   6161   CHECK(trouble_caller->IsFunction());
   6162   Function::Cast(*trouble_caller)->Call(global, 0, NULL);
   6163   CHECK_EQ(1, report_count);
   6164   v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
   6165 }
   6166 
   6167 static const char* script_resource_name = "ExceptionInNativeScript.js";
   6168 static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
   6169                                                 v8::Handle<Value>) {
   6170   v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
   6171   CHECK(!name_val.IsEmpty() && name_val->IsString());
   6172   v8::String::AsciiValue name(message->GetScriptResourceName());
   6173   CHECK_EQ(script_resource_name, *name);
   6174   CHECK_EQ(3, message->GetLineNumber());
   6175   v8::String::AsciiValue source_line(message->GetSourceLine());
   6176   CHECK_EQ("  new o.foo();", *source_line);
   6177 }
   6178 
   6179 TEST(ExceptionInNativeScript) {
   6180   v8::HandleScope scope;
   6181   LocalContext env;
   6182   v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
   6183 
   6184   Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
   6185   v8::Local<v8::Object> global = env->Global();
   6186   global->Set(v8_str("trouble"), fun->GetFunction());
   6187 
   6188   Script::Compile(v8_str("function trouble() {\n"
   6189                          "  var o = {};\n"
   6190                          "  new o.foo();\n"
   6191                          "};"), v8::String::New(script_resource_name))->Run();
   6192   Local<Value> trouble = global->Get(v8_str("trouble"));
   6193   CHECK(trouble->IsFunction());
   6194   Function::Cast(*trouble)->Call(global, 0, NULL);
   6195   v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
   6196 }
   6197 
   6198 
   6199 TEST(CompilationErrorUsingTryCatchHandler) {
   6200   v8::HandleScope scope;
   6201   LocalContext env;
   6202   v8::TryCatch try_catch;
   6203   Script::Compile(v8_str("This doesn't &*&@#$&*^ compile."));
   6204   CHECK_NE(NULL, *try_catch.Exception());
   6205   CHECK(try_catch.HasCaught());
   6206 }
   6207 
   6208 
   6209 TEST(TryCatchFinallyUsingTryCatchHandler) {
   6210   v8::HandleScope scope;
   6211   LocalContext env;
   6212   v8::TryCatch try_catch;
   6213   Script::Compile(v8_str("try { throw ''; } catch (e) {}"))->Run();
   6214   CHECK(!try_catch.HasCaught());
   6215   Script::Compile(v8_str("try { throw ''; } finally {}"))->Run();
   6216   CHECK(try_catch.HasCaught());
   6217   try_catch.Reset();
   6218   Script::Compile(v8_str("(function() {"
   6219                          "try { throw ''; } finally { return; }"
   6220                          "})()"))->Run();
   6221   CHECK(!try_catch.HasCaught());
   6222   Script::Compile(v8_str("(function()"
   6223                          "  { try { throw ''; } finally { throw 0; }"
   6224                          "})()"))->Run();
   6225   CHECK(try_catch.HasCaught());
   6226 }
   6227 
   6228 
   6229 // SecurityHandler can't be run twice
   6230 TEST(SecurityHandler) {
   6231   v8::HandleScope scope0;
   6232   v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
   6233   global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
   6234                                            IndexedSecurityTestCallback);
   6235   // Create an environment
   6236   v8::Persistent<Context> context0 =
   6237     Context::New(NULL, global_template);
   6238   context0->Enter();
   6239 
   6240   v8::Handle<v8::Object> global0 = context0->Global();
   6241   v8::Handle<Script> script0 = v8_compile("foo = 111");
   6242   script0->Run();
   6243   global0->Set(v8_str("0"), v8_num(999));
   6244   v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
   6245   CHECK_EQ(111, foo0->Int32Value());
   6246   v8::Handle<Value> z0 = global0->Get(v8_str("0"));
   6247   CHECK_EQ(999, z0->Int32Value());
   6248 
   6249   // Create another environment, should fail security checks.
   6250   v8::HandleScope scope1;
   6251 
   6252   v8::Persistent<Context> context1 =
   6253     Context::New(NULL, global_template);
   6254   context1->Enter();
   6255 
   6256   v8::Handle<v8::Object> global1 = context1->Global();
   6257   global1->Set(v8_str("othercontext"), global0);
   6258   // This set will fail the security check.
   6259   v8::Handle<Script> script1 =
   6260     v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
   6261   script1->Run();
   6262   // This read will pass the security check.
   6263   v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
   6264   CHECK_EQ(111, foo1->Int32Value());
   6265   // This read will pass the security check.
   6266   v8::Handle<Value> z1 = global0->Get(v8_str("0"));
   6267   CHECK_EQ(999, z1->Int32Value());
   6268 
   6269   // Create another environment, should pass security checks.
   6270   { g_security_callback_result = true;  // allow security handler to pass.
   6271     v8::HandleScope scope2;
   6272     LocalContext context2;
   6273     v8::Handle<v8::Object> global2 = context2->Global();
   6274     global2->Set(v8_str("othercontext"), global0);
   6275     v8::Handle<Script> script2 =
   6276         v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
   6277     script2->Run();
   6278     v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
   6279     CHECK_EQ(333, foo2->Int32Value());
   6280     v8::Handle<Value> z2 = global0->Get(v8_str("0"));
   6281     CHECK_EQ(888, z2->Int32Value());
   6282   }
   6283 
   6284   context1->Exit();
   6285   context1.Dispose();
   6286 
   6287   context0->Exit();
   6288   context0.Dispose();
   6289 }
   6290 
   6291 
   6292 THREADED_TEST(SecurityChecks) {
   6293   v8::HandleScope handle_scope;
   6294   LocalContext env1;
   6295   v8::Persistent<Context> env2 = Context::New();
   6296 
   6297   Local<Value> foo = v8_str("foo");
   6298   Local<Value> bar = v8_str("bar");
   6299 
   6300   // Set to the same domain.
   6301   env1->SetSecurityToken(foo);
   6302 
   6303   // Create a function in env1.
   6304   Script::Compile(v8_str("spy=function(){return spy;}"))->Run();
   6305   Local<Value> spy = env1->Global()->Get(v8_str("spy"));
   6306   CHECK(spy->IsFunction());
   6307 
   6308   // Create another function accessing global objects.
   6309   Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run();
   6310   Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
   6311   CHECK(spy2->IsFunction());
   6312 
   6313   // Switch to env2 in the same domain and invoke spy on env2.
   6314   {
   6315     env2->SetSecurityToken(foo);
   6316     // Enter env2
   6317     Context::Scope scope_env2(env2);
   6318     Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
   6319     CHECK(result->IsFunction());
   6320   }
   6321 
   6322   {
   6323     env2->SetSecurityToken(bar);
   6324     Context::Scope scope_env2(env2);
   6325 
   6326     // Call cross_domain_call, it should throw an exception
   6327     v8::TryCatch try_catch;
   6328     Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
   6329     CHECK(try_catch.HasCaught());
   6330   }
   6331 
   6332   env2.Dispose();
   6333 }
   6334 
   6335 
   6336 // Regression test case for issue 1183439.
   6337 THREADED_TEST(SecurityChecksForPrototypeChain) {
   6338   v8::HandleScope scope;
   6339   LocalContext current;
   6340   v8::Persistent<Context> other = Context::New();
   6341 
   6342   // Change context to be able to get to the Object function in the
   6343   // other context without hitting the security checks.
   6344   v8::Local<Value> other_object;
   6345   { Context::Scope scope(other);
   6346     other_object = other->Global()->Get(v8_str("Object"));
   6347     other->Global()->Set(v8_num(42), v8_num(87));
   6348   }
   6349 
   6350   current->Global()->Set(v8_str("other"), other->Global());
   6351   CHECK(v8_compile("other")->Run()->Equals(other->Global()));
   6352 
   6353   // Make sure the security check fails here and we get an undefined
   6354   // result instead of getting the Object function. Repeat in a loop
   6355   // to make sure to exercise the IC code.
   6356   v8::Local<Script> access_other0 = v8_compile("other.Object");
   6357   v8::Local<Script> access_other1 = v8_compile("other[42]");
   6358   for (int i = 0; i < 5; i++) {
   6359     CHECK(!access_other0->Run()->Equals(other_object));
   6360     CHECK(access_other0->Run()->IsUndefined());
   6361     CHECK(!access_other1->Run()->Equals(v8_num(87)));
   6362     CHECK(access_other1->Run()->IsUndefined());
   6363   }
   6364 
   6365   // Create an object that has 'other' in its prototype chain and make
   6366   // sure we cannot access the Object function indirectly through
   6367   // that. Repeat in a loop to make sure to exercise the IC code.
   6368   v8_compile("function F() { };"
   6369              "F.prototype = other;"
   6370              "var f = new F();")->Run();
   6371   v8::Local<Script> access_f0 = v8_compile("f.Object");
   6372   v8::Local<Script> access_f1 = v8_compile("f[42]");
   6373   for (int j = 0; j < 5; j++) {
   6374     CHECK(!access_f0->Run()->Equals(other_object));
   6375     CHECK(access_f0->Run()->IsUndefined());
   6376     CHECK(!access_f1->Run()->Equals(v8_num(87)));
   6377     CHECK(access_f1->Run()->IsUndefined());
   6378   }
   6379 
   6380   // Now it gets hairy: Set the prototype for the other global object
   6381   // to be the current global object. The prototype chain for 'f' now
   6382   // goes through 'other' but ends up in the current global object.
   6383   { Context::Scope scope(other);
   6384     other->Global()->Set(v8_str("__proto__"), current->Global());
   6385   }
   6386   // Set a named and an index property on the current global
   6387   // object. To force the lookup to go through the other global object,
   6388   // the properties must not exist in the other global object.
   6389   current->Global()->Set(v8_str("foo"), v8_num(100));
   6390   current->Global()->Set(v8_num(99), v8_num(101));
   6391   // Try to read the properties from f and make sure that the access
   6392   // gets stopped by the security checks on the other global object.
   6393   Local<Script> access_f2 = v8_compile("f.foo");
   6394   Local<Script> access_f3 = v8_compile("f[99]");
   6395   for (int k = 0; k < 5; k++) {
   6396     CHECK(!access_f2->Run()->Equals(v8_num(100)));
   6397     CHECK(access_f2->Run()->IsUndefined());
   6398     CHECK(!access_f3->Run()->Equals(v8_num(101)));
   6399     CHECK(access_f3->Run()->IsUndefined());
   6400   }
   6401   other.Dispose();
   6402 }
   6403 
   6404 
   6405 THREADED_TEST(CrossDomainDelete) {
   6406   v8::HandleScope handle_scope;
   6407   LocalContext env1;
   6408   v8::Persistent<Context> env2 = Context::New();
   6409 
   6410   Local<Value> foo = v8_str("foo");
   6411   Local<Value> bar = v8_str("bar");
   6412 
   6413   // Set to the same domain.
   6414   env1->SetSecurityToken(foo);
   6415   env2->SetSecurityToken(foo);
   6416 
   6417   env1->Global()->Set(v8_str("prop"), v8_num(3));
   6418   env2->Global()->Set(v8_str("env1"), env1->Global());
   6419 
   6420   // Change env2 to a different domain and delete env1.prop.
   6421   env2->SetSecurityToken(bar);
   6422   {
   6423     Context::Scope scope_env2(env2);
   6424     Local<Value> result =
   6425         Script::Compile(v8_str("delete env1.prop"))->Run();
   6426     CHECK(result->IsFalse());
   6427   }
   6428 
   6429   // Check that env1.prop still exists.
   6430   Local<Value> v = env1->Global()->Get(v8_str("prop"));
   6431   CHECK(v->IsNumber());
   6432   CHECK_EQ(3, v->Int32Value());
   6433 
   6434   env2.Dispose();
   6435 }
   6436 
   6437 
   6438 THREADED_TEST(CrossDomainIsPropertyEnumerable) {
   6439   v8::HandleScope handle_scope;
   6440   LocalContext env1;
   6441   v8::Persistent<Context> env2 = Context::New();
   6442 
   6443   Local<Value> foo = v8_str("foo");
   6444   Local<Value> bar = v8_str("bar");
   6445 
   6446   // Set to the same domain.
   6447   env1->SetSecurityToken(foo);
   6448   env2->SetSecurityToken(foo);
   6449 
   6450   env1->Global()->Set(v8_str("prop"), v8_num(3));
   6451   env2->Global()->Set(v8_str("env1"), env1->Global());
   6452 
   6453   // env1.prop is enumerable in env2.
   6454   Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
   6455   {
   6456     Context::Scope scope_env2(env2);
   6457     Local<Value> result = Script::Compile(test)->Run();
   6458     CHECK(result->IsTrue());
   6459   }
   6460 
   6461   // Change env2 to a different domain and test again.
   6462   env2->SetSecurityToken(bar);
   6463   {
   6464     Context::Scope scope_env2(env2);
   6465     Local<Value> result = Script::Compile(test)->Run();
   6466     CHECK(result->IsFalse());
   6467   }
   6468 
   6469   env2.Dispose();
   6470 }
   6471 
   6472 
   6473 THREADED_TEST(CrossDomainForIn) {
   6474   v8::HandleScope handle_scope;
   6475   LocalContext env1;
   6476   v8::Persistent<Context> env2 = Context::New();
   6477 
   6478   Local<Value> foo = v8_str("foo");
   6479   Local<Value> bar = v8_str("bar");
   6480 
   6481   // Set to the same domain.
   6482   env1->SetSecurityToken(foo);
   6483   env2->SetSecurityToken(foo);
   6484 
   6485   env1->Global()->Set(v8_str("prop"), v8_num(3));
   6486   env2->Global()->Set(v8_str("env1"), env1->Global());
   6487 
   6488   // Change env2 to a different domain and set env1's global object
   6489   // as the __proto__ of an object in env2 and enumerate properties
   6490   // in for-in. It shouldn't enumerate properties on env1's global
   6491   // object.
   6492   env2->SetSecurityToken(bar);
   6493   {
   6494     Context::Scope scope_env2(env2);
   6495     Local<Value> result =
   6496         CompileRun("(function(){var obj = {'__proto__':env1};"
   6497                    "for (var p in obj)"
   6498                    "   if (p == 'prop') return false;"
   6499                    "return true;})()");
   6500     CHECK(result->IsTrue());
   6501   }
   6502   env2.Dispose();
   6503 }
   6504 
   6505 
   6506 TEST(ContextDetachGlobal) {
   6507   v8::HandleScope handle_scope;
   6508   LocalContext env1;
   6509   v8::Persistent<Context> env2 = Context::New();
   6510 
   6511   Local<v8::Object> global1 = env1->Global();
   6512 
   6513   Local<Value> foo = v8_str("foo");
   6514 
   6515   // Set to the same domain.
   6516   env1->SetSecurityToken(foo);
   6517   env2->SetSecurityToken(foo);
   6518 
   6519   // Enter env2
   6520   env2->Enter();
   6521 
   6522   // Create a function in env2 and add a reference to it in env1.
   6523   Local<v8::Object> global2 = env2->Global();
   6524   global2->Set(v8_str("prop"), v8::Integer::New(1));
   6525   CompileRun("function getProp() {return prop;}");
   6526 
   6527   env1->Global()->Set(v8_str("getProp"),
   6528                       global2->Get(v8_str("getProp")));
   6529 
   6530   // Detach env2's global, and reuse the global object of env2
   6531   env2->Exit();
   6532   env2->DetachGlobal();
   6533   // env2 has a new global object.
   6534   CHECK(!env2->Global()->Equals(global2));
   6535 
   6536   v8::Persistent<Context> env3 =
   6537       Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
   6538   env3->SetSecurityToken(v8_str("bar"));
   6539   env3->Enter();
   6540 
   6541   Local<v8::Object> global3 = env3->Global();
   6542   CHECK_EQ(global2, global3);
   6543   CHECK(global3->Get(v8_str("prop"))->IsUndefined());
   6544   CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
   6545   global3->Set(v8_str("prop"), v8::Integer::New(-1));
   6546   global3->Set(v8_str("prop2"), v8::Integer::New(2));
   6547   env3->Exit();
   6548 
   6549   // Call getProp in env1, and it should return the value 1
   6550   {
   6551     Local<Value> get_prop = global1->Get(v8_str("getProp"));
   6552     CHECK(get_prop->IsFunction());
   6553     v8::TryCatch try_catch;
   6554     Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
   6555     CHECK(!try_catch.HasCaught());
   6556     CHECK_EQ(1, r->Int32Value());
   6557   }
   6558 
   6559   // Check that env3 is not accessible from env1
   6560   {
   6561     Local<Value> r = global3->Get(v8_str("prop2"));
   6562     CHECK(r->IsUndefined());
   6563   }
   6564 
   6565   env2.Dispose();
   6566   env3.Dispose();
   6567 }
   6568 
   6569 
   6570 TEST(DetachAndReattachGlobal) {
   6571   v8::HandleScope scope;
   6572   LocalContext env1;
   6573 
   6574   // Create second environment.
   6575   v8::Persistent<Context> env2 = Context::New();
   6576 
   6577   Local<Value> foo = v8_str("foo");
   6578 
   6579   // Set same security token for env1 and env2.
   6580   env1->SetSecurityToken(foo);
   6581   env2->SetSecurityToken(foo);
   6582 
   6583   // Create a property on the global object in env2.
   6584   {
   6585     v8::Context::Scope scope(env2);
   6586     env2->Global()->Set(v8_str("p"), v8::Integer::New(42));
   6587   }
   6588 
   6589   // Create a reference to env2 global from env1 global.
   6590   env1->Global()->Set(v8_str("other"), env2->Global());
   6591 
   6592   // Check that we have access to other.p in env2 from env1.
   6593   Local<Value> result = CompileRun("other.p");
   6594   CHECK(result->IsInt32());
   6595   CHECK_EQ(42, result->Int32Value());
   6596 
   6597   // Hold on to global from env2 and detach global from env2.
   6598   Local<v8::Object> global2 = env2->Global();
   6599   env2->DetachGlobal();
   6600 
   6601   // Check that the global has been detached. No other.p property can
   6602   // be found.
   6603   result = CompileRun("other.p");
   6604   CHECK(result->IsUndefined());
   6605 
   6606   // Reuse global2 for env3.
   6607   v8::Persistent<Context> env3 =
   6608       Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
   6609   CHECK_EQ(global2, env3->Global());
   6610 
   6611   // Start by using the same security token for env3 as for env1 and env2.
   6612   env3->SetSecurityToken(foo);
   6613 
   6614   // Create a property on the global object in env3.
   6615   {
   6616     v8::Context::Scope scope(env3);
   6617     env3->Global()->Set(v8_str("p"), v8::Integer::New(24));
   6618   }
   6619 
   6620   // Check that other.p is now the property in env3 and that we have access.
   6621   result = CompileRun("other.p");
   6622   CHECK(result->IsInt32());
   6623   CHECK_EQ(24, result->Int32Value());
   6624 
   6625   // Change security token for env3 to something different from env1 and env2.
   6626   env3->SetSecurityToken(v8_str("bar"));
   6627 
   6628   // Check that we do not have access to other.p in env1. |other| is now
   6629   // the global object for env3 which has a different security token,
   6630   // so access should be blocked.
   6631   result = CompileRun("other.p");
   6632   CHECK(result->IsUndefined());
   6633 
   6634   // Detach the global for env3 and reattach it to env2.
   6635   env3->DetachGlobal();
   6636   env2->ReattachGlobal(global2);
   6637 
   6638   // Check that we have access to other.p again in env1.  |other| is now
   6639   // the global object for env2 which has the same security token as env1.
   6640   result = CompileRun("other.p");
   6641   CHECK(result->IsInt32());
   6642   CHECK_EQ(42, result->Int32Value());
   6643 
   6644   env2.Dispose();
   6645   env3.Dispose();
   6646 }
   6647 
   6648 
   6649 static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
   6650 static bool NamedAccessBlocker(Local<v8::Object> global,
   6651                                Local<Value> name,
   6652                                v8::AccessType type,
   6653                                Local<Value> data) {
   6654   return Context::GetCurrent()->Global()->Equals(global) ||
   6655       allowed_access_type[type];
   6656 }
   6657 
   6658 
   6659 static bool IndexedAccessBlocker(Local<v8::Object> global,
   6660                                  uint32_t key,
   6661                                  v8::AccessType type,
   6662                                  Local<Value> data) {
   6663   return Context::GetCurrent()->Global()->Equals(global) ||
   6664       allowed_access_type[type];
   6665 }
   6666 
   6667 
   6668 static int g_echo_value = -1;
   6669 static v8::Handle<Value> EchoGetter(Local<String> name,
   6670                                     const AccessorInfo& info) {
   6671   return v8_num(g_echo_value);
   6672 }
   6673 
   6674 
   6675 static void EchoSetter(Local<String> name,
   6676                        Local<Value> value,
   6677                        const AccessorInfo&) {
   6678   if (value->IsNumber())
   6679     g_echo_value = value->Int32Value();
   6680 }
   6681 
   6682 
   6683 static v8::Handle<Value> UnreachableGetter(Local<String> name,
   6684                                            const AccessorInfo& info) {
   6685   CHECK(false);  // This function should not be called..
   6686   return v8::Undefined();
   6687 }
   6688 
   6689 
   6690 static void UnreachableSetter(Local<String>, Local<Value>,
   6691                               const AccessorInfo&) {
   6692   CHECK(false);  // This function should nto be called.
   6693 }
   6694 
   6695 
   6696 TEST(AccessControl) {
   6697   v8::HandleScope handle_scope;
   6698   v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
   6699 
   6700   global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
   6701                                            IndexedAccessBlocker);
   6702 
   6703   // Add an accessor accessible by cross-domain JS code.
   6704   global_template->SetAccessor(
   6705       v8_str("accessible_prop"),
   6706       EchoGetter, EchoSetter,
   6707       v8::Handle<Value>(),
   6708       v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
   6709 
   6710   // Add an accessor that is not accessible by cross-domain JS code.
   6711   global_template->SetAccessor(v8_str("blocked_prop"),
   6712                                UnreachableGetter, UnreachableSetter,
   6713                                v8::Handle<Value>(),
   6714                                v8::DEFAULT);
   6715 
   6716   // Create an environment
   6717   v8::Persistent<Context> context0 = Context::New(NULL, global_template);
   6718   context0->Enter();
   6719 
   6720   v8::Handle<v8::Object> global0 = context0->Global();
   6721 
   6722   // Define a property with JS getter and setter.
   6723   CompileRun(
   6724       "function getter() { return 'getter'; };\n"
   6725       "function setter() { return 'setter'; }\n"
   6726       "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
   6727 
   6728   Local<Value> getter = global0->Get(v8_str("getter"));
   6729   Local<Value> setter = global0->Get(v8_str("setter"));
   6730 
   6731   // And define normal element.
   6732   global0->Set(239, v8_str("239"));
   6733 
   6734   // Define an element with JS getter and setter.
   6735   CompileRun(
   6736       "function el_getter() { return 'el_getter'; };\n"
   6737       "function el_setter() { return 'el_setter'; };\n"
   6738       "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
   6739 
   6740   Local<Value> el_getter = global0->Get(v8_str("el_getter"));
   6741   Local<Value> el_setter = global0->Get(v8_str("el_setter"));
   6742 
   6743   v8::HandleScope scope1;
   6744 
   6745   v8::Persistent<Context> context1 = Context::New();
   6746   context1->Enter();
   6747 
   6748   v8::Handle<v8::Object> global1 = context1->Global();
   6749   global1->Set(v8_str("other"), global0);
   6750 
   6751   // Access blocked property.
   6752   CompileRun("other.blocked_prop = 1");
   6753 
   6754   ExpectUndefined("other.blocked_prop");
   6755   ExpectUndefined(
   6756       "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
   6757   ExpectFalse("propertyIsEnumerable.call(other, 'blocked_prop')");
   6758 
   6759   // Enable ACCESS_HAS
   6760   allowed_access_type[v8::ACCESS_HAS] = true;
   6761   ExpectUndefined("other.blocked_prop");
   6762   // ... and now we can get the descriptor...
   6763   ExpectUndefined(
   6764       "Object.getOwnPropertyDescriptor(other, 'blocked_prop').value");
   6765   // ... and enumerate the property.
   6766   ExpectTrue("propertyIsEnumerable.call(other, 'blocked_prop')");
   6767   allowed_access_type[v8::ACCESS_HAS] = false;
   6768 
   6769   // Access blocked element.
   6770   CompileRun("other[239] = 1");
   6771 
   6772   ExpectUndefined("other[239]");
   6773   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239')");
   6774   ExpectFalse("propertyIsEnumerable.call(other, '239')");
   6775 
   6776   // Enable ACCESS_HAS
   6777   allowed_access_type[v8::ACCESS_HAS] = true;
   6778   ExpectUndefined("other[239]");
   6779   // ... and now we can get the descriptor...
   6780   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239').value");
   6781   // ... and enumerate the property.
   6782   ExpectTrue("propertyIsEnumerable.call(other, '239')");
   6783   allowed_access_type[v8::ACCESS_HAS] = false;
   6784 
   6785   // Access a property with JS accessor.
   6786   CompileRun("other.js_accessor_p = 2");
   6787 
   6788   ExpectUndefined("other.js_accessor_p");
   6789   ExpectUndefined(
   6790       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p')");
   6791 
   6792   // Enable ACCESS_HAS.
   6793   allowed_access_type[v8::ACCESS_HAS] = true;
   6794   ExpectUndefined("other.js_accessor_p");
   6795   ExpectUndefined(
   6796       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
   6797   ExpectUndefined(
   6798       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
   6799   ExpectUndefined(
   6800       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
   6801   allowed_access_type[v8::ACCESS_HAS] = false;
   6802 
   6803   // Enable both ACCESS_HAS and ACCESS_GET.
   6804   allowed_access_type[v8::ACCESS_HAS] = true;
   6805   allowed_access_type[v8::ACCESS_GET] = true;
   6806 
   6807   ExpectString("other.js_accessor_p", "getter");
   6808   ExpectObject(
   6809       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
   6810   ExpectUndefined(
   6811       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
   6812   ExpectUndefined(
   6813       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
   6814 
   6815   allowed_access_type[v8::ACCESS_GET] = false;
   6816   allowed_access_type[v8::ACCESS_HAS] = false;
   6817 
   6818   // Enable both ACCESS_HAS and ACCESS_SET.
   6819   allowed_access_type[v8::ACCESS_HAS] = true;
   6820   allowed_access_type[v8::ACCESS_SET] = true;
   6821 
   6822   ExpectUndefined("other.js_accessor_p");
   6823   ExpectUndefined(
   6824       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
   6825   ExpectObject(
   6826       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
   6827   ExpectUndefined(
   6828       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
   6829 
   6830   allowed_access_type[v8::ACCESS_SET] = false;
   6831   allowed_access_type[v8::ACCESS_HAS] = false;
   6832 
   6833   // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
   6834   allowed_access_type[v8::ACCESS_HAS] = true;
   6835   allowed_access_type[v8::ACCESS_GET] = true;
   6836   allowed_access_type[v8::ACCESS_SET] = true;
   6837 
   6838   ExpectString("other.js_accessor_p", "getter");
   6839   ExpectObject(
   6840       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
   6841   ExpectObject(
   6842       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
   6843   ExpectUndefined(
   6844       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
   6845 
   6846   allowed_access_type[v8::ACCESS_SET] = false;
   6847   allowed_access_type[v8::ACCESS_GET] = false;
   6848   allowed_access_type[v8::ACCESS_HAS] = false;
   6849 
   6850   // Access an element with JS accessor.
   6851   CompileRun("other[42] = 2");
   6852 
   6853   ExpectUndefined("other[42]");
   6854   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42')");
   6855 
   6856   // Enable ACCESS_HAS.
   6857   allowed_access_type[v8::ACCESS_HAS] = true;
   6858   ExpectUndefined("other[42]");
   6859   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
   6860   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
   6861   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
   6862   allowed_access_type[v8::ACCESS_HAS] = false;
   6863 
   6864   // Enable both ACCESS_HAS and ACCESS_GET.
   6865   allowed_access_type[v8::ACCESS_HAS] = true;
   6866   allowed_access_type[v8::ACCESS_GET] = true;
   6867 
   6868   ExpectString("other[42]", "el_getter");
   6869   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
   6870   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
   6871   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
   6872 
   6873   allowed_access_type[v8::ACCESS_GET] = false;
   6874   allowed_access_type[v8::ACCESS_HAS] = false;
   6875 
   6876   // Enable both ACCESS_HAS and ACCESS_SET.
   6877   allowed_access_type[v8::ACCESS_HAS] = true;
   6878   allowed_access_type[v8::ACCESS_SET] = true;
   6879 
   6880   ExpectUndefined("other[42]");
   6881   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
   6882   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
   6883   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
   6884 
   6885   allowed_access_type[v8::ACCESS_SET] = false;
   6886   allowed_access_type[v8::ACCESS_HAS] = false;
   6887 
   6888   // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
   6889   allowed_access_type[v8::ACCESS_HAS] = true;
   6890   allowed_access_type[v8::ACCESS_GET] = true;
   6891   allowed_access_type[v8::ACCESS_SET] = true;
   6892 
   6893   ExpectString("other[42]", "el_getter");
   6894   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
   6895   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
   6896   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
   6897 
   6898   allowed_access_type[v8::ACCESS_SET] = false;
   6899   allowed_access_type[v8::ACCESS_GET] = false;
   6900   allowed_access_type[v8::ACCESS_HAS] = false;
   6901 
   6902   v8::Handle<Value> value;
   6903 
   6904   // Access accessible property
   6905   value = CompileRun("other.accessible_prop = 3");
   6906   CHECK(value->IsNumber());
   6907   CHECK_EQ(3, value->Int32Value());
   6908   CHECK_EQ(3, g_echo_value);
   6909 
   6910   value = CompileRun("other.accessible_prop");
   6911   CHECK(value->IsNumber());
   6912   CHECK_EQ(3, value->Int32Value());
   6913 
   6914   value = CompileRun(
   6915       "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
   6916   CHECK(value->IsNumber());
   6917   CHECK_EQ(3, value->Int32Value());
   6918 
   6919   value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
   6920   CHECK(value->IsTrue());
   6921 
   6922   // Enumeration doesn't enumerate accessors from inaccessible objects in
   6923   // the prototype chain even if the accessors are in themselves accessible.
   6924   value =
   6925       CompileRun("(function(){var obj = {'__proto__':other};"
   6926                  "for (var p in obj)"
   6927                  "   if (p == 'accessible_prop' || p == 'blocked_prop') {"
   6928                  "     return false;"
   6929                  "   }"
   6930                  "return true;})()");
   6931   CHECK(value->IsTrue());
   6932 
   6933   context1->Exit();
   6934   context0->Exit();
   6935   context1.Dispose();
   6936   context0.Dispose();
   6937 }
   6938 
   6939 
   6940 TEST(AccessControlES5) {
   6941   v8::HandleScope handle_scope;
   6942   v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
   6943 
   6944   global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
   6945                                            IndexedAccessBlocker);
   6946 
   6947   // Add accessible accessor.
   6948   global_template->SetAccessor(
   6949       v8_str("accessible_prop"),
   6950       EchoGetter, EchoSetter,
   6951       v8::Handle<Value>(),
   6952       v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
   6953 
   6954 
   6955   // Add an accessor that is not accessible by cross-domain JS code.
   6956   global_template->SetAccessor(v8_str("blocked_prop"),
   6957                                UnreachableGetter, UnreachableSetter,
   6958                                v8::Handle<Value>(),
   6959                                v8::DEFAULT);
   6960 
   6961   // Create an environment
   6962   v8::Persistent<Context> context0 = Context::New(NULL, global_template);
   6963   context0->Enter();
   6964 
   6965   v8::Handle<v8::Object> global0 = context0->Global();
   6966 
   6967   v8::Persistent<Context> context1 = Context::New();
   6968   context1->Enter();
   6969   v8::Handle<v8::Object> global1 = context1->Global();
   6970   global1->Set(v8_str("other"), global0);
   6971 
   6972   // Regression test for issue 1154.
   6973   ExpectTrue("Object.keys(other).indexOf('blocked_prop') == -1");
   6974 
   6975   ExpectUndefined("other.blocked_prop");
   6976 
   6977   // Regression test for issue 1027.
   6978   CompileRun("Object.defineProperty(\n"
   6979              "  other, 'blocked_prop', {configurable: false})");
   6980   ExpectUndefined("other.blocked_prop");
   6981   ExpectUndefined(
   6982       "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
   6983 
   6984   // Regression test for issue 1171.
   6985   ExpectTrue("Object.isExtensible(other)");
   6986   CompileRun("Object.preventExtensions(other)");
   6987   ExpectTrue("Object.isExtensible(other)");
   6988 
   6989   // Object.seal and Object.freeze.
   6990   CompileRun("Object.freeze(other)");
   6991   ExpectTrue("Object.isExtensible(other)");
   6992 
   6993   CompileRun("Object.seal(other)");
   6994   ExpectTrue("Object.isExtensible(other)");
   6995 
   6996   // Regression test for issue 1250.
   6997   // Make sure that we can set the accessible accessors value using normal
   6998   // assignment.
   6999   CompileRun("other.accessible_prop = 42");
   7000   CHECK_EQ(42, g_echo_value);
   7001 
   7002   v8::Handle<Value> value;
   7003   // We follow Safari in ignoring assignments to host object accessors.
   7004   CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
   7005   value = CompileRun("other.accessible_prop == 42");
   7006   CHECK(value->IsTrue());
   7007 }
   7008 
   7009 
   7010 static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
   7011                                             Local<Value> name,
   7012                                             v8::AccessType type,
   7013                                             Local<Value> data) {
   7014   return false;
   7015 }
   7016 
   7017 
   7018 static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
   7019                                               uint32_t key,
   7020                                               v8::AccessType type,
   7021                                               Local<Value> data) {
   7022   return false;
   7023 }
   7024 
   7025 
   7026 THREADED_TEST(AccessControlGetOwnPropertyNames) {
   7027   v8::HandleScope handle_scope;
   7028   v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
   7029 
   7030   obj_template->Set(v8_str("x"), v8::Integer::New(42));
   7031   obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
   7032                                         GetOwnPropertyNamesIndexedBlocker);
   7033 
   7034   // Create an environment
   7035   v8::Persistent<Context> context0 = Context::New(NULL, obj_template);
   7036   context0->Enter();
   7037 
   7038   v8::Handle<v8::Object> global0 = context0->Global();
   7039 
   7040   v8::HandleScope scope1;
   7041 
   7042   v8::Persistent<Context> context1 = Context::New();
   7043   context1->Enter();
   7044 
   7045   v8::Handle<v8::Object> global1 = context1->Global();
   7046   global1->Set(v8_str("other"), global0);
   7047   global1->Set(v8_str("object"), obj_template->NewInstance());
   7048 
   7049   v8::Handle<Value> value;
   7050 
   7051   // Attempt to get the property names of the other global object and
   7052   // of an object that requires access checks.  Accessing the other
   7053   // global object should be blocked by access checks on the global
   7054   // proxy object.  Accessing the object that requires access checks
   7055   // is blocked by the access checks on the object itself.
   7056   value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
   7057   CHECK(value->IsTrue());
   7058 
   7059   value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
   7060   CHECK(value->IsTrue());
   7061 
   7062   context1->Exit();
   7063   context0->Exit();
   7064   context1.Dispose();
   7065   context0.Dispose();
   7066 }
   7067 
   7068 
   7069 static v8::Handle<v8::Array> NamedPropertyEnumerator(const AccessorInfo& info) {
   7070   v8::Handle<v8::Array> result = v8::Array::New(1);
   7071   result->Set(0, v8_str("x"));
   7072   return result;
   7073 }
   7074 
   7075 
   7076 THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
   7077   v8::HandleScope handle_scope;
   7078   v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
   7079 
   7080   obj_template->Set(v8_str("x"), v8::Integer::New(42));
   7081   obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
   7082                                         NamedPropertyEnumerator);
   7083 
   7084   LocalContext context;
   7085   v8::Handle<v8::Object> global = context->Global();
   7086   global->Set(v8_str("object"), obj_template->NewInstance());
   7087 
   7088   v8::Handle<Value> value =
   7089       CompileRun("Object.getOwnPropertyNames(object).join(',')");
   7090   CHECK_EQ(v8_str("x"), value);
   7091 }
   7092 
   7093 
   7094 static v8::Handle<Value> ConstTenGetter(Local<String> name,
   7095                                         const AccessorInfo& info) {
   7096   return v8_num(10);
   7097 }
   7098 
   7099 
   7100 THREADED_TEST(CrossDomainAccessors) {
   7101   v8::HandleScope handle_scope;
   7102 
   7103   v8::Handle<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
   7104 
   7105   v8::Handle<v8::ObjectTemplate> global_template =
   7106       func_template->InstanceTemplate();
   7107 
   7108   v8::Handle<v8::ObjectTemplate> proto_template =
   7109       func_template->PrototypeTemplate();
   7110 
   7111   // Add an accessor to proto that's accessible by cross-domain JS code.
   7112   proto_template->SetAccessor(v8_str("accessible"),
   7113                               ConstTenGetter, 0,
   7114                               v8::Handle<Value>(),
   7115                               v8::ALL_CAN_READ);
   7116 
   7117   // Add an accessor that is not accessible by cross-domain JS code.
   7118   global_template->SetAccessor(v8_str("unreachable"),
   7119                                UnreachableGetter, 0,
   7120                                v8::Handle<Value>(),
   7121                                v8::DEFAULT);
   7122 
   7123   v8::Persistent<Context> context0 = Context::New(NULL, global_template);
   7124   context0->Enter();
   7125 
   7126   Local<v8::Object> global = context0->Global();
   7127   // Add a normal property that shadows 'accessible'
   7128   global->Set(v8_str("accessible"), v8_num(11));
   7129 
   7130   // Enter a new context.
   7131   v8::HandleScope scope1;
   7132   v8::Persistent<Context> context1 = Context::New();
   7133   context1->Enter();
   7134 
   7135   v8::Handle<v8::Object> global1 = context1->Global();
   7136   global1->Set(v8_str("other"), global);
   7137 
   7138   // Should return 10, instead of 11
   7139   v8::Handle<Value> value = v8_compile("other.accessible")->Run();
   7140   CHECK(value->IsNumber());
   7141   CHECK_EQ(10, value->Int32Value());
   7142 
   7143   value = v8_compile("other.unreachable")->Run();
   7144   CHECK(value->IsUndefined());
   7145 
   7146   context1->Exit();
   7147   context0->Exit();
   7148   context1.Dispose();
   7149   context0.Dispose();
   7150 }
   7151 
   7152 
   7153 static int named_access_count = 0;
   7154 static int indexed_access_count = 0;
   7155 
   7156 static bool NamedAccessCounter(Local<v8::Object> global,
   7157                                Local<Value> name,
   7158                                v8::AccessType type,
   7159                                Local<Value> data) {
   7160   named_access_count++;
   7161   return true;
   7162 }
   7163 
   7164 
   7165 static bool IndexedAccessCounter(Local<v8::Object> global,
   7166                                  uint32_t key,
   7167                                  v8::AccessType type,
   7168                                  Local<Value> data) {
   7169   indexed_access_count++;
   7170   return true;
   7171 }
   7172 
   7173 
   7174 // This one is too easily disturbed by other tests.
   7175 TEST(AccessControlIC) {
   7176   named_access_count = 0;
   7177   indexed_access_count = 0;
   7178 
   7179   v8::HandleScope handle_scope;
   7180 
   7181   // Create an environment.
   7182   v8::Persistent<Context> context0 = Context::New();
   7183   context0->Enter();
   7184 
   7185   // Create an object that requires access-check functions to be
   7186   // called for cross-domain access.
   7187   v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
   7188   object_template->SetAccessCheckCallbacks(NamedAccessCounter,
   7189                                            IndexedAccessCounter);
   7190   Local<v8::Object> object = object_template->NewInstance();
   7191 
   7192   v8::HandleScope scope1;
   7193 
   7194   // Create another environment.
   7195   v8::Persistent<Context> context1 = Context::New();
   7196   context1->Enter();
   7197 
   7198   // Make easy access to the object from the other environment.
   7199   v8::Handle<v8::Object> global1 = context1->Global();
   7200   global1->Set(v8_str("obj"), object);
   7201 
   7202   v8::Handle<Value> value;
   7203 
   7204   // Check that the named access-control function is called every time.
   7205   CompileRun("function testProp(obj) {"
   7206              "  for (var i = 0; i < 10; i++) obj.prop = 1;"
   7207              "  for (var j = 0; j < 10; j++) obj.prop;"
   7208              "  return obj.prop"
   7209              "}");
   7210   value = CompileRun("testProp(obj)");
   7211   CHECK(value->IsNumber());
   7212   CHECK_EQ(1, value->Int32Value());
   7213   CHECK_EQ(21, named_access_count);
   7214 
   7215   // Check that the named access-control function is called every time.
   7216   CompileRun("var p = 'prop';"
   7217              "function testKeyed(obj) {"
   7218              "  for (var i = 0; i < 10; i++) obj[p] = 1;"
   7219              "  for (var j = 0; j < 10; j++) obj[p];"
   7220              "  return obj[p];"
   7221              "}");
   7222   // Use obj which requires access checks.  No inline caching is used
   7223   // in that case.
   7224   value = CompileRun("testKeyed(obj)");
   7225   CHECK(value->IsNumber());
   7226   CHECK_EQ(1, value->Int32Value());
   7227   CHECK_EQ(42, named_access_count);
   7228   // Force the inline caches into generic state and try again.
   7229   CompileRun("testKeyed({ a: 0 })");
   7230   CompileRun("testKeyed({ b: 0 })");
   7231   value = CompileRun("testKeyed(obj)");
   7232   CHECK(value->IsNumber());
   7233   CHECK_EQ(1, value->Int32Value());
   7234   CHECK_EQ(63, named_access_count);
   7235 
   7236   // Check that the indexed access-control function is called every time.
   7237   CompileRun("function testIndexed(obj) {"
   7238              "  for (var i = 0; i < 10; i++) obj[0] = 1;"
   7239              "  for (var j = 0; j < 10; j++) obj[0];"
   7240              "  return obj[0]"
   7241              "}");
   7242   value = CompileRun("testIndexed(obj)");
   7243   CHECK(value->IsNumber());
   7244   CHECK_EQ(1, value->Int32Value());
   7245   CHECK_EQ(21, indexed_access_count);
   7246   // Force the inline caches into generic state.
   7247   CompileRun("testIndexed(new Array(1))");
   7248   // Test that the indexed access check is called.
   7249   value = CompileRun("testIndexed(obj)");
   7250   CHECK(value->IsNumber());
   7251   CHECK_EQ(1, value->Int32Value());
   7252   CHECK_EQ(42, indexed_access_count);
   7253 
   7254   // Check that the named access check is called when invoking
   7255   // functions on an object that requires access checks.
   7256   CompileRun("obj.f = function() {}");
   7257   CompileRun("function testCallNormal(obj) {"
   7258              "  for (var i = 0; i < 10; i++) obj.f();"
   7259              "}");
   7260   CompileRun("testCallNormal(obj)");
   7261   CHECK_EQ(74, named_access_count);
   7262 
   7263   // Force obj into slow case.
   7264   value = CompileRun("delete obj.prop");
   7265   CHECK(value->BooleanValue());
   7266   // Force inline caches into dictionary probing mode.
   7267   CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
   7268   // Test that the named access check is called.
   7269   value = CompileRun("testProp(obj);");
   7270   CHECK(value->IsNumber());
   7271   CHECK_EQ(1, value->Int32Value());
   7272   CHECK_EQ(96, named_access_count);
   7273 
   7274   // Force the call inline cache into dictionary probing mode.
   7275   CompileRun("o.f = function() {}; testCallNormal(o)");
   7276   // Test that the named access check is still called for each
   7277   // invocation of the function.
   7278   value = CompileRun("testCallNormal(obj)");
   7279   CHECK_EQ(106, named_access_count);
   7280 
   7281   context1->Exit();
   7282   context0->Exit();
   7283   context1.Dispose();
   7284   context0.Dispose();
   7285 }
   7286 
   7287 
   7288 static bool NamedAccessFlatten(Local<v8::Object> global,
   7289                                Local<Value> name,
   7290                                v8::AccessType type,
   7291                                Local<Value> data) {
   7292   char buf[100];
   7293   int len;
   7294 
   7295   CHECK(name->IsString());
   7296 
   7297   memset(buf, 0x1, sizeof(buf));
   7298   len = name.As<String>()->WriteAscii(buf);
   7299   CHECK_EQ(4, len);
   7300 
   7301   uint16_t buf2[100];
   7302 
   7303   memset(buf, 0x1, sizeof(buf));
   7304   len = name.As<String>()->Write(buf2);
   7305   CHECK_EQ(4, len);
   7306 
   7307   return true;
   7308 }
   7309 
   7310 
   7311 static bool IndexedAccessFlatten(Local<v8::Object> global,
   7312                                  uint32_t key,
   7313                                  v8::AccessType type,
   7314                                  Local<Value> data) {
   7315   return true;
   7316 }
   7317 
   7318 
   7319 // Regression test.  In access checks, operations that may cause
   7320 // garbage collection are not allowed.  It used to be the case that
   7321 // using the Write operation on a string could cause a garbage
   7322 // collection due to flattening of the string.  This is no longer the
   7323 // case.
   7324 THREADED_TEST(AccessControlFlatten) {
   7325   named_access_count = 0;
   7326   indexed_access_count = 0;
   7327 
   7328   v8::HandleScope handle_scope;
   7329 
   7330   // Create an environment.
   7331   v8::Persistent<Context> context0 = Context::New();
   7332   context0->Enter();
   7333 
   7334   // Create an object that requires access-check functions to be
   7335   // called for cross-domain access.
   7336   v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
   7337   object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
   7338                                            IndexedAccessFlatten);
   7339   Local<v8::Object> object = object_template->NewInstance();
   7340 
   7341   v8::HandleScope scope1;
   7342 
   7343   // Create another environment.
   7344   v8::Persistent<Context> context1 = Context::New();
   7345   context1->Enter();
   7346 
   7347   // Make easy access to the object from the other environment.
   7348   v8::Handle<v8::Object> global1 = context1->Global();
   7349   global1->Set(v8_str("obj"), object);
   7350 
   7351   v8::Handle<Value> value;
   7352 
   7353   value = v8_compile("var p = 'as' + 'df';")->Run();
   7354   value = v8_compile("obj[p];")->Run();
   7355 
   7356   context1->Exit();
   7357   context0->Exit();
   7358   context1.Dispose();
   7359   context0.Dispose();
   7360 }
   7361 
   7362 
   7363 static v8::Handle<Value> AccessControlNamedGetter(
   7364     Local<String>, const AccessorInfo&) {
   7365   return v8::Integer::New(42);
   7366 }
   7367 
   7368 
   7369 static v8::Handle<Value> AccessControlNamedSetter(
   7370     Local<String>, Local<Value> value, const AccessorInfo&) {
   7371   return value;
   7372 }
   7373 
   7374 
   7375 static v8::Handle<Value> AccessControlIndexedGetter(
   7376       uint32_t index,
   7377       const AccessorInfo& info) {
   7378   return v8_num(42);
   7379 }
   7380 
   7381 
   7382 static v8::Handle<Value> AccessControlIndexedSetter(
   7383     uint32_t, Local<Value> value, const AccessorInfo&) {
   7384   return value;
   7385 }
   7386 
   7387 
   7388 THREADED_TEST(AccessControlInterceptorIC) {
   7389   named_access_count = 0;
   7390   indexed_access_count = 0;
   7391 
   7392   v8::HandleScope handle_scope;
   7393 
   7394   // Create an environment.
   7395   v8::Persistent<Context> context0 = Context::New();
   7396   context0->Enter();
   7397 
   7398   // Create an object that requires access-check functions to be
   7399   // called for cross-domain access.  The object also has interceptors
   7400   // interceptor.
   7401   v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
   7402   object_template->SetAccessCheckCallbacks(NamedAccessCounter,
   7403                                            IndexedAccessCounter);
   7404   object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
   7405                                            AccessControlNamedSetter);
   7406   object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
   7407                                              AccessControlIndexedSetter);
   7408   Local<v8::Object> object = object_template->NewInstance();
   7409 
   7410   v8::HandleScope scope1;
   7411 
   7412   // Create another environment.
   7413   v8::Persistent<Context> context1 = Context::New();
   7414   context1->Enter();
   7415 
   7416   // Make easy access to the object from the other environment.
   7417   v8::Handle<v8::Object> global1 = context1->Global();
   7418   global1->Set(v8_str("obj"), object);
   7419 
   7420   v8::Handle<Value> value;
   7421 
   7422   // Check that the named access-control function is called every time
   7423   // eventhough there is an interceptor on the object.
   7424   value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
   7425   value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
   7426                      "obj.x")->Run();
   7427   CHECK(value->IsNumber());
   7428   CHECK_EQ(42, value->Int32Value());
   7429   CHECK_EQ(21, named_access_count);
   7430 
   7431   value = v8_compile("var p = 'x';")->Run();
   7432   value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
   7433   value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
   7434                      "obj[p]")->Run();
   7435   CHECK(value->IsNumber());
   7436   CHECK_EQ(42, value->Int32Value());
   7437   CHECK_EQ(42, named_access_count);
   7438 
   7439   // Check that the indexed access-control function is called every
   7440   // time eventhough there is an interceptor on the object.
   7441   value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
   7442   value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
   7443                      "obj[0]")->Run();
   7444   CHECK(value->IsNumber());
   7445   CHECK_EQ(42, value->Int32Value());
   7446   CHECK_EQ(21, indexed_access_count);
   7447 
   7448   context1->Exit();
   7449   context0->Exit();
   7450   context1.Dispose();
   7451   context0.Dispose();
   7452 }
   7453 
   7454 
   7455 THREADED_TEST(Version) {
   7456   v8::V8::GetVersion();
   7457 }
   7458 
   7459 
   7460 static v8::Handle<Value> InstanceFunctionCallback(const v8::Arguments& args) {
   7461   ApiTestFuzzer::Fuzz();
   7462   return v8_num(12);
   7463 }
   7464 
   7465 
   7466 THREADED_TEST(InstanceProperties) {
   7467   v8::HandleScope handle_scope;
   7468   LocalContext context;
   7469 
   7470   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
   7471   Local<ObjectTemplate> instance = t->InstanceTemplate();
   7472 
   7473   instance->Set(v8_str("x"), v8_num(42));
   7474   instance->Set(v8_str("f"),
   7475                 v8::FunctionTemplate::New(InstanceFunctionCallback));
   7476 
   7477   Local<Value> o = t->GetFunction()->NewInstance();
   7478 
   7479   context->Global()->Set(v8_str("i"), o);
   7480   Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
   7481   CHECK_EQ(42, value->Int32Value());
   7482 
   7483   value = Script::Compile(v8_str("i.f()"))->Run();
   7484   CHECK_EQ(12, value->Int32Value());
   7485 }
   7486 
   7487 
   7488 static v8::Handle<Value>
   7489 GlobalObjectInstancePropertiesGet(Local<String> key, const AccessorInfo&) {
   7490   ApiTestFuzzer::Fuzz();
   7491   return v8::Handle<Value>();
   7492 }
   7493 
   7494 
   7495 THREADED_TEST(GlobalObjectInstanceProperties) {
   7496   v8::HandleScope handle_scope;
   7497 
   7498   Local<Value> global_object;
   7499 
   7500   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
   7501   t->InstanceTemplate()->SetNamedPropertyHandler(
   7502       GlobalObjectInstancePropertiesGet);
   7503   Local<ObjectTemplate> instance_template = t->InstanceTemplate();
   7504   instance_template->Set(v8_str("x"), v8_num(42));
   7505   instance_template->Set(v8_str("f"),
   7506                          v8::FunctionTemplate::New(InstanceFunctionCallback));
   7507 
   7508   // The script to check how Crankshaft compiles missing global function
   7509   // invocations.  function g is not defined and should throw on call.
   7510   const char* script =
   7511       "function wrapper(call) {"
   7512       "  var x = 0, y = 1;"
   7513       "  for (var i = 0; i < 1000; i++) {"
   7514       "    x += i * 100;"
   7515       "    y += i * 100;"
   7516       "  }"
   7517       "  if (call) g();"
   7518       "}"
   7519       "for (var i = 0; i < 17; i++) wrapper(false);"
   7520       "var thrown = 0;"
   7521       "try { wrapper(true); } catch (e) { thrown = 1; };"
   7522       "thrown";
   7523 
   7524   {
   7525     LocalContext env(NULL, instance_template);
   7526     // Hold on to the global object so it can be used again in another
   7527     // environment initialization.
   7528     global_object = env->Global();
   7529 
   7530     Local<Value> value = Script::Compile(v8_str("x"))->Run();
   7531     CHECK_EQ(42, value->Int32Value());
   7532     value = Script::Compile(v8_str("f()"))->Run();
   7533     CHECK_EQ(12, value->Int32Value());
   7534     value = Script::Compile(v8_str(script))->Run();
   7535     CHECK_EQ(1, value->Int32Value());
   7536   }
   7537 
   7538   {
   7539     // Create new environment reusing the global object.
   7540     LocalContext env(NULL, instance_template, global_object);
   7541     Local<Value> value = Script::Compile(v8_str("x"))->Run();
   7542     CHECK_EQ(42, value->Int32Value());
   7543     value = Script::Compile(v8_str("f()"))->Run();
   7544     CHECK_EQ(12, value->Int32Value());
   7545     value = Script::Compile(v8_str(script))->Run();
   7546     CHECK_EQ(1, value->Int32Value());
   7547   }
   7548 }
   7549 
   7550 
   7551 THREADED_TEST(CallKnownGlobalReceiver) {
   7552   v8::HandleScope handle_scope;
   7553 
   7554   Local<Value> global_object;
   7555 
   7556   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
   7557   Local<ObjectTemplate> instance_template = t->InstanceTemplate();
   7558 
   7559   // The script to check that we leave global object not
   7560   // global object proxy on stack when we deoptimize from inside
   7561   // arguments evaluation.
   7562   // To provoke error we need to both force deoptimization
   7563   // from arguments evaluation and to force CallIC to take
   7564   // CallIC_Miss code path that can't cope with global proxy.
   7565   const char* script =
   7566       "function bar(x, y) { try { } finally { } }"
   7567       "function baz(x) { try { } finally { } }"
   7568       "function bom(x) { try { } finally { } }"
   7569       "function foo(x) { bar([x], bom(2)); }"
   7570       "for (var i = 0; i < 10000; i++) foo(1);"
   7571       "foo";
   7572 
   7573   Local<Value> foo;
   7574   {
   7575     LocalContext env(NULL, instance_template);
   7576     // Hold on to the global object so it can be used again in another
   7577     // environment initialization.
   7578     global_object = env->Global();
   7579     foo = Script::Compile(v8_str(script))->Run();
   7580   }
   7581 
   7582   {
   7583     // Create new environment reusing the global object.
   7584     LocalContext env(NULL, instance_template, global_object);
   7585     env->Global()->Set(v8_str("foo"), foo);
   7586     Script::Compile(v8_str("foo()"))->Run();
   7587   }
   7588 }
   7589 
   7590 
   7591 static v8::Handle<Value> ShadowFunctionCallback(const v8::Arguments& args) {
   7592   ApiTestFuzzer::Fuzz();
   7593   return v8_num(42);
   7594 }
   7595 
   7596 
   7597 static int shadow_y;
   7598 static int shadow_y_setter_call_count;
   7599 static int shadow_y_getter_call_count;
   7600 
   7601 
   7602 static void ShadowYSetter(Local<String>, Local<Value>, const AccessorInfo&) {
   7603   shadow_y_setter_call_count++;
   7604   shadow_y = 42;
   7605 }
   7606 
   7607 
   7608 static v8::Handle<Value> ShadowYGetter(Local<String> name,
   7609                                        const AccessorInfo& info) {
   7610   ApiTestFuzzer::Fuzz();
   7611   shadow_y_getter_call_count++;
   7612   return v8_num(shadow_y);
   7613 }
   7614 
   7615 
   7616 static v8::Handle<Value> ShadowIndexedGet(uint32_t index,
   7617                                           const AccessorInfo& info) {
   7618   return v8::Handle<Value>();
   7619 }
   7620 
   7621 
   7622 static v8::Handle<Value> ShadowNamedGet(Local<String> key,
   7623                                         const AccessorInfo&) {
   7624   return v8::Handle<Value>();
   7625 }
   7626 
   7627 
   7628 THREADED_TEST(ShadowObject) {
   7629   shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
   7630   v8::HandleScope handle_scope;
   7631 
   7632   Local<ObjectTemplate> global_template = v8::ObjectTemplate::New();
   7633   LocalContext context(NULL, global_template);
   7634 
   7635   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
   7636   t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
   7637   t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
   7638   Local<ObjectTemplate> proto = t->PrototypeTemplate();
   7639   Local<ObjectTemplate> instance = t->InstanceTemplate();
   7640 
   7641   // Only allow calls of f on instances of t.
   7642   Local<v8::Signature> signature = v8::Signature::New(t);
   7643   proto->Set(v8_str("f"),
   7644              v8::FunctionTemplate::New(ShadowFunctionCallback,
   7645                                        Local<Value>(),
   7646                                        signature));
   7647   proto->Set(v8_str("x"), v8_num(12));
   7648 
   7649   instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
   7650 
   7651   Local<Value> o = t->GetFunction()->NewInstance();
   7652   context->Global()->Set(v8_str("__proto__"), o);
   7653 
   7654   Local<Value> value =
   7655       Script::Compile(v8_str("this.propertyIsEnumerable(0)"))->Run();
   7656   CHECK(value->IsBoolean());
   7657   CHECK(!value->BooleanValue());
   7658 
   7659   value = Script::Compile(v8_str("x"))->Run();
   7660   CHECK_EQ(12, value->Int32Value());
   7661 
   7662   value = Script::Compile(v8_str("f()"))->Run();
   7663   CHECK_EQ(42, value->Int32Value());
   7664 
   7665   Script::Compile(v8_str("y = 42"))->Run();
   7666   CHECK_EQ(1, shadow_y_setter_call_count);
   7667   value = Script::Compile(v8_str("y"))->Run();
   7668   CHECK_EQ(1, shadow_y_getter_call_count);
   7669   CHECK_EQ(42, value->Int32Value());
   7670 }
   7671 
   7672 
   7673 THREADED_TEST(HiddenPrototype) {
   7674   v8::HandleScope handle_scope;
   7675   LocalContext context;
   7676 
   7677   Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
   7678   t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
   7679   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
   7680   t1->SetHiddenPrototype(true);
   7681   t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
   7682   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
   7683   t2->SetHiddenPrototype(true);
   7684   t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
   7685   Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
   7686   t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
   7687 
   7688   Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
   7689   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
   7690   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
   7691   Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
   7692 
   7693   // Setting the prototype on an object skips hidden prototypes.
   7694   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
   7695   o0->Set(v8_str("__proto__"), o1);
   7696   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
   7697   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
   7698   o0->Set(v8_str("__proto__"), o2);
   7699   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
   7700   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
   7701   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
   7702   o0->Set(v8_str("__proto__"), o3);
   7703   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
   7704   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
   7705   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
   7706   CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
   7707 
   7708   // Getting the prototype of o0 should get the first visible one
   7709   // which is o3.  Therefore, z should not be defined on the prototype
   7710   // object.
   7711   Local<Value> proto = o0->Get(v8_str("__proto__"));
   7712   CHECK(proto->IsObject());
   7713   CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
   7714 }
   7715 
   7716 
   7717 THREADED_TEST(SetPrototype) {
   7718   v8::HandleScope handle_scope;
   7719   LocalContext context;
   7720 
   7721   Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
   7722   t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
   7723   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
   7724   t1->SetHiddenPrototype(true);
   7725   t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
   7726   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
   7727   t2->SetHiddenPrototype(true);
   7728   t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
   7729   Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
   7730   t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
   7731 
   7732   Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
   7733   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
   7734   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
   7735   Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
   7736 
   7737   // Setting the prototype on an object does not skip hidden prototypes.
   7738   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
   7739   CHECK(o0->SetPrototype(o1));
   7740   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
   7741   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
   7742   CHECK(o1->SetPrototype(o2));
   7743   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
   7744   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
   7745   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
   7746   CHECK(o2->SetPrototype(o3));
   7747   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
   7748   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
   7749   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
   7750   CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
   7751 
   7752   // Getting the prototype of o0 should get the first visible one
   7753   // which is o3.  Therefore, z should not be defined on the prototype
   7754   // object.
   7755   Local<Value> proto = o0->Get(v8_str("__proto__"));
   7756   CHECK(proto->IsObject());
   7757   CHECK_EQ(proto.As<v8::Object>(), o3);
   7758 
   7759   // However, Object::GetPrototype ignores hidden prototype.
   7760   Local<Value> proto0 = o0->GetPrototype();
   7761   CHECK(proto0->IsObject());
   7762   CHECK_EQ(proto0.As<v8::Object>(), o1);
   7763 
   7764   Local<Value> proto1 = o1->GetPrototype();
   7765   CHECK(proto1->IsObject());
   7766   CHECK_EQ(proto1.As<v8::Object>(), o2);
   7767 
   7768   Local<Value> proto2 = o2->GetPrototype();
   7769   CHECK(proto2->IsObject());
   7770   CHECK_EQ(proto2.As<v8::Object>(), o3);
   7771 }
   7772 
   7773 
   7774 // Getting property names of an object with a prototype chain that
   7775 // triggers dictionary elements in GetLocalPropertyNames() shouldn't
   7776 // crash the runtime.
   7777 THREADED_TEST(Regress91517) {
   7778   i::FLAG_allow_natives_syntax = true;
   7779   v8::HandleScope handle_scope;
   7780   LocalContext context;
   7781 
   7782   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
   7783   t1->SetHiddenPrototype(true);
   7784   t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1));
   7785   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
   7786   t2->SetHiddenPrototype(true);
   7787   t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2));
   7788   t2->InstanceTemplate()->Set(v8_str("objects"), v8::Object::New());
   7789   t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2));
   7790   Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
   7791   t3->SetHiddenPrototype(true);
   7792   t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3));
   7793   Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New();
   7794   t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4));
   7795 
   7796   // Force dictionary-based properties.
   7797   i::ScopedVector<char> name_buf(1024);
   7798   for (int i = 1; i <= 1000; i++) {
   7799     i::OS::SNPrintF(name_buf, "sdf%d", i);
   7800     t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2));
   7801   }
   7802 
   7803   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
   7804   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
   7805   Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
   7806   Local<v8::Object> o4 = t4->GetFunction()->NewInstance();
   7807 
   7808   // Create prototype chain of hidden prototypes.
   7809   CHECK(o4->SetPrototype(o3));
   7810   CHECK(o3->SetPrototype(o2));
   7811   CHECK(o2->SetPrototype(o1));
   7812 
   7813   // Call the runtime version of GetLocalPropertyNames() on the natively
   7814   // created object through JavaScript.
   7815   context->Global()->Set(v8_str("obj"), o4);
   7816   CompileRun("var names = %GetLocalPropertyNames(obj);");
   7817 
   7818   ExpectInt32("names.length", 1006);
   7819   ExpectTrue("names.indexOf(\"baz\") >= 0");
   7820   ExpectTrue("names.indexOf(\"boo\") >= 0");
   7821   ExpectTrue("names.indexOf(\"foo\") >= 0");
   7822   ExpectTrue("names.indexOf(\"fuz1\") >= 0");
   7823   ExpectTrue("names.indexOf(\"fuz2\") >= 0");
   7824   ExpectFalse("names[1005] == undefined");
   7825 }
   7826 
   7827 
   7828 THREADED_TEST(FunctionReadOnlyPrototype) {
   7829   v8::HandleScope handle_scope;
   7830   LocalContext context;
   7831 
   7832   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
   7833   t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(42));
   7834   t1->ReadOnlyPrototype();
   7835   context->Global()->Set(v8_str("func1"), t1->GetFunction());
   7836   // Configured value of ReadOnly flag.
   7837   CHECK(CompileRun(
   7838       "(function() {"
   7839       "  descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
   7840       "  return (descriptor['writable'] == false);"
   7841       "})()")->BooleanValue());
   7842   CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value());
   7843   CHECK_EQ(42,
   7844            CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value());
   7845 
   7846   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
   7847   t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(42));
   7848   context->Global()->Set(v8_str("func2"), t2->GetFunction());
   7849   // Default value of ReadOnly flag.
   7850   CHECK(CompileRun(
   7851       "(function() {"
   7852       "  descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
   7853       "  return (descriptor['writable'] == true);"
   7854       "})()")->BooleanValue());
   7855   CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value());
   7856 }
   7857 
   7858 
   7859 THREADED_TEST(SetPrototypeThrows) {
   7860   v8::HandleScope handle_scope;
   7861   LocalContext context;
   7862 
   7863   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
   7864 
   7865   Local<v8::Object> o0 = t->GetFunction()->NewInstance();
   7866   Local<v8::Object> o1 = t->GetFunction()->NewInstance();
   7867 
   7868   CHECK(o0->SetPrototype(o1));
   7869   // If setting the prototype leads to the cycle, SetPrototype should
   7870   // return false and keep VM in sane state.
   7871   v8::TryCatch try_catch;
   7872   CHECK(!o1->SetPrototype(o0));
   7873   CHECK(!try_catch.HasCaught());
   7874   ASSERT(!i::Isolate::Current()->